blob: b60eebf1ba70f0bfc66f788beeb7878dc7550080 [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)),
Mark Mendell805b3b52015-09-18 14:10:29 -0400524 relative_call_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)),
525 fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000526 // Use a fake return address register to mimic Quick.
527 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100528}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100529
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100530Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100531 switch (type) {
532 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100533 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100534 X86ManagedRegister pair =
535 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100536 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
537 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100538 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
539 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100540 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100541 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100542 }
543
544 case Primitive::kPrimByte:
545 case Primitive::kPrimBoolean:
546 case Primitive::kPrimChar:
547 case Primitive::kPrimShort:
548 case Primitive::kPrimInt:
549 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100550 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100551 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100552 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100553 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
554 X86ManagedRegister current =
555 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
556 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100557 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100558 }
559 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100560 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100561 }
562
563 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100564 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100565 return Location::FpuRegisterLocation(
566 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100567 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100568
569 case Primitive::kPrimVoid:
570 LOG(FATAL) << "Unreachable type " << type;
571 }
572
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100573 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100574}
575
Mark Mendell5f874182015-03-04 15:42:45 -0500576void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100577 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100578 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100579
580 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100581 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100582
Mark Mendell5f874182015-03-04 15:42:45 -0500583 if (is_baseline) {
584 blocked_core_registers_[EBP] = true;
585 blocked_core_registers_[ESI] = true;
586 blocked_core_registers_[EDI] = true;
587 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100588
589 UpdateBlockedPairRegisters();
590}
591
592void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
593 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
594 X86ManagedRegister current =
595 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
596 if (blocked_core_registers_[current.AsRegisterPairLow()]
597 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
598 blocked_register_pairs_[i] = true;
599 }
600 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100601}
602
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100603InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
604 : HGraphVisitor(graph),
605 assembler_(codegen->GetAssembler()),
606 codegen_(codegen) {}
607
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100608static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100609 return dwarf::Reg::X86Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100610}
611
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000612void CodeGeneratorX86::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100613 __ cfi().SetCurrentCFAOffset(kX86WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000614 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000615 bool skip_overflow_check =
616 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000617 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000618
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000619 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100620 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100621 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100622 }
623
Mark Mendell5f874182015-03-04 15:42:45 -0500624 if (HasEmptyFrame()) {
625 return;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000626 }
Mark Mendell5f874182015-03-04 15:42:45 -0500627
628 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
629 Register reg = kCoreCalleeSaves[i];
630 if (allocated_registers_.ContainsCoreRegister(reg)) {
631 __ pushl(reg);
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100632 __ cfi().AdjustCFAOffset(kX86WordSize);
633 __ cfi().RelOffset(DWARFReg(reg), 0);
Mark Mendell5f874182015-03-04 15:42:45 -0500634 }
635 }
636
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100637 int adjust = GetFrameSize() - FrameEntrySpillSize();
638 __ subl(ESP, Immediate(adjust));
639 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100640 __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000641}
642
643void CodeGeneratorX86::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100644 __ cfi().RememberState();
645 if (!HasEmptyFrame()) {
646 int adjust = GetFrameSize() - FrameEntrySpillSize();
647 __ addl(ESP, Immediate(adjust));
648 __ cfi().AdjustCFAOffset(-adjust);
Mark Mendell5f874182015-03-04 15:42:45 -0500649
David Srbeckyc34dc932015-04-12 09:27:43 +0100650 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
651 Register reg = kCoreCalleeSaves[i];
652 if (allocated_registers_.ContainsCoreRegister(reg)) {
653 __ popl(reg);
654 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize));
655 __ cfi().Restore(DWARFReg(reg));
656 }
Mark Mendell5f874182015-03-04 15:42:45 -0500657 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000658 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100659 __ ret();
660 __ cfi().RestoreState();
661 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000662}
663
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100664void CodeGeneratorX86::Bind(HBasicBlock* block) {
665 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000666}
667
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100668Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
669 switch (load->GetType()) {
670 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100671 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100672 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100673
674 case Primitive::kPrimInt:
675 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100676 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100677 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100678
679 case Primitive::kPrimBoolean:
680 case Primitive::kPrimByte:
681 case Primitive::kPrimChar:
682 case Primitive::kPrimShort:
683 case Primitive::kPrimVoid:
684 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700685 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100686 }
687
688 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700689 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100690}
691
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100692Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(Primitive::Type type) const {
693 switch (type) {
694 case Primitive::kPrimBoolean:
695 case Primitive::kPrimByte:
696 case Primitive::kPrimChar:
697 case Primitive::kPrimShort:
698 case Primitive::kPrimInt:
699 case Primitive::kPrimNot:
700 return Location::RegisterLocation(EAX);
701
702 case Primitive::kPrimLong:
703 return Location::RegisterPairLocation(EAX, EDX);
704
705 case Primitive::kPrimVoid:
706 return Location::NoLocation();
707
708 case Primitive::kPrimDouble:
709 case Primitive::kPrimFloat:
710 return Location::FpuRegisterLocation(XMM0);
711 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100712
713 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100714}
715
716Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
717 return Location::RegisterLocation(kMethodRegisterArgument);
718}
719
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100720Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100721 switch (type) {
722 case Primitive::kPrimBoolean:
723 case Primitive::kPrimByte:
724 case Primitive::kPrimChar:
725 case Primitive::kPrimShort:
726 case Primitive::kPrimInt:
727 case Primitive::kPrimNot: {
728 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000729 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100730 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100731 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100732 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000733 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100734 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100735 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100736
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000737 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100738 uint32_t index = gp_index_;
739 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000740 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100741 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100742 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
743 calling_convention.GetRegisterPairAt(index));
744 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100745 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000746 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
747 }
748 }
749
750 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100751 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000752 stack_index_++;
753 if (index < calling_convention.GetNumberOfFpuRegisters()) {
754 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
755 } else {
756 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
757 }
758 }
759
760 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100761 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000762 stack_index_ += 2;
763 if (index < calling_convention.GetNumberOfFpuRegisters()) {
764 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
765 } else {
766 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100767 }
768 }
769
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100770 case Primitive::kPrimVoid:
771 LOG(FATAL) << "Unexpected parameter type " << type;
772 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100773 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100774 return Location();
775}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100776
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100777void CodeGeneratorX86::Move32(Location destination, Location source) {
778 if (source.Equals(destination)) {
779 return;
780 }
781 if (destination.IsRegister()) {
782 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000783 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100784 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000785 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100786 } else {
787 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000788 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100789 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100790 } else if (destination.IsFpuRegister()) {
791 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000792 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100793 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000794 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100795 } else {
796 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000797 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100798 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100799 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000800 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100801 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000802 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100803 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000804 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500805 } else if (source.IsConstant()) {
806 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000807 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -0500808 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100809 } else {
810 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100811 __ pushl(Address(ESP, source.GetStackIndex()));
812 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100813 }
814 }
815}
816
817void CodeGeneratorX86::Move64(Location destination, Location source) {
818 if (source.Equals(destination)) {
819 return;
820 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100821 if (destination.IsRegisterPair()) {
822 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000823 EmitParallelMoves(
824 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
825 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100826 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000827 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100828 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
829 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100830 } else if (source.IsFpuRegister()) {
Calin Juravlee460d1d2015-09-29 04:52:17 +0100831 XmmRegister src_reg = source.AsFpuRegister<XmmRegister>();
832 __ movd(destination.AsRegisterPairLow<Register>(), src_reg);
833 __ psrlq(src_reg, Immediate(32));
834 __ movd(destination.AsRegisterPairHigh<Register>(), src_reg);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100835 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000836 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100837 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100838 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
839 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100840 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
841 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100842 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500843 if (source.IsFpuRegister()) {
844 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
845 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000846 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Calin Juravlee460d1d2015-09-29 04:52:17 +0100847 } else if (source.IsRegisterPair()) {
848 size_t elem_size = Primitive::ComponentSize(Primitive::kPrimInt);
849 // Create stack space for 2 elements.
850 __ subl(ESP, Immediate(2 * elem_size));
851 __ movl(Address(ESP, 0), source.AsRegisterPairLow<Register>());
852 __ movl(Address(ESP, elem_size), source.AsRegisterPairHigh<Register>());
853 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
854 // And remove the temporary stack space we allocated.
855 __ addl(ESP, Immediate(2 * elem_size));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100856 } else {
857 LOG(FATAL) << "Unimplemented";
858 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100859 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000860 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100861 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000862 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100863 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100864 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100865 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100866 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000867 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000868 } else if (source.IsConstant()) {
869 HConstant* constant = source.GetConstant();
870 int64_t value;
871 if (constant->IsLongConstant()) {
872 value = constant->AsLongConstant()->GetValue();
873 } else {
874 DCHECK(constant->IsDoubleConstant());
Roland Levillainda4d79b2015-03-24 14:36:11 +0000875 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000876 }
877 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
878 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100879 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000880 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000881 EmitParallelMoves(
882 Location::StackSlot(source.GetStackIndex()),
883 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100884 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000885 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100886 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
887 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100888 }
889 }
890}
891
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100892void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000893 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100894 if (instruction->IsCurrentMethod()) {
895 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
896 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000897 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100898 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000899 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000900 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
901 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000902 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000903 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000904 } else if (location.IsStackSlot()) {
905 __ movl(Address(ESP, location.GetStackIndex()), imm);
906 } else {
907 DCHECK(location.IsConstant());
908 DCHECK_EQ(location.GetConstant(), const_to_move);
909 }
910 } else if (const_to_move->IsLongConstant()) {
911 int64_t value = const_to_move->AsLongConstant()->GetValue();
912 if (location.IsRegisterPair()) {
913 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
914 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
915 } else if (location.IsDoubleStackSlot()) {
916 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000917 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
918 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000919 } else {
920 DCHECK(location.IsConstant());
921 DCHECK_EQ(location.GetConstant(), instruction);
922 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100923 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000924 } else if (instruction->IsTemporary()) {
925 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000926 if (temp_location.IsStackSlot()) {
927 Move32(location, temp_location);
928 } else {
929 DCHECK(temp_location.IsDoubleStackSlot());
930 Move64(location, temp_location);
931 }
Roland Levillain476df552014-10-09 17:51:36 +0100932 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100933 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100934 switch (instruction->GetType()) {
935 case Primitive::kPrimBoolean:
936 case Primitive::kPrimByte:
937 case Primitive::kPrimChar:
938 case Primitive::kPrimShort:
939 case Primitive::kPrimInt:
940 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100941 case Primitive::kPrimFloat:
942 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100943 break;
944
945 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100946 case Primitive::kPrimDouble:
947 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100948 break;
949
950 default:
951 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
952 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000953 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100954 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100955 switch (instruction->GetType()) {
956 case Primitive::kPrimBoolean:
957 case Primitive::kPrimByte:
958 case Primitive::kPrimChar:
959 case Primitive::kPrimShort:
960 case Primitive::kPrimInt:
961 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100962 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000963 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100964 break;
965
966 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100967 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000968 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100969 break;
970
971 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100972 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100973 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000974 }
975}
976
Calin Juravle175dc732015-08-25 15:42:32 +0100977void CodeGeneratorX86::MoveConstant(Location location, int32_t value) {
978 DCHECK(location.IsRegister());
979 __ movl(location.AsRegister<Register>(), Immediate(value));
980}
981
Calin Juravlee460d1d2015-09-29 04:52:17 +0100982void CodeGeneratorX86::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
983 if (Primitive::Is64BitType(dst_type)) {
984 Move64(dst, src);
985 } else {
986 Move32(dst, src);
987 }
988}
989
990void CodeGeneratorX86::AddLocationAsTemp(Location location, LocationSummary* locations) {
991 if (location.IsRegister()) {
992 locations->AddTemp(location);
993 } else if (location.IsRegisterPair()) {
994 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairLow<Register>()));
995 locations->AddTemp(Location::RegisterLocation(location.AsRegisterPairHigh<Register>()));
996 } else {
997 UNIMPLEMENTED(FATAL) << "AddLocationAsTemp not implemented for location " << location;
998 }
999}
1000
David Brazdilfc6a86a2015-06-26 10:33:45 +00001001void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001002 DCHECK(!successor->IsExitBlock());
1003
1004 HBasicBlock* block = got->GetBlock();
1005 HInstruction* previous = got->GetPrevious();
1006
1007 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +00001008 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01001009 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
1010 return;
1011 }
1012
1013 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
1014 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
1015 }
1016 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001017 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001018 }
1019}
1020
David Brazdilfc6a86a2015-06-26 10:33:45 +00001021void LocationsBuilderX86::VisitGoto(HGoto* got) {
1022 got->SetLocations(nullptr);
1023}
1024
1025void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
1026 HandleGoto(got, got->GetSuccessor());
1027}
1028
1029void LocationsBuilderX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1030 try_boundary->SetLocations(nullptr);
1031}
1032
1033void InstructionCodeGeneratorX86::VisitTryBoundary(HTryBoundary* try_boundary) {
1034 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
1035 if (!successor->IsExitBlock()) {
1036 HandleGoto(try_boundary, successor);
1037 }
1038}
1039
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001040void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001041 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001042}
1043
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001044void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001045 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001046}
1047
Mark Mendellc4701932015-04-10 13:18:51 -04001048void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
1049 Label* true_label,
1050 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001051 if (cond->IsFPConditionTrueIfNaN()) {
1052 __ j(kUnordered, true_label);
1053 } else if (cond->IsFPConditionFalseIfNaN()) {
1054 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001055 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001056 __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001057}
1058
1059void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
1060 Label* true_label,
1061 Label* false_label) {
1062 LocationSummary* locations = cond->GetLocations();
1063 Location left = locations->InAt(0);
1064 Location right = locations->InAt(1);
1065 IfCondition if_cond = cond->GetCondition();
1066
Mark Mendellc4701932015-04-10 13:18:51 -04001067 Register left_high = left.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001068 Register left_low = left.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001069 IfCondition true_high_cond = if_cond;
1070 IfCondition false_high_cond = cond->GetOppositeCondition();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001071 Condition final_condition = X86UnsignedOrFPCondition(if_cond);
Mark Mendellc4701932015-04-10 13:18:51 -04001072
1073 // Set the conditions for the test, remembering that == needs to be
1074 // decided using the low words.
1075 switch (if_cond) {
1076 case kCondEQ:
Mark Mendellc4701932015-04-10 13:18:51 -04001077 case kCondNE:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001078 // Nothing to do.
Mark Mendellc4701932015-04-10 13:18:51 -04001079 break;
1080 case kCondLT:
1081 false_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001082 break;
1083 case kCondLE:
1084 true_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001085 break;
1086 case kCondGT:
1087 false_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001088 break;
1089 case kCondGE:
1090 true_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001091 break;
1092 }
1093
1094 if (right.IsConstant()) {
1095 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellc4701932015-04-10 13:18:51 -04001096 int32_t val_high = High32Bits(value);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001097 int32_t val_low = Low32Bits(value);
Mark Mendellc4701932015-04-10 13:18:51 -04001098
1099 if (val_high == 0) {
1100 __ testl(left_high, left_high);
1101 } else {
1102 __ cmpl(left_high, Immediate(val_high));
1103 }
1104 if (if_cond == kCondNE) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001105 __ j(X86SignedCondition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001106 } else if (if_cond == kCondEQ) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001107 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001108 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001109 __ j(X86SignedCondition(true_high_cond), true_label);
1110 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001111 }
1112 // Must be equal high, so compare the lows.
1113 if (val_low == 0) {
1114 __ testl(left_low, left_low);
1115 } else {
1116 __ cmpl(left_low, Immediate(val_low));
1117 }
1118 } else {
Mark Mendellc4701932015-04-10 13:18:51 -04001119 Register right_high = right.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001120 Register right_low = right.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001121
1122 __ cmpl(left_high, right_high);
1123 if (if_cond == kCondNE) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001124 __ j(X86SignedCondition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001125 } else if (if_cond == kCondEQ) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001126 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001127 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001128 __ j(X86SignedCondition(true_high_cond), true_label);
1129 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001130 }
1131 // Must be equal high, so compare the lows.
1132 __ cmpl(left_low, right_low);
1133 }
1134 // The last comparison might be unsigned.
1135 __ j(final_condition, true_label);
1136}
1137
1138void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HIf* if_instr,
1139 HCondition* condition,
1140 Label* true_target,
1141 Label* false_target,
1142 Label* always_true_target) {
1143 LocationSummary* locations = condition->GetLocations();
1144 Location left = locations->InAt(0);
1145 Location right = locations->InAt(1);
1146
1147 // We don't want true_target as a nullptr.
1148 if (true_target == nullptr) {
1149 true_target = always_true_target;
1150 }
1151 bool falls_through = (false_target == nullptr);
1152
1153 // FP compares don't like null false_targets.
1154 if (false_target == nullptr) {
1155 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1156 }
1157
1158 Primitive::Type type = condition->InputAt(0)->GetType();
1159 switch (type) {
1160 case Primitive::kPrimLong:
1161 GenerateLongComparesAndJumps(condition, true_target, false_target);
1162 break;
1163 case Primitive::kPrimFloat:
Mark Mendellc4701932015-04-10 13:18:51 -04001164 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1165 GenerateFPJumps(condition, true_target, false_target);
1166 break;
1167 case Primitive::kPrimDouble:
Mark Mendellc4701932015-04-10 13:18:51 -04001168 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1169 GenerateFPJumps(condition, true_target, false_target);
1170 break;
1171 default:
1172 LOG(FATAL) << "Unexpected compare type " << type;
1173 }
1174
1175 if (!falls_through) {
1176 __ jmp(false_target);
1177 }
1178}
1179
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001180void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
1181 Label* true_target,
1182 Label* false_target,
1183 Label* always_true_target) {
1184 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001185 if (cond->IsIntConstant()) {
1186 // Constant condition, statically compared against 1.
1187 int32_t cond_value = cond->AsIntConstant()->GetValue();
1188 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001189 if (always_true_target != nullptr) {
1190 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001191 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001192 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001193 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001194 DCHECK_EQ(cond_value, 0);
1195 }
1196 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001197 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001198 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
1199 // Moves do not affect the eflags register, so if the condition is
1200 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001201 // again. We can't use the eflags on long/FP conditions if they are
1202 // materialized due to the complex branching.
1203 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001204 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001205 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
Roland Levillain4fa13f62015-07-06 18:11:54 +01001206 && (type != Primitive::kPrimLong && !Primitive::IsFloatingPointType(type));
1207 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001208 if (!eflags_set) {
1209 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001210 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001211 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001212 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001213 } else {
1214 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
1215 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001216 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001217 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001218 __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001219 }
1220 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001221 // Condition has not been materialized, use its inputs as the
1222 // comparison and its condition as the branch condition.
1223
Mark Mendellc4701932015-04-10 13:18:51 -04001224 // Is this a long or FP comparison that has been folded into the HCondition?
1225 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1226 // Generate the comparison directly.
1227 GenerateCompareTestAndBranch(instruction->AsIf(),
1228 cond->AsCondition(),
1229 true_target,
1230 false_target,
1231 always_true_target);
1232 return;
1233 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001234
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001235 Location lhs = cond->GetLocations()->InAt(0);
1236 Location rhs = cond->GetLocations()->InAt(1);
1237 // LHS is guaranteed to be in a register (see
1238 // LocationsBuilderX86::VisitCondition).
1239 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001240 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001241 } else if (rhs.IsConstant()) {
Calin Juravleb3306642015-04-20 18:30:42 +01001242 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -05001243 if (constant == 0) {
1244 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1245 } else {
1246 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1247 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001248 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001249 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001250 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001251 __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001252 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001253 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001254 if (false_target != nullptr) {
1255 __ jmp(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001256 }
1257}
1258
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001259void LocationsBuilderX86::VisitIf(HIf* if_instr) {
1260 LocationSummary* locations =
1261 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1262 HInstruction* cond = if_instr->InputAt(0);
1263 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1264 locations->SetInAt(0, Location::Any());
1265 }
1266}
1267
1268void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
1269 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1270 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1271 Label* always_true_target = true_target;
1272 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1273 if_instr->IfTrueSuccessor())) {
1274 always_true_target = nullptr;
1275 }
1276 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1277 if_instr->IfFalseSuccessor())) {
1278 false_target = nullptr;
1279 }
1280 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1281}
1282
1283void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
1284 LocationSummary* locations = new (GetGraph()->GetArena())
1285 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1286 HInstruction* cond = deoptimize->InputAt(0);
1287 DCHECK(cond->IsCondition());
1288 if (cond->AsCondition()->NeedsMaterialization()) {
1289 locations->SetInAt(0, Location::Any());
1290 }
1291}
1292
1293void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001294 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001295 DeoptimizationSlowPathX86(deoptimize);
1296 codegen_->AddSlowPath(slow_path);
1297 Label* slow_path_entry = slow_path->GetEntryLabel();
1298 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1299}
1300
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001301void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001302 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001303}
1304
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001305void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
1306 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001307}
1308
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001309void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001310 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001311}
1312
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001313void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001314 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001315 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001316}
1317
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001318void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001319 LocationSummary* locations =
1320 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001321 switch (store->InputAt(1)->GetType()) {
1322 case Primitive::kPrimBoolean:
1323 case Primitive::kPrimByte:
1324 case Primitive::kPrimChar:
1325 case Primitive::kPrimShort:
1326 case Primitive::kPrimInt:
1327 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001328 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001329 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1330 break;
1331
1332 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001333 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001334 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1335 break;
1336
1337 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001338 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001339 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001340}
1341
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001342void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001343 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001344}
1345
Roland Levillain0d37cd02015-05-27 16:39:19 +01001346void LocationsBuilderX86::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001347 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001348 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001349 // Handle the long/FP comparisons made in instruction simplification.
1350 switch (cond->InputAt(0)->GetType()) {
1351 case Primitive::kPrimLong: {
1352 locations->SetInAt(0, Location::RequiresRegister());
1353 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1354 if (cond->NeedsMaterialization()) {
1355 locations->SetOut(Location::RequiresRegister());
1356 }
1357 break;
1358 }
1359 case Primitive::kPrimFloat:
1360 case Primitive::kPrimDouble: {
1361 locations->SetInAt(0, Location::RequiresFpuRegister());
1362 locations->SetInAt(1, Location::RequiresFpuRegister());
1363 if (cond->NeedsMaterialization()) {
1364 locations->SetOut(Location::RequiresRegister());
1365 }
1366 break;
1367 }
1368 default:
1369 locations->SetInAt(0, Location::RequiresRegister());
1370 locations->SetInAt(1, Location::Any());
1371 if (cond->NeedsMaterialization()) {
1372 // We need a byte register.
1373 locations->SetOut(Location::RegisterLocation(ECX));
1374 }
1375 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001376 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001377}
1378
Roland Levillain0d37cd02015-05-27 16:39:19 +01001379void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001380 if (!cond->NeedsMaterialization()) {
1381 return;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001382 }
Mark Mendellc4701932015-04-10 13:18:51 -04001383
1384 LocationSummary* locations = cond->GetLocations();
1385 Location lhs = locations->InAt(0);
1386 Location rhs = locations->InAt(1);
1387 Register reg = locations->Out().AsRegister<Register>();
1388 Label true_label, false_label;
1389
1390 switch (cond->InputAt(0)->GetType()) {
1391 default: {
1392 // Integer case.
1393
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01001394 // Clear output register: setb only sets the low byte.
Mark Mendellc4701932015-04-10 13:18:51 -04001395 __ xorl(reg, reg);
1396
1397 if (rhs.IsRegister()) {
1398 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
1399 } else if (rhs.IsConstant()) {
1400 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1401 if (constant == 0) {
1402 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1403 } else {
1404 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1405 }
1406 } else {
1407 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
1408 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001409 __ setb(X86SignedCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001410 return;
1411 }
1412 case Primitive::kPrimLong:
1413 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1414 break;
1415 case Primitive::kPrimFloat:
1416 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1417 GenerateFPJumps(cond, &true_label, &false_label);
1418 break;
1419 case Primitive::kPrimDouble:
1420 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1421 GenerateFPJumps(cond, &true_label, &false_label);
1422 break;
1423 }
1424
1425 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001426 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001427
Roland Levillain4fa13f62015-07-06 18:11:54 +01001428 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001429 __ Bind(&false_label);
1430 __ xorl(reg, reg);
1431 __ jmp(&done_label);
1432
Roland Levillain4fa13f62015-07-06 18:11:54 +01001433 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001434 __ Bind(&true_label);
1435 __ movl(reg, Immediate(1));
1436 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001437}
1438
1439void LocationsBuilderX86::VisitEqual(HEqual* comp) {
1440 VisitCondition(comp);
1441}
1442
1443void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
1444 VisitCondition(comp);
1445}
1446
1447void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
1448 VisitCondition(comp);
1449}
1450
1451void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
1452 VisitCondition(comp);
1453}
1454
1455void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
1456 VisitCondition(comp);
1457}
1458
1459void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
1460 VisitCondition(comp);
1461}
1462
1463void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1464 VisitCondition(comp);
1465}
1466
1467void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1468 VisitCondition(comp);
1469}
1470
1471void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
1472 VisitCondition(comp);
1473}
1474
1475void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
1476 VisitCondition(comp);
1477}
1478
1479void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1480 VisitCondition(comp);
1481}
1482
1483void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1484 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001485}
1486
1487void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001488 LocationSummary* locations =
1489 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001490 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001491}
1492
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001493void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001494 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001495 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001496}
1497
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001498void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1499 LocationSummary* locations =
1500 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1501 locations->SetOut(Location::ConstantLocation(constant));
1502}
1503
1504void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1505 // Will be generated at use site.
1506 UNUSED(constant);
1507}
1508
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001509void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001510 LocationSummary* locations =
1511 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001512 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001513}
1514
1515void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1516 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001517 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001518}
1519
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001520void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1521 LocationSummary* locations =
1522 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1523 locations->SetOut(Location::ConstantLocation(constant));
1524}
1525
1526void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1527 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001528 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001529}
1530
1531void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1532 LocationSummary* locations =
1533 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1534 locations->SetOut(Location::ConstantLocation(constant));
1535}
1536
1537void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1538 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001539 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001540}
1541
Calin Juravle27df7582015-04-17 19:12:31 +01001542void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1543 memory_barrier->SetLocations(nullptr);
1544}
1545
1546void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1547 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1548}
1549
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001550void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001551 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001552}
1553
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001554void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001555 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001556 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001557}
1558
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001559void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001560 LocationSummary* locations =
1561 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001562 switch (ret->InputAt(0)->GetType()) {
1563 case Primitive::kPrimBoolean:
1564 case Primitive::kPrimByte:
1565 case Primitive::kPrimChar:
1566 case Primitive::kPrimShort:
1567 case Primitive::kPrimInt:
1568 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001569 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001570 break;
1571
1572 case Primitive::kPrimLong:
1573 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001574 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001575 break;
1576
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001577 case Primitive::kPrimFloat:
1578 case Primitive::kPrimDouble:
1579 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001580 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001581 break;
1582
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001583 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001584 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001585 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001586}
1587
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001588void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001589 if (kIsDebugBuild) {
1590 switch (ret->InputAt(0)->GetType()) {
1591 case Primitive::kPrimBoolean:
1592 case Primitive::kPrimByte:
1593 case Primitive::kPrimChar:
1594 case Primitive::kPrimShort:
1595 case Primitive::kPrimInt:
1596 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001597 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001598 break;
1599
1600 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001601 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1602 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001603 break;
1604
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001605 case Primitive::kPrimFloat:
1606 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001607 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001608 break;
1609
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001610 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001611 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001612 }
1613 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001614 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001615}
1616
Calin Juravle175dc732015-08-25 15:42:32 +01001617void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1618 // The trampoline uses the same calling convention as dex calling conventions,
1619 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1620 // the method_idx.
1621 HandleInvoke(invoke);
1622}
1623
1624void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1625 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1626}
1627
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001628void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001629 // When we do not run baseline, explicit clinit checks triggered by static
1630 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1631 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001632
Mark Mendellfb8d2792015-03-31 22:16:59 -04001633 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001634 if (intrinsic.TryDispatch(invoke)) {
1635 return;
1636 }
1637
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001638 HandleInvoke(invoke);
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001639
1640 if (codegen_->IsBaseline()) {
1641 // Baseline does not have enough registers if the current method also
1642 // needs a register. We therefore do not require a register for it, and let
1643 // the code generation of the invoke handle it.
1644 LocationSummary* locations = invoke->GetLocations();
1645 Location location = locations->InAt(invoke->GetCurrentMethodInputIndex());
1646 if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) {
1647 locations->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::NoLocation());
1648 }
1649 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001650}
1651
Mark Mendell09ed1a32015-03-25 08:30:06 -04001652static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1653 if (invoke->GetLocations()->Intrinsified()) {
1654 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1655 intrinsic.Dispatch(invoke);
1656 return true;
1657 }
1658 return false;
1659}
1660
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001661void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001662 // When we do not run baseline, explicit clinit checks triggered by static
1663 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1664 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001665
Mark Mendell09ed1a32015-03-25 08:30:06 -04001666 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1667 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001668 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001669
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001670 LocationSummary* locations = invoke->GetLocations();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001671 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001672 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Mingyao Yang8693fe12015-04-17 16:51:08 -07001673 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001674}
1675
1676void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1677 HandleInvoke(invoke);
1678}
1679
1680void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001681 InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001682 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001683}
1684
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001685void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001686 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1687 return;
1688 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001689
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001690 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001691 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001692 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001693}
1694
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001695void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1696 HandleInvoke(invoke);
1697 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001698 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001699}
1700
1701void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1702 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001703 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001704 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1705 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001706 LocationSummary* locations = invoke->GetLocations();
1707 Location receiver = locations->InAt(0);
1708 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1709
1710 // Set the hidden argument.
1711 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001712 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001713
1714 // temp = object->GetClass();
1715 if (receiver.IsStackSlot()) {
1716 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1717 __ movl(temp, Address(temp, class_offset));
1718 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001719 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001720 }
Roland Levillain4d027112015-07-01 15:41:14 +01001721 codegen_->MaybeRecordImplicitNullCheck(invoke);
1722 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001723 // temp = temp->GetImtEntryAt(method_offset);
1724 __ movl(temp, Address(temp, method_offset));
1725 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001726 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001727 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001728
1729 DCHECK(!codegen_->IsLeafMethod());
1730 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1731}
1732
Roland Levillain88cb1752014-10-20 16:36:47 +01001733void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1734 LocationSummary* locations =
1735 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1736 switch (neg->GetResultType()) {
1737 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001738 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001739 locations->SetInAt(0, Location::RequiresRegister());
1740 locations->SetOut(Location::SameAsFirstInput());
1741 break;
1742
Roland Levillain88cb1752014-10-20 16:36:47 +01001743 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001744 locations->SetInAt(0, Location::RequiresFpuRegister());
1745 locations->SetOut(Location::SameAsFirstInput());
1746 locations->AddTemp(Location::RequiresRegister());
1747 locations->AddTemp(Location::RequiresFpuRegister());
1748 break;
1749
Roland Levillain88cb1752014-10-20 16:36:47 +01001750 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001751 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001752 locations->SetOut(Location::SameAsFirstInput());
1753 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001754 break;
1755
1756 default:
1757 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1758 }
1759}
1760
1761void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1762 LocationSummary* locations = neg->GetLocations();
1763 Location out = locations->Out();
1764 Location in = locations->InAt(0);
1765 switch (neg->GetResultType()) {
1766 case Primitive::kPrimInt:
1767 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001768 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001769 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001770 break;
1771
1772 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001773 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001774 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001775 __ negl(out.AsRegisterPairLow<Register>());
1776 // Negation is similar to subtraction from zero. The least
1777 // significant byte triggers a borrow when it is different from
1778 // zero; to take it into account, add 1 to the most significant
1779 // byte if the carry flag (CF) is set to 1 after the first NEGL
1780 // operation.
1781 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1782 __ negl(out.AsRegisterPairHigh<Register>());
1783 break;
1784
Roland Levillain5368c212014-11-27 15:03:41 +00001785 case Primitive::kPrimFloat: {
1786 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001787 Register constant = locations->GetTemp(0).AsRegister<Register>();
1788 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001789 // Implement float negation with an exclusive or with value
1790 // 0x80000000 (mask for bit 31, representing the sign of a
1791 // single-precision floating-point number).
1792 __ movl(constant, Immediate(INT32_C(0x80000000)));
1793 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001794 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001795 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001796 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001797
Roland Levillain5368c212014-11-27 15:03:41 +00001798 case Primitive::kPrimDouble: {
1799 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001800 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001801 // Implement double negation with an exclusive or with value
1802 // 0x8000000000000000 (mask for bit 63, representing the sign of
1803 // a double-precision floating-point number).
1804 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001805 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001806 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001807 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001808
1809 default:
1810 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1811 }
1812}
1813
Roland Levillaindff1f282014-11-05 14:15:05 +00001814void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001815 Primitive::Type result_type = conversion->GetResultType();
1816 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001817 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001818
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001819 // The float-to-long and double-to-long type conversions rely on a
1820 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001821 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001822 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1823 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001824 ? LocationSummary::kCall
1825 : LocationSummary::kNoCall;
1826 LocationSummary* locations =
1827 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1828
David Brazdilb2bd1c52015-03-25 11:17:37 +00001829 // The Java language does not allow treating boolean as an integral type but
1830 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001831
Roland Levillaindff1f282014-11-05 14:15:05 +00001832 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001833 case Primitive::kPrimByte:
1834 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001835 case Primitive::kPrimBoolean:
1836 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001837 case Primitive::kPrimShort:
1838 case Primitive::kPrimInt:
1839 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001840 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001841 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1842 // Make the output overlap to please the register allocator. This greatly simplifies
1843 // the validation of the linear scan implementation
1844 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001845 break;
1846
1847 default:
1848 LOG(FATAL) << "Unexpected type conversion from " << input_type
1849 << " to " << result_type;
1850 }
1851 break;
1852
Roland Levillain01a8d712014-11-14 16:27:39 +00001853 case Primitive::kPrimShort:
1854 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001855 case Primitive::kPrimBoolean:
1856 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001857 case Primitive::kPrimByte:
1858 case Primitive::kPrimInt:
1859 case Primitive::kPrimChar:
1860 // Processing a Dex `int-to-short' instruction.
1861 locations->SetInAt(0, Location::Any());
1862 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1863 break;
1864
1865 default:
1866 LOG(FATAL) << "Unexpected type conversion from " << input_type
1867 << " to " << result_type;
1868 }
1869 break;
1870
Roland Levillain946e1432014-11-11 17:35:19 +00001871 case Primitive::kPrimInt:
1872 switch (input_type) {
1873 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001874 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001875 locations->SetInAt(0, Location::Any());
1876 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1877 break;
1878
1879 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001880 // Processing a Dex `float-to-int' instruction.
1881 locations->SetInAt(0, Location::RequiresFpuRegister());
1882 locations->SetOut(Location::RequiresRegister());
1883 locations->AddTemp(Location::RequiresFpuRegister());
1884 break;
1885
Roland Levillain946e1432014-11-11 17:35:19 +00001886 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001887 // Processing a Dex `double-to-int' instruction.
1888 locations->SetInAt(0, Location::RequiresFpuRegister());
1889 locations->SetOut(Location::RequiresRegister());
1890 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001891 break;
1892
1893 default:
1894 LOG(FATAL) << "Unexpected type conversion from " << input_type
1895 << " to " << result_type;
1896 }
1897 break;
1898
Roland Levillaindff1f282014-11-05 14:15:05 +00001899 case Primitive::kPrimLong:
1900 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001901 case Primitive::kPrimBoolean:
1902 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001903 case Primitive::kPrimByte:
1904 case Primitive::kPrimShort:
1905 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001906 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001907 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001908 locations->SetInAt(0, Location::RegisterLocation(EAX));
1909 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1910 break;
1911
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001912 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001913 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001914 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001915 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001916 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1917 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1918
Vladimir Marko949c91f2015-01-27 10:48:44 +00001919 // The runtime helper puts the result in EAX, EDX.
1920 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001921 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001922 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001923
1924 default:
1925 LOG(FATAL) << "Unexpected type conversion from " << input_type
1926 << " to " << result_type;
1927 }
1928 break;
1929
Roland Levillain981e4542014-11-14 11:47:14 +00001930 case Primitive::kPrimChar:
1931 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001932 case Primitive::kPrimBoolean:
1933 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001934 case Primitive::kPrimByte:
1935 case Primitive::kPrimShort:
1936 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001937 // Processing a Dex `int-to-char' instruction.
1938 locations->SetInAt(0, Location::Any());
1939 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1940 break;
1941
1942 default:
1943 LOG(FATAL) << "Unexpected type conversion from " << input_type
1944 << " to " << result_type;
1945 }
1946 break;
1947
Roland Levillaindff1f282014-11-05 14:15:05 +00001948 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001949 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001950 case Primitive::kPrimBoolean:
1951 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001952 case Primitive::kPrimByte:
1953 case Primitive::kPrimShort:
1954 case Primitive::kPrimInt:
1955 case Primitive::kPrimChar:
1956 // Processing a Dex `int-to-float' instruction.
1957 locations->SetInAt(0, Location::RequiresRegister());
1958 locations->SetOut(Location::RequiresFpuRegister());
1959 break;
1960
1961 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001962 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001963 locations->SetInAt(0, Location::Any());
1964 locations->SetOut(Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001965 break;
1966
Roland Levillaincff13742014-11-17 14:32:17 +00001967 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001968 // Processing a Dex `double-to-float' instruction.
1969 locations->SetInAt(0, Location::RequiresFpuRegister());
1970 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001971 break;
1972
1973 default:
1974 LOG(FATAL) << "Unexpected type conversion from " << input_type
1975 << " to " << result_type;
1976 };
1977 break;
1978
Roland Levillaindff1f282014-11-05 14:15:05 +00001979 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001980 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001981 case Primitive::kPrimBoolean:
1982 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001983 case Primitive::kPrimByte:
1984 case Primitive::kPrimShort:
1985 case Primitive::kPrimInt:
1986 case Primitive::kPrimChar:
1987 // Processing a Dex `int-to-double' instruction.
1988 locations->SetInAt(0, Location::RequiresRegister());
1989 locations->SetOut(Location::RequiresFpuRegister());
1990 break;
1991
1992 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001993 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001994 locations->SetInAt(0, Location::Any());
1995 locations->SetOut(Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001996 break;
1997
Roland Levillaincff13742014-11-17 14:32:17 +00001998 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001999 // Processing a Dex `float-to-double' instruction.
2000 locations->SetInAt(0, Location::RequiresFpuRegister());
2001 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002002 break;
2003
2004 default:
2005 LOG(FATAL) << "Unexpected type conversion from " << input_type
2006 << " to " << result_type;
2007 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002008 break;
2009
2010 default:
2011 LOG(FATAL) << "Unexpected type conversion from " << input_type
2012 << " to " << result_type;
2013 }
2014}
2015
2016void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
2017 LocationSummary* locations = conversion->GetLocations();
2018 Location out = locations->Out();
2019 Location in = locations->InAt(0);
2020 Primitive::Type result_type = conversion->GetResultType();
2021 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002022 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002023 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002024 case Primitive::kPrimByte:
2025 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002026 case Primitive::kPrimBoolean:
2027 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002028 case Primitive::kPrimShort:
2029 case Primitive::kPrimInt:
2030 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002031 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002032 if (in.IsRegister()) {
2033 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002034 } else {
2035 DCHECK(in.GetConstant()->IsIntConstant());
2036 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
2037 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
2038 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00002039 break;
2040
2041 default:
2042 LOG(FATAL) << "Unexpected type conversion from " << input_type
2043 << " to " << result_type;
2044 }
2045 break;
2046
Roland Levillain01a8d712014-11-14 16:27:39 +00002047 case Primitive::kPrimShort:
2048 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002049 case Primitive::kPrimBoolean:
2050 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002051 case Primitive::kPrimByte:
2052 case Primitive::kPrimInt:
2053 case Primitive::kPrimChar:
2054 // Processing a Dex `int-to-short' instruction.
2055 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002056 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002057 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002058 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00002059 } else {
2060 DCHECK(in.GetConstant()->IsIntConstant());
2061 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002062 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00002063 }
2064 break;
2065
2066 default:
2067 LOG(FATAL) << "Unexpected type conversion from " << input_type
2068 << " to " << result_type;
2069 }
2070 break;
2071
Roland Levillain946e1432014-11-11 17:35:19 +00002072 case Primitive::kPrimInt:
2073 switch (input_type) {
2074 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002075 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002076 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002077 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002078 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002079 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00002080 } else {
2081 DCHECK(in.IsConstant());
2082 DCHECK(in.GetConstant()->IsLongConstant());
2083 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002084 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002085 }
2086 break;
2087
Roland Levillain3f8f9362014-12-02 17:45:01 +00002088 case Primitive::kPrimFloat: {
2089 // Processing a Dex `float-to-int' instruction.
2090 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2091 Register output = out.AsRegister<Register>();
2092 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002093 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002094
2095 __ movl(output, Immediate(kPrimIntMax));
2096 // temp = int-to-float(output)
2097 __ cvtsi2ss(temp, output);
2098 // if input >= temp goto done
2099 __ comiss(input, temp);
2100 __ j(kAboveEqual, &done);
2101 // if input == NaN goto nan
2102 __ j(kUnordered, &nan);
2103 // output = float-to-int-truncate(input)
2104 __ cvttss2si(output, input);
2105 __ jmp(&done);
2106 __ Bind(&nan);
2107 // output = 0
2108 __ xorl(output, output);
2109 __ Bind(&done);
2110 break;
2111 }
2112
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002113 case Primitive::kPrimDouble: {
2114 // Processing a Dex `double-to-int' instruction.
2115 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2116 Register output = out.AsRegister<Register>();
2117 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002118 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002119
2120 __ movl(output, Immediate(kPrimIntMax));
2121 // temp = int-to-double(output)
2122 __ cvtsi2sd(temp, output);
2123 // if input >= temp goto done
2124 __ comisd(input, temp);
2125 __ j(kAboveEqual, &done);
2126 // if input == NaN goto nan
2127 __ j(kUnordered, &nan);
2128 // output = double-to-int-truncate(input)
2129 __ cvttsd2si(output, input);
2130 __ jmp(&done);
2131 __ Bind(&nan);
2132 // output = 0
2133 __ xorl(output, output);
2134 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002135 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002136 }
Roland Levillain946e1432014-11-11 17:35:19 +00002137
2138 default:
2139 LOG(FATAL) << "Unexpected type conversion from " << input_type
2140 << " to " << result_type;
2141 }
2142 break;
2143
Roland Levillaindff1f282014-11-05 14:15:05 +00002144 case Primitive::kPrimLong:
2145 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002146 case Primitive::kPrimBoolean:
2147 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002148 case Primitive::kPrimByte:
2149 case Primitive::kPrimShort:
2150 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002151 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002152 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002153 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
2154 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00002155 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00002156 __ cdq();
2157 break;
2158
2159 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002160 // Processing a Dex `float-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002161 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2162 conversion,
2163 conversion->GetDexPc(),
2164 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002165 break;
2166
Roland Levillaindff1f282014-11-05 14:15:05 +00002167 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002168 // Processing a Dex `double-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002169 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2170 conversion,
2171 conversion->GetDexPc(),
2172 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002173 break;
2174
2175 default:
2176 LOG(FATAL) << "Unexpected type conversion from " << input_type
2177 << " to " << result_type;
2178 }
2179 break;
2180
Roland Levillain981e4542014-11-14 11:47:14 +00002181 case Primitive::kPrimChar:
2182 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002183 case Primitive::kPrimBoolean:
2184 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002185 case Primitive::kPrimByte:
2186 case Primitive::kPrimShort:
2187 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002188 // Processing a Dex `Process a Dex `int-to-char'' instruction.
2189 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002190 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00002191 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002192 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00002193 } else {
2194 DCHECK(in.GetConstant()->IsIntConstant());
2195 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002196 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00002197 }
2198 break;
2199
2200 default:
2201 LOG(FATAL) << "Unexpected type conversion from " << input_type
2202 << " to " << result_type;
2203 }
2204 break;
2205
Roland Levillaindff1f282014-11-05 14:15:05 +00002206 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002207 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002208 case Primitive::kPrimBoolean:
2209 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002210 case Primitive::kPrimByte:
2211 case Primitive::kPrimShort:
2212 case Primitive::kPrimInt:
2213 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002214 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002215 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002216 break;
2217
Roland Levillain6d0e4832014-11-27 18:31:21 +00002218 case Primitive::kPrimLong: {
2219 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002220 size_t adjustment = 0;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002221
Roland Levillain232ade02015-04-20 15:14:36 +01002222 // Create stack space for the call to
2223 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
2224 // TODO: enhance register allocator to ask for stack temporaries.
2225 if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
2226 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2227 __ subl(ESP, Immediate(adjustment));
2228 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002229
Roland Levillain232ade02015-04-20 15:14:36 +01002230 // Load the value to the FP stack, using temporaries if needed.
2231 PushOntoFPStack(in, 0, adjustment, false, true);
2232
2233 if (out.IsStackSlot()) {
2234 __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
2235 } else {
2236 __ fstps(Address(ESP, 0));
2237 Location stack_temp = Location::StackSlot(0);
2238 codegen_->Move32(out, stack_temp);
2239 }
2240
2241 // Remove the temporary stack space we allocated.
2242 if (adjustment != 0) {
2243 __ addl(ESP, Immediate(adjustment));
2244 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002245 break;
2246 }
2247
Roland Levillaincff13742014-11-17 14:32:17 +00002248 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002249 // Processing a Dex `double-to-float' instruction.
2250 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002251 break;
2252
2253 default:
2254 LOG(FATAL) << "Unexpected type conversion from " << input_type
2255 << " to " << result_type;
2256 };
2257 break;
2258
Roland Levillaindff1f282014-11-05 14:15:05 +00002259 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002260 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002261 case Primitive::kPrimBoolean:
2262 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002263 case Primitive::kPrimByte:
2264 case Primitive::kPrimShort:
2265 case Primitive::kPrimInt:
2266 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002267 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002268 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002269 break;
2270
Roland Levillain647b9ed2014-11-27 12:06:00 +00002271 case Primitive::kPrimLong: {
2272 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002273 size_t adjustment = 0;
Roland Levillain647b9ed2014-11-27 12:06:00 +00002274
Roland Levillain232ade02015-04-20 15:14:36 +01002275 // Create stack space for the call to
2276 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
2277 // TODO: enhance register allocator to ask for stack temporaries.
2278 if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
2279 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2280 __ subl(ESP, Immediate(adjustment));
2281 }
2282
2283 // Load the value to the FP stack, using temporaries if needed.
2284 PushOntoFPStack(in, 0, adjustment, false, true);
2285
2286 if (out.IsDoubleStackSlot()) {
2287 __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
2288 } else {
2289 __ fstpl(Address(ESP, 0));
2290 Location stack_temp = Location::DoubleStackSlot(0);
2291 codegen_->Move64(out, stack_temp);
2292 }
2293
2294 // Remove the temporary stack space we allocated.
2295 if (adjustment != 0) {
2296 __ addl(ESP, Immediate(adjustment));
2297 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002298 break;
2299 }
2300
Roland Levillaincff13742014-11-17 14:32:17 +00002301 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002302 // Processing a Dex `float-to-double' instruction.
2303 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002304 break;
2305
2306 default:
2307 LOG(FATAL) << "Unexpected type conversion from " << input_type
2308 << " to " << result_type;
2309 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002310 break;
2311
2312 default:
2313 LOG(FATAL) << "Unexpected type conversion from " << input_type
2314 << " to " << result_type;
2315 }
2316}
2317
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002318void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002319 LocationSummary* locations =
2320 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002321 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002322 case Primitive::kPrimInt: {
2323 locations->SetInAt(0, Location::RequiresRegister());
2324 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2325 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2326 break;
2327 }
2328
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002329 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002330 locations->SetInAt(0, Location::RequiresRegister());
2331 locations->SetInAt(1, Location::Any());
2332 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002333 break;
2334 }
2335
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002336 case Primitive::kPrimFloat:
2337 case Primitive::kPrimDouble: {
2338 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002339 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002340 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002341 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002342 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002343
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002344 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002345 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2346 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002347 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002348}
2349
2350void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
2351 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002352 Location first = locations->InAt(0);
2353 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05002354 Location out = locations->Out();
2355
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002356 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002357 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002358 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002359 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2360 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002361 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2362 __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
Mark Mendell09b84632015-02-13 17:48:38 -05002363 } else {
2364 __ leal(out.AsRegister<Register>(), Address(
2365 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
2366 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002367 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002368 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
2369 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2370 __ addl(out.AsRegister<Register>(), Immediate(value));
2371 } else {
2372 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
2373 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002374 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05002375 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002376 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002377 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002378 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002379 }
2380
2381 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002382 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002383 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2384 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002385 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002386 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
2387 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002388 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002389 } else {
2390 DCHECK(second.IsConstant()) << second;
2391 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2392 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2393 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002394 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002395 break;
2396 }
2397
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002398 case Primitive::kPrimFloat: {
2399 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002400 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002401 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2402 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2403 DCHECK(!const_area->NeedsMaterialization());
2404 __ addss(first.AsFpuRegister<XmmRegister>(),
2405 codegen_->LiteralFloatAddress(
2406 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2407 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2408 } else {
2409 DCHECK(second.IsStackSlot());
2410 __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002411 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002412 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002413 }
2414
2415 case Primitive::kPrimDouble: {
2416 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002417 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002418 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2419 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2420 DCHECK(!const_area->NeedsMaterialization());
2421 __ addsd(first.AsFpuRegister<XmmRegister>(),
2422 codegen_->LiteralDoubleAddress(
2423 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2424 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2425 } else {
2426 DCHECK(second.IsDoubleStackSlot());
2427 __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002428 }
2429 break;
2430 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002431
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002432 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002433 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002434 }
2435}
2436
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002437void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002438 LocationSummary* locations =
2439 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002440 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002441 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002442 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002443 locations->SetInAt(0, Location::RequiresRegister());
2444 locations->SetInAt(1, Location::Any());
2445 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002446 break;
2447 }
Calin Juravle11351682014-10-23 15:38:15 +01002448 case Primitive::kPrimFloat:
2449 case Primitive::kPrimDouble: {
2450 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002451 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002452 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002453 break;
Calin Juravle11351682014-10-23 15:38:15 +01002454 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002455
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002456 default:
Calin Juravle11351682014-10-23 15:38:15 +01002457 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002458 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002459}
2460
2461void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
2462 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002463 Location first = locations->InAt(0);
2464 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01002465 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002466 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002467 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002468 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002469 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002470 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002471 __ subl(first.AsRegister<Register>(),
2472 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002473 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002474 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002475 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002476 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002477 }
2478
2479 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002480 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01002481 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2482 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002483 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01002484 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002485 __ sbbl(first.AsRegisterPairHigh<Register>(),
2486 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002487 } else {
2488 DCHECK(second.IsConstant()) << second;
2489 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2490 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2491 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002492 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002493 break;
2494 }
2495
Calin Juravle11351682014-10-23 15:38:15 +01002496 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002497 if (second.IsFpuRegister()) {
2498 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2499 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2500 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2501 DCHECK(!const_area->NeedsMaterialization());
2502 __ subss(first.AsFpuRegister<XmmRegister>(),
2503 codegen_->LiteralFloatAddress(
2504 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2505 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2506 } else {
2507 DCHECK(second.IsStackSlot());
2508 __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2509 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002510 break;
Calin Juravle11351682014-10-23 15:38:15 +01002511 }
2512
2513 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002514 if (second.IsFpuRegister()) {
2515 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2516 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2517 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2518 DCHECK(!const_area->NeedsMaterialization());
2519 __ subsd(first.AsFpuRegister<XmmRegister>(),
2520 codegen_->LiteralDoubleAddress(
2521 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2522 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2523 } else {
2524 DCHECK(second.IsDoubleStackSlot());
2525 __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2526 }
Calin Juravle11351682014-10-23 15:38:15 +01002527 break;
2528 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002529
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002530 default:
Calin Juravle11351682014-10-23 15:38:15 +01002531 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002532 }
2533}
2534
Calin Juravle34bacdf2014-10-07 20:23:36 +01002535void LocationsBuilderX86::VisitMul(HMul* mul) {
2536 LocationSummary* locations =
2537 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2538 switch (mul->GetResultType()) {
2539 case Primitive::kPrimInt:
2540 locations->SetInAt(0, Location::RequiresRegister());
2541 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002542 if (mul->InputAt(1)->IsIntConstant()) {
2543 // Can use 3 operand multiply.
2544 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2545 } else {
2546 locations->SetOut(Location::SameAsFirstInput());
2547 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002548 break;
2549 case Primitive::kPrimLong: {
2550 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002551 locations->SetInAt(1, Location::Any());
2552 locations->SetOut(Location::SameAsFirstInput());
2553 // Needed for imul on 32bits with 64bits output.
2554 locations->AddTemp(Location::RegisterLocation(EAX));
2555 locations->AddTemp(Location::RegisterLocation(EDX));
2556 break;
2557 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002558 case Primitive::kPrimFloat:
2559 case Primitive::kPrimDouble: {
2560 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002561 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002562 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002563 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002564 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002565
2566 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002567 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002568 }
2569}
2570
2571void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2572 LocationSummary* locations = mul->GetLocations();
2573 Location first = locations->InAt(0);
2574 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002575 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002576
2577 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002578 case Primitive::kPrimInt:
2579 // The constant may have ended up in a register, so test explicitly to avoid
2580 // problems where the output may not be the same as the first operand.
2581 if (mul->InputAt(1)->IsIntConstant()) {
2582 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2583 __ imull(out.AsRegister<Register>(), first.AsRegister<Register>(), imm);
2584 } else if (second.IsRegister()) {
2585 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002586 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002587 } else {
2588 DCHECK(second.IsStackSlot());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002589 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002590 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002591 }
2592 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002593
2594 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002595 Register in1_hi = first.AsRegisterPairHigh<Register>();
2596 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002597 Register eax = locations->GetTemp(0).AsRegister<Register>();
2598 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002599
2600 DCHECK_EQ(EAX, eax);
2601 DCHECK_EQ(EDX, edx);
2602
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002603 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002604 // output: in1
2605 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2606 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2607 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002608 if (second.IsConstant()) {
2609 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002610
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002611 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2612 int32_t low_value = Low32Bits(value);
2613 int32_t high_value = High32Bits(value);
2614 Immediate low(low_value);
2615 Immediate high(high_value);
2616
2617 __ movl(eax, high);
2618 // eax <- in1.lo * in2.hi
2619 __ imull(eax, in1_lo);
2620 // in1.hi <- in1.hi * in2.lo
2621 __ imull(in1_hi, low);
2622 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2623 __ addl(in1_hi, eax);
2624 // move in2_lo to eax to prepare for double precision
2625 __ movl(eax, low);
2626 // edx:eax <- in1.lo * in2.lo
2627 __ mull(in1_lo);
2628 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2629 __ addl(in1_hi, edx);
2630 // in1.lo <- (in1.lo * in2.lo)[31:0];
2631 __ movl(in1_lo, eax);
2632 } else if (second.IsRegisterPair()) {
2633 Register in2_hi = second.AsRegisterPairHigh<Register>();
2634 Register in2_lo = second.AsRegisterPairLow<Register>();
2635
2636 __ movl(eax, in2_hi);
2637 // eax <- in1.lo * in2.hi
2638 __ imull(eax, in1_lo);
2639 // in1.hi <- in1.hi * in2.lo
2640 __ imull(in1_hi, in2_lo);
2641 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2642 __ addl(in1_hi, eax);
2643 // move in1_lo to eax to prepare for double precision
2644 __ movl(eax, in1_lo);
2645 // edx:eax <- in1.lo * in2.lo
2646 __ mull(in2_lo);
2647 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2648 __ addl(in1_hi, edx);
2649 // in1.lo <- (in1.lo * in2.lo)[31:0];
2650 __ movl(in1_lo, eax);
2651 } else {
2652 DCHECK(second.IsDoubleStackSlot()) << second;
2653 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2654 Address in2_lo(ESP, second.GetStackIndex());
2655
2656 __ movl(eax, in2_hi);
2657 // eax <- in1.lo * in2.hi
2658 __ imull(eax, in1_lo);
2659 // in1.hi <- in1.hi * in2.lo
2660 __ imull(in1_hi, in2_lo);
2661 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2662 __ addl(in1_hi, eax);
2663 // move in1_lo to eax to prepare for double precision
2664 __ movl(eax, in1_lo);
2665 // edx:eax <- in1.lo * in2.lo
2666 __ mull(in2_lo);
2667 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2668 __ addl(in1_hi, edx);
2669 // in1.lo <- (in1.lo * in2.lo)[31:0];
2670 __ movl(in1_lo, eax);
2671 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002672
2673 break;
2674 }
2675
Calin Juravleb5bfa962014-10-21 18:02:24 +01002676 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002677 DCHECK(first.Equals(locations->Out()));
2678 if (second.IsFpuRegister()) {
2679 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2680 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2681 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2682 DCHECK(!const_area->NeedsMaterialization());
2683 __ mulss(first.AsFpuRegister<XmmRegister>(),
2684 codegen_->LiteralFloatAddress(
2685 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2686 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2687 } else {
2688 DCHECK(second.IsStackSlot());
2689 __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2690 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002691 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002692 }
2693
2694 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002695 DCHECK(first.Equals(locations->Out()));
2696 if (second.IsFpuRegister()) {
2697 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2698 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2699 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2700 DCHECK(!const_area->NeedsMaterialization());
2701 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2702 codegen_->LiteralDoubleAddress(
2703 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2704 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2705 } else {
2706 DCHECK(second.IsDoubleStackSlot());
2707 __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2708 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002709 break;
2710 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002711
2712 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002713 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002714 }
2715}
2716
Roland Levillain232ade02015-04-20 15:14:36 +01002717void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
2718 uint32_t temp_offset,
2719 uint32_t stack_adjustment,
2720 bool is_fp,
2721 bool is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002722 if (source.IsStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002723 DCHECK(!is_wide);
2724 if (is_fp) {
2725 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2726 } else {
2727 __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2728 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002729 } else if (source.IsDoubleStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002730 DCHECK(is_wide);
2731 if (is_fp) {
2732 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2733 } else {
2734 __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2735 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002736 } else {
2737 // Write the value to the temporary location on the stack and load to FP stack.
Roland Levillain232ade02015-04-20 15:14:36 +01002738 if (!is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002739 Location stack_temp = Location::StackSlot(temp_offset);
2740 codegen_->Move32(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002741 if (is_fp) {
2742 __ flds(Address(ESP, temp_offset));
2743 } else {
2744 __ filds(Address(ESP, temp_offset));
2745 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002746 } else {
2747 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2748 codegen_->Move64(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002749 if (is_fp) {
2750 __ fldl(Address(ESP, temp_offset));
2751 } else {
2752 __ fildl(Address(ESP, temp_offset));
2753 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002754 }
2755 }
2756}
2757
2758void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2759 Primitive::Type type = rem->GetResultType();
2760 bool is_float = type == Primitive::kPrimFloat;
2761 size_t elem_size = Primitive::ComponentSize(type);
2762 LocationSummary* locations = rem->GetLocations();
2763 Location first = locations->InAt(0);
2764 Location second = locations->InAt(1);
2765 Location out = locations->Out();
2766
2767 // Create stack space for 2 elements.
2768 // TODO: enhance register allocator to ask for stack temporaries.
2769 __ subl(ESP, Immediate(2 * elem_size));
2770
2771 // Load the values to the FP stack in reverse order, using temporaries if needed.
Roland Levillain232ade02015-04-20 15:14:36 +01002772 const bool is_wide = !is_float;
2773 PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp */ true, is_wide);
2774 PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp */ true, is_wide);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002775
2776 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002777 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002778 __ Bind(&retry);
2779 __ fprem();
2780
2781 // Move FP status to AX.
2782 __ fstsw();
2783
2784 // And see if the argument reduction is complete. This is signaled by the
2785 // C2 FPU flag bit set to 0.
2786 __ andl(EAX, Immediate(kC2ConditionMask));
2787 __ j(kNotEqual, &retry);
2788
2789 // We have settled on the final value. Retrieve it into an XMM register.
2790 // Store FP top of stack to real stack.
2791 if (is_float) {
2792 __ fsts(Address(ESP, 0));
2793 } else {
2794 __ fstl(Address(ESP, 0));
2795 }
2796
2797 // Pop the 2 items from the FP stack.
2798 __ fucompp();
2799
2800 // Load the value from the stack into an XMM register.
2801 DCHECK(out.IsFpuRegister()) << out;
2802 if (is_float) {
2803 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2804 } else {
2805 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2806 }
2807
2808 // And remove the temporary stack space we allocated.
2809 __ addl(ESP, Immediate(2 * elem_size));
2810}
2811
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002812
2813void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2814 DCHECK(instruction->IsDiv() || instruction->IsRem());
2815
2816 LocationSummary* locations = instruction->GetLocations();
2817 DCHECK(locations->InAt(1).IsConstant());
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002818 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002819
2820 Register out_register = locations->Out().AsRegister<Register>();
2821 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002822 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002823
2824 DCHECK(imm == 1 || imm == -1);
2825
2826 if (instruction->IsRem()) {
2827 __ xorl(out_register, out_register);
2828 } else {
2829 __ movl(out_register, input_register);
2830 if (imm == -1) {
2831 __ negl(out_register);
2832 }
2833 }
2834}
2835
2836
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002837void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002838 LocationSummary* locations = instruction->GetLocations();
2839
2840 Register out_register = locations->Out().AsRegister<Register>();
2841 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002842 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002843
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002844 DCHECK(IsPowerOfTwo(std::abs(imm)));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002845 Register num = locations->GetTemp(0).AsRegister<Register>();
2846
2847 __ leal(num, Address(input_register, std::abs(imm) - 1));
2848 __ testl(input_register, input_register);
2849 __ cmovl(kGreaterEqual, num, input_register);
2850 int shift = CTZ(imm);
2851 __ sarl(num, Immediate(shift));
2852
2853 if (imm < 0) {
2854 __ negl(num);
2855 }
2856
2857 __ movl(out_register, num);
2858}
2859
2860void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2861 DCHECK(instruction->IsDiv() || instruction->IsRem());
2862
2863 LocationSummary* locations = instruction->GetLocations();
2864 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2865
2866 Register eax = locations->InAt(0).AsRegister<Register>();
2867 Register out = locations->Out().AsRegister<Register>();
2868 Register num;
2869 Register edx;
2870
2871 if (instruction->IsDiv()) {
2872 edx = locations->GetTemp(0).AsRegister<Register>();
2873 num = locations->GetTemp(1).AsRegister<Register>();
2874 } else {
2875 edx = locations->Out().AsRegister<Register>();
2876 num = locations->GetTemp(0).AsRegister<Register>();
2877 }
2878
2879 DCHECK_EQ(EAX, eax);
2880 DCHECK_EQ(EDX, edx);
2881 if (instruction->IsDiv()) {
2882 DCHECK_EQ(EAX, out);
2883 } else {
2884 DCHECK_EQ(EDX, out);
2885 }
2886
2887 int64_t magic;
2888 int shift;
2889 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2890
Mark Mendell0c9497d2015-08-21 09:30:05 -04002891 NearLabel ndiv;
2892 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002893 // If numerator is 0, the result is 0, no computation needed.
2894 __ testl(eax, eax);
2895 __ j(kNotEqual, &ndiv);
2896
2897 __ xorl(out, out);
2898 __ jmp(&end);
2899
2900 __ Bind(&ndiv);
2901
2902 // Save the numerator.
2903 __ movl(num, eax);
2904
2905 // EAX = magic
2906 __ movl(eax, Immediate(magic));
2907
2908 // EDX:EAX = magic * numerator
2909 __ imull(num);
2910
2911 if (imm > 0 && magic < 0) {
2912 // EDX += num
2913 __ addl(edx, num);
2914 } else if (imm < 0 && magic > 0) {
2915 __ subl(edx, num);
2916 }
2917
2918 // Shift if needed.
2919 if (shift != 0) {
2920 __ sarl(edx, Immediate(shift));
2921 }
2922
2923 // EDX += 1 if EDX < 0
2924 __ movl(eax, edx);
2925 __ shrl(edx, Immediate(31));
2926 __ addl(edx, eax);
2927
2928 if (instruction->IsRem()) {
2929 __ movl(eax, num);
2930 __ imull(edx, Immediate(imm));
2931 __ subl(eax, edx);
2932 __ movl(edx, eax);
2933 } else {
2934 __ movl(eax, edx);
2935 }
2936 __ Bind(&end);
2937}
2938
Calin Juravlebacfec32014-11-14 15:54:36 +00002939void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2940 DCHECK(instruction->IsDiv() || instruction->IsRem());
2941
2942 LocationSummary* locations = instruction->GetLocations();
2943 Location out = locations->Out();
2944 Location first = locations->InAt(0);
2945 Location second = locations->InAt(1);
2946 bool is_div = instruction->IsDiv();
2947
2948 switch (instruction->GetResultType()) {
2949 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002950 DCHECK_EQ(EAX, first.AsRegister<Register>());
2951 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002952
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002953 if (instruction->InputAt(1)->IsIntConstant()) {
2954 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002955
2956 if (imm == 0) {
2957 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
2958 } else if (imm == 1 || imm == -1) {
2959 DivRemOneOrMinusOne(instruction);
2960 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002961 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002962 } else {
2963 DCHECK(imm <= -2 || imm >= 2);
2964 GenerateDivRemWithAnyConstant(instruction);
2965 }
2966 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07002967 SlowPathCode* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002968 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002969 is_div);
2970 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002971
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002972 Register second_reg = second.AsRegister<Register>();
2973 // 0x80000000/-1 triggers an arithmetic exception!
2974 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2975 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002976
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002977 __ cmpl(second_reg, Immediate(-1));
2978 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002979
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002980 // edx:eax <- sign-extended of eax
2981 __ cdq();
2982 // eax = quotient, edx = remainder
2983 __ idivl(second_reg);
2984 __ Bind(slow_path->GetExitLabel());
2985 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002986 break;
2987 }
2988
2989 case Primitive::kPrimLong: {
2990 InvokeRuntimeCallingConvention calling_convention;
2991 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2992 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2993 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2994 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2995 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2996 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2997
2998 if (is_div) {
Alexandre Rames8158f282015-08-07 10:26:17 +01002999 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv),
3000 instruction,
3001 instruction->GetDexPc(),
3002 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00003003 } else {
Alexandre Rames8158f282015-08-07 10:26:17 +01003004 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod),
3005 instruction,
3006 instruction->GetDexPc(),
3007 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00003008 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003009 break;
3010 }
3011
3012 default:
3013 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
3014 }
3015}
3016
Calin Juravle7c4954d2014-10-28 16:57:40 +00003017void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003018 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003019 ? LocationSummary::kCall
3020 : LocationSummary::kNoCall;
3021 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
3022
Calin Juravle7c4954d2014-10-28 16:57:40 +00003023 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00003024 case Primitive::kPrimInt: {
3025 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003026 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003027 locations->SetOut(Location::SameAsFirstInput());
3028 // Intel uses edx:eax as the dividend.
3029 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003030 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3031 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
3032 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003033 if (div->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003034 locations->AddTemp(Location::RequiresRegister());
3035 }
Calin Juravled0d48522014-11-04 16:40:20 +00003036 break;
3037 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003038 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003039 InvokeRuntimeCallingConvention calling_convention;
3040 locations->SetInAt(0, Location::RegisterPairLocation(
3041 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3042 locations->SetInAt(1, Location::RegisterPairLocation(
3043 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3044 // Runtime helper puts the result in EAX, EDX.
3045 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00003046 break;
3047 }
3048 case Primitive::kPrimFloat:
3049 case Primitive::kPrimDouble: {
3050 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04003051 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003052 locations->SetOut(Location::SameAsFirstInput());
3053 break;
3054 }
3055
3056 default:
3057 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3058 }
3059}
3060
3061void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
3062 LocationSummary* locations = div->GetLocations();
3063 Location first = locations->InAt(0);
3064 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003065
3066 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003067 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00003068 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003069 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003070 break;
3071 }
3072
3073 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003074 if (second.IsFpuRegister()) {
3075 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3076 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3077 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3078 DCHECK(!const_area->NeedsMaterialization());
3079 __ divss(first.AsFpuRegister<XmmRegister>(),
3080 codegen_->LiteralFloatAddress(
3081 const_area->GetConstant()->AsFloatConstant()->GetValue(),
3082 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3083 } else {
3084 DCHECK(second.IsStackSlot());
3085 __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3086 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003087 break;
3088 }
3089
3090 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003091 if (second.IsFpuRegister()) {
3092 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3093 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3094 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3095 DCHECK(!const_area->NeedsMaterialization());
3096 __ divsd(first.AsFpuRegister<XmmRegister>(),
3097 codegen_->LiteralDoubleAddress(
3098 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
3099 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3100 } else {
3101 DCHECK(second.IsDoubleStackSlot());
3102 __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3103 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003104 break;
3105 }
3106
3107 default:
3108 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3109 }
3110}
3111
Calin Juravlebacfec32014-11-14 15:54:36 +00003112void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003113 Primitive::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003114
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003115 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
3116 ? LocationSummary::kCall
3117 : LocationSummary::kNoCall;
3118 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00003119
Calin Juravled2ec87d2014-12-08 14:24:46 +00003120 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003121 case Primitive::kPrimInt: {
3122 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003123 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003124 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003125 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3126 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
3127 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003128 if (rem->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003129 locations->AddTemp(Location::RequiresRegister());
3130 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003131 break;
3132 }
3133 case Primitive::kPrimLong: {
3134 InvokeRuntimeCallingConvention calling_convention;
3135 locations->SetInAt(0, Location::RegisterPairLocation(
3136 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3137 locations->SetInAt(1, Location::RegisterPairLocation(
3138 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3139 // Runtime helper puts the result in EAX, EDX.
3140 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
3141 break;
3142 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003143 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003144 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003145 locations->SetInAt(0, Location::Any());
3146 locations->SetInAt(1, Location::Any());
3147 locations->SetOut(Location::RequiresFpuRegister());
3148 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003149 break;
3150 }
3151
3152 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003153 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003154 }
3155}
3156
3157void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
3158 Primitive::Type type = rem->GetResultType();
3159 switch (type) {
3160 case Primitive::kPrimInt:
3161 case Primitive::kPrimLong: {
3162 GenerateDivRemIntegral(rem);
3163 break;
3164 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003165 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00003166 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003167 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00003168 break;
3169 }
3170 default:
3171 LOG(FATAL) << "Unexpected rem type " << type;
3172 }
3173}
3174
Calin Juravled0d48522014-11-04 16:40:20 +00003175void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003176 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3177 ? LocationSummary::kCallOnSlowPath
3178 : LocationSummary::kNoCall;
3179 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003180 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003181 case Primitive::kPrimByte:
3182 case Primitive::kPrimChar:
3183 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003184 case Primitive::kPrimInt: {
3185 locations->SetInAt(0, Location::Any());
3186 break;
3187 }
3188 case Primitive::kPrimLong: {
3189 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3190 if (!instruction->IsConstant()) {
3191 locations->AddTemp(Location::RequiresRegister());
3192 }
3193 break;
3194 }
3195 default:
3196 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3197 }
Calin Juravled0d48522014-11-04 16:40:20 +00003198 if (instruction->HasUses()) {
3199 locations->SetOut(Location::SameAsFirstInput());
3200 }
3201}
3202
3203void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003204 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003205 codegen_->AddSlowPath(slow_path);
3206
3207 LocationSummary* locations = instruction->GetLocations();
3208 Location value = locations->InAt(0);
3209
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003210 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003211 case Primitive::kPrimByte:
3212 case Primitive::kPrimChar:
3213 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003214 case Primitive::kPrimInt: {
3215 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003216 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003217 __ j(kEqual, slow_path->GetEntryLabel());
3218 } else if (value.IsStackSlot()) {
3219 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
3220 __ j(kEqual, slow_path->GetEntryLabel());
3221 } else {
3222 DCHECK(value.IsConstant()) << value;
3223 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3224 __ jmp(slow_path->GetEntryLabel());
3225 }
3226 }
3227 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003228 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003229 case Primitive::kPrimLong: {
3230 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003231 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003232 __ movl(temp, value.AsRegisterPairLow<Register>());
3233 __ orl(temp, value.AsRegisterPairHigh<Register>());
3234 __ j(kEqual, slow_path->GetEntryLabel());
3235 } else {
3236 DCHECK(value.IsConstant()) << value;
3237 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3238 __ jmp(slow_path->GetEntryLabel());
3239 }
3240 }
3241 break;
3242 }
3243 default:
3244 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003245 }
Calin Juravled0d48522014-11-04 16:40:20 +00003246}
3247
Calin Juravle9aec02f2014-11-18 23:06:35 +00003248void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
3249 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3250
3251 LocationSummary* locations =
3252 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3253
3254 switch (op->GetResultType()) {
Mark P Mendell73945692015-04-29 14:56:17 +00003255 case Primitive::kPrimInt:
Calin Juravle9aec02f2014-11-18 23:06:35 +00003256 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003257 // Can't have Location::Any() and output SameAsFirstInput()
Calin Juravle9aec02f2014-11-18 23:06:35 +00003258 locations->SetInAt(0, Location::RequiresRegister());
Mark P Mendell73945692015-04-29 14:56:17 +00003259 // The shift count needs to be in CL or a constant.
3260 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003261 locations->SetOut(Location::SameAsFirstInput());
3262 break;
3263 }
3264 default:
3265 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3266 }
3267}
3268
3269void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
3270 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3271
3272 LocationSummary* locations = op->GetLocations();
3273 Location first = locations->InAt(0);
3274 Location second = locations->InAt(1);
3275 DCHECK(first.Equals(locations->Out()));
3276
3277 switch (op->GetResultType()) {
3278 case Primitive::kPrimInt: {
Mark P Mendell73945692015-04-29 14:56:17 +00003279 DCHECK(first.IsRegister());
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003280 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003281 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003282 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003283 DCHECK_EQ(ECX, second_reg);
3284 if (op->IsShl()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003285 __ shll(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003286 } else if (op->IsShr()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003287 __ sarl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003288 } else {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003289 __ shrl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003290 }
3291 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003292 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue;
3293 if (shift == 0) {
3294 return;
3295 }
3296 Immediate imm(shift);
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003297 if (op->IsShl()) {
3298 __ shll(first_reg, imm);
3299 } else if (op->IsShr()) {
3300 __ sarl(first_reg, imm);
3301 } else {
3302 __ shrl(first_reg, imm);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003303 }
3304 }
3305 break;
3306 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003307 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003308 if (second.IsRegister()) {
3309 Register second_reg = second.AsRegister<Register>();
3310 DCHECK_EQ(ECX, second_reg);
3311 if (op->IsShl()) {
3312 GenerateShlLong(first, second_reg);
3313 } else if (op->IsShr()) {
3314 GenerateShrLong(first, second_reg);
3315 } else {
3316 GenerateUShrLong(first, second_reg);
3317 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003318 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003319 // Shift by a constant.
3320 int shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue;
3321 // Nothing to do if the shift is 0, as the input is already the output.
3322 if (shift != 0) {
3323 if (op->IsShl()) {
3324 GenerateShlLong(first, shift);
3325 } else if (op->IsShr()) {
3326 GenerateShrLong(first, shift);
3327 } else {
3328 GenerateUShrLong(first, shift);
3329 }
3330 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003331 }
3332 break;
3333 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003334 default:
3335 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3336 }
3337}
3338
Mark P Mendell73945692015-04-29 14:56:17 +00003339void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
3340 Register low = loc.AsRegisterPairLow<Register>();
3341 Register high = loc.AsRegisterPairHigh<Register>();
Mark Mendellba56d062015-05-05 21:34:03 -04003342 if (shift == 1) {
3343 // This is just an addition.
3344 __ addl(low, low);
3345 __ adcl(high, high);
3346 } else if (shift == 32) {
Mark P Mendell73945692015-04-29 14:56:17 +00003347 // Shift by 32 is easy. High gets low, and low gets 0.
3348 codegen_->EmitParallelMoves(
3349 loc.ToLow(),
3350 loc.ToHigh(),
3351 Primitive::kPrimInt,
3352 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3353 loc.ToLow(),
3354 Primitive::kPrimInt);
3355 } else if (shift > 32) {
3356 // Low part becomes 0. High part is low part << (shift-32).
3357 __ movl(high, low);
3358 __ shll(high, Immediate(shift - 32));
3359 __ xorl(low, low);
3360 } else {
3361 // Between 1 and 31.
3362 __ shld(high, low, Immediate(shift));
3363 __ shll(low, Immediate(shift));
3364 }
3365}
3366
Calin Juravle9aec02f2014-11-18 23:06:35 +00003367void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003368 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003369 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
3370 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
3371 __ testl(shifter, Immediate(32));
3372 __ j(kEqual, &done);
3373 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
3374 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
3375 __ Bind(&done);
3376}
3377
Mark P Mendell73945692015-04-29 14:56:17 +00003378void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
3379 Register low = loc.AsRegisterPairLow<Register>();
3380 Register high = loc.AsRegisterPairHigh<Register>();
3381 if (shift == 32) {
3382 // Need to copy the sign.
3383 DCHECK_NE(low, high);
3384 __ movl(low, high);
3385 __ sarl(high, Immediate(31));
3386 } else if (shift > 32) {
3387 DCHECK_NE(low, high);
3388 // High part becomes sign. Low part is shifted by shift - 32.
3389 __ movl(low, high);
3390 __ sarl(high, Immediate(31));
3391 __ sarl(low, Immediate(shift - 32));
3392 } else {
3393 // Between 1 and 31.
3394 __ shrd(low, high, Immediate(shift));
3395 __ sarl(high, Immediate(shift));
3396 }
3397}
3398
Calin Juravle9aec02f2014-11-18 23:06:35 +00003399void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003400 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003401 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3402 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
3403 __ testl(shifter, Immediate(32));
3404 __ j(kEqual, &done);
3405 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3406 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
3407 __ Bind(&done);
3408}
3409
Mark P Mendell73945692015-04-29 14:56:17 +00003410void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
3411 Register low = loc.AsRegisterPairLow<Register>();
3412 Register high = loc.AsRegisterPairHigh<Register>();
3413 if (shift == 32) {
3414 // Shift by 32 is easy. Low gets high, and high gets 0.
3415 codegen_->EmitParallelMoves(
3416 loc.ToHigh(),
3417 loc.ToLow(),
3418 Primitive::kPrimInt,
3419 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3420 loc.ToHigh(),
3421 Primitive::kPrimInt);
3422 } else if (shift > 32) {
3423 // Low part is high >> (shift - 32). High part becomes 0.
3424 __ movl(low, high);
3425 __ shrl(low, Immediate(shift - 32));
3426 __ xorl(high, high);
3427 } else {
3428 // Between 1 and 31.
3429 __ shrd(low, high, Immediate(shift));
3430 __ shrl(high, Immediate(shift));
3431 }
3432}
3433
Calin Juravle9aec02f2014-11-18 23:06:35 +00003434void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003435 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003436 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3437 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
3438 __ testl(shifter, Immediate(32));
3439 __ j(kEqual, &done);
3440 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3441 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
3442 __ Bind(&done);
3443}
3444
3445void LocationsBuilderX86::VisitShl(HShl* shl) {
3446 HandleShift(shl);
3447}
3448
3449void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
3450 HandleShift(shl);
3451}
3452
3453void LocationsBuilderX86::VisitShr(HShr* shr) {
3454 HandleShift(shr);
3455}
3456
3457void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
3458 HandleShift(shr);
3459}
3460
3461void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
3462 HandleShift(ushr);
3463}
3464
3465void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
3466 HandleShift(ushr);
3467}
3468
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003469void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003470 LocationSummary* locations =
3471 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003472 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003473 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003474 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003475 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003476}
3477
3478void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
3479 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003480 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01003481 // Note: if heap poisoning is enabled, the entry point takes cares
3482 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003483 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3484 instruction,
3485 instruction->GetDexPc(),
3486 nullptr);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003487 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003488}
3489
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003490void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
3491 LocationSummary* locations =
3492 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3493 locations->SetOut(Location::RegisterLocation(EAX));
3494 InvokeRuntimeCallingConvention calling_convention;
3495 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003496 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003497 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003498}
3499
3500void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
3501 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003502 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
3503
Roland Levillain4d027112015-07-01 15:41:14 +01003504 // Note: if heap poisoning is enabled, the entry point takes cares
3505 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003506 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3507 instruction,
3508 instruction->GetDexPc(),
3509 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003510 DCHECK(!codegen_->IsLeafMethod());
3511}
3512
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003513void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003514 LocationSummary* locations =
3515 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003516 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3517 if (location.IsStackSlot()) {
3518 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3519 } else if (location.IsDoubleStackSlot()) {
3520 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003521 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003522 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003523}
3524
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003525void InstructionCodeGeneratorX86::VisitParameterValue(
3526 HParameterValue* instruction ATTRIBUTE_UNUSED) {
3527}
3528
3529void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
3530 LocationSummary* locations =
3531 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3532 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3533}
3534
3535void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003536}
3537
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003538void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003539 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003540 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003541 locations->SetInAt(0, Location::RequiresRegister());
3542 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003543}
3544
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003545void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
3546 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01003547 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003548 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01003549 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003550 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003551 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003552 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003553 break;
3554
3555 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003556 __ notl(out.AsRegisterPairLow<Register>());
3557 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003558 break;
3559
3560 default:
3561 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3562 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003563}
3564
David Brazdil66d126e2015-04-03 16:02:44 +01003565void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
3566 LocationSummary* locations =
3567 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3568 locations->SetInAt(0, Location::RequiresRegister());
3569 locations->SetOut(Location::SameAsFirstInput());
3570}
3571
3572void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003573 LocationSummary* locations = bool_not->GetLocations();
3574 Location in = locations->InAt(0);
3575 Location out = locations->Out();
3576 DCHECK(in.Equals(out));
3577 __ xorl(out.AsRegister<Register>(), Immediate(1));
3578}
3579
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003580void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003581 LocationSummary* locations =
3582 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003583 switch (compare->InputAt(0)->GetType()) {
3584 case Primitive::kPrimLong: {
3585 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00003586 locations->SetInAt(1, Location::Any());
3587 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3588 break;
3589 }
3590 case Primitive::kPrimFloat:
3591 case Primitive::kPrimDouble: {
3592 locations->SetInAt(0, Location::RequiresFpuRegister());
3593 locations->SetInAt(1, Location::RequiresFpuRegister());
3594 locations->SetOut(Location::RequiresRegister());
3595 break;
3596 }
3597 default:
3598 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3599 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003600}
3601
3602void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003603 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003604 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003605 Location left = locations->InAt(0);
3606 Location right = locations->InAt(1);
3607
Mark Mendell0c9497d2015-08-21 09:30:05 -04003608 NearLabel less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003609 switch (compare->InputAt(0)->GetType()) {
3610 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003611 Register left_low = left.AsRegisterPairLow<Register>();
3612 Register left_high = left.AsRegisterPairHigh<Register>();
3613 int32_t val_low = 0;
3614 int32_t val_high = 0;
3615 bool right_is_const = false;
3616
3617 if (right.IsConstant()) {
3618 DCHECK(right.GetConstant()->IsLongConstant());
3619 right_is_const = true;
3620 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
3621 val_low = Low32Bits(val);
3622 val_high = High32Bits(val);
3623 }
3624
Calin Juravleddb7df22014-11-25 20:56:51 +00003625 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003626 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003627 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003628 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003629 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003630 DCHECK(right_is_const) << right;
3631 if (val_high == 0) {
3632 __ testl(left_high, left_high);
3633 } else {
3634 __ cmpl(left_high, Immediate(val_high));
3635 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003636 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003637 __ j(kLess, &less); // Signed compare.
3638 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003639 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003640 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003641 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003642 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003643 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003644 DCHECK(right_is_const) << right;
3645 if (val_low == 0) {
3646 __ testl(left_low, left_low);
3647 } else {
3648 __ cmpl(left_low, Immediate(val_low));
3649 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003650 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003651 break;
3652 }
3653 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003654 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003655 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
3656 break;
3657 }
3658 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003659 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003660 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003661 break;
3662 }
3663 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003664 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003665 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003666 __ movl(out, Immediate(0));
3667 __ j(kEqual, &done);
3668 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
3669
3670 __ Bind(&greater);
3671 __ movl(out, Immediate(1));
3672 __ jmp(&done);
3673
3674 __ Bind(&less);
3675 __ movl(out, Immediate(-1));
3676
3677 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003678}
3679
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003680void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003681 LocationSummary* locations =
3682 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003683 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3684 locations->SetInAt(i, Location::Any());
3685 }
3686 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003687}
3688
3689void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003690 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003691 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003692}
3693
Calin Juravle52c48962014-12-16 17:02:57 +00003694void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
3695 /*
3696 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3697 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3698 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3699 */
3700 switch (kind) {
3701 case MemBarrierKind::kAnyAny: {
3702 __ mfence();
3703 break;
3704 }
3705 case MemBarrierKind::kAnyStore:
3706 case MemBarrierKind::kLoadAny:
3707 case MemBarrierKind::kStoreStore: {
3708 // nop
3709 break;
3710 }
3711 default:
3712 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003713 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003714}
3715
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003716
Vladimir Marko58155012015-08-19 12:49:41 +00003717void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
3718 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
3719 switch (invoke->GetMethodLoadKind()) {
3720 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
3721 // temp = thread->string_init_entrypoint
3722 __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(invoke->GetStringInitOffset()));
3723 break;
3724 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
3725 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3726 break;
3727 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
3728 __ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress()));
3729 break;
3730 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
3731 __ movl(temp.AsRegister<Register>(), Immediate(0)); // Placeholder.
3732 method_patches_.emplace_back(invoke->GetTargetMethod());
3733 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
3734 break;
3735 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
3736 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
3737 FALLTHROUGH_INTENDED;
3738 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
3739 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3740 Register method_reg;
3741 Register reg = temp.AsRegister<Register>();
3742 if (current_method.IsRegister()) {
3743 method_reg = current_method.AsRegister<Register>();
3744 } else {
3745 DCHECK(IsBaseline() || invoke->GetLocations()->Intrinsified());
3746 DCHECK(!current_method.IsValid());
3747 method_reg = reg;
3748 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
3749 }
3750 // temp = temp->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +01003751 __ movl(reg, Address(method_reg,
3752 ArtMethod::DexCacheResolvedMethodsOffset(kX86PointerSize).Int32Value()));
Vladimir Marko58155012015-08-19 12:49:41 +00003753 // temp = temp[index_in_cache]
3754 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
3755 __ movl(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
3756 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +01003757 }
Vladimir Marko58155012015-08-19 12:49:41 +00003758 }
3759
3760 switch (invoke->GetCodePtrLocation()) {
3761 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
3762 __ call(GetFrameEntryLabel());
3763 break;
3764 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
3765 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
3766 Label* label = &relative_call_patches_.back().label;
3767 __ call(label); // Bind to the patch label, override at link time.
3768 __ Bind(label); // Bind the label at the end of the "call" insn.
3769 break;
3770 }
3771 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
3772 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
3773 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
3774 // (Though the direct CALL ptr16:32 is available for consideration).
3775 FALLTHROUGH_INTENDED;
3776 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
3777 // (callee_method + offset_of_quick_compiled_code)()
3778 __ call(Address(callee_method.AsRegister<Register>(),
3779 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
3780 kX86WordSize).Int32Value()));
3781 break;
Mark Mendell09ed1a32015-03-25 08:30:06 -04003782 }
3783
3784 DCHECK(!IsLeafMethod());
Mark Mendell09ed1a32015-03-25 08:30:06 -04003785}
3786
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003787void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
3788 Register temp = temp_in.AsRegister<Register>();
3789 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
3790 invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
3791 LocationSummary* locations = invoke->GetLocations();
3792 Location receiver = locations->InAt(0);
3793 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3794 // temp = object->GetClass();
3795 DCHECK(receiver.IsRegister());
3796 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
3797 MaybeRecordImplicitNullCheck(invoke);
3798 __ MaybeUnpoisonHeapReference(temp);
3799 // temp = temp->GetMethodAt(method_offset);
3800 __ movl(temp, Address(temp, method_offset));
3801 // call temp->GetEntryPoint();
3802 __ call(Address(
3803 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3804}
3805
Vladimir Marko58155012015-08-19 12:49:41 +00003806void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
3807 DCHECK(linker_patches->empty());
3808 linker_patches->reserve(method_patches_.size() + relative_call_patches_.size());
3809 for (const MethodPatchInfo<Label>& info : method_patches_) {
3810 // The label points to the end of the "movl" insn but the literal offset for method
3811 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3812 uint32_t literal_offset = info.label.Position() - 4;
3813 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
3814 info.target_method.dex_file,
3815 info.target_method.dex_method_index));
3816 }
3817 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
3818 // The label points to the end of the "call" insn but the literal offset for method
3819 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3820 uint32_t literal_offset = info.label.Position() - 4;
3821 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
3822 info.target_method.dex_file,
3823 info.target_method.dex_method_index));
3824 }
3825}
3826
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003827void CodeGeneratorX86::MarkGCCard(Register temp,
3828 Register card,
3829 Register object,
3830 Register value,
3831 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003832 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003833 if (value_can_be_null) {
3834 __ testl(value, value);
3835 __ j(kEqual, &is_null);
3836 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003837 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3838 __ movl(temp, object);
3839 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003840 __ movb(Address(temp, card, TIMES_1, 0),
3841 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003842 if (value_can_be_null) {
3843 __ Bind(&is_null);
3844 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003845}
3846
Calin Juravle52c48962014-12-16 17:02:57 +00003847void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3848 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003849 LocationSummary* locations =
3850 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003851 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003852
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003853 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3854 locations->SetOut(Location::RequiresFpuRegister());
3855 } else {
3856 // The output overlaps in case of long: we don't want the low move to overwrite
3857 // the object's location.
3858 locations->SetOut(Location::RequiresRegister(),
3859 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3860 : Location::kNoOutputOverlap);
3861 }
Calin Juravle52c48962014-12-16 17:02:57 +00003862
3863 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3864 // Long values can be loaded atomically into an XMM using movsd.
3865 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3866 // and then copy the XMM into the output 32bits at a time).
3867 locations->AddTemp(Location::RequiresFpuRegister());
3868 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003869}
3870
Calin Juravle52c48962014-12-16 17:02:57 +00003871void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3872 const FieldInfo& field_info) {
3873 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003874
Calin Juravle52c48962014-12-16 17:02:57 +00003875 LocationSummary* locations = instruction->GetLocations();
3876 Register base = locations->InAt(0).AsRegister<Register>();
3877 Location out = locations->Out();
3878 bool is_volatile = field_info.IsVolatile();
3879 Primitive::Type field_type = field_info.GetFieldType();
3880 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3881
3882 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003883 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003884 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003885 break;
3886 }
3887
3888 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003889 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003890 break;
3891 }
3892
3893 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003894 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003895 break;
3896 }
3897
3898 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003899 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003900 break;
3901 }
3902
3903 case Primitive::kPrimInt:
3904 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003905 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003906 break;
3907 }
3908
3909 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00003910 if (is_volatile) {
3911 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3912 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003913 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003914 __ movd(out.AsRegisterPairLow<Register>(), temp);
3915 __ psrlq(temp, Immediate(32));
3916 __ movd(out.AsRegisterPairHigh<Register>(), temp);
3917 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003918 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003919 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003920 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003921 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
3922 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003923 break;
3924 }
3925
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003926 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003927 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003928 break;
3929 }
3930
3931 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003932 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003933 break;
3934 }
3935
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003936 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003937 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003938 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003939 }
Calin Juravle52c48962014-12-16 17:02:57 +00003940
Calin Juravle77520bc2015-01-12 18:45:46 +00003941 // Longs are handled in the switch.
3942 if (field_type != Primitive::kPrimLong) {
3943 codegen_->MaybeRecordImplicitNullCheck(instruction);
3944 }
3945
Calin Juravle52c48962014-12-16 17:02:57 +00003946 if (is_volatile) {
3947 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3948 }
Roland Levillain4d027112015-07-01 15:41:14 +01003949
3950 if (field_type == Primitive::kPrimNot) {
3951 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3952 }
Calin Juravle52c48962014-12-16 17:02:57 +00003953}
3954
3955void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3956 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3957
3958 LocationSummary* locations =
3959 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3960 locations->SetInAt(0, Location::RequiresRegister());
3961 bool is_volatile = field_info.IsVolatile();
3962 Primitive::Type field_type = field_info.GetFieldType();
3963 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
3964 || (field_type == Primitive::kPrimByte);
3965
3966 // The register allocator does not support multiple
3967 // inputs that die at entry with one in a specific register.
3968 if (is_byte_type) {
3969 // Ensure the value is in a byte register.
3970 locations->SetInAt(1, Location::RegisterLocation(EAX));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003971 } else if (Primitive::IsFloatingPointType(field_type)) {
3972 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003973 } else {
3974 locations->SetInAt(1, Location::RequiresRegister());
3975 }
Calin Juravle52c48962014-12-16 17:02:57 +00003976 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Roland Levillain4d027112015-07-01 15:41:14 +01003977 // Temporary registers for the write barrier.
3978 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Calin Juravle52c48962014-12-16 17:02:57 +00003979 // Ensure the card is in a byte register.
3980 locations->AddTemp(Location::RegisterLocation(ECX));
3981 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
3982 // 64bits value can be atomically written to an address with movsd and an XMM register.
3983 // We need two XMM registers because there's no easier way to (bit) copy a register pair
3984 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
3985 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
3986 // isolated cases when we need this it isn't worth adding the extra complexity.
3987 locations->AddTemp(Location::RequiresFpuRegister());
3988 locations->AddTemp(Location::RequiresFpuRegister());
3989 }
3990}
3991
3992void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003993 const FieldInfo& field_info,
3994 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003995 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3996
3997 LocationSummary* locations = instruction->GetLocations();
3998 Register base = locations->InAt(0).AsRegister<Register>();
3999 Location value = locations->InAt(1);
4000 bool is_volatile = field_info.IsVolatile();
4001 Primitive::Type field_type = field_info.GetFieldType();
4002 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01004003 bool needs_write_barrier =
4004 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004005
4006 if (is_volatile) {
4007 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4008 }
4009
4010 switch (field_type) {
4011 case Primitive::kPrimBoolean:
4012 case Primitive::kPrimByte: {
4013 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
4014 break;
4015 }
4016
4017 case Primitive::kPrimShort:
4018 case Primitive::kPrimChar: {
4019 __ movw(Address(base, offset), value.AsRegister<Register>());
4020 break;
4021 }
4022
4023 case Primitive::kPrimInt:
4024 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01004025 if (kPoisonHeapReferences && needs_write_barrier) {
4026 // Note that in the case where `value` is a null reference,
4027 // we do not enter this block, as the reference does not
4028 // need poisoning.
4029 DCHECK_EQ(field_type, Primitive::kPrimNot);
4030 Register temp = locations->GetTemp(0).AsRegister<Register>();
4031 __ movl(temp, value.AsRegister<Register>());
4032 __ PoisonHeapReference(temp);
4033 __ movl(Address(base, offset), temp);
4034 } else {
4035 __ movl(Address(base, offset), value.AsRegister<Register>());
4036 }
Calin Juravle52c48962014-12-16 17:02:57 +00004037 break;
4038 }
4039
4040 case Primitive::kPrimLong: {
4041 if (is_volatile) {
4042 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4043 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
4044 __ movd(temp1, value.AsRegisterPairLow<Register>());
4045 __ movd(temp2, value.AsRegisterPairHigh<Register>());
4046 __ punpckldq(temp1, temp2);
4047 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00004048 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004049 } else {
4050 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004051 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004052 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
4053 }
4054 break;
4055 }
4056
4057 case Primitive::kPrimFloat: {
4058 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4059 break;
4060 }
4061
4062 case Primitive::kPrimDouble: {
4063 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4064 break;
4065 }
4066
4067 case Primitive::kPrimVoid:
4068 LOG(FATAL) << "Unreachable type " << field_type;
4069 UNREACHABLE();
4070 }
4071
Calin Juravle77520bc2015-01-12 18:45:46 +00004072 // Longs are handled in the switch.
4073 if (field_type != Primitive::kPrimLong) {
4074 codegen_->MaybeRecordImplicitNullCheck(instruction);
4075 }
4076
Roland Levillain4d027112015-07-01 15:41:14 +01004077 if (needs_write_barrier) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004078 Register temp = locations->GetTemp(0).AsRegister<Register>();
4079 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004080 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004081 }
4082
Calin Juravle52c48962014-12-16 17:02:57 +00004083 if (is_volatile) {
4084 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4085 }
4086}
4087
4088void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4089 HandleFieldGet(instruction, instruction->GetFieldInfo());
4090}
4091
4092void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4093 HandleFieldGet(instruction, instruction->GetFieldInfo());
4094}
4095
4096void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4097 HandleFieldSet(instruction, instruction->GetFieldInfo());
4098}
4099
4100void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004101 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004102}
4103
4104void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4105 HandleFieldSet(instruction, instruction->GetFieldInfo());
4106}
4107
4108void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004109 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004110}
4111
4112void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4113 HandleFieldGet(instruction, instruction->GetFieldInfo());
4114}
4115
4116void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4117 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004118}
4119
Calin Juravlee460d1d2015-09-29 04:52:17 +01004120void LocationsBuilderX86::VisitUnresolvedInstanceFieldGet(
4121 HUnresolvedInstanceFieldGet* instruction) {
4122 FieldAccessCallingConventionX86 calling_convention;
4123 codegen_->CreateUnresolvedFieldLocationSummary(
4124 instruction, instruction->GetFieldType(), calling_convention);
4125}
4126
4127void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldGet(
4128 HUnresolvedInstanceFieldGet* instruction) {
4129 FieldAccessCallingConventionX86 calling_convention;
4130 codegen_->GenerateUnresolvedFieldAccess(instruction,
4131 instruction->GetFieldType(),
4132 instruction->GetFieldIndex(),
4133 instruction->GetDexPc(),
4134 calling_convention);
4135}
4136
4137void LocationsBuilderX86::VisitUnresolvedInstanceFieldSet(
4138 HUnresolvedInstanceFieldSet* instruction) {
4139 FieldAccessCallingConventionX86 calling_convention;
4140 codegen_->CreateUnresolvedFieldLocationSummary(
4141 instruction, instruction->GetFieldType(), calling_convention);
4142}
4143
4144void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldSet(
4145 HUnresolvedInstanceFieldSet* instruction) {
4146 FieldAccessCallingConventionX86 calling_convention;
4147 codegen_->GenerateUnresolvedFieldAccess(instruction,
4148 instruction->GetFieldType(),
4149 instruction->GetFieldIndex(),
4150 instruction->GetDexPc(),
4151 calling_convention);
4152}
4153
4154void LocationsBuilderX86::VisitUnresolvedStaticFieldGet(
4155 HUnresolvedStaticFieldGet* instruction) {
4156 FieldAccessCallingConventionX86 calling_convention;
4157 codegen_->CreateUnresolvedFieldLocationSummary(
4158 instruction, instruction->GetFieldType(), calling_convention);
4159}
4160
4161void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldGet(
4162 HUnresolvedStaticFieldGet* instruction) {
4163 FieldAccessCallingConventionX86 calling_convention;
4164 codegen_->GenerateUnresolvedFieldAccess(instruction,
4165 instruction->GetFieldType(),
4166 instruction->GetFieldIndex(),
4167 instruction->GetDexPc(),
4168 calling_convention);
4169}
4170
4171void LocationsBuilderX86::VisitUnresolvedStaticFieldSet(
4172 HUnresolvedStaticFieldSet* instruction) {
4173 FieldAccessCallingConventionX86 calling_convention;
4174 codegen_->CreateUnresolvedFieldLocationSummary(
4175 instruction, instruction->GetFieldType(), calling_convention);
4176}
4177
4178void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldSet(
4179 HUnresolvedStaticFieldSet* instruction) {
4180 FieldAccessCallingConventionX86 calling_convention;
4181 codegen_->GenerateUnresolvedFieldAccess(instruction,
4182 instruction->GetFieldType(),
4183 instruction->GetFieldIndex(),
4184 instruction->GetDexPc(),
4185 calling_convention);
4186}
4187
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004188void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004189 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4190 ? LocationSummary::kCallOnSlowPath
4191 : LocationSummary::kNoCall;
4192 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4193 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004194 ? Location::RequiresRegister()
4195 : Location::Any();
4196 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004197 if (instruction->HasUses()) {
4198 locations->SetOut(Location::SameAsFirstInput());
4199 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004200}
4201
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004202void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004203 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4204 return;
4205 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004206 LocationSummary* locations = instruction->GetLocations();
4207 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004208
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004209 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
4210 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4211}
4212
4213void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004214 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004215 codegen_->AddSlowPath(slow_path);
4216
4217 LocationSummary* locations = instruction->GetLocations();
4218 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004219
4220 if (obj.IsRegister()) {
Mark Mendell42514f62015-03-31 11:34:22 -04004221 __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004222 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004223 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004224 } else {
4225 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004226 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004227 __ jmp(slow_path->GetEntryLabel());
4228 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004229 }
4230 __ j(kEqual, slow_path->GetEntryLabel());
4231}
4232
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004233void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004234 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004235 GenerateImplicitNullCheck(instruction);
4236 } else {
4237 GenerateExplicitNullCheck(instruction);
4238 }
4239}
4240
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004241void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004242 LocationSummary* locations =
4243 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004244 locations->SetInAt(0, Location::RequiresRegister());
4245 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004246 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4247 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4248 } else {
4249 // The output overlaps in case of long: we don't want the low move to overwrite
4250 // the array's location.
4251 locations->SetOut(Location::RequiresRegister(),
4252 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
4253 : Location::kNoOutputOverlap);
4254 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004255}
4256
4257void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
4258 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004259 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004260 Location index = locations->InAt(1);
4261
Calin Juravle77520bc2015-01-12 18:45:46 +00004262 Primitive::Type type = instruction->GetType();
4263 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004264 case Primitive::kPrimBoolean: {
4265 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004266 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004267 if (index.IsConstant()) {
4268 __ movzxb(out, Address(obj,
4269 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4270 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004271 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004272 }
4273 break;
4274 }
4275
4276 case Primitive::kPrimByte: {
4277 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004278 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004279 if (index.IsConstant()) {
4280 __ movsxb(out, Address(obj,
4281 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4282 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004283 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004284 }
4285 break;
4286 }
4287
4288 case Primitive::kPrimShort: {
4289 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004290 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004291 if (index.IsConstant()) {
4292 __ movsxw(out, Address(obj,
4293 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4294 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004295 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004296 }
4297 break;
4298 }
4299
4300 case Primitive::kPrimChar: {
4301 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004302 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004303 if (index.IsConstant()) {
4304 __ movzxw(out, Address(obj,
4305 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4306 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004307 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004308 }
4309 break;
4310 }
4311
4312 case Primitive::kPrimInt:
4313 case Primitive::kPrimNot: {
4314 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004315 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004316 if (index.IsConstant()) {
4317 __ movl(out, Address(obj,
4318 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4319 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004320 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004321 }
4322 break;
4323 }
4324
4325 case Primitive::kPrimLong: {
4326 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004327 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004328 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004329 if (index.IsConstant()) {
4330 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004331 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004332 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004333 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004334 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004335 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004336 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004337 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004338 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004339 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004340 }
4341 break;
4342 }
4343
Mark Mendell7c8d0092015-01-26 11:21:33 -05004344 case Primitive::kPrimFloat: {
4345 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4346 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4347 if (index.IsConstant()) {
4348 __ movss(out, Address(obj,
4349 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4350 } else {
4351 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
4352 }
4353 break;
4354 }
4355
4356 case Primitive::kPrimDouble: {
4357 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4358 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4359 if (index.IsConstant()) {
4360 __ movsd(out, Address(obj,
4361 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4362 } else {
4363 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
4364 }
4365 break;
4366 }
4367
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004368 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00004369 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004370 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004371 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004372
4373 if (type != Primitive::kPrimLong) {
4374 codegen_->MaybeRecordImplicitNullCheck(instruction);
4375 }
Roland Levillain4d027112015-07-01 15:41:14 +01004376
4377 if (type == Primitive::kPrimNot) {
4378 Register out = locations->Out().AsRegister<Register>();
4379 __ MaybeUnpoisonHeapReference(out);
4380 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004381}
4382
4383void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05004384 // This location builder might end up asking to up to four registers, which is
4385 // not currently possible for baseline. The situation in which we need four
4386 // registers cannot be met by baseline though, because it has not run any
4387 // optimization.
4388
Nicolas Geoffray39468442014-09-02 15:17:15 +01004389 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004390 bool needs_write_barrier =
4391 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4392
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004393 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004394
Nicolas Geoffray39468442014-09-02 15:17:15 +01004395 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4396 instruction,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004397 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004398
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004399 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
4400 || (value_type == Primitive::kPrimByte);
4401 // We need the inputs to be different than the output in case of long operation.
4402 // In case of a byte operation, the register allocator does not support multiple
4403 // inputs that die at entry with one in a specific register.
4404 locations->SetInAt(0, Location::RequiresRegister());
4405 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4406 if (is_byte_type) {
4407 // Ensure the value is in a byte register.
4408 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
4409 } else if (Primitive::IsFloatingPointType(value_type)) {
4410 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004411 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004412 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4413 }
4414 if (needs_write_barrier) {
4415 // Temporary registers for the write barrier.
4416 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
4417 // Ensure the card is in a byte register.
4418 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004419 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004420}
4421
4422void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
4423 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004424 Register array = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004425 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004426 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004427 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004428 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4429 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4430 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4431 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004432 bool needs_write_barrier =
4433 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004434
4435 switch (value_type) {
4436 case Primitive::kPrimBoolean:
4437 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004438 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4439 Address address = index.IsConstant()
4440 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset)
4441 : Address(array, index.AsRegister<Register>(), TIMES_1, offset);
4442 if (value.IsRegister()) {
4443 __ movb(address, value.AsRegister<ByteRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004444 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004445 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004446 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004447 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004448 break;
4449 }
4450
4451 case Primitive::kPrimShort:
4452 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004453 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4454 Address address = index.IsConstant()
4455 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset)
4456 : Address(array, index.AsRegister<Register>(), TIMES_2, offset);
4457 if (value.IsRegister()) {
4458 __ movw(address, value.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004459 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004460 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004461 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004462 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004463 break;
4464 }
4465
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004466 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004467 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4468 Address address = index.IsConstant()
4469 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4470 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
4471 if (!value.IsRegister()) {
4472 // Just setting null.
4473 DCHECK(instruction->InputAt(2)->IsNullConstant());
4474 DCHECK(value.IsConstant()) << value;
4475 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004476 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004477 DCHECK(!needs_write_barrier);
4478 DCHECK(!may_need_runtime_call);
4479 break;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004480 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004481
4482 DCHECK(needs_write_barrier);
4483 Register register_value = value.AsRegister<Register>();
4484 NearLabel done, not_null, do_put;
4485 SlowPathCode* slow_path = nullptr;
4486 Register temp = locations->GetTemp(0).AsRegister<Register>();
4487 if (may_need_runtime_call) {
4488 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86(instruction);
4489 codegen_->AddSlowPath(slow_path);
4490 if (instruction->GetValueCanBeNull()) {
4491 __ testl(register_value, register_value);
4492 __ j(kNotEqual, &not_null);
4493 __ movl(address, Immediate(0));
4494 codegen_->MaybeRecordImplicitNullCheck(instruction);
4495 __ jmp(&done);
4496 __ Bind(&not_null);
4497 }
4498
4499 __ movl(temp, Address(array, class_offset));
4500 codegen_->MaybeRecordImplicitNullCheck(instruction);
4501 __ MaybeUnpoisonHeapReference(temp);
4502 __ movl(temp, Address(temp, component_offset));
4503 // No need to poison/unpoison, we're comparing two poisoned references.
4504 __ cmpl(temp, Address(register_value, class_offset));
4505 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4506 __ j(kEqual, &do_put);
4507 __ MaybeUnpoisonHeapReference(temp);
4508 __ movl(temp, Address(temp, super_offset));
4509 // No need to unpoison, we're comparing against null..
4510 __ testl(temp, temp);
4511 __ j(kNotEqual, slow_path->GetEntryLabel());
4512 __ Bind(&do_put);
4513 } else {
4514 __ j(kNotEqual, slow_path->GetEntryLabel());
4515 }
4516 }
4517
4518 if (kPoisonHeapReferences) {
4519 __ movl(temp, register_value);
4520 __ PoisonHeapReference(temp);
4521 __ movl(address, temp);
4522 } else {
4523 __ movl(address, register_value);
4524 }
4525 if (!may_need_runtime_call) {
4526 codegen_->MaybeRecordImplicitNullCheck(instruction);
4527 }
4528
4529 Register card = locations->GetTemp(1).AsRegister<Register>();
4530 codegen_->MarkGCCard(
4531 temp, card, array, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
4532 __ Bind(&done);
4533
4534 if (slow_path != nullptr) {
4535 __ Bind(slow_path->GetExitLabel());
4536 }
4537
4538 break;
4539 }
4540 case Primitive::kPrimInt: {
4541 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4542 Address address = index.IsConstant()
4543 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4544 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
4545 if (value.IsRegister()) {
4546 __ movl(address, value.AsRegister<Register>());
4547 } else {
4548 DCHECK(value.IsConstant()) << value;
4549 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4550 __ movl(address, Immediate(v));
4551 }
4552 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004553 break;
4554 }
4555
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004556 case Primitive::kPrimLong: {
4557 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004558 if (index.IsConstant()) {
4559 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004560 if (value.IsRegisterPair()) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004561 __ movl(Address(array, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004562 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004563 __ movl(Address(array, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004564 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004565 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004566 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004567 __ movl(Address(array, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004568 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004569 __ movl(Address(array, offset + kX86WordSize), Immediate(High32Bits(val)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004570 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004571 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004572 if (value.IsRegisterPair()) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004573 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004574 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004575 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004576 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004577 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004578 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004579 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004580 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004581 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004582 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004583 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004584 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004585 Immediate(High32Bits(val)));
4586 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004587 }
4588 break;
4589 }
4590
Mark Mendell7c8d0092015-01-26 11:21:33 -05004591 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004592 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4593 Address address = index.IsConstant()
4594 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4595 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004596 DCHECK(value.IsFpuRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004597 __ movss(address, value.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004598 break;
4599 }
4600
4601 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004602 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4603 Address address = index.IsConstant()
4604 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4605 : Address(array, index.AsRegister<Register>(), TIMES_8, offset);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004606 DCHECK(value.IsFpuRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004607 __ movsd(address, value.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004608 break;
4609 }
4610
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004611 case Primitive::kPrimVoid:
4612 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004613 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004614 }
4615}
4616
4617void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
4618 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004619 locations->SetInAt(0, Location::RequiresRegister());
4620 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004621}
4622
4623void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
4624 LocationSummary* locations = instruction->GetLocations();
4625 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004626 Register obj = locations->InAt(0).AsRegister<Register>();
4627 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004628 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004629 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004630}
4631
4632void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004633 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4634 ? LocationSummary::kCallOnSlowPath
4635 : LocationSummary::kNoCall;
4636 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004637 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004638 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004639 if (instruction->HasUses()) {
4640 locations->SetOut(Location::SameAsFirstInput());
4641 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004642}
4643
4644void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
4645 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004646 Location index_loc = locations->InAt(0);
4647 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004648 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004649 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004650
Mark Mendell99dbd682015-04-22 16:18:52 -04004651 if (length_loc.IsConstant()) {
4652 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4653 if (index_loc.IsConstant()) {
4654 // BCE will remove the bounds check if we are guarenteed to pass.
4655 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4656 if (index < 0 || index >= length) {
4657 codegen_->AddSlowPath(slow_path);
4658 __ jmp(slow_path->GetEntryLabel());
4659 } else {
4660 // Some optimization after BCE may have generated this, and we should not
4661 // generate a bounds check if it is a valid range.
4662 }
4663 return;
4664 }
4665
4666 // We have to reverse the jump condition because the length is the constant.
4667 Register index_reg = index_loc.AsRegister<Register>();
4668 __ cmpl(index_reg, Immediate(length));
4669 codegen_->AddSlowPath(slow_path);
4670 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004671 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004672 Register length = length_loc.AsRegister<Register>();
4673 if (index_loc.IsConstant()) {
4674 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4675 __ cmpl(length, Immediate(value));
4676 } else {
4677 __ cmpl(length, index_loc.AsRegister<Register>());
4678 }
4679 codegen_->AddSlowPath(slow_path);
4680 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004681 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004682}
4683
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004684void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
4685 temp->SetLocations(nullptr);
4686}
4687
4688void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
4689 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004690 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004691}
4692
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004693void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004694 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004695 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004696}
4697
4698void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004699 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4700}
4701
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004702void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
4703 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4704}
4705
4706void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004707 HBasicBlock* block = instruction->GetBlock();
4708 if (block->GetLoopInformation() != nullptr) {
4709 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4710 // The back edge will generate the suspend check.
4711 return;
4712 }
4713 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4714 // The goto will generate the suspend check.
4715 return;
4716 }
4717 GenerateSuspendCheck(instruction, nullptr);
4718}
4719
4720void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
4721 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004722 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004723 down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
4724 if (slow_path == nullptr) {
4725 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
4726 instruction->SetSlowPath(slow_path);
4727 codegen_->AddSlowPath(slow_path);
4728 if (successor != nullptr) {
4729 DCHECK(successor->IsLoopHeader());
4730 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4731 }
4732 } else {
4733 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4734 }
4735
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004736 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004737 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004738 if (successor == nullptr) {
4739 __ j(kNotEqual, slow_path->GetEntryLabel());
4740 __ Bind(slow_path->GetReturnLabel());
4741 } else {
4742 __ j(kEqual, codegen_->GetLabelOf(successor));
4743 __ jmp(slow_path->GetEntryLabel());
4744 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004745}
4746
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004747X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
4748 return codegen_->GetAssembler();
4749}
4750
Mark Mendell7c8d0092015-01-26 11:21:33 -05004751void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004752 ScratchRegisterScope ensure_scratch(
4753 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4754 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4755 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4756 __ movl(temp_reg, Address(ESP, src + stack_offset));
4757 __ movl(Address(ESP, dst + stack_offset), temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004758}
4759
4760void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004761 ScratchRegisterScope ensure_scratch(
4762 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4763 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4764 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4765 __ movl(temp_reg, Address(ESP, src + stack_offset));
4766 __ movl(Address(ESP, dst + stack_offset), temp_reg);
4767 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
4768 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004769}
4770
4771void ParallelMoveResolverX86::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004772 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 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004925 Location source = move->GetSource();
4926 Location destination = move->GetDestination();
4927
4928 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell90979812015-07-28 16:41:21 -04004929 // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary.
4930 DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>());
4931 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
4932 __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>());
4933 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004934 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004935 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004936 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004937 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004938 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4939 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004940 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
4941 // Use XOR Swap algorithm to avoid a temporary.
4942 DCHECK_NE(source.reg(), destination.reg());
4943 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4944 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4945 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4946 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
4947 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
4948 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
4949 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004950 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
4951 // Take advantage of the 16 bytes in the XMM register.
4952 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
4953 Address stack(ESP, destination.GetStackIndex());
4954 // Load the double into the high doubleword.
4955 __ movhpd(reg, stack);
4956
4957 // Store the low double into the destination.
4958 __ movsd(stack, reg);
4959
4960 // Move the high double to the low double.
4961 __ psrldq(reg, Immediate(8));
4962 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
4963 // Take advantage of the 16 bytes in the XMM register.
4964 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
4965 Address stack(ESP, source.GetStackIndex());
4966 // Load the double into the high doubleword.
4967 __ movhpd(reg, stack);
4968
4969 // Store the low double into the destination.
4970 __ movsd(stack, reg);
4971
4972 // Move the high double to the low double.
4973 __ psrldq(reg, Immediate(8));
4974 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
4975 Exchange(destination.GetStackIndex(), source.GetStackIndex());
4976 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004977 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004978 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004979 }
4980}
4981
4982void ParallelMoveResolverX86::SpillScratch(int reg) {
4983 __ pushl(static_cast<Register>(reg));
4984}
4985
4986void ParallelMoveResolverX86::RestoreScratch(int reg) {
4987 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004988}
4989
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004990void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01004991 InvokeRuntimeCallingConvention calling_convention;
4992 CodeGenerator::CreateLoadClassLocationSummary(
4993 cls,
4994 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
4995 Location::RegisterLocation(EAX));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004996}
4997
4998void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004999 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005000 if (cls->NeedsAccessCheck()) {
5001 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5002 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5003 cls,
5004 cls->GetDexPc(),
5005 nullptr);
Calin Juravle580b6092015-10-06 17:35:58 +01005006 return;
5007 }
5008
5009 Register out = locations->Out().AsRegister<Register>();
5010 Register current_method = locations->InAt(0).AsRegister<Register>();
5011 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005012 DCHECK(!cls->CanCallRuntime());
5013 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07005014 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005015 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005016 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005017 __ movl(out, Address(
Vladimir Marko05792b92015-08-03 11:56:49 +01005018 current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86PointerSize).Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005019 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01005020 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005021
Andreas Gampe85b62f22015-09-09 13:15:38 -07005022 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005023 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5024 codegen_->AddSlowPath(slow_path);
5025 __ testl(out, out);
5026 __ j(kEqual, slow_path->GetEntryLabel());
5027 if (cls->MustGenerateClinitCheck()) {
5028 GenerateClassInitializationCheck(slow_path, out);
5029 } else {
5030 __ Bind(slow_path->GetExitLabel());
5031 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005032 }
5033}
5034
5035void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
5036 LocationSummary* locations =
5037 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5038 locations->SetInAt(0, Location::RequiresRegister());
5039 if (check->HasUses()) {
5040 locations->SetOut(Location::SameAsFirstInput());
5041 }
5042}
5043
5044void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005045 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005046 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005047 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005048 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005049 GenerateClassInitializationCheck(slow_path,
5050 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005051}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005052
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005053void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005054 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005055 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
5056 Immediate(mirror::Class::kStatusInitialized));
5057 __ j(kLess, slow_path->GetEntryLabel());
5058 __ Bind(slow_path->GetExitLabel());
5059 // No need for memory fence, thanks to the X86 memory model.
5060}
5061
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005062void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
5063 LocationSummary* locations =
5064 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005065 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005066 locations->SetOut(Location::RequiresRegister());
5067}
5068
5069void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07005070 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005071 codegen_->AddSlowPath(slow_path);
5072
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005073 LocationSummary* locations = load->GetLocations();
5074 Register out = locations->Out().AsRegister<Register>();
5075 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07005076 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08005077 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005078 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01005079 // TODO: We will need a read barrier here.
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005080 __ testl(out, out);
5081 __ j(kEqual, slow_path->GetEntryLabel());
5082 __ Bind(slow_path->GetExitLabel());
5083}
5084
David Brazdilcb1c0552015-08-04 16:22:25 +01005085static Address GetExceptionTlsAddress() {
5086 return Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
5087}
5088
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005089void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
5090 LocationSummary* locations =
5091 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5092 locations->SetOut(Location::RequiresRegister());
5093}
5094
5095void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01005096 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress());
5097}
5098
5099void LocationsBuilderX86::VisitClearException(HClearException* clear) {
5100 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5101}
5102
5103void InstructionCodeGeneratorX86::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5104 __ fs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005105}
5106
5107void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
5108 LocationSummary* locations =
5109 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5110 InvokeRuntimeCallingConvention calling_convention;
5111 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5112}
5113
5114void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005115 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
5116 instruction,
5117 instruction->GetDexPc(),
5118 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005119}
5120
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005121void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005122 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5123 switch (instruction->GetTypeCheckKind()) {
5124 case TypeCheckKind::kExactCheck:
5125 case TypeCheckKind::kAbstractClassCheck:
5126 case TypeCheckKind::kClassHierarchyCheck:
5127 case TypeCheckKind::kArrayObjectCheck:
5128 call_kind = LocationSummary::kNoCall;
5129 break;
Calin Juravle98893e12015-10-02 21:05:03 +01005130 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005131 case TypeCheckKind::kInterfaceCheck:
5132 call_kind = LocationSummary::kCall;
5133 break;
5134 case TypeCheckKind::kArrayCheck:
5135 call_kind = LocationSummary::kCallOnSlowPath;
5136 break;
5137 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005138 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005139 if (call_kind != LocationSummary::kCall) {
5140 locations->SetInAt(0, Location::RequiresRegister());
5141 locations->SetInAt(1, Location::Any());
5142 // Note that TypeCheckSlowPathX86 uses this register too.
5143 locations->SetOut(Location::RequiresRegister());
5144 } else {
5145 InvokeRuntimeCallingConvention calling_convention;
5146 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5147 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5148 locations->SetOut(Location::RegisterLocation(EAX));
5149 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005150}
5151
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005152void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005153 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005154 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005155 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005156 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005157 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005158 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5159 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5160 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005161 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005162 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005163
5164 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005165 // Avoid null check if we know obj is not null.
5166 if (instruction->MustDoNullCheck()) {
5167 __ testl(obj, obj);
5168 __ j(kEqual, &zero);
5169 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005170
Calin Juravle98893e12015-10-02 21:05:03 +01005171 // In case of an interface/unresolved check, we put the object class into the object register.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005172 // This is safe, as the register is caller-save, and the object must be in another
5173 // register if it survives the runtime call.
Calin Juravle98893e12015-10-02 21:05:03 +01005174 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
5175 (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005176 ? obj
5177 : out;
5178 __ movl(target, Address(obj, class_offset));
5179 __ MaybeUnpoisonHeapReference(target);
5180
5181 switch (instruction->GetTypeCheckKind()) {
5182 case TypeCheckKind::kExactCheck: {
5183 if (cls.IsRegister()) {
5184 __ cmpl(out, cls.AsRegister<Register>());
5185 } else {
5186 DCHECK(cls.IsStackSlot()) << cls;
5187 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5188 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005189
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005190 // Classes must be equal for the instanceof to succeed.
5191 __ j(kNotEqual, &zero);
5192 __ movl(out, Immediate(1));
5193 __ jmp(&done);
5194 break;
5195 }
5196 case TypeCheckKind::kAbstractClassCheck: {
5197 // If the class is abstract, we eagerly fetch the super class of the
5198 // object to avoid doing a comparison we know will fail.
5199 NearLabel loop;
5200 __ Bind(&loop);
5201 __ movl(out, Address(out, super_offset));
5202 __ MaybeUnpoisonHeapReference(out);
5203 __ testl(out, out);
5204 // If `out` is null, we use it for the result, and jump to `done`.
5205 __ j(kEqual, &done);
5206 if (cls.IsRegister()) {
5207 __ cmpl(out, cls.AsRegister<Register>());
5208 } else {
5209 DCHECK(cls.IsStackSlot()) << cls;
5210 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5211 }
5212 __ j(kNotEqual, &loop);
5213 __ movl(out, Immediate(1));
5214 if (zero.IsLinked()) {
5215 __ jmp(&done);
5216 }
5217 break;
5218 }
5219 case TypeCheckKind::kClassHierarchyCheck: {
5220 // Walk over the class hierarchy to find a match.
5221 NearLabel loop, success;
5222 __ Bind(&loop);
5223 if (cls.IsRegister()) {
5224 __ cmpl(out, cls.AsRegister<Register>());
5225 } else {
5226 DCHECK(cls.IsStackSlot()) << cls;
5227 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5228 }
5229 __ j(kEqual, &success);
5230 __ movl(out, Address(out, super_offset));
5231 __ MaybeUnpoisonHeapReference(out);
5232 __ testl(out, out);
5233 __ j(kNotEqual, &loop);
5234 // If `out` is null, we use it for the result, and jump to `done`.
5235 __ jmp(&done);
5236 __ Bind(&success);
5237 __ movl(out, Immediate(1));
5238 if (zero.IsLinked()) {
5239 __ jmp(&done);
5240 }
5241 break;
5242 }
5243 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005244 // Do an exact check.
5245 NearLabel exact_check;
5246 if (cls.IsRegister()) {
5247 __ cmpl(out, cls.AsRegister<Register>());
5248 } else {
5249 DCHECK(cls.IsStackSlot()) << cls;
5250 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5251 }
5252 __ j(kEqual, &exact_check);
5253 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005254 __ movl(out, Address(out, component_offset));
5255 __ MaybeUnpoisonHeapReference(out);
5256 __ testl(out, out);
5257 // If `out` is null, we use it for the result, and jump to `done`.
5258 __ j(kEqual, &done);
5259 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5260 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005261 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005262 __ movl(out, Immediate(1));
5263 __ jmp(&done);
5264 break;
5265 }
5266 case TypeCheckKind::kArrayCheck: {
5267 if (cls.IsRegister()) {
5268 __ cmpl(out, cls.AsRegister<Register>());
5269 } else {
5270 DCHECK(cls.IsStackSlot()) << cls;
5271 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5272 }
5273 DCHECK(locations->OnlyCallsOnSlowPath());
5274 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5275 instruction, /* is_fatal */ false);
5276 codegen_->AddSlowPath(slow_path);
5277 __ j(kNotEqual, slow_path->GetEntryLabel());
5278 __ movl(out, Immediate(1));
5279 if (zero.IsLinked()) {
5280 __ jmp(&done);
5281 }
5282 break;
5283 }
Calin Juravle98893e12015-10-02 21:05:03 +01005284 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005285 case TypeCheckKind::kInterfaceCheck:
5286 default: {
5287 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
5288 instruction,
5289 instruction->GetDexPc(),
5290 nullptr);
5291 if (zero.IsLinked()) {
5292 __ jmp(&done);
5293 }
5294 break;
5295 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005296 }
5297
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005298 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005299 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005300 __ xorl(out, out);
5301 }
5302
5303 if (done.IsLinked()) {
5304 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005305 }
5306
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005307 if (slow_path != nullptr) {
5308 __ Bind(slow_path->GetExitLabel());
5309 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005310}
5311
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005312void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005313 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5314 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5315
5316 switch (instruction->GetTypeCheckKind()) {
5317 case TypeCheckKind::kExactCheck:
5318 case TypeCheckKind::kAbstractClassCheck:
5319 case TypeCheckKind::kClassHierarchyCheck:
5320 case TypeCheckKind::kArrayObjectCheck:
5321 call_kind = throws_into_catch
5322 ? LocationSummary::kCallOnSlowPath
5323 : LocationSummary::kNoCall;
5324 break;
5325 case TypeCheckKind::kInterfaceCheck:
Calin Juravle98893e12015-10-02 21:05:03 +01005326 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005327 call_kind = LocationSummary::kCall;
5328 break;
5329 case TypeCheckKind::kArrayCheck:
5330 call_kind = LocationSummary::kCallOnSlowPath;
5331 break;
5332 }
5333
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005334 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005335 instruction, call_kind);
5336 if (call_kind != LocationSummary::kCall) {
5337 locations->SetInAt(0, Location::RequiresRegister());
5338 locations->SetInAt(1, Location::Any());
5339 // Note that TypeCheckSlowPathX86 uses this register too.
5340 locations->AddTemp(Location::RequiresRegister());
5341 } else {
5342 InvokeRuntimeCallingConvention calling_convention;
5343 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5344 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5345 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005346}
5347
5348void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
5349 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005350 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005351 Location cls = locations->InAt(1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005352 Register temp = locations->WillCall()
5353 ? kNoRegister
5354 : locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray64acf302015-09-14 22:20:29 +01005355
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005356 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5357 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5358 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5359 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5360 SlowPathCode* slow_path = nullptr;
5361
5362 if (!locations->WillCall()) {
5363 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5364 instruction, !locations->CanCall());
5365 codegen_->AddSlowPath(slow_path);
5366 }
5367
5368 NearLabel done, abstract_entry;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005369 // Avoid null check if we know obj is not null.
5370 if (instruction->MustDoNullCheck()) {
5371 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005372 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005373 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005374
5375 if (locations->WillCall()) {
5376 __ movl(obj, Address(obj, class_offset));
5377 __ MaybeUnpoisonHeapReference(obj);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005378 } else {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005379 __ movl(temp, Address(obj, class_offset));
5380 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005381 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005382
5383 switch (instruction->GetTypeCheckKind()) {
5384 case TypeCheckKind::kExactCheck:
5385 case TypeCheckKind::kArrayCheck: {
5386 if (cls.IsRegister()) {
5387 __ cmpl(temp, cls.AsRegister<Register>());
5388 } else {
5389 DCHECK(cls.IsStackSlot()) << cls;
5390 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5391 }
5392 // Jump to slow path for throwing the exception or doing a
5393 // more involved array check.
5394 __ j(kNotEqual, slow_path->GetEntryLabel());
5395 break;
5396 }
5397 case TypeCheckKind::kAbstractClassCheck: {
5398 // If the class is abstract, we eagerly fetch the super class of the
5399 // object to avoid doing a comparison we know will fail.
5400 NearLabel loop, success;
5401 __ Bind(&loop);
5402 __ movl(temp, Address(temp, super_offset));
5403 __ MaybeUnpoisonHeapReference(temp);
5404 __ testl(temp, temp);
5405 // Jump to the slow path to throw the exception.
5406 __ j(kEqual, slow_path->GetEntryLabel());
5407 if (cls.IsRegister()) {
5408 __ cmpl(temp, cls.AsRegister<Register>());
5409 } else {
5410 DCHECK(cls.IsStackSlot()) << cls;
5411 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5412 }
5413 __ j(kNotEqual, &loop);
5414 break;
5415 }
5416 case TypeCheckKind::kClassHierarchyCheck: {
5417 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005418 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005419 __ Bind(&loop);
5420 if (cls.IsRegister()) {
5421 __ cmpl(temp, cls.AsRegister<Register>());
5422 } else {
5423 DCHECK(cls.IsStackSlot()) << cls;
5424 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5425 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005426 __ j(kEqual, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005427 __ movl(temp, Address(temp, super_offset));
5428 __ MaybeUnpoisonHeapReference(temp);
5429 __ testl(temp, temp);
5430 __ j(kNotEqual, &loop);
5431 // Jump to the slow path to throw the exception.
5432 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005433 break;
5434 }
5435 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005436 // Do an exact check.
5437 if (cls.IsRegister()) {
5438 __ cmpl(temp, cls.AsRegister<Register>());
5439 } else {
5440 DCHECK(cls.IsStackSlot()) << cls;
5441 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5442 }
5443 __ j(kEqual, &done);
5444 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005445 __ movl(temp, Address(temp, component_offset));
5446 __ MaybeUnpoisonHeapReference(temp);
5447 __ testl(temp, temp);
5448 __ j(kEqual, slow_path->GetEntryLabel());
5449 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
5450 __ j(kNotEqual, slow_path->GetEntryLabel());
5451 break;
5452 }
Calin Juravle98893e12015-10-02 21:05:03 +01005453 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005454 case TypeCheckKind::kInterfaceCheck:
5455 default:
5456 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5457 instruction,
5458 instruction->GetDexPc(),
5459 nullptr);
5460 break;
5461 }
5462 __ Bind(&done);
5463
5464 if (slow_path != nullptr) {
5465 __ Bind(slow_path->GetExitLabel());
5466 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005467}
5468
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005469void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
5470 LocationSummary* locations =
5471 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5472 InvokeRuntimeCallingConvention calling_convention;
5473 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5474}
5475
5476void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005477 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5478 : QUICK_ENTRY_POINT(pUnlockObject),
5479 instruction,
5480 instruction->GetDexPc(),
5481 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005482}
5483
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005484void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5485void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5486void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5487
5488void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5489 LocationSummary* locations =
5490 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5491 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5492 || instruction->GetResultType() == Primitive::kPrimLong);
5493 locations->SetInAt(0, Location::RequiresRegister());
5494 locations->SetInAt(1, Location::Any());
5495 locations->SetOut(Location::SameAsFirstInput());
5496}
5497
5498void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
5499 HandleBitwiseOperation(instruction);
5500}
5501
5502void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
5503 HandleBitwiseOperation(instruction);
5504}
5505
5506void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
5507 HandleBitwiseOperation(instruction);
5508}
5509
5510void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5511 LocationSummary* locations = instruction->GetLocations();
5512 Location first = locations->InAt(0);
5513 Location second = locations->InAt(1);
5514 DCHECK(first.Equals(locations->Out()));
5515
5516 if (instruction->GetResultType() == Primitive::kPrimInt) {
5517 if (second.IsRegister()) {
5518 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005519 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005520 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005521 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005522 } else {
5523 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005524 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005525 }
5526 } else if (second.IsConstant()) {
5527 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005528 __ andl(first.AsRegister<Register>(),
5529 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005530 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005531 __ orl(first.AsRegister<Register>(),
5532 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005533 } else {
5534 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00005535 __ xorl(first.AsRegister<Register>(),
5536 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005537 }
5538 } else {
5539 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005540 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005541 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005542 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005543 } else {
5544 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005545 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005546 }
5547 }
5548 } else {
5549 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5550 if (second.IsRegisterPair()) {
5551 if (instruction->IsAnd()) {
5552 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5553 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5554 } else if (instruction->IsOr()) {
5555 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5556 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5557 } else {
5558 DCHECK(instruction->IsXor());
5559 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5560 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5561 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005562 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005563 if (instruction->IsAnd()) {
5564 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5565 __ andl(first.AsRegisterPairHigh<Register>(),
5566 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5567 } else if (instruction->IsOr()) {
5568 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5569 __ orl(first.AsRegisterPairHigh<Register>(),
5570 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5571 } else {
5572 DCHECK(instruction->IsXor());
5573 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5574 __ xorl(first.AsRegisterPairHigh<Register>(),
5575 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5576 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005577 } else {
5578 DCHECK(second.IsConstant()) << second;
5579 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005580 int32_t low_value = Low32Bits(value);
5581 int32_t high_value = High32Bits(value);
5582 Immediate low(low_value);
5583 Immediate high(high_value);
5584 Register first_low = first.AsRegisterPairLow<Register>();
5585 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005586 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005587 if (low_value == 0) {
5588 __ xorl(first_low, first_low);
5589 } else if (low_value != -1) {
5590 __ andl(first_low, low);
5591 }
5592 if (high_value == 0) {
5593 __ xorl(first_high, first_high);
5594 } else if (high_value != -1) {
5595 __ andl(first_high, high);
5596 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005597 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005598 if (low_value != 0) {
5599 __ orl(first_low, low);
5600 }
5601 if (high_value != 0) {
5602 __ orl(first_high, high);
5603 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005604 } else {
5605 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005606 if (low_value != 0) {
5607 __ xorl(first_low, low);
5608 }
5609 if (high_value != 0) {
5610 __ xorl(first_high, high);
5611 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005612 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005613 }
5614 }
5615}
5616
Calin Juravleb1498f62015-02-16 13:13:29 +00005617void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
5618 // Nothing to do, this should be removed during prepare for register allocator.
5619 UNUSED(instruction);
5620 LOG(FATAL) << "Unreachable";
5621}
5622
5623void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
5624 // Nothing to do, this should be removed during prepare for register allocator.
5625 UNUSED(instruction);
5626 LOG(FATAL) << "Unreachable";
5627}
5628
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005629void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) {
5630 DCHECK(codegen_->IsBaseline());
5631 LocationSummary* locations =
5632 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5633 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5634}
5635
5636void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5637 DCHECK(codegen_->IsBaseline());
5638 // Will be generated at use site.
5639}
5640
Mark Mendellfe57faa2015-09-18 09:26:15 -04005641// Simple implementation of packed switch - generate cascaded compare/jumps.
5642void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5643 LocationSummary* locations =
5644 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5645 locations->SetInAt(0, Location::RequiresRegister());
5646}
5647
5648void InstructionCodeGeneratorX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5649 int32_t lower_bound = switch_instr->GetStartValue();
5650 int32_t num_entries = switch_instr->GetNumEntries();
5651 LocationSummary* locations = switch_instr->GetLocations();
5652 Register value_reg = locations->InAt(0).AsRegister<Register>();
5653 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5654
5655 // Create a series of compare/jumps.
5656 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5657 for (int i = 0; i < num_entries; i++) {
5658 int32_t case_value = lower_bound + i;
5659 if (case_value == 0) {
5660 __ testl(value_reg, value_reg);
5661 } else {
5662 __ cmpl(value_reg, Immediate(case_value));
5663 }
Vladimir Markoec7802a2015-10-01 20:57:57 +01005664 __ j(kEqual, codegen_->GetLabelOf(successors[i]));
Mark Mendellfe57faa2015-09-18 09:26:15 -04005665 }
5666
5667 // And the default for any other value.
5668 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5669 __ jmp(codegen_->GetLabelOf(default_block));
5670 }
5671}
5672
Mark Mendell805b3b52015-09-18 14:10:29 -04005673void LocationsBuilderX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
5674 LocationSummary* locations =
5675 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5676 locations->SetInAt(0, Location::RequiresRegister());
5677
5678 // Constant area pointer.
5679 locations->SetInAt(1, Location::RequiresRegister());
5680
5681 // And the temporary we need.
5682 locations->AddTemp(Location::RequiresRegister());
5683}
5684
5685void InstructionCodeGeneratorX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
5686 int32_t lower_bound = switch_instr->GetStartValue();
5687 int32_t num_entries = switch_instr->GetNumEntries();
5688 LocationSummary* locations = switch_instr->GetLocations();
5689 Register value_reg = locations->InAt(0).AsRegister<Register>();
5690 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5691
5692 // Optimizing has a jump area.
5693 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
5694 Register constant_area = locations->InAt(1).AsRegister<Register>();
5695
5696 // Remove the bias, if needed.
5697 if (lower_bound != 0) {
5698 __ leal(temp_reg, Address(value_reg, -lower_bound));
5699 value_reg = temp_reg;
5700 }
5701
5702 // Is the value in range?
5703 DCHECK_GE(num_entries, 1);
5704 __ cmpl(value_reg, Immediate(num_entries - 1));
5705 __ j(kAbove, codegen_->GetLabelOf(default_block));
5706
5707 // We are in the range of the table.
5708 // Load (target-constant_area) from the jump table, indexing by the value.
5709 __ movl(temp_reg, codegen_->LiteralCaseTable(switch_instr, constant_area, value_reg));
5710
5711 // Compute the actual target address by adding in constant_area.
5712 __ addl(temp_reg, constant_area);
5713
5714 // And jump.
5715 __ jmp(temp_reg);
5716}
5717
Mark Mendell0616ae02015-04-17 12:49:27 -04005718void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
5719 HX86ComputeBaseMethodAddress* insn) {
5720 LocationSummary* locations =
5721 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5722 locations->SetOut(Location::RequiresRegister());
5723}
5724
5725void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
5726 HX86ComputeBaseMethodAddress* insn) {
5727 LocationSummary* locations = insn->GetLocations();
5728 Register reg = locations->Out().AsRegister<Register>();
5729
5730 // Generate call to next instruction.
5731 Label next_instruction;
5732 __ call(&next_instruction);
5733 __ Bind(&next_instruction);
5734
5735 // Remember this offset for later use with constant area.
5736 codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize());
5737
5738 // Grab the return address off the stack.
5739 __ popl(reg);
5740}
5741
5742void LocationsBuilderX86::VisitX86LoadFromConstantTable(
5743 HX86LoadFromConstantTable* insn) {
5744 LocationSummary* locations =
5745 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5746
5747 locations->SetInAt(0, Location::RequiresRegister());
5748 locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
5749
5750 // If we don't need to be materialized, we only need the inputs to be set.
5751 if (!insn->NeedsMaterialization()) {
5752 return;
5753 }
5754
5755 switch (insn->GetType()) {
5756 case Primitive::kPrimFloat:
5757 case Primitive::kPrimDouble:
5758 locations->SetOut(Location::RequiresFpuRegister());
5759 break;
5760
5761 case Primitive::kPrimInt:
5762 locations->SetOut(Location::RequiresRegister());
5763 break;
5764
5765 default:
5766 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5767 }
5768}
5769
5770void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
5771 if (!insn->NeedsMaterialization()) {
5772 return;
5773 }
5774
5775 LocationSummary* locations = insn->GetLocations();
5776 Location out = locations->Out();
5777 Register const_area = locations->InAt(0).AsRegister<Register>();
5778 HConstant *value = insn->GetConstant();
5779
5780 switch (insn->GetType()) {
5781 case Primitive::kPrimFloat:
5782 __ movss(out.AsFpuRegister<XmmRegister>(),
5783 codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area));
5784 break;
5785
5786 case Primitive::kPrimDouble:
5787 __ movsd(out.AsFpuRegister<XmmRegister>(),
5788 codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area));
5789 break;
5790
5791 case Primitive::kPrimInt:
5792 __ movl(out.AsRegister<Register>(),
5793 codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area));
5794 break;
5795
5796 default:
5797 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5798 }
5799}
5800
Mark Mendell0616ae02015-04-17 12:49:27 -04005801/**
5802 * Class to handle late fixup of offsets into constant area.
5803 */
Vladimir Marko5233f932015-09-29 19:01:15 +01005804class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
Mark Mendell0616ae02015-04-17 12:49:27 -04005805 public:
Mark Mendell805b3b52015-09-18 14:10:29 -04005806 RIPFixup(CodeGeneratorX86& codegen, size_t offset)
5807 : codegen_(&codegen), offset_into_constant_area_(offset) {}
5808
5809 protected:
5810 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
5811
5812 CodeGeneratorX86* codegen_;
Mark Mendell0616ae02015-04-17 12:49:27 -04005813
5814 private:
5815 void Process(const MemoryRegion& region, int pos) OVERRIDE {
5816 // Patch the correct offset for the instruction. The place to patch is the
5817 // last 4 bytes of the instruction.
5818 // The value to patch is the distance from the offset in the constant area
5819 // from the address computed by the HX86ComputeBaseMethodAddress instruction.
Mark Mendell805b3b52015-09-18 14:10:29 -04005820 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
5821 int32_t relative_position = constant_offset - codegen_->GetMethodAddressOffset();;
Mark Mendell0616ae02015-04-17 12:49:27 -04005822
5823 // Patch in the right value.
5824 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
5825 }
5826
Mark Mendell0616ae02015-04-17 12:49:27 -04005827 // Location in constant area that the fixup refers to.
Mark Mendell805b3b52015-09-18 14:10:29 -04005828 int32_t offset_into_constant_area_;
Mark Mendell0616ae02015-04-17 12:49:27 -04005829};
5830
Mark Mendell805b3b52015-09-18 14:10:29 -04005831/**
5832 * Class to handle late fixup of offsets to a jump table that will be created in the
5833 * constant area.
5834 */
5835class JumpTableRIPFixup : public RIPFixup {
5836 public:
5837 JumpTableRIPFixup(CodeGeneratorX86& codegen, HX86PackedSwitch* switch_instr)
5838 : RIPFixup(codegen, static_cast<size_t>(-1)), switch_instr_(switch_instr) {}
5839
5840 void CreateJumpTable() {
5841 X86Assembler* assembler = codegen_->GetAssembler();
5842
5843 // Ensure that the reference to the jump table has the correct offset.
5844 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
5845 SetOffset(offset_in_constant_table);
5846
5847 // The label values in the jump table are computed relative to the
5848 // instruction addressing the constant area.
5849 const int32_t relative_offset = codegen_->GetMethodAddressOffset();
5850
5851 // Populate the jump table with the correct values for the jump table.
5852 int32_t num_entries = switch_instr_->GetNumEntries();
5853 HBasicBlock* block = switch_instr_->GetBlock();
5854 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
5855 // The value that we want is the target offset - the position of the table.
5856 for (int32_t i = 0; i < num_entries; i++) {
5857 HBasicBlock* b = successors[i];
5858 Label* l = codegen_->GetLabelOf(b);
5859 DCHECK(l->IsBound());
5860 int32_t offset_to_block = l->Position() - relative_offset;
5861 assembler->AppendInt32(offset_to_block);
5862 }
5863 }
5864
5865 private:
5866 const HX86PackedSwitch* switch_instr_;
5867};
5868
5869void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
5870 // Generate the constant area if needed.
5871 X86Assembler* assembler = GetAssembler();
5872 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
5873 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
5874 // byte values.
5875 assembler->Align(4, 0);
5876 constant_area_start_ = assembler->CodeSize();
5877
5878 // Populate any jump tables.
5879 for (auto jump_table : fixups_to_jump_tables_) {
5880 jump_table->CreateJumpTable();
5881 }
5882
5883 // And now add the constant area to the generated code.
5884 assembler->AddConstantArea();
5885 }
5886
5887 // And finish up.
5888 CodeGenerator::Finalize(allocator);
5889}
5890
Mark Mendell0616ae02015-04-17 12:49:27 -04005891Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) {
5892 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
5893 return Address(reg, kDummy32BitOffset, fixup);
5894}
5895
5896Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) {
5897 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
5898 return Address(reg, kDummy32BitOffset, fixup);
5899}
5900
5901Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) {
5902 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
5903 return Address(reg, kDummy32BitOffset, fixup);
5904}
5905
5906Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) {
5907 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
5908 return Address(reg, kDummy32BitOffset, fixup);
5909}
5910
Mark Mendell805b3b52015-09-18 14:10:29 -04005911Address CodeGeneratorX86::LiteralCaseTable(HX86PackedSwitch* switch_instr,
5912 Register reg,
5913 Register value) {
5914 // Create a fixup to be used to create and address the jump table.
5915 JumpTableRIPFixup* table_fixup =
5916 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
5917
5918 // We have to populate the jump tables.
5919 fixups_to_jump_tables_.push_back(table_fixup);
5920
5921 // We want a scaled address, as we are extracting the correct offset from the table.
5922 return Address(reg, value, TIMES_4, kDummy32BitOffset, table_fixup);
5923}
5924
Mark Mendell0616ae02015-04-17 12:49:27 -04005925/**
5926 * Finds instructions that need the constant area base as an input.
5927 */
5928class ConstantHandlerVisitor : public HGraphVisitor {
5929 public:
5930 explicit ConstantHandlerVisitor(HGraph* graph) : HGraphVisitor(graph), base_(nullptr) {}
5931
5932 private:
5933 void VisitAdd(HAdd* add) OVERRIDE {
5934 BinaryFP(add);
5935 }
5936
5937 void VisitSub(HSub* sub) OVERRIDE {
5938 BinaryFP(sub);
5939 }
5940
5941 void VisitMul(HMul* mul) OVERRIDE {
5942 BinaryFP(mul);
5943 }
5944
5945 void VisitDiv(HDiv* div) OVERRIDE {
5946 BinaryFP(div);
5947 }
5948
5949 void VisitReturn(HReturn* ret) OVERRIDE {
5950 HConstant* value = ret->InputAt(0)->AsConstant();
5951 if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) {
5952 ReplaceInput(ret, value, 0, true);
5953 }
5954 }
5955
5956 void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
5957 HandleInvoke(invoke);
5958 }
5959
5960 void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE {
5961 HandleInvoke(invoke);
5962 }
5963
5964 void VisitInvokeInterface(HInvokeInterface* invoke) OVERRIDE {
5965 HandleInvoke(invoke);
5966 }
5967
5968 void BinaryFP(HBinaryOperation* bin) {
5969 HConstant* rhs = bin->InputAt(1)->AsConstant();
5970 if (rhs != nullptr && Primitive::IsFloatingPointType(bin->GetResultType())) {
5971 ReplaceInput(bin, rhs, 1, false);
5972 }
5973 }
5974
Mark Mendell805b3b52015-09-18 14:10:29 -04005975 void VisitPackedSwitch(HPackedSwitch* switch_insn) OVERRIDE {
5976 // We need to replace the HPackedSwitch with a HX86PackedSwitch in order to
5977 // address the constant area.
5978 InitializeConstantAreaPointer(switch_insn);
5979 HGraph* graph = GetGraph();
5980 HBasicBlock* block = switch_insn->GetBlock();
5981 HX86PackedSwitch* x86_switch = new (graph->GetArena()) HX86PackedSwitch(
5982 switch_insn->GetStartValue(),
5983 switch_insn->GetNumEntries(),
5984 switch_insn->InputAt(0),
5985 base_,
5986 switch_insn->GetDexPc());
5987 block->ReplaceAndRemoveInstructionWith(switch_insn, x86_switch);
5988 }
5989
Mark Mendell0616ae02015-04-17 12:49:27 -04005990 void InitializeConstantAreaPointer(HInstruction* user) {
5991 // Ensure we only initialize the pointer once.
5992 if (base_ != nullptr) {
5993 return;
5994 }
5995
5996 HGraph* graph = GetGraph();
5997 HBasicBlock* entry = graph->GetEntryBlock();
5998 base_ = new (graph->GetArena()) HX86ComputeBaseMethodAddress();
5999 HInstruction* insert_pos = (user->GetBlock() == entry) ? user : entry->GetLastInstruction();
6000 entry->InsertInstructionBefore(base_, insert_pos);
6001 DCHECK(base_ != nullptr);
6002 }
6003
6004 void ReplaceInput(HInstruction* insn, HConstant* value, int input_index, bool materialize) {
6005 InitializeConstantAreaPointer(insn);
6006 HGraph* graph = GetGraph();
6007 HBasicBlock* block = insn->GetBlock();
6008 HX86LoadFromConstantTable* load_constant =
6009 new (graph->GetArena()) HX86LoadFromConstantTable(base_, value, materialize);
6010 block->InsertInstructionBefore(load_constant, insn);
6011 insn->ReplaceInput(load_constant, input_index);
6012 }
6013
6014 void HandleInvoke(HInvoke* invoke) {
6015 // Ensure that we can load FP arguments from the constant area.
6016 for (size_t i = 0, e = invoke->InputCount(); i < e; i++) {
6017 HConstant* input = invoke->InputAt(i)->AsConstant();
6018 if (input != nullptr && Primitive::IsFloatingPointType(input->GetType())) {
6019 ReplaceInput(invoke, input, i, true);
6020 }
6021 }
6022 }
6023
6024 // The generated HX86ComputeBaseMethodAddress in the entry block needed as an
6025 // input to the HX86LoadFromConstantTable instructions.
6026 HX86ComputeBaseMethodAddress* base_;
6027};
6028
6029void ConstantAreaFixups::Run() {
6030 ConstantHandlerVisitor visitor(graph_);
6031 visitor.VisitInsertionOrder();
6032}
6033
Andreas Gampe85b62f22015-09-09 13:15:38 -07006034// TODO: target as memory.
6035void CodeGeneratorX86::MoveFromReturnRegister(Location target, Primitive::Type type) {
6036 if (!target.IsValid()) {
6037 DCHECK(type == Primitive::kPrimVoid);
6038 return;
6039 }
6040
6041 DCHECK_NE(type, Primitive::kPrimVoid);
6042
6043 Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type);
6044 if (target.Equals(return_loc)) {
6045 return;
6046 }
6047
6048 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
6049 // with the else branch.
6050 if (type == Primitive::kPrimLong) {
6051 HParallelMove parallel_move(GetGraph()->GetArena());
6052 parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), Primitive::kPrimInt, nullptr);
6053 parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), Primitive::kPrimInt, nullptr);
6054 GetMoveResolver()->EmitNativeCode(&parallel_move);
6055 } else {
6056 // Let the parallel move resolver take care of all of this.
6057 HParallelMove parallel_move(GetGraph()->GetArena());
6058 parallel_move.AddMove(return_loc, target, type, nullptr);
6059 GetMoveResolver()->EmitNativeCode(&parallel_move);
6060 }
6061}
6062
Roland Levillain4d027112015-07-01 15:41:14 +01006063#undef __
6064
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006065} // namespace x86
6066} // namespace art