blob: 277f6b48c8b8582969b8e990bec337e85820830a [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 Geoffraye5038322014-07-04 09:41:32 +0100383#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100384#define __ down_cast<X86Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100385
Roland Levillain4fa13f62015-07-06 18:11:54 +0100386inline Condition X86SignedCondition(IfCondition cond) {
Dave Allison20dfc792014-06-16 20:44:29 -0700387 switch (cond) {
388 case kCondEQ: return kEqual;
389 case kCondNE: return kNotEqual;
390 case kCondLT: return kLess;
391 case kCondLE: return kLessEqual;
392 case kCondGT: return kGreater;
393 case kCondGE: return kGreaterEqual;
Dave Allison20dfc792014-06-16 20:44:29 -0700394 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100395 LOG(FATAL) << "Unreachable";
396 UNREACHABLE();
397}
398
399inline Condition X86UnsignedOrFPCondition(IfCondition cond) {
400 switch (cond) {
401 case kCondEQ: return kEqual;
402 case kCondNE: return kNotEqual;
403 case kCondLT: return kBelow;
404 case kCondLE: return kBelowEqual;
405 case kCondGT: return kAbove;
406 case kCondGE: return kAboveEqual;
407 }
408 LOG(FATAL) << "Unreachable";
409 UNREACHABLE();
Dave Allison20dfc792014-06-16 20:44:29 -0700410}
411
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100412void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100413 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100414}
415
416void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100417 stream << XmmRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100418}
419
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100420size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
421 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
422 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100423}
424
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100425size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
426 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
427 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100428}
429
Mark Mendell7c8d0092015-01-26 11:21:33 -0500430size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
431 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
432 return GetFloatingPointSpillSlotSize();
433}
434
435size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
436 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
437 return GetFloatingPointSpillSlotSize();
438}
439
Calin Juravle175dc732015-08-25 15:42:32 +0100440void CodeGeneratorX86::InvokeRuntime(QuickEntrypointEnum entrypoint,
441 HInstruction* instruction,
442 uint32_t dex_pc,
443 SlowPathCode* slow_path) {
444 InvokeRuntime(GetThreadOffset<kX86WordSize>(entrypoint).Int32Value(),
445 instruction,
446 dex_pc,
447 slow_path);
448}
449
450void CodeGeneratorX86::InvokeRuntime(int32_t entry_point_offset,
Alexandre Rames8158f282015-08-07 10:26:17 +0100451 HInstruction* instruction,
452 uint32_t dex_pc,
453 SlowPathCode* slow_path) {
Alexandre Rames78e3ef62015-08-12 13:43:29 +0100454 ValidateInvokeRuntime(instruction, slow_path);
Calin Juravle175dc732015-08-25 15:42:32 +0100455 __ fs()->call(Address::Absolute(entry_point_offset));
Alexandre Rames8158f282015-08-07 10:26:17 +0100456 RecordPcInfo(instruction, dex_pc, slow_path);
Alexandre Rames8158f282015-08-07 10:26:17 +0100457}
458
Mark Mendellfb8d2792015-03-31 22:16:59 -0400459CodeGeneratorX86::CodeGeneratorX86(HGraph* graph,
460 const X86InstructionSetFeatures& isa_features,
Serban Constantinescuecc43662015-08-13 13:33:12 +0100461 const CompilerOptions& compiler_options,
462 OptimizingCompilerStats* stats)
Mark Mendell5f874182015-03-04 15:42:45 -0500463 : CodeGenerator(graph,
464 kNumberOfCpuRegisters,
465 kNumberOfXmmRegisters,
466 kNumberOfRegisterPairs,
467 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
468 arraysize(kCoreCalleeSaves))
469 | (1 << kFakeReturnRegister),
Serban Constantinescuecc43662015-08-13 13:33:12 +0100470 0,
471 compiler_options,
472 stats),
Vladimir Marko225b6462015-09-28 12:17:40 +0100473 block_labels_(nullptr),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100474 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100475 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400476 move_resolver_(graph->GetArena(), this),
Vladimir Marko58155012015-08-19 12:49:41 +0000477 isa_features_(isa_features),
478 method_patches_(graph->GetArena()->Adapter()),
479 relative_call_patches_(graph->GetArena()->Adapter()) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000480 // Use a fake return address register to mimic Quick.
481 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100482}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100483
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100484Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100485 switch (type) {
486 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100487 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100488 X86ManagedRegister pair =
489 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100490 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
491 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100492 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
493 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100494 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100495 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100496 }
497
498 case Primitive::kPrimByte:
499 case Primitive::kPrimBoolean:
500 case Primitive::kPrimChar:
501 case Primitive::kPrimShort:
502 case Primitive::kPrimInt:
503 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100504 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100505 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100506 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100507 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
508 X86ManagedRegister current =
509 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
510 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100511 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100512 }
513 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100514 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100515 }
516
517 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100518 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100519 return Location::FpuRegisterLocation(
520 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100521 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100522
523 case Primitive::kPrimVoid:
524 LOG(FATAL) << "Unreachable type " << type;
525 }
526
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100527 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100528}
529
Mark Mendell5f874182015-03-04 15:42:45 -0500530void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100531 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100532 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100533
534 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100535 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100536
Mark Mendell5f874182015-03-04 15:42:45 -0500537 if (is_baseline) {
538 blocked_core_registers_[EBP] = true;
539 blocked_core_registers_[ESI] = true;
540 blocked_core_registers_[EDI] = true;
541 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100542
543 UpdateBlockedPairRegisters();
544}
545
546void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
547 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
548 X86ManagedRegister current =
549 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
550 if (blocked_core_registers_[current.AsRegisterPairLow()]
551 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
552 blocked_register_pairs_[i] = true;
553 }
554 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100555}
556
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100557InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
558 : HGraphVisitor(graph),
559 assembler_(codegen->GetAssembler()),
560 codegen_(codegen) {}
561
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100562static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100563 return dwarf::Reg::X86Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100564}
565
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000566void CodeGeneratorX86::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100567 __ cfi().SetCurrentCFAOffset(kX86WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000568 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000569 bool skip_overflow_check =
570 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000571 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000572
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000573 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100574 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100575 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100576 }
577
Mark Mendell5f874182015-03-04 15:42:45 -0500578 if (HasEmptyFrame()) {
579 return;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000580 }
Mark Mendell5f874182015-03-04 15:42:45 -0500581
582 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
583 Register reg = kCoreCalleeSaves[i];
584 if (allocated_registers_.ContainsCoreRegister(reg)) {
585 __ pushl(reg);
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100586 __ cfi().AdjustCFAOffset(kX86WordSize);
587 __ cfi().RelOffset(DWARFReg(reg), 0);
Mark Mendell5f874182015-03-04 15:42:45 -0500588 }
589 }
590
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100591 int adjust = GetFrameSize() - FrameEntrySpillSize();
592 __ subl(ESP, Immediate(adjust));
593 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100594 __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000595}
596
597void CodeGeneratorX86::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100598 __ cfi().RememberState();
599 if (!HasEmptyFrame()) {
600 int adjust = GetFrameSize() - FrameEntrySpillSize();
601 __ addl(ESP, Immediate(adjust));
602 __ cfi().AdjustCFAOffset(-adjust);
Mark Mendell5f874182015-03-04 15:42:45 -0500603
David Srbeckyc34dc932015-04-12 09:27:43 +0100604 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
605 Register reg = kCoreCalleeSaves[i];
606 if (allocated_registers_.ContainsCoreRegister(reg)) {
607 __ popl(reg);
608 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize));
609 __ cfi().Restore(DWARFReg(reg));
610 }
Mark Mendell5f874182015-03-04 15:42:45 -0500611 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000612 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100613 __ ret();
614 __ cfi().RestoreState();
615 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000616}
617
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100618void CodeGeneratorX86::Bind(HBasicBlock* block) {
619 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000620}
621
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100622Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
623 switch (load->GetType()) {
624 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100625 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100626 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100627
628 case Primitive::kPrimInt:
629 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100630 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100631 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100632
633 case Primitive::kPrimBoolean:
634 case Primitive::kPrimByte:
635 case Primitive::kPrimChar:
636 case Primitive::kPrimShort:
637 case Primitive::kPrimVoid:
638 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700639 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100640 }
641
642 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700643 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100644}
645
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100646Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(Primitive::Type type) const {
647 switch (type) {
648 case Primitive::kPrimBoolean:
649 case Primitive::kPrimByte:
650 case Primitive::kPrimChar:
651 case Primitive::kPrimShort:
652 case Primitive::kPrimInt:
653 case Primitive::kPrimNot:
654 return Location::RegisterLocation(EAX);
655
656 case Primitive::kPrimLong:
657 return Location::RegisterPairLocation(EAX, EDX);
658
659 case Primitive::kPrimVoid:
660 return Location::NoLocation();
661
662 case Primitive::kPrimDouble:
663 case Primitive::kPrimFloat:
664 return Location::FpuRegisterLocation(XMM0);
665 }
Nicolas Geoffray0d1652e2015-06-03 12:12:19 +0100666
667 UNREACHABLE();
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100668}
669
670Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
671 return Location::RegisterLocation(kMethodRegisterArgument);
672}
673
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100674Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100675 switch (type) {
676 case Primitive::kPrimBoolean:
677 case Primitive::kPrimByte:
678 case Primitive::kPrimChar:
679 case Primitive::kPrimShort:
680 case Primitive::kPrimInt:
681 case Primitive::kPrimNot: {
682 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000683 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100684 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100685 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100686 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000687 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100688 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100689 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100690
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000691 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100692 uint32_t index = gp_index_;
693 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000694 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100695 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100696 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
697 calling_convention.GetRegisterPairAt(index));
698 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100699 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000700 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
701 }
702 }
703
704 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100705 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000706 stack_index_++;
707 if (index < calling_convention.GetNumberOfFpuRegisters()) {
708 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
709 } else {
710 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
711 }
712 }
713
714 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100715 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000716 stack_index_ += 2;
717 if (index < calling_convention.GetNumberOfFpuRegisters()) {
718 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
719 } else {
720 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100721 }
722 }
723
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100724 case Primitive::kPrimVoid:
725 LOG(FATAL) << "Unexpected parameter type " << type;
726 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100727 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100728 return Location();
729}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100730
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100731void CodeGeneratorX86::Move32(Location destination, Location source) {
732 if (source.Equals(destination)) {
733 return;
734 }
735 if (destination.IsRegister()) {
736 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000737 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100738 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000739 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100740 } else {
741 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000742 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100743 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100744 } else if (destination.IsFpuRegister()) {
745 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000746 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100747 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000748 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100749 } else {
750 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000751 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100752 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100753 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000754 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100755 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000756 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100757 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000758 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500759 } else if (source.IsConstant()) {
760 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000761 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -0500762 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100763 } else {
764 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100765 __ pushl(Address(ESP, source.GetStackIndex()));
766 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100767 }
768 }
769}
770
771void CodeGeneratorX86::Move64(Location destination, Location source) {
772 if (source.Equals(destination)) {
773 return;
774 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100775 if (destination.IsRegisterPair()) {
776 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000777 EmitParallelMoves(
778 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
779 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100780 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000781 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100782 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
783 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100784 } else if (source.IsFpuRegister()) {
785 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100786 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000787 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100788 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100789 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
790 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100791 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
792 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100793 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500794 if (source.IsFpuRegister()) {
795 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
796 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000797 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100798 } else {
799 LOG(FATAL) << "Unimplemented";
800 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100801 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000802 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100803 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000804 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100805 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100806 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100807 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100808 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000809 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000810 } else if (source.IsConstant()) {
811 HConstant* constant = source.GetConstant();
812 int64_t value;
813 if (constant->IsLongConstant()) {
814 value = constant->AsLongConstant()->GetValue();
815 } else {
816 DCHECK(constant->IsDoubleConstant());
Roland Levillainda4d79b2015-03-24 14:36:11 +0000817 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000818 }
819 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
820 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100821 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000822 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000823 EmitParallelMoves(
824 Location::StackSlot(source.GetStackIndex()),
825 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100826 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000827 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100828 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
829 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100830 }
831 }
832}
833
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100834void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000835 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100836 if (instruction->IsCurrentMethod()) {
837 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
838 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000839 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100840 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000841 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000842 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
843 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000844 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000845 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000846 } else if (location.IsStackSlot()) {
847 __ movl(Address(ESP, location.GetStackIndex()), imm);
848 } else {
849 DCHECK(location.IsConstant());
850 DCHECK_EQ(location.GetConstant(), const_to_move);
851 }
852 } else if (const_to_move->IsLongConstant()) {
853 int64_t value = const_to_move->AsLongConstant()->GetValue();
854 if (location.IsRegisterPair()) {
855 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
856 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
857 } else if (location.IsDoubleStackSlot()) {
858 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000859 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
860 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000861 } else {
862 DCHECK(location.IsConstant());
863 DCHECK_EQ(location.GetConstant(), instruction);
864 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100865 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000866 } else if (instruction->IsTemporary()) {
867 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000868 if (temp_location.IsStackSlot()) {
869 Move32(location, temp_location);
870 } else {
871 DCHECK(temp_location.IsDoubleStackSlot());
872 Move64(location, temp_location);
873 }
Roland Levillain476df552014-10-09 17:51:36 +0100874 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100875 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100876 switch (instruction->GetType()) {
877 case Primitive::kPrimBoolean:
878 case Primitive::kPrimByte:
879 case Primitive::kPrimChar:
880 case Primitive::kPrimShort:
881 case Primitive::kPrimInt:
882 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100883 case Primitive::kPrimFloat:
884 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100885 break;
886
887 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100888 case Primitive::kPrimDouble:
889 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100890 break;
891
892 default:
893 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
894 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000895 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100896 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100897 switch (instruction->GetType()) {
898 case Primitive::kPrimBoolean:
899 case Primitive::kPrimByte:
900 case Primitive::kPrimChar:
901 case Primitive::kPrimShort:
902 case Primitive::kPrimInt:
903 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100904 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000905 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100906 break;
907
908 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100909 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000910 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100911 break;
912
913 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100914 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100915 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000916 }
917}
918
Calin Juravle175dc732015-08-25 15:42:32 +0100919void CodeGeneratorX86::MoveConstant(Location location, int32_t value) {
920 DCHECK(location.IsRegister());
921 __ movl(location.AsRegister<Register>(), Immediate(value));
922}
923
David Brazdilfc6a86a2015-06-26 10:33:45 +0000924void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100925 DCHECK(!successor->IsExitBlock());
926
927 HBasicBlock* block = got->GetBlock();
928 HInstruction* previous = got->GetPrevious();
929
930 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000931 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100932 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
933 return;
934 }
935
936 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
937 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
938 }
939 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000940 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000941 }
942}
943
David Brazdilfc6a86a2015-06-26 10:33:45 +0000944void LocationsBuilderX86::VisitGoto(HGoto* got) {
945 got->SetLocations(nullptr);
946}
947
948void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
949 HandleGoto(got, got->GetSuccessor());
950}
951
952void LocationsBuilderX86::VisitTryBoundary(HTryBoundary* try_boundary) {
953 try_boundary->SetLocations(nullptr);
954}
955
956void InstructionCodeGeneratorX86::VisitTryBoundary(HTryBoundary* try_boundary) {
957 HBasicBlock* successor = try_boundary->GetNormalFlowSuccessor();
958 if (!successor->IsExitBlock()) {
959 HandleGoto(try_boundary, successor);
960 }
961}
962
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000963void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000964 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000965}
966
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000967void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700968 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000969}
970
Mark Mendellc4701932015-04-10 13:18:51 -0400971void InstructionCodeGeneratorX86::GenerateFPJumps(HCondition* cond,
972 Label* true_label,
973 Label* false_label) {
Roland Levillain4fa13f62015-07-06 18:11:54 +0100974 if (cond->IsFPConditionTrueIfNaN()) {
975 __ j(kUnordered, true_label);
976 } else if (cond->IsFPConditionFalseIfNaN()) {
977 __ j(kUnordered, false_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400978 }
Roland Levillain4fa13f62015-07-06 18:11:54 +0100979 __ j(X86UnsignedOrFPCondition(cond->GetCondition()), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -0400980}
981
982void InstructionCodeGeneratorX86::GenerateLongComparesAndJumps(HCondition* cond,
983 Label* true_label,
984 Label* false_label) {
985 LocationSummary* locations = cond->GetLocations();
986 Location left = locations->InAt(0);
987 Location right = locations->InAt(1);
988 IfCondition if_cond = cond->GetCondition();
989
Mark Mendellc4701932015-04-10 13:18:51 -0400990 Register left_high = left.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +0100991 Register left_low = left.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -0400992 IfCondition true_high_cond = if_cond;
993 IfCondition false_high_cond = cond->GetOppositeCondition();
Roland Levillain4fa13f62015-07-06 18:11:54 +0100994 Condition final_condition = X86UnsignedOrFPCondition(if_cond);
Mark Mendellc4701932015-04-10 13:18:51 -0400995
996 // Set the conditions for the test, remembering that == needs to be
997 // decided using the low words.
998 switch (if_cond) {
999 case kCondEQ:
Mark Mendellc4701932015-04-10 13:18:51 -04001000 case kCondNE:
Roland Levillain4fa13f62015-07-06 18:11:54 +01001001 // Nothing to do.
Mark Mendellc4701932015-04-10 13:18:51 -04001002 break;
1003 case kCondLT:
1004 false_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001005 break;
1006 case kCondLE:
1007 true_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001008 break;
1009 case kCondGT:
1010 false_high_cond = kCondLT;
Mark Mendellc4701932015-04-10 13:18:51 -04001011 break;
1012 case kCondGE:
1013 true_high_cond = kCondGT;
Mark Mendellc4701932015-04-10 13:18:51 -04001014 break;
1015 }
1016
1017 if (right.IsConstant()) {
1018 int64_t value = right.GetConstant()->AsLongConstant()->GetValue();
Mark Mendellc4701932015-04-10 13:18:51 -04001019 int32_t val_high = High32Bits(value);
Roland Levillain4fa13f62015-07-06 18:11:54 +01001020 int32_t val_low = Low32Bits(value);
Mark Mendellc4701932015-04-10 13:18:51 -04001021
1022 if (val_high == 0) {
1023 __ testl(left_high, left_high);
1024 } else {
1025 __ cmpl(left_high, Immediate(val_high));
1026 }
1027 if (if_cond == kCondNE) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001028 __ j(X86SignedCondition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001029 } else if (if_cond == kCondEQ) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001030 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001031 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001032 __ j(X86SignedCondition(true_high_cond), true_label);
1033 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001034 }
1035 // Must be equal high, so compare the lows.
1036 if (val_low == 0) {
1037 __ testl(left_low, left_low);
1038 } else {
1039 __ cmpl(left_low, Immediate(val_low));
1040 }
1041 } else {
Mark Mendellc4701932015-04-10 13:18:51 -04001042 Register right_high = right.AsRegisterPairHigh<Register>();
Roland Levillain4fa13f62015-07-06 18:11:54 +01001043 Register right_low = right.AsRegisterPairLow<Register>();
Mark Mendellc4701932015-04-10 13:18:51 -04001044
1045 __ cmpl(left_high, right_high);
1046 if (if_cond == kCondNE) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001047 __ j(X86SignedCondition(true_high_cond), true_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001048 } else if (if_cond == kCondEQ) {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001049 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001050 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001051 __ j(X86SignedCondition(true_high_cond), true_label);
1052 __ j(X86SignedCondition(false_high_cond), false_label);
Mark Mendellc4701932015-04-10 13:18:51 -04001053 }
1054 // Must be equal high, so compare the lows.
1055 __ cmpl(left_low, right_low);
1056 }
1057 // The last comparison might be unsigned.
1058 __ j(final_condition, true_label);
1059}
1060
1061void InstructionCodeGeneratorX86::GenerateCompareTestAndBranch(HIf* if_instr,
1062 HCondition* condition,
1063 Label* true_target,
1064 Label* false_target,
1065 Label* always_true_target) {
1066 LocationSummary* locations = condition->GetLocations();
1067 Location left = locations->InAt(0);
1068 Location right = locations->InAt(1);
1069
1070 // We don't want true_target as a nullptr.
1071 if (true_target == nullptr) {
1072 true_target = always_true_target;
1073 }
1074 bool falls_through = (false_target == nullptr);
1075
1076 // FP compares don't like null false_targets.
1077 if (false_target == nullptr) {
1078 false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1079 }
1080
1081 Primitive::Type type = condition->InputAt(0)->GetType();
1082 switch (type) {
1083 case Primitive::kPrimLong:
1084 GenerateLongComparesAndJumps(condition, true_target, false_target);
1085 break;
1086 case Primitive::kPrimFloat:
Mark Mendellc4701932015-04-10 13:18:51 -04001087 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1088 GenerateFPJumps(condition, true_target, false_target);
1089 break;
1090 case Primitive::kPrimDouble:
Mark Mendellc4701932015-04-10 13:18:51 -04001091 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
1092 GenerateFPJumps(condition, true_target, false_target);
1093 break;
1094 default:
1095 LOG(FATAL) << "Unexpected compare type " << type;
1096 }
1097
1098 if (!falls_through) {
1099 __ jmp(false_target);
1100 }
1101}
1102
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001103void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
1104 Label* true_target,
1105 Label* false_target,
1106 Label* always_true_target) {
1107 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001108 if (cond->IsIntConstant()) {
1109 // Constant condition, statically compared against 1.
1110 int32_t cond_value = cond->AsIntConstant()->GetValue();
1111 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001112 if (always_true_target != nullptr) {
1113 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001114 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001115 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +01001116 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001117 DCHECK_EQ(cond_value, 0);
1118 }
1119 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001120 bool is_materialized =
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001121 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
1122 // Moves do not affect the eflags register, so if the condition is
1123 // evaluated just before the if, we don't need to evaluate it
Mark Mendellc4701932015-04-10 13:18:51 -04001124 // again. We can't use the eflags on long/FP conditions if they are
1125 // materialized due to the complex branching.
1126 Primitive::Type type = cond->IsCondition() ? cond->InputAt(0)->GetType() : Primitive::kPrimInt;
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001127 bool eflags_set = cond->IsCondition()
Mark Mendellc4701932015-04-10 13:18:51 -04001128 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction)
Roland Levillain4fa13f62015-07-06 18:11:54 +01001129 && (type != Primitive::kPrimLong && !Primitive::IsFloatingPointType(type));
1130 if (is_materialized) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001131 if (!eflags_set) {
1132 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001133 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001134 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001135 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001136 } else {
1137 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
1138 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001139 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001140 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001141 __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001142 }
1143 } else {
Roland Levillain4fa13f62015-07-06 18:11:54 +01001144 // Condition has not been materialized, use its inputs as the
1145 // comparison and its condition as the branch condition.
1146
Mark Mendellc4701932015-04-10 13:18:51 -04001147 // Is this a long or FP comparison that has been folded into the HCondition?
1148 if (type == Primitive::kPrimLong || Primitive::IsFloatingPointType(type)) {
1149 // Generate the comparison directly.
1150 GenerateCompareTestAndBranch(instruction->AsIf(),
1151 cond->AsCondition(),
1152 true_target,
1153 false_target,
1154 always_true_target);
1155 return;
1156 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001157
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001158 Location lhs = cond->GetLocations()->InAt(0);
1159 Location rhs = cond->GetLocations()->InAt(1);
1160 // LHS is guaranteed to be in a register (see
1161 // LocationsBuilderX86::VisitCondition).
1162 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001163 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001164 } else if (rhs.IsConstant()) {
Calin Juravleb3306642015-04-20 18:30:42 +01001165 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -05001166 if (constant == 0) {
1167 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1168 } else {
1169 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1170 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001171 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001172 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001173 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001174 __ j(X86SignedCondition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -07001175 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001176 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001177 if (false_target != nullptr) {
1178 __ jmp(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001179 }
1180}
1181
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001182void LocationsBuilderX86::VisitIf(HIf* if_instr) {
1183 LocationSummary* locations =
1184 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
1185 HInstruction* cond = if_instr->InputAt(0);
1186 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
1187 locations->SetInAt(0, Location::Any());
1188 }
1189}
1190
1191void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
1192 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
1193 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
1194 Label* always_true_target = true_target;
1195 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1196 if_instr->IfTrueSuccessor())) {
1197 always_true_target = nullptr;
1198 }
1199 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
1200 if_instr->IfFalseSuccessor())) {
1201 false_target = nullptr;
1202 }
1203 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
1204}
1205
1206void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
1207 LocationSummary* locations = new (GetGraph()->GetArena())
1208 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
1209 HInstruction* cond = deoptimize->InputAt(0);
1210 DCHECK(cond->IsCondition());
1211 if (cond->AsCondition()->NeedsMaterialization()) {
1212 locations->SetInAt(0, Location::Any());
1213 }
1214}
1215
1216void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07001217 SlowPathCode* slow_path = new (GetGraph()->GetArena())
Mingyao Yangd43b3ac2015-04-01 14:03:04 -07001218 DeoptimizationSlowPathX86(deoptimize);
1219 codegen_->AddSlowPath(slow_path);
1220 Label* slow_path_entry = slow_path->GetEntryLabel();
1221 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
1222}
1223
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001224void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001225 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001226}
1227
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001228void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
1229 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001230}
1231
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001232void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001233 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001234}
1235
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001236void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +01001237 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001238 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001239}
1240
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001241void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001242 LocationSummary* locations =
1243 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001244 switch (store->InputAt(1)->GetType()) {
1245 case Primitive::kPrimBoolean:
1246 case Primitive::kPrimByte:
1247 case Primitive::kPrimChar:
1248 case Primitive::kPrimShort:
1249 case Primitive::kPrimInt:
1250 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001251 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001252 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
1253 break;
1254
1255 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001256 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001257 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1258 break;
1259
1260 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001261 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001262 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001263}
1264
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001265void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001266 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001267}
1268
Roland Levillain0d37cd02015-05-27 16:39:19 +01001269void LocationsBuilderX86::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001270 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001271 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Mark Mendellc4701932015-04-10 13:18:51 -04001272 // Handle the long/FP comparisons made in instruction simplification.
1273 switch (cond->InputAt(0)->GetType()) {
1274 case Primitive::kPrimLong: {
1275 locations->SetInAt(0, Location::RequiresRegister());
1276 locations->SetInAt(1, Location::RegisterOrConstant(cond->InputAt(1)));
1277 if (cond->NeedsMaterialization()) {
1278 locations->SetOut(Location::RequiresRegister());
1279 }
1280 break;
1281 }
1282 case Primitive::kPrimFloat:
1283 case Primitive::kPrimDouble: {
1284 locations->SetInAt(0, Location::RequiresFpuRegister());
1285 locations->SetInAt(1, Location::RequiresFpuRegister());
1286 if (cond->NeedsMaterialization()) {
1287 locations->SetOut(Location::RequiresRegister());
1288 }
1289 break;
1290 }
1291 default:
1292 locations->SetInAt(0, Location::RequiresRegister());
1293 locations->SetInAt(1, Location::Any());
1294 if (cond->NeedsMaterialization()) {
1295 // We need a byte register.
1296 locations->SetOut(Location::RegisterLocation(ECX));
1297 }
1298 break;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001299 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001300}
1301
Roland Levillain0d37cd02015-05-27 16:39:19 +01001302void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
Mark Mendellc4701932015-04-10 13:18:51 -04001303 if (!cond->NeedsMaterialization()) {
1304 return;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001305 }
Mark Mendellc4701932015-04-10 13:18:51 -04001306
1307 LocationSummary* locations = cond->GetLocations();
1308 Location lhs = locations->InAt(0);
1309 Location rhs = locations->InAt(1);
1310 Register reg = locations->Out().AsRegister<Register>();
1311 Label true_label, false_label;
1312
1313 switch (cond->InputAt(0)->GetType()) {
1314 default: {
1315 // Integer case.
1316
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01001317 // Clear output register: setb only sets the low byte.
Mark Mendellc4701932015-04-10 13:18:51 -04001318 __ xorl(reg, reg);
1319
1320 if (rhs.IsRegister()) {
1321 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
1322 } else if (rhs.IsConstant()) {
1323 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
1324 if (constant == 0) {
1325 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1326 } else {
1327 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1328 }
1329 } else {
1330 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
1331 }
Roland Levillain4fa13f62015-07-06 18:11:54 +01001332 __ setb(X86SignedCondition(cond->GetCondition()), reg);
Mark Mendellc4701932015-04-10 13:18:51 -04001333 return;
1334 }
1335 case Primitive::kPrimLong:
1336 GenerateLongComparesAndJumps(cond, &true_label, &false_label);
1337 break;
1338 case Primitive::kPrimFloat:
1339 __ ucomiss(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1340 GenerateFPJumps(cond, &true_label, &false_label);
1341 break;
1342 case Primitive::kPrimDouble:
1343 __ ucomisd(lhs.AsFpuRegister<XmmRegister>(), rhs.AsFpuRegister<XmmRegister>());
1344 GenerateFPJumps(cond, &true_label, &false_label);
1345 break;
1346 }
1347
1348 // Convert the jumps into the result.
Mark Mendell0c9497d2015-08-21 09:30:05 -04001349 NearLabel done_label;
Mark Mendellc4701932015-04-10 13:18:51 -04001350
Roland Levillain4fa13f62015-07-06 18:11:54 +01001351 // False case: result = 0.
Mark Mendellc4701932015-04-10 13:18:51 -04001352 __ Bind(&false_label);
1353 __ xorl(reg, reg);
1354 __ jmp(&done_label);
1355
Roland Levillain4fa13f62015-07-06 18:11:54 +01001356 // True case: result = 1.
Mark Mendellc4701932015-04-10 13:18:51 -04001357 __ Bind(&true_label);
1358 __ movl(reg, Immediate(1));
1359 __ Bind(&done_label);
Dave Allison20dfc792014-06-16 20:44:29 -07001360}
1361
1362void LocationsBuilderX86::VisitEqual(HEqual* comp) {
1363 VisitCondition(comp);
1364}
1365
1366void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
1367 VisitCondition(comp);
1368}
1369
1370void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
1371 VisitCondition(comp);
1372}
1373
1374void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
1375 VisitCondition(comp);
1376}
1377
1378void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
1379 VisitCondition(comp);
1380}
1381
1382void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
1383 VisitCondition(comp);
1384}
1385
1386void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1387 VisitCondition(comp);
1388}
1389
1390void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1391 VisitCondition(comp);
1392}
1393
1394void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
1395 VisitCondition(comp);
1396}
1397
1398void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
1399 VisitCondition(comp);
1400}
1401
1402void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1403 VisitCondition(comp);
1404}
1405
1406void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1407 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001408}
1409
1410void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001411 LocationSummary* locations =
1412 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001413 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001414}
1415
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001416void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001417 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001418 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001419}
1420
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001421void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1422 LocationSummary* locations =
1423 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1424 locations->SetOut(Location::ConstantLocation(constant));
1425}
1426
1427void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1428 // Will be generated at use site.
1429 UNUSED(constant);
1430}
1431
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001432void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001433 LocationSummary* locations =
1434 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001435 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001436}
1437
1438void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1439 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001440 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001441}
1442
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001443void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1444 LocationSummary* locations =
1445 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1446 locations->SetOut(Location::ConstantLocation(constant));
1447}
1448
1449void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1450 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001451 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001452}
1453
1454void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1455 LocationSummary* locations =
1456 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1457 locations->SetOut(Location::ConstantLocation(constant));
1458}
1459
1460void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1461 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001462 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001463}
1464
Calin Juravle27df7582015-04-17 19:12:31 +01001465void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1466 memory_barrier->SetLocations(nullptr);
1467}
1468
1469void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1470 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1471}
1472
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001473void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001474 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001475}
1476
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001477void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001478 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001479 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001480}
1481
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001482void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001483 LocationSummary* locations =
1484 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001485 switch (ret->InputAt(0)->GetType()) {
1486 case Primitive::kPrimBoolean:
1487 case Primitive::kPrimByte:
1488 case Primitive::kPrimChar:
1489 case Primitive::kPrimShort:
1490 case Primitive::kPrimInt:
1491 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001492 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001493 break;
1494
1495 case Primitive::kPrimLong:
1496 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001497 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001498 break;
1499
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001500 case Primitive::kPrimFloat:
1501 case Primitive::kPrimDouble:
1502 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001503 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001504 break;
1505
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001506 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001507 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001508 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001509}
1510
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001511void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001512 if (kIsDebugBuild) {
1513 switch (ret->InputAt(0)->GetType()) {
1514 case Primitive::kPrimBoolean:
1515 case Primitive::kPrimByte:
1516 case Primitive::kPrimChar:
1517 case Primitive::kPrimShort:
1518 case Primitive::kPrimInt:
1519 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001520 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001521 break;
1522
1523 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001524 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1525 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001526 break;
1527
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001528 case Primitive::kPrimFloat:
1529 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001530 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001531 break;
1532
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001533 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001534 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001535 }
1536 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001537 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001538}
1539
Calin Juravle175dc732015-08-25 15:42:32 +01001540void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1541 // The trampoline uses the same calling convention as dex calling conventions,
1542 // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
1543 // the method_idx.
1544 HandleInvoke(invoke);
1545}
1546
1547void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) {
1548 codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke);
1549}
1550
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001551void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001552 // When we do not run baseline, explicit clinit checks triggered by static
1553 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1554 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001555
Mark Mendellfb8d2792015-03-31 22:16:59 -04001556 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001557 if (intrinsic.TryDispatch(invoke)) {
1558 return;
1559 }
1560
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001561 HandleInvoke(invoke);
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001562
1563 if (codegen_->IsBaseline()) {
1564 // Baseline does not have enough registers if the current method also
1565 // needs a register. We therefore do not require a register for it, and let
1566 // the code generation of the invoke handle it.
1567 LocationSummary* locations = invoke->GetLocations();
1568 Location location = locations->InAt(invoke->GetCurrentMethodInputIndex());
1569 if (location.IsUnallocated() && location.GetPolicy() == Location::kRequiresRegister) {
1570 locations->SetInAt(invoke->GetCurrentMethodInputIndex(), Location::NoLocation());
1571 }
1572 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001573}
1574
Mark Mendell09ed1a32015-03-25 08:30:06 -04001575static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1576 if (invoke->GetLocations()->Intrinsified()) {
1577 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1578 intrinsic.Dispatch(invoke);
1579 return true;
1580 }
1581 return false;
1582}
1583
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001584void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001585 // When we do not run baseline, explicit clinit checks triggered by static
1586 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1587 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001588
Mark Mendell09ed1a32015-03-25 08:30:06 -04001589 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1590 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001591 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001592
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001593 LocationSummary* locations = invoke->GetLocations();
Mark Mendell09ed1a32015-03-25 08:30:06 -04001594 codegen_->GenerateStaticOrDirectCall(
Nicolas Geoffray94015b92015-06-04 18:21:04 +01001595 invoke, locations->HasTemps() ? locations->GetTemp(0) : Location::NoLocation());
Mingyao Yang8693fe12015-04-17 16:51:08 -07001596 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001597}
1598
1599void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1600 HandleInvoke(invoke);
1601}
1602
1603void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001604 InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001605 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001606}
1607
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001608void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001609 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1610 return;
1611 }
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001612
Andreas Gampebfb5ba92015-09-01 15:45:02 +00001613 codegen_->GenerateVirtualCall(invoke, invoke->GetLocations()->GetTemp(0));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001614 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001615 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001616}
1617
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001618void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1619 HandleInvoke(invoke);
1620 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001621 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001622}
1623
1624void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1625 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001626 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001627 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1628 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001629 LocationSummary* locations = invoke->GetLocations();
1630 Location receiver = locations->InAt(0);
1631 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1632
1633 // Set the hidden argument.
1634 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001635 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001636
1637 // temp = object->GetClass();
1638 if (receiver.IsStackSlot()) {
1639 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1640 __ movl(temp, Address(temp, class_offset));
1641 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001642 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001643 }
Roland Levillain4d027112015-07-01 15:41:14 +01001644 codegen_->MaybeRecordImplicitNullCheck(invoke);
1645 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001646 // temp = temp->GetImtEntryAt(method_offset);
1647 __ movl(temp, Address(temp, method_offset));
1648 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001649 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001650 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001651
1652 DCHECK(!codegen_->IsLeafMethod());
1653 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1654}
1655
Roland Levillain88cb1752014-10-20 16:36:47 +01001656void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1657 LocationSummary* locations =
1658 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1659 switch (neg->GetResultType()) {
1660 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001661 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001662 locations->SetInAt(0, Location::RequiresRegister());
1663 locations->SetOut(Location::SameAsFirstInput());
1664 break;
1665
Roland Levillain88cb1752014-10-20 16:36:47 +01001666 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001667 locations->SetInAt(0, Location::RequiresFpuRegister());
1668 locations->SetOut(Location::SameAsFirstInput());
1669 locations->AddTemp(Location::RequiresRegister());
1670 locations->AddTemp(Location::RequiresFpuRegister());
1671 break;
1672
Roland Levillain88cb1752014-10-20 16:36:47 +01001673 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001674 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001675 locations->SetOut(Location::SameAsFirstInput());
1676 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001677 break;
1678
1679 default:
1680 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1681 }
1682}
1683
1684void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1685 LocationSummary* locations = neg->GetLocations();
1686 Location out = locations->Out();
1687 Location in = locations->InAt(0);
1688 switch (neg->GetResultType()) {
1689 case Primitive::kPrimInt:
1690 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001691 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001692 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001693 break;
1694
1695 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001696 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001697 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001698 __ negl(out.AsRegisterPairLow<Register>());
1699 // Negation is similar to subtraction from zero. The least
1700 // significant byte triggers a borrow when it is different from
1701 // zero; to take it into account, add 1 to the most significant
1702 // byte if the carry flag (CF) is set to 1 after the first NEGL
1703 // operation.
1704 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1705 __ negl(out.AsRegisterPairHigh<Register>());
1706 break;
1707
Roland Levillain5368c212014-11-27 15:03:41 +00001708 case Primitive::kPrimFloat: {
1709 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001710 Register constant = locations->GetTemp(0).AsRegister<Register>();
1711 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001712 // Implement float negation with an exclusive or with value
1713 // 0x80000000 (mask for bit 31, representing the sign of a
1714 // single-precision floating-point number).
1715 __ movl(constant, Immediate(INT32_C(0x80000000)));
1716 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001717 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001718 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001719 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001720
Roland Levillain5368c212014-11-27 15:03:41 +00001721 case Primitive::kPrimDouble: {
1722 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001723 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001724 // Implement double negation with an exclusive or with value
1725 // 0x8000000000000000 (mask for bit 63, representing the sign of
1726 // a double-precision floating-point number).
1727 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001728 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001729 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001730 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001731
1732 default:
1733 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1734 }
1735}
1736
Roland Levillaindff1f282014-11-05 14:15:05 +00001737void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001738 Primitive::Type result_type = conversion->GetResultType();
1739 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001740 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001741
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001742 // The float-to-long and double-to-long type conversions rely on a
1743 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001744 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001745 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1746 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001747 ? LocationSummary::kCall
1748 : LocationSummary::kNoCall;
1749 LocationSummary* locations =
1750 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1751
David Brazdilb2bd1c52015-03-25 11:17:37 +00001752 // The Java language does not allow treating boolean as an integral type but
1753 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001754
Roland Levillaindff1f282014-11-05 14:15:05 +00001755 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001756 case Primitive::kPrimByte:
1757 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001758 case Primitive::kPrimBoolean:
1759 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001760 case Primitive::kPrimShort:
1761 case Primitive::kPrimInt:
1762 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001763 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001764 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1765 // Make the output overlap to please the register allocator. This greatly simplifies
1766 // the validation of the linear scan implementation
1767 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001768 break;
1769
1770 default:
1771 LOG(FATAL) << "Unexpected type conversion from " << input_type
1772 << " to " << result_type;
1773 }
1774 break;
1775
Roland Levillain01a8d712014-11-14 16:27:39 +00001776 case Primitive::kPrimShort:
1777 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001778 case Primitive::kPrimBoolean:
1779 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001780 case Primitive::kPrimByte:
1781 case Primitive::kPrimInt:
1782 case Primitive::kPrimChar:
1783 // Processing a Dex `int-to-short' instruction.
1784 locations->SetInAt(0, Location::Any());
1785 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1786 break;
1787
1788 default:
1789 LOG(FATAL) << "Unexpected type conversion from " << input_type
1790 << " to " << result_type;
1791 }
1792 break;
1793
Roland Levillain946e1432014-11-11 17:35:19 +00001794 case Primitive::kPrimInt:
1795 switch (input_type) {
1796 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001797 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001798 locations->SetInAt(0, Location::Any());
1799 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1800 break;
1801
1802 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001803 // Processing a Dex `float-to-int' instruction.
1804 locations->SetInAt(0, Location::RequiresFpuRegister());
1805 locations->SetOut(Location::RequiresRegister());
1806 locations->AddTemp(Location::RequiresFpuRegister());
1807 break;
1808
Roland Levillain946e1432014-11-11 17:35:19 +00001809 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001810 // Processing a Dex `double-to-int' instruction.
1811 locations->SetInAt(0, Location::RequiresFpuRegister());
1812 locations->SetOut(Location::RequiresRegister());
1813 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001814 break;
1815
1816 default:
1817 LOG(FATAL) << "Unexpected type conversion from " << input_type
1818 << " to " << result_type;
1819 }
1820 break;
1821
Roland Levillaindff1f282014-11-05 14:15:05 +00001822 case Primitive::kPrimLong:
1823 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001824 case Primitive::kPrimBoolean:
1825 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001826 case Primitive::kPrimByte:
1827 case Primitive::kPrimShort:
1828 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001829 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001830 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001831 locations->SetInAt(0, Location::RegisterLocation(EAX));
1832 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1833 break;
1834
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001835 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001836 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001837 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001838 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001839 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1840 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1841
Vladimir Marko949c91f2015-01-27 10:48:44 +00001842 // The runtime helper puts the result in EAX, EDX.
1843 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001844 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001845 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001846
1847 default:
1848 LOG(FATAL) << "Unexpected type conversion from " << input_type
1849 << " to " << result_type;
1850 }
1851 break;
1852
Roland Levillain981e4542014-11-14 11:47:14 +00001853 case Primitive::kPrimChar:
1854 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001855 case Primitive::kPrimBoolean:
1856 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001857 case Primitive::kPrimByte:
1858 case Primitive::kPrimShort:
1859 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001860 // Processing a Dex `int-to-char' instruction.
1861 locations->SetInAt(0, Location::Any());
1862 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1863 break;
1864
1865 default:
1866 LOG(FATAL) << "Unexpected type conversion from " << input_type
1867 << " to " << result_type;
1868 }
1869 break;
1870
Roland Levillaindff1f282014-11-05 14:15:05 +00001871 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001872 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001873 case Primitive::kPrimBoolean:
1874 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001875 case Primitive::kPrimByte:
1876 case Primitive::kPrimShort:
1877 case Primitive::kPrimInt:
1878 case Primitive::kPrimChar:
1879 // Processing a Dex `int-to-float' instruction.
1880 locations->SetInAt(0, Location::RequiresRegister());
1881 locations->SetOut(Location::RequiresFpuRegister());
1882 break;
1883
1884 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001885 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001886 locations->SetInAt(0, Location::Any());
1887 locations->SetOut(Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001888 break;
1889
Roland Levillaincff13742014-11-17 14:32:17 +00001890 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001891 // Processing a Dex `double-to-float' instruction.
1892 locations->SetInAt(0, Location::RequiresFpuRegister());
1893 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001894 break;
1895
1896 default:
1897 LOG(FATAL) << "Unexpected type conversion from " << input_type
1898 << " to " << result_type;
1899 };
1900 break;
1901
Roland Levillaindff1f282014-11-05 14:15:05 +00001902 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001903 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001904 case Primitive::kPrimBoolean:
1905 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001906 case Primitive::kPrimByte:
1907 case Primitive::kPrimShort:
1908 case Primitive::kPrimInt:
1909 case Primitive::kPrimChar:
1910 // Processing a Dex `int-to-double' instruction.
1911 locations->SetInAt(0, Location::RequiresRegister());
1912 locations->SetOut(Location::RequiresFpuRegister());
1913 break;
1914
1915 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001916 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001917 locations->SetInAt(0, Location::Any());
1918 locations->SetOut(Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001919 break;
1920
Roland Levillaincff13742014-11-17 14:32:17 +00001921 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001922 // Processing a Dex `float-to-double' instruction.
1923 locations->SetInAt(0, Location::RequiresFpuRegister());
1924 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001925 break;
1926
1927 default:
1928 LOG(FATAL) << "Unexpected type conversion from " << input_type
1929 << " to " << result_type;
1930 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001931 break;
1932
1933 default:
1934 LOG(FATAL) << "Unexpected type conversion from " << input_type
1935 << " to " << result_type;
1936 }
1937}
1938
1939void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
1940 LocationSummary* locations = conversion->GetLocations();
1941 Location out = locations->Out();
1942 Location in = locations->InAt(0);
1943 Primitive::Type result_type = conversion->GetResultType();
1944 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001945 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001946 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001947 case Primitive::kPrimByte:
1948 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001949 case Primitive::kPrimBoolean:
1950 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001951 case Primitive::kPrimShort:
1952 case Primitive::kPrimInt:
1953 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001954 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001955 if (in.IsRegister()) {
1956 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001957 } else {
1958 DCHECK(in.GetConstant()->IsIntConstant());
1959 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1960 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
1961 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00001962 break;
1963
1964 default:
1965 LOG(FATAL) << "Unexpected type conversion from " << input_type
1966 << " to " << result_type;
1967 }
1968 break;
1969
Roland Levillain01a8d712014-11-14 16:27:39 +00001970 case Primitive::kPrimShort:
1971 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001972 case Primitive::kPrimBoolean:
1973 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001974 case Primitive::kPrimByte:
1975 case Primitive::kPrimInt:
1976 case Primitive::kPrimChar:
1977 // Processing a Dex `int-to-short' instruction.
1978 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001979 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001980 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001981 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00001982 } else {
1983 DCHECK(in.GetConstant()->IsIntConstant());
1984 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001985 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00001986 }
1987 break;
1988
1989 default:
1990 LOG(FATAL) << "Unexpected type conversion from " << input_type
1991 << " to " << result_type;
1992 }
1993 break;
1994
Roland Levillain946e1432014-11-11 17:35:19 +00001995 case Primitive::kPrimInt:
1996 switch (input_type) {
1997 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001998 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001999 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002000 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00002001 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002002 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00002003 } else {
2004 DCHECK(in.IsConstant());
2005 DCHECK(in.GetConstant()->IsLongConstant());
2006 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002007 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00002008 }
2009 break;
2010
Roland Levillain3f8f9362014-12-02 17:45:01 +00002011 case Primitive::kPrimFloat: {
2012 // Processing a Dex `float-to-int' instruction.
2013 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2014 Register output = out.AsRegister<Register>();
2015 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002016 NearLabel done, nan;
Roland Levillain3f8f9362014-12-02 17:45:01 +00002017
2018 __ movl(output, Immediate(kPrimIntMax));
2019 // temp = int-to-float(output)
2020 __ cvtsi2ss(temp, output);
2021 // if input >= temp goto done
2022 __ comiss(input, temp);
2023 __ j(kAboveEqual, &done);
2024 // if input == NaN goto nan
2025 __ j(kUnordered, &nan);
2026 // output = float-to-int-truncate(input)
2027 __ cvttss2si(output, input);
2028 __ jmp(&done);
2029 __ Bind(&nan);
2030 // output = 0
2031 __ xorl(output, output);
2032 __ Bind(&done);
2033 break;
2034 }
2035
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002036 case Primitive::kPrimDouble: {
2037 // Processing a Dex `double-to-int' instruction.
2038 XmmRegister input = in.AsFpuRegister<XmmRegister>();
2039 Register output = out.AsRegister<Register>();
2040 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Mark Mendell0c9497d2015-08-21 09:30:05 -04002041 NearLabel done, nan;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002042
2043 __ movl(output, Immediate(kPrimIntMax));
2044 // temp = int-to-double(output)
2045 __ cvtsi2sd(temp, output);
2046 // if input >= temp goto done
2047 __ comisd(input, temp);
2048 __ j(kAboveEqual, &done);
2049 // if input == NaN goto nan
2050 __ j(kUnordered, &nan);
2051 // output = double-to-int-truncate(input)
2052 __ cvttsd2si(output, input);
2053 __ jmp(&done);
2054 __ Bind(&nan);
2055 // output = 0
2056 __ xorl(output, output);
2057 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00002058 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002059 }
Roland Levillain946e1432014-11-11 17:35:19 +00002060
2061 default:
2062 LOG(FATAL) << "Unexpected type conversion from " << input_type
2063 << " to " << result_type;
2064 }
2065 break;
2066
Roland Levillaindff1f282014-11-05 14:15:05 +00002067 case Primitive::kPrimLong:
2068 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002069 case Primitive::kPrimBoolean:
2070 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00002071 case Primitive::kPrimByte:
2072 case Primitive::kPrimShort:
2073 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00002074 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00002075 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00002076 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
2077 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00002078 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00002079 __ cdq();
2080 break;
2081
2082 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00002083 // Processing a Dex `float-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002084 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l),
2085 conversion,
2086 conversion->GetDexPc(),
2087 nullptr);
Roland Levillain624279f2014-12-04 11:54:28 +00002088 break;
2089
Roland Levillaindff1f282014-11-05 14:15:05 +00002090 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00002091 // Processing a Dex `double-to-long' instruction.
Alexandre Rames8158f282015-08-07 10:26:17 +01002092 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l),
2093 conversion,
2094 conversion->GetDexPc(),
2095 nullptr);
Roland Levillaindff1f282014-11-05 14:15:05 +00002096 break;
2097
2098 default:
2099 LOG(FATAL) << "Unexpected type conversion from " << input_type
2100 << " to " << result_type;
2101 }
2102 break;
2103
Roland Levillain981e4542014-11-14 11:47:14 +00002104 case Primitive::kPrimChar:
2105 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002106 case Primitive::kPrimBoolean:
2107 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00002108 case Primitive::kPrimByte:
2109 case Primitive::kPrimShort:
2110 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00002111 // Processing a Dex `Process a Dex `int-to-char'' instruction.
2112 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002113 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00002114 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002115 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00002116 } else {
2117 DCHECK(in.GetConstant()->IsIntConstant());
2118 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002119 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00002120 }
2121 break;
2122
2123 default:
2124 LOG(FATAL) << "Unexpected type conversion from " << input_type
2125 << " to " << result_type;
2126 }
2127 break;
2128
Roland Levillaindff1f282014-11-05 14:15:05 +00002129 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00002130 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002131 case Primitive::kPrimBoolean:
2132 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002133 case Primitive::kPrimByte:
2134 case Primitive::kPrimShort:
2135 case Primitive::kPrimInt:
2136 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002137 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002138 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002139 break;
2140
Roland Levillain6d0e4832014-11-27 18:31:21 +00002141 case Primitive::kPrimLong: {
2142 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002143 size_t adjustment = 0;
Roland Levillain6d0e4832014-11-27 18:31:21 +00002144
Roland Levillain232ade02015-04-20 15:14:36 +01002145 // Create stack space for the call to
2146 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
2147 // TODO: enhance register allocator to ask for stack temporaries.
2148 if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
2149 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2150 __ subl(ESP, Immediate(adjustment));
2151 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002152
Roland Levillain232ade02015-04-20 15:14:36 +01002153 // Load the value to the FP stack, using temporaries if needed.
2154 PushOntoFPStack(in, 0, adjustment, false, true);
2155
2156 if (out.IsStackSlot()) {
2157 __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
2158 } else {
2159 __ fstps(Address(ESP, 0));
2160 Location stack_temp = Location::StackSlot(0);
2161 codegen_->Move32(out, stack_temp);
2162 }
2163
2164 // Remove the temporary stack space we allocated.
2165 if (adjustment != 0) {
2166 __ addl(ESP, Immediate(adjustment));
2167 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00002168 break;
2169 }
2170
Roland Levillaincff13742014-11-17 14:32:17 +00002171 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002172 // Processing a Dex `double-to-float' instruction.
2173 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002174 break;
2175
2176 default:
2177 LOG(FATAL) << "Unexpected type conversion from " << input_type
2178 << " to " << result_type;
2179 };
2180 break;
2181
Roland Levillaindff1f282014-11-05 14:15:05 +00002182 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00002183 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00002184 case Primitive::kPrimBoolean:
2185 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00002186 case Primitive::kPrimByte:
2187 case Primitive::kPrimShort:
2188 case Primitive::kPrimInt:
2189 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00002190 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00002191 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00002192 break;
2193
Roland Levillain647b9ed2014-11-27 12:06:00 +00002194 case Primitive::kPrimLong: {
2195 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01002196 size_t adjustment = 0;
Roland Levillain647b9ed2014-11-27 12:06:00 +00002197
Roland Levillain232ade02015-04-20 15:14:36 +01002198 // Create stack space for the call to
2199 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
2200 // TODO: enhance register allocator to ask for stack temporaries.
2201 if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
2202 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
2203 __ subl(ESP, Immediate(adjustment));
2204 }
2205
2206 // Load the value to the FP stack, using temporaries if needed.
2207 PushOntoFPStack(in, 0, adjustment, false, true);
2208
2209 if (out.IsDoubleStackSlot()) {
2210 __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
2211 } else {
2212 __ fstpl(Address(ESP, 0));
2213 Location stack_temp = Location::DoubleStackSlot(0);
2214 codegen_->Move64(out, stack_temp);
2215 }
2216
2217 // Remove the temporary stack space we allocated.
2218 if (adjustment != 0) {
2219 __ addl(ESP, Immediate(adjustment));
2220 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00002221 break;
2222 }
2223
Roland Levillaincff13742014-11-17 14:32:17 +00002224 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00002225 // Processing a Dex `float-to-double' instruction.
2226 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00002227 break;
2228
2229 default:
2230 LOG(FATAL) << "Unexpected type conversion from " << input_type
2231 << " to " << result_type;
2232 };
Roland Levillaindff1f282014-11-05 14:15:05 +00002233 break;
2234
2235 default:
2236 LOG(FATAL) << "Unexpected type conversion from " << input_type
2237 << " to " << result_type;
2238 }
2239}
2240
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002241void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002242 LocationSummary* locations =
2243 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002244 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002245 case Primitive::kPrimInt: {
2246 locations->SetInAt(0, Location::RequiresRegister());
2247 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
2248 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2249 break;
2250 }
2251
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002252 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002253 locations->SetInAt(0, Location::RequiresRegister());
2254 locations->SetInAt(1, Location::Any());
2255 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002256 break;
2257 }
2258
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002259 case Primitive::kPrimFloat:
2260 case Primitive::kPrimDouble: {
2261 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002262 locations->SetInAt(1, Location::Any());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002263 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002264 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002265 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002266
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002267 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002268 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
2269 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002270 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002271}
2272
2273void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
2274 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002275 Location first = locations->InAt(0);
2276 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05002277 Location out = locations->Out();
2278
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002279 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002280 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002281 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002282 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2283 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
Mark Mendell33bf2452015-05-27 10:08:24 -04002284 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
2285 __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
Mark Mendell09b84632015-02-13 17:48:38 -05002286 } else {
2287 __ leal(out.AsRegister<Register>(), Address(
2288 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
2289 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002290 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05002291 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
2292 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
2293 __ addl(out.AsRegister<Register>(), Immediate(value));
2294 } else {
2295 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
2296 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002297 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05002298 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002299 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002300 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002301 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002302 }
2303
2304 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002305 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002306 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2307 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002308 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002309 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
2310 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002311 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002312 } else {
2313 DCHECK(second.IsConstant()) << second;
2314 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2315 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2316 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002317 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002318 break;
2319 }
2320
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002321 case Primitive::kPrimFloat: {
2322 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002323 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002324 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2325 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2326 DCHECK(!const_area->NeedsMaterialization());
2327 __ addss(first.AsFpuRegister<XmmRegister>(),
2328 codegen_->LiteralFloatAddress(
2329 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2330 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2331 } else {
2332 DCHECK(second.IsStackSlot());
2333 __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002334 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002335 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002336 }
2337
2338 case Primitive::kPrimDouble: {
2339 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002340 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Mark Mendell0616ae02015-04-17 12:49:27 -04002341 } else if (add->InputAt(1)->IsX86LoadFromConstantTable()) {
2342 HX86LoadFromConstantTable* const_area = add->InputAt(1)->AsX86LoadFromConstantTable();
2343 DCHECK(!const_area->NeedsMaterialization());
2344 __ addsd(first.AsFpuRegister<XmmRegister>(),
2345 codegen_->LiteralDoubleAddress(
2346 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2347 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2348 } else {
2349 DCHECK(second.IsDoubleStackSlot());
2350 __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002351 }
2352 break;
2353 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002354
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002355 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002356 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002357 }
2358}
2359
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002360void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002361 LocationSummary* locations =
2362 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002363 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002364 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002365 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002366 locations->SetInAt(0, Location::RequiresRegister());
2367 locations->SetInAt(1, Location::Any());
2368 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002369 break;
2370 }
Calin Juravle11351682014-10-23 15:38:15 +01002371 case Primitive::kPrimFloat:
2372 case Primitive::kPrimDouble: {
2373 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002374 locations->SetInAt(1, Location::Any());
Calin Juravle11351682014-10-23 15:38:15 +01002375 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002376 break;
Calin Juravle11351682014-10-23 15:38:15 +01002377 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002378
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002379 default:
Calin Juravle11351682014-10-23 15:38:15 +01002380 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002381 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002382}
2383
2384void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
2385 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002386 Location first = locations->InAt(0);
2387 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01002388 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002389 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002390 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002391 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002392 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002393 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002394 __ subl(first.AsRegister<Register>(),
2395 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002396 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002397 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002398 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002399 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002400 }
2401
2402 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002403 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01002404 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2405 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002406 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01002407 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002408 __ sbbl(first.AsRegisterPairHigh<Register>(),
2409 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002410 } else {
2411 DCHECK(second.IsConstant()) << second;
2412 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2413 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2414 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002415 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002416 break;
2417 }
2418
Calin Juravle11351682014-10-23 15:38:15 +01002419 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002420 if (second.IsFpuRegister()) {
2421 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2422 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2423 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2424 DCHECK(!const_area->NeedsMaterialization());
2425 __ subss(first.AsFpuRegister<XmmRegister>(),
2426 codegen_->LiteralFloatAddress(
2427 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2428 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2429 } else {
2430 DCHECK(second.IsStackSlot());
2431 __ subss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2432 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002433 break;
Calin Juravle11351682014-10-23 15:38:15 +01002434 }
2435
2436 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002437 if (second.IsFpuRegister()) {
2438 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2439 } else if (sub->InputAt(1)->IsX86LoadFromConstantTable()) {
2440 HX86LoadFromConstantTable* const_area = sub->InputAt(1)->AsX86LoadFromConstantTable();
2441 DCHECK(!const_area->NeedsMaterialization());
2442 __ subsd(first.AsFpuRegister<XmmRegister>(),
2443 codegen_->LiteralDoubleAddress(
2444 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2445 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2446 } else {
2447 DCHECK(second.IsDoubleStackSlot());
2448 __ subsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2449 }
Calin Juravle11351682014-10-23 15:38:15 +01002450 break;
2451 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002452
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002453 default:
Calin Juravle11351682014-10-23 15:38:15 +01002454 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002455 }
2456}
2457
Calin Juravle34bacdf2014-10-07 20:23:36 +01002458void LocationsBuilderX86::VisitMul(HMul* mul) {
2459 LocationSummary* locations =
2460 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2461 switch (mul->GetResultType()) {
2462 case Primitive::kPrimInt:
2463 locations->SetInAt(0, Location::RequiresRegister());
2464 locations->SetInAt(1, Location::Any());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002465 if (mul->InputAt(1)->IsIntConstant()) {
2466 // Can use 3 operand multiply.
2467 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2468 } else {
2469 locations->SetOut(Location::SameAsFirstInput());
2470 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002471 break;
2472 case Primitive::kPrimLong: {
2473 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002474 locations->SetInAt(1, Location::Any());
2475 locations->SetOut(Location::SameAsFirstInput());
2476 // Needed for imul on 32bits with 64bits output.
2477 locations->AddTemp(Location::RegisterLocation(EAX));
2478 locations->AddTemp(Location::RegisterLocation(EDX));
2479 break;
2480 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002481 case Primitive::kPrimFloat:
2482 case Primitive::kPrimDouble: {
2483 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002484 locations->SetInAt(1, Location::Any());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002485 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002486 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002487 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002488
2489 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002490 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002491 }
2492}
2493
2494void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2495 LocationSummary* locations = mul->GetLocations();
2496 Location first = locations->InAt(0);
2497 Location second = locations->InAt(1);
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002498 Location out = locations->Out();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002499
2500 switch (mul->GetResultType()) {
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002501 case Primitive::kPrimInt:
2502 // The constant may have ended up in a register, so test explicitly to avoid
2503 // problems where the output may not be the same as the first operand.
2504 if (mul->InputAt(1)->IsIntConstant()) {
2505 Immediate imm(mul->InputAt(1)->AsIntConstant()->GetValue());
2506 __ imull(out.AsRegister<Register>(), first.AsRegister<Register>(), imm);
2507 } else if (second.IsRegister()) {
2508 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002509 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002510 } else {
2511 DCHECK(second.IsStackSlot());
Mark Mendell4a2aa4a2015-07-27 16:13:10 -04002512 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002513 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002514 }
2515 break;
Calin Juravle34bacdf2014-10-07 20:23:36 +01002516
2517 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002518 Register in1_hi = first.AsRegisterPairHigh<Register>();
2519 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002520 Register eax = locations->GetTemp(0).AsRegister<Register>();
2521 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002522
2523 DCHECK_EQ(EAX, eax);
2524 DCHECK_EQ(EDX, edx);
2525
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002526 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002527 // output: in1
2528 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2529 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2530 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002531 if (second.IsConstant()) {
2532 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002533
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002534 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2535 int32_t low_value = Low32Bits(value);
2536 int32_t high_value = High32Bits(value);
2537 Immediate low(low_value);
2538 Immediate high(high_value);
2539
2540 __ movl(eax, high);
2541 // eax <- in1.lo * in2.hi
2542 __ imull(eax, in1_lo);
2543 // in1.hi <- in1.hi * in2.lo
2544 __ imull(in1_hi, low);
2545 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2546 __ addl(in1_hi, eax);
2547 // move in2_lo to eax to prepare for double precision
2548 __ movl(eax, low);
2549 // edx:eax <- in1.lo * in2.lo
2550 __ mull(in1_lo);
2551 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2552 __ addl(in1_hi, edx);
2553 // in1.lo <- (in1.lo * in2.lo)[31:0];
2554 __ movl(in1_lo, eax);
2555 } else if (second.IsRegisterPair()) {
2556 Register in2_hi = second.AsRegisterPairHigh<Register>();
2557 Register in2_lo = second.AsRegisterPairLow<Register>();
2558
2559 __ movl(eax, in2_hi);
2560 // eax <- in1.lo * in2.hi
2561 __ imull(eax, in1_lo);
2562 // in1.hi <- in1.hi * in2.lo
2563 __ imull(in1_hi, in2_lo);
2564 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2565 __ addl(in1_hi, eax);
2566 // move in1_lo to eax to prepare for double precision
2567 __ movl(eax, in1_lo);
2568 // edx:eax <- in1.lo * in2.lo
2569 __ mull(in2_lo);
2570 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2571 __ addl(in1_hi, edx);
2572 // in1.lo <- (in1.lo * in2.lo)[31:0];
2573 __ movl(in1_lo, eax);
2574 } else {
2575 DCHECK(second.IsDoubleStackSlot()) << second;
2576 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2577 Address in2_lo(ESP, second.GetStackIndex());
2578
2579 __ movl(eax, in2_hi);
2580 // eax <- in1.lo * in2.hi
2581 __ imull(eax, in1_lo);
2582 // in1.hi <- in1.hi * in2.lo
2583 __ imull(in1_hi, in2_lo);
2584 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2585 __ addl(in1_hi, eax);
2586 // move in1_lo to eax to prepare for double precision
2587 __ movl(eax, in1_lo);
2588 // edx:eax <- in1.lo * in2.lo
2589 __ mull(in2_lo);
2590 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2591 __ addl(in1_hi, edx);
2592 // in1.lo <- (in1.lo * in2.lo)[31:0];
2593 __ movl(in1_lo, eax);
2594 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002595
2596 break;
2597 }
2598
Calin Juravleb5bfa962014-10-21 18:02:24 +01002599 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002600 DCHECK(first.Equals(locations->Out()));
2601 if (second.IsFpuRegister()) {
2602 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2603 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2604 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2605 DCHECK(!const_area->NeedsMaterialization());
2606 __ mulss(first.AsFpuRegister<XmmRegister>(),
2607 codegen_->LiteralFloatAddress(
2608 const_area->GetConstant()->AsFloatConstant()->GetValue(),
2609 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2610 } else {
2611 DCHECK(second.IsStackSlot());
2612 __ mulss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2613 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002614 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002615 }
2616
2617 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002618 DCHECK(first.Equals(locations->Out()));
2619 if (second.IsFpuRegister()) {
2620 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2621 } else if (mul->InputAt(1)->IsX86LoadFromConstantTable()) {
2622 HX86LoadFromConstantTable* const_area = mul->InputAt(1)->AsX86LoadFromConstantTable();
2623 DCHECK(!const_area->NeedsMaterialization());
2624 __ mulsd(first.AsFpuRegister<XmmRegister>(),
2625 codegen_->LiteralDoubleAddress(
2626 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
2627 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
2628 } else {
2629 DCHECK(second.IsDoubleStackSlot());
2630 __ mulsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
2631 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002632 break;
2633 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002634
2635 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002636 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002637 }
2638}
2639
Roland Levillain232ade02015-04-20 15:14:36 +01002640void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
2641 uint32_t temp_offset,
2642 uint32_t stack_adjustment,
2643 bool is_fp,
2644 bool is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002645 if (source.IsStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002646 DCHECK(!is_wide);
2647 if (is_fp) {
2648 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2649 } else {
2650 __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2651 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002652 } else if (source.IsDoubleStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002653 DCHECK(is_wide);
2654 if (is_fp) {
2655 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2656 } else {
2657 __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2658 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002659 } else {
2660 // Write the value to the temporary location on the stack and load to FP stack.
Roland Levillain232ade02015-04-20 15:14:36 +01002661 if (!is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002662 Location stack_temp = Location::StackSlot(temp_offset);
2663 codegen_->Move32(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002664 if (is_fp) {
2665 __ flds(Address(ESP, temp_offset));
2666 } else {
2667 __ filds(Address(ESP, temp_offset));
2668 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002669 } else {
2670 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2671 codegen_->Move64(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002672 if (is_fp) {
2673 __ fldl(Address(ESP, temp_offset));
2674 } else {
2675 __ fildl(Address(ESP, temp_offset));
2676 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002677 }
2678 }
2679}
2680
2681void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2682 Primitive::Type type = rem->GetResultType();
2683 bool is_float = type == Primitive::kPrimFloat;
2684 size_t elem_size = Primitive::ComponentSize(type);
2685 LocationSummary* locations = rem->GetLocations();
2686 Location first = locations->InAt(0);
2687 Location second = locations->InAt(1);
2688 Location out = locations->Out();
2689
2690 // Create stack space for 2 elements.
2691 // TODO: enhance register allocator to ask for stack temporaries.
2692 __ subl(ESP, Immediate(2 * elem_size));
2693
2694 // Load the values to the FP stack in reverse order, using temporaries if needed.
Roland Levillain232ade02015-04-20 15:14:36 +01002695 const bool is_wide = !is_float;
2696 PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp */ true, is_wide);
2697 PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp */ true, is_wide);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002698
2699 // Loop doing FPREM until we stabilize.
Mark Mendell0c9497d2015-08-21 09:30:05 -04002700 NearLabel retry;
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002701 __ Bind(&retry);
2702 __ fprem();
2703
2704 // Move FP status to AX.
2705 __ fstsw();
2706
2707 // And see if the argument reduction is complete. This is signaled by the
2708 // C2 FPU flag bit set to 0.
2709 __ andl(EAX, Immediate(kC2ConditionMask));
2710 __ j(kNotEqual, &retry);
2711
2712 // We have settled on the final value. Retrieve it into an XMM register.
2713 // Store FP top of stack to real stack.
2714 if (is_float) {
2715 __ fsts(Address(ESP, 0));
2716 } else {
2717 __ fstl(Address(ESP, 0));
2718 }
2719
2720 // Pop the 2 items from the FP stack.
2721 __ fucompp();
2722
2723 // Load the value from the stack into an XMM register.
2724 DCHECK(out.IsFpuRegister()) << out;
2725 if (is_float) {
2726 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2727 } else {
2728 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2729 }
2730
2731 // And remove the temporary stack space we allocated.
2732 __ addl(ESP, Immediate(2 * elem_size));
2733}
2734
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002735
2736void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2737 DCHECK(instruction->IsDiv() || instruction->IsRem());
2738
2739 LocationSummary* locations = instruction->GetLocations();
2740 DCHECK(locations->InAt(1).IsConstant());
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002741 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002742
2743 Register out_register = locations->Out().AsRegister<Register>();
2744 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002745 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002746
2747 DCHECK(imm == 1 || imm == -1);
2748
2749 if (instruction->IsRem()) {
2750 __ xorl(out_register, out_register);
2751 } else {
2752 __ movl(out_register, input_register);
2753 if (imm == -1) {
2754 __ negl(out_register);
2755 }
2756 }
2757}
2758
2759
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002760void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002761 LocationSummary* locations = instruction->GetLocations();
2762
2763 Register out_register = locations->Out().AsRegister<Register>();
2764 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002765 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002766
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002767 DCHECK(IsPowerOfTwo(std::abs(imm)));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002768 Register num = locations->GetTemp(0).AsRegister<Register>();
2769
2770 __ leal(num, Address(input_register, std::abs(imm) - 1));
2771 __ testl(input_register, input_register);
2772 __ cmovl(kGreaterEqual, num, input_register);
2773 int shift = CTZ(imm);
2774 __ sarl(num, Immediate(shift));
2775
2776 if (imm < 0) {
2777 __ negl(num);
2778 }
2779
2780 __ movl(out_register, num);
2781}
2782
2783void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2784 DCHECK(instruction->IsDiv() || instruction->IsRem());
2785
2786 LocationSummary* locations = instruction->GetLocations();
2787 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2788
2789 Register eax = locations->InAt(0).AsRegister<Register>();
2790 Register out = locations->Out().AsRegister<Register>();
2791 Register num;
2792 Register edx;
2793
2794 if (instruction->IsDiv()) {
2795 edx = locations->GetTemp(0).AsRegister<Register>();
2796 num = locations->GetTemp(1).AsRegister<Register>();
2797 } else {
2798 edx = locations->Out().AsRegister<Register>();
2799 num = locations->GetTemp(0).AsRegister<Register>();
2800 }
2801
2802 DCHECK_EQ(EAX, eax);
2803 DCHECK_EQ(EDX, edx);
2804 if (instruction->IsDiv()) {
2805 DCHECK_EQ(EAX, out);
2806 } else {
2807 DCHECK_EQ(EDX, out);
2808 }
2809
2810 int64_t magic;
2811 int shift;
2812 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2813
Mark Mendell0c9497d2015-08-21 09:30:05 -04002814 NearLabel ndiv;
2815 NearLabel end;
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002816 // If numerator is 0, the result is 0, no computation needed.
2817 __ testl(eax, eax);
2818 __ j(kNotEqual, &ndiv);
2819
2820 __ xorl(out, out);
2821 __ jmp(&end);
2822
2823 __ Bind(&ndiv);
2824
2825 // Save the numerator.
2826 __ movl(num, eax);
2827
2828 // EAX = magic
2829 __ movl(eax, Immediate(magic));
2830
2831 // EDX:EAX = magic * numerator
2832 __ imull(num);
2833
2834 if (imm > 0 && magic < 0) {
2835 // EDX += num
2836 __ addl(edx, num);
2837 } else if (imm < 0 && magic > 0) {
2838 __ subl(edx, num);
2839 }
2840
2841 // Shift if needed.
2842 if (shift != 0) {
2843 __ sarl(edx, Immediate(shift));
2844 }
2845
2846 // EDX += 1 if EDX < 0
2847 __ movl(eax, edx);
2848 __ shrl(edx, Immediate(31));
2849 __ addl(edx, eax);
2850
2851 if (instruction->IsRem()) {
2852 __ movl(eax, num);
2853 __ imull(edx, Immediate(imm));
2854 __ subl(eax, edx);
2855 __ movl(edx, eax);
2856 } else {
2857 __ movl(eax, edx);
2858 }
2859 __ Bind(&end);
2860}
2861
Calin Juravlebacfec32014-11-14 15:54:36 +00002862void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2863 DCHECK(instruction->IsDiv() || instruction->IsRem());
2864
2865 LocationSummary* locations = instruction->GetLocations();
2866 Location out = locations->Out();
2867 Location first = locations->InAt(0);
2868 Location second = locations->InAt(1);
2869 bool is_div = instruction->IsDiv();
2870
2871 switch (instruction->GetResultType()) {
2872 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002873 DCHECK_EQ(EAX, first.AsRegister<Register>());
2874 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002875
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002876 if (instruction->InputAt(1)->IsIntConstant()) {
2877 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002878
2879 if (imm == 0) {
2880 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
2881 } else if (imm == 1 || imm == -1) {
2882 DivRemOneOrMinusOne(instruction);
2883 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002884 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002885 } else {
2886 DCHECK(imm <= -2 || imm >= 2);
2887 GenerateDivRemWithAnyConstant(instruction);
2888 }
2889 } else {
Andreas Gampe85b62f22015-09-09 13:15:38 -07002890 SlowPathCode* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002891 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002892 is_div);
2893 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002894
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002895 Register second_reg = second.AsRegister<Register>();
2896 // 0x80000000/-1 triggers an arithmetic exception!
2897 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2898 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002899
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002900 __ cmpl(second_reg, Immediate(-1));
2901 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002902
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002903 // edx:eax <- sign-extended of eax
2904 __ cdq();
2905 // eax = quotient, edx = remainder
2906 __ idivl(second_reg);
2907 __ Bind(slow_path->GetExitLabel());
2908 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002909 break;
2910 }
2911
2912 case Primitive::kPrimLong: {
2913 InvokeRuntimeCallingConvention calling_convention;
2914 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2915 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2916 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2917 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2918 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2919 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2920
2921 if (is_div) {
Alexandre Rames8158f282015-08-07 10:26:17 +01002922 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv),
2923 instruction,
2924 instruction->GetDexPc(),
2925 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002926 } else {
Alexandre Rames8158f282015-08-07 10:26:17 +01002927 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod),
2928 instruction,
2929 instruction->GetDexPc(),
2930 nullptr);
Calin Juravlebacfec32014-11-14 15:54:36 +00002931 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002932 break;
2933 }
2934
2935 default:
2936 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
2937 }
2938}
2939
Calin Juravle7c4954d2014-10-28 16:57:40 +00002940void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002941 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002942 ? LocationSummary::kCall
2943 : LocationSummary::kNoCall;
2944 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2945
Calin Juravle7c4954d2014-10-28 16:57:40 +00002946 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002947 case Primitive::kPrimInt: {
2948 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002949 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002950 locations->SetOut(Location::SameAsFirstInput());
2951 // Intel uses edx:eax as the dividend.
2952 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002953 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2954 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
2955 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002956 if (div->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002957 locations->AddTemp(Location::RequiresRegister());
2958 }
Calin Juravled0d48522014-11-04 16:40:20 +00002959 break;
2960 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002961 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002962 InvokeRuntimeCallingConvention calling_convention;
2963 locations->SetInAt(0, Location::RegisterPairLocation(
2964 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2965 locations->SetInAt(1, Location::RegisterPairLocation(
2966 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2967 // Runtime helper puts the result in EAX, EDX.
2968 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002969 break;
2970 }
2971 case Primitive::kPrimFloat:
2972 case Primitive::kPrimDouble: {
2973 locations->SetInAt(0, Location::RequiresFpuRegister());
Mark Mendell0616ae02015-04-17 12:49:27 -04002974 locations->SetInAt(1, Location::Any());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002975 locations->SetOut(Location::SameAsFirstInput());
2976 break;
2977 }
2978
2979 default:
2980 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2981 }
2982}
2983
2984void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
2985 LocationSummary* locations = div->GetLocations();
2986 Location first = locations->InAt(0);
2987 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002988
2989 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002990 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00002991 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002992 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002993 break;
2994 }
2995
2996 case Primitive::kPrimFloat: {
Mark Mendell0616ae02015-04-17 12:49:27 -04002997 if (second.IsFpuRegister()) {
2998 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
2999 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3000 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3001 DCHECK(!const_area->NeedsMaterialization());
3002 __ divss(first.AsFpuRegister<XmmRegister>(),
3003 codegen_->LiteralFloatAddress(
3004 const_area->GetConstant()->AsFloatConstant()->GetValue(),
3005 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3006 } else {
3007 DCHECK(second.IsStackSlot());
3008 __ divss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3009 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003010 break;
3011 }
3012
3013 case Primitive::kPrimDouble: {
Mark Mendell0616ae02015-04-17 12:49:27 -04003014 if (second.IsFpuRegister()) {
3015 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
3016 } else if (div->InputAt(1)->IsX86LoadFromConstantTable()) {
3017 HX86LoadFromConstantTable* const_area = div->InputAt(1)->AsX86LoadFromConstantTable();
3018 DCHECK(!const_area->NeedsMaterialization());
3019 __ divsd(first.AsFpuRegister<XmmRegister>(),
3020 codegen_->LiteralDoubleAddress(
3021 const_area->GetConstant()->AsDoubleConstant()->GetValue(),
3022 const_area->GetLocations()->InAt(0).AsRegister<Register>()));
3023 } else {
3024 DCHECK(second.IsDoubleStackSlot());
3025 __ divsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
3026 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00003027 break;
3028 }
3029
3030 default:
3031 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
3032 }
3033}
3034
Calin Juravlebacfec32014-11-14 15:54:36 +00003035void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00003036 Primitive::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003037
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003038 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
3039 ? LocationSummary::kCall
3040 : LocationSummary::kNoCall;
3041 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00003042
Calin Juravled2ec87d2014-12-08 14:24:46 +00003043 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00003044 case Primitive::kPrimInt: {
3045 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003046 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00003047 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003048 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
3049 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
3050 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01003051 if (rem->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01003052 locations->AddTemp(Location::RequiresRegister());
3053 }
Calin Juravlebacfec32014-11-14 15:54:36 +00003054 break;
3055 }
3056 case Primitive::kPrimLong: {
3057 InvokeRuntimeCallingConvention calling_convention;
3058 locations->SetInAt(0, Location::RegisterPairLocation(
3059 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
3060 locations->SetInAt(1, Location::RegisterPairLocation(
3061 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
3062 // Runtime helper puts the result in EAX, EDX.
3063 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
3064 break;
3065 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003066 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003067 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003068 locations->SetInAt(0, Location::Any());
3069 locations->SetInAt(1, Location::Any());
3070 locations->SetOut(Location::RequiresFpuRegister());
3071 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00003072 break;
3073 }
3074
3075 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00003076 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00003077 }
3078}
3079
3080void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
3081 Primitive::Type type = rem->GetResultType();
3082 switch (type) {
3083 case Primitive::kPrimInt:
3084 case Primitive::kPrimLong: {
3085 GenerateDivRemIntegral(rem);
3086 break;
3087 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003088 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00003089 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05003090 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00003091 break;
3092 }
3093 default:
3094 LOG(FATAL) << "Unexpected rem type " << type;
3095 }
3096}
3097
Calin Juravled0d48522014-11-04 16:40:20 +00003098void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00003099 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
3100 ? LocationSummary::kCallOnSlowPath
3101 : LocationSummary::kNoCall;
3102 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003103 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003104 case Primitive::kPrimByte:
3105 case Primitive::kPrimChar:
3106 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003107 case Primitive::kPrimInt: {
3108 locations->SetInAt(0, Location::Any());
3109 break;
3110 }
3111 case Primitive::kPrimLong: {
3112 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
3113 if (!instruction->IsConstant()) {
3114 locations->AddTemp(Location::RequiresRegister());
3115 }
3116 break;
3117 }
3118 default:
3119 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
3120 }
Calin Juravled0d48522014-11-04 16:40:20 +00003121 if (instruction->HasUses()) {
3122 locations->SetOut(Location::SameAsFirstInput());
3123 }
3124}
3125
3126void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07003127 SlowPathCode* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
Calin Juravled0d48522014-11-04 16:40:20 +00003128 codegen_->AddSlowPath(slow_path);
3129
3130 LocationSummary* locations = instruction->GetLocations();
3131 Location value = locations->InAt(0);
3132
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003133 switch (instruction->GetType()) {
Serguei Katkov8c0676c2015-08-03 13:55:33 +06003134 case Primitive::kPrimByte:
3135 case Primitive::kPrimChar:
3136 case Primitive::kPrimShort:
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003137 case Primitive::kPrimInt: {
3138 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003139 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003140 __ j(kEqual, slow_path->GetEntryLabel());
3141 } else if (value.IsStackSlot()) {
3142 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
3143 __ j(kEqual, slow_path->GetEntryLabel());
3144 } else {
3145 DCHECK(value.IsConstant()) << value;
3146 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
3147 __ jmp(slow_path->GetEntryLabel());
3148 }
3149 }
3150 break;
Calin Juravled0d48522014-11-04 16:40:20 +00003151 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003152 case Primitive::kPrimLong: {
3153 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003154 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00003155 __ movl(temp, value.AsRegisterPairLow<Register>());
3156 __ orl(temp, value.AsRegisterPairHigh<Register>());
3157 __ j(kEqual, slow_path->GetEntryLabel());
3158 } else {
3159 DCHECK(value.IsConstant()) << value;
3160 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
3161 __ jmp(slow_path->GetEntryLabel());
3162 }
3163 }
3164 break;
3165 }
3166 default:
3167 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00003168 }
Calin Juravled0d48522014-11-04 16:40:20 +00003169}
3170
Calin Juravle9aec02f2014-11-18 23:06:35 +00003171void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
3172 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3173
3174 LocationSummary* locations =
3175 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
3176
3177 switch (op->GetResultType()) {
Mark P Mendell73945692015-04-29 14:56:17 +00003178 case Primitive::kPrimInt:
Calin Juravle9aec02f2014-11-18 23:06:35 +00003179 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003180 // Can't have Location::Any() and output SameAsFirstInput()
Calin Juravle9aec02f2014-11-18 23:06:35 +00003181 locations->SetInAt(0, Location::RequiresRegister());
Mark P Mendell73945692015-04-29 14:56:17 +00003182 // The shift count needs to be in CL or a constant.
3183 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
Calin Juravle9aec02f2014-11-18 23:06:35 +00003184 locations->SetOut(Location::SameAsFirstInput());
3185 break;
3186 }
3187 default:
3188 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3189 }
3190}
3191
3192void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
3193 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
3194
3195 LocationSummary* locations = op->GetLocations();
3196 Location first = locations->InAt(0);
3197 Location second = locations->InAt(1);
3198 DCHECK(first.Equals(locations->Out()));
3199
3200 switch (op->GetResultType()) {
3201 case Primitive::kPrimInt: {
Mark P Mendell73945692015-04-29 14:56:17 +00003202 DCHECK(first.IsRegister());
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003203 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003204 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003205 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00003206 DCHECK_EQ(ECX, second_reg);
3207 if (op->IsShl()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003208 __ shll(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003209 } else if (op->IsShr()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003210 __ sarl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003211 } else {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003212 __ shrl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003213 }
3214 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003215 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue;
3216 if (shift == 0) {
3217 return;
3218 }
3219 Immediate imm(shift);
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003220 if (op->IsShl()) {
3221 __ shll(first_reg, imm);
3222 } else if (op->IsShr()) {
3223 __ sarl(first_reg, imm);
3224 } else {
3225 __ shrl(first_reg, imm);
Calin Juravle9aec02f2014-11-18 23:06:35 +00003226 }
3227 }
3228 break;
3229 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003230 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00003231 if (second.IsRegister()) {
3232 Register second_reg = second.AsRegister<Register>();
3233 DCHECK_EQ(ECX, second_reg);
3234 if (op->IsShl()) {
3235 GenerateShlLong(first, second_reg);
3236 } else if (op->IsShr()) {
3237 GenerateShrLong(first, second_reg);
3238 } else {
3239 GenerateUShrLong(first, second_reg);
3240 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003241 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00003242 // Shift by a constant.
3243 int shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue;
3244 // Nothing to do if the shift is 0, as the input is already the output.
3245 if (shift != 0) {
3246 if (op->IsShl()) {
3247 GenerateShlLong(first, shift);
3248 } else if (op->IsShr()) {
3249 GenerateShrLong(first, shift);
3250 } else {
3251 GenerateUShrLong(first, shift);
3252 }
3253 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00003254 }
3255 break;
3256 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00003257 default:
3258 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
3259 }
3260}
3261
Mark P Mendell73945692015-04-29 14:56:17 +00003262void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
3263 Register low = loc.AsRegisterPairLow<Register>();
3264 Register high = loc.AsRegisterPairHigh<Register>();
Mark Mendellba56d062015-05-05 21:34:03 -04003265 if (shift == 1) {
3266 // This is just an addition.
3267 __ addl(low, low);
3268 __ adcl(high, high);
3269 } else if (shift == 32) {
Mark P Mendell73945692015-04-29 14:56:17 +00003270 // Shift by 32 is easy. High gets low, and low gets 0.
3271 codegen_->EmitParallelMoves(
3272 loc.ToLow(),
3273 loc.ToHigh(),
3274 Primitive::kPrimInt,
3275 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3276 loc.ToLow(),
3277 Primitive::kPrimInt);
3278 } else if (shift > 32) {
3279 // Low part becomes 0. High part is low part << (shift-32).
3280 __ movl(high, low);
3281 __ shll(high, Immediate(shift - 32));
3282 __ xorl(low, low);
3283 } else {
3284 // Between 1 and 31.
3285 __ shld(high, low, Immediate(shift));
3286 __ shll(low, Immediate(shift));
3287 }
3288}
3289
Calin Juravle9aec02f2014-11-18 23:06:35 +00003290void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003291 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003292 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
3293 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
3294 __ testl(shifter, Immediate(32));
3295 __ j(kEqual, &done);
3296 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
3297 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
3298 __ Bind(&done);
3299}
3300
Mark P Mendell73945692015-04-29 14:56:17 +00003301void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
3302 Register low = loc.AsRegisterPairLow<Register>();
3303 Register high = loc.AsRegisterPairHigh<Register>();
3304 if (shift == 32) {
3305 // Need to copy the sign.
3306 DCHECK_NE(low, high);
3307 __ movl(low, high);
3308 __ sarl(high, Immediate(31));
3309 } else if (shift > 32) {
3310 DCHECK_NE(low, high);
3311 // High part becomes sign. Low part is shifted by shift - 32.
3312 __ movl(low, high);
3313 __ sarl(high, Immediate(31));
3314 __ sarl(low, Immediate(shift - 32));
3315 } else {
3316 // Between 1 and 31.
3317 __ shrd(low, high, Immediate(shift));
3318 __ sarl(high, Immediate(shift));
3319 }
3320}
3321
Calin Juravle9aec02f2014-11-18 23:06:35 +00003322void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003323 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003324 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3325 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
3326 __ testl(shifter, Immediate(32));
3327 __ j(kEqual, &done);
3328 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3329 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
3330 __ Bind(&done);
3331}
3332
Mark P Mendell73945692015-04-29 14:56:17 +00003333void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
3334 Register low = loc.AsRegisterPairLow<Register>();
3335 Register high = loc.AsRegisterPairHigh<Register>();
3336 if (shift == 32) {
3337 // Shift by 32 is easy. Low gets high, and high gets 0.
3338 codegen_->EmitParallelMoves(
3339 loc.ToHigh(),
3340 loc.ToLow(),
3341 Primitive::kPrimInt,
3342 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
3343 loc.ToHigh(),
3344 Primitive::kPrimInt);
3345 } else if (shift > 32) {
3346 // Low part is high >> (shift - 32). High part becomes 0.
3347 __ movl(low, high);
3348 __ shrl(low, Immediate(shift - 32));
3349 __ xorl(high, high);
3350 } else {
3351 // Between 1 and 31.
3352 __ shrd(low, high, Immediate(shift));
3353 __ shrl(high, Immediate(shift));
3354 }
3355}
3356
Calin Juravle9aec02f2014-11-18 23:06:35 +00003357void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003358 NearLabel done;
Calin Juravle9aec02f2014-11-18 23:06:35 +00003359 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
3360 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
3361 __ testl(shifter, Immediate(32));
3362 __ j(kEqual, &done);
3363 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
3364 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
3365 __ Bind(&done);
3366}
3367
3368void LocationsBuilderX86::VisitShl(HShl* shl) {
3369 HandleShift(shl);
3370}
3371
3372void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
3373 HandleShift(shl);
3374}
3375
3376void LocationsBuilderX86::VisitShr(HShr* shr) {
3377 HandleShift(shr);
3378}
3379
3380void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
3381 HandleShift(shr);
3382}
3383
3384void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
3385 HandleShift(ushr);
3386}
3387
3388void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
3389 HandleShift(ushr);
3390}
3391
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003392void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003393 LocationSummary* locations =
3394 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003395 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003396 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003397 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003398 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003399}
3400
3401void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
3402 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003403 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Roland Levillain4d027112015-07-01 15:41:14 +01003404 // Note: if heap poisoning is enabled, the entry point takes cares
3405 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003406 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3407 instruction,
3408 instruction->GetDexPc(),
3409 nullptr);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01003410 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01003411}
3412
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003413void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
3414 LocationSummary* locations =
3415 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3416 locations->SetOut(Location::RegisterLocation(EAX));
3417 InvokeRuntimeCallingConvention calling_convention;
3418 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08003419 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray69aa6012015-06-09 10:34:25 +01003420 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003421}
3422
3423void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
3424 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003425 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
3426
Roland Levillain4d027112015-07-01 15:41:14 +01003427 // Note: if heap poisoning is enabled, the entry point takes cares
3428 // of poisoning the reference.
Calin Juravle175dc732015-08-25 15:42:32 +01003429 codegen_->InvokeRuntime(instruction->GetEntrypoint(),
3430 instruction,
3431 instruction->GetDexPc(),
3432 nullptr);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01003433 DCHECK(!codegen_->IsLeafMethod());
3434}
3435
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003436void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003437 LocationSummary* locations =
3438 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003439 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3440 if (location.IsStackSlot()) {
3441 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3442 } else if (location.IsDoubleStackSlot()) {
3443 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003444 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003445 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003446}
3447
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003448void InstructionCodeGeneratorX86::VisitParameterValue(
3449 HParameterValue* instruction ATTRIBUTE_UNUSED) {
3450}
3451
3452void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
3453 LocationSummary* locations =
3454 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3455 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3456}
3457
3458void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003459}
3460
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003461void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003462 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003463 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003464 locations->SetInAt(0, Location::RequiresRegister());
3465 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003466}
3467
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003468void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
3469 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01003470 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003471 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01003472 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003473 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003474 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003475 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003476 break;
3477
3478 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003479 __ notl(out.AsRegisterPairLow<Register>());
3480 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003481 break;
3482
3483 default:
3484 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3485 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003486}
3487
David Brazdil66d126e2015-04-03 16:02:44 +01003488void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
3489 LocationSummary* locations =
3490 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3491 locations->SetInAt(0, Location::RequiresRegister());
3492 locations->SetOut(Location::SameAsFirstInput());
3493}
3494
3495void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003496 LocationSummary* locations = bool_not->GetLocations();
3497 Location in = locations->InAt(0);
3498 Location out = locations->Out();
3499 DCHECK(in.Equals(out));
3500 __ xorl(out.AsRegister<Register>(), Immediate(1));
3501}
3502
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003503void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003504 LocationSummary* locations =
3505 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003506 switch (compare->InputAt(0)->GetType()) {
3507 case Primitive::kPrimLong: {
3508 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00003509 locations->SetInAt(1, Location::Any());
3510 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3511 break;
3512 }
3513 case Primitive::kPrimFloat:
3514 case Primitive::kPrimDouble: {
3515 locations->SetInAt(0, Location::RequiresFpuRegister());
3516 locations->SetInAt(1, Location::RequiresFpuRegister());
3517 locations->SetOut(Location::RequiresRegister());
3518 break;
3519 }
3520 default:
3521 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3522 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003523}
3524
3525void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003526 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003527 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003528 Location left = locations->InAt(0);
3529 Location right = locations->InAt(1);
3530
Mark Mendell0c9497d2015-08-21 09:30:05 -04003531 NearLabel less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003532 switch (compare->InputAt(0)->GetType()) {
3533 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003534 Register left_low = left.AsRegisterPairLow<Register>();
3535 Register left_high = left.AsRegisterPairHigh<Register>();
3536 int32_t val_low = 0;
3537 int32_t val_high = 0;
3538 bool right_is_const = false;
3539
3540 if (right.IsConstant()) {
3541 DCHECK(right.GetConstant()->IsLongConstant());
3542 right_is_const = true;
3543 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
3544 val_low = Low32Bits(val);
3545 val_high = High32Bits(val);
3546 }
3547
Calin Juravleddb7df22014-11-25 20:56:51 +00003548 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003549 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003550 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003551 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003552 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003553 DCHECK(right_is_const) << right;
3554 if (val_high == 0) {
3555 __ testl(left_high, left_high);
3556 } else {
3557 __ cmpl(left_high, Immediate(val_high));
3558 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003559 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003560 __ j(kLess, &less); // Signed compare.
3561 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003562 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003563 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003564 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003565 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003566 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003567 DCHECK(right_is_const) << right;
3568 if (val_low == 0) {
3569 __ testl(left_low, left_low);
3570 } else {
3571 __ cmpl(left_low, Immediate(val_low));
3572 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003573 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003574 break;
3575 }
3576 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003577 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003578 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
3579 break;
3580 }
3581 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003582 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003583 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003584 break;
3585 }
3586 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003587 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003588 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003589 __ movl(out, Immediate(0));
3590 __ j(kEqual, &done);
3591 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
3592
3593 __ Bind(&greater);
3594 __ movl(out, Immediate(1));
3595 __ jmp(&done);
3596
3597 __ Bind(&less);
3598 __ movl(out, Immediate(-1));
3599
3600 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003601}
3602
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003603void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003604 LocationSummary* locations =
3605 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003606 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3607 locations->SetInAt(i, Location::Any());
3608 }
3609 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003610}
3611
3612void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003613 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003614 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003615}
3616
Calin Juravle52c48962014-12-16 17:02:57 +00003617void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
3618 /*
3619 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3620 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3621 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3622 */
3623 switch (kind) {
3624 case MemBarrierKind::kAnyAny: {
3625 __ mfence();
3626 break;
3627 }
3628 case MemBarrierKind::kAnyStore:
3629 case MemBarrierKind::kLoadAny:
3630 case MemBarrierKind::kStoreStore: {
3631 // nop
3632 break;
3633 }
3634 default:
3635 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003636 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003637}
3638
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003639
Vladimir Marko58155012015-08-19 12:49:41 +00003640void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Location temp) {
3641 Location callee_method = temp; // For all kinds except kRecursive, callee will be in temp.
3642 switch (invoke->GetMethodLoadKind()) {
3643 case HInvokeStaticOrDirect::MethodLoadKind::kStringInit:
3644 // temp = thread->string_init_entrypoint
3645 __ fs()->movl(temp.AsRegister<Register>(), Address::Absolute(invoke->GetStringInitOffset()));
3646 break;
3647 case HInvokeStaticOrDirect::MethodLoadKind::kRecursive:
3648 callee_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3649 break;
3650 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress:
3651 __ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress()));
3652 break;
3653 case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddressWithFixup:
3654 __ movl(temp.AsRegister<Register>(), Immediate(0)); // Placeholder.
3655 method_patches_.emplace_back(invoke->GetTargetMethod());
3656 __ Bind(&method_patches_.back().label); // Bind the label at the end of the "movl" insn.
3657 break;
3658 case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative:
3659 // TODO: Implement this type. For the moment, we fall back to kDexCacheViaMethod.
3660 FALLTHROUGH_INTENDED;
3661 case HInvokeStaticOrDirect::MethodLoadKind::kDexCacheViaMethod: {
3662 Location current_method = invoke->GetLocations()->InAt(invoke->GetCurrentMethodInputIndex());
3663 Register method_reg;
3664 Register reg = temp.AsRegister<Register>();
3665 if (current_method.IsRegister()) {
3666 method_reg = current_method.AsRegister<Register>();
3667 } else {
3668 DCHECK(IsBaseline() || invoke->GetLocations()->Intrinsified());
3669 DCHECK(!current_method.IsValid());
3670 method_reg = reg;
3671 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
3672 }
3673 // temp = temp->dex_cache_resolved_methods_;
Vladimir Marko05792b92015-08-03 11:56:49 +01003674 __ movl(reg, Address(method_reg,
3675 ArtMethod::DexCacheResolvedMethodsOffset(kX86PointerSize).Int32Value()));
Vladimir Marko58155012015-08-19 12:49:41 +00003676 // temp = temp[index_in_cache]
3677 uint32_t index_in_cache = invoke->GetTargetMethod().dex_method_index;
3678 __ movl(reg, Address(reg, CodeGenerator::GetCachePointerOffset(index_in_cache)));
3679 break;
Vladimir Marko9b688a02015-05-06 14:12:42 +01003680 }
Vladimir Marko58155012015-08-19 12:49:41 +00003681 }
3682
3683 switch (invoke->GetCodePtrLocation()) {
3684 case HInvokeStaticOrDirect::CodePtrLocation::kCallSelf:
3685 __ call(GetFrameEntryLabel());
3686 break;
3687 case HInvokeStaticOrDirect::CodePtrLocation::kCallPCRelative: {
3688 relative_call_patches_.emplace_back(invoke->GetTargetMethod());
3689 Label* label = &relative_call_patches_.back().label;
3690 __ call(label); // Bind to the patch label, override at link time.
3691 __ Bind(label); // Bind the label at the end of the "call" insn.
3692 break;
3693 }
3694 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirectWithFixup:
3695 case HInvokeStaticOrDirect::CodePtrLocation::kCallDirect:
3696 // For direct code, we actually prefer to call via the code pointer from ArtMethod*.
3697 // (Though the direct CALL ptr16:32 is available for consideration).
3698 FALLTHROUGH_INTENDED;
3699 case HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod:
3700 // (callee_method + offset_of_quick_compiled_code)()
3701 __ call(Address(callee_method.AsRegister<Register>(),
3702 ArtMethod::EntryPointFromQuickCompiledCodeOffset(
3703 kX86WordSize).Int32Value()));
3704 break;
Mark Mendell09ed1a32015-03-25 08:30:06 -04003705 }
3706
3707 DCHECK(!IsLeafMethod());
Mark Mendell09ed1a32015-03-25 08:30:06 -04003708}
3709
Andreas Gampebfb5ba92015-09-01 15:45:02 +00003710void CodeGeneratorX86::GenerateVirtualCall(HInvokeVirtual* invoke, Location temp_in) {
3711 Register temp = temp_in.AsRegister<Register>();
3712 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
3713 invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
3714 LocationSummary* locations = invoke->GetLocations();
3715 Location receiver = locations->InAt(0);
3716 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3717 // temp = object->GetClass();
3718 DCHECK(receiver.IsRegister());
3719 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
3720 MaybeRecordImplicitNullCheck(invoke);
3721 __ MaybeUnpoisonHeapReference(temp);
3722 // temp = temp->GetMethodAt(method_offset);
3723 __ movl(temp, Address(temp, method_offset));
3724 // call temp->GetEntryPoint();
3725 __ call(Address(
3726 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3727}
3728
Vladimir Marko58155012015-08-19 12:49:41 +00003729void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) {
3730 DCHECK(linker_patches->empty());
3731 linker_patches->reserve(method_patches_.size() + relative_call_patches_.size());
3732 for (const MethodPatchInfo<Label>& info : method_patches_) {
3733 // The label points to the end of the "movl" insn but the literal offset for method
3734 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3735 uint32_t literal_offset = info.label.Position() - 4;
3736 linker_patches->push_back(LinkerPatch::MethodPatch(literal_offset,
3737 info.target_method.dex_file,
3738 info.target_method.dex_method_index));
3739 }
3740 for (const MethodPatchInfo<Label>& info : relative_call_patches_) {
3741 // The label points to the end of the "call" insn but the literal offset for method
3742 // patch x86 needs to point to the embedded constant which occupies the last 4 bytes.
3743 uint32_t literal_offset = info.label.Position() - 4;
3744 linker_patches->push_back(LinkerPatch::RelativeCodePatch(literal_offset,
3745 info.target_method.dex_file,
3746 info.target_method.dex_method_index));
3747 }
3748}
3749
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003750void CodeGeneratorX86::MarkGCCard(Register temp,
3751 Register card,
3752 Register object,
3753 Register value,
3754 bool value_can_be_null) {
Mark Mendell0c9497d2015-08-21 09:30:05 -04003755 NearLabel is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003756 if (value_can_be_null) {
3757 __ testl(value, value);
3758 __ j(kEqual, &is_null);
3759 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003760 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3761 __ movl(temp, object);
3762 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003763 __ movb(Address(temp, card, TIMES_1, 0),
3764 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003765 if (value_can_be_null) {
3766 __ Bind(&is_null);
3767 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003768}
3769
Calin Juravle52c48962014-12-16 17:02:57 +00003770void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3771 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003772 LocationSummary* locations =
3773 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003774 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003775
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003776 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3777 locations->SetOut(Location::RequiresFpuRegister());
3778 } else {
3779 // The output overlaps in case of long: we don't want the low move to overwrite
3780 // the object's location.
3781 locations->SetOut(Location::RequiresRegister(),
3782 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3783 : Location::kNoOutputOverlap);
3784 }
Calin Juravle52c48962014-12-16 17:02:57 +00003785
3786 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3787 // Long values can be loaded atomically into an XMM using movsd.
3788 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3789 // and then copy the XMM into the output 32bits at a time).
3790 locations->AddTemp(Location::RequiresFpuRegister());
3791 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003792}
3793
Calin Juravle52c48962014-12-16 17:02:57 +00003794void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3795 const FieldInfo& field_info) {
3796 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003797
Calin Juravle52c48962014-12-16 17:02:57 +00003798 LocationSummary* locations = instruction->GetLocations();
3799 Register base = locations->InAt(0).AsRegister<Register>();
3800 Location out = locations->Out();
3801 bool is_volatile = field_info.IsVolatile();
3802 Primitive::Type field_type = field_info.GetFieldType();
3803 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3804
3805 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003806 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003807 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003808 break;
3809 }
3810
3811 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003812 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003813 break;
3814 }
3815
3816 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003817 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003818 break;
3819 }
3820
3821 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003822 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003823 break;
3824 }
3825
3826 case Primitive::kPrimInt:
3827 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003828 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003829 break;
3830 }
3831
3832 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00003833 if (is_volatile) {
3834 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3835 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003836 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003837 __ movd(out.AsRegisterPairLow<Register>(), temp);
3838 __ psrlq(temp, Immediate(32));
3839 __ movd(out.AsRegisterPairHigh<Register>(), temp);
3840 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003841 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003842 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003843 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003844 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
3845 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003846 break;
3847 }
3848
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003849 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003850 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003851 break;
3852 }
3853
3854 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003855 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003856 break;
3857 }
3858
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003859 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003860 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003861 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003862 }
Calin Juravle52c48962014-12-16 17:02:57 +00003863
Calin Juravle77520bc2015-01-12 18:45:46 +00003864 // Longs are handled in the switch.
3865 if (field_type != Primitive::kPrimLong) {
3866 codegen_->MaybeRecordImplicitNullCheck(instruction);
3867 }
3868
Calin Juravle52c48962014-12-16 17:02:57 +00003869 if (is_volatile) {
3870 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3871 }
Roland Levillain4d027112015-07-01 15:41:14 +01003872
3873 if (field_type == Primitive::kPrimNot) {
3874 __ MaybeUnpoisonHeapReference(out.AsRegister<Register>());
3875 }
Calin Juravle52c48962014-12-16 17:02:57 +00003876}
3877
3878void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3879 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3880
3881 LocationSummary* locations =
3882 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3883 locations->SetInAt(0, Location::RequiresRegister());
3884 bool is_volatile = field_info.IsVolatile();
3885 Primitive::Type field_type = field_info.GetFieldType();
3886 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
3887 || (field_type == Primitive::kPrimByte);
3888
3889 // The register allocator does not support multiple
3890 // inputs that die at entry with one in a specific register.
3891 if (is_byte_type) {
3892 // Ensure the value is in a byte register.
3893 locations->SetInAt(1, Location::RegisterLocation(EAX));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003894 } else if (Primitive::IsFloatingPointType(field_type)) {
3895 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003896 } else {
3897 locations->SetInAt(1, Location::RequiresRegister());
3898 }
Calin Juravle52c48962014-12-16 17:02:57 +00003899 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
Roland Levillain4d027112015-07-01 15:41:14 +01003900 // Temporary registers for the write barrier.
3901 locations->AddTemp(Location::RequiresRegister()); // Possibly used for reference poisoning too.
Calin Juravle52c48962014-12-16 17:02:57 +00003902 // Ensure the card is in a byte register.
3903 locations->AddTemp(Location::RegisterLocation(ECX));
3904 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
3905 // 64bits value can be atomically written to an address with movsd and an XMM register.
3906 // We need two XMM registers because there's no easier way to (bit) copy a register pair
3907 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
3908 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
3909 // isolated cases when we need this it isn't worth adding the extra complexity.
3910 locations->AddTemp(Location::RequiresFpuRegister());
3911 locations->AddTemp(Location::RequiresFpuRegister());
3912 }
3913}
3914
3915void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003916 const FieldInfo& field_info,
3917 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003918 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3919
3920 LocationSummary* locations = instruction->GetLocations();
3921 Register base = locations->InAt(0).AsRegister<Register>();
3922 Location value = locations->InAt(1);
3923 bool is_volatile = field_info.IsVolatile();
3924 Primitive::Type field_type = field_info.GetFieldType();
3925 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
Roland Levillain4d027112015-07-01 15:41:14 +01003926 bool needs_write_barrier =
3927 CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1));
Calin Juravle52c48962014-12-16 17:02:57 +00003928
3929 if (is_volatile) {
3930 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3931 }
3932
3933 switch (field_type) {
3934 case Primitive::kPrimBoolean:
3935 case Primitive::kPrimByte: {
3936 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
3937 break;
3938 }
3939
3940 case Primitive::kPrimShort:
3941 case Primitive::kPrimChar: {
3942 __ movw(Address(base, offset), value.AsRegister<Register>());
3943 break;
3944 }
3945
3946 case Primitive::kPrimInt:
3947 case Primitive::kPrimNot: {
Roland Levillain4d027112015-07-01 15:41:14 +01003948 if (kPoisonHeapReferences && needs_write_barrier) {
3949 // Note that in the case where `value` is a null reference,
3950 // we do not enter this block, as the reference does not
3951 // need poisoning.
3952 DCHECK_EQ(field_type, Primitive::kPrimNot);
3953 Register temp = locations->GetTemp(0).AsRegister<Register>();
3954 __ movl(temp, value.AsRegister<Register>());
3955 __ PoisonHeapReference(temp);
3956 __ movl(Address(base, offset), temp);
3957 } else {
3958 __ movl(Address(base, offset), value.AsRegister<Register>());
3959 }
Calin Juravle52c48962014-12-16 17:02:57 +00003960 break;
3961 }
3962
3963 case Primitive::kPrimLong: {
3964 if (is_volatile) {
3965 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3966 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
3967 __ movd(temp1, value.AsRegisterPairLow<Register>());
3968 __ movd(temp2, value.AsRegisterPairHigh<Register>());
3969 __ punpckldq(temp1, temp2);
3970 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00003971 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003972 } else {
3973 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003974 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003975 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
3976 }
3977 break;
3978 }
3979
3980 case Primitive::kPrimFloat: {
3981 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3982 break;
3983 }
3984
3985 case Primitive::kPrimDouble: {
3986 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3987 break;
3988 }
3989
3990 case Primitive::kPrimVoid:
3991 LOG(FATAL) << "Unreachable type " << field_type;
3992 UNREACHABLE();
3993 }
3994
Calin Juravle77520bc2015-01-12 18:45:46 +00003995 // Longs are handled in the switch.
3996 if (field_type != Primitive::kPrimLong) {
3997 codegen_->MaybeRecordImplicitNullCheck(instruction);
3998 }
3999
Roland Levillain4d027112015-07-01 15:41:14 +01004000 if (needs_write_barrier) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004001 Register temp = locations->GetTemp(0).AsRegister<Register>();
4002 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004003 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00004004 }
4005
Calin Juravle52c48962014-12-16 17:02:57 +00004006 if (is_volatile) {
4007 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
4008 }
4009}
4010
4011void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4012 HandleFieldGet(instruction, instruction->GetFieldInfo());
4013}
4014
4015void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
4016 HandleFieldGet(instruction, instruction->GetFieldInfo());
4017}
4018
4019void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
4020 HandleFieldSet(instruction, instruction->GetFieldInfo());
4021}
4022
4023void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004024 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004025}
4026
4027void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
4028 HandleFieldSet(instruction, instruction->GetFieldInfo());
4029}
4030
4031void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004032 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00004033}
4034
4035void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4036 HandleFieldGet(instruction, instruction->GetFieldInfo());
4037}
4038
4039void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
4040 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004041}
4042
4043void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004044 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4045 ? LocationSummary::kCallOnSlowPath
4046 : LocationSummary::kNoCall;
4047 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4048 Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004049 ? Location::RequiresRegister()
4050 : Location::Any();
4051 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004052 if (instruction->HasUses()) {
4053 locations->SetOut(Location::SameAsFirstInput());
4054 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004055}
4056
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004057void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00004058 if (codegen_->CanMoveNullCheckToUser(instruction)) {
4059 return;
4060 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004061 LocationSummary* locations = instruction->GetLocations();
4062 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00004063
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004064 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
4065 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4066}
4067
4068void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004069 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004070 codegen_->AddSlowPath(slow_path);
4071
4072 LocationSummary* locations = instruction->GetLocations();
4073 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004074
4075 if (obj.IsRegister()) {
Mark Mendell42514f62015-03-31 11:34:22 -04004076 __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004077 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004078 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004079 } else {
4080 DCHECK(obj.IsConstant()) << obj;
David Brazdil77a48ae2015-09-15 12:34:04 +00004081 DCHECK(obj.GetConstant()->IsNullConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004082 __ jmp(slow_path->GetEntryLabel());
4083 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004084 }
4085 __ j(kEqual, slow_path->GetEntryLabel());
4086}
4087
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004088void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004089 if (codegen_->IsImplicitNullCheckAllowed(instruction)) {
Calin Juravlecd6dffe2015-01-08 17:35:35 +00004090 GenerateImplicitNullCheck(instruction);
4091 } else {
4092 GenerateExplicitNullCheck(instruction);
4093 }
4094}
4095
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004096void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01004097 LocationSummary* locations =
4098 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004099 locations->SetInAt(0, Location::RequiresRegister());
4100 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004101 if (Primitive::IsFloatingPointType(instruction->GetType())) {
4102 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
4103 } else {
4104 // The output overlaps in case of long: we don't want the low move to overwrite
4105 // the array's location.
4106 locations->SetOut(Location::RequiresRegister(),
4107 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
4108 : Location::kNoOutputOverlap);
4109 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004110}
4111
4112void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
4113 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004114 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004115 Location index = locations->InAt(1);
4116
Calin Juravle77520bc2015-01-12 18:45:46 +00004117 Primitive::Type type = instruction->GetType();
4118 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004119 case Primitive::kPrimBoolean: {
4120 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004121 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004122 if (index.IsConstant()) {
4123 __ movzxb(out, Address(obj,
4124 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4125 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004126 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004127 }
4128 break;
4129 }
4130
4131 case Primitive::kPrimByte: {
4132 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004133 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004134 if (index.IsConstant()) {
4135 __ movsxb(out, Address(obj,
4136 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
4137 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004138 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004139 }
4140 break;
4141 }
4142
4143 case Primitive::kPrimShort: {
4144 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004145 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004146 if (index.IsConstant()) {
4147 __ movsxw(out, Address(obj,
4148 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4149 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004150 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004151 }
4152 break;
4153 }
4154
4155 case Primitive::kPrimChar: {
4156 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004157 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004158 if (index.IsConstant()) {
4159 __ movzxw(out, Address(obj,
4160 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
4161 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004162 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004163 }
4164 break;
4165 }
4166
4167 case Primitive::kPrimInt:
4168 case Primitive::kPrimNot: {
4169 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004170 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004171 if (index.IsConstant()) {
4172 __ movl(out, Address(obj,
4173 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4174 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004175 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004176 }
4177 break;
4178 }
4179
4180 case Primitive::kPrimLong: {
4181 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004182 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004183 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004184 if (index.IsConstant()) {
4185 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004186 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004187 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004188 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004189 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004190 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004191 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004192 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004193 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00004194 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004195 }
4196 break;
4197 }
4198
Mark Mendell7c8d0092015-01-26 11:21:33 -05004199 case Primitive::kPrimFloat: {
4200 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4201 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4202 if (index.IsConstant()) {
4203 __ movss(out, Address(obj,
4204 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
4205 } else {
4206 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
4207 }
4208 break;
4209 }
4210
4211 case Primitive::kPrimDouble: {
4212 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4213 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
4214 if (index.IsConstant()) {
4215 __ movsd(out, Address(obj,
4216 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
4217 } else {
4218 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
4219 }
4220 break;
4221 }
4222
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004223 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00004224 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07004225 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004226 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004227
4228 if (type != Primitive::kPrimLong) {
4229 codegen_->MaybeRecordImplicitNullCheck(instruction);
4230 }
Roland Levillain4d027112015-07-01 15:41:14 +01004231
4232 if (type == Primitive::kPrimNot) {
4233 Register out = locations->Out().AsRegister<Register>();
4234 __ MaybeUnpoisonHeapReference(out);
4235 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004236}
4237
4238void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05004239 // This location builder might end up asking to up to four registers, which is
4240 // not currently possible for baseline. The situation in which we need four
4241 // registers cannot be met by baseline though, because it has not run any
4242 // optimization.
4243
Nicolas Geoffray39468442014-09-02 15:17:15 +01004244 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004245 bool needs_write_barrier =
4246 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
4247
Mark Mendell5f874182015-03-04 15:42:45 -05004248 bool needs_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004249
Nicolas Geoffray39468442014-09-02 15:17:15 +01004250 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4251 instruction,
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004252 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004253
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004254 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004255 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004256 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4257 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
4258 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004259 } else {
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01004260 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
4261 || (value_type == Primitive::kPrimByte);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01004262 // We need the inputs to be different than the output in case of long operation.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01004263 // In case of a byte operation, the register allocator does not support multiple
4264 // inputs that die at entry with one in a specific register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004265 locations->SetInAt(0, Location::RequiresRegister());
4266 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01004267 if (is_byte_type) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00004268 // Ensure the value is in a byte register.
4269 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004270 } else if (Primitive::IsFloatingPointType(value_type)) {
4271 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004272 } else {
Alexandre Rames88c13cd2015-04-14 17:35:39 +01004273 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004274 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004275 if (needs_write_barrier) {
Roland Levillain4d027112015-07-01 15:41:14 +01004276 // Temporary registers for the write barrier.
4277 locations->AddTemp(Location::RequiresRegister()); // Possibly used for ref. poisoning too.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00004278 // Ensure the card is in a byte register.
4279 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004280 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004281 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004282}
4283
4284void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
4285 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004286 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004287 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004288 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01004289 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004290 bool needs_runtime_call = locations->WillCall();
4291 bool needs_write_barrier =
4292 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004293
4294 switch (value_type) {
4295 case Primitive::kPrimBoolean:
4296 case Primitive::kPrimByte: {
4297 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004298 if (index.IsConstant()) {
4299 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004300 if (value.IsRegister()) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00004301 __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004302 } else {
4303 __ movb(Address(obj, offset),
4304 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
4305 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004306 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004307 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004308 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00004309 value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004310 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004311 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004312 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
4313 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004314 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004315 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004316 break;
4317 }
4318
4319 case Primitive::kPrimShort:
4320 case Primitive::kPrimChar: {
4321 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004322 if (index.IsConstant()) {
4323 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004324 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004325 __ movw(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004326 } else {
4327 __ movw(Address(obj, offset),
4328 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
4329 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004330 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004331 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004332 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
4333 value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004334 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004335 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004336 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
4337 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004338 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004339 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004340 break;
4341 }
4342
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004343 case Primitive::kPrimInt:
4344 case Primitive::kPrimNot: {
4345 if (!needs_runtime_call) {
4346 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
4347 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004348 size_t offset =
4349 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004350 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01004351 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
4352 Register temp = locations->GetTemp(0).AsRegister<Register>();
4353 __ movl(temp, value.AsRegister<Register>());
4354 __ PoisonHeapReference(temp);
4355 __ movl(Address(obj, offset), temp);
4356 } else {
4357 __ movl(Address(obj, offset), value.AsRegister<Register>());
4358 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004359 } else {
4360 DCHECK(value.IsConstant()) << value;
Roland Levillain4d027112015-07-01 15:41:14 +01004361 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4362 // `value_type == Primitive::kPrimNot` implies `v == 0`.
4363 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
4364 // Note: if heap poisoning is enabled, no need to poison
4365 // (negate) `v` if it is a reference, as it would be null.
4366 __ movl(Address(obj, offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004367 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004368 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004369 DCHECK(index.IsRegister()) << index;
4370 if (value.IsRegister()) {
Roland Levillain4d027112015-07-01 15:41:14 +01004371 if (kPoisonHeapReferences && value_type == Primitive::kPrimNot) {
4372 Register temp = locations->GetTemp(0).AsRegister<Register>();
4373 __ movl(temp, value.AsRegister<Register>());
4374 __ PoisonHeapReference(temp);
4375 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset), temp);
4376 } else {
4377 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
4378 value.AsRegister<Register>());
4379 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004380 } else {
4381 DCHECK(value.IsConstant()) << value;
Roland Levillain4d027112015-07-01 15:41:14 +01004382 int32_t v = CodeGenerator::GetInt32ValueOf(value.GetConstant());
4383 // `value_type == Primitive::kPrimNot` implies `v == 0`.
4384 DCHECK((value_type != Primitive::kPrimNot) || (v == 0));
4385 // Note: if heap poisoning is enabled, no need to poison
4386 // (negate) `v` if it is a reference, as it would be null.
4387 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset), Immediate(v));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004388 }
4389 }
Calin Juravle77520bc2015-01-12 18:45:46 +00004390 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004391
4392 if (needs_write_barrier) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004393 Register temp = locations->GetTemp(0).AsRegister<Register>();
4394 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01004395 codegen_->MarkGCCard(
4396 temp, card, obj, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004397 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004398 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00004399 DCHECK_EQ(value_type, Primitive::kPrimNot);
4400 DCHECK(!codegen_->IsLeafMethod());
Roland Levillain4d027112015-07-01 15:41:14 +01004401 // Note: if heap poisoning is enabled, pAputObject takes cares
4402 // of poisoning the reference.
Alexandre Rames8158f282015-08-07 10:26:17 +01004403 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject),
4404 instruction,
4405 instruction->GetDexPc(),
4406 nullptr);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004407 }
4408 break;
4409 }
4410
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004411 case Primitive::kPrimLong: {
4412 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004413 if (index.IsConstant()) {
4414 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004415 if (value.IsRegisterPair()) {
4416 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004417 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004418 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004419 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004420 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004421 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
4422 __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004423 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004424 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
4425 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004426 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004427 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004428 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004429 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00004430 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004431 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004432 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004433 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01004434 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004435 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004436 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004437 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00004438 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004439 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004440 Immediate(High32Bits(val)));
4441 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004442 }
4443 break;
4444 }
4445
Mark Mendell7c8d0092015-01-26 11:21:33 -05004446 case Primitive::kPrimFloat: {
4447 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
4448 DCHECK(value.IsFpuRegister());
4449 if (index.IsConstant()) {
4450 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
4451 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
4452 } else {
4453 __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
4454 value.AsFpuRegister<XmmRegister>());
4455 }
4456 break;
4457 }
4458
4459 case Primitive::kPrimDouble: {
4460 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
4461 DCHECK(value.IsFpuRegister());
4462 if (index.IsConstant()) {
4463 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
4464 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
4465 } else {
4466 __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
4467 value.AsFpuRegister<XmmRegister>());
4468 }
4469 break;
4470 }
4471
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004472 case Primitive::kPrimVoid:
4473 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07004474 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004475 }
4476}
4477
4478void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
4479 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01004480 locations->SetInAt(0, Location::RequiresRegister());
4481 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004482}
4483
4484void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
4485 LocationSummary* locations = instruction->GetLocations();
4486 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004487 Register obj = locations->InAt(0).AsRegister<Register>();
4488 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004489 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00004490 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004491}
4492
4493void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
David Brazdil77a48ae2015-09-15 12:34:04 +00004494 LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
4495 ? LocationSummary::kCallOnSlowPath
4496 : LocationSummary::kNoCall;
4497 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Mark Mendellf60c90b2015-03-04 15:12:59 -05004498 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04004499 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01004500 if (instruction->HasUses()) {
4501 locations->SetOut(Location::SameAsFirstInput());
4502 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004503}
4504
4505void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
4506 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05004507 Location index_loc = locations->InAt(0);
4508 Location length_loc = locations->InAt(1);
Andreas Gampe85b62f22015-09-09 13:15:38 -07004509 SlowPathCode* slow_path =
Serban Constantinescu5a6cc492015-08-13 15:20:25 +01004510 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004511
Mark Mendell99dbd682015-04-22 16:18:52 -04004512 if (length_loc.IsConstant()) {
4513 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
4514 if (index_loc.IsConstant()) {
4515 // BCE will remove the bounds check if we are guarenteed to pass.
4516 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4517 if (index < 0 || index >= length) {
4518 codegen_->AddSlowPath(slow_path);
4519 __ jmp(slow_path->GetEntryLabel());
4520 } else {
4521 // Some optimization after BCE may have generated this, and we should not
4522 // generate a bounds check if it is a valid range.
4523 }
4524 return;
4525 }
4526
4527 // We have to reverse the jump condition because the length is the constant.
4528 Register index_reg = index_loc.AsRegister<Register>();
4529 __ cmpl(index_reg, Immediate(length));
4530 codegen_->AddSlowPath(slow_path);
4531 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004532 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04004533 Register length = length_loc.AsRegister<Register>();
4534 if (index_loc.IsConstant()) {
4535 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
4536 __ cmpl(length, Immediate(value));
4537 } else {
4538 __ cmpl(length, index_loc.AsRegister<Register>());
4539 }
4540 codegen_->AddSlowPath(slow_path);
4541 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05004542 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01004543}
4544
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004545void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
4546 temp->SetLocations(nullptr);
4547}
4548
4549void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
4550 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004551 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01004552}
4553
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004554void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07004555 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004556 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004557}
4558
4559void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004560 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
4561}
4562
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004563void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
4564 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
4565}
4566
4567void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004568 HBasicBlock* block = instruction->GetBlock();
4569 if (block->GetLoopInformation() != nullptr) {
4570 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4571 // The back edge will generate the suspend check.
4572 return;
4573 }
4574 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4575 // The goto will generate the suspend check.
4576 return;
4577 }
4578 GenerateSuspendCheck(instruction, nullptr);
4579}
4580
4581void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
4582 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004583 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004584 down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
4585 if (slow_path == nullptr) {
4586 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
4587 instruction->SetSlowPath(slow_path);
4588 codegen_->AddSlowPath(slow_path);
4589 if (successor != nullptr) {
4590 DCHECK(successor->IsLoopHeader());
4591 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4592 }
4593 } else {
4594 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4595 }
4596
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004597 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004598 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004599 if (successor == nullptr) {
4600 __ j(kNotEqual, slow_path->GetEntryLabel());
4601 __ Bind(slow_path->GetReturnLabel());
4602 } else {
4603 __ j(kEqual, codegen_->GetLabelOf(successor));
4604 __ jmp(slow_path->GetEntryLabel());
4605 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004606}
4607
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004608X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
4609 return codegen_->GetAssembler();
4610}
4611
Mark Mendell7c8d0092015-01-26 11:21:33 -05004612void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004613 ScratchRegisterScope ensure_scratch(
4614 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4615 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4616 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4617 __ movl(temp_reg, Address(ESP, src + stack_offset));
4618 __ movl(Address(ESP, dst + stack_offset), temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004619}
4620
4621void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004622 ScratchRegisterScope ensure_scratch(
4623 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4624 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4625 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4626 __ movl(temp_reg, Address(ESP, src + stack_offset));
4627 __ movl(Address(ESP, dst + stack_offset), temp_reg);
4628 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
4629 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004630}
4631
4632void ParallelMoveResolverX86::EmitMove(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004633 DCHECK_LT(index, moves_.size());
4634 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004635 Location source = move->GetSource();
4636 Location destination = move->GetDestination();
4637
4638 if (source.IsRegister()) {
4639 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004640 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004641 } else {
4642 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004643 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004644 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004645 } else if (source.IsFpuRegister()) {
4646 if (destination.IsFpuRegister()) {
4647 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4648 } else if (destination.IsStackSlot()) {
4649 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4650 } else {
4651 DCHECK(destination.IsDoubleStackSlot());
4652 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4653 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004654 } else if (source.IsStackSlot()) {
4655 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004656 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004657 } else if (destination.IsFpuRegister()) {
4658 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004659 } else {
4660 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004661 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
4662 }
4663 } else if (source.IsDoubleStackSlot()) {
4664 if (destination.IsFpuRegister()) {
4665 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
4666 } else {
4667 DCHECK(destination.IsDoubleStackSlot()) << destination;
4668 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004669 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004670 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004671 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004672 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004673 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004674 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004675 if (value == 0) {
4676 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
4677 } else {
4678 __ movl(destination.AsRegister<Register>(), Immediate(value));
4679 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004680 } else {
4681 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05004682 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004683 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004684 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004685 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004686 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004687 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004688 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004689 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4690 if (value == 0) {
4691 // Easy handling of 0.0.
4692 __ xorps(dest, dest);
4693 } else {
4694 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004695 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4696 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
4697 __ movl(temp, Immediate(value));
4698 __ movd(dest, temp);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004699 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004700 } else {
4701 DCHECK(destination.IsStackSlot()) << destination;
4702 __ movl(Address(ESP, destination.GetStackIndex()), imm);
4703 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004704 } else if (constant->IsLongConstant()) {
4705 int64_t value = constant->AsLongConstant()->GetValue();
4706 int32_t low_value = Low32Bits(value);
4707 int32_t high_value = High32Bits(value);
4708 Immediate low(low_value);
4709 Immediate high(high_value);
4710 if (destination.IsDoubleStackSlot()) {
4711 __ movl(Address(ESP, destination.GetStackIndex()), low);
4712 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4713 } else {
4714 __ movl(destination.AsRegisterPairLow<Register>(), low);
4715 __ movl(destination.AsRegisterPairHigh<Register>(), high);
4716 }
4717 } else {
4718 DCHECK(constant->IsDoubleConstant());
4719 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004720 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004721 int32_t low_value = Low32Bits(value);
4722 int32_t high_value = High32Bits(value);
4723 Immediate low(low_value);
4724 Immediate high(high_value);
4725 if (destination.IsFpuRegister()) {
4726 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4727 if (value == 0) {
4728 // Easy handling of 0.0.
4729 __ xorpd(dest, dest);
4730 } else {
4731 __ pushl(high);
4732 __ pushl(low);
4733 __ movsd(dest, Address(ESP, 0));
4734 __ addl(ESP, Immediate(8));
4735 }
4736 } else {
4737 DCHECK(destination.IsDoubleStackSlot()) << destination;
4738 __ movl(Address(ESP, destination.GetStackIndex()), low);
4739 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4740 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004741 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004742 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00004743 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004744 }
4745}
4746
Mark Mendella5c19ce2015-04-01 12:51:05 -04004747void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004748 Register suggested_scratch = reg == EAX ? EBX : EAX;
4749 ScratchRegisterScope ensure_scratch(
4750 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
4751
4752 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4753 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
4754 __ movl(Address(ESP, mem + stack_offset), reg);
4755 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004756}
4757
Mark Mendell7c8d0092015-01-26 11:21:33 -05004758void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004759 ScratchRegisterScope ensure_scratch(
4760 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4761
4762 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4763 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4764 __ movl(temp_reg, Address(ESP, mem + stack_offset));
4765 __ movss(Address(ESP, mem + stack_offset), reg);
4766 __ movd(reg, temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004767}
4768
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004769void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004770 ScratchRegisterScope ensure_scratch1(
4771 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004772
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004773 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
4774 ScratchRegisterScope ensure_scratch2(
4775 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004776
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004777 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
4778 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
4779 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
4780 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
4781 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
4782 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004783}
4784
4785void ParallelMoveResolverX86::EmitSwap(size_t index) {
Vladimir Marko225b6462015-09-28 12:17:40 +01004786 DCHECK_LT(index, moves_.size());
4787 MoveOperands* move = moves_[index];
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004788 Location source = move->GetSource();
4789 Location destination = move->GetDestination();
4790
4791 if (source.IsRegister() && destination.IsRegister()) {
Mark Mendell90979812015-07-28 16:41:21 -04004792 // Use XOR swap algorithm to avoid serializing XCHG instruction or using a temporary.
4793 DCHECK_NE(destination.AsRegister<Register>(), source.AsRegister<Register>());
4794 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
4795 __ xorl(source.AsRegister<Register>(), destination.AsRegister<Register>());
4796 __ xorl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004797 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004798 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004799 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004800 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004801 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4802 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004803 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
4804 // Use XOR Swap algorithm to avoid a temporary.
4805 DCHECK_NE(source.reg(), destination.reg());
4806 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4807 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4808 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4809 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
4810 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
4811 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
4812 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004813 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
4814 // Take advantage of the 16 bytes in the XMM register.
4815 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
4816 Address stack(ESP, destination.GetStackIndex());
4817 // Load the double into the high doubleword.
4818 __ movhpd(reg, stack);
4819
4820 // Store the low double into the destination.
4821 __ movsd(stack, reg);
4822
4823 // Move the high double to the low double.
4824 __ psrldq(reg, Immediate(8));
4825 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
4826 // Take advantage of the 16 bytes in the XMM register.
4827 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
4828 Address stack(ESP, source.GetStackIndex());
4829 // Load the double into the high doubleword.
4830 __ movhpd(reg, stack);
4831
4832 // Store the low double into the destination.
4833 __ movsd(stack, reg);
4834
4835 // Move the high double to the low double.
4836 __ psrldq(reg, Immediate(8));
4837 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
4838 Exchange(destination.GetStackIndex(), source.GetStackIndex());
4839 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004840 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004841 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004842 }
4843}
4844
4845void ParallelMoveResolverX86::SpillScratch(int reg) {
4846 __ pushl(static_cast<Register>(reg));
4847}
4848
4849void ParallelMoveResolverX86::RestoreScratch(int reg) {
4850 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004851}
4852
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004853void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004854 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4855 ? LocationSummary::kCallOnSlowPath
4856 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004857 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004858 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004859 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004860 locations->SetOut(Location::RequiresRegister());
4861}
4862
4863void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004864 LocationSummary* locations = cls->GetLocations();
4865 Register out = locations->Out().AsRegister<Register>();
4866 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004867 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004868 DCHECK(!cls->CanCallRuntime());
4869 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004870 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004871 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004872 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004873 __ movl(out, Address(
Vladimir Marko05792b92015-08-03 11:56:49 +01004874 current_method, ArtMethod::DexCacheResolvedTypesOffset(kX86PointerSize).Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004875 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01004876 // TODO: We will need a read barrier here.
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004877
Andreas Gampe85b62f22015-09-09 13:15:38 -07004878 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004879 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4880 codegen_->AddSlowPath(slow_path);
4881 __ testl(out, out);
4882 __ j(kEqual, slow_path->GetEntryLabel());
4883 if (cls->MustGenerateClinitCheck()) {
4884 GenerateClassInitializationCheck(slow_path, out);
4885 } else {
4886 __ Bind(slow_path->GetExitLabel());
4887 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004888 }
4889}
4890
4891void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
4892 LocationSummary* locations =
4893 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4894 locations->SetInAt(0, Location::RequiresRegister());
4895 if (check->HasUses()) {
4896 locations->SetOut(Location::SameAsFirstInput());
4897 }
4898}
4899
4900void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004901 // We assume the class to not be null.
Andreas Gampe85b62f22015-09-09 13:15:38 -07004902 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004903 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004904 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004905 GenerateClassInitializationCheck(slow_path,
4906 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004907}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004908
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004909void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
Andreas Gampe85b62f22015-09-09 13:15:38 -07004910 SlowPathCode* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004911 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4912 Immediate(mirror::Class::kStatusInitialized));
4913 __ j(kLess, slow_path->GetEntryLabel());
4914 __ Bind(slow_path->GetExitLabel());
4915 // No need for memory fence, thanks to the X86 memory model.
4916}
4917
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004918void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
4919 LocationSummary* locations =
4920 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004921 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004922 locations->SetOut(Location::RequiresRegister());
4923}
4924
4925void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
Andreas Gampe85b62f22015-09-09 13:15:38 -07004926 SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004927 codegen_->AddSlowPath(slow_path);
4928
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004929 LocationSummary* locations = load->GetLocations();
4930 Register out = locations->Out().AsRegister<Register>();
4931 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004932 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004933 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004934 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
Vladimir Marko05792b92015-08-03 11:56:49 +01004935 // TODO: We will need a read barrier here.
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004936 __ testl(out, out);
4937 __ j(kEqual, slow_path->GetEntryLabel());
4938 __ Bind(slow_path->GetExitLabel());
4939}
4940
David Brazdilcb1c0552015-08-04 16:22:25 +01004941static Address GetExceptionTlsAddress() {
4942 return Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
4943}
4944
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004945void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
4946 LocationSummary* locations =
4947 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4948 locations->SetOut(Location::RequiresRegister());
4949}
4950
4951void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
David Brazdilcb1c0552015-08-04 16:22:25 +01004952 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), GetExceptionTlsAddress());
4953}
4954
4955void LocationsBuilderX86::VisitClearException(HClearException* clear) {
4956 new (GetGraph()->GetArena()) LocationSummary(clear, LocationSummary::kNoCall);
4957}
4958
4959void InstructionCodeGeneratorX86::VisitClearException(HClearException* clear ATTRIBUTE_UNUSED) {
4960 __ fs()->movl(GetExceptionTlsAddress(), Immediate(0));
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004961}
4962
4963void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
4964 LocationSummary* locations =
4965 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4966 InvokeRuntimeCallingConvention calling_convention;
4967 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4968}
4969
4970void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01004971 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pDeliverException),
4972 instruction,
4973 instruction->GetDexPc(),
4974 nullptr);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004975}
4976
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004977void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004978 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
4979 switch (instruction->GetTypeCheckKind()) {
4980 case TypeCheckKind::kExactCheck:
4981 case TypeCheckKind::kAbstractClassCheck:
4982 case TypeCheckKind::kClassHierarchyCheck:
4983 case TypeCheckKind::kArrayObjectCheck:
4984 call_kind = LocationSummary::kNoCall;
4985 break;
4986 case TypeCheckKind::kInterfaceCheck:
4987 call_kind = LocationSummary::kCall;
4988 break;
4989 case TypeCheckKind::kArrayCheck:
4990 call_kind = LocationSummary::kCallOnSlowPath;
4991 break;
4992 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004993 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00004994 if (call_kind != LocationSummary::kCall) {
4995 locations->SetInAt(0, Location::RequiresRegister());
4996 locations->SetInAt(1, Location::Any());
4997 // Note that TypeCheckSlowPathX86 uses this register too.
4998 locations->SetOut(Location::RequiresRegister());
4999 } else {
5000 InvokeRuntimeCallingConvention calling_convention;
5001 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5002 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5003 locations->SetOut(Location::RegisterLocation(EAX));
5004 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005005}
5006
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005007void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005008 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005009 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005010 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00005011 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005012 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005013 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5014 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5015 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
Andreas Gampe85b62f22015-09-09 13:15:38 -07005016 SlowPathCode* slow_path = nullptr;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005017 NearLabel done, zero;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005018
5019 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005020 // Avoid null check if we know obj is not null.
5021 if (instruction->MustDoNullCheck()) {
5022 __ testl(obj, obj);
5023 __ j(kEqual, &zero);
5024 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005025
5026 // In case of an interface check, we put the object class into the object register.
5027 // This is safe, as the register is caller-save, and the object must be in another
5028 // register if it survives the runtime call.
5029 Register target = (instruction->GetTypeCheckKind() == TypeCheckKind::kInterfaceCheck)
5030 ? obj
5031 : out;
5032 __ movl(target, Address(obj, class_offset));
5033 __ MaybeUnpoisonHeapReference(target);
5034
5035 switch (instruction->GetTypeCheckKind()) {
5036 case TypeCheckKind::kExactCheck: {
5037 if (cls.IsRegister()) {
5038 __ cmpl(out, cls.AsRegister<Register>());
5039 } else {
5040 DCHECK(cls.IsStackSlot()) << cls;
5041 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5042 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005043
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005044 // Classes must be equal for the instanceof to succeed.
5045 __ j(kNotEqual, &zero);
5046 __ movl(out, Immediate(1));
5047 __ jmp(&done);
5048 break;
5049 }
5050 case TypeCheckKind::kAbstractClassCheck: {
5051 // If the class is abstract, we eagerly fetch the super class of the
5052 // object to avoid doing a comparison we know will fail.
5053 NearLabel loop;
5054 __ Bind(&loop);
5055 __ movl(out, Address(out, super_offset));
5056 __ MaybeUnpoisonHeapReference(out);
5057 __ testl(out, out);
5058 // If `out` is null, we use it for the result, and jump to `done`.
5059 __ j(kEqual, &done);
5060 if (cls.IsRegister()) {
5061 __ cmpl(out, cls.AsRegister<Register>());
5062 } else {
5063 DCHECK(cls.IsStackSlot()) << cls;
5064 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5065 }
5066 __ j(kNotEqual, &loop);
5067 __ movl(out, Immediate(1));
5068 if (zero.IsLinked()) {
5069 __ jmp(&done);
5070 }
5071 break;
5072 }
5073 case TypeCheckKind::kClassHierarchyCheck: {
5074 // Walk over the class hierarchy to find a match.
5075 NearLabel loop, success;
5076 __ Bind(&loop);
5077 if (cls.IsRegister()) {
5078 __ cmpl(out, cls.AsRegister<Register>());
5079 } else {
5080 DCHECK(cls.IsStackSlot()) << cls;
5081 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5082 }
5083 __ j(kEqual, &success);
5084 __ movl(out, Address(out, super_offset));
5085 __ MaybeUnpoisonHeapReference(out);
5086 __ testl(out, out);
5087 __ j(kNotEqual, &loop);
5088 // If `out` is null, we use it for the result, and jump to `done`.
5089 __ jmp(&done);
5090 __ Bind(&success);
5091 __ movl(out, Immediate(1));
5092 if (zero.IsLinked()) {
5093 __ jmp(&done);
5094 }
5095 break;
5096 }
5097 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005098 // Do an exact check.
5099 NearLabel exact_check;
5100 if (cls.IsRegister()) {
5101 __ cmpl(out, cls.AsRegister<Register>());
5102 } else {
5103 DCHECK(cls.IsStackSlot()) << cls;
5104 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5105 }
5106 __ j(kEqual, &exact_check);
5107 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005108 __ movl(out, Address(out, component_offset));
5109 __ MaybeUnpoisonHeapReference(out);
5110 __ testl(out, out);
5111 // If `out` is null, we use it for the result, and jump to `done`.
5112 __ j(kEqual, &done);
5113 __ cmpw(Address(out, primitive_offset), Immediate(Primitive::kPrimNot));
5114 __ j(kNotEqual, &zero);
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005115 __ Bind(&exact_check);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005116 __ movl(out, Immediate(1));
5117 __ jmp(&done);
5118 break;
5119 }
5120 case TypeCheckKind::kArrayCheck: {
5121 if (cls.IsRegister()) {
5122 __ cmpl(out, cls.AsRegister<Register>());
5123 } else {
5124 DCHECK(cls.IsStackSlot()) << cls;
5125 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
5126 }
5127 DCHECK(locations->OnlyCallsOnSlowPath());
5128 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5129 instruction, /* is_fatal */ false);
5130 codegen_->AddSlowPath(slow_path);
5131 __ j(kNotEqual, slow_path->GetEntryLabel());
5132 __ movl(out, Immediate(1));
5133 if (zero.IsLinked()) {
5134 __ jmp(&done);
5135 }
5136 break;
5137 }
5138
5139 case TypeCheckKind::kInterfaceCheck:
5140 default: {
5141 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial),
5142 instruction,
5143 instruction->GetDexPc(),
5144 nullptr);
5145 if (zero.IsLinked()) {
5146 __ jmp(&done);
5147 }
5148 break;
5149 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005150 }
5151
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005152 if (zero.IsLinked()) {
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005153 __ Bind(&zero);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005154 __ xorl(out, out);
5155 }
5156
5157 if (done.IsLinked()) {
5158 __ Bind(&done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005159 }
5160
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005161 if (slow_path != nullptr) {
5162 __ Bind(slow_path->GetExitLabel());
5163 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00005164}
5165
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005166void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005167 LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
5168 bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
5169
5170 switch (instruction->GetTypeCheckKind()) {
5171 case TypeCheckKind::kExactCheck:
5172 case TypeCheckKind::kAbstractClassCheck:
5173 case TypeCheckKind::kClassHierarchyCheck:
5174 case TypeCheckKind::kArrayObjectCheck:
5175 call_kind = throws_into_catch
5176 ? LocationSummary::kCallOnSlowPath
5177 : LocationSummary::kNoCall;
5178 break;
5179 case TypeCheckKind::kInterfaceCheck:
5180 call_kind = LocationSummary::kCall;
5181 break;
5182 case TypeCheckKind::kArrayCheck:
5183 call_kind = LocationSummary::kCallOnSlowPath;
5184 break;
5185 }
5186
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005187 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005188 instruction, call_kind);
5189 if (call_kind != LocationSummary::kCall) {
5190 locations->SetInAt(0, Location::RequiresRegister());
5191 locations->SetInAt(1, Location::Any());
5192 // Note that TypeCheckSlowPathX86 uses this register too.
5193 locations->AddTemp(Location::RequiresRegister());
5194 } else {
5195 InvokeRuntimeCallingConvention calling_convention;
5196 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5197 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
5198 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005199}
5200
5201void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
5202 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00005203 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005204 Location cls = locations->InAt(1);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005205 Register temp = locations->WillCall()
5206 ? kNoRegister
5207 : locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray64acf302015-09-14 22:20:29 +01005208
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005209 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
5210 uint32_t super_offset = mirror::Class::SuperClassOffset().Int32Value();
5211 uint32_t component_offset = mirror::Class::ComponentTypeOffset().Int32Value();
5212 uint32_t primitive_offset = mirror::Class::PrimitiveTypeOffset().Int32Value();
5213 SlowPathCode* slow_path = nullptr;
5214
5215 if (!locations->WillCall()) {
5216 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
5217 instruction, !locations->CanCall());
5218 codegen_->AddSlowPath(slow_path);
5219 }
5220
5221 NearLabel done, abstract_entry;
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005222 // Avoid null check if we know obj is not null.
5223 if (instruction->MustDoNullCheck()) {
5224 __ testl(obj, obj);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005225 __ j(kEqual, &done);
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01005226 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005227
5228 if (locations->WillCall()) {
5229 __ movl(obj, Address(obj, class_offset));
5230 __ MaybeUnpoisonHeapReference(obj);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005231 } else {
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005232 __ movl(temp, Address(obj, class_offset));
5233 __ MaybeUnpoisonHeapReference(temp);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005234 }
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005235
5236 switch (instruction->GetTypeCheckKind()) {
5237 case TypeCheckKind::kExactCheck:
5238 case TypeCheckKind::kArrayCheck: {
5239 if (cls.IsRegister()) {
5240 __ cmpl(temp, cls.AsRegister<Register>());
5241 } else {
5242 DCHECK(cls.IsStackSlot()) << cls;
5243 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5244 }
5245 // Jump to slow path for throwing the exception or doing a
5246 // more involved array check.
5247 __ j(kNotEqual, slow_path->GetEntryLabel());
5248 break;
5249 }
5250 case TypeCheckKind::kAbstractClassCheck: {
5251 // If the class is abstract, we eagerly fetch the super class of the
5252 // object to avoid doing a comparison we know will fail.
5253 NearLabel loop, success;
5254 __ Bind(&loop);
5255 __ movl(temp, Address(temp, super_offset));
5256 __ MaybeUnpoisonHeapReference(temp);
5257 __ testl(temp, temp);
5258 // Jump to the slow path to throw the exception.
5259 __ j(kEqual, slow_path->GetEntryLabel());
5260 if (cls.IsRegister()) {
5261 __ cmpl(temp, cls.AsRegister<Register>());
5262 } else {
5263 DCHECK(cls.IsStackSlot()) << cls;
5264 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5265 }
5266 __ j(kNotEqual, &loop);
5267 break;
5268 }
5269 case TypeCheckKind::kClassHierarchyCheck: {
5270 // Walk over the class hierarchy to find a match.
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005271 NearLabel loop;
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005272 __ Bind(&loop);
5273 if (cls.IsRegister()) {
5274 __ cmpl(temp, cls.AsRegister<Register>());
5275 } else {
5276 DCHECK(cls.IsStackSlot()) << cls;
5277 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5278 }
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005279 __ j(kEqual, &done);
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005280 __ movl(temp, Address(temp, super_offset));
5281 __ MaybeUnpoisonHeapReference(temp);
5282 __ testl(temp, temp);
5283 __ j(kNotEqual, &loop);
5284 // Jump to the slow path to throw the exception.
5285 __ jmp(slow_path->GetEntryLabel());
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005286 break;
5287 }
5288 case TypeCheckKind::kArrayObjectCheck: {
Nicolas Geoffrayabfcf182015-09-21 18:41:21 +01005289 // Do an exact check.
5290 if (cls.IsRegister()) {
5291 __ cmpl(temp, cls.AsRegister<Register>());
5292 } else {
5293 DCHECK(cls.IsStackSlot()) << cls;
5294 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
5295 }
5296 __ j(kEqual, &done);
5297 // Otherwise, we need to check that the object's class is a non primitive array.
Nicolas Geoffray85c7bab2015-09-18 13:40:46 +00005298 __ movl(temp, Address(temp, component_offset));
5299 __ MaybeUnpoisonHeapReference(temp);
5300 __ testl(temp, temp);
5301 __ j(kEqual, slow_path->GetEntryLabel());
5302 __ cmpw(Address(temp, primitive_offset), Immediate(Primitive::kPrimNot));
5303 __ j(kNotEqual, slow_path->GetEntryLabel());
5304 break;
5305 }
5306 case TypeCheckKind::kInterfaceCheck:
5307 default:
5308 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast),
5309 instruction,
5310 instruction->GetDexPc(),
5311 nullptr);
5312 break;
5313 }
5314 __ Bind(&done);
5315
5316 if (slow_path != nullptr) {
5317 __ Bind(slow_path->GetExitLabel());
5318 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00005319}
5320
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005321void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
5322 LocationSummary* locations =
5323 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
5324 InvokeRuntimeCallingConvention calling_convention;
5325 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
5326}
5327
5328void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
Alexandre Rames8158f282015-08-07 10:26:17 +01005329 codegen_->InvokeRuntime(instruction->IsEnter() ? QUICK_ENTRY_POINT(pLockObject)
5330 : QUICK_ENTRY_POINT(pUnlockObject),
5331 instruction,
5332 instruction->GetDexPc(),
5333 nullptr);
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00005334}
5335
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005336void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
5337void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
5338void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
5339
5340void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5341 LocationSummary* locations =
5342 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5343 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
5344 || instruction->GetResultType() == Primitive::kPrimLong);
5345 locations->SetInAt(0, Location::RequiresRegister());
5346 locations->SetInAt(1, Location::Any());
5347 locations->SetOut(Location::SameAsFirstInput());
5348}
5349
5350void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
5351 HandleBitwiseOperation(instruction);
5352}
5353
5354void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
5355 HandleBitwiseOperation(instruction);
5356}
5357
5358void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
5359 HandleBitwiseOperation(instruction);
5360}
5361
5362void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
5363 LocationSummary* locations = instruction->GetLocations();
5364 Location first = locations->InAt(0);
5365 Location second = locations->InAt(1);
5366 DCHECK(first.Equals(locations->Out()));
5367
5368 if (instruction->GetResultType() == Primitive::kPrimInt) {
5369 if (second.IsRegister()) {
5370 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005371 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005372 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005373 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005374 } else {
5375 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005376 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005377 }
5378 } else if (second.IsConstant()) {
5379 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005380 __ andl(first.AsRegister<Register>(),
5381 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005382 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00005383 __ orl(first.AsRegister<Register>(),
5384 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005385 } else {
5386 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00005387 __ xorl(first.AsRegister<Register>(),
5388 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005389 }
5390 } else {
5391 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005392 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005393 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00005394 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005395 } else {
5396 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00005397 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005398 }
5399 }
5400 } else {
5401 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
5402 if (second.IsRegisterPair()) {
5403 if (instruction->IsAnd()) {
5404 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5405 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5406 } else if (instruction->IsOr()) {
5407 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5408 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5409 } else {
5410 DCHECK(instruction->IsXor());
5411 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
5412 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
5413 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005414 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005415 if (instruction->IsAnd()) {
5416 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5417 __ andl(first.AsRegisterPairHigh<Register>(),
5418 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5419 } else if (instruction->IsOr()) {
5420 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5421 __ orl(first.AsRegisterPairHigh<Register>(),
5422 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5423 } else {
5424 DCHECK(instruction->IsXor());
5425 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
5426 __ xorl(first.AsRegisterPairHigh<Register>(),
5427 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
5428 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005429 } else {
5430 DCHECK(second.IsConstant()) << second;
5431 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005432 int32_t low_value = Low32Bits(value);
5433 int32_t high_value = High32Bits(value);
5434 Immediate low(low_value);
5435 Immediate high(high_value);
5436 Register first_low = first.AsRegisterPairLow<Register>();
5437 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005438 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005439 if (low_value == 0) {
5440 __ xorl(first_low, first_low);
5441 } else if (low_value != -1) {
5442 __ andl(first_low, low);
5443 }
5444 if (high_value == 0) {
5445 __ xorl(first_high, first_high);
5446 } else if (high_value != -1) {
5447 __ andl(first_high, high);
5448 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005449 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005450 if (low_value != 0) {
5451 __ orl(first_low, low);
5452 }
5453 if (high_value != 0) {
5454 __ orl(first_high, high);
5455 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005456 } else {
5457 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04005458 if (low_value != 0) {
5459 __ xorl(first_low, low);
5460 }
5461 if (high_value != 0) {
5462 __ xorl(first_high, high);
5463 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00005464 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00005465 }
5466 }
5467}
5468
Calin Juravleb1498f62015-02-16 13:13:29 +00005469void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
5470 // Nothing to do, this should be removed during prepare for register allocator.
5471 UNUSED(instruction);
5472 LOG(FATAL) << "Unreachable";
5473}
5474
5475void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
5476 // Nothing to do, this should be removed during prepare for register allocator.
5477 UNUSED(instruction);
5478 LOG(FATAL) << "Unreachable";
5479}
5480
Nicolas Geoffray2e7cd752015-07-10 11:38:52 +01005481void LocationsBuilderX86::VisitFakeString(HFakeString* instruction) {
5482 DCHECK(codegen_->IsBaseline());
5483 LocationSummary* locations =
5484 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
5485 locations->SetOut(Location::ConstantLocation(GetGraph()->GetNullConstant()));
5486}
5487
5488void InstructionCodeGeneratorX86::VisitFakeString(HFakeString* instruction ATTRIBUTE_UNUSED) {
5489 DCHECK(codegen_->IsBaseline());
5490 // Will be generated at use site.
5491}
5492
Mark Mendellfe57faa2015-09-18 09:26:15 -04005493// Simple implementation of packed switch - generate cascaded compare/jumps.
5494void LocationsBuilderX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5495 LocationSummary* locations =
5496 new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
5497 locations->SetInAt(0, Location::RequiresRegister());
5498}
5499
5500void InstructionCodeGeneratorX86::VisitPackedSwitch(HPackedSwitch* switch_instr) {
5501 int32_t lower_bound = switch_instr->GetStartValue();
5502 int32_t num_entries = switch_instr->GetNumEntries();
5503 LocationSummary* locations = switch_instr->GetLocations();
5504 Register value_reg = locations->InAt(0).AsRegister<Register>();
5505 HBasicBlock* default_block = switch_instr->GetDefaultBlock();
5506
5507 // Create a series of compare/jumps.
5508 const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
5509 for (int i = 0; i < num_entries; i++) {
5510 int32_t case_value = lower_bound + i;
5511 if (case_value == 0) {
5512 __ testl(value_reg, value_reg);
5513 } else {
5514 __ cmpl(value_reg, Immediate(case_value));
5515 }
5516 __ j(kEqual, codegen_->GetLabelOf(successors.at(i)));
5517 }
5518
5519 // And the default for any other value.
5520 if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
5521 __ jmp(codegen_->GetLabelOf(default_block));
5522 }
5523}
5524
Mark Mendell0616ae02015-04-17 12:49:27 -04005525void LocationsBuilderX86::VisitX86ComputeBaseMethodAddress(
5526 HX86ComputeBaseMethodAddress* insn) {
5527 LocationSummary* locations =
5528 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5529 locations->SetOut(Location::RequiresRegister());
5530}
5531
5532void InstructionCodeGeneratorX86::VisitX86ComputeBaseMethodAddress(
5533 HX86ComputeBaseMethodAddress* insn) {
5534 LocationSummary* locations = insn->GetLocations();
5535 Register reg = locations->Out().AsRegister<Register>();
5536
5537 // Generate call to next instruction.
5538 Label next_instruction;
5539 __ call(&next_instruction);
5540 __ Bind(&next_instruction);
5541
5542 // Remember this offset for later use with constant area.
5543 codegen_->SetMethodAddressOffset(GetAssembler()->CodeSize());
5544
5545 // Grab the return address off the stack.
5546 __ popl(reg);
5547}
5548
5549void LocationsBuilderX86::VisitX86LoadFromConstantTable(
5550 HX86LoadFromConstantTable* insn) {
5551 LocationSummary* locations =
5552 new (GetGraph()->GetArena()) LocationSummary(insn, LocationSummary::kNoCall);
5553
5554 locations->SetInAt(0, Location::RequiresRegister());
5555 locations->SetInAt(1, Location::ConstantLocation(insn->GetConstant()));
5556
5557 // If we don't need to be materialized, we only need the inputs to be set.
5558 if (!insn->NeedsMaterialization()) {
5559 return;
5560 }
5561
5562 switch (insn->GetType()) {
5563 case Primitive::kPrimFloat:
5564 case Primitive::kPrimDouble:
5565 locations->SetOut(Location::RequiresFpuRegister());
5566 break;
5567
5568 case Primitive::kPrimInt:
5569 locations->SetOut(Location::RequiresRegister());
5570 break;
5571
5572 default:
5573 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5574 }
5575}
5576
5577void InstructionCodeGeneratorX86::VisitX86LoadFromConstantTable(HX86LoadFromConstantTable* insn) {
5578 if (!insn->NeedsMaterialization()) {
5579 return;
5580 }
5581
5582 LocationSummary* locations = insn->GetLocations();
5583 Location out = locations->Out();
5584 Register const_area = locations->InAt(0).AsRegister<Register>();
5585 HConstant *value = insn->GetConstant();
5586
5587 switch (insn->GetType()) {
5588 case Primitive::kPrimFloat:
5589 __ movss(out.AsFpuRegister<XmmRegister>(),
5590 codegen_->LiteralFloatAddress(value->AsFloatConstant()->GetValue(), const_area));
5591 break;
5592
5593 case Primitive::kPrimDouble:
5594 __ movsd(out.AsFpuRegister<XmmRegister>(),
5595 codegen_->LiteralDoubleAddress(value->AsDoubleConstant()->GetValue(), const_area));
5596 break;
5597
5598 case Primitive::kPrimInt:
5599 __ movl(out.AsRegister<Register>(),
5600 codegen_->LiteralInt32Address(value->AsIntConstant()->GetValue(), const_area));
5601 break;
5602
5603 default:
5604 LOG(FATAL) << "Unsupported x86 constant area type " << insn->GetType();
5605 }
5606}
5607
5608void CodeGeneratorX86::Finalize(CodeAllocator* allocator) {
5609 // Generate the constant area if needed.
5610 X86Assembler* assembler = GetAssembler();
5611 if (!assembler->IsConstantAreaEmpty()) {
5612 // Align to 4 byte boundary to reduce cache misses, as the data is 4 and 8
5613 // byte values.
5614 assembler->Align(4, 0);
5615 constant_area_start_ = assembler->CodeSize();
5616 assembler->AddConstantArea();
5617 }
5618
5619 // And finish up.
5620 CodeGenerator::Finalize(allocator);
5621}
5622
5623/**
5624 * Class to handle late fixup of offsets into constant area.
5625 */
5626class RIPFixup : public AssemblerFixup, public ArenaObject<kArenaAllocMisc> {
5627 public:
5628 RIPFixup(const CodeGeneratorX86& codegen, int offset)
5629 : codegen_(codegen), offset_into_constant_area_(offset) {}
5630
5631 private:
5632 void Process(const MemoryRegion& region, int pos) OVERRIDE {
5633 // Patch the correct offset for the instruction. The place to patch is the
5634 // last 4 bytes of the instruction.
5635 // The value to patch is the distance from the offset in the constant area
5636 // from the address computed by the HX86ComputeBaseMethodAddress instruction.
5637 int32_t constant_offset = codegen_.ConstantAreaStart() + offset_into_constant_area_;
5638 int32_t relative_position = constant_offset - codegen_.GetMethodAddressOffset();;
5639
5640 // Patch in the right value.
5641 region.StoreUnaligned<int32_t>(pos - 4, relative_position);
5642 }
5643
5644 const CodeGeneratorX86& codegen_;
5645
5646 // Location in constant area that the fixup refers to.
5647 int offset_into_constant_area_;
5648};
5649
5650Address CodeGeneratorX86::LiteralDoubleAddress(double v, Register reg) {
5651 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddDouble(v));
5652 return Address(reg, kDummy32BitOffset, fixup);
5653}
5654
5655Address CodeGeneratorX86::LiteralFloatAddress(float v, Register reg) {
5656 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddFloat(v));
5657 return Address(reg, kDummy32BitOffset, fixup);
5658}
5659
5660Address CodeGeneratorX86::LiteralInt32Address(int32_t v, Register reg) {
5661 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt32(v));
5662 return Address(reg, kDummy32BitOffset, fixup);
5663}
5664
5665Address CodeGeneratorX86::LiteralInt64Address(int64_t v, Register reg) {
5666 AssemblerFixup* fixup = new (GetGraph()->GetArena()) RIPFixup(*this, __ AddInt64(v));
5667 return Address(reg, kDummy32BitOffset, fixup);
5668}
5669
5670/**
5671 * Finds instructions that need the constant area base as an input.
5672 */
5673class ConstantHandlerVisitor : public HGraphVisitor {
5674 public:
5675 explicit ConstantHandlerVisitor(HGraph* graph) : HGraphVisitor(graph), base_(nullptr) {}
5676
5677 private:
5678 void VisitAdd(HAdd* add) OVERRIDE {
5679 BinaryFP(add);
5680 }
5681
5682 void VisitSub(HSub* sub) OVERRIDE {
5683 BinaryFP(sub);
5684 }
5685
5686 void VisitMul(HMul* mul) OVERRIDE {
5687 BinaryFP(mul);
5688 }
5689
5690 void VisitDiv(HDiv* div) OVERRIDE {
5691 BinaryFP(div);
5692 }
5693
5694 void VisitReturn(HReturn* ret) OVERRIDE {
5695 HConstant* value = ret->InputAt(0)->AsConstant();
5696 if ((value != nullptr && Primitive::IsFloatingPointType(value->GetType()))) {
5697 ReplaceInput(ret, value, 0, true);
5698 }
5699 }
5700
5701 void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE {
5702 HandleInvoke(invoke);
5703 }
5704
5705 void VisitInvokeVirtual(HInvokeVirtual* invoke) OVERRIDE {
5706 HandleInvoke(invoke);
5707 }
5708
5709 void VisitInvokeInterface(HInvokeInterface* invoke) OVERRIDE {
5710 HandleInvoke(invoke);
5711 }
5712
5713 void BinaryFP(HBinaryOperation* bin) {
5714 HConstant* rhs = bin->InputAt(1)->AsConstant();
5715 if (rhs != nullptr && Primitive::IsFloatingPointType(bin->GetResultType())) {
5716 ReplaceInput(bin, rhs, 1, false);
5717 }
5718 }
5719
5720 void InitializeConstantAreaPointer(HInstruction* user) {
5721 // Ensure we only initialize the pointer once.
5722 if (base_ != nullptr) {
5723 return;
5724 }
5725
5726 HGraph* graph = GetGraph();
5727 HBasicBlock* entry = graph->GetEntryBlock();
5728 base_ = new (graph->GetArena()) HX86ComputeBaseMethodAddress();
5729 HInstruction* insert_pos = (user->GetBlock() == entry) ? user : entry->GetLastInstruction();
5730 entry->InsertInstructionBefore(base_, insert_pos);
5731 DCHECK(base_ != nullptr);
5732 }
5733
5734 void ReplaceInput(HInstruction* insn, HConstant* value, int input_index, bool materialize) {
5735 InitializeConstantAreaPointer(insn);
5736 HGraph* graph = GetGraph();
5737 HBasicBlock* block = insn->GetBlock();
5738 HX86LoadFromConstantTable* load_constant =
5739 new (graph->GetArena()) HX86LoadFromConstantTable(base_, value, materialize);
5740 block->InsertInstructionBefore(load_constant, insn);
5741 insn->ReplaceInput(load_constant, input_index);
5742 }
5743
5744 void HandleInvoke(HInvoke* invoke) {
5745 // Ensure that we can load FP arguments from the constant area.
5746 for (size_t i = 0, e = invoke->InputCount(); i < e; i++) {
5747 HConstant* input = invoke->InputAt(i)->AsConstant();
5748 if (input != nullptr && Primitive::IsFloatingPointType(input->GetType())) {
5749 ReplaceInput(invoke, input, i, true);
5750 }
5751 }
5752 }
5753
5754 // The generated HX86ComputeBaseMethodAddress in the entry block needed as an
5755 // input to the HX86LoadFromConstantTable instructions.
5756 HX86ComputeBaseMethodAddress* base_;
5757};
5758
5759void ConstantAreaFixups::Run() {
5760 ConstantHandlerVisitor visitor(graph_);
5761 visitor.VisitInsertionOrder();
5762}
5763
Andreas Gampe85b62f22015-09-09 13:15:38 -07005764// TODO: target as memory.
5765void CodeGeneratorX86::MoveFromReturnRegister(Location target, Primitive::Type type) {
5766 if (!target.IsValid()) {
5767 DCHECK(type == Primitive::kPrimVoid);
5768 return;
5769 }
5770
5771 DCHECK_NE(type, Primitive::kPrimVoid);
5772
5773 Location return_loc = InvokeDexCallingConventionVisitorX86().GetReturnLocation(type);
5774 if (target.Equals(return_loc)) {
5775 return;
5776 }
5777
5778 // TODO: Consider pairs in the parallel move resolver, then this could be nicely merged
5779 // with the else branch.
5780 if (type == Primitive::kPrimLong) {
5781 HParallelMove parallel_move(GetGraph()->GetArena());
5782 parallel_move.AddMove(return_loc.ToLow(), target.ToLow(), Primitive::kPrimInt, nullptr);
5783 parallel_move.AddMove(return_loc.ToHigh(), target.ToHigh(), Primitive::kPrimInt, nullptr);
5784 GetMoveResolver()->EmitNativeCode(&parallel_move);
5785 } else {
5786 // Let the parallel move resolver take care of all of this.
5787 HParallelMove parallel_move(GetGraph()->GetArena());
5788 parallel_move.AddMove(return_loc, target, type, nullptr);
5789 GetMoveResolver()->EmitNativeCode(&parallel_move);
5790 }
5791}
5792
Roland Levillain4d027112015-07-01 15:41:14 +01005793#undef __
5794
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00005795} // namespace x86
5796} // namespace art