blob: b89ca11ad038f08ea1d81fadce9c74107855a13c [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
Roland Levillain4fa13f62015-07-06 18:11:54 +0100431inline Condition X86SignedCondition(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;
Dave Allison20dfc792014-06-16 20:44:29 -0700439 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100440 LOG(FATAL) << "Unreachable";
441 UNREACHABLE();
442}
443
444inline Condition X86UnsignedOrFPCondition(IfCondition cond) {
445 switch (cond) {
446 case kCondEQ: return kEqual;
447 case kCondNE: return kNotEqual;
448 case kCondLT: return kBelow;
449 case kCondLE: return kBelowEqual;
450 case kCondGT: return kAbove;
451 case kCondGE: return kAboveEqual;
452 }
453 LOG(FATAL) << "Unreachable";
454 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700455}
456
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100457void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100458 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100459}
460
461void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100462 stream << XmmRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100463}
464
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100465size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
466 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
467 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100468}
469
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100470size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
471 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
472 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100473}
474
Mark Mendell7c8d0092015-01-26 11:21:33 -0500475size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
476 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
477 return GetFloatingPointSpillSlotSize();
478}
479
480size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
481 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
482 return GetFloatingPointSpillSlotSize();
483}
484
Calin Juravle175dc732015-08-25 15:42:32 +0100485void CodeGeneratorX86::InvokeRuntime(QuickEntrypointEnum entrypoint,
486 HInstruction* instruction,
487 uint32_t dex_pc,
488 SlowPathCode* slow_path) {
489 InvokeRuntime(GetThreadOffset<kX86WordSize>(entrypoint).Int32Value(),
490 instruction,
491 dex_pc,
492 slow_path);
493}
494
495void CodeGeneratorX86::InvokeRuntime(int32_t entry_point_offset,
Alexandre Rames8158f282015-08-07 10:26:17 +0100496 HInstruction* instruction,
497 uint32_t dex_pc,
498 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100499 ValidateInvokeRuntime(instruction, slow_path);
Calin Juravle175dc732015-08-25 15:42:32 +0100500 __ fs()->call(Address::Absolute(entry_point_offset));
Alexandre Rames8158f282015-08-07 10:26:17 +0100501 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100502}
503
Mark Mendellfb8d2792015-03-31 22:16:59 -0400504CodeGeneratorX86::CodeGeneratorX86(HGraph* graph,
505 const X86InstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100506 const CompilerOptions& compiler_options,
507 OptimizingCompilerStats* stats)
Mark Mendell5f874182015-03-04 15:42:45 -0500508 : CodeGenerator(graph,
509 kNumberOfCpuRegisters,
510 kNumberOfXmmRegisters,
511 kNumberOfRegisterPairs,
512 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
513 arraysize(kCoreCalleeSaves))
514 | (1 << kFakeReturnRegister),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100515 0,
516 compiler_options,
517 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100518 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100519 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100520 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400521 move_resolver_(graph->GetArena(), this),
Vladimir Marko58155012015-08-19 12:49:41 +0000522 isa_features_(isa_features),
Vladimir Marko5233f932015-09-29 19:01:15 +0100523 method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
524 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000525 // Use a fake return address register to mimic Quick.
526 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100527}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100528
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100529Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100530 switch (type) {
531 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100532 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100533 X86ManagedRegister pair =
534 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100535 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
536 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100537 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
538 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100539 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100540 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100541 }
542
543 case Primitive::kPrimByte:
544 case Primitive::kPrimBoolean:
545 case Primitive::kPrimChar:
546 case Primitive::kPrimShort:
547 case Primitive::kPrimInt:
548 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100549 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100550 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100551 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100552 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
553 X86ManagedRegister current =
554 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
555 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100556 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100557 }
558 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100559 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100560 }
561
562 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100563 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100564 return Location::FpuRegisterLocation(
565 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100566 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100567
568 case Primitive::kPrimVoid:
569 LOG(FATAL) << "Unreachable type " << type;
570 }
571
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100572 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100573}
574
Mark Mendell5f874182015-03-04 15:42:45 -0500575void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100576 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100577 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100578
579 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100580 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100581
Mark Mendell5f874182015-03-04 15:42:45 -0500582 if (is_baseline) {
583 blocked_core_registers_[EBP] = true;
584 blocked_core_registers_[ESI] = true;
585 blocked_core_registers_[EDI] = true;
586 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100587
588 UpdateBlockedPairRegisters();
589}
590
591void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
592 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
593 X86ManagedRegister current =
594 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
595 if (blocked_core_registers_[current.AsRegisterPairLow()]
596 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
597 blocked_register_pairs_[i] = true;
598 }
599 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100600}
601
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100602InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
603 : HGraphVisitor(graph),
604 assembler_(codegen->GetAssembler()),
605 codegen_(codegen) {}
606
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100607static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100608 return dwarf::Reg::X86Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100609}
610
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000611void CodeGeneratorX86::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100612 __ cfi().SetCurrentCFAOffset(kX86WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000613 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000614 bool skip_overflow_check =
615 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000616 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000617
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000618 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100619 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100620 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100621 }
622
Mark Mendell5f874182015-03-04 15:42:45 -0500623 if (HasEmptyFrame()) {
624 return;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000625 }
Mark Mendell5f874182015-03-04 15:42:45 -0500626
627 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
628 Register reg = kCoreCalleeSaves[i];
629 if (allocated_registers_.ContainsCoreRegister(reg)) {
630 __ pushl(reg);
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100631 __ cfi().AdjustCFAOffset(kX86WordSize);
632 __ cfi().RelOffset(DWARFReg(reg), 0);
Mark Mendell5f874182015-03-04 15:42:45 -0500633 }
634 }
635
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100636 int adjust = GetFrameSize() - FrameEntrySpillSize();
637 __ subl(ESP, Immediate(adjust));
638 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100639 __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000640}
641
642void CodeGeneratorX86::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100643 __ cfi().RememberState();
644 if (!HasEmptyFrame()) {
645 int adjust = GetFrameSize() - FrameEntrySpillSize();
646 __ addl(ESP, Immediate(adjust));
647 __ cfi().AdjustCFAOffset(-adjust);
Mark Mendell5f874182015-03-04 15:42:45 -0500648
David Srbeckyc34dc932015-04-12 09:27:43 +0100649 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
650 Register reg = kCoreCalleeSaves[i];
651 if (allocated_registers_.ContainsCoreRegister(reg)) {
652 __ popl(reg);
653 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize));
654 __ cfi().Restore(DWARFReg(reg));
655 }
Mark Mendell5f874182015-03-04 15:42:45 -0500656 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000657 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100658 __ ret();
659 __ cfi().RestoreState();
660 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000661}
662
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100663void CodeGeneratorX86::Bind(HBasicBlock* block) {
664 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000665}
666
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100667Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
668 switch (load->GetType()) {
669 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100670 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100671 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100672
673 case Primitive::kPrimInt:
674 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100675 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100676 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100677
678 case Primitive::kPrimBoolean:
679 case Primitive::kPrimByte:
680 case Primitive::kPrimChar:
681 case Primitive::kPrimShort:
682 case Primitive::kPrimVoid:
683 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700684 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100685 }
686
687 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700688 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100689}
690
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100691Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(Primitive::Type type) const {
692 switch (type) {
693 case Primitive::kPrimBoolean:
694 case Primitive::kPrimByte:
695 case Primitive::kPrimChar:
696 case Primitive::kPrimShort:
697 case Primitive::kPrimInt:
698 case Primitive::kPrimNot:
699 return Location::RegisterLocation(EAX);
700
701 case Primitive::kPrimLong:
702 return Location::RegisterPairLocation(EAX, EDX);
703
704 case Primitive::kPrimVoid:
705 return Location::NoLocation();
706
707 case Primitive::kPrimDouble:
708 case Primitive::kPrimFloat:
709 return Location::FpuRegisterLocation(XMM0);
710 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100711
712 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100713}
714
715Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
716 return Location::RegisterLocation(kMethodRegisterArgument);
717}
718
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100719Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100720 switch (type) {
721 case Primitive::kPrimBoolean:
722 case Primitive::kPrimByte:
723 case Primitive::kPrimChar:
724 case Primitive::kPrimShort:
725 case Primitive::kPrimInt:
726 case Primitive::kPrimNot: {
727 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000728 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100729 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100730 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100731 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000732 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100733 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100734 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100735
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000736 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100737 uint32_t index = gp_index_;
738 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000739 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100740 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100741 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
742 calling_convention.GetRegisterPairAt(index));
743 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100744 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000745 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
746 }
747 }
748
749 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100750 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000751 stack_index_++;
752 if (index < calling_convention.GetNumberOfFpuRegisters()) {
753 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
754 } else {
755 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
756 }
757 }
758
759 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100760 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000761 stack_index_ += 2;
762 if (index < calling_convention.GetNumberOfFpuRegisters()) {
763 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
764 } else {
765 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100766 }
767 }
768
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100769 case Primitive::kPrimVoid:
770 LOG(FATAL) << "Unexpected parameter type " << type;
771 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100772 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100773 return Location();
774}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100775
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100776void CodeGeneratorX86::Move32(Location destination, Location source) {
777 if (source.Equals(destination)) {
778 return;
779 }
780 if (destination.IsRegister()) {
781 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000782 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100783 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000784 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100785 } else {
786 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000787 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100788 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100789 } else if (destination.IsFpuRegister()) {
790 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000791 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100792 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000793 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100794 } else {
795 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000796 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100797 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100798 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000799 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100800 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000801 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100802 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000803 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500804 } else if (source.IsConstant()) {
805 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000806 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -0500807 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100808 } else {
809 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100810 __ pushl(Address(ESP, source.GetStackIndex()));
811 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100812 }
813 }
814}
815
816void CodeGeneratorX86::Move64(Location destination, Location source) {
817 if (source.Equals(destination)) {
818 return;
819 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100820 if (destination.IsRegisterPair()) {
821 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000822 EmitParallelMoves(
823 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
824 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100825 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000826 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100827 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
828 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100829 } else if (source.IsFpuRegister()) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100830 XmmRegister src_reg = source.AsFpuRegister<XmmRegister>();
831 __ movd(destination.AsRegisterPairLow<Register>(), src_reg);
832 __ psrlq(src_reg, Immediate(32));
833 __ movd(destination.AsRegisterPairHigh<Register>(), src_reg);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100834 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000835 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100836 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100837 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
838 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100839 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
840 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100841 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500842 if (source.IsFpuRegister()) {
843 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
844 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000845 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Calin Juravlee460d1d2015-09-29 04:52:17 +0100846 } else if (source.IsRegisterPair()) {
847 size_t elem_size = Primitive::ComponentSize(Primitive::kPrimInt);
848 // Create stack space for 2 elements.
849 __ subl(ESP, Immediate(2 * elem_size));
850 __ movl(Address(ESP, 0), source.AsRegisterPairLow<Register>());
851 __ movl(Address(ESP, elem_size), source.AsRegisterPairHigh<Register>());
852 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
853 // And remove the temporary stack space we allocated.
854 __ addl(ESP, Immediate(2 * elem_size));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100855 } else {
856 LOG(FATAL) << "Unimplemented";
857 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100858 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000859 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100860 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000861 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100862 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100863 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100864 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100865 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000866 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000867 } else if (source.IsConstant()) {
868 HConstant* constant = source.GetConstant();
869 int64_t value;
870 if (constant->IsLongConstant()) {
871 value = constant->AsLongConstant()->GetValue();
872 } else {
873 DCHECK(constant->IsDoubleConstant());
Roland Levillainda4d79b2015-03-24 14:36:11 +0000874 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000875 }
876 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
877 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100878 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000879 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000880 EmitParallelMoves(
881 Location::StackSlot(source.GetStackIndex()),
882 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100883 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000884 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100885 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
886 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100887 }
888 }
889}
890
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100891void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000892 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100893 if (instruction->IsCurrentMethod()) {
894 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
895 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000896 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100897 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000898 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000899 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
900 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000901 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000902 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000903 } else if (location.IsStackSlot()) {
904 __ movl(Address(ESP, location.GetStackIndex()), imm);
905 } else {
906 DCHECK(location.IsConstant());
907 DCHECK_EQ(location.GetConstant(), const_to_move);
908 }
909 } else if (const_to_move->IsLongConstant()) {
910 int64_t value = const_to_move->AsLongConstant()->GetValue();
911 if (location.IsRegisterPair()) {
912 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
913 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
914 } else if (location.IsDoubleStackSlot()) {
915 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000916 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
917 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000918 } else {
919 DCHECK(location.IsConstant());
920 DCHECK_EQ(location.GetConstant(), instruction);
921 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100922 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000923 } else if (instruction->IsTemporary()) {
924 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000925 if (temp_location.IsStackSlot()) {
926 Move32(location, temp_location);
927 } else {
928 DCHECK(temp_location.IsDoubleStackSlot());
929 Move64(location, temp_location);
930 }
Roland Levillain476df552014-10-09 17:51:36 +0100931 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100932 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100933 switch (instruction->GetType()) {
934 case Primitive::kPrimBoolean:
935 case Primitive::kPrimByte:
936 case Primitive::kPrimChar:
937 case Primitive::kPrimShort:
938 case Primitive::kPrimInt:
939 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100940 case Primitive::kPrimFloat:
941 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100942 break;
943
944 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100945 case Primitive::kPrimDouble:
946 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100947 break;
948
949 default:
950 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
951 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000952 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100953 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100954 switch (instruction->GetType()) {
955 case Primitive::kPrimBoolean:
956 case Primitive::kPrimByte:
957 case Primitive::kPrimChar:
958 case Primitive::kPrimShort:
959 case Primitive::kPrimInt:
960 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100961 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000962 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100963 break;
964
965 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100966 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000967 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100968 break;
969
970 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100971 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100972 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000973 }
974}
975
Calin Juravle175dc732015-08-25 15:42:32 +0100976void CodeGeneratorX86::MoveConstant(Location location, int32_t value) {
977 DCHECK(location.IsRegister());
978 __ movl(location.AsRegister<Register>(), Immediate(value));
979}
980
Calin Juravlee460d1d2015-09-29 04:52:17 +0100981void CodeGeneratorX86::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
982 if (Primitive::Is64BitType(dst_type)) {
983 Move64(dst, src);
984 } else {
985 Move32(dst, src);
986 }
987}
988
989void CodeGeneratorX86::AddLocationAsTemp(Location location, LocationSummary* locations) {
990 if (location.IsRegister()) {
991 locations->AddTemp(location);
992 } else if (location.IsRegisterPair()) {
993 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
994 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
995 } else {
996 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
997 }
998}
999
David Brazdilfc6a86a2015-06-26 10:33:45 +00001000void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001001 DCHECK(!successor->IsExitBlock());
1002
1003 HBasicBlock* block = got->GetBlock();
1004 HInstruction* previous = got->GetPrevious();
1005
1006 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001007 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001008 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1009 return;
1010 }
1011
1012 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1013 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1014 }
1015 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001016 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001017 }
1018}
1019
David Brazdilfc6a86a2015-06-26 10:33:45 +00001020void LocationsBuilderX86::VisitGoto(HGoto* got) {
1021 got->SetLocations(nullptr);
1022}
1023
1024void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
1025 HandleGoto(got, got->GetSuccessor());
1026}
1027
1028void LocationsBuilderX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1029 try_boundary->SetLocations(nullptr);
1030}
1031
1032void InstructionCodeGeneratorX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1033 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1034 if (!successor->IsExitBlock()) {
1035 HandleGoto(try_boundary, successor);
1036 }
1037}
1038
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001039void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001040 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001041}
1042
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001043void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001044 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001045}
1046
Mark Mendellc4701932015-04-10 13:18:51 -04001047void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
1048 Label* true_label,
1049 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001050 if (cond->IsFPConditionTrueIfNaN()) {
1051 __ j(kUnordered, true_label);
1052 } else if (cond->IsFPConditionFalseIfNaN()) {
1053 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001054 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001055 __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001056}
1057
1058void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
1059 Label* true_label,
1060 Label* false_label) {
1061 LocationSummary* locations = cond->GetLocations();
1062 Location left = locations->InAt(0);
1063 Location right = locations->InAt(1);
1064 IfCondition if_cond = cond->GetCondition();
1065
Mark Mendellc4701932015-04-10 13:18:51 -04001066 Register left_high = left.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001067 Register left_low = left.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001068 IfCondition true_high_cond = if_cond;
1069 IfCondition false_high_cond = cond->GetOppositeCondition();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001070 Condition final_condition = X86UnsignedOrFPCondition(if_cond);
Mark Mendellc4701932015-04-10 13:18:51 -04001071
1072 // Set the conditions for the test, remembering that == needs to be
1073 // decided using the low words.
1074 switch (if_cond) {
1075 case kCondEQ:
Mark Mendellc4701932015-04-10 13:18:51 -04001076 case kCondNE:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001077 // Nothing to do.
Mark Mendellc4701932015-04-10 13:18:51 -04001078 break;
1079 case kCondLT:
1080 false_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001081 break;
1082 case kCondLE:
1083 true_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001084 break;
1085 case kCondGT:
1086 false_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001087 break;
1088 case kCondGE:
1089 true_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001090 break;
1091 }
1092
1093 if (right.IsConstant()) {
1094 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellc4701932015-04-10 13:18:51 -04001095 int32_t val_high = High32Bits(value);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001096 int32_t val_low = Low32Bits(value);
Mark Mendellc4701932015-04-10 13:18:51 -04001097
1098 if (val_high == 0) {
1099 __ testl(left_high, left_high);
1100 } else {
1101 __ cmpl(left_high, Immediate(val_high));
1102 }
1103 if (if_cond == kCondNE) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001104 __ j(X86SignedCondition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001105 } else if (if_cond == kCondEQ) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001106 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001107 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001108 __ j(X86SignedCondition(true_high_cond), true_label);
1109 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001110 }
1111 // Must be equal high, so compare the lows.
1112 if (val_low == 0) {
1113 __ testl(left_low, left_low);
1114 } else {
1115 __ cmpl(left_low, Immediate(val_low));
1116 }
1117 } else {
Mark Mendellc4701932015-04-10 13:18:51 -04001118 Register right_high = right.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001119 Register right_low = right.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001120
1121 __ cmpl(left_high, right_high);
1122 if (if_cond == kCondNE) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001123 __ j(X86SignedCondition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001124 } else if (if_cond == kCondEQ) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001125 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001126 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001127 __ j(X86SignedCondition(true_high_cond), true_label);
1128 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001129 }
1130 // Must be equal high, so compare the lows.
1131 __ cmpl(left_low, right_low);
1132 }
1133 // The last comparison might be unsigned.
1134 __ j(final_condition, true_label);
1135}
1136
1137void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HIf* if_instr,
1138 HCondition* condition,
1139 Label* true_target,
1140 Label* false_target,
1141 Label* always_true_target) {
1142 LocationSummary* locations = condition->GetLocations();
1143 Location left = locations->InAt(0);
1144 Location right = locations->InAt(1);
1145
1146 // We don't want true_target as a nullptr.
1147 if (true_target == nullptr) {
1148 true_target = always_true_target;
1149 }
1150 bool falls_through = (false_target == nullptr);
1151
1152 // FP compares don't like null false_targets.
1153 if (false_target == nullptr) {
1154 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1155 }
1156
1157 Primitive::Type type = condition->InputAt(0)->GetType();
1158 switch (type) {
1159 case Primitive::kPrimLong:
1160 GenerateLongComparesAndJumps(condition, true_target, false_target);
1161 break;
1162 case Primitive::kPrimFloat:
Mark Mendellc4701932015-04-10 13:18:51 -04001163 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1164 GenerateFPJumps(condition, true_target, false_target);
1165 break;
1166 case Primitive::kPrimDouble:
Mark Mendellc4701932015-04-10 13:18:51 -04001167 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1168 GenerateFPJumps(condition, true_target, false_target);
1169 break;
1170 default:
1171 LOG(FATAL) << "Unexpected compare type " << type;
1172 }
1173
1174 if (!falls_through) {
1175 __ jmp(false_target);
1176 }
1177}
1178
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001179void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
1180 Label* true_target,
1181 Label* false_target,
1182 Label* always_true_target) {
1183 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001184 if (cond->IsIntConstant()) {
1185 // Constant condition, statically compared against 1.
1186 int32_t cond_value = cond->AsIntConstant()->GetValue();
1187 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001188 if (always_true_target != nullptr) {
1189 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001190 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001191 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001192 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001193 DCHECK_EQ(cond_value, 0);
1194 }
1195 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001196 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001197 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
1198 // Moves do not affect the eflags register, so if the condition is
1199 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001200 // again. We can't use the eflags on long/FP conditions if they are
1201 // materialized due to the complex branching.
1202 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001203 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001204 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
Roland Levillain4fa13f62015-07-06 18:11:54 +01001205 && (type != Primitive::kPrimLong && !Primitive::IsFloatingPointType(type));
1206 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001207 if (!eflags_set) {
1208 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001209 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001210 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001211 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001212 } else {
1213 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
1214 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001215 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001216 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001217 __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001218 }
1219 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001220 // Condition has not been materialized, use its inputs as the
1221 // comparison and its condition as the branch condition.
1222
Mark Mendellc4701932015-04-10 13:18:51 -04001223 // Is this a long or FP comparison that has been folded into the HCondition?
1224 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1225 // Generate the comparison directly.
1226 GenerateCompareTestAndBranch(instruction->AsIf(),
1227 cond->AsCondition(),
1228 true_target,
1229 false_target,
1230 always_true_target);
1231 return;
1232 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001233
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001234 Location lhs = cond->GetLocations()->InAt(0);
1235 Location rhs = cond->GetLocations()->InAt(1);
1236 // LHS is guaranteed to be in a register (see
1237 // LocationsBuilderX86::VisitCondition).
1238 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001239 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001240 } else if (rhs.IsConstant()) {
Calin Juravleb3306642015-04-20 18:30:42 +01001241 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -05001242 if (constant == 0) {
1243 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1244 } else {
1245 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1246 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001247 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001248 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001249 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001250 __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001251 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001252 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001253 if (false_target != nullptr) {
1254 __ jmp(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001255 }
1256}
1257
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001258void LocationsBuilderX86::VisitIf(HIf* if_instr) {
1259 LocationSummary* locations =
1260 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1261 HInstruction* cond = if_instr->InputAt(0);
1262 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1263 locations->SetInAt(0, Location::Any());
1264 }
1265}
1266
1267void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
1268 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1269 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1270 Label* always_true_target = true_target;
1271 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1272 if_instr->IfTrueSuccessor())) {
1273 always_true_target = nullptr;
1274 }
1275 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1276 if_instr->IfFalseSuccessor())) {
1277 false_target = nullptr;
1278 }
1279 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1280}
1281
1282void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
1283 LocationSummary* locations = new (GetGraph()->GetArena())
1284 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1285 HInstruction* cond = deoptimize->InputAt(0);
1286 DCHECK(cond->IsCondition());
1287 if (cond->AsCondition()->NeedsMaterialization()) {
1288 locations->SetInAt(0, Location::Any());
1289 }
1290}
1291
1292void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001293 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001294 DeoptimizationSlowPathX86(deoptimize);
1295 codegen_->AddSlowPath(slow_path);
1296 Label* slow_path_entry = slow_path->GetEntryLabel();
1297 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1298}
1299
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001300void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001301 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001302}
1303
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001304void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
1305 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001306}
1307
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001308void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001309 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001310}
1311
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001312void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001313 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001314 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001315}
1316
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001317void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001318 LocationSummary* locations =
1319 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001320 switch (store->InputAt(1)->GetType()) {
1321 case Primitive::kPrimBoolean:
1322 case Primitive::kPrimByte:
1323 case Primitive::kPrimChar:
1324 case Primitive::kPrimShort:
1325 case Primitive::kPrimInt:
1326 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001327 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001328 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1329 break;
1330
1331 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001332 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001333 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1334 break;
1335
1336 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001337 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001338 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001339}
1340
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001341void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001342 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001343}
1344
Roland Levillain0d37cd02015-05-27 16:39:19 +01001345void LocationsBuilderX86::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001346 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001347 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001348 // Handle the long/FP comparisons made in instruction simplification.
1349 switch (cond->InputAt(0)->GetType()) {
1350 case Primitive::kPrimLong: {
1351 locations->SetInAt(0, Location::RequiresRegister());
1352 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1353 if (cond->NeedsMaterialization()) {
1354 locations->SetOut(Location::RequiresRegister());
1355 }
1356 break;
1357 }
1358 case Primitive::kPrimFloat:
1359 case Primitive::kPrimDouble: {
1360 locations->SetInAt(0, Location::RequiresFpuRegister());
1361 locations->SetInAt(1, Location::RequiresFpuRegister());
1362 if (cond->NeedsMaterialization()) {
1363 locations->SetOut(Location::RequiresRegister());
1364 }
1365 break;
1366 }
1367 default:
1368 locations->SetInAt(0, Location::RequiresRegister());
1369 locations->SetInAt(1, Location::Any());
1370 if (cond->NeedsMaterialization()) {
1371 // We need a byte register.
1372 locations->SetOut(Location::RegisterLocation(ECX));
1373 }
1374 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001375 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001376}
1377
Roland Levillain0d37cd02015-05-27 16:39:19 +01001378void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001379 if (!cond->NeedsMaterialization()) {
1380 return;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001381 }
Mark Mendellc4701932015-04-10 13:18:51 -04001382
1383 LocationSummary* locations = cond->GetLocations();
1384 Location lhs = locations->InAt(0);
1385 Location rhs = locations->InAt(1);
1386 Register reg = locations->Out().AsRegister<Register>();
1387 Label true_label, false_label;
1388
1389 switch (cond->InputAt(0)->GetType()) {
1390 default: {
1391 // Integer case.
1392
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01001393 // Clear output register: setb only sets the low byte.
Mark Mendellc4701932015-04-10 13:18:51 -04001394 __ xorl(reg, reg);
1395
1396 if (rhs.IsRegister()) {
1397 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
1398 } else if (rhs.IsConstant()) {
1399 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1400 if (constant == 0) {
1401 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1402 } else {
1403 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1404 }
1405 } else {
1406 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
1407 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001408 __ setb(X86SignedCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001409 return;
1410 }
1411 case Primitive::kPrimLong:
1412 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1413 break;
1414 case Primitive::kPrimFloat:
1415 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1416 GenerateFPJumps(cond, &true_label, &false_label);
1417 break;
1418 case Primitive::kPrimDouble:
1419 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1420 GenerateFPJumps(cond, &true_label, &false_label);
1421 break;
1422 }
1423
1424 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001425 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001426
Roland Levillain4fa13f62015-07-06 18:11:54 +01001427 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001428 __ Bind(&false_label);
1429 __ xorl(reg, reg);
1430 __ jmp(&done_label);
1431
Roland Levillain4fa13f62015-07-06 18:11:54 +01001432 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001433 __ Bind(&true_label);
1434 __ movl(reg, Immediate(1));
1435 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001436}
1437
1438void LocationsBuilderX86::VisitEqual(HEqual* comp) {
1439 VisitCondition(comp);
1440}
1441
1442void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
1443 VisitCondition(comp);
1444}
1445
1446void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
1447 VisitCondition(comp);
1448}
1449
1450void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
1451 VisitCondition(comp);
1452}
1453
1454void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
1455 VisitCondition(comp);
1456}
1457
1458void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
1459 VisitCondition(comp);
1460}
1461
1462void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1463 VisitCondition(comp);
1464}
1465
1466void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1467 VisitCondition(comp);
1468}
1469
1470void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
1471 VisitCondition(comp);
1472}
1473
1474void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
1475 VisitCondition(comp);
1476}
1477
1478void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1479 VisitCondition(comp);
1480}
1481
1482void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1483 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001484}
1485
1486void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001487 LocationSummary* locations =
1488 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001489 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001490}
1491
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001492void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001493 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001494 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001495}
1496
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001497void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1498 LocationSummary* locations =
1499 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1500 locations->SetOut(Location::ConstantLocation(constant));
1501}
1502
1503void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1504 // Will be generated at use site.
1505 UNUSED(constant);
1506}
1507
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001508void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001509 LocationSummary* locations =
1510 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001511 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001512}
1513
1514void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1515 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001516 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001517}
1518
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001519void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1520 LocationSummary* locations =
1521 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1522 locations->SetOut(Location::ConstantLocation(constant));
1523}
1524
1525void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1526 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001527 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001528}
1529
1530void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1531 LocationSummary* locations =
1532 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1533 locations->SetOut(Location::ConstantLocation(constant));
1534}
1535
1536void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1537 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001538 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001539}
1540
Calin Juravle27df7582015-04-17 19:12:31 +01001541void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1542 memory_barrier->SetLocations(nullptr);
1543}
1544
1545void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1546 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1547}
1548
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001549void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001550 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001551}
1552
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001553void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001554 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001555 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001556}
1557
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001558void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001559 LocationSummary* locations =
1560 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001561 switch (ret->InputAt(0)->GetType()) {
1562 case Primitive::kPrimBoolean:
1563 case Primitive::kPrimByte:
1564 case Primitive::kPrimChar:
1565 case Primitive::kPrimShort:
1566 case Primitive::kPrimInt:
1567 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001568 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001569 break;
1570
1571 case Primitive::kPrimLong:
1572 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001573 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001574 break;
1575
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001576 case Primitive::kPrimFloat:
1577 case Primitive::kPrimDouble:
1578 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001579 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001580 break;
1581
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001582 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001583 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001584 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001585}
1586
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001587void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001588 if (kIsDebugBuild) {
1589 switch (ret->InputAt(0)->GetType()) {
1590 case Primitive::kPrimBoolean:
1591 case Primitive::kPrimByte:
1592 case Primitive::kPrimChar:
1593 case Primitive::kPrimShort:
1594 case Primitive::kPrimInt:
1595 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001596 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001597 break;
1598
1599 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001600 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1601 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001602 break;
1603
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001604 case Primitive::kPrimFloat:
1605 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001606 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001607 break;
1608
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001609 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001610 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001611 }
1612 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001613 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001614}
1615
Calin Juravle175dc732015-08-25 15:42:32 +01001616void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1617 // The trampoline uses the same calling convention as dex calling conventions,
1618 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1619 // the method_idx.
1620 HandleInvoke(invoke);
1621}
1622
1623void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1624 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1625}
1626
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001627void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001628 // When we do not run baseline, explicit clinit checks triggered by static
1629 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1630 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001631
Mark Mendellfb8d2792015-03-31 22:16:59 -04001632 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001633 if (intrinsic.TryDispatch(invoke)) {
1634 return;
1635 }
1636
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001637 HandleInvoke(invoke);
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001638
1639 if (codegen_->IsBaseline()) {
1640 // Baseline does not have enough registers if the current method also
1641 // needs a register. We therefore do not require a register for it, and let
1642 // the code generation of the invoke handle it.
1643 LocationSummary* locations = invoke->GetLocations();
1644 Location location = locations->InAt(invoke->GetCurrentMethodInputIndex());
1645 if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) {
1646 locations->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::NoLocation());
1647 }
1648 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001649}
1650
Mark Mendell09ed1a32015-03-25 08:30:06 -04001651static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1652 if (invoke->GetLocations()->Intrinsified()) {
1653 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1654 intrinsic.Dispatch(invoke);
1655 return true;
1656 }
1657 return false;
1658}
1659
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001660void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001661 // When we do not run baseline, explicit clinit checks triggered by static
1662 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1663 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001664
Mark Mendell09ed1a32015-03-25 08:30:06 -04001665 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1666 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001667 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001668
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001669 LocationSummary* locations = invoke->GetLocations();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001670 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001671 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Mingyao Yang8693fe12015-04-17 16:51:08 -07001672 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001673}
1674
1675void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1676 HandleInvoke(invoke);
1677}
1678
1679void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001680 InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001681 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001682}
1683
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001684void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001685 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1686 return;
1687 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001688
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001689 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001690 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001691 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001692}
1693
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001694void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1695 HandleInvoke(invoke);
1696 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001697 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001698}
1699
1700void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1701 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001702 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001703 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1704 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001705 LocationSummary* locations = invoke->GetLocations();
1706 Location receiver = locations->InAt(0);
1707 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1708
1709 // Set the hidden argument.
1710 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001711 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001712
1713 // temp = object->GetClass();
1714 if (receiver.IsStackSlot()) {
1715 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1716 __ movl(temp, Address(temp, class_offset));
1717 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001718 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001719 }
Roland Levillain4d027112015-07-01 15:41:14 +01001720 codegen_->MaybeRecordImplicitNullCheck(invoke);
1721 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001722 // temp = temp->GetImtEntryAt(method_offset);
1723 __ movl(temp, Address(temp, method_offset));
1724 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001725 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001726 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001727
1728 DCHECK(!codegen_->IsLeafMethod());
1729 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1730}
1731
Roland Levillain88cb1752014-10-20 16:36:47 +01001732void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1733 LocationSummary* locations =
1734 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1735 switch (neg->GetResultType()) {
1736 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001737 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001738 locations->SetInAt(0, Location::RequiresRegister());
1739 locations->SetOut(Location::SameAsFirstInput());
1740 break;
1741
Roland Levillain88cb1752014-10-20 16:36:47 +01001742 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001743 locations->SetInAt(0, Location::RequiresFpuRegister());
1744 locations->SetOut(Location::SameAsFirstInput());
1745 locations->AddTemp(Location::RequiresRegister());
1746 locations->AddTemp(Location::RequiresFpuRegister());
1747 break;
1748
Roland Levillain88cb1752014-10-20 16:36:47 +01001749 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001750 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001751 locations->SetOut(Location::SameAsFirstInput());
1752 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001753 break;
1754
1755 default:
1756 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1757 }
1758}
1759
1760void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1761 LocationSummary* locations = neg->GetLocations();
1762 Location out = locations->Out();
1763 Location in = locations->InAt(0);
1764 switch (neg->GetResultType()) {
1765 case Primitive::kPrimInt:
1766 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001767 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001768 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001769 break;
1770
1771 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001772 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001773 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001774 __ negl(out.AsRegisterPairLow<Register>());
1775 // Negation is similar to subtraction from zero. The least
1776 // significant byte triggers a borrow when it is different from
1777 // zero; to take it into account, add 1 to the most significant
1778 // byte if the carry flag (CF) is set to 1 after the first NEGL
1779 // operation.
1780 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1781 __ negl(out.AsRegisterPairHigh<Register>());
1782 break;
1783
Roland Levillain5368c212014-11-27 15:03:41 +00001784 case Primitive::kPrimFloat: {
1785 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001786 Register constant = locations->GetTemp(0).AsRegister<Register>();
1787 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001788 // Implement float negation with an exclusive or with value
1789 // 0x80000000 (mask for bit 31, representing the sign of a
1790 // single-precision floating-point number).
1791 __ movl(constant, Immediate(INT32_C(0x80000000)));
1792 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001793 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001794 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001795 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001796
Roland Levillain5368c212014-11-27 15:03:41 +00001797 case Primitive::kPrimDouble: {
1798 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001799 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001800 // Implement double negation with an exclusive or with value
1801 // 0x8000000000000000 (mask for bit 63, representing the sign of
1802 // a double-precision floating-point number).
1803 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001804 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001805 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001806 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001807
1808 default:
1809 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1810 }
1811}
1812
Roland Levillaindff1f282014-11-05 14:15:05 +00001813void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001814 Primitive::Type result_type = conversion->GetResultType();
1815 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001816 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001817
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001818 // The float-to-long and double-to-long type conversions rely on a
1819 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001820 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001821 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1822 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001823 ? LocationSummary::kCall
1824 : LocationSummary::kNoCall;
1825 LocationSummary* locations =
1826 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1827
David Brazdilb2bd1c52015-03-25 11:17:37 +00001828 // The Java language does not allow treating boolean as an integral type but
1829 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001830
Roland Levillaindff1f282014-11-05 14:15:05 +00001831 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001832 case Primitive::kPrimByte:
1833 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001834 case Primitive::kPrimBoolean:
1835 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001836 case Primitive::kPrimShort:
1837 case Primitive::kPrimInt:
1838 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001839 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001840 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1841 // Make the output overlap to please the register allocator. This greatly simplifies
1842 // the validation of the linear scan implementation
1843 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001844 break;
1845
1846 default:
1847 LOG(FATAL) << "Unexpected type conversion from " << input_type
1848 << " to " << result_type;
1849 }
1850 break;
1851
Roland Levillain01a8d712014-11-14 16:27:39 +00001852 case Primitive::kPrimShort:
1853 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001854 case Primitive::kPrimBoolean:
1855 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001856 case Primitive::kPrimByte:
1857 case Primitive::kPrimInt:
1858 case Primitive::kPrimChar:
1859 // Processing a Dex `int-to-short' instruction.
1860 locations->SetInAt(0, Location::Any());
1861 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1862 break;
1863
1864 default:
1865 LOG(FATAL) << "Unexpected type conversion from " << input_type
1866 << " to " << result_type;
1867 }
1868 break;
1869
Roland Levillain946e1432014-11-11 17:35:19 +00001870 case Primitive::kPrimInt:
1871 switch (input_type) {
1872 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001873 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001874 locations->SetInAt(0, Location::Any());
1875 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1876 break;
1877
1878 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001879 // Processing a Dex `float-to-int' instruction.
1880 locations->SetInAt(0, Location::RequiresFpuRegister());
1881 locations->SetOut(Location::RequiresRegister());
1882 locations->AddTemp(Location::RequiresFpuRegister());
1883 break;
1884
Roland Levillain946e1432014-11-11 17:35:19 +00001885 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001886 // Processing a Dex `double-to-int' instruction.
1887 locations->SetInAt(0, Location::RequiresFpuRegister());
1888 locations->SetOut(Location::RequiresRegister());
1889 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001890 break;
1891
1892 default:
1893 LOG(FATAL) << "Unexpected type conversion from " << input_type
1894 << " to " << result_type;
1895 }
1896 break;
1897
Roland Levillaindff1f282014-11-05 14:15:05 +00001898 case Primitive::kPrimLong:
1899 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001900 case Primitive::kPrimBoolean:
1901 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001902 case Primitive::kPrimByte:
1903 case Primitive::kPrimShort:
1904 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001905 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001906 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001907 locations->SetInAt(0, Location::RegisterLocation(EAX));
1908 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1909 break;
1910
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001911 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001912 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001913 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001914 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001915 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1916 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1917
Vladimir Marko949c91f2015-01-27 10:48:44 +00001918 // The runtime helper puts the result in EAX, EDX.
1919 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001920 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001921 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001922
1923 default:
1924 LOG(FATAL) << "Unexpected type conversion from " << input_type
1925 << " to " << result_type;
1926 }
1927 break;
1928
Roland Levillain981e4542014-11-14 11:47:14 +00001929 case Primitive::kPrimChar:
1930 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001931 case Primitive::kPrimBoolean:
1932 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001933 case Primitive::kPrimByte:
1934 case Primitive::kPrimShort:
1935 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001936 // Processing a Dex `int-to-char' instruction.
1937 locations->SetInAt(0, Location::Any());
1938 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1939 break;
1940
1941 default:
1942 LOG(FATAL) << "Unexpected type conversion from " << input_type
1943 << " to " << result_type;
1944 }
1945 break;
1946
Roland Levillaindff1f282014-11-05 14:15:05 +00001947 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001948 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001949 case Primitive::kPrimBoolean:
1950 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001951 case Primitive::kPrimByte:
1952 case Primitive::kPrimShort:
1953 case Primitive::kPrimInt:
1954 case Primitive::kPrimChar:
1955 // Processing a Dex `int-to-float' instruction.
1956 locations->SetInAt(0, Location::RequiresRegister());
1957 locations->SetOut(Location::RequiresFpuRegister());
1958 break;
1959
1960 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001961 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001962 locations->SetInAt(0, Location::Any());
1963 locations->SetOut(Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001964 break;
1965
Roland Levillaincff13742014-11-17 14:32:17 +00001966 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001967 // Processing a Dex `double-to-float' instruction.
1968 locations->SetInAt(0, Location::RequiresFpuRegister());
1969 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001970 break;
1971
1972 default:
1973 LOG(FATAL) << "Unexpected type conversion from " << input_type
1974 << " to " << result_type;
1975 };
1976 break;
1977
Roland Levillaindff1f282014-11-05 14:15:05 +00001978 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001979 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001980 case Primitive::kPrimBoolean:
1981 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001982 case Primitive::kPrimByte:
1983 case Primitive::kPrimShort:
1984 case Primitive::kPrimInt:
1985 case Primitive::kPrimChar:
1986 // Processing a Dex `int-to-double' instruction.
1987 locations->SetInAt(0, Location::RequiresRegister());
1988 locations->SetOut(Location::RequiresFpuRegister());
1989 break;
1990
1991 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001992 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001993 locations->SetInAt(0, Location::Any());
1994 locations->SetOut(Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001995 break;
1996
Roland Levillaincff13742014-11-17 14:32:17 +00001997 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001998 // Processing a Dex `float-to-double' instruction.
1999 locations->SetInAt(0, Location::RequiresFpuRegister());
2000 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002001 break;
2002
2003 default:
2004 LOG(FATAL) << "Unexpected type conversion from " << input_type
2005 << " to " << result_type;
2006 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002007 break;
2008
2009 default:
2010 LOG(FATAL) << "Unexpected type conversion from " << input_type
2011 << " to " << result_type;
2012 }
2013}
2014
2015void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
2016 LocationSummary* locations = conversion->GetLocations();
2017 Location out = locations->Out();
2018 Location in = locations->InAt(0);
2019 Primitive::Type result_type = conversion->GetResultType();
2020 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002021 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002022 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002023 case Primitive::kPrimByte:
2024 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002025 case Primitive::kPrimBoolean:
2026 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002027 case Primitive::kPrimShort:
2028 case Primitive::kPrimInt:
2029 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002030 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002031 if (in.IsRegister()) {
2032 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002033 } else {
2034 DCHECK(in.GetConstant()->IsIntConstant());
2035 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
2036 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
2037 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00002038 break;
2039
2040 default:
2041 LOG(FATAL) << "Unexpected type conversion from " << input_type
2042 << " to " << result_type;
2043 }
2044 break;
2045
Roland Levillain01a8d712014-11-14 16:27:39 +00002046 case Primitive::kPrimShort:
2047 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002048 case Primitive::kPrimBoolean:
2049 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002050 case Primitive::kPrimByte:
2051 case Primitive::kPrimInt:
2052 case Primitive::kPrimChar:
2053 // Processing a Dex `int-to-short' instruction.
2054 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002055 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002056 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002057 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00002058 } else {
2059 DCHECK(in.GetConstant()->IsIntConstant());
2060 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002061 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00002062 }
2063 break;
2064
2065 default:
2066 LOG(FATAL) << "Unexpected type conversion from " << input_type
2067 << " to " << result_type;
2068 }
2069 break;
2070
Roland Levillain946e1432014-11-11 17:35:19 +00002071 case Primitive::kPrimInt:
2072 switch (input_type) {
2073 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002074 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002075 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002076 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002077 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002078 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00002079 } else {
2080 DCHECK(in.IsConstant());
2081 DCHECK(in.GetConstant()->IsLongConstant());
2082 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002083 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002084 }
2085 break;
2086
Roland Levillain3f8f9362014-12-02 17:45:01 +00002087 case Primitive::kPrimFloat: {
2088 // Processing a Dex `float-to-int' instruction.
2089 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2090 Register output = out.AsRegister<Register>();
2091 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002092 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002093
2094 __ movl(output, Immediate(kPrimIntMax));
2095 // temp = int-to-float(output)
2096 __ cvtsi2ss(temp, output);
2097 // if input >= temp goto done
2098 __ comiss(input, temp);
2099 __ j(kAboveEqual, &done);
2100 // if input == NaN goto nan
2101 __ j(kUnordered, &nan);
2102 // output = float-to-int-truncate(input)
2103 __ cvttss2si(output, input);
2104 __ jmp(&done);
2105 __ Bind(&nan);
2106 // output = 0
2107 __ xorl(output, output);
2108 __ Bind(&done);
2109 break;
2110 }
2111
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002112 case Primitive::kPrimDouble: {
2113 // Processing a Dex `double-to-int' instruction.
2114 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2115 Register output = out.AsRegister<Register>();
2116 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002117 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002118
2119 __ movl(output, Immediate(kPrimIntMax));
2120 // temp = int-to-double(output)
2121 __ cvtsi2sd(temp, output);
2122 // if input >= temp goto done
2123 __ comisd(input, temp);
2124 __ j(kAboveEqual, &done);
2125 // if input == NaN goto nan
2126 __ j(kUnordered, &nan);
2127 // output = double-to-int-truncate(input)
2128 __ cvttsd2si(output, input);
2129 __ jmp(&done);
2130 __ Bind(&nan);
2131 // output = 0
2132 __ xorl(output, output);
2133 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002134 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002135 }
Roland Levillain946e1432014-11-11 17:35:19 +00002136
2137 default:
2138 LOG(FATAL) << "Unexpected type conversion from " << input_type
2139 << " to " << result_type;
2140 }
2141 break;
2142
Roland Levillaindff1f282014-11-05 14:15:05 +00002143 case Primitive::kPrimLong:
2144 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002145 case Primitive::kPrimBoolean:
2146 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002147 case Primitive::kPrimByte:
2148 case Primitive::kPrimShort:
2149 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002150 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002151 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002152 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
2153 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00002154 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00002155 __ cdq();
2156 break;
2157
2158 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002159 // Processing a Dex `float-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002160 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2161 conversion,
2162 conversion->GetDexPc(),
2163 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002164 break;
2165
Roland Levillaindff1f282014-11-05 14:15:05 +00002166 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002167 // Processing a Dex `double-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002168 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2169 conversion,
2170 conversion->GetDexPc(),
2171 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002172 break;
2173
2174 default:
2175 LOG(FATAL) << "Unexpected type conversion from " << input_type
2176 << " to " << result_type;
2177 }
2178 break;
2179
Roland Levillain981e4542014-11-14 11:47:14 +00002180 case Primitive::kPrimChar:
2181 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002182 case Primitive::kPrimBoolean:
2183 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002184 case Primitive::kPrimByte:
2185 case Primitive::kPrimShort:
2186 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002187 // Processing a Dex `Process a Dex `int-to-char'' instruction.
2188 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002189 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00002190 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002191 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00002192 } else {
2193 DCHECK(in.GetConstant()->IsIntConstant());
2194 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002195 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00002196 }
2197 break;
2198
2199 default:
2200 LOG(FATAL) << "Unexpected type conversion from " << input_type
2201 << " to " << result_type;
2202 }
2203 break;
2204
Roland Levillaindff1f282014-11-05 14:15:05 +00002205 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002206 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002207 case Primitive::kPrimBoolean:
2208 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002209 case Primitive::kPrimByte:
2210 case Primitive::kPrimShort:
2211 case Primitive::kPrimInt:
2212 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002213 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002214 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002215 break;
2216
Roland Levillain6d0e4832014-11-27 18:31:21 +00002217 case Primitive::kPrimLong: {
2218 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002219 size_t adjustment = 0;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002220
Roland Levillain232ade02015-04-20 15:14:36 +01002221 // Create stack space for the call to
2222 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
2223 // TODO: enhance register allocator to ask for stack temporaries.
2224 if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
2225 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2226 __ subl(ESP, Immediate(adjustment));
2227 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002228
Roland Levillain232ade02015-04-20 15:14:36 +01002229 // Load the value to the FP stack, using temporaries if needed.
2230 PushOntoFPStack(in, 0, adjustment, false, true);
2231
2232 if (out.IsStackSlot()) {
2233 __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
2234 } else {
2235 __ fstps(Address(ESP, 0));
2236 Location stack_temp = Location::StackSlot(0);
2237 codegen_->Move32(out, stack_temp);
2238 }
2239
2240 // Remove the temporary stack space we allocated.
2241 if (adjustment != 0) {
2242 __ addl(ESP, Immediate(adjustment));
2243 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002244 break;
2245 }
2246
Roland Levillaincff13742014-11-17 14:32:17 +00002247 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002248 // Processing a Dex `double-to-float' instruction.
2249 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002250 break;
2251
2252 default:
2253 LOG(FATAL) << "Unexpected type conversion from " << input_type
2254 << " to " << result_type;
2255 };
2256 break;
2257
Roland Levillaindff1f282014-11-05 14:15:05 +00002258 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002259 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002260 case Primitive::kPrimBoolean:
2261 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002262 case Primitive::kPrimByte:
2263 case Primitive::kPrimShort:
2264 case Primitive::kPrimInt:
2265 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002266 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002267 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002268 break;
2269
Roland Levillain647b9ed2014-11-27 12:06:00 +00002270 case Primitive::kPrimLong: {
2271 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002272 size_t adjustment = 0;
Roland Levillain647b9ed2014-11-27 12:06:00 +00002273
Roland Levillain232ade02015-04-20 15:14:36 +01002274 // Create stack space for the call to
2275 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
2276 // TODO: enhance register allocator to ask for stack temporaries.
2277 if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
2278 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2279 __ subl(ESP, Immediate(adjustment));
2280 }
2281
2282 // Load the value to the FP stack, using temporaries if needed.
2283 PushOntoFPStack(in, 0, adjustment, false, true);
2284
2285 if (out.IsDoubleStackSlot()) {
2286 __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
2287 } else {
2288 __ fstpl(Address(ESP, 0));
2289 Location stack_temp = Location::DoubleStackSlot(0);
2290 codegen_->Move64(out, stack_temp);
2291 }
2292
2293 // Remove the temporary stack space we allocated.
2294 if (adjustment != 0) {
2295 __ addl(ESP, Immediate(adjustment));
2296 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002297 break;
2298 }
2299
Roland Levillaincff13742014-11-17 14:32:17 +00002300 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002301 // Processing a Dex `float-to-double' instruction.
2302 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002303 break;
2304
2305 default:
2306 LOG(FATAL) << "Unexpected type conversion from " << input_type
2307 << " to " << result_type;
2308 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002309 break;
2310
2311 default:
2312 LOG(FATAL) << "Unexpected type conversion from " << input_type
2313 << " to " << result_type;
2314 }
2315}
2316
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002317void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002318 LocationSummary* locations =
2319 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002320 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002321 case Primitive::kPrimInt: {
2322 locations->SetInAt(0, Location::RequiresRegister());
2323 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2324 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2325 break;
2326 }
2327
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002328 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002329 locations->SetInAt(0, Location::RequiresRegister());
2330 locations->SetInAt(1, Location::Any());
2331 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002332 break;
2333 }
2334
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002335 case Primitive::kPrimFloat:
2336 case Primitive::kPrimDouble: {
2337 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002338 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002339 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002340 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002341 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002342
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002343 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002344 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2345 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002346 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002347}
2348
2349void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
2350 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002351 Location first = locations->InAt(0);
2352 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05002353 Location out = locations->Out();
2354
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002355 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002356 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002357 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002358 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2359 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002360 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2361 __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
Mark Mendell09b84632015-02-13 17:48:38 -05002362 } else {
2363 __ leal(out.AsRegister<Register>(), Address(
2364 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
2365 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002366 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002367 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
2368 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2369 __ addl(out.AsRegister<Register>(), Immediate(value));
2370 } else {
2371 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
2372 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002373 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05002374 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002375 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002376 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002377 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002378 }
2379
2380 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002381 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002382 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2383 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002384 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002385 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
2386 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002387 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002388 } else {
2389 DCHECK(second.IsConstant()) << second;
2390 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2391 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2392 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002393 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002394 break;
2395 }
2396
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002397 case Primitive::kPrimFloat: {
2398 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002399 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002400 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2401 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2402 DCHECK(!const_area->NeedsMaterialization());
2403 __ addss(first.AsFpuRegister<XmmRegister>(),
2404 codegen_->LiteralFloatAddress(
2405 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2406 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2407 } else {
2408 DCHECK(second.IsStackSlot());
2409 __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002410 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002411 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002412 }
2413
2414 case Primitive::kPrimDouble: {
2415 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002416 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002417 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2418 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2419 DCHECK(!const_area->NeedsMaterialization());
2420 __ addsd(first.AsFpuRegister<XmmRegister>(),
2421 codegen_->LiteralDoubleAddress(
2422 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2423 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2424 } else {
2425 DCHECK(second.IsDoubleStackSlot());
2426 __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002427 }
2428 break;
2429 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002430
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002431 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002432 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002433 }
2434}
2435
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002436void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002437 LocationSummary* locations =
2438 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002439 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002440 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002441 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002442 locations->SetInAt(0, Location::RequiresRegister());
2443 locations->SetInAt(1, Location::Any());
2444 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002445 break;
2446 }
Calin Juravle11351682014-10-23 15:38:15 +01002447 case Primitive::kPrimFloat:
2448 case Primitive::kPrimDouble: {
2449 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002450 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002451 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002452 break;
Calin Juravle11351682014-10-23 15:38:15 +01002453 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002454
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002455 default:
Calin Juravle11351682014-10-23 15:38:15 +01002456 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002457 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002458}
2459
2460void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
2461 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002462 Location first = locations->InAt(0);
2463 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01002464 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002465 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002466 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002467 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002468 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002469 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002470 __ subl(first.AsRegister<Register>(),
2471 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002472 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002473 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002474 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002475 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002476 }
2477
2478 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002479 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01002480 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2481 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002482 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01002483 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002484 __ sbbl(first.AsRegisterPairHigh<Register>(),
2485 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002486 } else {
2487 DCHECK(second.IsConstant()) << second;
2488 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2489 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2490 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002491 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002492 break;
2493 }
2494
Calin Juravle11351682014-10-23 15:38:15 +01002495 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002496 if (second.IsFpuRegister()) {
2497 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2498 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2499 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2500 DCHECK(!const_area->NeedsMaterialization());
2501 __ subss(first.AsFpuRegister<XmmRegister>(),
2502 codegen_->LiteralFloatAddress(
2503 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2504 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2505 } else {
2506 DCHECK(second.IsStackSlot());
2507 __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2508 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002509 break;
Calin Juravle11351682014-10-23 15:38:15 +01002510 }
2511
2512 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002513 if (second.IsFpuRegister()) {
2514 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2515 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2516 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2517 DCHECK(!const_area->NeedsMaterialization());
2518 __ subsd(first.AsFpuRegister<XmmRegister>(),
2519 codegen_->LiteralDoubleAddress(
2520 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2521 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2522 } else {
2523 DCHECK(second.IsDoubleStackSlot());
2524 __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2525 }
Calin Juravle11351682014-10-23 15:38:15 +01002526 break;
2527 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002528
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002529 default:
Calin Juravle11351682014-10-23 15:38:15 +01002530 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002531 }
2532}
2533
Calin Juravle34bacdf2014-10-07 20:23:36 +01002534void LocationsBuilderX86::VisitMul(HMul* mul) {
2535 LocationSummary* locations =
2536 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2537 switch (mul->GetResultType()) {
2538 case Primitive::kPrimInt:
2539 locations->SetInAt(0, Location::RequiresRegister());
2540 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002541 if (mul->InputAt(1)->IsIntConstant()) {
2542 // Can use 3 operand multiply.
2543 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2544 } else {
2545 locations->SetOut(Location::SameAsFirstInput());
2546 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002547 break;
2548 case Primitive::kPrimLong: {
2549 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002550 locations->SetInAt(1, Location::Any());
2551 locations->SetOut(Location::SameAsFirstInput());
2552 // Needed for imul on 32bits with 64bits output.
2553 locations->AddTemp(Location::RegisterLocation(EAX));
2554 locations->AddTemp(Location::RegisterLocation(EDX));
2555 break;
2556 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002557 case Primitive::kPrimFloat:
2558 case Primitive::kPrimDouble: {
2559 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002560 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002561 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002562 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002563 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002564
2565 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002566 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002567 }
2568}
2569
2570void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2571 LocationSummary* locations = mul->GetLocations();
2572 Location first = locations->InAt(0);
2573 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002574 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002575
2576 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002577 case Primitive::kPrimInt:
2578 // The constant may have ended up in a register, so test explicitly to avoid
2579 // problems where the output may not be the same as the first operand.
2580 if (mul->InputAt(1)->IsIntConstant()) {
2581 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2582 __ imull(out.AsRegister<Register>(), first.AsRegister<Register>(), imm);
2583 } else if (second.IsRegister()) {
2584 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002585 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002586 } else {
2587 DCHECK(second.IsStackSlot());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002588 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002589 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002590 }
2591 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002592
2593 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002594 Register in1_hi = first.AsRegisterPairHigh<Register>();
2595 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002596 Register eax = locations->GetTemp(0).AsRegister<Register>();
2597 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002598
2599 DCHECK_EQ(EAX, eax);
2600 DCHECK_EQ(EDX, edx);
2601
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002602 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002603 // output: in1
2604 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2605 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2606 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002607 if (second.IsConstant()) {
2608 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002609
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002610 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2611 int32_t low_value = Low32Bits(value);
2612 int32_t high_value = High32Bits(value);
2613 Immediate low(low_value);
2614 Immediate high(high_value);
2615
2616 __ movl(eax, high);
2617 // eax <- in1.lo * in2.hi
2618 __ imull(eax, in1_lo);
2619 // in1.hi <- in1.hi * in2.lo
2620 __ imull(in1_hi, low);
2621 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2622 __ addl(in1_hi, eax);
2623 // move in2_lo to eax to prepare for double precision
2624 __ movl(eax, low);
2625 // edx:eax <- in1.lo * in2.lo
2626 __ mull(in1_lo);
2627 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2628 __ addl(in1_hi, edx);
2629 // in1.lo <- (in1.lo * in2.lo)[31:0];
2630 __ movl(in1_lo, eax);
2631 } else if (second.IsRegisterPair()) {
2632 Register in2_hi = second.AsRegisterPairHigh<Register>();
2633 Register in2_lo = second.AsRegisterPairLow<Register>();
2634
2635 __ movl(eax, in2_hi);
2636 // eax <- in1.lo * in2.hi
2637 __ imull(eax, in1_lo);
2638 // in1.hi <- in1.hi * in2.lo
2639 __ imull(in1_hi, in2_lo);
2640 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2641 __ addl(in1_hi, eax);
2642 // move in1_lo to eax to prepare for double precision
2643 __ movl(eax, in1_lo);
2644 // edx:eax <- in1.lo * in2.lo
2645 __ mull(in2_lo);
2646 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2647 __ addl(in1_hi, edx);
2648 // in1.lo <- (in1.lo * in2.lo)[31:0];
2649 __ movl(in1_lo, eax);
2650 } else {
2651 DCHECK(second.IsDoubleStackSlot()) << second;
2652 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2653 Address in2_lo(ESP, second.GetStackIndex());
2654
2655 __ movl(eax, in2_hi);
2656 // eax <- in1.lo * in2.hi
2657 __ imull(eax, in1_lo);
2658 // in1.hi <- in1.hi * in2.lo
2659 __ imull(in1_hi, in2_lo);
2660 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2661 __ addl(in1_hi, eax);
2662 // move in1_lo to eax to prepare for double precision
2663 __ movl(eax, in1_lo);
2664 // edx:eax <- in1.lo * in2.lo
2665 __ mull(in2_lo);
2666 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2667 __ addl(in1_hi, edx);
2668 // in1.lo <- (in1.lo * in2.lo)[31:0];
2669 __ movl(in1_lo, eax);
2670 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002671
2672 break;
2673 }
2674
Calin Juravleb5bfa962014-10-21 18:02:24 +01002675 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002676 DCHECK(first.Equals(locations->Out()));
2677 if (second.IsFpuRegister()) {
2678 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2679 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2680 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2681 DCHECK(!const_area->NeedsMaterialization());
2682 __ mulss(first.AsFpuRegister<XmmRegister>(),
2683 codegen_->LiteralFloatAddress(
2684 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2685 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2686 } else {
2687 DCHECK(second.IsStackSlot());
2688 __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2689 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002690 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002691 }
2692
2693 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002694 DCHECK(first.Equals(locations->Out()));
2695 if (second.IsFpuRegister()) {
2696 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2697 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2698 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2699 DCHECK(!const_area->NeedsMaterialization());
2700 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2701 codegen_->LiteralDoubleAddress(
2702 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2703 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2704 } else {
2705 DCHECK(second.IsDoubleStackSlot());
2706 __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2707 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002708 break;
2709 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002710
2711 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002712 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002713 }
2714}
2715
Roland Levillain232ade02015-04-20 15:14:36 +01002716void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
2717 uint32_t temp_offset,
2718 uint32_t stack_adjustment,
2719 bool is_fp,
2720 bool is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002721 if (source.IsStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002722 DCHECK(!is_wide);
2723 if (is_fp) {
2724 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2725 } else {
2726 __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2727 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002728 } else if (source.IsDoubleStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002729 DCHECK(is_wide);
2730 if (is_fp) {
2731 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2732 } else {
2733 __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2734 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002735 } else {
2736 // Write the value to the temporary location on the stack and load to FP stack.
Roland Levillain232ade02015-04-20 15:14:36 +01002737 if (!is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002738 Location stack_temp = Location::StackSlot(temp_offset);
2739 codegen_->Move32(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002740 if (is_fp) {
2741 __ flds(Address(ESP, temp_offset));
2742 } else {
2743 __ filds(Address(ESP, temp_offset));
2744 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002745 } else {
2746 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2747 codegen_->Move64(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002748 if (is_fp) {
2749 __ fldl(Address(ESP, temp_offset));
2750 } else {
2751 __ fildl(Address(ESP, temp_offset));
2752 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002753 }
2754 }
2755}
2756
2757void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2758 Primitive::Type type = rem->GetResultType();
2759 bool is_float = type == Primitive::kPrimFloat;
2760 size_t elem_size = Primitive::ComponentSize(type);
2761 LocationSummary* locations = rem->GetLocations();
2762 Location first = locations->InAt(0);
2763 Location second = locations->InAt(1);
2764 Location out = locations->Out();
2765
2766 // Create stack space for 2 elements.
2767 // TODO: enhance register allocator to ask for stack temporaries.
2768 __ subl(ESP, Immediate(2 * elem_size));
2769
2770 // Load the values to the FP stack in reverse order, using temporaries if needed.
Roland Levillain232ade02015-04-20 15:14:36 +01002771 const bool is_wide = !is_float;
2772 PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp */ true, is_wide);
2773 PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp */ true, is_wide);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002774
2775 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002776 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002777 __ Bind(&retry);
2778 __ fprem();
2779
2780 // Move FP status to AX.
2781 __ fstsw();
2782
2783 // And see if the argument reduction is complete. This is signaled by the
2784 // C2 FPU flag bit set to 0.
2785 __ andl(EAX, Immediate(kC2ConditionMask));
2786 __ j(kNotEqual, &retry);
2787
2788 // We have settled on the final value. Retrieve it into an XMM register.
2789 // Store FP top of stack to real stack.
2790 if (is_float) {
2791 __ fsts(Address(ESP, 0));
2792 } else {
2793 __ fstl(Address(ESP, 0));
2794 }
2795
2796 // Pop the 2 items from the FP stack.
2797 __ fucompp();
2798
2799 // Load the value from the stack into an XMM register.
2800 DCHECK(out.IsFpuRegister()) << out;
2801 if (is_float) {
2802 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2803 } else {
2804 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2805 }
2806
2807 // And remove the temporary stack space we allocated.
2808 __ addl(ESP, Immediate(2 * elem_size));
2809}
2810
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002811
2812void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2813 DCHECK(instruction->IsDiv() || instruction->IsRem());
2814
2815 LocationSummary* locations = instruction->GetLocations();
2816 DCHECK(locations->InAt(1).IsConstant());
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002817 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002818
2819 Register out_register = locations->Out().AsRegister<Register>();
2820 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002821 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002822
2823 DCHECK(imm == 1 || imm == -1);
2824
2825 if (instruction->IsRem()) {
2826 __ xorl(out_register, out_register);
2827 } else {
2828 __ movl(out_register, input_register);
2829 if (imm == -1) {
2830 __ negl(out_register);
2831 }
2832 }
2833}
2834
2835
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002836void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002837 LocationSummary* locations = instruction->GetLocations();
2838
2839 Register out_register = locations->Out().AsRegister<Register>();
2840 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002841 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002842
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002843 DCHECK(IsPowerOfTwo(std::abs(imm)));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002844 Register num = locations->GetTemp(0).AsRegister<Register>();
2845
2846 __ leal(num, Address(input_register, std::abs(imm) - 1));
2847 __ testl(input_register, input_register);
2848 __ cmovl(kGreaterEqual, num, input_register);
2849 int shift = CTZ(imm);
2850 __ sarl(num, Immediate(shift));
2851
2852 if (imm < 0) {
2853 __ negl(num);
2854 }
2855
2856 __ movl(out_register, num);
2857}
2858
2859void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2860 DCHECK(instruction->IsDiv() || instruction->IsRem());
2861
2862 LocationSummary* locations = instruction->GetLocations();
2863 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2864
2865 Register eax = locations->InAt(0).AsRegister<Register>();
2866 Register out = locations->Out().AsRegister<Register>();
2867 Register num;
2868 Register edx;
2869
2870 if (instruction->IsDiv()) {
2871 edx = locations->GetTemp(0).AsRegister<Register>();
2872 num = locations->GetTemp(1).AsRegister<Register>();
2873 } else {
2874 edx = locations->Out().AsRegister<Register>();
2875 num = locations->GetTemp(0).AsRegister<Register>();
2876 }
2877
2878 DCHECK_EQ(EAX, eax);
2879 DCHECK_EQ(EDX, edx);
2880 if (instruction->IsDiv()) {
2881 DCHECK_EQ(EAX, out);
2882 } else {
2883 DCHECK_EQ(EDX, out);
2884 }
2885
2886 int64_t magic;
2887 int shift;
2888 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2889
Mark Mendell0c9497d2015-08-21 09:30:05 -04002890 NearLabel ndiv;
2891 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002892 // If numerator is 0, the result is 0, no computation needed.
2893 __ testl(eax, eax);
2894 __ j(kNotEqual, &ndiv);
2895
2896 __ xorl(out, out);
2897 __ jmp(&end);
2898
2899 __ Bind(&ndiv);
2900
2901 // Save the numerator.
2902 __ movl(num, eax);
2903
2904 // EAX = magic
2905 __ movl(eax, Immediate(magic));
2906
2907 // EDX:EAX = magic * numerator
2908 __ imull(num);
2909
2910 if (imm > 0 && magic < 0) {
2911 // EDX += num
2912 __ addl(edx, num);
2913 } else if (imm < 0 && magic > 0) {
2914 __ subl(edx, num);
2915 }
2916
2917 // Shift if needed.
2918 if (shift != 0) {
2919 __ sarl(edx, Immediate(shift));
2920 }
2921
2922 // EDX += 1 if EDX < 0
2923 __ movl(eax, edx);
2924 __ shrl(edx, Immediate(31));
2925 __ addl(edx, eax);
2926
2927 if (instruction->IsRem()) {
2928 __ movl(eax, num);
2929 __ imull(edx, Immediate(imm));
2930 __ subl(eax, edx);
2931 __ movl(edx, eax);
2932 } else {
2933 __ movl(eax, edx);
2934 }
2935 __ Bind(&end);
2936}
2937
Calin Juravlebacfec32014-11-14 15:54:36 +00002938void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2939 DCHECK(instruction->IsDiv() || instruction->IsRem());
2940
2941 LocationSummary* locations = instruction->GetLocations();
2942 Location out = locations->Out();
2943 Location first = locations->InAt(0);
2944 Location second = locations->InAt(1);
2945 bool is_div = instruction->IsDiv();
2946
2947 switch (instruction->GetResultType()) {
2948 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002949 DCHECK_EQ(EAX, first.AsRegister<Register>());
2950 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002951
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002952 if (instruction->InputAt(1)->IsIntConstant()) {
2953 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002954
2955 if (imm == 0) {
2956 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
2957 } else if (imm == 1 || imm == -1) {
2958 DivRemOneOrMinusOne(instruction);
2959 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002960 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002961 } else {
2962 DCHECK(imm <= -2 || imm >= 2);
2963 GenerateDivRemWithAnyConstant(instruction);
2964 }
2965 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07002966 SlowPathCode* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002967 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002968 is_div);
2969 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002970
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002971 Register second_reg = second.AsRegister<Register>();
2972 // 0x80000000/-1 triggers an arithmetic exception!
2973 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2974 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002975
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002976 __ cmpl(second_reg, Immediate(-1));
2977 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002978
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002979 // edx:eax <- sign-extended of eax
2980 __ cdq();
2981 // eax = quotient, edx = remainder
2982 __ idivl(second_reg);
2983 __ Bind(slow_path->GetExitLabel());
2984 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002985 break;
2986 }
2987
2988 case Primitive::kPrimLong: {
2989 InvokeRuntimeCallingConvention calling_convention;
2990 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2991 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2992 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2993 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2994 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2995 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2996
2997 if (is_div) {
Alexandre Rames8158f282015-08-07 10:26:17 +01002998 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv),
2999 instruction,
3000 instruction->GetDexPc(),
3001 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00003002 } else {
Alexandre Rames8158f282015-08-07 10:26:17 +01003003 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod),
3004 instruction,
3005 instruction->GetDexPc(),
3006 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00003007 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003008 break;
3009 }
3010
3011 default:
3012 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
3013 }
3014}
3015
Calin Juravle7c4954d2014-10-28 16:57:40 +00003016void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003017 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003018 ? LocationSummary::kCall
3019 : LocationSummary::kNoCall;
3020 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
3021
Calin Juravle7c4954d2014-10-28 16:57:40 +00003022 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00003023 case Primitive::kPrimInt: {
3024 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003025 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003026 locations->SetOut(Location::SameAsFirstInput());
3027 // Intel uses edx:eax as the dividend.
3028 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003029 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3030 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
3031 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003032 if (div->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003033 locations->AddTemp(Location::RequiresRegister());
3034 }
Calin Juravled0d48522014-11-04 16:40:20 +00003035 break;
3036 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003037 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003038 InvokeRuntimeCallingConvention calling_convention;
3039 locations->SetInAt(0, Location::RegisterPairLocation(
3040 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3041 locations->SetInAt(1, Location::RegisterPairLocation(
3042 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3043 // Runtime helper puts the result in EAX, EDX.
3044 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00003045 break;
3046 }
3047 case Primitive::kPrimFloat:
3048 case Primitive::kPrimDouble: {
3049 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04003050 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003051 locations->SetOut(Location::SameAsFirstInput());
3052 break;
3053 }
3054
3055 default:
3056 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3057 }
3058}
3059
3060void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
3061 LocationSummary* locations = div->GetLocations();
3062 Location first = locations->InAt(0);
3063 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003064
3065 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003066 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00003067 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003068 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003069 break;
3070 }
3071
3072 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003073 if (second.IsFpuRegister()) {
3074 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3075 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3076 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3077 DCHECK(!const_area->NeedsMaterialization());
3078 __ divss(first.AsFpuRegister<XmmRegister>(),
3079 codegen_->LiteralFloatAddress(
3080 const_area->GetConstant()->AsFloatConstant()->GetValue(),
3081 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3082 } else {
3083 DCHECK(second.IsStackSlot());
3084 __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3085 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003086 break;
3087 }
3088
3089 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003090 if (second.IsFpuRegister()) {
3091 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3092 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3093 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3094 DCHECK(!const_area->NeedsMaterialization());
3095 __ divsd(first.AsFpuRegister<XmmRegister>(),
3096 codegen_->LiteralDoubleAddress(
3097 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
3098 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3099 } else {
3100 DCHECK(second.IsDoubleStackSlot());
3101 __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3102 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003103 break;
3104 }
3105
3106 default:
3107 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3108 }
3109}
3110
Calin Juravlebacfec32014-11-14 15:54:36 +00003111void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003112 Primitive::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003113
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003114 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
3115 ? LocationSummary::kCall
3116 : LocationSummary::kNoCall;
3117 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00003118
Calin Juravled2ec87d2014-12-08 14:24:46 +00003119 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003120 case Primitive::kPrimInt: {
3121 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003122 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003123 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003124 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3125 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
3126 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003127 if (rem->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003128 locations->AddTemp(Location::RequiresRegister());
3129 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003130 break;
3131 }
3132 case Primitive::kPrimLong: {
3133 InvokeRuntimeCallingConvention calling_convention;
3134 locations->SetInAt(0, Location::RegisterPairLocation(
3135 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3136 locations->SetInAt(1, Location::RegisterPairLocation(
3137 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3138 // Runtime helper puts the result in EAX, EDX.
3139 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
3140 break;
3141 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003142 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003143 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003144 locations->SetInAt(0, Location::Any());
3145 locations->SetInAt(1, Location::Any());
3146 locations->SetOut(Location::RequiresFpuRegister());
3147 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003148 break;
3149 }
3150
3151 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003152 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003153 }
3154}
3155
3156void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
3157 Primitive::Type type = rem->GetResultType();
3158 switch (type) {
3159 case Primitive::kPrimInt:
3160 case Primitive::kPrimLong: {
3161 GenerateDivRemIntegral(rem);
3162 break;
3163 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003164 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00003165 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003166 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00003167 break;
3168 }
3169 default:
3170 LOG(FATAL) << "Unexpected rem type " << type;
3171 }
3172}
3173
Calin Juravled0d48522014-11-04 16:40:20 +00003174void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003175 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3176 ? LocationSummary::kCallOnSlowPath
3177 : LocationSummary::kNoCall;
3178 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003179 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003180 case Primitive::kPrimByte:
3181 case Primitive::kPrimChar:
3182 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003183 case Primitive::kPrimInt: {
3184 locations->SetInAt(0, Location::Any());
3185 break;
3186 }
3187 case Primitive::kPrimLong: {
3188 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3189 if (!instruction->IsConstant()) {
3190 locations->AddTemp(Location::RequiresRegister());
3191 }
3192 break;
3193 }
3194 default:
3195 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3196 }
Calin Juravled0d48522014-11-04 16:40:20 +00003197 if (instruction->HasUses()) {
3198 locations->SetOut(Location::SameAsFirstInput());
3199 }
3200}
3201
3202void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003203 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003204 codegen_->AddSlowPath(slow_path);
3205
3206 LocationSummary* locations = instruction->GetLocations();
3207 Location value = locations->InAt(0);
3208
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003209 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003210 case Primitive::kPrimByte:
3211 case Primitive::kPrimChar:
3212 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003213 case Primitive::kPrimInt: {
3214 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003215 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003216 __ j(kEqual, slow_path->GetEntryLabel());
3217 } else if (value.IsStackSlot()) {
3218 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
3219 __ j(kEqual, slow_path->GetEntryLabel());
3220 } else {
3221 DCHECK(value.IsConstant()) << value;
3222 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3223 __ jmp(slow_path->GetEntryLabel());
3224 }
3225 }
3226 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003227 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003228 case Primitive::kPrimLong: {
3229 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003230 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003231 __ movl(temp, value.AsRegisterPairLow<Register>());
3232 __ orl(temp, value.AsRegisterPairHigh<Register>());
3233 __ j(kEqual, slow_path->GetEntryLabel());
3234 } else {
3235 DCHECK(value.IsConstant()) << value;
3236 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3237 __ jmp(slow_path->GetEntryLabel());
3238 }
3239 }
3240 break;
3241 }
3242 default:
3243 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003244 }
Calin Juravled0d48522014-11-04 16:40:20 +00003245}
3246
Calin Juravle9aec02f2014-11-18 23:06:35 +00003247void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
3248 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3249
3250 LocationSummary* locations =
3251 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3252
3253 switch (op->GetResultType()) {
Mark P Mendell73945692015-04-29 14:56:17 +00003254 case Primitive::kPrimInt:
Calin Juravle9aec02f2014-11-18 23:06:35 +00003255 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003256 // Can't have Location::Any() and output SameAsFirstInput()
Calin Juravle9aec02f2014-11-18 23:06:35 +00003257 locations->SetInAt(0, Location::RequiresRegister());
Mark P Mendell73945692015-04-29 14:56:17 +00003258 // The shift count needs to be in CL or a constant.
3259 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003260 locations->SetOut(Location::SameAsFirstInput());
3261 break;
3262 }
3263 default:
3264 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3265 }
3266}
3267
3268void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
3269 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3270
3271 LocationSummary* locations = op->GetLocations();
3272 Location first = locations->InAt(0);
3273 Location second = locations->InAt(1);
3274 DCHECK(first.Equals(locations->Out()));
3275
3276 switch (op->GetResultType()) {
3277 case Primitive::kPrimInt: {
Mark P Mendell73945692015-04-29 14:56:17 +00003278 DCHECK(first.IsRegister());
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003279 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003280 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003281 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003282 DCHECK_EQ(ECX, second_reg);
3283 if (op->IsShl()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003284 __ shll(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003285 } else if (op->IsShr()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003286 __ sarl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003287 } else {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003288 __ shrl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003289 }
3290 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003291 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue;
3292 if (shift == 0) {
3293 return;
3294 }
3295 Immediate imm(shift);
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003296 if (op->IsShl()) {
3297 __ shll(first_reg, imm);
3298 } else if (op->IsShr()) {
3299 __ sarl(first_reg, imm);
3300 } else {
3301 __ shrl(first_reg, imm);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003302 }
3303 }
3304 break;
3305 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003306 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003307 if (second.IsRegister()) {
3308 Register second_reg = second.AsRegister<Register>();
3309 DCHECK_EQ(ECX, second_reg);
3310 if (op->IsShl()) {
3311 GenerateShlLong(first, second_reg);
3312 } else if (op->IsShr()) {
3313 GenerateShrLong(first, second_reg);
3314 } else {
3315 GenerateUShrLong(first, second_reg);
3316 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003317 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003318 // Shift by a constant.
3319 int shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue;
3320 // Nothing to do if the shift is 0, as the input is already the output.
3321 if (shift != 0) {
3322 if (op->IsShl()) {
3323 GenerateShlLong(first, shift);
3324 } else if (op->IsShr()) {
3325 GenerateShrLong(first, shift);
3326 } else {
3327 GenerateUShrLong(first, shift);
3328 }
3329 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003330 }
3331 break;
3332 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003333 default:
3334 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3335 }
3336}
3337
Mark P Mendell73945692015-04-29 14:56:17 +00003338void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
3339 Register low = loc.AsRegisterPairLow<Register>();
3340 Register high = loc.AsRegisterPairHigh<Register>();
Mark Mendellba56d062015-05-05 21:34:03 -04003341 if (shift == 1) {
3342 // This is just an addition.
3343 __ addl(low, low);
3344 __ adcl(high, high);
3345 } else if (shift == 32) {
Mark P Mendell73945692015-04-29 14:56:17 +00003346 // Shift by 32 is easy. High gets low, and low gets 0.
3347 codegen_->EmitParallelMoves(
3348 loc.ToLow(),
3349 loc.ToHigh(),
3350 Primitive::kPrimInt,
3351 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3352 loc.ToLow(),
3353 Primitive::kPrimInt);
3354 } else if (shift > 32) {
3355 // Low part becomes 0. High part is low part << (shift-32).
3356 __ movl(high, low);
3357 __ shll(high, Immediate(shift - 32));
3358 __ xorl(low, low);
3359 } else {
3360 // Between 1 and 31.
3361 __ shld(high, low, Immediate(shift));
3362 __ shll(low, Immediate(shift));
3363 }
3364}
3365
Calin Juravle9aec02f2014-11-18 23:06:35 +00003366void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003367 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003368 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
3369 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
3370 __ testl(shifter, Immediate(32));
3371 __ j(kEqual, &done);
3372 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
3373 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
3374 __ Bind(&done);
3375}
3376
Mark P Mendell73945692015-04-29 14:56:17 +00003377void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
3378 Register low = loc.AsRegisterPairLow<Register>();
3379 Register high = loc.AsRegisterPairHigh<Register>();
3380 if (shift == 32) {
3381 // Need to copy the sign.
3382 DCHECK_NE(low, high);
3383 __ movl(low, high);
3384 __ sarl(high, Immediate(31));
3385 } else if (shift > 32) {
3386 DCHECK_NE(low, high);
3387 // High part becomes sign. Low part is shifted by shift - 32.
3388 __ movl(low, high);
3389 __ sarl(high, Immediate(31));
3390 __ sarl(low, Immediate(shift - 32));
3391 } else {
3392 // Between 1 and 31.
3393 __ shrd(low, high, Immediate(shift));
3394 __ sarl(high, Immediate(shift));
3395 }
3396}
3397
Calin Juravle9aec02f2014-11-18 23:06:35 +00003398void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003399 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003400 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3401 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
3402 __ testl(shifter, Immediate(32));
3403 __ j(kEqual, &done);
3404 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3405 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
3406 __ Bind(&done);
3407}
3408
Mark P Mendell73945692015-04-29 14:56:17 +00003409void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
3410 Register low = loc.AsRegisterPairLow<Register>();
3411 Register high = loc.AsRegisterPairHigh<Register>();
3412 if (shift == 32) {
3413 // Shift by 32 is easy. Low gets high, and high gets 0.
3414 codegen_->EmitParallelMoves(
3415 loc.ToHigh(),
3416 loc.ToLow(),
3417 Primitive::kPrimInt,
3418 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3419 loc.ToHigh(),
3420 Primitive::kPrimInt);
3421 } else if (shift > 32) {
3422 // Low part is high >> (shift - 32). High part becomes 0.
3423 __ movl(low, high);
3424 __ shrl(low, Immediate(shift - 32));
3425 __ xorl(high, high);
3426 } else {
3427 // Between 1 and 31.
3428 __ shrd(low, high, Immediate(shift));
3429 __ shrl(high, Immediate(shift));
3430 }
3431}
3432
Calin Juravle9aec02f2014-11-18 23:06:35 +00003433void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003434 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003435 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3436 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
3437 __ testl(shifter, Immediate(32));
3438 __ j(kEqual, &done);
3439 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3440 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
3441 __ Bind(&done);
3442}
3443
3444void LocationsBuilderX86::VisitShl(HShl* shl) {
3445 HandleShift(shl);
3446}
3447
3448void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
3449 HandleShift(shl);
3450}
3451
3452void LocationsBuilderX86::VisitShr(HShr* shr) {
3453 HandleShift(shr);
3454}
3455
3456void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
3457 HandleShift(shr);
3458}
3459
3460void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
3461 HandleShift(ushr);
3462}
3463
3464void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
3465 HandleShift(ushr);
3466}
3467
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003468void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003469 LocationSummary* locations =
3470 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003471 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003472 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003473 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003474 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003475}
3476
3477void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
3478 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003479 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01003480 // Note: if heap poisoning is enabled, the entry point takes cares
3481 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003482 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3483 instruction,
3484 instruction->GetDexPc(),
3485 nullptr);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003486 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003487}
3488
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003489void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
3490 LocationSummary* locations =
3491 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3492 locations->SetOut(Location::RegisterLocation(EAX));
3493 InvokeRuntimeCallingConvention calling_convention;
3494 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003495 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003496 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003497}
3498
3499void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
3500 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003501 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
3502
Roland Levillain4d027112015-07-01 15:41:14 +01003503 // Note: if heap poisoning is enabled, the entry point takes cares
3504 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003505 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3506 instruction,
3507 instruction->GetDexPc(),
3508 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003509 DCHECK(!codegen_->IsLeafMethod());
3510}
3511
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003512void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003513 LocationSummary* locations =
3514 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003515 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3516 if (location.IsStackSlot()) {
3517 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3518 } else if (location.IsDoubleStackSlot()) {
3519 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003520 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003521 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003522}
3523
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003524void InstructionCodeGeneratorX86::VisitParameterValue(
3525 HParameterValue* instruction ATTRIBUTE_UNUSED) {
3526}
3527
3528void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
3529 LocationSummary* locations =
3530 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3531 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3532}
3533
3534void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003535}
3536
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003537void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003538 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003539 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003540 locations->SetInAt(0, Location::RequiresRegister());
3541 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003542}
3543
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003544void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
3545 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01003546 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003547 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01003548 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003549 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003550 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003551 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003552 break;
3553
3554 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003555 __ notl(out.AsRegisterPairLow<Register>());
3556 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003557 break;
3558
3559 default:
3560 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3561 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003562}
3563
David Brazdil66d126e2015-04-03 16:02:44 +01003564void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
3565 LocationSummary* locations =
3566 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3567 locations->SetInAt(0, Location::RequiresRegister());
3568 locations->SetOut(Location::SameAsFirstInput());
3569}
3570
3571void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003572 LocationSummary* locations = bool_not->GetLocations();
3573 Location in = locations->InAt(0);
3574 Location out = locations->Out();
3575 DCHECK(in.Equals(out));
3576 __ xorl(out.AsRegister<Register>(), Immediate(1));
3577}
3578
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003579void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003580 LocationSummary* locations =
3581 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003582 switch (compare->InputAt(0)->GetType()) {
3583 case Primitive::kPrimLong: {
3584 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00003585 locations->SetInAt(1, Location::Any());
3586 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3587 break;
3588 }
3589 case Primitive::kPrimFloat:
3590 case Primitive::kPrimDouble: {
3591 locations->SetInAt(0, Location::RequiresFpuRegister());
3592 locations->SetInAt(1, Location::RequiresFpuRegister());
3593 locations->SetOut(Location::RequiresRegister());
3594 break;
3595 }
3596 default:
3597 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3598 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003599}
3600
3601void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003602 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003603 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003604 Location left = locations->InAt(0);
3605 Location right = locations->InAt(1);
3606
Mark Mendell0c9497d2015-08-21 09:30:05 -04003607 NearLabel less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003608 switch (compare->InputAt(0)->GetType()) {
3609 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003610 Register left_low = left.AsRegisterPairLow<Register>();
3611 Register left_high = left.AsRegisterPairHigh<Register>();
3612 int32_t val_low = 0;
3613 int32_t val_high = 0;
3614 bool right_is_const = false;
3615
3616 if (right.IsConstant()) {
3617 DCHECK(right.GetConstant()->IsLongConstant());
3618 right_is_const = true;
3619 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
3620 val_low = Low32Bits(val);
3621 val_high = High32Bits(val);
3622 }
3623
Calin Juravleddb7df22014-11-25 20:56:51 +00003624 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003625 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003626 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003627 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003628 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003629 DCHECK(right_is_const) << right;
3630 if (val_high == 0) {
3631 __ testl(left_high, left_high);
3632 } else {
3633 __ cmpl(left_high, Immediate(val_high));
3634 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003635 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003636 __ j(kLess, &less); // Signed compare.
3637 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003638 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003639 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003640 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003641 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003642 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003643 DCHECK(right_is_const) << right;
3644 if (val_low == 0) {
3645 __ testl(left_low, left_low);
3646 } else {
3647 __ cmpl(left_low, Immediate(val_low));
3648 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003649 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003650 break;
3651 }
3652 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003653 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003654 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
3655 break;
3656 }
3657 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003658 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003659 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003660 break;
3661 }
3662 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003663 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003664 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003665 __ movl(out, Immediate(0));
3666 __ j(kEqual, &done);
3667 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
3668
3669 __ Bind(&greater);
3670 __ movl(out, Immediate(1));
3671 __ jmp(&done);
3672
3673 __ Bind(&less);
3674 __ movl(out, Immediate(-1));
3675
3676 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003677}
3678
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003679void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003680 LocationSummary* locations =
3681 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003682 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3683 locations->SetInAt(i, Location::Any());
3684 }
3685 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003686}
3687
3688void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003689 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003690 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003691}
3692
Calin Juravle52c48962014-12-16 17:02:57 +00003693void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
3694 /*
3695 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3696 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3697 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3698 */
3699 switch (kind) {
3700 case MemBarrierKind::kAnyAny: {
3701 __ mfence();
3702 break;
3703 }
3704 case MemBarrierKind::kAnyStore:
3705 case MemBarrierKind::kLoadAny:
3706 case MemBarrierKind::kStoreStore: {
3707 // nop
3708 break;
3709 }
3710 default:
3711 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003712 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003713}
3714
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003715
Vladimir Marko58155012015-08-19 12:49:41 +00003716void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
3717 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
3718 switch (invoke->GetMethodLoadKind()) {
3719 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
3720 // temp = thread->string_init_entrypoint
3721 __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(invoke->GetStringInitOffset()));
3722 break;
3723 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
3724 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3725 break;
3726 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
3727 __ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress()));
3728 break;
3729 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
3730 __ movl(temp.AsRegister<Register>(), Immediate(0)); // Placeholder.
3731 method_patches_.emplace_back(invoke->GetTargetMethod());
3732 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
3733 break;
3734 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
3735 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
3736 FALLTHROUGH_INTENDED;
3737 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
3738 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3739 Register method_reg;
3740 Register reg = temp.AsRegister<Register>();
3741 if (current_method.IsRegister()) {
3742 method_reg = current_method.AsRegister<Register>();
3743 } else {
3744 DCHECK(IsBaseline() || invoke->GetLocations()->Intrinsified());
3745 DCHECK(!current_method.IsValid());
3746 method_reg = reg;
3747 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
3748 }
3749 // temp = temp->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +01003750 __ movl(reg, Address(method_reg,
3751 ArtMethod::DexCacheResolvedMethodsOffset(kX86PointerSize).Int32Value()));
Vladimir Marko58155012015-08-19 12:49:41 +00003752 // temp = temp[index_in_cache]
3753 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
3754 __ movl(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
3755 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +01003756 }
Vladimir Marko58155012015-08-19 12:49:41 +00003757 }
3758
3759 switch (invoke->GetCodePtrLocation()) {
3760 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
3761 __ call(GetFrameEntryLabel());
3762 break;
3763 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
3764 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
3765 Label* label = &relative_call_patches_.back().label;
3766 __ call(label); // Bind to the patch label, override at link time.
3767 __ Bind(label); // Bind the label at the end of the "call" insn.
3768 break;
3769 }
3770 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
3771 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
3772 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
3773 // (Though the direct CALL ptr16:32 is available for consideration).
3774 FALLTHROUGH_INTENDED;
3775 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
3776 // (callee_method + offset_of_quick_compiled_code)()
3777 __ call(Address(callee_method.AsRegister<Register>(),
3778 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
3779 kX86WordSize).Int32Value()));
3780 break;
Mark Mendell09ed1a32015-03-25 08:30:06 -04003781 }
3782
3783 DCHECK(!IsLeafMethod());
Mark Mendell09ed1a32015-03-25 08:30:06 -04003784}
3785
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003786void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
3787 Register temp = temp_in.AsRegister<Register>();
3788 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
3789 invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
3790 LocationSummary* locations = invoke->GetLocations();
3791 Location receiver = locations->InAt(0);
3792 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3793 // temp = object->GetClass();
3794 DCHECK(receiver.IsRegister());
3795 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
3796 MaybeRecordImplicitNullCheck(invoke);
3797 __ MaybeUnpoisonHeapReference(temp);
3798 // temp = temp->GetMethodAt(method_offset);
3799 __ movl(temp, Address(temp, method_offset));
3800 // call temp->GetEntryPoint();
3801 __ call(Address(
3802 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3803}
3804
Vladimir Marko58155012015-08-19 12:49:41 +00003805void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
3806 DCHECK(linker_patches->empty());
3807 linker_patches->reserve(method_patches_.size() + relative_call_patches_.size());
3808 for (const MethodPatchInfo<Label>& info : method_patches_) {
3809 // The label points to the end of the "movl" insn but the literal offset for method
3810 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3811 uint32_t literal_offset = info.label.Position() - 4;
3812 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
3813 info.target_method.dex_file,
3814 info.target_method.dex_method_index));
3815 }
3816 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
3817 // The label points to the end of the "call" insn but the literal offset for method
3818 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3819 uint32_t literal_offset = info.label.Position() - 4;
3820 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
3821 info.target_method.dex_file,
3822 info.target_method.dex_method_index));
3823 }
3824}
3825
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003826void CodeGeneratorX86::MarkGCCard(Register temp,
3827 Register card,
3828 Register object,
3829 Register value,
3830 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003831 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003832 if (value_can_be_null) {
3833 __ testl(value, value);
3834 __ j(kEqual, &is_null);
3835 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003836 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3837 __ movl(temp, object);
3838 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003839 __ movb(Address(temp, card, TIMES_1, 0),
3840 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003841 if (value_can_be_null) {
3842 __ Bind(&is_null);
3843 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003844}
3845
Calin Juravle52c48962014-12-16 17:02:57 +00003846void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3847 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003848 LocationSummary* locations =
3849 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003850 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003851
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003852 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3853 locations->SetOut(Location::RequiresFpuRegister());
3854 } else {
3855 // The output overlaps in case of long: we don't want the low move to overwrite
3856 // the object's location.
3857 locations->SetOut(Location::RequiresRegister(),
3858 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3859 : Location::kNoOutputOverlap);
3860 }
Calin Juravle52c48962014-12-16 17:02:57 +00003861
3862 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3863 // Long values can be loaded atomically into an XMM using movsd.
3864 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3865 // and then copy the XMM into the output 32bits at a time).
3866 locations->AddTemp(Location::RequiresFpuRegister());
3867 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003868}
3869
Calin Juravle52c48962014-12-16 17:02:57 +00003870void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3871 const FieldInfo& field_info) {
3872 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003873
Calin Juravle52c48962014-12-16 17:02:57 +00003874 LocationSummary* locations = instruction->GetLocations();
3875 Register base = locations->InAt(0).AsRegister<Register>();
3876 Location out = locations->Out();
3877 bool is_volatile = field_info.IsVolatile();
3878 Primitive::Type field_type = field_info.GetFieldType();
3879 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3880
3881 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003882 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003883 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003884 break;
3885 }
3886
3887 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003888 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003889 break;
3890 }
3891
3892 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003893 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003894 break;
3895 }
3896
3897 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003898 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003899 break;
3900 }
3901
3902 case Primitive::kPrimInt:
3903 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003904 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003905 break;
3906 }
3907
3908 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00003909 if (is_volatile) {
3910 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3911 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003912 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003913 __ movd(out.AsRegisterPairLow<Register>(), temp);
3914 __ psrlq(temp, Immediate(32));
3915 __ movd(out.AsRegisterPairHigh<Register>(), temp);
3916 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003917 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003918 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003919 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003920 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
3921 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003922 break;
3923 }
3924
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003925 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003926 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003927 break;
3928 }
3929
3930 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003931 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003932 break;
3933 }
3934
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003935 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003936 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003937 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003938 }
Calin Juravle52c48962014-12-16 17:02:57 +00003939
Calin Juravle77520bc2015-01-12 18:45:46 +00003940 // Longs are handled in the switch.
3941 if (field_type != Primitive::kPrimLong) {
3942 codegen_->MaybeRecordImplicitNullCheck(instruction);
3943 }
3944
Calin Juravle52c48962014-12-16 17:02:57 +00003945 if (is_volatile) {
3946 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3947 }
Roland Levillain4d027112015-07-01 15:41:14 +01003948
3949 if (field_type == Primitive::kPrimNot) {
3950 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3951 }
Calin Juravle52c48962014-12-16 17:02:57 +00003952}
3953
3954void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3955 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3956
3957 LocationSummary* locations =
3958 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3959 locations->SetInAt(0, Location::RequiresRegister());
3960 bool is_volatile = field_info.IsVolatile();
3961 Primitive::Type field_type = field_info.GetFieldType();
3962 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
3963 || (field_type == Primitive::kPrimByte);
3964
3965 // The register allocator does not support multiple
3966 // inputs that die at entry with one in a specific register.
3967 if (is_byte_type) {
3968 // Ensure the value is in a byte register.
3969 locations->SetInAt(1, Location::RegisterLocation(EAX));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003970 } else if (Primitive::IsFloatingPointType(field_type)) {
3971 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003972 } else {
3973 locations->SetInAt(1, Location::RequiresRegister());
3974 }
Calin Juravle52c48962014-12-16 17:02:57 +00003975 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Roland Levillain4d027112015-07-01 15:41:14 +01003976 // Temporary registers for the write barrier.
3977 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Calin Juravle52c48962014-12-16 17:02:57 +00003978 // Ensure the card is in a byte register.
3979 locations->AddTemp(Location::RegisterLocation(ECX));
3980 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
3981 // 64bits value can be atomically written to an address with movsd and an XMM register.
3982 // We need two XMM registers because there's no easier way to (bit) copy a register pair
3983 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
3984 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
3985 // isolated cases when we need this it isn't worth adding the extra complexity.
3986 locations->AddTemp(Location::RequiresFpuRegister());
3987 locations->AddTemp(Location::RequiresFpuRegister());
3988 }
3989}
3990
3991void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003992 const FieldInfo& field_info,
3993 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003994 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3995
3996 LocationSummary* locations = instruction->GetLocations();
3997 Register base = locations->InAt(0).AsRegister<Register>();
3998 Location value = locations->InAt(1);
3999 bool is_volatile = field_info.IsVolatile();
4000 Primitive::Type field_type = field_info.GetFieldType();
4001 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01004002 bool needs_write_barrier =
4003 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004004
4005 if (is_volatile) {
4006 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4007 }
4008
4009 switch (field_type) {
4010 case Primitive::kPrimBoolean:
4011 case Primitive::kPrimByte: {
4012 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
4013 break;
4014 }
4015
4016 case Primitive::kPrimShort:
4017 case Primitive::kPrimChar: {
4018 __ movw(Address(base, offset), value.AsRegister<Register>());
4019 break;
4020 }
4021
4022 case Primitive::kPrimInt:
4023 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01004024 if (kPoisonHeapReferences && needs_write_barrier) {
4025 // Note that in the case where `value` is a null reference,
4026 // we do not enter this block, as the reference does not
4027 // need poisoning.
4028 DCHECK_EQ(field_type, Primitive::kPrimNot);
4029 Register temp = locations->GetTemp(0).AsRegister<Register>();
4030 __ movl(temp, value.AsRegister<Register>());
4031 __ PoisonHeapReference(temp);
4032 __ movl(Address(base, offset), temp);
4033 } else {
4034 __ movl(Address(base, offset), value.AsRegister<Register>());
4035 }
Calin Juravle52c48962014-12-16 17:02:57 +00004036 break;
4037 }
4038
4039 case Primitive::kPrimLong: {
4040 if (is_volatile) {
4041 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4042 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
4043 __ movd(temp1, value.AsRegisterPairLow<Register>());
4044 __ movd(temp2, value.AsRegisterPairHigh<Register>());
4045 __ punpckldq(temp1, temp2);
4046 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00004047 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004048 } else {
4049 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004050 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004051 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
4052 }
4053 break;
4054 }
4055
4056 case Primitive::kPrimFloat: {
4057 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4058 break;
4059 }
4060
4061 case Primitive::kPrimDouble: {
4062 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4063 break;
4064 }
4065
4066 case Primitive::kPrimVoid:
4067 LOG(FATAL) << "Unreachable type " << field_type;
4068 UNREACHABLE();
4069 }
4070
Calin Juravle77520bc2015-01-12 18:45:46 +00004071 // Longs are handled in the switch.
4072 if (field_type != Primitive::kPrimLong) {
4073 codegen_->MaybeRecordImplicitNullCheck(instruction);
4074 }
4075
Roland Levillain4d027112015-07-01 15:41:14 +01004076 if (needs_write_barrier) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004077 Register temp = locations->GetTemp(0).AsRegister<Register>();
4078 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004079 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004080 }
4081
Calin Juravle52c48962014-12-16 17:02:57 +00004082 if (is_volatile) {
4083 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4084 }
4085}
4086
4087void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4088 HandleFieldGet(instruction, instruction->GetFieldInfo());
4089}
4090
4091void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4092 HandleFieldGet(instruction, instruction->GetFieldInfo());
4093}
4094
4095void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4096 HandleFieldSet(instruction, instruction->GetFieldInfo());
4097}
4098
4099void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004100 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004101}
4102
4103void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4104 HandleFieldSet(instruction, instruction->GetFieldInfo());
4105}
4106
4107void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004108 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004109}
4110
4111void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4112 HandleFieldGet(instruction, instruction->GetFieldInfo());
4113}
4114
4115void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4116 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004117}
4118
Calin Juravlee460d1d2015-09-29 04:52:17 +01004119void LocationsBuilderX86::VisitUnresolvedInstanceFieldGet(
4120 HUnresolvedInstanceFieldGet* instruction) {
4121 FieldAccessCallingConventionX86 calling_convention;
4122 codegen_->CreateUnresolvedFieldLocationSummary(
4123 instruction, instruction->GetFieldType(), calling_convention);
4124}
4125
4126void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldGet(
4127 HUnresolvedInstanceFieldGet* instruction) {
4128 FieldAccessCallingConventionX86 calling_convention;
4129 codegen_->GenerateUnresolvedFieldAccess(instruction,
4130 instruction->GetFieldType(),
4131 instruction->GetFieldIndex(),
4132 instruction->GetDexPc(),
4133 calling_convention);
4134}
4135
4136void LocationsBuilderX86::VisitUnresolvedInstanceFieldSet(
4137 HUnresolvedInstanceFieldSet* instruction) {
4138 FieldAccessCallingConventionX86 calling_convention;
4139 codegen_->CreateUnresolvedFieldLocationSummary(
4140 instruction, instruction->GetFieldType(), calling_convention);
4141}
4142
4143void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldSet(
4144 HUnresolvedInstanceFieldSet* instruction) {
4145 FieldAccessCallingConventionX86 calling_convention;
4146 codegen_->GenerateUnresolvedFieldAccess(instruction,
4147 instruction->GetFieldType(),
4148 instruction->GetFieldIndex(),
4149 instruction->GetDexPc(),
4150 calling_convention);
4151}
4152
4153void LocationsBuilderX86::VisitUnresolvedStaticFieldGet(
4154 HUnresolvedStaticFieldGet* instruction) {
4155 FieldAccessCallingConventionX86 calling_convention;
4156 codegen_->CreateUnresolvedFieldLocationSummary(
4157 instruction, instruction->GetFieldType(), calling_convention);
4158}
4159
4160void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldGet(
4161 HUnresolvedStaticFieldGet* instruction) {
4162 FieldAccessCallingConventionX86 calling_convention;
4163 codegen_->GenerateUnresolvedFieldAccess(instruction,
4164 instruction->GetFieldType(),
4165 instruction->GetFieldIndex(),
4166 instruction->GetDexPc(),
4167 calling_convention);
4168}
4169
4170void LocationsBuilderX86::VisitUnresolvedStaticFieldSet(
4171 HUnresolvedStaticFieldSet* instruction) {
4172 FieldAccessCallingConventionX86 calling_convention;
4173 codegen_->CreateUnresolvedFieldLocationSummary(
4174 instruction, instruction->GetFieldType(), calling_convention);
4175}
4176
4177void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldSet(
4178 HUnresolvedStaticFieldSet* instruction) {
4179 FieldAccessCallingConventionX86 calling_convention;
4180 codegen_->GenerateUnresolvedFieldAccess(instruction,
4181 instruction->GetFieldType(),
4182 instruction->GetFieldIndex(),
4183 instruction->GetDexPc(),
4184 calling_convention);
4185}
4186
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004187void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004188 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4189 ? LocationSummary::kCallOnSlowPath
4190 : LocationSummary::kNoCall;
4191 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4192 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004193 ? Location::RequiresRegister()
4194 : Location::Any();
4195 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004196 if (instruction->HasUses()) {
4197 locations->SetOut(Location::SameAsFirstInput());
4198 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004199}
4200
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004201void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004202 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4203 return;
4204 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004205 LocationSummary* locations = instruction->GetLocations();
4206 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004207
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004208 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
4209 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4210}
4211
4212void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004213 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004214 codegen_->AddSlowPath(slow_path);
4215
4216 LocationSummary* locations = instruction->GetLocations();
4217 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004218
4219 if (obj.IsRegister()) {
Mark Mendell42514f62015-03-31 11:34:22 -04004220 __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004221 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004222 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004223 } else {
4224 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004225 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004226 __ jmp(slow_path->GetEntryLabel());
4227 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004228 }
4229 __ j(kEqual, slow_path->GetEntryLabel());
4230}
4231
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004232void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004233 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004234 GenerateImplicitNullCheck(instruction);
4235 } else {
4236 GenerateExplicitNullCheck(instruction);
4237 }
4238}
4239
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004240void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004241 LocationSummary* locations =
4242 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004243 locations->SetInAt(0, Location::RequiresRegister());
4244 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004245 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4246 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4247 } else {
4248 // The output overlaps in case of long: we don't want the low move to overwrite
4249 // the array's location.
4250 locations->SetOut(Location::RequiresRegister(),
4251 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
4252 : Location::kNoOutputOverlap);
4253 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004254}
4255
4256void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
4257 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004258 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004259 Location index = locations->InAt(1);
4260
Calin Juravle77520bc2015-01-12 18:45:46 +00004261 Primitive::Type type = instruction->GetType();
4262 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004263 case Primitive::kPrimBoolean: {
4264 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004265 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004266 if (index.IsConstant()) {
4267 __ movzxb(out, Address(obj,
4268 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4269 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004270 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004271 }
4272 break;
4273 }
4274
4275 case Primitive::kPrimByte: {
4276 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004277 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004278 if (index.IsConstant()) {
4279 __ movsxb(out, Address(obj,
4280 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4281 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004282 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004283 }
4284 break;
4285 }
4286
4287 case Primitive::kPrimShort: {
4288 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004289 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004290 if (index.IsConstant()) {
4291 __ movsxw(out, Address(obj,
4292 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4293 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004294 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004295 }
4296 break;
4297 }
4298
4299 case Primitive::kPrimChar: {
4300 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004301 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004302 if (index.IsConstant()) {
4303 __ movzxw(out, Address(obj,
4304 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4305 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004306 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004307 }
4308 break;
4309 }
4310
4311 case Primitive::kPrimInt:
4312 case Primitive::kPrimNot: {
4313 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004314 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004315 if (index.IsConstant()) {
4316 __ movl(out, Address(obj,
4317 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4318 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004319 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004320 }
4321 break;
4322 }
4323
4324 case Primitive::kPrimLong: {
4325 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004326 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004327 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004328 if (index.IsConstant()) {
4329 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004330 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004331 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004332 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004333 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004334 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004335 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004336 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004337 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004338 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004339 }
4340 break;
4341 }
4342
Mark Mendell7c8d0092015-01-26 11:21:33 -05004343 case Primitive::kPrimFloat: {
4344 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4345 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4346 if (index.IsConstant()) {
4347 __ movss(out, Address(obj,
4348 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4349 } else {
4350 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
4351 }
4352 break;
4353 }
4354
4355 case Primitive::kPrimDouble: {
4356 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4357 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4358 if (index.IsConstant()) {
4359 __ movsd(out, Address(obj,
4360 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4361 } else {
4362 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
4363 }
4364 break;
4365 }
4366
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004367 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00004368 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004369 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004370 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004371
4372 if (type != Primitive::kPrimLong) {
4373 codegen_->MaybeRecordImplicitNullCheck(instruction);
4374 }
Roland Levillain4d027112015-07-01 15:41:14 +01004375
4376 if (type == Primitive::kPrimNot) {
4377 Register out = locations->Out().AsRegister<Register>();
4378 __ MaybeUnpoisonHeapReference(out);
4379 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004380}
4381
4382void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05004383 // This location builder might end up asking to up to four registers, which is
4384 // not currently possible for baseline. The situation in which we need four
4385 // registers cannot be met by baseline though, because it has not run any
4386 // optimization.
4387
Nicolas Geoffray39468442014-09-02 15:17:15 +01004388 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004389 bool needs_write_barrier =
4390 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4391
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004392 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004393
Nicolas Geoffray39468442014-09-02 15:17:15 +01004394 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4395 instruction,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004396 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004397
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004398 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
4399 || (value_type == Primitive::kPrimByte);
4400 // We need the inputs to be different than the output in case of long operation.
4401 // In case of a byte operation, the register allocator does not support multiple
4402 // inputs that die at entry with one in a specific register.
4403 locations->SetInAt(0, Location::RequiresRegister());
4404 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4405 if (is_byte_type) {
4406 // Ensure the value is in a byte register.
4407 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
4408 } else if (Primitive::IsFloatingPointType(value_type)) {
4409 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004410 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004411 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4412 }
4413 if (needs_write_barrier) {
4414 // Temporary registers for the write barrier.
4415 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
4416 // Ensure the card is in a byte register.
4417 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004418 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004419}
4420
4421void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
4422 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004423 Register array = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004424 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004425 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004426 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004427 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4428 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4429 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4430 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004431 bool needs_write_barrier =
4432 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004433
4434 switch (value_type) {
4435 case Primitive::kPrimBoolean:
4436 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004437 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4438 Address address = index.IsConstant()
4439 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset)
4440 : Address(array, index.AsRegister<Register>(), TIMES_1, offset);
4441 if (value.IsRegister()) {
4442 __ movb(address, value.AsRegister<ByteRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004443 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004444 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004445 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004446 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004447 break;
4448 }
4449
4450 case Primitive::kPrimShort:
4451 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004452 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4453 Address address = index.IsConstant()
4454 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset)
4455 : Address(array, index.AsRegister<Register>(), TIMES_2, offset);
4456 if (value.IsRegister()) {
4457 __ movw(address, value.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004458 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004459 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004460 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004461 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004462 break;
4463 }
4464
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004465 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004466 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4467 Address address = index.IsConstant()
4468 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4469 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
4470 if (!value.IsRegister()) {
4471 // Just setting null.
4472 DCHECK(instruction->InputAt(2)->IsNullConstant());
4473 DCHECK(value.IsConstant()) << value;
4474 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004475 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004476 DCHECK(!needs_write_barrier);
4477 DCHECK(!may_need_runtime_call);
4478 break;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004479 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004480
4481 DCHECK(needs_write_barrier);
4482 Register register_value = value.AsRegister<Register>();
4483 NearLabel done, not_null, do_put;
4484 SlowPathCode* slow_path = nullptr;
4485 Register temp = locations->GetTemp(0).AsRegister<Register>();
4486 if (may_need_runtime_call) {
4487 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86(instruction);
4488 codegen_->AddSlowPath(slow_path);
4489 if (instruction->GetValueCanBeNull()) {
4490 __ testl(register_value, register_value);
4491 __ j(kNotEqual, &not_null);
4492 __ movl(address, Immediate(0));
4493 codegen_->MaybeRecordImplicitNullCheck(instruction);
4494 __ jmp(&done);
4495 __ Bind(&not_null);
4496 }
4497
4498 __ movl(temp, Address(array, class_offset));
4499 codegen_->MaybeRecordImplicitNullCheck(instruction);
4500 __ MaybeUnpoisonHeapReference(temp);
4501 __ movl(temp, Address(temp, component_offset));
4502 // No need to poison/unpoison, we're comparing two poisoned references.
4503 __ cmpl(temp, Address(register_value, class_offset));
4504 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4505 __ j(kEqual, &do_put);
4506 __ MaybeUnpoisonHeapReference(temp);
4507 __ movl(temp, Address(temp, super_offset));
4508 // No need to unpoison, we're comparing against null..
4509 __ testl(temp, temp);
4510 __ j(kNotEqual, slow_path->GetEntryLabel());
4511 __ Bind(&do_put);
4512 } else {
4513 __ j(kNotEqual, slow_path->GetEntryLabel());
4514 }
4515 }
4516
4517 if (kPoisonHeapReferences) {
4518 __ movl(temp, register_value);
4519 __ PoisonHeapReference(temp);
4520 __ movl(address, temp);
4521 } else {
4522 __ movl(address, register_value);
4523 }
4524 if (!may_need_runtime_call) {
4525 codegen_->MaybeRecordImplicitNullCheck(instruction);
4526 }
4527
4528 Register card = locations->GetTemp(1).AsRegister<Register>();
4529 codegen_->MarkGCCard(
4530 temp, card, array, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
4531 __ Bind(&done);
4532
4533 if (slow_path != nullptr) {
4534 __ Bind(slow_path->GetExitLabel());
4535 }
4536
4537 break;
4538 }
4539 case Primitive::kPrimInt: {
4540 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4541 Address address = index.IsConstant()
4542 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4543 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
4544 if (value.IsRegister()) {
4545 __ movl(address, value.AsRegister<Register>());
4546 } else {
4547 DCHECK(value.IsConstant()) << value;
4548 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4549 __ movl(address, Immediate(v));
4550 }
4551 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004552 break;
4553 }
4554
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004555 case Primitive::kPrimLong: {
4556 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004557 if (index.IsConstant()) {
4558 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004559 if (value.IsRegisterPair()) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004560 __ movl(Address(array, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004561 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004562 __ movl(Address(array, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004563 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004564 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004565 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004566 __ movl(Address(array, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004567 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004568 __ movl(Address(array, offset + kX86WordSize), Immediate(High32Bits(val)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004569 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004570 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004571 if (value.IsRegisterPair()) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004572 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004573 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004574 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004575 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004576 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004577 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004578 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004579 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004580 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004581 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004582 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004583 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004584 Immediate(High32Bits(val)));
4585 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004586 }
4587 break;
4588 }
4589
Mark Mendell7c8d0092015-01-26 11:21:33 -05004590 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004591 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4592 Address address = index.IsConstant()
4593 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4594 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004595 DCHECK(value.IsFpuRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004596 __ movss(address, value.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004597 break;
4598 }
4599
4600 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004601 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4602 Address address = index.IsConstant()
4603 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4604 : Address(array, index.AsRegister<Register>(), TIMES_8, offset);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004605 DCHECK(value.IsFpuRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004606 __ movsd(address, value.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004607 break;
4608 }
4609
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004610 case Primitive::kPrimVoid:
4611 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004612 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004613 }
4614}
4615
4616void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
4617 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004618 locations->SetInAt(0, Location::RequiresRegister());
4619 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004620}
4621
4622void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
4623 LocationSummary* locations = instruction->GetLocations();
4624 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004625 Register obj = locations->InAt(0).AsRegister<Register>();
4626 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004627 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004628 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004629}
4630
4631void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004632 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4633 ? LocationSummary::kCallOnSlowPath
4634 : LocationSummary::kNoCall;
4635 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004636 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004637 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004638 if (instruction->HasUses()) {
4639 locations->SetOut(Location::SameAsFirstInput());
4640 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004641}
4642
4643void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
4644 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004645 Location index_loc = locations->InAt(0);
4646 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004647 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004648 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004649
Mark Mendell99dbd682015-04-22 16:18:52 -04004650 if (length_loc.IsConstant()) {
4651 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4652 if (index_loc.IsConstant()) {
4653 // BCE will remove the bounds check if we are guarenteed to pass.
4654 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4655 if (index < 0 || index >= length) {
4656 codegen_->AddSlowPath(slow_path);
4657 __ jmp(slow_path->GetEntryLabel());
4658 } else {
4659 // Some optimization after BCE may have generated this, and we should not
4660 // generate a bounds check if it is a valid range.
4661 }
4662 return;
4663 }
4664
4665 // We have to reverse the jump condition because the length is the constant.
4666 Register index_reg = index_loc.AsRegister<Register>();
4667 __ cmpl(index_reg, Immediate(length));
4668 codegen_->AddSlowPath(slow_path);
4669 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004670 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004671 Register length = length_loc.AsRegister<Register>();
4672 if (index_loc.IsConstant()) {
4673 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4674 __ cmpl(length, Immediate(value));
4675 } else {
4676 __ cmpl(length, index_loc.AsRegister<Register>());
4677 }
4678 codegen_->AddSlowPath(slow_path);
4679 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004680 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004681}
4682
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004683void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
4684 temp->SetLocations(nullptr);
4685}
4686
4687void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
4688 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004689 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004690}
4691
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004692void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004693 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004694 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004695}
4696
4697void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004698 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4699}
4700
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004701void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
4702 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4703}
4704
4705void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004706 HBasicBlock* block = instruction->GetBlock();
4707 if (block->GetLoopInformation() != nullptr) {
4708 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4709 // The back edge will generate the suspend check.
4710 return;
4711 }
4712 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4713 // The goto will generate the suspend check.
4714 return;
4715 }
4716 GenerateSuspendCheck(instruction, nullptr);
4717}
4718
4719void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
4720 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004721 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004722 down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
4723 if (slow_path == nullptr) {
4724 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
4725 instruction->SetSlowPath(slow_path);
4726 codegen_->AddSlowPath(slow_path);
4727 if (successor != nullptr) {
4728 DCHECK(successor->IsLoopHeader());
4729 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4730 }
4731 } else {
4732 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4733 }
4734
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004735 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004736 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004737 if (successor == nullptr) {
4738 __ j(kNotEqual, slow_path->GetEntryLabel());
4739 __ Bind(slow_path->GetReturnLabel());
4740 } else {
4741 __ j(kEqual, codegen_->GetLabelOf(successor));
4742 __ jmp(slow_path->GetEntryLabel());
4743 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004744}
4745
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004746X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
4747 return codegen_->GetAssembler();
4748}
4749
Mark Mendell7c8d0092015-01-26 11:21:33 -05004750void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004751 ScratchRegisterScope ensure_scratch(
4752 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4753 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4754 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4755 __ movl(temp_reg, Address(ESP, src + stack_offset));
4756 __ movl(Address(ESP, dst + stack_offset), temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004757}
4758
4759void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004760 ScratchRegisterScope ensure_scratch(
4761 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4762 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4763 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4764 __ movl(temp_reg, Address(ESP, src + stack_offset));
4765 __ movl(Address(ESP, dst + stack_offset), temp_reg);
4766 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
4767 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004768}
4769
4770void ParallelMoveResolverX86::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004771 DCHECK_LT(index, moves_.size());
4772 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004773 Location source = move->GetSource();
4774 Location destination = move->GetDestination();
4775
4776 if (source.IsRegister()) {
4777 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004778 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004779 } else {
4780 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004781 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004782 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004783 } else if (source.IsFpuRegister()) {
4784 if (destination.IsFpuRegister()) {
4785 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4786 } else if (destination.IsStackSlot()) {
4787 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4788 } else {
4789 DCHECK(destination.IsDoubleStackSlot());
4790 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4791 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004792 } else if (source.IsStackSlot()) {
4793 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004794 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004795 } else if (destination.IsFpuRegister()) {
4796 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004797 } else {
4798 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004799 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
4800 }
4801 } else if (source.IsDoubleStackSlot()) {
4802 if (destination.IsFpuRegister()) {
4803 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
4804 } else {
4805 DCHECK(destination.IsDoubleStackSlot()) << destination;
4806 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004807 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004808 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004809 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004810 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004811 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004812 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004813 if (value == 0) {
4814 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
4815 } else {
4816 __ movl(destination.AsRegister<Register>(), Immediate(value));
4817 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004818 } else {
4819 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05004820 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004821 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004822 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004823 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004824 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004825 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004826 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004827 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4828 if (value == 0) {
4829 // Easy handling of 0.0.
4830 __ xorps(dest, dest);
4831 } else {
4832 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004833 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4834 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
4835 __ movl(temp, Immediate(value));
4836 __ movd(dest, temp);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004837 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004838 } else {
4839 DCHECK(destination.IsStackSlot()) << destination;
4840 __ movl(Address(ESP, destination.GetStackIndex()), imm);
4841 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004842 } else if (constant->IsLongConstant()) {
4843 int64_t value = constant->AsLongConstant()->GetValue();
4844 int32_t low_value = Low32Bits(value);
4845 int32_t high_value = High32Bits(value);
4846 Immediate low(low_value);
4847 Immediate high(high_value);
4848 if (destination.IsDoubleStackSlot()) {
4849 __ movl(Address(ESP, destination.GetStackIndex()), low);
4850 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4851 } else {
4852 __ movl(destination.AsRegisterPairLow<Register>(), low);
4853 __ movl(destination.AsRegisterPairHigh<Register>(), high);
4854 }
4855 } else {
4856 DCHECK(constant->IsDoubleConstant());
4857 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004858 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004859 int32_t low_value = Low32Bits(value);
4860 int32_t high_value = High32Bits(value);
4861 Immediate low(low_value);
4862 Immediate high(high_value);
4863 if (destination.IsFpuRegister()) {
4864 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4865 if (value == 0) {
4866 // Easy handling of 0.0.
4867 __ xorpd(dest, dest);
4868 } else {
4869 __ pushl(high);
4870 __ pushl(low);
4871 __ movsd(dest, Address(ESP, 0));
4872 __ addl(ESP, Immediate(8));
4873 }
4874 } else {
4875 DCHECK(destination.IsDoubleStackSlot()) << destination;
4876 __ movl(Address(ESP, destination.GetStackIndex()), low);
4877 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4878 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004879 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004880 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00004881 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004882 }
4883}
4884
Mark Mendella5c19ce2015-04-01 12:51:05 -04004885void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004886 Register suggested_scratch = reg == EAX ? EBX : EAX;
4887 ScratchRegisterScope ensure_scratch(
4888 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
4889
4890 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4891 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
4892 __ movl(Address(ESP, mem + stack_offset), reg);
4893 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004894}
4895
Mark Mendell7c8d0092015-01-26 11:21:33 -05004896void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004897 ScratchRegisterScope ensure_scratch(
4898 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4899
4900 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4901 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4902 __ movl(temp_reg, Address(ESP, mem + stack_offset));
4903 __ movss(Address(ESP, mem + stack_offset), reg);
4904 __ movd(reg, temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004905}
4906
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004907void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004908 ScratchRegisterScope ensure_scratch1(
4909 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004910
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004911 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
4912 ScratchRegisterScope ensure_scratch2(
4913 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004914
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004915 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
4916 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
4917 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
4918 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
4919 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
4920 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004921}
4922
4923void ParallelMoveResolverX86::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004924 DCHECK_LT(index, moves_.size());
4925 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004926 Location source = move->GetSource();
4927 Location destination = move->GetDestination();
4928
4929 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell90979812015-07-28 16:41:21 -04004930 // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary.
4931 DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>());
4932 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
4933 __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>());
4934 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004935 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004936 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004937 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004938 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004939 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4940 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004941 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
4942 // Use XOR Swap algorithm to avoid a temporary.
4943 DCHECK_NE(source.reg(), destination.reg());
4944 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4945 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4946 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4947 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
4948 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
4949 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
4950 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004951 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
4952 // Take advantage of the 16 bytes in the XMM register.
4953 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
4954 Address stack(ESP, destination.GetStackIndex());
4955 // Load the double into the high doubleword.
4956 __ movhpd(reg, stack);
4957
4958 // Store the low double into the destination.
4959 __ movsd(stack, reg);
4960
4961 // Move the high double to the low double.
4962 __ psrldq(reg, Immediate(8));
4963 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
4964 // Take advantage of the 16 bytes in the XMM register.
4965 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
4966 Address stack(ESP, source.GetStackIndex());
4967 // Load the double into the high doubleword.
4968 __ movhpd(reg, stack);
4969
4970 // Store the low double into the destination.
4971 __ movsd(stack, reg);
4972
4973 // Move the high double to the low double.
4974 __ psrldq(reg, Immediate(8));
4975 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
4976 Exchange(destination.GetStackIndex(), source.GetStackIndex());
4977 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004978 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004979 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004980 }
4981}
4982
4983void ParallelMoveResolverX86::SpillScratch(int reg) {
4984 __ pushl(static_cast<Register>(reg));
4985}
4986
4987void ParallelMoveResolverX86::RestoreScratch(int reg) {
4988 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004989}
4990
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004991void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01004992 InvokeRuntimeCallingConvention calling_convention;
4993 CodeGenerator::CreateLoadClassLocationSummary(
4994 cls,
4995 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
4996 Location::RegisterLocation(EAX));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004997}
4998
4999void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005000 LocationSummary* locations = cls->GetLocations();
5001 Register out = locations->Out().AsRegister<Register>();
5002 Register current_method = locations->InAt(0).AsRegister<Register>();
Calin Juravle98893e12015-10-02 21:05:03 +01005003 if (cls->NeedsAccessCheck()) {
5004 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5005 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5006 cls,
5007 cls->GetDexPc(),
5008 nullptr);
5009 } else if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005010 DCHECK(!cls->CanCallRuntime());
5011 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07005012 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005013 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005014 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005015 __ movl(out, Address(
Vladimir Marko05792b92015-08-03 11:56:49 +01005016 current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86PointerSize).Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005017 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01005018 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005019
Andreas Gampe85b62f22015-09-09 13:15:38 -07005020 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005021 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5022 codegen_->AddSlowPath(slow_path);
5023 __ testl(out, out);
5024 __ j(kEqual, slow_path->GetEntryLabel());
5025 if (cls->MustGenerateClinitCheck()) {
5026 GenerateClassInitializationCheck(slow_path, out);
5027 } else {
5028 __ Bind(slow_path->GetExitLabel());
5029 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005030 }
5031}
5032
5033void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
5034 LocationSummary* locations =
5035 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5036 locations->SetInAt(0, Location::RequiresRegister());
5037 if (check->HasUses()) {
5038 locations->SetOut(Location::SameAsFirstInput());
5039 }
5040}
5041
5042void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005043 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005044 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005045 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005046 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005047 GenerateClassInitializationCheck(slow_path,
5048 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005049}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005050
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005051void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005052 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005053 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
5054 Immediate(mirror::Class::kStatusInitialized));
5055 __ j(kLess, slow_path->GetEntryLabel());
5056 __ Bind(slow_path->GetExitLabel());
5057 // No need for memory fence, thanks to the X86 memory model.
5058}
5059
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005060void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
5061 LocationSummary* locations =
5062 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005063 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005064 locations->SetOut(Location::RequiresRegister());
5065}
5066
5067void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07005068 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005069 codegen_->AddSlowPath(slow_path);
5070
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005071 LocationSummary* locations = load->GetLocations();
5072 Register out = locations->Out().AsRegister<Register>();
5073 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07005074 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08005075 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005076 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01005077 // TODO: We will need a read barrier here.
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005078 __ testl(out, out);
5079 __ j(kEqual, slow_path->GetEntryLabel());
5080 __ Bind(slow_path->GetExitLabel());
5081}
5082
David Brazdilcb1c0552015-08-04 16:22:25 +01005083static Address GetExceptionTlsAddress() {
5084 return Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
5085}
5086
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005087void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
5088 LocationSummary* locations =
5089 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5090 locations->SetOut(Location::RequiresRegister());
5091}
5092
5093void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01005094 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress());
5095}
5096
5097void LocationsBuilderX86::VisitClearException(HClearException* clear) {
5098 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5099}
5100
5101void InstructionCodeGeneratorX86::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5102 __ fs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005103}
5104
5105void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
5106 LocationSummary* locations =
5107 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5108 InvokeRuntimeCallingConvention calling_convention;
5109 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5110}
5111
5112void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005113 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
5114 instruction,
5115 instruction->GetDexPc(),
5116 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005117}
5118
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005119void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005120 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5121 switch (instruction->GetTypeCheckKind()) {
5122 case TypeCheckKind::kExactCheck:
5123 case TypeCheckKind::kAbstractClassCheck:
5124 case TypeCheckKind::kClassHierarchyCheck:
5125 case TypeCheckKind::kArrayObjectCheck:
5126 call_kind = LocationSummary::kNoCall;
5127 break;
Calin Juravle98893e12015-10-02 21:05:03 +01005128 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005129 case TypeCheckKind::kInterfaceCheck:
5130 call_kind = LocationSummary::kCall;
5131 break;
5132 case TypeCheckKind::kArrayCheck:
5133 call_kind = LocationSummary::kCallOnSlowPath;
5134 break;
5135 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005136 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005137 if (call_kind != LocationSummary::kCall) {
5138 locations->SetInAt(0, Location::RequiresRegister());
5139 locations->SetInAt(1, Location::Any());
5140 // Note that TypeCheckSlowPathX86 uses this register too.
5141 locations->SetOut(Location::RequiresRegister());
5142 } else {
5143 InvokeRuntimeCallingConvention calling_convention;
5144 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5145 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5146 locations->SetOut(Location::RegisterLocation(EAX));
5147 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005148}
5149
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005150void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005151 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005152 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005153 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005154 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005155 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005156 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5157 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5158 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005159 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005160 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005161
5162 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005163 // Avoid null check if we know obj is not null.
5164 if (instruction->MustDoNullCheck()) {
5165 __ testl(obj, obj);
5166 __ j(kEqual, &zero);
5167 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005168
Calin Juravle98893e12015-10-02 21:05:03 +01005169 // In case of an interface/unresolved check, we put the object class into the object register.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005170 // This is safe, as the register is caller-save, and the object must be in another
5171 // register if it survives the runtime call.
Calin Juravle98893e12015-10-02 21:05:03 +01005172 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
5173 (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005174 ? obj
5175 : out;
5176 __ movl(target, Address(obj, class_offset));
5177 __ MaybeUnpoisonHeapReference(target);
5178
5179 switch (instruction->GetTypeCheckKind()) {
5180 case TypeCheckKind::kExactCheck: {
5181 if (cls.IsRegister()) {
5182 __ cmpl(out, cls.AsRegister<Register>());
5183 } else {
5184 DCHECK(cls.IsStackSlot()) << cls;
5185 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5186 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005187
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005188 // Classes must be equal for the instanceof to succeed.
5189 __ j(kNotEqual, &zero);
5190 __ movl(out, Immediate(1));
5191 __ jmp(&done);
5192 break;
5193 }
5194 case TypeCheckKind::kAbstractClassCheck: {
5195 // If the class is abstract, we eagerly fetch the super class of the
5196 // object to avoid doing a comparison we know will fail.
5197 NearLabel loop;
5198 __ Bind(&loop);
5199 __ movl(out, Address(out, super_offset));
5200 __ MaybeUnpoisonHeapReference(out);
5201 __ testl(out, out);
5202 // If `out` is null, we use it for the result, and jump to `done`.
5203 __ j(kEqual, &done);
5204 if (cls.IsRegister()) {
5205 __ cmpl(out, cls.AsRegister<Register>());
5206 } else {
5207 DCHECK(cls.IsStackSlot()) << cls;
5208 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5209 }
5210 __ j(kNotEqual, &loop);
5211 __ movl(out, Immediate(1));
5212 if (zero.IsLinked()) {
5213 __ jmp(&done);
5214 }
5215 break;
5216 }
5217 case TypeCheckKind::kClassHierarchyCheck: {
5218 // Walk over the class hierarchy to find a match.
5219 NearLabel loop, success;
5220 __ Bind(&loop);
5221 if (cls.IsRegister()) {
5222 __ cmpl(out, cls.AsRegister<Register>());
5223 } else {
5224 DCHECK(cls.IsStackSlot()) << cls;
5225 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5226 }
5227 __ j(kEqual, &success);
5228 __ movl(out, Address(out, super_offset));
5229 __ MaybeUnpoisonHeapReference(out);
5230 __ testl(out, out);
5231 __ j(kNotEqual, &loop);
5232 // If `out` is null, we use it for the result, and jump to `done`.
5233 __ jmp(&done);
5234 __ Bind(&success);
5235 __ movl(out, Immediate(1));
5236 if (zero.IsLinked()) {
5237 __ jmp(&done);
5238 }
5239 break;
5240 }
5241 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005242 // Do an exact check.
5243 NearLabel exact_check;
5244 if (cls.IsRegister()) {
5245 __ cmpl(out, cls.AsRegister<Register>());
5246 } else {
5247 DCHECK(cls.IsStackSlot()) << cls;
5248 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5249 }
5250 __ j(kEqual, &exact_check);
5251 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005252 __ movl(out, Address(out, component_offset));
5253 __ MaybeUnpoisonHeapReference(out);
5254 __ testl(out, out);
5255 // If `out` is null, we use it for the result, and jump to `done`.
5256 __ j(kEqual, &done);
5257 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5258 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005259 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005260 __ movl(out, Immediate(1));
5261 __ jmp(&done);
5262 break;
5263 }
5264 case TypeCheckKind::kArrayCheck: {
5265 if (cls.IsRegister()) {
5266 __ cmpl(out, cls.AsRegister<Register>());
5267 } else {
5268 DCHECK(cls.IsStackSlot()) << cls;
5269 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5270 }
5271 DCHECK(locations->OnlyCallsOnSlowPath());
5272 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5273 instruction, /* is_fatal */ false);
5274 codegen_->AddSlowPath(slow_path);
5275 __ j(kNotEqual, slow_path->GetEntryLabel());
5276 __ movl(out, Immediate(1));
5277 if (zero.IsLinked()) {
5278 __ jmp(&done);
5279 }
5280 break;
5281 }
Calin Juravle98893e12015-10-02 21:05:03 +01005282 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005283 case TypeCheckKind::kInterfaceCheck:
5284 default: {
5285 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
5286 instruction,
5287 instruction->GetDexPc(),
5288 nullptr);
5289 if (zero.IsLinked()) {
5290 __ jmp(&done);
5291 }
5292 break;
5293 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005294 }
5295
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005296 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005297 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005298 __ xorl(out, out);
5299 }
5300
5301 if (done.IsLinked()) {
5302 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005303 }
5304
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005305 if (slow_path != nullptr) {
5306 __ Bind(slow_path->GetExitLabel());
5307 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005308}
5309
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005310void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005311 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5312 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5313
5314 switch (instruction->GetTypeCheckKind()) {
5315 case TypeCheckKind::kExactCheck:
5316 case TypeCheckKind::kAbstractClassCheck:
5317 case TypeCheckKind::kClassHierarchyCheck:
5318 case TypeCheckKind::kArrayObjectCheck:
5319 call_kind = throws_into_catch
5320 ? LocationSummary::kCallOnSlowPath
5321 : LocationSummary::kNoCall;
5322 break;
5323 case TypeCheckKind::kInterfaceCheck:
Calin Juravle98893e12015-10-02 21:05:03 +01005324 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005325 call_kind = LocationSummary::kCall;
5326 break;
5327 case TypeCheckKind::kArrayCheck:
5328 call_kind = LocationSummary::kCallOnSlowPath;
5329 break;
5330 }
5331
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005332 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005333 instruction, call_kind);
5334 if (call_kind != LocationSummary::kCall) {
5335 locations->SetInAt(0, Location::RequiresRegister());
5336 locations->SetInAt(1, Location::Any());
5337 // Note that TypeCheckSlowPathX86 uses this register too.
5338 locations->AddTemp(Location::RequiresRegister());
5339 } else {
5340 InvokeRuntimeCallingConvention calling_convention;
5341 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5342 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5343 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005344}
5345
5346void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
5347 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005348 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005349 Location cls = locations->InAt(1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005350 Register temp = locations->WillCall()
5351 ? kNoRegister
5352 : locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray64acf302015-09-14 22:20:29 +01005353
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005354 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5355 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5356 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5357 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5358 SlowPathCode* slow_path = nullptr;
5359
5360 if (!locations->WillCall()) {
5361 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5362 instruction, !locations->CanCall());
5363 codegen_->AddSlowPath(slow_path);
5364 }
5365
5366 NearLabel done, abstract_entry;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005367 // Avoid null check if we know obj is not null.
5368 if (instruction->MustDoNullCheck()) {
5369 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005370 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005371 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005372
5373 if (locations->WillCall()) {
5374 __ movl(obj, Address(obj, class_offset));
5375 __ MaybeUnpoisonHeapReference(obj);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005376 } else {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005377 __ movl(temp, Address(obj, class_offset));
5378 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005379 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005380
5381 switch (instruction->GetTypeCheckKind()) {
5382 case TypeCheckKind::kExactCheck:
5383 case TypeCheckKind::kArrayCheck: {
5384 if (cls.IsRegister()) {
5385 __ cmpl(temp, cls.AsRegister<Register>());
5386 } else {
5387 DCHECK(cls.IsStackSlot()) << cls;
5388 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5389 }
5390 // Jump to slow path for throwing the exception or doing a
5391 // more involved array check.
5392 __ j(kNotEqual, slow_path->GetEntryLabel());
5393 break;
5394 }
5395 case TypeCheckKind::kAbstractClassCheck: {
5396 // If the class is abstract, we eagerly fetch the super class of the
5397 // object to avoid doing a comparison we know will fail.
5398 NearLabel loop, success;
5399 __ Bind(&loop);
5400 __ movl(temp, Address(temp, super_offset));
5401 __ MaybeUnpoisonHeapReference(temp);
5402 __ testl(temp, temp);
5403 // Jump to the slow path to throw the exception.
5404 __ j(kEqual, slow_path->GetEntryLabel());
5405 if (cls.IsRegister()) {
5406 __ cmpl(temp, cls.AsRegister<Register>());
5407 } else {
5408 DCHECK(cls.IsStackSlot()) << cls;
5409 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5410 }
5411 __ j(kNotEqual, &loop);
5412 break;
5413 }
5414 case TypeCheckKind::kClassHierarchyCheck: {
5415 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005416 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005417 __ Bind(&loop);
5418 if (cls.IsRegister()) {
5419 __ cmpl(temp, cls.AsRegister<Register>());
5420 } else {
5421 DCHECK(cls.IsStackSlot()) << cls;
5422 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5423 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005424 __ j(kEqual, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005425 __ movl(temp, Address(temp, super_offset));
5426 __ MaybeUnpoisonHeapReference(temp);
5427 __ testl(temp, temp);
5428 __ j(kNotEqual, &loop);
5429 // Jump to the slow path to throw the exception.
5430 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005431 break;
5432 }
5433 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005434 // Do an exact check.
5435 if (cls.IsRegister()) {
5436 __ cmpl(temp, cls.AsRegister<Register>());
5437 } else {
5438 DCHECK(cls.IsStackSlot()) << cls;
5439 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5440 }
5441 __ j(kEqual, &done);
5442 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005443 __ movl(temp, Address(temp, component_offset));
5444 __ MaybeUnpoisonHeapReference(temp);
5445 __ testl(temp, temp);
5446 __ j(kEqual, slow_path->GetEntryLabel());
5447 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
5448 __ j(kNotEqual, slow_path->GetEntryLabel());
5449 break;
5450 }
Calin Juravle98893e12015-10-02 21:05:03 +01005451 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005452 case TypeCheckKind::kInterfaceCheck:
5453 default:
5454 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5455 instruction,
5456 instruction->GetDexPc(),
5457 nullptr);
5458 break;
5459 }
5460 __ Bind(&done);
5461
5462 if (slow_path != nullptr) {
5463 __ Bind(slow_path->GetExitLabel());
5464 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005465}
5466
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005467void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
5468 LocationSummary* locations =
5469 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5470 InvokeRuntimeCallingConvention calling_convention;
5471 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5472}
5473
5474void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005475 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5476 : QUICK_ENTRY_POINT(pUnlockObject),
5477 instruction,
5478 instruction->GetDexPc(),
5479 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005480}
5481
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005482void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5483void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5484void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5485
5486void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5487 LocationSummary* locations =
5488 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5489 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5490 || instruction->GetResultType() == Primitive::kPrimLong);
5491 locations->SetInAt(0, Location::RequiresRegister());
5492 locations->SetInAt(1, Location::Any());
5493 locations->SetOut(Location::SameAsFirstInput());
5494}
5495
5496void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
5497 HandleBitwiseOperation(instruction);
5498}
5499
5500void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
5501 HandleBitwiseOperation(instruction);
5502}
5503
5504void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
5505 HandleBitwiseOperation(instruction);
5506}
5507
5508void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5509 LocationSummary* locations = instruction->GetLocations();
5510 Location first = locations->InAt(0);
5511 Location second = locations->InAt(1);
5512 DCHECK(first.Equals(locations->Out()));
5513
5514 if (instruction->GetResultType() == Primitive::kPrimInt) {
5515 if (second.IsRegister()) {
5516 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005517 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005518 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005519 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005520 } else {
5521 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005522 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005523 }
5524 } else if (second.IsConstant()) {
5525 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005526 __ andl(first.AsRegister<Register>(),
5527 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005528 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005529 __ orl(first.AsRegister<Register>(),
5530 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005531 } else {
5532 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00005533 __ xorl(first.AsRegister<Register>(),
5534 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005535 }
5536 } else {
5537 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005538 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005539 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005540 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005541 } else {
5542 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005543 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005544 }
5545 }
5546 } else {
5547 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5548 if (second.IsRegisterPair()) {
5549 if (instruction->IsAnd()) {
5550 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5551 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5552 } else if (instruction->IsOr()) {
5553 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5554 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5555 } else {
5556 DCHECK(instruction->IsXor());
5557 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5558 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5559 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005560 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005561 if (instruction->IsAnd()) {
5562 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5563 __ andl(first.AsRegisterPairHigh<Register>(),
5564 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5565 } else if (instruction->IsOr()) {
5566 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5567 __ orl(first.AsRegisterPairHigh<Register>(),
5568 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5569 } else {
5570 DCHECK(instruction->IsXor());
5571 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5572 __ xorl(first.AsRegisterPairHigh<Register>(),
5573 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5574 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005575 } else {
5576 DCHECK(second.IsConstant()) << second;
5577 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005578 int32_t low_value = Low32Bits(value);
5579 int32_t high_value = High32Bits(value);
5580 Immediate low(low_value);
5581 Immediate high(high_value);
5582 Register first_low = first.AsRegisterPairLow<Register>();
5583 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005584 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005585 if (low_value == 0) {
5586 __ xorl(first_low, first_low);
5587 } else if (low_value != -1) {
5588 __ andl(first_low, low);
5589 }
5590 if (high_value == 0) {
5591 __ xorl(first_high, first_high);
5592 } else if (high_value != -1) {
5593 __ andl(first_high, high);
5594 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005595 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005596 if (low_value != 0) {
5597 __ orl(first_low, low);
5598 }
5599 if (high_value != 0) {
5600 __ orl(first_high, high);
5601 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005602 } else {
5603 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005604 if (low_value != 0) {
5605 __ xorl(first_low, low);
5606 }
5607 if (high_value != 0) {
5608 __ xorl(first_high, high);
5609 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005610 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005611 }
5612 }
5613}
5614
Calin Juravleb1498f62015-02-16 13:13:29 +00005615void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
5616 // Nothing to do, this should be removed during prepare for register allocator.
5617 UNUSED(instruction);
5618 LOG(FATAL) << "Unreachable";
5619}
5620
5621void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
5622 // Nothing to do, this should be removed during prepare for register allocator.
5623 UNUSED(instruction);
5624 LOG(FATAL) << "Unreachable";
5625}
5626
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005627void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) {
5628 DCHECK(codegen_->IsBaseline());
5629 LocationSummary* locations =
5630 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5631 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5632}
5633
5634void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5635 DCHECK(codegen_->IsBaseline());
5636 // Will be generated at use site.
5637}
5638
Mark Mendellfe57faa2015-09-18 09:26:15 -04005639// Simple implementation of packed switch - generate cascaded compare/jumps.
5640void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5641 LocationSummary* locations =
5642 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5643 locations->SetInAt(0, Location::RequiresRegister());
5644}
5645
5646void InstructionCodeGeneratorX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5647 int32_t lower_bound = switch_instr->GetStartValue();
5648 int32_t num_entries = switch_instr->GetNumEntries();
5649 LocationSummary* locations = switch_instr->GetLocations();
5650 Register value_reg = locations->InAt(0).AsRegister<Register>();
5651 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5652
5653 // Create a series of compare/jumps.
5654 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5655 for (int i = 0; i < num_entries; i++) {
5656 int32_t case_value = lower_bound + i;
5657 if (case_value == 0) {
5658 __ testl(value_reg, value_reg);
5659 } else {
5660 __ cmpl(value_reg, Immediate(case_value));
5661 }
5662 __ j(kEqual, codegen_->GetLabelOf(successors.at(i)));
5663 }
5664
5665 // And the default for any other value.
5666 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5667 __ jmp(codegen_->GetLabelOf(default_block));
5668 }
5669}
5670
Mark Mendell0616ae02015-04-17 12:49:27 -04005671void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
5672 HX86ComputeBaseMethodAddress* insn) {
5673 LocationSummary* locations =
5674 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5675 locations->SetOut(Location::RequiresRegister());
5676}
5677
5678void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
5679 HX86ComputeBaseMethodAddress* insn) {
5680 LocationSummary* locations = insn->GetLocations();
5681 Register reg = locations->Out().AsRegister<Register>();
5682
5683 // Generate call to next instruction.
5684 Label next_instruction;
5685 __ call(&next_instruction);
5686 __ Bind(&next_instruction);
5687
5688 // Remember this offset for later use with constant area.
5689 codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize());
5690
5691 // Grab the return address off the stack.
5692 __ popl(reg);
5693}
5694
5695void LocationsBuilderX86::VisitX86LoadFromConstantTable(
5696 HX86LoadFromConstantTable* insn) {
5697 LocationSummary* locations =
5698 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5699
5700 locations->SetInAt(0, Location::RequiresRegister());
5701 locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
5702
5703 // If we don't need to be materialized, we only need the inputs to be set.
5704 if (!insn->NeedsMaterialization()) {
5705 return;
5706 }
5707
5708 switch (insn->GetType()) {
5709 case Primitive::kPrimFloat:
5710 case Primitive::kPrimDouble:
5711 locations->SetOut(Location::RequiresFpuRegister());
5712 break;
5713
5714 case Primitive::kPrimInt:
5715 locations->SetOut(Location::RequiresRegister());
5716 break;
5717
5718 default:
5719 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5720 }
5721}
5722
5723void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
5724 if (!insn->NeedsMaterialization()) {
5725 return;
5726 }
5727
5728 LocationSummary* locations = insn->GetLocations();
5729 Location out = locations->Out();
5730 Register const_area = locations->InAt(0).AsRegister<Register>();
5731 HConstant *value = insn->GetConstant();
5732
5733 switch (insn->GetType()) {
5734 case Primitive::kPrimFloat:
5735 __ movss(out.AsFpuRegister<XmmRegister>(),
5736 codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area));
5737 break;
5738
5739 case Primitive::kPrimDouble:
5740 __ movsd(out.AsFpuRegister<XmmRegister>(),
5741 codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area));
5742 break;
5743
5744 case Primitive::kPrimInt:
5745 __ movl(out.AsRegister<Register>(),
5746 codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area));
5747 break;
5748
5749 default:
5750 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5751 }
5752}
5753
5754void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
5755 // Generate the constant area if needed.
5756 X86Assembler* assembler = GetAssembler();
5757 if (!assembler->IsConstantAreaEmpty()) {
5758 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
5759 // byte values.
5760 assembler->Align(4, 0);
5761 constant_area_start_ = assembler->CodeSize();
5762 assembler->AddConstantArea();
5763 }
5764
5765 // And finish up.
5766 CodeGenerator::Finalize(allocator);
5767}
5768
5769/**
5770 * Class to handle late fixup of offsets into constant area.
5771 */
Vladimir Marko5233f932015-09-29 19:01:15 +01005772class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
Mark Mendell0616ae02015-04-17 12:49:27 -04005773 public:
5774 RIPFixup(const CodeGeneratorX86& codegen, int offset)
5775 : codegen_(codegen), offset_into_constant_area_(offset) {}
5776
5777 private:
5778 void Process(const MemoryRegion& region, int pos) OVERRIDE {
5779 // Patch the correct offset for the instruction. The place to patch is the
5780 // last 4 bytes of the instruction.
5781 // The value to patch is the distance from the offset in the constant area
5782 // from the address computed by the HX86ComputeBaseMethodAddress instruction.
5783 int32_t constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
5784 int32_t relative_position = constant_offset - codegen_.GetMethodAddressOffset();;
5785
5786 // Patch in the right value.
5787 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
5788 }
5789
5790 const CodeGeneratorX86& codegen_;
5791
5792 // Location in constant area that the fixup refers to.
5793 int offset_into_constant_area_;
5794};
5795
5796Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) {
5797 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
5798 return Address(reg, kDummy32BitOffset, fixup);
5799}
5800
5801Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) {
5802 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
5803 return Address(reg, kDummy32BitOffset, fixup);
5804}
5805
5806Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) {
5807 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
5808 return Address(reg, kDummy32BitOffset, fixup);
5809}
5810
5811Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) {
5812 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
5813 return Address(reg, kDummy32BitOffset, fixup);
5814}
5815
5816/**
5817 * Finds instructions that need the constant area base as an input.
5818 */
5819class ConstantHandlerVisitor : public HGraphVisitor {
5820 public:
5821 explicit ConstantHandlerVisitor(HGraph* graph) : HGraphVisitor(graph), base_(nullptr) {}
5822
5823 private:
5824 void VisitAdd(HAdd* add) OVERRIDE {
5825 BinaryFP(add);
5826 }
5827
5828 void VisitSub(HSub* sub) OVERRIDE {
5829 BinaryFP(sub);
5830 }
5831
5832 void VisitMul(HMul* mul) OVERRIDE {
5833 BinaryFP(mul);
5834 }
5835
5836 void VisitDiv(HDiv* div) OVERRIDE {
5837 BinaryFP(div);
5838 }
5839
5840 void VisitReturn(HReturn* ret) OVERRIDE {
5841 HConstant* value = ret->InputAt(0)->AsConstant();
5842 if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) {
5843 ReplaceInput(ret, value, 0, true);
5844 }
5845 }
5846
5847 void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
5848 HandleInvoke(invoke);
5849 }
5850
5851 void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE {
5852 HandleInvoke(invoke);
5853 }
5854
5855 void VisitInvokeInterface(HInvokeInterface* invoke) OVERRIDE {
5856 HandleInvoke(invoke);
5857 }
5858
5859 void BinaryFP(HBinaryOperation* bin) {
5860 HConstant* rhs = bin->InputAt(1)->AsConstant();
5861 if (rhs != nullptr && Primitive::IsFloatingPointType(bin->GetResultType())) {
5862 ReplaceInput(bin, rhs, 1, false);
5863 }
5864 }
5865
5866 void InitializeConstantAreaPointer(HInstruction* user) {
5867 // Ensure we only initialize the pointer once.
5868 if (base_ != nullptr) {
5869 return;
5870 }
5871
5872 HGraph* graph = GetGraph();
5873 HBasicBlock* entry = graph->GetEntryBlock();
5874 base_ = new (graph->GetArena()) HX86ComputeBaseMethodAddress();
5875 HInstruction* insert_pos = (user->GetBlock() == entry) ? user : entry->GetLastInstruction();
5876 entry->InsertInstructionBefore(base_, insert_pos);
5877 DCHECK(base_ != nullptr);
5878 }
5879
5880 void ReplaceInput(HInstruction* insn, HConstant* value, int input_index, bool materialize) {
5881 InitializeConstantAreaPointer(insn);
5882 HGraph* graph = GetGraph();
5883 HBasicBlock* block = insn->GetBlock();
5884 HX86LoadFromConstantTable* load_constant =
5885 new (graph->GetArena()) HX86LoadFromConstantTable(base_, value, materialize);
5886 block->InsertInstructionBefore(load_constant, insn);
5887 insn->ReplaceInput(load_constant, input_index);
5888 }
5889
5890 void HandleInvoke(HInvoke* invoke) {
5891 // Ensure that we can load FP arguments from the constant area.
5892 for (size_t i = 0, e = invoke->InputCount(); i < e; i++) {
5893 HConstant* input = invoke->InputAt(i)->AsConstant();
5894 if (input != nullptr && Primitive::IsFloatingPointType(input->GetType())) {
5895 ReplaceInput(invoke, input, i, true);
5896 }
5897 }
5898 }
5899
5900 // The generated HX86ComputeBaseMethodAddress in the entry block needed as an
5901 // input to the HX86LoadFromConstantTable instructions.
5902 HX86ComputeBaseMethodAddress* base_;
5903};
5904
5905void ConstantAreaFixups::Run() {
5906 ConstantHandlerVisitor visitor(graph_);
5907 visitor.VisitInsertionOrder();
5908}
5909
Andreas Gampe85b62f22015-09-09 13:15:38 -07005910// TODO: target as memory.
5911void CodeGeneratorX86::MoveFromReturnRegister(Location target, Primitive::Type type) {
5912 if (!target.IsValid()) {
5913 DCHECK(type == Primitive::kPrimVoid);
5914 return;
5915 }
5916
5917 DCHECK_NE(type, Primitive::kPrimVoid);
5918
5919 Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type);
5920 if (target.Equals(return_loc)) {
5921 return;
5922 }
5923
5924 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5925 // with the else branch.
5926 if (type == Primitive::kPrimLong) {
5927 HParallelMove parallel_move(GetGraph()->GetArena());
5928 parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), Primitive::kPrimInt, nullptr);
5929 parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), Primitive::kPrimInt, nullptr);
5930 GetMoveResolver()->EmitNativeCode(&parallel_move);
5931 } else {
5932 // Let the parallel move resolver take care of all of this.
5933 HParallelMove parallel_move(GetGraph()->GetArena());
5934 parallel_move.AddMove(return_loc, target, type, nullptr);
5935 GetMoveResolver()->EmitNativeCode(&parallel_move);
5936 }
5937}
5938
Roland Levillain4d027112015-07-01 15:41:14 +01005939#undef __
5940
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00005941} // namespace x86
5942} // namespace art