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