blob: 9de159251fbbb9110ec7dcf66607dd13b18e54a2 [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
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001055void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001056 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001057}
1058
Mark Mendellc4701932015-04-10 13:18:51 -04001059void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
1060 Label* true_label,
1061 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001062 if (cond->IsFPConditionTrueIfNaN()) {
1063 __ j(kUnordered, true_label);
1064 } else if (cond->IsFPConditionFalseIfNaN()) {
1065 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001066 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001067 __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001068}
1069
1070void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
1071 Label* true_label,
1072 Label* false_label) {
1073 LocationSummary* locations = cond->GetLocations();
1074 Location left = locations->InAt(0);
1075 Location right = locations->InAt(1);
1076 IfCondition if_cond = cond->GetCondition();
1077
Mark Mendellc4701932015-04-10 13:18:51 -04001078 Register left_high = left.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001079 Register left_low = left.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001080 IfCondition true_high_cond = if_cond;
1081 IfCondition false_high_cond = cond->GetOppositeCondition();
Aart Bike9f37602015-10-09 11:15:55 -07001082 Condition final_condition = X86UnsignedOrFPCondition(if_cond); // unsigned on lower part
Mark Mendellc4701932015-04-10 13:18:51 -04001083
1084 // Set the conditions for the test, remembering that == needs to be
1085 // decided using the low words.
1086 switch (if_cond) {
1087 case kCondEQ:
Mark Mendellc4701932015-04-10 13:18:51 -04001088 case kCondNE:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001089 // Nothing to do.
Mark Mendellc4701932015-04-10 13:18:51 -04001090 break;
1091 case kCondLT:
1092 false_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001093 break;
1094 case kCondLE:
1095 true_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001096 break;
1097 case kCondGT:
1098 false_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001099 break;
1100 case kCondGE:
1101 true_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001102 break;
Aart Bike9f37602015-10-09 11:15:55 -07001103 case kCondB:
1104 false_high_cond = kCondA;
1105 break;
1106 case kCondBE:
1107 true_high_cond = kCondB;
1108 break;
1109 case kCondA:
1110 false_high_cond = kCondB;
1111 break;
1112 case kCondAE:
1113 true_high_cond = kCondA;
1114 break;
Mark Mendellc4701932015-04-10 13:18:51 -04001115 }
1116
1117 if (right.IsConstant()) {
1118 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellc4701932015-04-10 13:18:51 -04001119 int32_t val_high = High32Bits(value);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001120 int32_t val_low = Low32Bits(value);
Mark Mendellc4701932015-04-10 13:18:51 -04001121
1122 if (val_high == 0) {
1123 __ testl(left_high, left_high);
1124 } else {
1125 __ cmpl(left_high, Immediate(val_high));
1126 }
1127 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001128 __ j(X86Condition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001129 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001130 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001131 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001132 __ j(X86Condition(true_high_cond), true_label);
1133 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001134 }
1135 // Must be equal high, so compare the lows.
1136 if (val_low == 0) {
1137 __ testl(left_low, left_low);
1138 } else {
1139 __ cmpl(left_low, Immediate(val_low));
1140 }
1141 } else {
Mark Mendellc4701932015-04-10 13:18:51 -04001142 Register right_high = right.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001143 Register right_low = right.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001144
1145 __ cmpl(left_high, right_high);
1146 if (if_cond == kCondNE) {
Aart Bike9f37602015-10-09 11:15:55 -07001147 __ j(X86Condition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001148 } else if (if_cond == kCondEQ) {
Aart Bike9f37602015-10-09 11:15:55 -07001149 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001150 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001151 __ j(X86Condition(true_high_cond), true_label);
1152 __ j(X86Condition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001153 }
1154 // Must be equal high, so compare the lows.
1155 __ cmpl(left_low, right_low);
1156 }
1157 // The last comparison might be unsigned.
1158 __ j(final_condition, true_label);
1159}
1160
1161void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HIf* if_instr,
1162 HCondition* condition,
1163 Label* true_target,
1164 Label* false_target,
1165 Label* always_true_target) {
1166 LocationSummary* locations = condition->GetLocations();
1167 Location left = locations->InAt(0);
1168 Location right = locations->InAt(1);
1169
1170 // We don't want true_target as a nullptr.
1171 if (true_target == nullptr) {
1172 true_target = always_true_target;
1173 }
1174 bool falls_through = (false_target == nullptr);
1175
1176 // FP compares don't like null false_targets.
1177 if (false_target == nullptr) {
1178 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1179 }
1180
1181 Primitive::Type type = condition->InputAt(0)->GetType();
1182 switch (type) {
1183 case Primitive::kPrimLong:
1184 GenerateLongComparesAndJumps(condition, true_target, false_target);
1185 break;
1186 case Primitive::kPrimFloat:
Mark Mendellc4701932015-04-10 13:18:51 -04001187 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1188 GenerateFPJumps(condition, true_target, false_target);
1189 break;
1190 case Primitive::kPrimDouble:
Mark Mendellc4701932015-04-10 13:18:51 -04001191 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1192 GenerateFPJumps(condition, true_target, false_target);
1193 break;
1194 default:
1195 LOG(FATAL) << "Unexpected compare type " << type;
1196 }
1197
1198 if (!falls_through) {
1199 __ jmp(false_target);
1200 }
1201}
1202
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001203void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
1204 Label* true_target,
1205 Label* false_target,
1206 Label* always_true_target) {
1207 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001208 if (cond->IsIntConstant()) {
1209 // Constant condition, statically compared against 1.
1210 int32_t cond_value = cond->AsIntConstant()->GetValue();
1211 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001212 if (always_true_target != nullptr) {
1213 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001214 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001215 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001216 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001217 DCHECK_EQ(cond_value, 0);
1218 }
1219 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001220 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001221 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
1222 // 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.
1226 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001227 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001228 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
Roland Levillain4fa13f62015-07-06 18:11:54 +01001229 && (type != Primitive::kPrimLong && !Primitive::IsFloatingPointType(type));
1230 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001231 if (!eflags_set) {
1232 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001233 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001234 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001235 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001236 } else {
1237 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
1238 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001239 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001240 } else {
Aart Bike9f37602015-10-09 11:15:55 -07001241 __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001242 }
1243 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001244 // Condition has not been materialized, use its inputs as the
1245 // comparison and its condition as the branch condition.
1246
Mark Mendellc4701932015-04-10 13:18:51 -04001247 // Is this a long or FP comparison that has been folded into the HCondition?
1248 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1249 // Generate the comparison directly.
1250 GenerateCompareTestAndBranch(instruction->AsIf(),
1251 cond->AsCondition(),
1252 true_target,
1253 false_target,
1254 always_true_target);
1255 return;
1256 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001257
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001258 Location lhs = cond->GetLocations()->InAt(0);
1259 Location rhs = cond->GetLocations()->InAt(1);
1260 // LHS is guaranteed to be in a register (see
1261 // LocationsBuilderX86::VisitCondition).
1262 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001263 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001264 } else if (rhs.IsConstant()) {
Calin Juravleb3306642015-04-20 18:30:42 +01001265 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -05001266 if (constant == 0) {
1267 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1268 } else {
1269 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1270 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001271 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001272 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001273 }
Aart Bike9f37602015-10-09 11:15:55 -07001274 __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001275 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001276 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001277 if (false_target != nullptr) {
1278 __ jmp(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001279 }
1280}
1281
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001282void LocationsBuilderX86::VisitIf(HIf* if_instr) {
1283 LocationSummary* locations =
1284 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1285 HInstruction* cond = if_instr->InputAt(0);
1286 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1287 locations->SetInAt(0, Location::Any());
1288 }
1289}
1290
1291void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
1292 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1293 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1294 Label* always_true_target = true_target;
1295 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1296 if_instr->IfTrueSuccessor())) {
1297 always_true_target = nullptr;
1298 }
1299 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1300 if_instr->IfFalseSuccessor())) {
1301 false_target = nullptr;
1302 }
1303 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1304}
1305
1306void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
1307 LocationSummary* locations = new (GetGraph()->GetArena())
1308 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1309 HInstruction* cond = deoptimize->InputAt(0);
1310 DCHECK(cond->IsCondition());
1311 if (cond->AsCondition()->NeedsMaterialization()) {
1312 locations->SetInAt(0, Location::Any());
1313 }
1314}
1315
1316void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001317 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001318 DeoptimizationSlowPathX86(deoptimize);
1319 codegen_->AddSlowPath(slow_path);
1320 Label* slow_path_entry = slow_path->GetEntryLabel();
1321 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1322}
1323
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001324void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001325 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001326}
1327
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001328void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
1329 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001330}
1331
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001332void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001333 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001334}
1335
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001336void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001337 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001338 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001339}
1340
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001341void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001342 LocationSummary* locations =
1343 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001344 switch (store->InputAt(1)->GetType()) {
1345 case Primitive::kPrimBoolean:
1346 case Primitive::kPrimByte:
1347 case Primitive::kPrimChar:
1348 case Primitive::kPrimShort:
1349 case Primitive::kPrimInt:
1350 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001351 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001352 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1353 break;
1354
1355 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001356 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001357 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1358 break;
1359
1360 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001361 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001362 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001363}
1364
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001365void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001366 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001367}
1368
Roland Levillain0d37cd02015-05-27 16:39:19 +01001369void LocationsBuilderX86::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001370 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001371 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001372 // Handle the long/FP comparisons made in instruction simplification.
1373 switch (cond->InputAt(0)->GetType()) {
1374 case Primitive::kPrimLong: {
1375 locations->SetInAt(0, Location::RequiresRegister());
1376 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1377 if (cond->NeedsMaterialization()) {
1378 locations->SetOut(Location::RequiresRegister());
1379 }
1380 break;
1381 }
1382 case Primitive::kPrimFloat:
1383 case Primitive::kPrimDouble: {
1384 locations->SetInAt(0, Location::RequiresFpuRegister());
1385 locations->SetInAt(1, Location::RequiresFpuRegister());
1386 if (cond->NeedsMaterialization()) {
1387 locations->SetOut(Location::RequiresRegister());
1388 }
1389 break;
1390 }
1391 default:
1392 locations->SetInAt(0, Location::RequiresRegister());
1393 locations->SetInAt(1, Location::Any());
1394 if (cond->NeedsMaterialization()) {
1395 // We need a byte register.
1396 locations->SetOut(Location::RegisterLocation(ECX));
1397 }
1398 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001399 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001400}
1401
Roland Levillain0d37cd02015-05-27 16:39:19 +01001402void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001403 if (!cond->NeedsMaterialization()) {
1404 return;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001405 }
Mark Mendellc4701932015-04-10 13:18:51 -04001406
1407 LocationSummary* locations = cond->GetLocations();
1408 Location lhs = locations->InAt(0);
1409 Location rhs = locations->InAt(1);
1410 Register reg = locations->Out().AsRegister<Register>();
1411 Label true_label, false_label;
1412
1413 switch (cond->InputAt(0)->GetType()) {
1414 default: {
1415 // Integer case.
1416
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01001417 // Clear output register: setb only sets the low byte.
Mark Mendellc4701932015-04-10 13:18:51 -04001418 __ xorl(reg, reg);
1419
1420 if (rhs.IsRegister()) {
1421 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
1422 } else if (rhs.IsConstant()) {
1423 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1424 if (constant == 0) {
1425 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1426 } else {
1427 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1428 }
1429 } else {
1430 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
1431 }
Aart Bike9f37602015-10-09 11:15:55 -07001432 __ setb(X86Condition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001433 return;
1434 }
1435 case Primitive::kPrimLong:
1436 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1437 break;
1438 case Primitive::kPrimFloat:
1439 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1440 GenerateFPJumps(cond, &true_label, &false_label);
1441 break;
1442 case Primitive::kPrimDouble:
1443 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1444 GenerateFPJumps(cond, &true_label, &false_label);
1445 break;
1446 }
1447
1448 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001449 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001450
Roland Levillain4fa13f62015-07-06 18:11:54 +01001451 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001452 __ Bind(&false_label);
1453 __ xorl(reg, reg);
1454 __ jmp(&done_label);
1455
Roland Levillain4fa13f62015-07-06 18:11:54 +01001456 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001457 __ Bind(&true_label);
1458 __ movl(reg, Immediate(1));
1459 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001460}
1461
1462void LocationsBuilderX86::VisitEqual(HEqual* comp) {
1463 VisitCondition(comp);
1464}
1465
1466void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
1467 VisitCondition(comp);
1468}
1469
1470void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
1471 VisitCondition(comp);
1472}
1473
1474void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
1475 VisitCondition(comp);
1476}
1477
1478void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
1479 VisitCondition(comp);
1480}
1481
1482void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
1483 VisitCondition(comp);
1484}
1485
1486void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1487 VisitCondition(comp);
1488}
1489
1490void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1491 VisitCondition(comp);
1492}
1493
1494void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
1495 VisitCondition(comp);
1496}
1497
1498void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
1499 VisitCondition(comp);
1500}
1501
1502void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1503 VisitCondition(comp);
1504}
1505
1506void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1507 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001508}
1509
Aart Bike9f37602015-10-09 11:15:55 -07001510void LocationsBuilderX86::VisitBelow(HBelow* comp) {
1511 VisitCondition(comp);
1512}
1513
1514void InstructionCodeGeneratorX86::VisitBelow(HBelow* comp) {
1515 VisitCondition(comp);
1516}
1517
1518void LocationsBuilderX86::VisitBelowOrEqual(HBelowOrEqual* comp) {
1519 VisitCondition(comp);
1520}
1521
1522void InstructionCodeGeneratorX86::VisitBelowOrEqual(HBelowOrEqual* comp) {
1523 VisitCondition(comp);
1524}
1525
1526void LocationsBuilderX86::VisitAbove(HAbove* comp) {
1527 VisitCondition(comp);
1528}
1529
1530void InstructionCodeGeneratorX86::VisitAbove(HAbove* comp) {
1531 VisitCondition(comp);
1532}
1533
1534void LocationsBuilderX86::VisitAboveOrEqual(HAboveOrEqual* comp) {
1535 VisitCondition(comp);
1536}
1537
1538void InstructionCodeGeneratorX86::VisitAboveOrEqual(HAboveOrEqual* comp) {
1539 VisitCondition(comp);
1540}
1541
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001542void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001543 LocationSummary* locations =
1544 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001545 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001546}
1547
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001548void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001549 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001550 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001551}
1552
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001553void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1554 LocationSummary* locations =
1555 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1556 locations->SetOut(Location::ConstantLocation(constant));
1557}
1558
1559void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1560 // Will be generated at use site.
1561 UNUSED(constant);
1562}
1563
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001564void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001565 LocationSummary* locations =
1566 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001567 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001568}
1569
1570void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1571 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001572 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001573}
1574
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001575void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1576 LocationSummary* locations =
1577 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1578 locations->SetOut(Location::ConstantLocation(constant));
1579}
1580
1581void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1582 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001583 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001584}
1585
1586void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1587 LocationSummary* locations =
1588 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1589 locations->SetOut(Location::ConstantLocation(constant));
1590}
1591
1592void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1593 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001594 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001595}
1596
Calin Juravle27df7582015-04-17 19:12:31 +01001597void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1598 memory_barrier->SetLocations(nullptr);
1599}
1600
1601void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1602 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1603}
1604
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001605void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001606 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001607}
1608
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001609void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001610 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001611 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001612}
1613
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001614void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001615 LocationSummary* locations =
1616 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001617 switch (ret->InputAt(0)->GetType()) {
1618 case Primitive::kPrimBoolean:
1619 case Primitive::kPrimByte:
1620 case Primitive::kPrimChar:
1621 case Primitive::kPrimShort:
1622 case Primitive::kPrimInt:
1623 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001624 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001625 break;
1626
1627 case Primitive::kPrimLong:
1628 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001629 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001630 break;
1631
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001632 case Primitive::kPrimFloat:
1633 case Primitive::kPrimDouble:
1634 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001635 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001636 break;
1637
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001638 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001639 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001640 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001641}
1642
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001643void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001644 if (kIsDebugBuild) {
1645 switch (ret->InputAt(0)->GetType()) {
1646 case Primitive::kPrimBoolean:
1647 case Primitive::kPrimByte:
1648 case Primitive::kPrimChar:
1649 case Primitive::kPrimShort:
1650 case Primitive::kPrimInt:
1651 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001652 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001653 break;
1654
1655 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001656 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1657 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001658 break;
1659
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001660 case Primitive::kPrimFloat:
1661 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001662 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001663 break;
1664
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001665 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001666 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001667 }
1668 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001669 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001670}
1671
Calin Juravle175dc732015-08-25 15:42:32 +01001672void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1673 // The trampoline uses the same calling convention as dex calling conventions,
1674 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1675 // the method_idx.
1676 HandleInvoke(invoke);
1677}
1678
1679void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1680 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1681}
1682
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001683void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001684 // When we do not run baseline, explicit clinit checks triggered by static
1685 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1686 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001687
Mark Mendellfb8d2792015-03-31 22:16:59 -04001688 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001689 if (intrinsic.TryDispatch(invoke)) {
1690 return;
1691 }
1692
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001693 HandleInvoke(invoke);
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001694
1695 if (codegen_->IsBaseline()) {
1696 // Baseline does not have enough registers if the current method also
1697 // needs a register. We therefore do not require a register for it, and let
1698 // the code generation of the invoke handle it.
1699 LocationSummary* locations = invoke->GetLocations();
1700 Location location = locations->InAt(invoke->GetCurrentMethodInputIndex());
1701 if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) {
1702 locations->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::NoLocation());
1703 }
1704 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001705}
1706
Mark Mendell09ed1a32015-03-25 08:30:06 -04001707static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1708 if (invoke->GetLocations()->Intrinsified()) {
1709 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1710 intrinsic.Dispatch(invoke);
1711 return true;
1712 }
1713 return false;
1714}
1715
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001716void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001717 // When we do not run baseline, explicit clinit checks triggered by static
1718 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1719 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001720
Mark Mendell09ed1a32015-03-25 08:30:06 -04001721 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1722 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001723 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001724
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001725 LocationSummary* locations = invoke->GetLocations();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001726 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001727 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Mingyao Yang8693fe12015-04-17 16:51:08 -07001728 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001729}
1730
1731void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1732 HandleInvoke(invoke);
1733}
1734
1735void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001736 InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001737 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001738}
1739
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001740void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001741 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1742 return;
1743 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001744
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001745 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001746 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001747 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001748}
1749
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001750void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1751 HandleInvoke(invoke);
1752 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001753 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001754}
1755
1756void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1757 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001758 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001759 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1760 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001761 LocationSummary* locations = invoke->GetLocations();
1762 Location receiver = locations->InAt(0);
1763 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1764
1765 // Set the hidden argument.
1766 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001767 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001768
1769 // temp = object->GetClass();
1770 if (receiver.IsStackSlot()) {
1771 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1772 __ movl(temp, Address(temp, class_offset));
1773 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001774 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001775 }
Roland Levillain4d027112015-07-01 15:41:14 +01001776 codegen_->MaybeRecordImplicitNullCheck(invoke);
1777 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001778 // temp = temp->GetImtEntryAt(method_offset);
1779 __ movl(temp, Address(temp, method_offset));
1780 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001781 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001782 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001783
1784 DCHECK(!codegen_->IsLeafMethod());
1785 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1786}
1787
Roland Levillain88cb1752014-10-20 16:36:47 +01001788void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1789 LocationSummary* locations =
1790 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1791 switch (neg->GetResultType()) {
1792 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001793 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001794 locations->SetInAt(0, Location::RequiresRegister());
1795 locations->SetOut(Location::SameAsFirstInput());
1796 break;
1797
Roland Levillain88cb1752014-10-20 16:36:47 +01001798 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001799 locations->SetInAt(0, Location::RequiresFpuRegister());
1800 locations->SetOut(Location::SameAsFirstInput());
1801 locations->AddTemp(Location::RequiresRegister());
1802 locations->AddTemp(Location::RequiresFpuRegister());
1803 break;
1804
Roland Levillain88cb1752014-10-20 16:36:47 +01001805 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001806 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001807 locations->SetOut(Location::SameAsFirstInput());
1808 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001809 break;
1810
1811 default:
1812 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1813 }
1814}
1815
1816void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1817 LocationSummary* locations = neg->GetLocations();
1818 Location out = locations->Out();
1819 Location in = locations->InAt(0);
1820 switch (neg->GetResultType()) {
1821 case Primitive::kPrimInt:
1822 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001823 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001824 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001825 break;
1826
1827 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001828 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001829 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001830 __ negl(out.AsRegisterPairLow<Register>());
1831 // Negation is similar to subtraction from zero. The least
1832 // significant byte triggers a borrow when it is different from
1833 // zero; to take it into account, add 1 to the most significant
1834 // byte if the carry flag (CF) is set to 1 after the first NEGL
1835 // operation.
1836 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1837 __ negl(out.AsRegisterPairHigh<Register>());
1838 break;
1839
Roland Levillain5368c212014-11-27 15:03:41 +00001840 case Primitive::kPrimFloat: {
1841 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001842 Register constant = locations->GetTemp(0).AsRegister<Register>();
1843 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001844 // Implement float negation with an exclusive or with value
1845 // 0x80000000 (mask for bit 31, representing the sign of a
1846 // single-precision floating-point number).
1847 __ movl(constant, Immediate(INT32_C(0x80000000)));
1848 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001849 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001850 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001851 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001852
Roland Levillain5368c212014-11-27 15:03:41 +00001853 case Primitive::kPrimDouble: {
1854 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001855 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001856 // Implement double negation with an exclusive or with value
1857 // 0x8000000000000000 (mask for bit 63, representing the sign of
1858 // a double-precision floating-point number).
1859 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001860 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001861 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001862 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001863
1864 default:
1865 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1866 }
1867}
1868
Roland Levillaindff1f282014-11-05 14:15:05 +00001869void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001870 Primitive::Type result_type = conversion->GetResultType();
1871 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001872 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001873
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001874 // The float-to-long and double-to-long type conversions rely on a
1875 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001876 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001877 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1878 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001879 ? LocationSummary::kCall
1880 : LocationSummary::kNoCall;
1881 LocationSummary* locations =
1882 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1883
David Brazdilb2bd1c52015-03-25 11:17:37 +00001884 // The Java language does not allow treating boolean as an integral type but
1885 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001886
Roland Levillaindff1f282014-11-05 14:15:05 +00001887 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001888 case Primitive::kPrimByte:
1889 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001890 case Primitive::kPrimBoolean:
1891 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001892 case Primitive::kPrimShort:
1893 case Primitive::kPrimInt:
1894 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001895 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001896 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1897 // Make the output overlap to please the register allocator. This greatly simplifies
1898 // the validation of the linear scan implementation
1899 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001900 break;
1901
1902 default:
1903 LOG(FATAL) << "Unexpected type conversion from " << input_type
1904 << " to " << result_type;
1905 }
1906 break;
1907
Roland Levillain01a8d712014-11-14 16:27:39 +00001908 case Primitive::kPrimShort:
1909 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001910 case Primitive::kPrimBoolean:
1911 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001912 case Primitive::kPrimByte:
1913 case Primitive::kPrimInt:
1914 case Primitive::kPrimChar:
1915 // Processing a Dex `int-to-short' instruction.
1916 locations->SetInAt(0, Location::Any());
1917 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1918 break;
1919
1920 default:
1921 LOG(FATAL) << "Unexpected type conversion from " << input_type
1922 << " to " << result_type;
1923 }
1924 break;
1925
Roland Levillain946e1432014-11-11 17:35:19 +00001926 case Primitive::kPrimInt:
1927 switch (input_type) {
1928 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001929 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001930 locations->SetInAt(0, Location::Any());
1931 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1932 break;
1933
1934 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001935 // Processing a Dex `float-to-int' instruction.
1936 locations->SetInAt(0, Location::RequiresFpuRegister());
1937 locations->SetOut(Location::RequiresRegister());
1938 locations->AddTemp(Location::RequiresFpuRegister());
1939 break;
1940
Roland Levillain946e1432014-11-11 17:35:19 +00001941 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001942 // Processing a Dex `double-to-int' instruction.
1943 locations->SetInAt(0, Location::RequiresFpuRegister());
1944 locations->SetOut(Location::RequiresRegister());
1945 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001946 break;
1947
1948 default:
1949 LOG(FATAL) << "Unexpected type conversion from " << input_type
1950 << " to " << result_type;
1951 }
1952 break;
1953
Roland Levillaindff1f282014-11-05 14:15:05 +00001954 case Primitive::kPrimLong:
1955 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001956 case Primitive::kPrimBoolean:
1957 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001958 case Primitive::kPrimByte:
1959 case Primitive::kPrimShort:
1960 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001961 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001962 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001963 locations->SetInAt(0, Location::RegisterLocation(EAX));
1964 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1965 break;
1966
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001967 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001968 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001969 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001970 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001971 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1972 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1973
Vladimir Marko949c91f2015-01-27 10:48:44 +00001974 // The runtime helper puts the result in EAX, EDX.
1975 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001976 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001977 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001978
1979 default:
1980 LOG(FATAL) << "Unexpected type conversion from " << input_type
1981 << " to " << result_type;
1982 }
1983 break;
1984
Roland Levillain981e4542014-11-14 11:47:14 +00001985 case Primitive::kPrimChar:
1986 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001987 case Primitive::kPrimBoolean:
1988 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001989 case Primitive::kPrimByte:
1990 case Primitive::kPrimShort:
1991 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001992 // Processing a Dex `int-to-char' instruction.
1993 locations->SetInAt(0, Location::Any());
1994 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1995 break;
1996
1997 default:
1998 LOG(FATAL) << "Unexpected type conversion from " << input_type
1999 << " to " << result_type;
2000 }
2001 break;
2002
Roland Levillaindff1f282014-11-05 14:15:05 +00002003 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002004 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002005 case Primitive::kPrimBoolean:
2006 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002007 case Primitive::kPrimByte:
2008 case Primitive::kPrimShort:
2009 case Primitive::kPrimInt:
2010 case Primitive::kPrimChar:
2011 // Processing a Dex `int-to-float' instruction.
2012 locations->SetInAt(0, Location::RequiresRegister());
2013 locations->SetOut(Location::RequiresFpuRegister());
2014 break;
2015
2016 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002017 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002018 locations->SetInAt(0, Location::Any());
2019 locations->SetOut(Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00002020 break;
2021
Roland Levillaincff13742014-11-17 14:32:17 +00002022 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002023 // Processing a Dex `double-to-float' instruction.
2024 locations->SetInAt(0, Location::RequiresFpuRegister());
2025 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002026 break;
2027
2028 default:
2029 LOG(FATAL) << "Unexpected type conversion from " << input_type
2030 << " to " << result_type;
2031 };
2032 break;
2033
Roland Levillaindff1f282014-11-05 14:15:05 +00002034 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002035 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002036 case Primitive::kPrimBoolean:
2037 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002038 case Primitive::kPrimByte:
2039 case Primitive::kPrimShort:
2040 case Primitive::kPrimInt:
2041 case Primitive::kPrimChar:
2042 // Processing a Dex `int-to-double' instruction.
2043 locations->SetInAt(0, Location::RequiresRegister());
2044 locations->SetOut(Location::RequiresFpuRegister());
2045 break;
2046
2047 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00002048 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002049 locations->SetInAt(0, Location::Any());
2050 locations->SetOut(Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00002051 break;
2052
Roland Levillaincff13742014-11-17 14:32:17 +00002053 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002054 // Processing a Dex `float-to-double' instruction.
2055 locations->SetInAt(0, Location::RequiresFpuRegister());
2056 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00002057 break;
2058
2059 default:
2060 LOG(FATAL) << "Unexpected type conversion from " << input_type
2061 << " to " << result_type;
2062 }
Roland Levillaindff1f282014-11-05 14:15:05 +00002063 break;
2064
2065 default:
2066 LOG(FATAL) << "Unexpected type conversion from " << input_type
2067 << " to " << result_type;
2068 }
2069}
2070
2071void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
2072 LocationSummary* locations = conversion->GetLocations();
2073 Location out = locations->Out();
2074 Location in = locations->InAt(0);
2075 Primitive::Type result_type = conversion->GetResultType();
2076 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00002077 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00002078 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00002079 case Primitive::kPrimByte:
2080 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002081 case Primitive::kPrimBoolean:
2082 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00002083 case Primitive::kPrimShort:
2084 case Primitive::kPrimInt:
2085 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002086 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002087 if (in.IsRegister()) {
2088 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002089 } else {
2090 DCHECK(in.GetConstant()->IsIntConstant());
2091 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
2092 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
2093 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00002094 break;
2095
2096 default:
2097 LOG(FATAL) << "Unexpected type conversion from " << input_type
2098 << " to " << result_type;
2099 }
2100 break;
2101
Roland Levillain01a8d712014-11-14 16:27:39 +00002102 case Primitive::kPrimShort:
2103 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002104 case Primitive::kPrimBoolean:
2105 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00002106 case Primitive::kPrimByte:
2107 case Primitive::kPrimInt:
2108 case Primitive::kPrimChar:
2109 // Processing a Dex `int-to-short' instruction.
2110 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002111 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00002112 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002113 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00002114 } else {
2115 DCHECK(in.GetConstant()->IsIntConstant());
2116 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002117 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00002118 }
2119 break;
2120
2121 default:
2122 LOG(FATAL) << "Unexpected type conversion from " << input_type
2123 << " to " << result_type;
2124 }
2125 break;
2126
Roland Levillain946e1432014-11-11 17:35:19 +00002127 case Primitive::kPrimInt:
2128 switch (input_type) {
2129 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00002130 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00002131 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002132 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002133 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002134 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00002135 } else {
2136 DCHECK(in.IsConstant());
2137 DCHECK(in.GetConstant()->IsLongConstant());
2138 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002139 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002140 }
2141 break;
2142
Roland Levillain3f8f9362014-12-02 17:45:01 +00002143 case Primitive::kPrimFloat: {
2144 // Processing a Dex `float-to-int' instruction.
2145 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2146 Register output = out.AsRegister<Register>();
2147 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002148 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002149
2150 __ movl(output, Immediate(kPrimIntMax));
2151 // temp = int-to-float(output)
2152 __ cvtsi2ss(temp, output);
2153 // if input >= temp goto done
2154 __ comiss(input, temp);
2155 __ j(kAboveEqual, &done);
2156 // if input == NaN goto nan
2157 __ j(kUnordered, &nan);
2158 // output = float-to-int-truncate(input)
2159 __ cvttss2si(output, input);
2160 __ jmp(&done);
2161 __ Bind(&nan);
2162 // output = 0
2163 __ xorl(output, output);
2164 __ Bind(&done);
2165 break;
2166 }
2167
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002168 case Primitive::kPrimDouble: {
2169 // Processing a Dex `double-to-int' instruction.
2170 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2171 Register output = out.AsRegister<Register>();
2172 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002173 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002174
2175 __ movl(output, Immediate(kPrimIntMax));
2176 // temp = int-to-double(output)
2177 __ cvtsi2sd(temp, output);
2178 // if input >= temp goto done
2179 __ comisd(input, temp);
2180 __ j(kAboveEqual, &done);
2181 // if input == NaN goto nan
2182 __ j(kUnordered, &nan);
2183 // output = double-to-int-truncate(input)
2184 __ cvttsd2si(output, input);
2185 __ jmp(&done);
2186 __ Bind(&nan);
2187 // output = 0
2188 __ xorl(output, output);
2189 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002190 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002191 }
Roland Levillain946e1432014-11-11 17:35:19 +00002192
2193 default:
2194 LOG(FATAL) << "Unexpected type conversion from " << input_type
2195 << " to " << result_type;
2196 }
2197 break;
2198
Roland Levillaindff1f282014-11-05 14:15:05 +00002199 case Primitive::kPrimLong:
2200 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002201 case Primitive::kPrimBoolean:
2202 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002203 case Primitive::kPrimByte:
2204 case Primitive::kPrimShort:
2205 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002206 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002207 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002208 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
2209 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00002210 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00002211 __ cdq();
2212 break;
2213
2214 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002215 // Processing a Dex `float-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002216 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2217 conversion,
2218 conversion->GetDexPc(),
2219 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002220 break;
2221
Roland Levillaindff1f282014-11-05 14:15:05 +00002222 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002223 // Processing a Dex `double-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002224 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2225 conversion,
2226 conversion->GetDexPc(),
2227 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002228 break;
2229
2230 default:
2231 LOG(FATAL) << "Unexpected type conversion from " << input_type
2232 << " to " << result_type;
2233 }
2234 break;
2235
Roland Levillain981e4542014-11-14 11:47:14 +00002236 case Primitive::kPrimChar:
2237 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002238 case Primitive::kPrimBoolean:
2239 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002240 case Primitive::kPrimByte:
2241 case Primitive::kPrimShort:
2242 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002243 // Processing a Dex `Process a Dex `int-to-char'' instruction.
2244 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002245 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00002246 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002247 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00002248 } else {
2249 DCHECK(in.GetConstant()->IsIntConstant());
2250 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002251 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00002252 }
2253 break;
2254
2255 default:
2256 LOG(FATAL) << "Unexpected type conversion from " << input_type
2257 << " to " << result_type;
2258 }
2259 break;
2260
Roland Levillaindff1f282014-11-05 14:15:05 +00002261 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002262 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002263 case Primitive::kPrimBoolean:
2264 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002265 case Primitive::kPrimByte:
2266 case Primitive::kPrimShort:
2267 case Primitive::kPrimInt:
2268 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002269 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002270 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002271 break;
2272
Roland Levillain6d0e4832014-11-27 18:31:21 +00002273 case Primitive::kPrimLong: {
2274 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002275 size_t adjustment = 0;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002276
Roland Levillain232ade02015-04-20 15:14:36 +01002277 // Create stack space for the call to
2278 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
2279 // TODO: enhance register allocator to ask for stack temporaries.
2280 if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
2281 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2282 __ subl(ESP, Immediate(adjustment));
2283 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002284
Roland Levillain232ade02015-04-20 15:14:36 +01002285 // Load the value to the FP stack, using temporaries if needed.
2286 PushOntoFPStack(in, 0, adjustment, false, true);
2287
2288 if (out.IsStackSlot()) {
2289 __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
2290 } else {
2291 __ fstps(Address(ESP, 0));
2292 Location stack_temp = Location::StackSlot(0);
2293 codegen_->Move32(out, stack_temp);
2294 }
2295
2296 // Remove the temporary stack space we allocated.
2297 if (adjustment != 0) {
2298 __ addl(ESP, Immediate(adjustment));
2299 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002300 break;
2301 }
2302
Roland Levillaincff13742014-11-17 14:32:17 +00002303 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002304 // Processing a Dex `double-to-float' instruction.
2305 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002306 break;
2307
2308 default:
2309 LOG(FATAL) << "Unexpected type conversion from " << input_type
2310 << " to " << result_type;
2311 };
2312 break;
2313
Roland Levillaindff1f282014-11-05 14:15:05 +00002314 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002315 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002316 case Primitive::kPrimBoolean:
2317 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002318 case Primitive::kPrimByte:
2319 case Primitive::kPrimShort:
2320 case Primitive::kPrimInt:
2321 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002322 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002323 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002324 break;
2325
Roland Levillain647b9ed2014-11-27 12:06:00 +00002326 case Primitive::kPrimLong: {
2327 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002328 size_t adjustment = 0;
Roland Levillain647b9ed2014-11-27 12:06:00 +00002329
Roland Levillain232ade02015-04-20 15:14:36 +01002330 // Create stack space for the call to
2331 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
2332 // TODO: enhance register allocator to ask for stack temporaries.
2333 if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
2334 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2335 __ subl(ESP, Immediate(adjustment));
2336 }
2337
2338 // Load the value to the FP stack, using temporaries if needed.
2339 PushOntoFPStack(in, 0, adjustment, false, true);
2340
2341 if (out.IsDoubleStackSlot()) {
2342 __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
2343 } else {
2344 __ fstpl(Address(ESP, 0));
2345 Location stack_temp = Location::DoubleStackSlot(0);
2346 codegen_->Move64(out, stack_temp);
2347 }
2348
2349 // Remove the temporary stack space we allocated.
2350 if (adjustment != 0) {
2351 __ addl(ESP, Immediate(adjustment));
2352 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002353 break;
2354 }
2355
Roland Levillaincff13742014-11-17 14:32:17 +00002356 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002357 // Processing a Dex `float-to-double' instruction.
2358 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002359 break;
2360
2361 default:
2362 LOG(FATAL) << "Unexpected type conversion from " << input_type
2363 << " to " << result_type;
2364 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002365 break;
2366
2367 default:
2368 LOG(FATAL) << "Unexpected type conversion from " << input_type
2369 << " to " << result_type;
2370 }
2371}
2372
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002373void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002374 LocationSummary* locations =
2375 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002376 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002377 case Primitive::kPrimInt: {
2378 locations->SetInAt(0, Location::RequiresRegister());
2379 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2380 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2381 break;
2382 }
2383
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002384 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002385 locations->SetInAt(0, Location::RequiresRegister());
2386 locations->SetInAt(1, Location::Any());
2387 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002388 break;
2389 }
2390
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002391 case Primitive::kPrimFloat:
2392 case Primitive::kPrimDouble: {
2393 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002394 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002395 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002396 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002397 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002398
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002399 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002400 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2401 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002402 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002403}
2404
2405void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
2406 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002407 Location first = locations->InAt(0);
2408 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05002409 Location out = locations->Out();
2410
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002411 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002412 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002413 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002414 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2415 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002416 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2417 __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
Mark Mendell09b84632015-02-13 17:48:38 -05002418 } else {
2419 __ leal(out.AsRegister<Register>(), Address(
2420 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
2421 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002422 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002423 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
2424 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2425 __ addl(out.AsRegister<Register>(), Immediate(value));
2426 } else {
2427 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
2428 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002429 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05002430 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002431 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002432 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002433 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002434 }
2435
2436 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002437 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002438 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2439 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002440 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002441 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
2442 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002443 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002444 } else {
2445 DCHECK(second.IsConstant()) << second;
2446 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2447 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2448 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002449 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002450 break;
2451 }
2452
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002453 case Primitive::kPrimFloat: {
2454 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002455 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002456 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2457 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2458 DCHECK(!const_area->NeedsMaterialization());
2459 __ addss(first.AsFpuRegister<XmmRegister>(),
2460 codegen_->LiteralFloatAddress(
2461 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2462 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2463 } else {
2464 DCHECK(second.IsStackSlot());
2465 __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002466 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002467 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002468 }
2469
2470 case Primitive::kPrimDouble: {
2471 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002472 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002473 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2474 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2475 DCHECK(!const_area->NeedsMaterialization());
2476 __ addsd(first.AsFpuRegister<XmmRegister>(),
2477 codegen_->LiteralDoubleAddress(
2478 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2479 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2480 } else {
2481 DCHECK(second.IsDoubleStackSlot());
2482 __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002483 }
2484 break;
2485 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002486
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002487 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002488 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002489 }
2490}
2491
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002492void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002493 LocationSummary* locations =
2494 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002495 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002496 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002497 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002498 locations->SetInAt(0, Location::RequiresRegister());
2499 locations->SetInAt(1, Location::Any());
2500 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002501 break;
2502 }
Calin Juravle11351682014-10-23 15:38:15 +01002503 case Primitive::kPrimFloat:
2504 case Primitive::kPrimDouble: {
2505 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002506 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002507 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002508 break;
Calin Juravle11351682014-10-23 15:38:15 +01002509 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002510
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002511 default:
Calin Juravle11351682014-10-23 15:38:15 +01002512 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002513 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002514}
2515
2516void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
2517 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002518 Location first = locations->InAt(0);
2519 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01002520 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002521 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002522 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002523 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002524 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002525 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002526 __ subl(first.AsRegister<Register>(),
2527 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002528 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002529 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002530 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002531 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002532 }
2533
2534 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002535 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01002536 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2537 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002538 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01002539 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002540 __ sbbl(first.AsRegisterPairHigh<Register>(),
2541 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002542 } else {
2543 DCHECK(second.IsConstant()) << second;
2544 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2545 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2546 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002547 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002548 break;
2549 }
2550
Calin Juravle11351682014-10-23 15:38:15 +01002551 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002552 if (second.IsFpuRegister()) {
2553 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2554 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2555 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2556 DCHECK(!const_area->NeedsMaterialization());
2557 __ subss(first.AsFpuRegister<XmmRegister>(),
2558 codegen_->LiteralFloatAddress(
2559 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2560 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2561 } else {
2562 DCHECK(second.IsStackSlot());
2563 __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2564 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002565 break;
Calin Juravle11351682014-10-23 15:38:15 +01002566 }
2567
2568 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002569 if (second.IsFpuRegister()) {
2570 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2571 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2572 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2573 DCHECK(!const_area->NeedsMaterialization());
2574 __ subsd(first.AsFpuRegister<XmmRegister>(),
2575 codegen_->LiteralDoubleAddress(
2576 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2577 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2578 } else {
2579 DCHECK(second.IsDoubleStackSlot());
2580 __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2581 }
Calin Juravle11351682014-10-23 15:38:15 +01002582 break;
2583 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002584
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002585 default:
Calin Juravle11351682014-10-23 15:38:15 +01002586 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002587 }
2588}
2589
Calin Juravle34bacdf2014-10-07 20:23:36 +01002590void LocationsBuilderX86::VisitMul(HMul* mul) {
2591 LocationSummary* locations =
2592 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2593 switch (mul->GetResultType()) {
2594 case Primitive::kPrimInt:
2595 locations->SetInAt(0, Location::RequiresRegister());
2596 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002597 if (mul->InputAt(1)->IsIntConstant()) {
2598 // Can use 3 operand multiply.
2599 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2600 } else {
2601 locations->SetOut(Location::SameAsFirstInput());
2602 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002603 break;
2604 case Primitive::kPrimLong: {
2605 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002606 locations->SetInAt(1, Location::Any());
2607 locations->SetOut(Location::SameAsFirstInput());
2608 // Needed for imul on 32bits with 64bits output.
2609 locations->AddTemp(Location::RegisterLocation(EAX));
2610 locations->AddTemp(Location::RegisterLocation(EDX));
2611 break;
2612 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002613 case Primitive::kPrimFloat:
2614 case Primitive::kPrimDouble: {
2615 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002616 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002617 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002618 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002619 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002620
2621 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002622 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002623 }
2624}
2625
2626void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2627 LocationSummary* locations = mul->GetLocations();
2628 Location first = locations->InAt(0);
2629 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002630 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002631
2632 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002633 case Primitive::kPrimInt:
2634 // The constant may have ended up in a register, so test explicitly to avoid
2635 // problems where the output may not be the same as the first operand.
2636 if (mul->InputAt(1)->IsIntConstant()) {
2637 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2638 __ imull(out.AsRegister<Register>(), first.AsRegister<Register>(), imm);
2639 } else if (second.IsRegister()) {
2640 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002641 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002642 } else {
2643 DCHECK(second.IsStackSlot());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002644 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002645 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002646 }
2647 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002648
2649 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002650 Register in1_hi = first.AsRegisterPairHigh<Register>();
2651 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002652 Register eax = locations->GetTemp(0).AsRegister<Register>();
2653 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002654
2655 DCHECK_EQ(EAX, eax);
2656 DCHECK_EQ(EDX, edx);
2657
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002658 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002659 // output: in1
2660 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2661 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2662 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002663 if (second.IsConstant()) {
2664 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002665
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002666 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2667 int32_t low_value = Low32Bits(value);
2668 int32_t high_value = High32Bits(value);
2669 Immediate low(low_value);
2670 Immediate high(high_value);
2671
2672 __ movl(eax, high);
2673 // eax <- in1.lo * in2.hi
2674 __ imull(eax, in1_lo);
2675 // in1.hi <- in1.hi * in2.lo
2676 __ imull(in1_hi, low);
2677 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2678 __ addl(in1_hi, eax);
2679 // move in2_lo to eax to prepare for double precision
2680 __ movl(eax, low);
2681 // edx:eax <- in1.lo * in2.lo
2682 __ mull(in1_lo);
2683 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2684 __ addl(in1_hi, edx);
2685 // in1.lo <- (in1.lo * in2.lo)[31:0];
2686 __ movl(in1_lo, eax);
2687 } else if (second.IsRegisterPair()) {
2688 Register in2_hi = second.AsRegisterPairHigh<Register>();
2689 Register in2_lo = second.AsRegisterPairLow<Register>();
2690
2691 __ movl(eax, in2_hi);
2692 // eax <- in1.lo * in2.hi
2693 __ imull(eax, in1_lo);
2694 // in1.hi <- in1.hi * in2.lo
2695 __ imull(in1_hi, in2_lo);
2696 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2697 __ addl(in1_hi, eax);
2698 // move in1_lo to eax to prepare for double precision
2699 __ movl(eax, in1_lo);
2700 // edx:eax <- in1.lo * in2.lo
2701 __ mull(in2_lo);
2702 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2703 __ addl(in1_hi, edx);
2704 // in1.lo <- (in1.lo * in2.lo)[31:0];
2705 __ movl(in1_lo, eax);
2706 } else {
2707 DCHECK(second.IsDoubleStackSlot()) << second;
2708 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2709 Address in2_lo(ESP, second.GetStackIndex());
2710
2711 __ movl(eax, in2_hi);
2712 // eax <- in1.lo * in2.hi
2713 __ imull(eax, in1_lo);
2714 // in1.hi <- in1.hi * in2.lo
2715 __ imull(in1_hi, in2_lo);
2716 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2717 __ addl(in1_hi, eax);
2718 // move in1_lo to eax to prepare for double precision
2719 __ movl(eax, in1_lo);
2720 // edx:eax <- in1.lo * in2.lo
2721 __ mull(in2_lo);
2722 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2723 __ addl(in1_hi, edx);
2724 // in1.lo <- (in1.lo * in2.lo)[31:0];
2725 __ movl(in1_lo, eax);
2726 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002727
2728 break;
2729 }
2730
Calin Juravleb5bfa962014-10-21 18:02:24 +01002731 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002732 DCHECK(first.Equals(locations->Out()));
2733 if (second.IsFpuRegister()) {
2734 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2735 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2736 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2737 DCHECK(!const_area->NeedsMaterialization());
2738 __ mulss(first.AsFpuRegister<XmmRegister>(),
2739 codegen_->LiteralFloatAddress(
2740 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2741 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2742 } else {
2743 DCHECK(second.IsStackSlot());
2744 __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2745 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002746 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002747 }
2748
2749 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002750 DCHECK(first.Equals(locations->Out()));
2751 if (second.IsFpuRegister()) {
2752 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2753 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2754 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2755 DCHECK(!const_area->NeedsMaterialization());
2756 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2757 codegen_->LiteralDoubleAddress(
2758 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2759 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2760 } else {
2761 DCHECK(second.IsDoubleStackSlot());
2762 __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2763 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002764 break;
2765 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002766
2767 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002768 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002769 }
2770}
2771
Roland Levillain232ade02015-04-20 15:14:36 +01002772void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
2773 uint32_t temp_offset,
2774 uint32_t stack_adjustment,
2775 bool is_fp,
2776 bool is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002777 if (source.IsStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002778 DCHECK(!is_wide);
2779 if (is_fp) {
2780 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2781 } else {
2782 __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2783 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002784 } else if (source.IsDoubleStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002785 DCHECK(is_wide);
2786 if (is_fp) {
2787 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2788 } else {
2789 __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2790 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002791 } else {
2792 // Write the value to the temporary location on the stack and load to FP stack.
Roland Levillain232ade02015-04-20 15:14:36 +01002793 if (!is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002794 Location stack_temp = Location::StackSlot(temp_offset);
2795 codegen_->Move32(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002796 if (is_fp) {
2797 __ flds(Address(ESP, temp_offset));
2798 } else {
2799 __ filds(Address(ESP, temp_offset));
2800 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002801 } else {
2802 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2803 codegen_->Move64(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002804 if (is_fp) {
2805 __ fldl(Address(ESP, temp_offset));
2806 } else {
2807 __ fildl(Address(ESP, temp_offset));
2808 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002809 }
2810 }
2811}
2812
2813void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2814 Primitive::Type type = rem->GetResultType();
2815 bool is_float = type == Primitive::kPrimFloat;
2816 size_t elem_size = Primitive::ComponentSize(type);
2817 LocationSummary* locations = rem->GetLocations();
2818 Location first = locations->InAt(0);
2819 Location second = locations->InAt(1);
2820 Location out = locations->Out();
2821
2822 // Create stack space for 2 elements.
2823 // TODO: enhance register allocator to ask for stack temporaries.
2824 __ subl(ESP, Immediate(2 * elem_size));
2825
2826 // Load the values to the FP stack in reverse order, using temporaries if needed.
Roland Levillain232ade02015-04-20 15:14:36 +01002827 const bool is_wide = !is_float;
2828 PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp */ true, is_wide);
2829 PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp */ true, is_wide);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002830
2831 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002832 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002833 __ Bind(&retry);
2834 __ fprem();
2835
2836 // Move FP status to AX.
2837 __ fstsw();
2838
2839 // And see if the argument reduction is complete. This is signaled by the
2840 // C2 FPU flag bit set to 0.
2841 __ andl(EAX, Immediate(kC2ConditionMask));
2842 __ j(kNotEqual, &retry);
2843
2844 // We have settled on the final value. Retrieve it into an XMM register.
2845 // Store FP top of stack to real stack.
2846 if (is_float) {
2847 __ fsts(Address(ESP, 0));
2848 } else {
2849 __ fstl(Address(ESP, 0));
2850 }
2851
2852 // Pop the 2 items from the FP stack.
2853 __ fucompp();
2854
2855 // Load the value from the stack into an XMM register.
2856 DCHECK(out.IsFpuRegister()) << out;
2857 if (is_float) {
2858 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2859 } else {
2860 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2861 }
2862
2863 // And remove the temporary stack space we allocated.
2864 __ addl(ESP, Immediate(2 * elem_size));
2865}
2866
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002867
2868void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2869 DCHECK(instruction->IsDiv() || instruction->IsRem());
2870
2871 LocationSummary* locations = instruction->GetLocations();
2872 DCHECK(locations->InAt(1).IsConstant());
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002873 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002874
2875 Register out_register = locations->Out().AsRegister<Register>();
2876 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002877 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002878
2879 DCHECK(imm == 1 || imm == -1);
2880
2881 if (instruction->IsRem()) {
2882 __ xorl(out_register, out_register);
2883 } else {
2884 __ movl(out_register, input_register);
2885 if (imm == -1) {
2886 __ negl(out_register);
2887 }
2888 }
2889}
2890
2891
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002892void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002893 LocationSummary* locations = instruction->GetLocations();
2894
2895 Register out_register = locations->Out().AsRegister<Register>();
2896 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002897 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002898
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002899 DCHECK(IsPowerOfTwo(std::abs(imm)));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002900 Register num = locations->GetTemp(0).AsRegister<Register>();
2901
2902 __ leal(num, Address(input_register, std::abs(imm) - 1));
2903 __ testl(input_register, input_register);
2904 __ cmovl(kGreaterEqual, num, input_register);
2905 int shift = CTZ(imm);
2906 __ sarl(num, Immediate(shift));
2907
2908 if (imm < 0) {
2909 __ negl(num);
2910 }
2911
2912 __ movl(out_register, num);
2913}
2914
2915void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2916 DCHECK(instruction->IsDiv() || instruction->IsRem());
2917
2918 LocationSummary* locations = instruction->GetLocations();
2919 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2920
2921 Register eax = locations->InAt(0).AsRegister<Register>();
2922 Register out = locations->Out().AsRegister<Register>();
2923 Register num;
2924 Register edx;
2925
2926 if (instruction->IsDiv()) {
2927 edx = locations->GetTemp(0).AsRegister<Register>();
2928 num = locations->GetTemp(1).AsRegister<Register>();
2929 } else {
2930 edx = locations->Out().AsRegister<Register>();
2931 num = locations->GetTemp(0).AsRegister<Register>();
2932 }
2933
2934 DCHECK_EQ(EAX, eax);
2935 DCHECK_EQ(EDX, edx);
2936 if (instruction->IsDiv()) {
2937 DCHECK_EQ(EAX, out);
2938 } else {
2939 DCHECK_EQ(EDX, out);
2940 }
2941
2942 int64_t magic;
2943 int shift;
2944 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2945
Mark Mendell0c9497d2015-08-21 09:30:05 -04002946 NearLabel ndiv;
2947 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002948 // If numerator is 0, the result is 0, no computation needed.
2949 __ testl(eax, eax);
2950 __ j(kNotEqual, &ndiv);
2951
2952 __ xorl(out, out);
2953 __ jmp(&end);
2954
2955 __ Bind(&ndiv);
2956
2957 // Save the numerator.
2958 __ movl(num, eax);
2959
2960 // EAX = magic
2961 __ movl(eax, Immediate(magic));
2962
2963 // EDX:EAX = magic * numerator
2964 __ imull(num);
2965
2966 if (imm > 0 && magic < 0) {
2967 // EDX += num
2968 __ addl(edx, num);
2969 } else if (imm < 0 && magic > 0) {
2970 __ subl(edx, num);
2971 }
2972
2973 // Shift if needed.
2974 if (shift != 0) {
2975 __ sarl(edx, Immediate(shift));
2976 }
2977
2978 // EDX += 1 if EDX < 0
2979 __ movl(eax, edx);
2980 __ shrl(edx, Immediate(31));
2981 __ addl(edx, eax);
2982
2983 if (instruction->IsRem()) {
2984 __ movl(eax, num);
2985 __ imull(edx, Immediate(imm));
2986 __ subl(eax, edx);
2987 __ movl(edx, eax);
2988 } else {
2989 __ movl(eax, edx);
2990 }
2991 __ Bind(&end);
2992}
2993
Calin Juravlebacfec32014-11-14 15:54:36 +00002994void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2995 DCHECK(instruction->IsDiv() || instruction->IsRem());
2996
2997 LocationSummary* locations = instruction->GetLocations();
2998 Location out = locations->Out();
2999 Location first = locations->InAt(0);
3000 Location second = locations->InAt(1);
3001 bool is_div = instruction->IsDiv();
3002
3003 switch (instruction->GetResultType()) {
3004 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003005 DCHECK_EQ(EAX, first.AsRegister<Register>());
3006 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00003007
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003008 if (instruction->InputAt(1)->IsIntConstant()) {
3009 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003010
3011 if (imm == 0) {
3012 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
3013 } else if (imm == 1 || imm == -1) {
3014 DivRemOneOrMinusOne(instruction);
3015 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003016 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003017 } else {
3018 DCHECK(imm <= -2 || imm >= 2);
3019 GenerateDivRemWithAnyConstant(instruction);
3020 }
3021 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003022 SlowPathCode* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00003023 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003024 is_div);
3025 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00003026
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003027 Register second_reg = second.AsRegister<Register>();
3028 // 0x80000000/-1 triggers an arithmetic exception!
3029 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
3030 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00003031
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003032 __ cmpl(second_reg, Immediate(-1));
3033 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00003034
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003035 // edx:eax <- sign-extended of eax
3036 __ cdq();
3037 // eax = quotient, edx = remainder
3038 __ idivl(second_reg);
3039 __ Bind(slow_path->GetExitLabel());
3040 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003041 break;
3042 }
3043
3044 case Primitive::kPrimLong: {
3045 InvokeRuntimeCallingConvention calling_convention;
3046 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
3047 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
3048 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
3049 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
3050 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
3051 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
3052
3053 if (is_div) {
Alexandre Rames8158f282015-08-07 10:26:17 +01003054 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv),
3055 instruction,
3056 instruction->GetDexPc(),
3057 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00003058 } else {
Alexandre Rames8158f282015-08-07 10:26:17 +01003059 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod),
3060 instruction,
3061 instruction->GetDexPc(),
3062 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00003063 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003064 break;
3065 }
3066
3067 default:
3068 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
3069 }
3070}
3071
Calin Juravle7c4954d2014-10-28 16:57:40 +00003072void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003073 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003074 ? LocationSummary::kCall
3075 : LocationSummary::kNoCall;
3076 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
3077
Calin Juravle7c4954d2014-10-28 16:57:40 +00003078 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00003079 case Primitive::kPrimInt: {
3080 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003081 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00003082 locations->SetOut(Location::SameAsFirstInput());
3083 // Intel uses edx:eax as the dividend.
3084 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003085 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3086 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
3087 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003088 if (div->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003089 locations->AddTemp(Location::RequiresRegister());
3090 }
Calin Juravled0d48522014-11-04 16:40:20 +00003091 break;
3092 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003093 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003094 InvokeRuntimeCallingConvention calling_convention;
3095 locations->SetInAt(0, Location::RegisterPairLocation(
3096 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3097 locations->SetInAt(1, Location::RegisterPairLocation(
3098 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3099 // Runtime helper puts the result in EAX, EDX.
3100 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00003101 break;
3102 }
3103 case Primitive::kPrimFloat:
3104 case Primitive::kPrimDouble: {
3105 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04003106 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00003107 locations->SetOut(Location::SameAsFirstInput());
3108 break;
3109 }
3110
3111 default:
3112 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3113 }
3114}
3115
3116void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
3117 LocationSummary* locations = div->GetLocations();
3118 Location first = locations->InAt(0);
3119 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003120
3121 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003122 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00003123 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00003124 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00003125 break;
3126 }
3127
3128 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003129 if (second.IsFpuRegister()) {
3130 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3131 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3132 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3133 DCHECK(!const_area->NeedsMaterialization());
3134 __ divss(first.AsFpuRegister<XmmRegister>(),
3135 codegen_->LiteralFloatAddress(
3136 const_area->GetConstant()->AsFloatConstant()->GetValue(),
3137 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3138 } else {
3139 DCHECK(second.IsStackSlot());
3140 __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3141 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003142 break;
3143 }
3144
3145 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003146 if (second.IsFpuRegister()) {
3147 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3148 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3149 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3150 DCHECK(!const_area->NeedsMaterialization());
3151 __ divsd(first.AsFpuRegister<XmmRegister>(),
3152 codegen_->LiteralDoubleAddress(
3153 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
3154 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3155 } else {
3156 DCHECK(second.IsDoubleStackSlot());
3157 __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3158 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003159 break;
3160 }
3161
3162 default:
3163 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3164 }
3165}
3166
Calin Juravlebacfec32014-11-14 15:54:36 +00003167void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003168 Primitive::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003169
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003170 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
3171 ? LocationSummary::kCall
3172 : LocationSummary::kNoCall;
3173 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00003174
Calin Juravled2ec87d2014-12-08 14:24:46 +00003175 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003176 case Primitive::kPrimInt: {
3177 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003178 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003179 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003180 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3181 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
3182 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003183 if (rem->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003184 locations->AddTemp(Location::RequiresRegister());
3185 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003186 break;
3187 }
3188 case Primitive::kPrimLong: {
3189 InvokeRuntimeCallingConvention calling_convention;
3190 locations->SetInAt(0, Location::RegisterPairLocation(
3191 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3192 locations->SetInAt(1, Location::RegisterPairLocation(
3193 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3194 // Runtime helper puts the result in EAX, EDX.
3195 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
3196 break;
3197 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003198 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003199 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003200 locations->SetInAt(0, Location::Any());
3201 locations->SetInAt(1, Location::Any());
3202 locations->SetOut(Location::RequiresFpuRegister());
3203 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003204 break;
3205 }
3206
3207 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003208 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003209 }
3210}
3211
3212void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
3213 Primitive::Type type = rem->GetResultType();
3214 switch (type) {
3215 case Primitive::kPrimInt:
3216 case Primitive::kPrimLong: {
3217 GenerateDivRemIntegral(rem);
3218 break;
3219 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003220 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00003221 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003222 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00003223 break;
3224 }
3225 default:
3226 LOG(FATAL) << "Unexpected rem type " << type;
3227 }
3228}
3229
Calin Juravled0d48522014-11-04 16:40:20 +00003230void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003231 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3232 ? LocationSummary::kCallOnSlowPath
3233 : LocationSummary::kNoCall;
3234 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003235 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003236 case Primitive::kPrimByte:
3237 case Primitive::kPrimChar:
3238 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003239 case Primitive::kPrimInt: {
3240 locations->SetInAt(0, Location::Any());
3241 break;
3242 }
3243 case Primitive::kPrimLong: {
3244 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3245 if (!instruction->IsConstant()) {
3246 locations->AddTemp(Location::RequiresRegister());
3247 }
3248 break;
3249 }
3250 default:
3251 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3252 }
Calin Juravled0d48522014-11-04 16:40:20 +00003253 if (instruction->HasUses()) {
3254 locations->SetOut(Location::SameAsFirstInput());
3255 }
3256}
3257
3258void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003259 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003260 codegen_->AddSlowPath(slow_path);
3261
3262 LocationSummary* locations = instruction->GetLocations();
3263 Location value = locations->InAt(0);
3264
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003265 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003266 case Primitive::kPrimByte:
3267 case Primitive::kPrimChar:
3268 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003269 case Primitive::kPrimInt: {
3270 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003271 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003272 __ j(kEqual, slow_path->GetEntryLabel());
3273 } else if (value.IsStackSlot()) {
3274 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
3275 __ j(kEqual, slow_path->GetEntryLabel());
3276 } else {
3277 DCHECK(value.IsConstant()) << value;
3278 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3279 __ jmp(slow_path->GetEntryLabel());
3280 }
3281 }
3282 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003283 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003284 case Primitive::kPrimLong: {
3285 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003286 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003287 __ movl(temp, value.AsRegisterPairLow<Register>());
3288 __ orl(temp, value.AsRegisterPairHigh<Register>());
3289 __ j(kEqual, slow_path->GetEntryLabel());
3290 } else {
3291 DCHECK(value.IsConstant()) << value;
3292 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3293 __ jmp(slow_path->GetEntryLabel());
3294 }
3295 }
3296 break;
3297 }
3298 default:
3299 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003300 }
Calin Juravled0d48522014-11-04 16:40:20 +00003301}
3302
Calin Juravle9aec02f2014-11-18 23:06:35 +00003303void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
3304 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3305
3306 LocationSummary* locations =
3307 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3308
3309 switch (op->GetResultType()) {
Mark P Mendell73945692015-04-29 14:56:17 +00003310 case Primitive::kPrimInt:
Calin Juravle9aec02f2014-11-18 23:06:35 +00003311 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003312 // Can't have Location::Any() and output SameAsFirstInput()
Calin Juravle9aec02f2014-11-18 23:06:35 +00003313 locations->SetInAt(0, Location::RequiresRegister());
Mark P Mendell73945692015-04-29 14:56:17 +00003314 // The shift count needs to be in CL or a constant.
3315 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003316 locations->SetOut(Location::SameAsFirstInput());
3317 break;
3318 }
3319 default:
3320 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3321 }
3322}
3323
3324void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
3325 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3326
3327 LocationSummary* locations = op->GetLocations();
3328 Location first = locations->InAt(0);
3329 Location second = locations->InAt(1);
3330 DCHECK(first.Equals(locations->Out()));
3331
3332 switch (op->GetResultType()) {
3333 case Primitive::kPrimInt: {
Mark P Mendell73945692015-04-29 14:56:17 +00003334 DCHECK(first.IsRegister());
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003335 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003336 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003337 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003338 DCHECK_EQ(ECX, second_reg);
3339 if (op->IsShl()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003340 __ shll(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003341 } else if (op->IsShr()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003342 __ sarl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003343 } else {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003344 __ shrl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003345 }
3346 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003347 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue;
3348 if (shift == 0) {
3349 return;
3350 }
3351 Immediate imm(shift);
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003352 if (op->IsShl()) {
3353 __ shll(first_reg, imm);
3354 } else if (op->IsShr()) {
3355 __ sarl(first_reg, imm);
3356 } else {
3357 __ shrl(first_reg, imm);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003358 }
3359 }
3360 break;
3361 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003362 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003363 if (second.IsRegister()) {
3364 Register second_reg = second.AsRegister<Register>();
3365 DCHECK_EQ(ECX, second_reg);
3366 if (op->IsShl()) {
3367 GenerateShlLong(first, second_reg);
3368 } else if (op->IsShr()) {
3369 GenerateShrLong(first, second_reg);
3370 } else {
3371 GenerateUShrLong(first, second_reg);
3372 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003373 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003374 // Shift by a constant.
3375 int shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue;
3376 // Nothing to do if the shift is 0, as the input is already the output.
3377 if (shift != 0) {
3378 if (op->IsShl()) {
3379 GenerateShlLong(first, shift);
3380 } else if (op->IsShr()) {
3381 GenerateShrLong(first, shift);
3382 } else {
3383 GenerateUShrLong(first, shift);
3384 }
3385 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003386 }
3387 break;
3388 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003389 default:
3390 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3391 }
3392}
3393
Mark P Mendell73945692015-04-29 14:56:17 +00003394void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
3395 Register low = loc.AsRegisterPairLow<Register>();
3396 Register high = loc.AsRegisterPairHigh<Register>();
Mark Mendellba56d062015-05-05 21:34:03 -04003397 if (shift == 1) {
3398 // This is just an addition.
3399 __ addl(low, low);
3400 __ adcl(high, high);
3401 } else if (shift == 32) {
Mark P Mendell73945692015-04-29 14:56:17 +00003402 // Shift by 32 is easy. High gets low, and low gets 0.
3403 codegen_->EmitParallelMoves(
3404 loc.ToLow(),
3405 loc.ToHigh(),
3406 Primitive::kPrimInt,
3407 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3408 loc.ToLow(),
3409 Primitive::kPrimInt);
3410 } else if (shift > 32) {
3411 // Low part becomes 0. High part is low part << (shift-32).
3412 __ movl(high, low);
3413 __ shll(high, Immediate(shift - 32));
3414 __ xorl(low, low);
3415 } else {
3416 // Between 1 and 31.
3417 __ shld(high, low, Immediate(shift));
3418 __ shll(low, Immediate(shift));
3419 }
3420}
3421
Calin Juravle9aec02f2014-11-18 23:06:35 +00003422void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003423 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003424 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
3425 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
3426 __ testl(shifter, Immediate(32));
3427 __ j(kEqual, &done);
3428 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
3429 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
3430 __ Bind(&done);
3431}
3432
Mark P Mendell73945692015-04-29 14:56:17 +00003433void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
3434 Register low = loc.AsRegisterPairLow<Register>();
3435 Register high = loc.AsRegisterPairHigh<Register>();
3436 if (shift == 32) {
3437 // Need to copy the sign.
3438 DCHECK_NE(low, high);
3439 __ movl(low, high);
3440 __ sarl(high, Immediate(31));
3441 } else if (shift > 32) {
3442 DCHECK_NE(low, high);
3443 // High part becomes sign. Low part is shifted by shift - 32.
3444 __ movl(low, high);
3445 __ sarl(high, Immediate(31));
3446 __ sarl(low, Immediate(shift - 32));
3447 } else {
3448 // Between 1 and 31.
3449 __ shrd(low, high, Immediate(shift));
3450 __ sarl(high, Immediate(shift));
3451 }
3452}
3453
Calin Juravle9aec02f2014-11-18 23:06:35 +00003454void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003455 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003456 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3457 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
3458 __ testl(shifter, Immediate(32));
3459 __ j(kEqual, &done);
3460 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3461 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
3462 __ Bind(&done);
3463}
3464
Mark P Mendell73945692015-04-29 14:56:17 +00003465void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
3466 Register low = loc.AsRegisterPairLow<Register>();
3467 Register high = loc.AsRegisterPairHigh<Register>();
3468 if (shift == 32) {
3469 // Shift by 32 is easy. Low gets high, and high gets 0.
3470 codegen_->EmitParallelMoves(
3471 loc.ToHigh(),
3472 loc.ToLow(),
3473 Primitive::kPrimInt,
3474 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3475 loc.ToHigh(),
3476 Primitive::kPrimInt);
3477 } else if (shift > 32) {
3478 // Low part is high >> (shift - 32). High part becomes 0.
3479 __ movl(low, high);
3480 __ shrl(low, Immediate(shift - 32));
3481 __ xorl(high, high);
3482 } else {
3483 // Between 1 and 31.
3484 __ shrd(low, high, Immediate(shift));
3485 __ shrl(high, Immediate(shift));
3486 }
3487}
3488
Calin Juravle9aec02f2014-11-18 23:06:35 +00003489void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003490 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003491 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3492 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
3493 __ testl(shifter, Immediate(32));
3494 __ j(kEqual, &done);
3495 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3496 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
3497 __ Bind(&done);
3498}
3499
3500void LocationsBuilderX86::VisitShl(HShl* shl) {
3501 HandleShift(shl);
3502}
3503
3504void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
3505 HandleShift(shl);
3506}
3507
3508void LocationsBuilderX86::VisitShr(HShr* shr) {
3509 HandleShift(shr);
3510}
3511
3512void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
3513 HandleShift(shr);
3514}
3515
3516void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
3517 HandleShift(ushr);
3518}
3519
3520void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
3521 HandleShift(ushr);
3522}
3523
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003524void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003525 LocationSummary* locations =
3526 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003527 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003528 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003529 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003530 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003531}
3532
3533void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
3534 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003535 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01003536 // Note: if heap poisoning is enabled, the entry point takes cares
3537 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003538 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3539 instruction,
3540 instruction->GetDexPc(),
3541 nullptr);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003542 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003543}
3544
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003545void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
3546 LocationSummary* locations =
3547 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3548 locations->SetOut(Location::RegisterLocation(EAX));
3549 InvokeRuntimeCallingConvention calling_convention;
3550 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003551 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003552 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003553}
3554
3555void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
3556 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003557 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
3558
Roland Levillain4d027112015-07-01 15:41:14 +01003559 // Note: if heap poisoning is enabled, the entry point takes cares
3560 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003561 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3562 instruction,
3563 instruction->GetDexPc(),
3564 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003565 DCHECK(!codegen_->IsLeafMethod());
3566}
3567
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003568void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003569 LocationSummary* locations =
3570 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003571 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3572 if (location.IsStackSlot()) {
3573 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3574 } else if (location.IsDoubleStackSlot()) {
3575 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003576 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003577 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003578}
3579
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003580void InstructionCodeGeneratorX86::VisitParameterValue(
3581 HParameterValue* instruction ATTRIBUTE_UNUSED) {
3582}
3583
3584void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
3585 LocationSummary* locations =
3586 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3587 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3588}
3589
3590void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003591}
3592
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003593void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003594 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003595 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003596 locations->SetInAt(0, Location::RequiresRegister());
3597 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003598}
3599
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003600void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
3601 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01003602 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003603 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01003604 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003605 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003606 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003607 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003608 break;
3609
3610 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003611 __ notl(out.AsRegisterPairLow<Register>());
3612 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003613 break;
3614
3615 default:
3616 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3617 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003618}
3619
David Brazdil66d126e2015-04-03 16:02:44 +01003620void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
3621 LocationSummary* locations =
3622 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3623 locations->SetInAt(0, Location::RequiresRegister());
3624 locations->SetOut(Location::SameAsFirstInput());
3625}
3626
3627void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003628 LocationSummary* locations = bool_not->GetLocations();
3629 Location in = locations->InAt(0);
3630 Location out = locations->Out();
3631 DCHECK(in.Equals(out));
3632 __ xorl(out.AsRegister<Register>(), Immediate(1));
3633}
3634
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003635void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003636 LocationSummary* locations =
3637 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003638 switch (compare->InputAt(0)->GetType()) {
3639 case Primitive::kPrimLong: {
3640 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00003641 locations->SetInAt(1, Location::Any());
3642 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3643 break;
3644 }
3645 case Primitive::kPrimFloat:
3646 case Primitive::kPrimDouble: {
3647 locations->SetInAt(0, Location::RequiresFpuRegister());
3648 locations->SetInAt(1, Location::RequiresFpuRegister());
3649 locations->SetOut(Location::RequiresRegister());
3650 break;
3651 }
3652 default:
3653 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3654 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003655}
3656
3657void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003658 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003659 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003660 Location left = locations->InAt(0);
3661 Location right = locations->InAt(1);
3662
Mark Mendell0c9497d2015-08-21 09:30:05 -04003663 NearLabel less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003664 switch (compare->InputAt(0)->GetType()) {
3665 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003666 Register left_low = left.AsRegisterPairLow<Register>();
3667 Register left_high = left.AsRegisterPairHigh<Register>();
3668 int32_t val_low = 0;
3669 int32_t val_high = 0;
3670 bool right_is_const = false;
3671
3672 if (right.IsConstant()) {
3673 DCHECK(right.GetConstant()->IsLongConstant());
3674 right_is_const = true;
3675 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
3676 val_low = Low32Bits(val);
3677 val_high = High32Bits(val);
3678 }
3679
Calin Juravleddb7df22014-11-25 20:56:51 +00003680 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003681 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003682 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003683 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003684 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003685 DCHECK(right_is_const) << right;
3686 if (val_high == 0) {
3687 __ testl(left_high, left_high);
3688 } else {
3689 __ cmpl(left_high, Immediate(val_high));
3690 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003691 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003692 __ j(kLess, &less); // Signed compare.
3693 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003694 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003695 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003696 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003697 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003698 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003699 DCHECK(right_is_const) << right;
3700 if (val_low == 0) {
3701 __ testl(left_low, left_low);
3702 } else {
3703 __ cmpl(left_low, Immediate(val_low));
3704 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003705 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003706 break;
3707 }
3708 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003709 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003710 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
3711 break;
3712 }
3713 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003714 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003715 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003716 break;
3717 }
3718 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003719 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003720 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003721 __ movl(out, Immediate(0));
3722 __ j(kEqual, &done);
3723 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
3724
3725 __ Bind(&greater);
3726 __ movl(out, Immediate(1));
3727 __ jmp(&done);
3728
3729 __ Bind(&less);
3730 __ movl(out, Immediate(-1));
3731
3732 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003733}
3734
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003735void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003736 LocationSummary* locations =
3737 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003738 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3739 locations->SetInAt(i, Location::Any());
3740 }
3741 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003742}
3743
3744void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003745 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003746 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003747}
3748
Calin Juravle52c48962014-12-16 17:02:57 +00003749void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
3750 /*
3751 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3752 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3753 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3754 */
3755 switch (kind) {
3756 case MemBarrierKind::kAnyAny: {
3757 __ mfence();
3758 break;
3759 }
3760 case MemBarrierKind::kAnyStore:
3761 case MemBarrierKind::kLoadAny:
3762 case MemBarrierKind::kStoreStore: {
3763 // nop
3764 break;
3765 }
3766 default:
3767 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003768 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003769}
3770
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003771
Vladimir Marko58155012015-08-19 12:49:41 +00003772void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
3773 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
3774 switch (invoke->GetMethodLoadKind()) {
3775 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
3776 // temp = thread->string_init_entrypoint
3777 __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(invoke->GetStringInitOffset()));
3778 break;
3779 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
3780 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3781 break;
3782 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
3783 __ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress()));
3784 break;
3785 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
3786 __ movl(temp.AsRegister<Register>(), Immediate(0)); // Placeholder.
3787 method_patches_.emplace_back(invoke->GetTargetMethod());
3788 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
3789 break;
3790 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
3791 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
3792 FALLTHROUGH_INTENDED;
3793 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
3794 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3795 Register method_reg;
3796 Register reg = temp.AsRegister<Register>();
3797 if (current_method.IsRegister()) {
3798 method_reg = current_method.AsRegister<Register>();
3799 } else {
3800 DCHECK(IsBaseline() || invoke->GetLocations()->Intrinsified());
3801 DCHECK(!current_method.IsValid());
3802 method_reg = reg;
3803 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
3804 }
3805 // temp = temp->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +01003806 __ movl(reg, Address(method_reg,
3807 ArtMethod::DexCacheResolvedMethodsOffset(kX86PointerSize).Int32Value()));
Vladimir Marko58155012015-08-19 12:49:41 +00003808 // temp = temp[index_in_cache]
3809 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
3810 __ movl(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
3811 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +01003812 }
Vladimir Marko58155012015-08-19 12:49:41 +00003813 }
3814
3815 switch (invoke->GetCodePtrLocation()) {
3816 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
3817 __ call(GetFrameEntryLabel());
3818 break;
3819 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
3820 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
3821 Label* label = &relative_call_patches_.back().label;
3822 __ call(label); // Bind to the patch label, override at link time.
3823 __ Bind(label); // Bind the label at the end of the "call" insn.
3824 break;
3825 }
3826 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
3827 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
3828 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
3829 // (Though the direct CALL ptr16:32 is available for consideration).
3830 FALLTHROUGH_INTENDED;
3831 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
3832 // (callee_method + offset_of_quick_compiled_code)()
3833 __ call(Address(callee_method.AsRegister<Register>(),
3834 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
3835 kX86WordSize).Int32Value()));
3836 break;
Mark Mendell09ed1a32015-03-25 08:30:06 -04003837 }
3838
3839 DCHECK(!IsLeafMethod());
Mark Mendell09ed1a32015-03-25 08:30:06 -04003840}
3841
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003842void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
3843 Register temp = temp_in.AsRegister<Register>();
3844 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
3845 invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
3846 LocationSummary* locations = invoke->GetLocations();
3847 Location receiver = locations->InAt(0);
3848 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3849 // temp = object->GetClass();
3850 DCHECK(receiver.IsRegister());
3851 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
3852 MaybeRecordImplicitNullCheck(invoke);
3853 __ MaybeUnpoisonHeapReference(temp);
3854 // temp = temp->GetMethodAt(method_offset);
3855 __ movl(temp, Address(temp, method_offset));
3856 // call temp->GetEntryPoint();
3857 __ call(Address(
3858 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3859}
3860
Vladimir Marko58155012015-08-19 12:49:41 +00003861void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
3862 DCHECK(linker_patches->empty());
3863 linker_patches->reserve(method_patches_.size() + relative_call_patches_.size());
3864 for (const MethodPatchInfo<Label>& info : method_patches_) {
3865 // The label points to the end of the "movl" insn but the literal offset for method
3866 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3867 uint32_t literal_offset = info.label.Position() - 4;
3868 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
3869 info.target_method.dex_file,
3870 info.target_method.dex_method_index));
3871 }
3872 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
3873 // The label points to the end of the "call" insn but the literal offset for method
3874 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3875 uint32_t literal_offset = info.label.Position() - 4;
3876 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
3877 info.target_method.dex_file,
3878 info.target_method.dex_method_index));
3879 }
3880}
3881
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003882void CodeGeneratorX86::MarkGCCard(Register temp,
3883 Register card,
3884 Register object,
3885 Register value,
3886 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003887 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003888 if (value_can_be_null) {
3889 __ testl(value, value);
3890 __ j(kEqual, &is_null);
3891 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003892 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3893 __ movl(temp, object);
3894 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003895 __ movb(Address(temp, card, TIMES_1, 0),
3896 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003897 if (value_can_be_null) {
3898 __ Bind(&is_null);
3899 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003900}
3901
Calin Juravle52c48962014-12-16 17:02:57 +00003902void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3903 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003904 LocationSummary* locations =
3905 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003906 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003907
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003908 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3909 locations->SetOut(Location::RequiresFpuRegister());
3910 } else {
3911 // The output overlaps in case of long: we don't want the low move to overwrite
3912 // the object's location.
3913 locations->SetOut(Location::RequiresRegister(),
3914 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3915 : Location::kNoOutputOverlap);
3916 }
Calin Juravle52c48962014-12-16 17:02:57 +00003917
3918 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3919 // Long values can be loaded atomically into an XMM using movsd.
3920 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3921 // and then copy the XMM into the output 32bits at a time).
3922 locations->AddTemp(Location::RequiresFpuRegister());
3923 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003924}
3925
Calin Juravle52c48962014-12-16 17:02:57 +00003926void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3927 const FieldInfo& field_info) {
3928 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003929
Calin Juravle52c48962014-12-16 17:02:57 +00003930 LocationSummary* locations = instruction->GetLocations();
3931 Register base = locations->InAt(0).AsRegister<Register>();
3932 Location out = locations->Out();
3933 bool is_volatile = field_info.IsVolatile();
3934 Primitive::Type field_type = field_info.GetFieldType();
3935 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3936
3937 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003938 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003939 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003940 break;
3941 }
3942
3943 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003944 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003945 break;
3946 }
3947
3948 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003949 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003950 break;
3951 }
3952
3953 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003954 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003955 break;
3956 }
3957
3958 case Primitive::kPrimInt:
3959 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003960 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003961 break;
3962 }
3963
3964 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00003965 if (is_volatile) {
3966 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3967 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003968 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003969 __ movd(out.AsRegisterPairLow<Register>(), temp);
3970 __ psrlq(temp, Immediate(32));
3971 __ movd(out.AsRegisterPairHigh<Register>(), temp);
3972 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003973 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003974 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003975 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003976 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
3977 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003978 break;
3979 }
3980
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003981 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003982 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003983 break;
3984 }
3985
3986 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003987 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003988 break;
3989 }
3990
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003991 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003992 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003993 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003994 }
Calin Juravle52c48962014-12-16 17:02:57 +00003995
Calin Juravle77520bc2015-01-12 18:45:46 +00003996 // Longs are handled in the switch.
3997 if (field_type != Primitive::kPrimLong) {
3998 codegen_->MaybeRecordImplicitNullCheck(instruction);
3999 }
4000
Calin Juravle52c48962014-12-16 17:02:57 +00004001 if (is_volatile) {
4002 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
4003 }
Roland Levillain4d027112015-07-01 15:41:14 +01004004
4005 if (field_type == Primitive::kPrimNot) {
4006 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
4007 }
Calin Juravle52c48962014-12-16 17:02:57 +00004008}
4009
4010void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
4011 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4012
4013 LocationSummary* locations =
4014 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4015 locations->SetInAt(0, Location::RequiresRegister());
4016 bool is_volatile = field_info.IsVolatile();
4017 Primitive::Type field_type = field_info.GetFieldType();
4018 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
4019 || (field_type == Primitive::kPrimByte);
4020
4021 // The register allocator does not support multiple
4022 // inputs that die at entry with one in a specific register.
4023 if (is_byte_type) {
4024 // Ensure the value is in a byte register.
4025 locations->SetInAt(1, Location::RegisterLocation(EAX));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004026 } else if (Primitive::IsFloatingPointType(field_type)) {
4027 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00004028 } else {
4029 locations->SetInAt(1, Location::RequiresRegister());
4030 }
Calin Juravle52c48962014-12-16 17:02:57 +00004031 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Roland Levillain4d027112015-07-01 15:41:14 +01004032 // Temporary registers for the write barrier.
4033 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Calin Juravle52c48962014-12-16 17:02:57 +00004034 // Ensure the card is in a byte register.
4035 locations->AddTemp(Location::RegisterLocation(ECX));
4036 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
4037 // 64bits value can be atomically written to an address with movsd and an XMM register.
4038 // We need two XMM registers because there's no easier way to (bit) copy a register pair
4039 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
4040 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
4041 // isolated cases when we need this it isn't worth adding the extra complexity.
4042 locations->AddTemp(Location::RequiresFpuRegister());
4043 locations->AddTemp(Location::RequiresFpuRegister());
4044 }
4045}
4046
4047void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004048 const FieldInfo& field_info,
4049 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00004050 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
4051
4052 LocationSummary* locations = instruction->GetLocations();
4053 Register base = locations->InAt(0).AsRegister<Register>();
4054 Location value = locations->InAt(1);
4055 bool is_volatile = field_info.IsVolatile();
4056 Primitive::Type field_type = field_info.GetFieldType();
4057 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01004058 bool needs_write_barrier =
4059 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00004060
4061 if (is_volatile) {
4062 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
4063 }
4064
4065 switch (field_type) {
4066 case Primitive::kPrimBoolean:
4067 case Primitive::kPrimByte: {
4068 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
4069 break;
4070 }
4071
4072 case Primitive::kPrimShort:
4073 case Primitive::kPrimChar: {
4074 __ movw(Address(base, offset), value.AsRegister<Register>());
4075 break;
4076 }
4077
4078 case Primitive::kPrimInt:
4079 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01004080 if (kPoisonHeapReferences && needs_write_barrier) {
4081 // Note that in the case where `value` is a null reference,
4082 // we do not enter this block, as the reference does not
4083 // need poisoning.
4084 DCHECK_EQ(field_type, Primitive::kPrimNot);
4085 Register temp = locations->GetTemp(0).AsRegister<Register>();
4086 __ movl(temp, value.AsRegister<Register>());
4087 __ PoisonHeapReference(temp);
4088 __ movl(Address(base, offset), temp);
4089 } else {
4090 __ movl(Address(base, offset), value.AsRegister<Register>());
4091 }
Calin Juravle52c48962014-12-16 17:02:57 +00004092 break;
4093 }
4094
4095 case Primitive::kPrimLong: {
4096 if (is_volatile) {
4097 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
4098 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
4099 __ movd(temp1, value.AsRegisterPairLow<Register>());
4100 __ movd(temp2, value.AsRegisterPairHigh<Register>());
4101 __ punpckldq(temp1, temp2);
4102 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00004103 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004104 } else {
4105 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004106 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00004107 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
4108 }
4109 break;
4110 }
4111
4112 case Primitive::kPrimFloat: {
4113 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4114 break;
4115 }
4116
4117 case Primitive::kPrimDouble: {
4118 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
4119 break;
4120 }
4121
4122 case Primitive::kPrimVoid:
4123 LOG(FATAL) << "Unreachable type " << field_type;
4124 UNREACHABLE();
4125 }
4126
Calin Juravle77520bc2015-01-12 18:45:46 +00004127 // Longs are handled in the switch.
4128 if (field_type != Primitive::kPrimLong) {
4129 codegen_->MaybeRecordImplicitNullCheck(instruction);
4130 }
4131
Roland Levillain4d027112015-07-01 15:41:14 +01004132 if (needs_write_barrier) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004133 Register temp = locations->GetTemp(0).AsRegister<Register>();
4134 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004135 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004136 }
4137
Calin Juravle52c48962014-12-16 17:02:57 +00004138 if (is_volatile) {
4139 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4140 }
4141}
4142
4143void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4144 HandleFieldGet(instruction, instruction->GetFieldInfo());
4145}
4146
4147void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4148 HandleFieldGet(instruction, instruction->GetFieldInfo());
4149}
4150
4151void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4152 HandleFieldSet(instruction, instruction->GetFieldInfo());
4153}
4154
4155void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004156 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004157}
4158
4159void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4160 HandleFieldSet(instruction, instruction->GetFieldInfo());
4161}
4162
4163void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004164 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004165}
4166
4167void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4168 HandleFieldGet(instruction, instruction->GetFieldInfo());
4169}
4170
4171void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4172 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004173}
4174
Calin Juravlee460d1d2015-09-29 04:52:17 +01004175void LocationsBuilderX86::VisitUnresolvedInstanceFieldGet(
4176 HUnresolvedInstanceFieldGet* instruction) {
4177 FieldAccessCallingConventionX86 calling_convention;
4178 codegen_->CreateUnresolvedFieldLocationSummary(
4179 instruction, instruction->GetFieldType(), calling_convention);
4180}
4181
4182void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldGet(
4183 HUnresolvedInstanceFieldGet* instruction) {
4184 FieldAccessCallingConventionX86 calling_convention;
4185 codegen_->GenerateUnresolvedFieldAccess(instruction,
4186 instruction->GetFieldType(),
4187 instruction->GetFieldIndex(),
4188 instruction->GetDexPc(),
4189 calling_convention);
4190}
4191
4192void LocationsBuilderX86::VisitUnresolvedInstanceFieldSet(
4193 HUnresolvedInstanceFieldSet* instruction) {
4194 FieldAccessCallingConventionX86 calling_convention;
4195 codegen_->CreateUnresolvedFieldLocationSummary(
4196 instruction, instruction->GetFieldType(), calling_convention);
4197}
4198
4199void InstructionCodeGeneratorX86::VisitUnresolvedInstanceFieldSet(
4200 HUnresolvedInstanceFieldSet* instruction) {
4201 FieldAccessCallingConventionX86 calling_convention;
4202 codegen_->GenerateUnresolvedFieldAccess(instruction,
4203 instruction->GetFieldType(),
4204 instruction->GetFieldIndex(),
4205 instruction->GetDexPc(),
4206 calling_convention);
4207}
4208
4209void LocationsBuilderX86::VisitUnresolvedStaticFieldGet(
4210 HUnresolvedStaticFieldGet* instruction) {
4211 FieldAccessCallingConventionX86 calling_convention;
4212 codegen_->CreateUnresolvedFieldLocationSummary(
4213 instruction, instruction->GetFieldType(), calling_convention);
4214}
4215
4216void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldGet(
4217 HUnresolvedStaticFieldGet* instruction) {
4218 FieldAccessCallingConventionX86 calling_convention;
4219 codegen_->GenerateUnresolvedFieldAccess(instruction,
4220 instruction->GetFieldType(),
4221 instruction->GetFieldIndex(),
4222 instruction->GetDexPc(),
4223 calling_convention);
4224}
4225
4226void LocationsBuilderX86::VisitUnresolvedStaticFieldSet(
4227 HUnresolvedStaticFieldSet* instruction) {
4228 FieldAccessCallingConventionX86 calling_convention;
4229 codegen_->CreateUnresolvedFieldLocationSummary(
4230 instruction, instruction->GetFieldType(), calling_convention);
4231}
4232
4233void InstructionCodeGeneratorX86::VisitUnresolvedStaticFieldSet(
4234 HUnresolvedStaticFieldSet* instruction) {
4235 FieldAccessCallingConventionX86 calling_convention;
4236 codegen_->GenerateUnresolvedFieldAccess(instruction,
4237 instruction->GetFieldType(),
4238 instruction->GetFieldIndex(),
4239 instruction->GetDexPc(),
4240 calling_convention);
4241}
4242
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004243void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004244 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4245 ? LocationSummary::kCallOnSlowPath
4246 : LocationSummary::kNoCall;
4247 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4248 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004249 ? Location::RequiresRegister()
4250 : Location::Any();
4251 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004252 if (instruction->HasUses()) {
4253 locations->SetOut(Location::SameAsFirstInput());
4254 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004255}
4256
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004257void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004258 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4259 return;
4260 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004261 LocationSummary* locations = instruction->GetLocations();
4262 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004263
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004264 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
4265 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4266}
4267
4268void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004269 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004270 codegen_->AddSlowPath(slow_path);
4271
4272 LocationSummary* locations = instruction->GetLocations();
4273 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004274
4275 if (obj.IsRegister()) {
Mark Mendell42514f62015-03-31 11:34:22 -04004276 __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004277 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004278 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004279 } else {
4280 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004281 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004282 __ jmp(slow_path->GetEntryLabel());
4283 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004284 }
4285 __ j(kEqual, slow_path->GetEntryLabel());
4286}
4287
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004288void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004289 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004290 GenerateImplicitNullCheck(instruction);
4291 } else {
4292 GenerateExplicitNullCheck(instruction);
4293 }
4294}
4295
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004296void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004297 LocationSummary* locations =
4298 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004299 locations->SetInAt(0, Location::RequiresRegister());
4300 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004301 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4302 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4303 } else {
4304 // The output overlaps in case of long: we don't want the low move to overwrite
4305 // the array's location.
4306 locations->SetOut(Location::RequiresRegister(),
4307 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
4308 : Location::kNoOutputOverlap);
4309 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004310}
4311
4312void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
4313 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004314 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004315 Location index = locations->InAt(1);
4316
Calin Juravle77520bc2015-01-12 18:45:46 +00004317 Primitive::Type type = instruction->GetType();
4318 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004319 case Primitive::kPrimBoolean: {
4320 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004321 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004322 if (index.IsConstant()) {
4323 __ movzxb(out, Address(obj,
4324 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4325 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004326 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004327 }
4328 break;
4329 }
4330
4331 case Primitive::kPrimByte: {
4332 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004333 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004334 if (index.IsConstant()) {
4335 __ movsxb(out, Address(obj,
4336 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4337 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004338 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004339 }
4340 break;
4341 }
4342
4343 case Primitive::kPrimShort: {
4344 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004345 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004346 if (index.IsConstant()) {
4347 __ movsxw(out, Address(obj,
4348 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4349 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004350 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004351 }
4352 break;
4353 }
4354
4355 case Primitive::kPrimChar: {
4356 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004357 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004358 if (index.IsConstant()) {
4359 __ movzxw(out, Address(obj,
4360 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4361 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004362 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004363 }
4364 break;
4365 }
4366
4367 case Primitive::kPrimInt:
4368 case Primitive::kPrimNot: {
4369 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004370 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004371 if (index.IsConstant()) {
4372 __ movl(out, Address(obj,
4373 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4374 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004375 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004376 }
4377 break;
4378 }
4379
4380 case Primitive::kPrimLong: {
4381 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004382 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004383 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004384 if (index.IsConstant()) {
4385 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004386 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004387 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004388 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004389 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004390 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004391 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004392 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004393 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004394 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004395 }
4396 break;
4397 }
4398
Mark Mendell7c8d0092015-01-26 11:21:33 -05004399 case Primitive::kPrimFloat: {
4400 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4401 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4402 if (index.IsConstant()) {
4403 __ movss(out, Address(obj,
4404 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4405 } else {
4406 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
4407 }
4408 break;
4409 }
4410
4411 case Primitive::kPrimDouble: {
4412 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4413 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4414 if (index.IsConstant()) {
4415 __ movsd(out, Address(obj,
4416 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4417 } else {
4418 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
4419 }
4420 break;
4421 }
4422
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004423 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00004424 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004425 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004426 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004427
4428 if (type != Primitive::kPrimLong) {
4429 codegen_->MaybeRecordImplicitNullCheck(instruction);
4430 }
Roland Levillain4d027112015-07-01 15:41:14 +01004431
4432 if (type == Primitive::kPrimNot) {
4433 Register out = locations->Out().AsRegister<Register>();
4434 __ MaybeUnpoisonHeapReference(out);
4435 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004436}
4437
4438void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05004439 // This location builder might end up asking to up to four registers, which is
4440 // not currently possible for baseline. The situation in which we need four
4441 // registers cannot be met by baseline though, because it has not run any
4442 // optimization.
4443
Nicolas Geoffray39468442014-09-02 15:17:15 +01004444 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004445 bool needs_write_barrier =
4446 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4447
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004448 bool may_need_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004449
Nicolas Geoffray39468442014-09-02 15:17:15 +01004450 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4451 instruction,
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004452 may_need_runtime_call ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004453
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004454 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
4455 || (value_type == Primitive::kPrimByte);
4456 // We need the inputs to be different than the output in case of long operation.
4457 // In case of a byte operation, the register allocator does not support multiple
4458 // inputs that die at entry with one in a specific register.
4459 locations->SetInAt(0, Location::RequiresRegister());
4460 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
4461 if (is_byte_type) {
4462 // Ensure the value is in a byte register.
4463 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
4464 } else if (Primitive::IsFloatingPointType(value_type)) {
4465 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004466 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004467 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
4468 }
4469 if (needs_write_barrier) {
4470 // Temporary registers for the write barrier.
4471 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
4472 // Ensure the card is in a byte register.
4473 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004474 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004475}
4476
4477void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
4478 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004479 Register array = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004480 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004481 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004482 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004483 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4484 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
4485 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
4486 bool may_need_runtime_call = locations->CanCall();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004487 bool needs_write_barrier =
4488 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004489
4490 switch (value_type) {
4491 case Primitive::kPrimBoolean:
4492 case Primitive::kPrimByte: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004493 uint32_t offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
4494 Address address = index.IsConstant()
4495 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + offset)
4496 : Address(array, index.AsRegister<Register>(), TIMES_1, offset);
4497 if (value.IsRegister()) {
4498 __ movb(address, value.AsRegister<ByteRegister>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004499 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004500 __ movb(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004501 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004502 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004503 break;
4504 }
4505
4506 case Primitive::kPrimShort:
4507 case Primitive::kPrimChar: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004508 uint32_t offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
4509 Address address = index.IsConstant()
4510 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + offset)
4511 : Address(array, index.AsRegister<Register>(), TIMES_2, offset);
4512 if (value.IsRegister()) {
4513 __ movw(address, value.AsRegister<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004514 } else {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004515 __ movw(address, Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004516 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004517 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004518 break;
4519 }
4520
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004521 case Primitive::kPrimNot: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004522 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4523 Address address = index.IsConstant()
4524 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4525 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
4526 if (!value.IsRegister()) {
4527 // Just setting null.
4528 DCHECK(instruction->InputAt(2)->IsNullConstant());
4529 DCHECK(value.IsConstant()) << value;
4530 __ movl(address, Immediate(0));
Calin Juravle77520bc2015-01-12 18:45:46 +00004531 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004532 DCHECK(!needs_write_barrier);
4533 DCHECK(!may_need_runtime_call);
4534 break;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004535 }
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004536
4537 DCHECK(needs_write_barrier);
4538 Register register_value = value.AsRegister<Register>();
4539 NearLabel done, not_null, do_put;
4540 SlowPathCode* slow_path = nullptr;
4541 Register temp = locations->GetTemp(0).AsRegister<Register>();
4542 if (may_need_runtime_call) {
4543 slow_path = new (GetGraph()->GetArena()) ArraySetSlowPathX86(instruction);
4544 codegen_->AddSlowPath(slow_path);
4545 if (instruction->GetValueCanBeNull()) {
4546 __ testl(register_value, register_value);
4547 __ j(kNotEqual, &not_null);
4548 __ movl(address, Immediate(0));
4549 codegen_->MaybeRecordImplicitNullCheck(instruction);
4550 __ jmp(&done);
4551 __ Bind(&not_null);
4552 }
4553
4554 __ movl(temp, Address(array, class_offset));
4555 codegen_->MaybeRecordImplicitNullCheck(instruction);
4556 __ MaybeUnpoisonHeapReference(temp);
4557 __ movl(temp, Address(temp, component_offset));
4558 // No need to poison/unpoison, we're comparing two poisoned references.
4559 __ cmpl(temp, Address(register_value, class_offset));
4560 if (instruction->StaticTypeOfArrayIsObjectArray()) {
4561 __ j(kEqual, &do_put);
4562 __ MaybeUnpoisonHeapReference(temp);
4563 __ movl(temp, Address(temp, super_offset));
4564 // No need to unpoison, we're comparing against null..
4565 __ testl(temp, temp);
4566 __ j(kNotEqual, slow_path->GetEntryLabel());
4567 __ Bind(&do_put);
4568 } else {
4569 __ j(kNotEqual, slow_path->GetEntryLabel());
4570 }
4571 }
4572
4573 if (kPoisonHeapReferences) {
4574 __ movl(temp, register_value);
4575 __ PoisonHeapReference(temp);
4576 __ movl(address, temp);
4577 } else {
4578 __ movl(address, register_value);
4579 }
4580 if (!may_need_runtime_call) {
4581 codegen_->MaybeRecordImplicitNullCheck(instruction);
4582 }
4583
4584 Register card = locations->GetTemp(1).AsRegister<Register>();
4585 codegen_->MarkGCCard(
4586 temp, card, array, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
4587 __ Bind(&done);
4588
4589 if (slow_path != nullptr) {
4590 __ Bind(slow_path->GetExitLabel());
4591 }
4592
4593 break;
4594 }
4595 case Primitive::kPrimInt: {
4596 uint32_t offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4597 Address address = index.IsConstant()
4598 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4599 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
4600 if (value.IsRegister()) {
4601 __ movl(address, value.AsRegister<Register>());
4602 } else {
4603 DCHECK(value.IsConstant()) << value;
4604 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4605 __ movl(address, Immediate(v));
4606 }
4607 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004608 break;
4609 }
4610
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004611 case Primitive::kPrimLong: {
4612 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004613 if (index.IsConstant()) {
4614 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004615 if (value.IsRegisterPair()) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004616 __ movl(Address(array, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004617 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004618 __ movl(Address(array, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004619 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004620 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004621 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004622 __ movl(Address(array, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004623 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004624 __ movl(Address(array, offset + kX86WordSize), Immediate(High32Bits(val)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004625 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004626 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004627 if (value.IsRegisterPair()) {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004628 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004629 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004630 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004631 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004632 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004633 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004634 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004635 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004636 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004637 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004638 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004639 __ movl(Address(array, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004640 Immediate(High32Bits(val)));
4641 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004642 }
4643 break;
4644 }
4645
Mark Mendell7c8d0092015-01-26 11:21:33 -05004646 case Primitive::kPrimFloat: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004647 uint32_t offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4648 Address address = index.IsConstant()
4649 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + offset)
4650 : Address(array, index.AsRegister<Register>(), TIMES_4, offset);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004651 DCHECK(value.IsFpuRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004652 __ movss(address, value.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004653 break;
4654 }
4655
4656 case Primitive::kPrimDouble: {
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004657 uint32_t offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4658 Address address = index.IsConstant()
4659 ? Address(array, (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + offset)
4660 : Address(array, index.AsRegister<Register>(), TIMES_8, offset);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004661 DCHECK(value.IsFpuRegister());
Nicolas Geoffraye0395dd2015-09-25 11:04:45 +01004662 __ movsd(address, value.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004663 break;
4664 }
4665
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004666 case Primitive::kPrimVoid:
4667 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004668 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004669 }
4670}
4671
4672void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
4673 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004674 locations->SetInAt(0, Location::RequiresRegister());
4675 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004676}
4677
4678void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
4679 LocationSummary* locations = instruction->GetLocations();
4680 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004681 Register obj = locations->InAt(0).AsRegister<Register>();
4682 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004683 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004684 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004685}
4686
4687void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004688 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4689 ? LocationSummary::kCallOnSlowPath
4690 : LocationSummary::kNoCall;
4691 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004692 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004693 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004694 if (instruction->HasUses()) {
4695 locations->SetOut(Location::SameAsFirstInput());
4696 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004697}
4698
4699void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
4700 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004701 Location index_loc = locations->InAt(0);
4702 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004703 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004704 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004705
Mark Mendell99dbd682015-04-22 16:18:52 -04004706 if (length_loc.IsConstant()) {
4707 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4708 if (index_loc.IsConstant()) {
4709 // BCE will remove the bounds check if we are guarenteed to pass.
4710 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4711 if (index < 0 || index >= length) {
4712 codegen_->AddSlowPath(slow_path);
4713 __ jmp(slow_path->GetEntryLabel());
4714 } else {
4715 // Some optimization after BCE may have generated this, and we should not
4716 // generate a bounds check if it is a valid range.
4717 }
4718 return;
4719 }
4720
4721 // We have to reverse the jump condition because the length is the constant.
4722 Register index_reg = index_loc.AsRegister<Register>();
4723 __ cmpl(index_reg, Immediate(length));
4724 codegen_->AddSlowPath(slow_path);
4725 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004726 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004727 Register length = length_loc.AsRegister<Register>();
4728 if (index_loc.IsConstant()) {
4729 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4730 __ cmpl(length, Immediate(value));
4731 } else {
4732 __ cmpl(length, index_loc.AsRegister<Register>());
4733 }
4734 codegen_->AddSlowPath(slow_path);
4735 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004736 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004737}
4738
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004739void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
4740 temp->SetLocations(nullptr);
4741}
4742
4743void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
4744 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004745 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004746}
4747
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004748void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004749 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004750 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004751}
4752
4753void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004754 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4755}
4756
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004757void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
4758 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4759}
4760
4761void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004762 HBasicBlock* block = instruction->GetBlock();
4763 if (block->GetLoopInformation() != nullptr) {
4764 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4765 // The back edge will generate the suspend check.
4766 return;
4767 }
4768 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4769 // The goto will generate the suspend check.
4770 return;
4771 }
4772 GenerateSuspendCheck(instruction, nullptr);
4773}
4774
4775void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
4776 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004777 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004778 down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
4779 if (slow_path == nullptr) {
4780 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
4781 instruction->SetSlowPath(slow_path);
4782 codegen_->AddSlowPath(slow_path);
4783 if (successor != nullptr) {
4784 DCHECK(successor->IsLoopHeader());
4785 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4786 }
4787 } else {
4788 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4789 }
4790
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004791 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004792 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004793 if (successor == nullptr) {
4794 __ j(kNotEqual, slow_path->GetEntryLabel());
4795 __ Bind(slow_path->GetReturnLabel());
4796 } else {
4797 __ j(kEqual, codegen_->GetLabelOf(successor));
4798 __ jmp(slow_path->GetEntryLabel());
4799 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004800}
4801
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004802X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
4803 return codegen_->GetAssembler();
4804}
4805
Mark Mendell7c8d0092015-01-26 11:21:33 -05004806void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004807 ScratchRegisterScope ensure_scratch(
4808 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4809 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4810 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4811 __ movl(temp_reg, Address(ESP, src + stack_offset));
4812 __ movl(Address(ESP, dst + stack_offset), temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004813}
4814
4815void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004816 ScratchRegisterScope ensure_scratch(
4817 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4818 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4819 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4820 __ movl(temp_reg, Address(ESP, src + stack_offset));
4821 __ movl(Address(ESP, dst + stack_offset), temp_reg);
4822 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
4823 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004824}
4825
4826void ParallelMoveResolverX86::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004827 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004828 Location source = move->GetSource();
4829 Location destination = move->GetDestination();
4830
4831 if (source.IsRegister()) {
4832 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004833 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004834 } else {
4835 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004836 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004837 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004838 } else if (source.IsFpuRegister()) {
4839 if (destination.IsFpuRegister()) {
4840 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4841 } else if (destination.IsStackSlot()) {
4842 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4843 } else {
4844 DCHECK(destination.IsDoubleStackSlot());
4845 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4846 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004847 } else if (source.IsStackSlot()) {
4848 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004849 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004850 } else if (destination.IsFpuRegister()) {
4851 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004852 } else {
4853 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004854 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
4855 }
4856 } else if (source.IsDoubleStackSlot()) {
4857 if (destination.IsFpuRegister()) {
4858 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
4859 } else {
4860 DCHECK(destination.IsDoubleStackSlot()) << destination;
4861 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004862 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004863 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004864 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004865 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004866 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004867 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004868 if (value == 0) {
4869 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
4870 } else {
4871 __ movl(destination.AsRegister<Register>(), Immediate(value));
4872 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004873 } else {
4874 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05004875 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004876 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004877 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004878 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004879 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004880 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004881 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004882 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4883 if (value == 0) {
4884 // Easy handling of 0.0.
4885 __ xorps(dest, dest);
4886 } else {
4887 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004888 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4889 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
4890 __ movl(temp, Immediate(value));
4891 __ movd(dest, temp);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004892 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004893 } else {
4894 DCHECK(destination.IsStackSlot()) << destination;
4895 __ movl(Address(ESP, destination.GetStackIndex()), imm);
4896 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004897 } else if (constant->IsLongConstant()) {
4898 int64_t value = constant->AsLongConstant()->GetValue();
4899 int32_t low_value = Low32Bits(value);
4900 int32_t high_value = High32Bits(value);
4901 Immediate low(low_value);
4902 Immediate high(high_value);
4903 if (destination.IsDoubleStackSlot()) {
4904 __ movl(Address(ESP, destination.GetStackIndex()), low);
4905 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4906 } else {
4907 __ movl(destination.AsRegisterPairLow<Register>(), low);
4908 __ movl(destination.AsRegisterPairHigh<Register>(), high);
4909 }
4910 } else {
4911 DCHECK(constant->IsDoubleConstant());
4912 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004913 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004914 int32_t low_value = Low32Bits(value);
4915 int32_t high_value = High32Bits(value);
4916 Immediate low(low_value);
4917 Immediate high(high_value);
4918 if (destination.IsFpuRegister()) {
4919 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4920 if (value == 0) {
4921 // Easy handling of 0.0.
4922 __ xorpd(dest, dest);
4923 } else {
4924 __ pushl(high);
4925 __ pushl(low);
4926 __ movsd(dest, Address(ESP, 0));
4927 __ addl(ESP, Immediate(8));
4928 }
4929 } else {
4930 DCHECK(destination.IsDoubleStackSlot()) << destination;
4931 __ movl(Address(ESP, destination.GetStackIndex()), low);
4932 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4933 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004934 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004935 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00004936 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004937 }
4938}
4939
Mark Mendella5c19ce2015-04-01 12:51:05 -04004940void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004941 Register suggested_scratch = reg == EAX ? EBX : EAX;
4942 ScratchRegisterScope ensure_scratch(
4943 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
4944
4945 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4946 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
4947 __ movl(Address(ESP, mem + stack_offset), reg);
4948 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004949}
4950
Mark Mendell7c8d0092015-01-26 11:21:33 -05004951void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004952 ScratchRegisterScope ensure_scratch(
4953 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4954
4955 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4956 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4957 __ movl(temp_reg, Address(ESP, mem + stack_offset));
4958 __ movss(Address(ESP, mem + stack_offset), reg);
4959 __ movd(reg, temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004960}
4961
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004962void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004963 ScratchRegisterScope ensure_scratch1(
4964 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004965
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004966 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
4967 ScratchRegisterScope ensure_scratch2(
4968 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004969
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004970 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
4971 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
4972 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
4973 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
4974 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
4975 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004976}
4977
4978void ParallelMoveResolverX86::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004979 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004980 Location source = move->GetSource();
4981 Location destination = move->GetDestination();
4982
4983 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell90979812015-07-28 16:41:21 -04004984 // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary.
4985 DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>());
4986 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
4987 __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>());
4988 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004989 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004990 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004991 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004992 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004993 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4994 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004995 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
4996 // Use XOR Swap algorithm to avoid a temporary.
4997 DCHECK_NE(source.reg(), destination.reg());
4998 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4999 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
5000 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
5001 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
5002 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
5003 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
5004 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005005 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
5006 // Take advantage of the 16 bytes in the XMM register.
5007 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
5008 Address stack(ESP, destination.GetStackIndex());
5009 // Load the double into the high doubleword.
5010 __ movhpd(reg, stack);
5011
5012 // Store the low double into the destination.
5013 __ movsd(stack, reg);
5014
5015 // Move the high double to the low double.
5016 __ psrldq(reg, Immediate(8));
5017 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
5018 // Take advantage of the 16 bytes in the XMM register.
5019 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
5020 Address stack(ESP, source.GetStackIndex());
5021 // Load the double into the high doubleword.
5022 __ movhpd(reg, stack);
5023
5024 // Store the low double into the destination.
5025 __ movsd(stack, reg);
5026
5027 // Move the high double to the low double.
5028 __ psrldq(reg, Immediate(8));
5029 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
5030 Exchange(destination.GetStackIndex(), source.GetStackIndex());
5031 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005032 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05005033 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01005034 }
5035}
5036
5037void ParallelMoveResolverX86::SpillScratch(int reg) {
5038 __ pushl(static_cast<Register>(reg));
5039}
5040
5041void ParallelMoveResolverX86::RestoreScratch(int reg) {
5042 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01005043}
5044
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005045void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Calin Juravle98893e12015-10-02 21:05:03 +01005046 InvokeRuntimeCallingConvention calling_convention;
5047 CodeGenerator::CreateLoadClassLocationSummary(
5048 cls,
5049 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
5050 Location::RegisterLocation(EAX));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005051}
5052
5053void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005054 LocationSummary* locations = cls->GetLocations();
Calin Juravle98893e12015-10-02 21:05:03 +01005055 if (cls->NeedsAccessCheck()) {
5056 codegen_->MoveConstant(locations->GetTemp(0), cls->GetTypeIndex());
5057 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInitializeTypeAndVerifyAccess),
5058 cls,
5059 cls->GetDexPc(),
5060 nullptr);
Calin Juravle580b6092015-10-06 17:35:58 +01005061 return;
5062 }
5063
5064 Register out = locations->Out().AsRegister<Register>();
5065 Register current_method = locations->InAt(0).AsRegister<Register>();
5066 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005067 DCHECK(!cls->CanCallRuntime());
5068 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07005069 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005070 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005071 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01005072 __ movl(out, Address(
Vladimir Marko05792b92015-08-03 11:56:49 +01005073 current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86PointerSize).Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005074 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01005075 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005076
Andreas Gampe85b62f22015-09-09 13:15:38 -07005077 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005078 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
5079 codegen_->AddSlowPath(slow_path);
5080 __ testl(out, out);
5081 __ j(kEqual, slow_path->GetEntryLabel());
5082 if (cls->MustGenerateClinitCheck()) {
5083 GenerateClassInitializationCheck(slow_path, out);
5084 } else {
5085 __ Bind(slow_path->GetExitLabel());
5086 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005087 }
5088}
5089
5090void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
5091 LocationSummary* locations =
5092 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
5093 locations->SetInAt(0, Location::RequiresRegister());
5094 if (check->HasUses()) {
5095 locations->SetOut(Location::SameAsFirstInput());
5096 }
5097}
5098
5099void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005100 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07005101 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005102 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005103 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00005104 GenerateClassInitializationCheck(slow_path,
5105 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005106}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005107
Nicolas Geoffray424f6762014-11-03 14:51:25 +00005108void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07005109 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01005110 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
5111 Immediate(mirror::Class::kStatusInitialized));
5112 __ j(kLess, slow_path->GetEntryLabel());
5113 __ Bind(slow_path->GetExitLabel());
5114 // No need for memory fence, thanks to the X86 memory model.
5115}
5116
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005117void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
5118 LocationSummary* locations =
5119 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005120 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005121 locations->SetOut(Location::RequiresRegister());
5122}
5123
5124void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07005125 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005126 codegen_->AddSlowPath(slow_path);
5127
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01005128 LocationSummary* locations = load->GetLocations();
5129 Register out = locations->Out().AsRegister<Register>();
5130 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07005131 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08005132 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005133 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01005134 // TODO: We will need a read barrier here.
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00005135 __ testl(out, out);
5136 __ j(kEqual, slow_path->GetEntryLabel());
5137 __ Bind(slow_path->GetExitLabel());
5138}
5139
David Brazdilcb1c0552015-08-04 16:22:25 +01005140static Address GetExceptionTlsAddress() {
5141 return Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
5142}
5143
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005144void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
5145 LocationSummary* locations =
5146 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
5147 locations->SetOut(Location::RequiresRegister());
5148}
5149
5150void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01005151 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress());
5152}
5153
5154void LocationsBuilderX86::VisitClearException(HClearException* clear) {
5155 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
5156}
5157
5158void InstructionCodeGeneratorX86::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
5159 __ fs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005160}
5161
5162void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
5163 LocationSummary* locations =
5164 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5165 InvokeRuntimeCallingConvention calling_convention;
5166 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5167}
5168
5169void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005170 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
5171 instruction,
5172 instruction->GetDexPc(),
5173 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00005174}
5175
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005176void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005177 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5178 switch (instruction->GetTypeCheckKind()) {
5179 case TypeCheckKind::kExactCheck:
5180 case TypeCheckKind::kAbstractClassCheck:
5181 case TypeCheckKind::kClassHierarchyCheck:
5182 case TypeCheckKind::kArrayObjectCheck:
5183 call_kind = LocationSummary::kNoCall;
5184 break;
Calin Juravle98893e12015-10-02 21:05:03 +01005185 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005186 case TypeCheckKind::kInterfaceCheck:
5187 call_kind = LocationSummary::kCall;
5188 break;
5189 case TypeCheckKind::kArrayCheck:
5190 call_kind = LocationSummary::kCallOnSlowPath;
5191 break;
5192 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005193 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005194 if (call_kind != LocationSummary::kCall) {
5195 locations->SetInAt(0, Location::RequiresRegister());
5196 locations->SetInAt(1, Location::Any());
5197 // Note that TypeCheckSlowPathX86 uses this register too.
5198 locations->SetOut(Location::RequiresRegister());
5199 } else {
5200 InvokeRuntimeCallingConvention calling_convention;
5201 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5202 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5203 locations->SetOut(Location::RegisterLocation(EAX));
5204 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005205}
5206
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005207void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005208 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005209 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005210 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005211 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005212 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005213 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5214 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5215 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005216 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005217 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005218
5219 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005220 // Avoid null check if we know obj is not null.
5221 if (instruction->MustDoNullCheck()) {
5222 __ testl(obj, obj);
5223 __ j(kEqual, &zero);
5224 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005225
Calin Juravle98893e12015-10-02 21:05:03 +01005226 // In case of an interface/unresolved check, we put the object class into the object register.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005227 // This is safe, as the register is caller-save, and the object must be in another
5228 // register if it survives the runtime call.
Calin Juravle98893e12015-10-02 21:05:03 +01005229 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck) ||
5230 (instruction->GetTypeCheckKind() == TypeCheckKind::kUnresolvedCheck)
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005231 ? obj
5232 : out;
5233 __ movl(target, Address(obj, class_offset));
5234 __ MaybeUnpoisonHeapReference(target);
5235
5236 switch (instruction->GetTypeCheckKind()) {
5237 case TypeCheckKind::kExactCheck: {
5238 if (cls.IsRegister()) {
5239 __ cmpl(out, cls.AsRegister<Register>());
5240 } else {
5241 DCHECK(cls.IsStackSlot()) << cls;
5242 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5243 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005244
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005245 // Classes must be equal for the instanceof to succeed.
5246 __ j(kNotEqual, &zero);
5247 __ movl(out, Immediate(1));
5248 __ jmp(&done);
5249 break;
5250 }
5251 case TypeCheckKind::kAbstractClassCheck: {
5252 // If the class is abstract, we eagerly fetch the super class of the
5253 // object to avoid doing a comparison we know will fail.
5254 NearLabel loop;
5255 __ Bind(&loop);
5256 __ movl(out, Address(out, super_offset));
5257 __ MaybeUnpoisonHeapReference(out);
5258 __ testl(out, out);
5259 // If `out` is null, we use it for the result, and jump to `done`.
5260 __ j(kEqual, &done);
5261 if (cls.IsRegister()) {
5262 __ cmpl(out, cls.AsRegister<Register>());
5263 } else {
5264 DCHECK(cls.IsStackSlot()) << cls;
5265 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5266 }
5267 __ j(kNotEqual, &loop);
5268 __ movl(out, Immediate(1));
5269 if (zero.IsLinked()) {
5270 __ jmp(&done);
5271 }
5272 break;
5273 }
5274 case TypeCheckKind::kClassHierarchyCheck: {
5275 // Walk over the class hierarchy to find a match.
5276 NearLabel loop, success;
5277 __ Bind(&loop);
5278 if (cls.IsRegister()) {
5279 __ cmpl(out, cls.AsRegister<Register>());
5280 } else {
5281 DCHECK(cls.IsStackSlot()) << cls;
5282 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5283 }
5284 __ j(kEqual, &success);
5285 __ movl(out, Address(out, super_offset));
5286 __ MaybeUnpoisonHeapReference(out);
5287 __ testl(out, out);
5288 __ j(kNotEqual, &loop);
5289 // If `out` is null, we use it for the result, and jump to `done`.
5290 __ jmp(&done);
5291 __ Bind(&success);
5292 __ movl(out, Immediate(1));
5293 if (zero.IsLinked()) {
5294 __ jmp(&done);
5295 }
5296 break;
5297 }
5298 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005299 // Do an exact check.
5300 NearLabel exact_check;
5301 if (cls.IsRegister()) {
5302 __ cmpl(out, cls.AsRegister<Register>());
5303 } else {
5304 DCHECK(cls.IsStackSlot()) << cls;
5305 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5306 }
5307 __ j(kEqual, &exact_check);
5308 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005309 __ movl(out, Address(out, component_offset));
5310 __ MaybeUnpoisonHeapReference(out);
5311 __ testl(out, out);
5312 // If `out` is null, we use it for the result, and jump to `done`.
5313 __ j(kEqual, &done);
5314 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5315 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005316 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005317 __ movl(out, Immediate(1));
5318 __ jmp(&done);
5319 break;
5320 }
5321 case TypeCheckKind::kArrayCheck: {
5322 if (cls.IsRegister()) {
5323 __ cmpl(out, cls.AsRegister<Register>());
5324 } else {
5325 DCHECK(cls.IsStackSlot()) << cls;
5326 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5327 }
5328 DCHECK(locations->OnlyCallsOnSlowPath());
5329 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5330 instruction, /* is_fatal */ false);
5331 codegen_->AddSlowPath(slow_path);
5332 __ j(kNotEqual, slow_path->GetEntryLabel());
5333 __ movl(out, Immediate(1));
5334 if (zero.IsLinked()) {
5335 __ jmp(&done);
5336 }
5337 break;
5338 }
Calin Juravle98893e12015-10-02 21:05:03 +01005339 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005340 case TypeCheckKind::kInterfaceCheck:
5341 default: {
5342 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
5343 instruction,
5344 instruction->GetDexPc(),
5345 nullptr);
5346 if (zero.IsLinked()) {
5347 __ jmp(&done);
5348 }
5349 break;
5350 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005351 }
5352
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005353 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005354 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005355 __ xorl(out, out);
5356 }
5357
5358 if (done.IsLinked()) {
5359 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005360 }
5361
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005362 if (slow_path != nullptr) {
5363 __ Bind(slow_path->GetExitLabel());
5364 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005365}
5366
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005367void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005368 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5369 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5370
5371 switch (instruction->GetTypeCheckKind()) {
5372 case TypeCheckKind::kExactCheck:
5373 case TypeCheckKind::kAbstractClassCheck:
5374 case TypeCheckKind::kClassHierarchyCheck:
5375 case TypeCheckKind::kArrayObjectCheck:
5376 call_kind = throws_into_catch
5377 ? LocationSummary::kCallOnSlowPath
5378 : LocationSummary::kNoCall;
5379 break;
5380 case TypeCheckKind::kInterfaceCheck:
Calin Juravle98893e12015-10-02 21:05:03 +01005381 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005382 call_kind = LocationSummary::kCall;
5383 break;
5384 case TypeCheckKind::kArrayCheck:
5385 call_kind = LocationSummary::kCallOnSlowPath;
5386 break;
5387 }
5388
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005389 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005390 instruction, call_kind);
5391 if (call_kind != LocationSummary::kCall) {
5392 locations->SetInAt(0, Location::RequiresRegister());
5393 locations->SetInAt(1, Location::Any());
5394 // Note that TypeCheckSlowPathX86 uses this register too.
5395 locations->AddTemp(Location::RequiresRegister());
5396 } else {
5397 InvokeRuntimeCallingConvention calling_convention;
5398 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5399 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5400 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005401}
5402
5403void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
5404 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005405 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005406 Location cls = locations->InAt(1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005407 Register temp = locations->WillCall()
5408 ? kNoRegister
5409 : locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray64acf302015-09-14 22:20:29 +01005410
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005411 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5412 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5413 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5414 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5415 SlowPathCode* slow_path = nullptr;
5416
5417 if (!locations->WillCall()) {
5418 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5419 instruction, !locations->CanCall());
5420 codegen_->AddSlowPath(slow_path);
5421 }
5422
5423 NearLabel done, abstract_entry;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005424 // Avoid null check if we know obj is not null.
5425 if (instruction->MustDoNullCheck()) {
5426 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005427 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005428 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005429
5430 if (locations->WillCall()) {
5431 __ movl(obj, Address(obj, class_offset));
5432 __ MaybeUnpoisonHeapReference(obj);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005433 } else {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005434 __ movl(temp, Address(obj, class_offset));
5435 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005436 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005437
5438 switch (instruction->GetTypeCheckKind()) {
5439 case TypeCheckKind::kExactCheck:
5440 case TypeCheckKind::kArrayCheck: {
5441 if (cls.IsRegister()) {
5442 __ cmpl(temp, cls.AsRegister<Register>());
5443 } else {
5444 DCHECK(cls.IsStackSlot()) << cls;
5445 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5446 }
5447 // Jump to slow path for throwing the exception or doing a
5448 // more involved array check.
5449 __ j(kNotEqual, slow_path->GetEntryLabel());
5450 break;
5451 }
5452 case TypeCheckKind::kAbstractClassCheck: {
5453 // If the class is abstract, we eagerly fetch the super class of the
5454 // object to avoid doing a comparison we know will fail.
5455 NearLabel loop, success;
5456 __ Bind(&loop);
5457 __ movl(temp, Address(temp, super_offset));
5458 __ MaybeUnpoisonHeapReference(temp);
5459 __ testl(temp, temp);
5460 // Jump to the slow path to throw the exception.
5461 __ j(kEqual, slow_path->GetEntryLabel());
5462 if (cls.IsRegister()) {
5463 __ cmpl(temp, cls.AsRegister<Register>());
5464 } else {
5465 DCHECK(cls.IsStackSlot()) << cls;
5466 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5467 }
5468 __ j(kNotEqual, &loop);
5469 break;
5470 }
5471 case TypeCheckKind::kClassHierarchyCheck: {
5472 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005473 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005474 __ Bind(&loop);
5475 if (cls.IsRegister()) {
5476 __ cmpl(temp, cls.AsRegister<Register>());
5477 } else {
5478 DCHECK(cls.IsStackSlot()) << cls;
5479 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5480 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005481 __ j(kEqual, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005482 __ movl(temp, Address(temp, super_offset));
5483 __ MaybeUnpoisonHeapReference(temp);
5484 __ testl(temp, temp);
5485 __ j(kNotEqual, &loop);
5486 // Jump to the slow path to throw the exception.
5487 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005488 break;
5489 }
5490 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005491 // Do an exact check.
5492 if (cls.IsRegister()) {
5493 __ cmpl(temp, cls.AsRegister<Register>());
5494 } else {
5495 DCHECK(cls.IsStackSlot()) << cls;
5496 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5497 }
5498 __ j(kEqual, &done);
5499 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005500 __ movl(temp, Address(temp, component_offset));
5501 __ MaybeUnpoisonHeapReference(temp);
5502 __ testl(temp, temp);
5503 __ j(kEqual, slow_path->GetEntryLabel());
5504 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
5505 __ j(kNotEqual, slow_path->GetEntryLabel());
5506 break;
5507 }
Calin Juravle98893e12015-10-02 21:05:03 +01005508 case TypeCheckKind::kUnresolvedCheck:
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005509 case TypeCheckKind::kInterfaceCheck:
5510 default:
5511 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5512 instruction,
5513 instruction->GetDexPc(),
5514 nullptr);
5515 break;
5516 }
5517 __ Bind(&done);
5518
5519 if (slow_path != nullptr) {
5520 __ Bind(slow_path->GetExitLabel());
5521 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005522}
5523
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005524void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
5525 LocationSummary* locations =
5526 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5527 InvokeRuntimeCallingConvention calling_convention;
5528 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5529}
5530
5531void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005532 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5533 : QUICK_ENTRY_POINT(pUnlockObject),
5534 instruction,
5535 instruction->GetDexPc(),
5536 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005537}
5538
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005539void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5540void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5541void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5542
5543void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5544 LocationSummary* locations =
5545 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5546 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5547 || instruction->GetResultType() == Primitive::kPrimLong);
5548 locations->SetInAt(0, Location::RequiresRegister());
5549 locations->SetInAt(1, Location::Any());
5550 locations->SetOut(Location::SameAsFirstInput());
5551}
5552
5553void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
5554 HandleBitwiseOperation(instruction);
5555}
5556
5557void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
5558 HandleBitwiseOperation(instruction);
5559}
5560
5561void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
5562 HandleBitwiseOperation(instruction);
5563}
5564
5565void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5566 LocationSummary* locations = instruction->GetLocations();
5567 Location first = locations->InAt(0);
5568 Location second = locations->InAt(1);
5569 DCHECK(first.Equals(locations->Out()));
5570
5571 if (instruction->GetResultType() == Primitive::kPrimInt) {
5572 if (second.IsRegister()) {
5573 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005574 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005575 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005576 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005577 } else {
5578 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005579 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005580 }
5581 } else if (second.IsConstant()) {
5582 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005583 __ andl(first.AsRegister<Register>(),
5584 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005585 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005586 __ orl(first.AsRegister<Register>(),
5587 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005588 } else {
5589 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00005590 __ xorl(first.AsRegister<Register>(),
5591 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005592 }
5593 } else {
5594 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005595 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005596 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005597 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005598 } else {
5599 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005600 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005601 }
5602 }
5603 } else {
5604 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5605 if (second.IsRegisterPair()) {
5606 if (instruction->IsAnd()) {
5607 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5608 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5609 } else if (instruction->IsOr()) {
5610 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5611 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5612 } else {
5613 DCHECK(instruction->IsXor());
5614 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5615 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5616 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005617 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005618 if (instruction->IsAnd()) {
5619 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5620 __ andl(first.AsRegisterPairHigh<Register>(),
5621 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5622 } else if (instruction->IsOr()) {
5623 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5624 __ orl(first.AsRegisterPairHigh<Register>(),
5625 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5626 } else {
5627 DCHECK(instruction->IsXor());
5628 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5629 __ xorl(first.AsRegisterPairHigh<Register>(),
5630 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5631 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005632 } else {
5633 DCHECK(second.IsConstant()) << second;
5634 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005635 int32_t low_value = Low32Bits(value);
5636 int32_t high_value = High32Bits(value);
5637 Immediate low(low_value);
5638 Immediate high(high_value);
5639 Register first_low = first.AsRegisterPairLow<Register>();
5640 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005641 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005642 if (low_value == 0) {
5643 __ xorl(first_low, first_low);
5644 } else if (low_value != -1) {
5645 __ andl(first_low, low);
5646 }
5647 if (high_value == 0) {
5648 __ xorl(first_high, first_high);
5649 } else if (high_value != -1) {
5650 __ andl(first_high, high);
5651 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005652 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005653 if (low_value != 0) {
5654 __ orl(first_low, low);
5655 }
5656 if (high_value != 0) {
5657 __ orl(first_high, high);
5658 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005659 } else {
5660 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005661 if (low_value != 0) {
5662 __ xorl(first_low, low);
5663 }
5664 if (high_value != 0) {
5665 __ xorl(first_high, high);
5666 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005667 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005668 }
5669 }
5670}
5671
Calin Juravleb1498f62015-02-16 13:13:29 +00005672void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
5673 // Nothing to do, this should be removed during prepare for register allocator.
5674 UNUSED(instruction);
5675 LOG(FATAL) << "Unreachable";
5676}
5677
5678void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
5679 // Nothing to do, this should be removed during prepare for register allocator.
5680 UNUSED(instruction);
5681 LOG(FATAL) << "Unreachable";
5682}
5683
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005684void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) {
5685 DCHECK(codegen_->IsBaseline());
5686 LocationSummary* locations =
5687 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5688 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5689}
5690
5691void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5692 DCHECK(codegen_->IsBaseline());
5693 // Will be generated at use site.
5694}
5695
Mark Mendellfe57faa2015-09-18 09:26:15 -04005696// Simple implementation of packed switch - generate cascaded compare/jumps.
5697void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5698 LocationSummary* locations =
5699 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5700 locations->SetInAt(0, Location::RequiresRegister());
5701}
5702
5703void InstructionCodeGeneratorX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5704 int32_t lower_bound = switch_instr->GetStartValue();
5705 int32_t num_entries = switch_instr->GetNumEntries();
5706 LocationSummary* locations = switch_instr->GetLocations();
5707 Register value_reg = locations->InAt(0).AsRegister<Register>();
5708 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5709
5710 // Create a series of compare/jumps.
5711 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5712 for (int i = 0; i < num_entries; i++) {
5713 int32_t case_value = lower_bound + i;
5714 if (case_value == 0) {
5715 __ testl(value_reg, value_reg);
5716 } else {
5717 __ cmpl(value_reg, Immediate(case_value));
5718 }
Vladimir Markoec7802a2015-10-01 20:57:57 +01005719 __ j(kEqual, codegen_->GetLabelOf(successors[i]));
Mark Mendellfe57faa2015-09-18 09:26:15 -04005720 }
5721
5722 // And the default for any other value.
5723 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5724 __ jmp(codegen_->GetLabelOf(default_block));
5725 }
5726}
5727
Mark Mendell805b3b52015-09-18 14:10:29 -04005728void LocationsBuilderX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
5729 LocationSummary* locations =
5730 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5731 locations->SetInAt(0, Location::RequiresRegister());
5732
5733 // Constant area pointer.
5734 locations->SetInAt(1, Location::RequiresRegister());
5735
5736 // And the temporary we need.
5737 locations->AddTemp(Location::RequiresRegister());
5738}
5739
5740void InstructionCodeGeneratorX86::VisitX86PackedSwitch(HX86PackedSwitch* switch_instr) {
5741 int32_t lower_bound = switch_instr->GetStartValue();
5742 int32_t num_entries = switch_instr->GetNumEntries();
5743 LocationSummary* locations = switch_instr->GetLocations();
5744 Register value_reg = locations->InAt(0).AsRegister<Register>();
5745 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5746
5747 // Optimizing has a jump area.
5748 Register temp_reg = locations->GetTemp(0).AsRegister<Register>();
5749 Register constant_area = locations->InAt(1).AsRegister<Register>();
5750
5751 // Remove the bias, if needed.
5752 if (lower_bound != 0) {
5753 __ leal(temp_reg, Address(value_reg, -lower_bound));
5754 value_reg = temp_reg;
5755 }
5756
5757 // Is the value in range?
5758 DCHECK_GE(num_entries, 1);
5759 __ cmpl(value_reg, Immediate(num_entries - 1));
5760 __ j(kAbove, codegen_->GetLabelOf(default_block));
5761
5762 // We are in the range of the table.
5763 // Load (target-constant_area) from the jump table, indexing by the value.
5764 __ movl(temp_reg, codegen_->LiteralCaseTable(switch_instr, constant_area, value_reg));
5765
5766 // Compute the actual target address by adding in constant_area.
5767 __ addl(temp_reg, constant_area);
5768
5769 // And jump.
5770 __ jmp(temp_reg);
5771}
5772
Mark Mendell0616ae02015-04-17 12:49:27 -04005773void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
5774 HX86ComputeBaseMethodAddress* insn) {
5775 LocationSummary* locations =
5776 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5777 locations->SetOut(Location::RequiresRegister());
5778}
5779
5780void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
5781 HX86ComputeBaseMethodAddress* insn) {
5782 LocationSummary* locations = insn->GetLocations();
5783 Register reg = locations->Out().AsRegister<Register>();
5784
5785 // Generate call to next instruction.
5786 Label next_instruction;
5787 __ call(&next_instruction);
5788 __ Bind(&next_instruction);
5789
5790 // Remember this offset for later use with constant area.
5791 codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize());
5792
5793 // Grab the return address off the stack.
5794 __ popl(reg);
5795}
5796
5797void LocationsBuilderX86::VisitX86LoadFromConstantTable(
5798 HX86LoadFromConstantTable* insn) {
5799 LocationSummary* locations =
5800 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5801
5802 locations->SetInAt(0, Location::RequiresRegister());
5803 locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
5804
5805 // If we don't need to be materialized, we only need the inputs to be set.
5806 if (!insn->NeedsMaterialization()) {
5807 return;
5808 }
5809
5810 switch (insn->GetType()) {
5811 case Primitive::kPrimFloat:
5812 case Primitive::kPrimDouble:
5813 locations->SetOut(Location::RequiresFpuRegister());
5814 break;
5815
5816 case Primitive::kPrimInt:
5817 locations->SetOut(Location::RequiresRegister());
5818 break;
5819
5820 default:
5821 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5822 }
5823}
5824
5825void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
5826 if (!insn->NeedsMaterialization()) {
5827 return;
5828 }
5829
5830 LocationSummary* locations = insn->GetLocations();
5831 Location out = locations->Out();
5832 Register const_area = locations->InAt(0).AsRegister<Register>();
5833 HConstant *value = insn->GetConstant();
5834
5835 switch (insn->GetType()) {
5836 case Primitive::kPrimFloat:
5837 __ movss(out.AsFpuRegister<XmmRegister>(),
5838 codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area));
5839 break;
5840
5841 case Primitive::kPrimDouble:
5842 __ movsd(out.AsFpuRegister<XmmRegister>(),
5843 codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area));
5844 break;
5845
5846 case Primitive::kPrimInt:
5847 __ movl(out.AsRegister<Register>(),
5848 codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area));
5849 break;
5850
5851 default:
5852 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5853 }
5854}
5855
Mark Mendell0616ae02015-04-17 12:49:27 -04005856/**
5857 * Class to handle late fixup of offsets into constant area.
5858 */
Vladimir Marko5233f932015-09-29 19:01:15 +01005859class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocCodeGenerator> {
Mark Mendell0616ae02015-04-17 12:49:27 -04005860 public:
Mark Mendell805b3b52015-09-18 14:10:29 -04005861 RIPFixup(CodeGeneratorX86& codegen, size_t offset)
5862 : codegen_(&codegen), offset_into_constant_area_(offset) {}
5863
5864 protected:
5865 void SetOffset(size_t offset) { offset_into_constant_area_ = offset; }
5866
5867 CodeGeneratorX86* codegen_;
Mark Mendell0616ae02015-04-17 12:49:27 -04005868
5869 private:
5870 void Process(const MemoryRegion& region, int pos) OVERRIDE {
5871 // Patch the correct offset for the instruction. The place to patch is the
5872 // last 4 bytes of the instruction.
5873 // The value to patch is the distance from the offset in the constant area
5874 // from the address computed by the HX86ComputeBaseMethodAddress instruction.
Mark Mendell805b3b52015-09-18 14:10:29 -04005875 int32_t constant_offset = codegen_->ConstantAreaStart() + offset_into_constant_area_;
5876 int32_t relative_position = constant_offset - codegen_->GetMethodAddressOffset();;
Mark Mendell0616ae02015-04-17 12:49:27 -04005877
5878 // Patch in the right value.
5879 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
5880 }
5881
Mark Mendell0616ae02015-04-17 12:49:27 -04005882 // Location in constant area that the fixup refers to.
Mark Mendell805b3b52015-09-18 14:10:29 -04005883 int32_t offset_into_constant_area_;
Mark Mendell0616ae02015-04-17 12:49:27 -04005884};
5885
Mark Mendell805b3b52015-09-18 14:10:29 -04005886/**
5887 * Class to handle late fixup of offsets to a jump table that will be created in the
5888 * constant area.
5889 */
5890class JumpTableRIPFixup : public RIPFixup {
5891 public:
5892 JumpTableRIPFixup(CodeGeneratorX86& codegen, HX86PackedSwitch* switch_instr)
5893 : RIPFixup(codegen, static_cast<size_t>(-1)), switch_instr_(switch_instr) {}
5894
5895 void CreateJumpTable() {
5896 X86Assembler* assembler = codegen_->GetAssembler();
5897
5898 // Ensure that the reference to the jump table has the correct offset.
5899 const int32_t offset_in_constant_table = assembler->ConstantAreaSize();
5900 SetOffset(offset_in_constant_table);
5901
5902 // The label values in the jump table are computed relative to the
5903 // instruction addressing the constant area.
5904 const int32_t relative_offset = codegen_->GetMethodAddressOffset();
5905
5906 // Populate the jump table with the correct values for the jump table.
5907 int32_t num_entries = switch_instr_->GetNumEntries();
5908 HBasicBlock* block = switch_instr_->GetBlock();
5909 const ArenaVector<HBasicBlock*>& successors = block->GetSuccessors();
5910 // The value that we want is the target offset - the position of the table.
5911 for (int32_t i = 0; i < num_entries; i++) {
5912 HBasicBlock* b = successors[i];
5913 Label* l = codegen_->GetLabelOf(b);
5914 DCHECK(l->IsBound());
5915 int32_t offset_to_block = l->Position() - relative_offset;
5916 assembler->AppendInt32(offset_to_block);
5917 }
5918 }
5919
5920 private:
5921 const HX86PackedSwitch* switch_instr_;
5922};
5923
5924void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
5925 // Generate the constant area if needed.
5926 X86Assembler* assembler = GetAssembler();
5927 if (!assembler->IsConstantAreaEmpty() || !fixups_to_jump_tables_.empty()) {
5928 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
5929 // byte values.
5930 assembler->Align(4, 0);
5931 constant_area_start_ = assembler->CodeSize();
5932
5933 // Populate any jump tables.
5934 for (auto jump_table : fixups_to_jump_tables_) {
5935 jump_table->CreateJumpTable();
5936 }
5937
5938 // And now add the constant area to the generated code.
5939 assembler->AddConstantArea();
5940 }
5941
5942 // And finish up.
5943 CodeGenerator::Finalize(allocator);
5944}
5945
Mark Mendell0616ae02015-04-17 12:49:27 -04005946Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) {
5947 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
5948 return Address(reg, kDummy32BitOffset, fixup);
5949}
5950
5951Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) {
5952 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
5953 return Address(reg, kDummy32BitOffset, fixup);
5954}
5955
5956Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) {
5957 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
5958 return Address(reg, kDummy32BitOffset, fixup);
5959}
5960
5961Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) {
5962 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
5963 return Address(reg, kDummy32BitOffset, fixup);
5964}
5965
Mark Mendell805b3b52015-09-18 14:10:29 -04005966Address CodeGeneratorX86::LiteralCaseTable(HX86PackedSwitch* switch_instr,
5967 Register reg,
5968 Register value) {
5969 // Create a fixup to be used to create and address the jump table.
5970 JumpTableRIPFixup* table_fixup =
5971 new (GetGraph()->GetArena()) JumpTableRIPFixup(*this, switch_instr);
5972
5973 // We have to populate the jump tables.
5974 fixups_to_jump_tables_.push_back(table_fixup);
5975
5976 // We want a scaled address, as we are extracting the correct offset from the table.
5977 return Address(reg, value, TIMES_4, kDummy32BitOffset, table_fixup);
5978}
5979
Andreas Gampe85b62f22015-09-09 13:15:38 -07005980// TODO: target as memory.
5981void CodeGeneratorX86::MoveFromReturnRegister(Location target, Primitive::Type type) {
5982 if (!target.IsValid()) {
5983 DCHECK(type == Primitive::kPrimVoid);
5984 return;
5985 }
5986
5987 DCHECK_NE(type, Primitive::kPrimVoid);
5988
5989 Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type);
5990 if (target.Equals(return_loc)) {
5991 return;
5992 }
5993
5994 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5995 // with the else branch.
5996 if (type == Primitive::kPrimLong) {
5997 HParallelMove parallel_move(GetGraph()->GetArena());
5998 parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), Primitive::kPrimInt, nullptr);
5999 parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), Primitive::kPrimInt, nullptr);
6000 GetMoveResolver()->EmitNativeCode(&parallel_move);
6001 } else {
6002 // Let the parallel move resolver take care of all of this.
6003 HParallelMove parallel_move(GetGraph()->GetArena());
6004 parallel_move.AddMove(return_loc, target, type, nullptr);
6005 GetMoveResolver()->EmitNativeCode(&parallel_move);
6006 }
6007}
6008
Roland Levillain4d027112015-07-01 15:41:14 +01006009#undef __
6010
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00006011} // namespace x86
6012} // namespace art