blob: 4c4fbd9b28e09e4d795f44730bb41f7b39e2115c [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"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010021#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +000022#include "entrypoints/quick/quick_entrypoints_enum.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010023#include "gc/accounting/card_table.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040024#include "intrinsics.h"
25#include "intrinsics_x86.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070026#include "mirror/array-inl.h"
Mathieu Chartiere401d142015-04-22 13:56:20 -070027#include "mirror/class-inl.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010028#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010030#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000031#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010032#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000034namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010035
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000036namespace x86 {
37
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038static constexpr int kCurrentMethodStackOffset = 0;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +010039static constexpr Register kMethodRegisterArgument = EAX;
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010040
Mark Mendell5f874182015-03-04 15:42:45 -050041static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010042
Mark Mendell24f2dfa2015-01-14 19:51:45 -050043static constexpr int kC2ConditionMask = 0x400;
44
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000045static constexpr int kFakeReturnRegister = Register(8);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +000046
Roland Levillain62a46b22015-06-01 18:24:13 +010047#define __ down_cast<X86Assembler*>(codegen->GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +010048
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010049class NullCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010050 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010051 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010052
Alexandre Rames2ed20af2015-03-06 13:55:35 +000053 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010054 __ Bind(GetEntryLabel());
55 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
Mingyao Yang2be48692015-03-31 17:03:08 -070056 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010057 }
58
59 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010060 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
62};
63
Calin Juravled0d48522014-11-04 16:40:20 +000064class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
65 public:
66 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
67
Alexandre Rames2ed20af2015-03-06 13:55:35 +000068 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000069 __ Bind(GetEntryLabel());
70 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
Mingyao Yang2be48692015-03-31 17:03:08 -070071 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Calin Juravled0d48522014-11-04 16:40:20 +000072 }
73
74 private:
75 HDivZeroCheck* const instruction_;
76 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
77};
78
Calin Juravlebacfec32014-11-14 15:54:36 +000079class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 {
Calin Juravled0d48522014-11-04 16:40:20 +000080 public:
Calin Juravlebacfec32014-11-14 15:54:36 +000081 explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +000082
Alexandre Rames2ed20af2015-03-06 13:55:35 +000083 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000084 __ Bind(GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +000085 if (is_div_) {
86 __ negl(reg_);
87 } else {
88 __ movl(reg_, Immediate(0));
89 }
Calin Juravled0d48522014-11-04 16:40:20 +000090 __ jmp(GetExitLabel());
91 }
92
93 private:
94 Register reg_;
Calin Juravlebacfec32014-11-14 15:54:36 +000095 bool is_div_;
96 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
Calin Juravled0d48522014-11-04 16:40:20 +000097};
98
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010099class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100100 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100101 BoundsCheckSlowPathX86(HBoundsCheck* instruction,
102 Location index_location,
103 Location length_location)
Roland Levillain199f3362014-11-27 17:15:16 +0000104 : instruction_(instruction),
105 index_location_(index_location),
106 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100107
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000108 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100109 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100110 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000111 // We're moving two locations to locations that could overlap, so we need a parallel
112 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100113 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000114 x86_codegen->EmitParallelMoves(
115 index_location_,
116 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100117 Primitive::kPrimInt,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000118 length_location_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100119 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
120 Primitive::kPrimInt);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100121 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
Mingyao Yang2be48692015-03-31 17:03:08 -0700122 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100123 }
124
125 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100126 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100127 const Location index_location_;
128 const Location length_location_;
129
130 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
131};
132
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100133class SuspendCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000134 public:
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000135 SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100136 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000137
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000138 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100139 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000140 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000141 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000142 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
Mingyao Yang2be48692015-03-31 17:03:08 -0700143 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000144 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100145 if (successor_ == nullptr) {
146 __ jmp(GetReturnLabel());
147 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100148 __ jmp(x86_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100149 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000150 }
151
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100152 Label* GetReturnLabel() {
153 DCHECK(successor_ == nullptr);
154 return &return_label_;
155 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000156
Nicolas Geoffraydb216f42015-05-05 17:02:20 +0100157 HBasicBlock* GetSuccessor() const {
158 return successor_;
159 }
160
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000161 private:
162 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100163 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000164 Label return_label_;
165
166 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
167};
168
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000169class LoadStringSlowPathX86 : public SlowPathCodeX86 {
170 public:
171 explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {}
172
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000173 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000174 LocationSummary* locations = instruction_->GetLocations();
175 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
176
177 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
178 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000179 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000180
181 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800182 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000183 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString)));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000184 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000185 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000186 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000187
188 __ jmp(GetExitLabel());
189 }
190
191 private:
192 HLoadString* const instruction_;
193
194 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
195};
196
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000197class LoadClassSlowPathX86 : public SlowPathCodeX86 {
198 public:
199 LoadClassSlowPathX86(HLoadClass* cls,
200 HInstruction* at,
201 uint32_t dex_pc,
202 bool do_clinit)
203 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
204 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
205 }
206
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000207 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000208 LocationSummary* locations = at_->GetLocations();
209 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
210 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000211 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000212
213 InvokeRuntimeCallingConvention calling_convention;
214 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000215 __ fs()->call(Address::Absolute(do_clinit_
216 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage)
217 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType)));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000218 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000219
220 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000221 Location out = locations->Out();
222 if (out.IsValid()) {
223 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
224 x86_codegen->Move32(out, Location::RegisterLocation(EAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000225 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000226
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000227 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000228 __ jmp(GetExitLabel());
229 }
230
231 private:
232 // The class this slow path will load.
233 HLoadClass* const cls_;
234
235 // The instruction where this slow path is happening.
236 // (Might be the load class or an initialization check).
237 HInstruction* const at_;
238
239 // The dex PC of `at_`.
240 const uint32_t dex_pc_;
241
242 // Whether to initialize the class.
243 const bool do_clinit_;
244
245 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
246};
247
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000248class TypeCheckSlowPathX86 : public SlowPathCodeX86 {
249 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000250 TypeCheckSlowPathX86(HInstruction* instruction,
251 Location class_to_check,
252 Location object_class,
253 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000254 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000255 class_to_check_(class_to_check),
256 object_class_(object_class),
257 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000258
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000259 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000260 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000261 DCHECK(instruction_->IsCheckCast()
262 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000263
264 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
265 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000266 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000267
268 // We're moving two locations to locations that could overlap, so we need a parallel
269 // move resolver.
270 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000271 x86_codegen->EmitParallelMoves(
272 class_to_check_,
273 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100274 Primitive::kPrimNot,
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000275 object_class_,
Nicolas Geoffray90218252015-04-15 11:56:51 +0100276 Location::RegisterLocation(calling_convention.GetRegisterAt(1)),
277 Primitive::kPrimNot);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000279 if (instruction_->IsInstanceOf()) {
Roland Levillain199f3362014-11-27 17:15:16 +0000280 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize,
281 pInstanceofNonTrivial)));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000282 } else {
283 DCHECK(instruction_->IsCheckCast());
284 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast)));
285 }
286
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000287 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000288 if (instruction_->IsInstanceOf()) {
289 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
290 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000291 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000292
293 __ jmp(GetExitLabel());
294 }
295
296 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000297 HInstruction* const instruction_;
298 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000299 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000300 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000301
302 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
303};
304
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700305class DeoptimizationSlowPathX86 : public SlowPathCodeX86 {
306 public:
307 explicit DeoptimizationSlowPathX86(HInstruction* instruction)
308 : instruction_(instruction) {}
309
310 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
311 __ Bind(GetEntryLabel());
312 SaveLiveRegisters(codegen, instruction_->GetLocations());
313 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeoptimize)));
314 // No need to restore live registers.
315 DCHECK(instruction_->IsDeoptimize());
316 HDeoptimize* deoptimize = instruction_->AsDeoptimize();
317 uint32_t dex_pc = deoptimize->GetDexPc();
318 codegen->RecordPcInfo(instruction_, dex_pc, this);
319 }
320
321 private:
322 HInstruction* const instruction_;
323 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathX86);
324};
325
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100326#undef __
Roland Levillain62a46b22015-06-01 18:24:13 +0100327#define __ down_cast<X86Assembler*>(GetAssembler())->
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100328
Dave Allison20dfc792014-06-16 20:44:29 -0700329inline Condition X86Condition(IfCondition cond) {
330 switch (cond) {
331 case kCondEQ: return kEqual;
332 case kCondNE: return kNotEqual;
333 case kCondLT: return kLess;
334 case kCondLE: return kLessEqual;
335 case kCondGT: return kGreater;
336 case kCondGE: return kGreaterEqual;
337 default:
338 LOG(FATAL) << "Unknown if condition";
339 }
340 return kEqual;
341}
342
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100343void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100344 stream << Register(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100345}
346
347void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
David Brazdilc74652862015-05-13 17:50:09 +0100348 stream << XmmRegister(reg);
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100349}
350
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100351size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
352 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
353 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100354}
355
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100356size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
357 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
358 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100359}
360
Mark Mendell7c8d0092015-01-26 11:21:33 -0500361size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
362 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
363 return GetFloatingPointSpillSlotSize();
364}
365
366size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
367 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
368 return GetFloatingPointSpillSlotSize();
369}
370
Mark Mendellfb8d2792015-03-31 22:16:59 -0400371CodeGeneratorX86::CodeGeneratorX86(HGraph* graph,
372 const X86InstructionSetFeatures& isa_features,
373 const CompilerOptions& compiler_options)
Mark Mendell5f874182015-03-04 15:42:45 -0500374 : CodeGenerator(graph,
375 kNumberOfCpuRegisters,
376 kNumberOfXmmRegisters,
377 kNumberOfRegisterPairs,
378 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
379 arraysize(kCoreCalleeSaves))
380 | (1 << kFakeReturnRegister),
381 0,
382 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100383 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100384 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100385 instruction_visitor_(graph, this),
Mark Mendellfb8d2792015-03-31 22:16:59 -0400386 move_resolver_(graph->GetArena(), this),
387 isa_features_(isa_features) {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000388 // Use a fake return address register to mimic Quick.
389 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100390}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100391
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100392Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100393 switch (type) {
394 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100395 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100396 X86ManagedRegister pair =
397 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100398 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
399 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100400 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
401 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100402 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100403 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100404 }
405
406 case Primitive::kPrimByte:
407 case Primitive::kPrimBoolean:
408 case Primitive::kPrimChar:
409 case Primitive::kPrimShort:
410 case Primitive::kPrimInt:
411 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100412 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100413 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100414 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100415 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
416 X86ManagedRegister current =
417 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
418 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100419 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100420 }
421 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100422 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100423 }
424
425 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100426 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100427 return Location::FpuRegisterLocation(
428 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100429 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100430
431 case Primitive::kPrimVoid:
432 LOG(FATAL) << "Unreachable type " << type;
433 }
434
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100435 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100436}
437
Mark Mendell5f874182015-03-04 15:42:45 -0500438void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100439 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100440 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100441
442 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100443 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100444
Mark Mendell5f874182015-03-04 15:42:45 -0500445 if (is_baseline) {
446 blocked_core_registers_[EBP] = true;
447 blocked_core_registers_[ESI] = true;
448 blocked_core_registers_[EDI] = true;
449 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100450
451 UpdateBlockedPairRegisters();
452}
453
454void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
455 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
456 X86ManagedRegister current =
457 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
458 if (blocked_core_registers_[current.AsRegisterPairLow()]
459 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
460 blocked_register_pairs_[i] = true;
461 }
462 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100463}
464
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100465InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
466 : HGraphVisitor(graph),
467 assembler_(codegen->GetAssembler()),
468 codegen_(codegen) {}
469
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100470static dwarf::Reg DWARFReg(Register reg) {
David Srbecky9d8606d2015-04-12 09:35:32 +0100471 return dwarf::Reg::X86Core(static_cast<int>(reg));
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100472}
473
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000474void CodeGeneratorX86::GenerateFrameEntry() {
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100475 __ cfi().SetCurrentCFAOffset(kX86WordSize); // return address
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000476 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000477 bool skip_overflow_check =
478 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000479 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000480
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000481 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100482 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100483 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100484 }
485
Mark Mendell5f874182015-03-04 15:42:45 -0500486 if (HasEmptyFrame()) {
487 return;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000488 }
Mark Mendell5f874182015-03-04 15:42:45 -0500489
490 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
491 Register reg = kCoreCalleeSaves[i];
492 if (allocated_registers_.ContainsCoreRegister(reg)) {
493 __ pushl(reg);
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100494 __ cfi().AdjustCFAOffset(kX86WordSize);
495 __ cfi().RelOffset(DWARFReg(reg), 0);
Mark Mendell5f874182015-03-04 15:42:45 -0500496 }
497 }
498
David Srbeckyc6b4dd82015-04-07 20:32:43 +0100499 int adjust = GetFrameSize() - FrameEntrySpillSize();
500 __ subl(ESP, Immediate(adjust));
501 __ cfi().AdjustCFAOffset(adjust);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100502 __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000503}
504
505void CodeGeneratorX86::GenerateFrameExit() {
David Srbeckyc34dc932015-04-12 09:27:43 +0100506 __ cfi().RememberState();
507 if (!HasEmptyFrame()) {
508 int adjust = GetFrameSize() - FrameEntrySpillSize();
509 __ addl(ESP, Immediate(adjust));
510 __ cfi().AdjustCFAOffset(-adjust);
Mark Mendell5f874182015-03-04 15:42:45 -0500511
David Srbeckyc34dc932015-04-12 09:27:43 +0100512 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
513 Register reg = kCoreCalleeSaves[i];
514 if (allocated_registers_.ContainsCoreRegister(reg)) {
515 __ popl(reg);
516 __ cfi().AdjustCFAOffset(-static_cast<int>(kX86WordSize));
517 __ cfi().Restore(DWARFReg(reg));
518 }
Mark Mendell5f874182015-03-04 15:42:45 -0500519 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000520 }
David Srbeckyc34dc932015-04-12 09:27:43 +0100521 __ ret();
522 __ cfi().RestoreState();
523 __ cfi().DefCFAOffset(GetFrameSize());
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000524}
525
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100526void CodeGeneratorX86::Bind(HBasicBlock* block) {
527 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000528}
529
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100530void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000531 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100532 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000533}
534
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100535Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
536 switch (load->GetType()) {
537 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100538 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100539 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100540
541 case Primitive::kPrimInt:
542 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100543 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100544 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100545
546 case Primitive::kPrimBoolean:
547 case Primitive::kPrimByte:
548 case Primitive::kPrimChar:
549 case Primitive::kPrimShort:
550 case Primitive::kPrimVoid:
551 LOG(FATAL) << "Unexpected type " << load->GetType();
Andreas Gampe65b798e2015-04-06 09:35:22 -0700552 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100553 }
554
555 LOG(FATAL) << "Unreachable";
Andreas Gampe65b798e2015-04-06 09:35:22 -0700556 UNREACHABLE();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100557}
558
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +0100559Location InvokeDexCallingConventionVisitorX86::GetReturnLocation(Primitive::Type type) const {
560 switch (type) {
561 case Primitive::kPrimBoolean:
562 case Primitive::kPrimByte:
563 case Primitive::kPrimChar:
564 case Primitive::kPrimShort:
565 case Primitive::kPrimInt:
566 case Primitive::kPrimNot:
567 return Location::RegisterLocation(EAX);
568
569 case Primitive::kPrimLong:
570 return Location::RegisterPairLocation(EAX, EDX);
571
572 case Primitive::kPrimVoid:
573 return Location::NoLocation();
574
575 case Primitive::kPrimDouble:
576 case Primitive::kPrimFloat:
577 return Location::FpuRegisterLocation(XMM0);
578 }
579}
580
581Location InvokeDexCallingConventionVisitorX86::GetMethodLocation() const {
582 return Location::RegisterLocation(kMethodRegisterArgument);
583}
584
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100585Location InvokeDexCallingConventionVisitorX86::GetNextLocation(Primitive::Type type) {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100586 switch (type) {
587 case Primitive::kPrimBoolean:
588 case Primitive::kPrimByte:
589 case Primitive::kPrimChar:
590 case Primitive::kPrimShort:
591 case Primitive::kPrimInt:
592 case Primitive::kPrimNot: {
593 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000594 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100595 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100596 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100597 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000598 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100599 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100600 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100601
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000602 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100603 uint32_t index = gp_index_;
604 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000605 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100606 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100607 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
608 calling_convention.GetRegisterPairAt(index));
609 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100610 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000611 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
612 }
613 }
614
615 case Primitive::kPrimFloat: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100616 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000617 stack_index_++;
618 if (index < calling_convention.GetNumberOfFpuRegisters()) {
619 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
620 } else {
621 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
622 }
623 }
624
625 case Primitive::kPrimDouble: {
Roland Levillain2d27c8e2015-04-28 15:48:45 +0100626 uint32_t index = float_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000627 stack_index_ += 2;
628 if (index < calling_convention.GetNumberOfFpuRegisters()) {
629 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
630 } else {
631 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100632 }
633 }
634
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100635 case Primitive::kPrimVoid:
636 LOG(FATAL) << "Unexpected parameter type " << type;
637 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100638 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100639 return Location();
640}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100641
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100642void CodeGeneratorX86::Move32(Location destination, Location source) {
643 if (source.Equals(destination)) {
644 return;
645 }
646 if (destination.IsRegister()) {
647 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000648 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100649 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000650 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100651 } else {
652 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000653 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100654 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100655 } else if (destination.IsFpuRegister()) {
656 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000657 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100658 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000659 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100660 } else {
661 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000662 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100663 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100664 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000665 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100666 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000667 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100668 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000669 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500670 } else if (source.IsConstant()) {
671 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000672 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -0500673 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100674 } else {
675 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100676 __ pushl(Address(ESP, source.GetStackIndex()));
677 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100678 }
679 }
680}
681
682void CodeGeneratorX86::Move64(Location destination, Location source) {
683 if (source.Equals(destination)) {
684 return;
685 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100686 if (destination.IsRegisterPair()) {
687 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000688 EmitParallelMoves(
689 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
690 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100691 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000692 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100693 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
694 Primitive::kPrimInt);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100695 } else if (source.IsFpuRegister()) {
696 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100697 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000698 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100699 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100700 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
701 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100702 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
703 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100704 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500705 if (source.IsFpuRegister()) {
706 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
707 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000708 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100709 } else {
710 LOG(FATAL) << "Unimplemented";
711 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100712 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000713 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100714 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000715 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100716 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100717 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100718 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100719 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000720 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000721 } else if (source.IsConstant()) {
722 HConstant* constant = source.GetConstant();
723 int64_t value;
724 if (constant->IsLongConstant()) {
725 value = constant->AsLongConstant()->GetValue();
726 } else {
727 DCHECK(constant->IsDoubleConstant());
Roland Levillainda4d79b2015-03-24 14:36:11 +0000728 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000729 }
730 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
731 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100732 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000733 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000734 EmitParallelMoves(
735 Location::StackSlot(source.GetStackIndex()),
736 Location::StackSlot(destination.GetStackIndex()),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100737 Primitive::kPrimInt,
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000738 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray90218252015-04-15 11:56:51 +0100739 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)),
740 Primitive::kPrimInt);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100741 }
742 }
743}
744
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100745void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000746 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100747 if (instruction->IsCurrentMethod()) {
748 Move32(location, Location::StackSlot(kCurrentMethodStackOffset));
749 } else if (locations != nullptr && locations->Out().Equals(location)) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000750 return;
Nicolas Geoffray76b1e172015-05-27 17:18:33 +0100751 } else if (locations != nullptr && locations->Out().IsConstant()) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000752 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000753 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
754 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000755 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000756 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000757 } else if (location.IsStackSlot()) {
758 __ movl(Address(ESP, location.GetStackIndex()), imm);
759 } else {
760 DCHECK(location.IsConstant());
761 DCHECK_EQ(location.GetConstant(), const_to_move);
762 }
763 } else if (const_to_move->IsLongConstant()) {
764 int64_t value = const_to_move->AsLongConstant()->GetValue();
765 if (location.IsRegisterPair()) {
766 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
767 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
768 } else if (location.IsDoubleStackSlot()) {
769 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000770 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
771 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000772 } else {
773 DCHECK(location.IsConstant());
774 DCHECK_EQ(location.GetConstant(), instruction);
775 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100776 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000777 } else if (instruction->IsTemporary()) {
778 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000779 if (temp_location.IsStackSlot()) {
780 Move32(location, temp_location);
781 } else {
782 DCHECK(temp_location.IsDoubleStackSlot());
783 Move64(location, temp_location);
784 }
Roland Levillain476df552014-10-09 17:51:36 +0100785 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100786 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100787 switch (instruction->GetType()) {
788 case Primitive::kPrimBoolean:
789 case Primitive::kPrimByte:
790 case Primitive::kPrimChar:
791 case Primitive::kPrimShort:
792 case Primitive::kPrimInt:
793 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100794 case Primitive::kPrimFloat:
795 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100796 break;
797
798 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100799 case Primitive::kPrimDouble:
800 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100801 break;
802
803 default:
804 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
805 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000806 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100807 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100808 switch (instruction->GetType()) {
809 case Primitive::kPrimBoolean:
810 case Primitive::kPrimByte:
811 case Primitive::kPrimChar:
812 case Primitive::kPrimShort:
813 case Primitive::kPrimInt:
814 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100815 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000816 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100817 break;
818
819 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100820 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000821 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100822 break;
823
824 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100825 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100826 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000827 }
828}
829
830void LocationsBuilderX86::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000831 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000832}
833
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000834void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000835 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100836 DCHECK(!successor->IsExitBlock());
837
838 HBasicBlock* block = got->GetBlock();
839 HInstruction* previous = got->GetPrevious();
840
841 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000842 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100843 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
844 return;
845 }
846
847 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
848 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
849 }
850 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000851 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000852 }
853}
854
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000855void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000856 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000857}
858
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000859void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700860 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000861}
862
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700863void InstructionCodeGeneratorX86::GenerateTestAndBranch(HInstruction* instruction,
864 Label* true_target,
865 Label* false_target,
866 Label* always_true_target) {
867 HInstruction* cond = instruction->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100868 if (cond->IsIntConstant()) {
869 // Constant condition, statically compared against 1.
870 int32_t cond_value = cond->AsIntConstant()->GetValue();
871 if (cond_value == 1) {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700872 if (always_true_target != nullptr) {
873 __ jmp(always_true_target);
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100874 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100875 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100876 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100877 DCHECK_EQ(cond_value, 0);
878 }
879 } else {
880 bool materialized =
881 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
882 // Moves do not affect the eflags register, so if the condition is
883 // evaluated just before the if, we don't need to evaluate it
884 // again.
885 bool eflags_set = cond->IsCondition()
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700886 && cond->AsCondition()->IsBeforeWhenDisregardMoves(instruction);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100887 if (materialized) {
888 if (!eflags_set) {
889 // Materialized condition, compare against 0.
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700890 Location lhs = instruction->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100891 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -0500892 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100893 } else {
894 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
895 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700896 __ j(kNotEqual, true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100897 } else {
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700898 __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100899 }
900 } else {
901 Location lhs = cond->GetLocations()->InAt(0);
902 Location rhs = cond->GetLocations()->InAt(1);
903 // LHS is guaranteed to be in a register (see
904 // LocationsBuilderX86::VisitCondition).
905 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000906 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100907 } else if (rhs.IsConstant()) {
Calin Juravleb3306642015-04-20 18:30:42 +0100908 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -0500909 if (constant == 0) {
910 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
911 } else {
912 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
913 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100914 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000915 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100916 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700917 __ j(X86Condition(cond->AsCondition()->GetCondition()), true_target);
Dave Allison20dfc792014-06-16 20:44:29 -0700918 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100919 }
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700920 if (false_target != nullptr) {
921 __ jmp(false_target);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000922 }
923}
924
Mingyao Yangd43b3ac2015-04-01 14:03:04 -0700925void LocationsBuilderX86::VisitIf(HIf* if_instr) {
926 LocationSummary* locations =
927 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
928 HInstruction* cond = if_instr->InputAt(0);
929 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
930 locations->SetInAt(0, Location::Any());
931 }
932}
933
934void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
935 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor());
936 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor());
937 Label* always_true_target = true_target;
938 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
939 if_instr->IfTrueSuccessor())) {
940 always_true_target = nullptr;
941 }
942 if (codegen_->GoesToNextBlock(if_instr->GetBlock(),
943 if_instr->IfFalseSuccessor())) {
944 false_target = nullptr;
945 }
946 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target);
947}
948
949void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
950 LocationSummary* locations = new (GetGraph()->GetArena())
951 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
952 HInstruction* cond = deoptimize->InputAt(0);
953 DCHECK(cond->IsCondition());
954 if (cond->AsCondition()->NeedsMaterialization()) {
955 locations->SetInAt(0, Location::Any());
956 }
957}
958
959void InstructionCodeGeneratorX86::VisitDeoptimize(HDeoptimize* deoptimize) {
960 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena())
961 DeoptimizationSlowPathX86(deoptimize);
962 codegen_->AddSlowPath(slow_path);
963 Label* slow_path_entry = slow_path->GetEntryLabel();
964 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry);
965}
966
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000967void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000968 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000969}
970
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000971void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
972 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000973}
974
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000975void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100976 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000977}
978
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000979void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100980 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700981 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000982}
983
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100984void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100985 LocationSummary* locations =
986 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100987 switch (store->InputAt(1)->GetType()) {
988 case Primitive::kPrimBoolean:
989 case Primitive::kPrimByte:
990 case Primitive::kPrimChar:
991 case Primitive::kPrimShort:
992 case Primitive::kPrimInt:
993 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100994 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100995 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
996 break;
997
998 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100999 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001000 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
1001 break;
1002
1003 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001004 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001005 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001006}
1007
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001008void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001009 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001010}
1011
Roland Levillain0d37cd02015-05-27 16:39:19 +01001012void LocationsBuilderX86::VisitCondition(HCondition* cond) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001013 LocationSummary* locations =
Roland Levillain0d37cd02015-05-27 16:39:19 +01001014 new (GetGraph()->GetArena()) LocationSummary(cond, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001015 locations->SetInAt(0, Location::RequiresRegister());
1016 locations->SetInAt(1, Location::Any());
Roland Levillain0d37cd02015-05-27 16:39:19 +01001017 if (cond->NeedsMaterialization()) {
Mark Mendell5f874182015-03-04 15:42:45 -05001018 // We need a byte register.
1019 locations->SetOut(Location::RegisterLocation(ECX));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001020 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001021}
1022
Roland Levillain0d37cd02015-05-27 16:39:19 +01001023void InstructionCodeGeneratorX86::VisitCondition(HCondition* cond) {
1024 if (cond->NeedsMaterialization()) {
1025 LocationSummary* locations = cond->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001026 Register reg = locations->Out().AsRegister<Register>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +01001027 // Clear register: setcc only sets the low byte.
1028 __ xorl(reg, reg);
Mark Mendell09b84632015-02-13 17:48:38 -05001029 Location lhs = locations->InAt(0);
1030 Location rhs = locations->InAt(1);
1031 if (rhs.IsRegister()) {
1032 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
1033 } else if (rhs.IsConstant()) {
Mingyao Yang8928cab2015-03-03 16:15:23 -08001034 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -05001035 if (constant == 0) {
1036 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
1037 } else {
1038 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
1039 }
Dave Allison20dfc792014-06-16 20:44:29 -07001040 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05001041 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Dave Allison20dfc792014-06-16 20:44:29 -07001042 }
Roland Levillain0d37cd02015-05-27 16:39:19 +01001043 __ setb(X86Condition(cond->GetCondition()), reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001044 }
Dave Allison20dfc792014-06-16 20:44:29 -07001045}
1046
1047void LocationsBuilderX86::VisitEqual(HEqual* comp) {
1048 VisitCondition(comp);
1049}
1050
1051void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
1052 VisitCondition(comp);
1053}
1054
1055void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
1056 VisitCondition(comp);
1057}
1058
1059void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
1060 VisitCondition(comp);
1061}
1062
1063void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
1064 VisitCondition(comp);
1065}
1066
1067void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
1068 VisitCondition(comp);
1069}
1070
1071void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1072 VisitCondition(comp);
1073}
1074
1075void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1076 VisitCondition(comp);
1077}
1078
1079void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
1080 VisitCondition(comp);
1081}
1082
1083void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
1084 VisitCondition(comp);
1085}
1086
1087void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1088 VisitCondition(comp);
1089}
1090
1091void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1092 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001093}
1094
1095void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001096 LocationSummary* locations =
1097 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001098 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001099}
1100
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001101void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001102 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001103 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001104}
1105
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001106void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1107 LocationSummary* locations =
1108 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1109 locations->SetOut(Location::ConstantLocation(constant));
1110}
1111
1112void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1113 // Will be generated at use site.
1114 UNUSED(constant);
1115}
1116
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001117void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001118 LocationSummary* locations =
1119 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001120 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001121}
1122
1123void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1124 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001125 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001126}
1127
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001128void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1129 LocationSummary* locations =
1130 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1131 locations->SetOut(Location::ConstantLocation(constant));
1132}
1133
1134void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1135 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001136 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001137}
1138
1139void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1140 LocationSummary* locations =
1141 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1142 locations->SetOut(Location::ConstantLocation(constant));
1143}
1144
1145void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1146 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001147 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001148}
1149
Calin Juravle27df7582015-04-17 19:12:31 +01001150void LocationsBuilderX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1151 memory_barrier->SetLocations(nullptr);
1152}
1153
1154void InstructionCodeGeneratorX86::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) {
1155 GenerateMemoryBarrier(memory_barrier->GetBarrierKind());
1156}
1157
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001158void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001159 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001160}
1161
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001162void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001163 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001164 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001165}
1166
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001167void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001168 LocationSummary* locations =
1169 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001170 switch (ret->InputAt(0)->GetType()) {
1171 case Primitive::kPrimBoolean:
1172 case Primitive::kPrimByte:
1173 case Primitive::kPrimChar:
1174 case Primitive::kPrimShort:
1175 case Primitive::kPrimInt:
1176 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001177 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001178 break;
1179
1180 case Primitive::kPrimLong:
1181 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001182 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001183 break;
1184
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001185 case Primitive::kPrimFloat:
1186 case Primitive::kPrimDouble:
1187 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001188 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001189 break;
1190
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001191 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001192 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001193 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001194}
1195
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001196void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001197 if (kIsDebugBuild) {
1198 switch (ret->InputAt(0)->GetType()) {
1199 case Primitive::kPrimBoolean:
1200 case Primitive::kPrimByte:
1201 case Primitive::kPrimChar:
1202 case Primitive::kPrimShort:
1203 case Primitive::kPrimInt:
1204 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001205 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001206 break;
1207
1208 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001209 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1210 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001211 break;
1212
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001213 case Primitive::kPrimFloat:
1214 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001215 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001216 break;
1217
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001218 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001219 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001220 }
1221 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001222 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001223}
1224
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001225void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001226 // When we do not run baseline, explicit clinit checks triggered by static
1227 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1228 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001229
Mark Mendellfb8d2792015-03-31 22:16:59 -04001230 IntrinsicLocationsBuilderX86 intrinsic(codegen_);
Mark Mendell09ed1a32015-03-25 08:30:06 -04001231 if (intrinsic.TryDispatch(invoke)) {
1232 return;
1233 }
1234
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001235 HandleInvoke(invoke);
1236}
1237
Mark Mendell09ed1a32015-03-25 08:30:06 -04001238static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1239 if (invoke->GetLocations()->Intrinsified()) {
1240 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1241 intrinsic.Dispatch(invoke);
1242 return true;
1243 }
1244 return false;
1245}
1246
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001247void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain3e3d7332015-04-28 11:00:54 +01001248 // When we do not run baseline, explicit clinit checks triggered by static
1249 // invokes must have been pruned by art::PrepareForRegisterAllocation.
1250 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck());
Roland Levillain4c0eb422015-04-24 16:43:49 +01001251
Mark Mendell09ed1a32015-03-25 08:30:06 -04001252 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1253 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001254 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001255
Mark Mendell09ed1a32015-03-25 08:30:06 -04001256 codegen_->GenerateStaticOrDirectCall(
1257 invoke, invoke->GetLocations()->GetTemp(0).AsRegister<Register>());
Mingyao Yang8693fe12015-04-17 16:51:08 -07001258 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001259}
1260
1261void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1262 HandleInvoke(invoke);
1263}
1264
1265void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Roland Levillain2d27c8e2015-04-28 15:48:45 +01001266 InvokeDexCallingConventionVisitorX86 calling_convention_visitor;
Nicolas Geoffrayfd88f162015-06-03 11:23:52 +01001267 CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001268}
1269
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001270void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001271 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001272 uint32_t method_offset = mirror::Class::EmbeddedVTableEntryOffset(
1273 invoke->GetVTableIndex(), kX86PointerSize).Uint32Value();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001274 LocationSummary* locations = invoke->GetLocations();
1275 Location receiver = locations->InAt(0);
1276 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1277 // temp = object->GetClass();
1278 if (receiver.IsStackSlot()) {
1279 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1280 __ movl(temp, Address(temp, class_offset));
1281 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001282 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001283 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001284 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001285 // temp = temp->GetMethodAt(method_offset);
1286 __ movl(temp, Address(temp, method_offset));
1287 // call temp->GetEntryPoint();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001288 __ call(Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07001289 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001290
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001291 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001292 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001293}
1294
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001295void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1296 HandleInvoke(invoke);
1297 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001298 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001299}
1300
1301void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1302 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001303 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001304 uint32_t method_offset = mirror::Class::EmbeddedImTableEntryOffset(
1305 invoke->GetImtIndex() % mirror::Class::kImtSize, kX86PointerSize).Uint32Value();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001306 LocationSummary* locations = invoke->GetLocations();
1307 Location receiver = locations->InAt(0);
1308 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1309
1310 // Set the hidden argument.
1311 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001312 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001313
1314 // temp = object->GetClass();
1315 if (receiver.IsStackSlot()) {
1316 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1317 __ movl(temp, Address(temp, class_offset));
1318 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001319 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001320 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001321 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001322 // temp = temp->GetImtEntryAt(method_offset);
1323 __ movl(temp, Address(temp, method_offset));
1324 // call temp->GetEntryPoint();
Mathieu Chartiere401d142015-04-22 13:56:20 -07001325 __ call(Address(temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001326 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001327
1328 DCHECK(!codegen_->IsLeafMethod());
1329 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1330}
1331
Roland Levillain88cb1752014-10-20 16:36:47 +01001332void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1333 LocationSummary* locations =
1334 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1335 switch (neg->GetResultType()) {
1336 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001337 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001338 locations->SetInAt(0, Location::RequiresRegister());
1339 locations->SetOut(Location::SameAsFirstInput());
1340 break;
1341
Roland Levillain88cb1752014-10-20 16:36:47 +01001342 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001343 locations->SetInAt(0, Location::RequiresFpuRegister());
1344 locations->SetOut(Location::SameAsFirstInput());
1345 locations->AddTemp(Location::RequiresRegister());
1346 locations->AddTemp(Location::RequiresFpuRegister());
1347 break;
1348
Roland Levillain88cb1752014-10-20 16:36:47 +01001349 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001350 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001351 locations->SetOut(Location::SameAsFirstInput());
1352 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001353 break;
1354
1355 default:
1356 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1357 }
1358}
1359
1360void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1361 LocationSummary* locations = neg->GetLocations();
1362 Location out = locations->Out();
1363 Location in = locations->InAt(0);
1364 switch (neg->GetResultType()) {
1365 case Primitive::kPrimInt:
1366 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001367 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001368 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001369 break;
1370
1371 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001372 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001373 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001374 __ negl(out.AsRegisterPairLow<Register>());
1375 // Negation is similar to subtraction from zero. The least
1376 // significant byte triggers a borrow when it is different from
1377 // zero; to take it into account, add 1 to the most significant
1378 // byte if the carry flag (CF) is set to 1 after the first NEGL
1379 // operation.
1380 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1381 __ negl(out.AsRegisterPairHigh<Register>());
1382 break;
1383
Roland Levillain5368c212014-11-27 15:03:41 +00001384 case Primitive::kPrimFloat: {
1385 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001386 Register constant = locations->GetTemp(0).AsRegister<Register>();
1387 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001388 // Implement float negation with an exclusive or with value
1389 // 0x80000000 (mask for bit 31, representing the sign of a
1390 // single-precision floating-point number).
1391 __ movl(constant, Immediate(INT32_C(0x80000000)));
1392 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001393 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001394 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001395 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001396
Roland Levillain5368c212014-11-27 15:03:41 +00001397 case Primitive::kPrimDouble: {
1398 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001399 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001400 // Implement double negation with an exclusive or with value
1401 // 0x8000000000000000 (mask for bit 63, representing the sign of
1402 // a double-precision floating-point number).
1403 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001404 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001405 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001406 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001407
1408 default:
1409 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1410 }
1411}
1412
Roland Levillaindff1f282014-11-05 14:15:05 +00001413void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001414 Primitive::Type result_type = conversion->GetResultType();
1415 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001416 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001417
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001418 // The float-to-long and double-to-long type conversions rely on a
1419 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001420 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001421 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1422 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001423 ? LocationSummary::kCall
1424 : LocationSummary::kNoCall;
1425 LocationSummary* locations =
1426 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1427
David Brazdilb2bd1c52015-03-25 11:17:37 +00001428 // The Java language does not allow treating boolean as an integral type but
1429 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001430
Roland Levillaindff1f282014-11-05 14:15:05 +00001431 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001432 case Primitive::kPrimByte:
1433 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001434 case Primitive::kPrimBoolean:
1435 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001436 case Primitive::kPrimShort:
1437 case Primitive::kPrimInt:
1438 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001439 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001440 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1441 // Make the output overlap to please the register allocator. This greatly simplifies
1442 // the validation of the linear scan implementation
1443 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001444 break;
1445
1446 default:
1447 LOG(FATAL) << "Unexpected type conversion from " << input_type
1448 << " to " << result_type;
1449 }
1450 break;
1451
Roland Levillain01a8d712014-11-14 16:27:39 +00001452 case Primitive::kPrimShort:
1453 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001454 case Primitive::kPrimBoolean:
1455 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001456 case Primitive::kPrimByte:
1457 case Primitive::kPrimInt:
1458 case Primitive::kPrimChar:
1459 // Processing a Dex `int-to-short' instruction.
1460 locations->SetInAt(0, Location::Any());
1461 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1462 break;
1463
1464 default:
1465 LOG(FATAL) << "Unexpected type conversion from " << input_type
1466 << " to " << result_type;
1467 }
1468 break;
1469
Roland Levillain946e1432014-11-11 17:35:19 +00001470 case Primitive::kPrimInt:
1471 switch (input_type) {
1472 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001473 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001474 locations->SetInAt(0, Location::Any());
1475 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1476 break;
1477
1478 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001479 // Processing a Dex `float-to-int' instruction.
1480 locations->SetInAt(0, Location::RequiresFpuRegister());
1481 locations->SetOut(Location::RequiresRegister());
1482 locations->AddTemp(Location::RequiresFpuRegister());
1483 break;
1484
Roland Levillain946e1432014-11-11 17:35:19 +00001485 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001486 // Processing a Dex `double-to-int' instruction.
1487 locations->SetInAt(0, Location::RequiresFpuRegister());
1488 locations->SetOut(Location::RequiresRegister());
1489 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001490 break;
1491
1492 default:
1493 LOG(FATAL) << "Unexpected type conversion from " << input_type
1494 << " to " << result_type;
1495 }
1496 break;
1497
Roland Levillaindff1f282014-11-05 14:15:05 +00001498 case Primitive::kPrimLong:
1499 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001500 case Primitive::kPrimBoolean:
1501 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001502 case Primitive::kPrimByte:
1503 case Primitive::kPrimShort:
1504 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001505 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001506 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001507 locations->SetInAt(0, Location::RegisterLocation(EAX));
1508 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1509 break;
1510
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001511 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001512 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001513 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001514 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001515 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1516 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1517
Vladimir Marko949c91f2015-01-27 10:48:44 +00001518 // The runtime helper puts the result in EAX, EDX.
1519 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001520 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001521 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001522
1523 default:
1524 LOG(FATAL) << "Unexpected type conversion from " << input_type
1525 << " to " << result_type;
1526 }
1527 break;
1528
Roland Levillain981e4542014-11-14 11:47:14 +00001529 case Primitive::kPrimChar:
1530 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001531 case Primitive::kPrimBoolean:
1532 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001533 case Primitive::kPrimByte:
1534 case Primitive::kPrimShort:
1535 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001536 // Processing a Dex `int-to-char' instruction.
1537 locations->SetInAt(0, Location::Any());
1538 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1539 break;
1540
1541 default:
1542 LOG(FATAL) << "Unexpected type conversion from " << input_type
1543 << " to " << result_type;
1544 }
1545 break;
1546
Roland Levillaindff1f282014-11-05 14:15:05 +00001547 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001548 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001549 case Primitive::kPrimBoolean:
1550 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001551 case Primitive::kPrimByte:
1552 case Primitive::kPrimShort:
1553 case Primitive::kPrimInt:
1554 case Primitive::kPrimChar:
1555 // Processing a Dex `int-to-float' instruction.
1556 locations->SetInAt(0, Location::RequiresRegister());
1557 locations->SetOut(Location::RequiresFpuRegister());
1558 break;
1559
1560 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001561 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001562 locations->SetInAt(0, Location::Any());
1563 locations->SetOut(Location::Any());
Roland Levillain6d0e4832014-11-27 18:31:21 +00001564 break;
1565
Roland Levillaincff13742014-11-17 14:32:17 +00001566 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001567 // Processing a Dex `double-to-float' instruction.
1568 locations->SetInAt(0, Location::RequiresFpuRegister());
1569 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001570 break;
1571
1572 default:
1573 LOG(FATAL) << "Unexpected type conversion from " << input_type
1574 << " to " << result_type;
1575 };
1576 break;
1577
Roland Levillaindff1f282014-11-05 14:15:05 +00001578 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001579 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001580 case Primitive::kPrimBoolean:
1581 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001582 case Primitive::kPrimByte:
1583 case Primitive::kPrimShort:
1584 case Primitive::kPrimInt:
1585 case Primitive::kPrimChar:
1586 // Processing a Dex `int-to-double' instruction.
1587 locations->SetInAt(0, Location::RequiresRegister());
1588 locations->SetOut(Location::RequiresFpuRegister());
1589 break;
1590
1591 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001592 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001593 locations->SetInAt(0, Location::Any());
1594 locations->SetOut(Location::Any());
Roland Levillain647b9ed2014-11-27 12:06:00 +00001595 break;
1596
Roland Levillaincff13742014-11-17 14:32:17 +00001597 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001598 // Processing a Dex `float-to-double' instruction.
1599 locations->SetInAt(0, Location::RequiresFpuRegister());
1600 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001601 break;
1602
1603 default:
1604 LOG(FATAL) << "Unexpected type conversion from " << input_type
1605 << " to " << result_type;
1606 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001607 break;
1608
1609 default:
1610 LOG(FATAL) << "Unexpected type conversion from " << input_type
1611 << " to " << result_type;
1612 }
1613}
1614
1615void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
1616 LocationSummary* locations = conversion->GetLocations();
1617 Location out = locations->Out();
1618 Location in = locations->InAt(0);
1619 Primitive::Type result_type = conversion->GetResultType();
1620 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001621 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001622 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001623 case Primitive::kPrimByte:
1624 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001625 case Primitive::kPrimBoolean:
1626 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001627 case Primitive::kPrimShort:
1628 case Primitive::kPrimInt:
1629 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001630 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001631 if (in.IsRegister()) {
1632 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001633 } else {
1634 DCHECK(in.GetConstant()->IsIntConstant());
1635 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1636 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
1637 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00001638 break;
1639
1640 default:
1641 LOG(FATAL) << "Unexpected type conversion from " << input_type
1642 << " to " << result_type;
1643 }
1644 break;
1645
Roland Levillain01a8d712014-11-14 16:27:39 +00001646 case Primitive::kPrimShort:
1647 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001648 case Primitive::kPrimBoolean:
1649 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001650 case Primitive::kPrimByte:
1651 case Primitive::kPrimInt:
1652 case Primitive::kPrimChar:
1653 // Processing a Dex `int-to-short' instruction.
1654 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001655 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001656 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001657 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00001658 } else {
1659 DCHECK(in.GetConstant()->IsIntConstant());
1660 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001661 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00001662 }
1663 break;
1664
1665 default:
1666 LOG(FATAL) << "Unexpected type conversion from " << input_type
1667 << " to " << result_type;
1668 }
1669 break;
1670
Roland Levillain946e1432014-11-11 17:35:19 +00001671 case Primitive::kPrimInt:
1672 switch (input_type) {
1673 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001674 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001675 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001676 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001677 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001678 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00001679 } else {
1680 DCHECK(in.IsConstant());
1681 DCHECK(in.GetConstant()->IsLongConstant());
1682 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001683 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001684 }
1685 break;
1686
Roland Levillain3f8f9362014-12-02 17:45:01 +00001687 case Primitive::kPrimFloat: {
1688 // Processing a Dex `float-to-int' instruction.
1689 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1690 Register output = out.AsRegister<Register>();
1691 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1692 Label done, nan;
1693
1694 __ movl(output, Immediate(kPrimIntMax));
1695 // temp = int-to-float(output)
1696 __ cvtsi2ss(temp, output);
1697 // if input >= temp goto done
1698 __ comiss(input, temp);
1699 __ j(kAboveEqual, &done);
1700 // if input == NaN goto nan
1701 __ j(kUnordered, &nan);
1702 // output = float-to-int-truncate(input)
1703 __ cvttss2si(output, input);
1704 __ jmp(&done);
1705 __ Bind(&nan);
1706 // output = 0
1707 __ xorl(output, output);
1708 __ Bind(&done);
1709 break;
1710 }
1711
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001712 case Primitive::kPrimDouble: {
1713 // Processing a Dex `double-to-int' instruction.
1714 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1715 Register output = out.AsRegister<Register>();
1716 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1717 Label done, nan;
1718
1719 __ movl(output, Immediate(kPrimIntMax));
1720 // temp = int-to-double(output)
1721 __ cvtsi2sd(temp, output);
1722 // if input >= temp goto done
1723 __ comisd(input, temp);
1724 __ j(kAboveEqual, &done);
1725 // if input == NaN goto nan
1726 __ j(kUnordered, &nan);
1727 // output = double-to-int-truncate(input)
1728 __ cvttsd2si(output, input);
1729 __ jmp(&done);
1730 __ Bind(&nan);
1731 // output = 0
1732 __ xorl(output, output);
1733 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001734 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001735 }
Roland Levillain946e1432014-11-11 17:35:19 +00001736
1737 default:
1738 LOG(FATAL) << "Unexpected type conversion from " << input_type
1739 << " to " << result_type;
1740 }
1741 break;
1742
Roland Levillaindff1f282014-11-05 14:15:05 +00001743 case Primitive::kPrimLong:
1744 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001745 case Primitive::kPrimBoolean:
1746 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001747 case Primitive::kPrimByte:
1748 case Primitive::kPrimShort:
1749 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001750 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001751 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001752 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
1753 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001754 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00001755 __ cdq();
1756 break;
1757
1758 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001759 // Processing a Dex `float-to-long' instruction.
1760 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l)));
Roland Levillain624279f2014-12-04 11:54:28 +00001761 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
1762 break;
1763
Roland Levillaindff1f282014-11-05 14:15:05 +00001764 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001765 // Processing a Dex `double-to-long' instruction.
1766 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l)));
1767 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
Roland Levillaindff1f282014-11-05 14:15:05 +00001768 break;
1769
1770 default:
1771 LOG(FATAL) << "Unexpected type conversion from " << input_type
1772 << " to " << result_type;
1773 }
1774 break;
1775
Roland Levillain981e4542014-11-14 11:47:14 +00001776 case Primitive::kPrimChar:
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 Levillain981e4542014-11-14 11:47:14 +00001780 case Primitive::kPrimByte:
1781 case Primitive::kPrimShort:
1782 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001783 // Processing a Dex `Process a Dex `int-to-char'' instruction.
1784 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001785 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00001786 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001787 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00001788 } else {
1789 DCHECK(in.GetConstant()->IsIntConstant());
1790 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001791 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00001792 }
1793 break;
1794
1795 default:
1796 LOG(FATAL) << "Unexpected type conversion from " << input_type
1797 << " to " << result_type;
1798 }
1799 break;
1800
Roland Levillaindff1f282014-11-05 14:15:05 +00001801 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001802 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001803 case Primitive::kPrimBoolean:
1804 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001805 case Primitive::kPrimByte:
1806 case Primitive::kPrimShort:
1807 case Primitive::kPrimInt:
1808 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001809 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001810 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001811 break;
1812
Roland Levillain6d0e4832014-11-27 18:31:21 +00001813 case Primitive::kPrimLong: {
1814 // Processing a Dex `long-to-float' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001815 size_t adjustment = 0;
Roland Levillain6d0e4832014-11-27 18:31:21 +00001816
Roland Levillain232ade02015-04-20 15:14:36 +01001817 // Create stack space for the call to
1818 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstps below.
1819 // TODO: enhance register allocator to ask for stack temporaries.
1820 if (!in.IsDoubleStackSlot() || !out.IsStackSlot()) {
1821 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
1822 __ subl(ESP, Immediate(adjustment));
1823 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001824
Roland Levillain232ade02015-04-20 15:14:36 +01001825 // Load the value to the FP stack, using temporaries if needed.
1826 PushOntoFPStack(in, 0, adjustment, false, true);
1827
1828 if (out.IsStackSlot()) {
1829 __ fstps(Address(ESP, out.GetStackIndex() + adjustment));
1830 } else {
1831 __ fstps(Address(ESP, 0));
1832 Location stack_temp = Location::StackSlot(0);
1833 codegen_->Move32(out, stack_temp);
1834 }
1835
1836 // Remove the temporary stack space we allocated.
1837 if (adjustment != 0) {
1838 __ addl(ESP, Immediate(adjustment));
1839 }
Roland Levillain6d0e4832014-11-27 18:31:21 +00001840 break;
1841 }
1842
Roland Levillaincff13742014-11-17 14:32:17 +00001843 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001844 // Processing a Dex `double-to-float' instruction.
1845 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001846 break;
1847
1848 default:
1849 LOG(FATAL) << "Unexpected type conversion from " << input_type
1850 << " to " << result_type;
1851 };
1852 break;
1853
Roland Levillaindff1f282014-11-05 14:15:05 +00001854 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001855 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001856 case Primitive::kPrimBoolean:
1857 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001858 case Primitive::kPrimByte:
1859 case Primitive::kPrimShort:
1860 case Primitive::kPrimInt:
1861 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001862 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001863 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001864 break;
1865
Roland Levillain647b9ed2014-11-27 12:06:00 +00001866 case Primitive::kPrimLong: {
1867 // Processing a Dex `long-to-double' instruction.
Roland Levillain232ade02015-04-20 15:14:36 +01001868 size_t adjustment = 0;
Roland Levillain647b9ed2014-11-27 12:06:00 +00001869
Roland Levillain232ade02015-04-20 15:14:36 +01001870 // Create stack space for the call to
1871 // InstructionCodeGeneratorX86::PushOntoFPStack and/or X86Assembler::fstpl below.
1872 // TODO: enhance register allocator to ask for stack temporaries.
1873 if (!in.IsDoubleStackSlot() || !out.IsDoubleStackSlot()) {
1874 adjustment = Primitive::ComponentSize(Primitive::kPrimLong);
1875 __ subl(ESP, Immediate(adjustment));
1876 }
1877
1878 // Load the value to the FP stack, using temporaries if needed.
1879 PushOntoFPStack(in, 0, adjustment, false, true);
1880
1881 if (out.IsDoubleStackSlot()) {
1882 __ fstpl(Address(ESP, out.GetStackIndex() + adjustment));
1883 } else {
1884 __ fstpl(Address(ESP, 0));
1885 Location stack_temp = Location::DoubleStackSlot(0);
1886 codegen_->Move64(out, stack_temp);
1887 }
1888
1889 // Remove the temporary stack space we allocated.
1890 if (adjustment != 0) {
1891 __ addl(ESP, Immediate(adjustment));
1892 }
Roland Levillain647b9ed2014-11-27 12:06:00 +00001893 break;
1894 }
1895
Roland Levillaincff13742014-11-17 14:32:17 +00001896 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001897 // Processing a Dex `float-to-double' instruction.
1898 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001899 break;
1900
1901 default:
1902 LOG(FATAL) << "Unexpected type conversion from " << input_type
1903 << " to " << result_type;
1904 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001905 break;
1906
1907 default:
1908 LOG(FATAL) << "Unexpected type conversion from " << input_type
1909 << " to " << result_type;
1910 }
1911}
1912
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001913void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001914 LocationSummary* locations =
1915 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001916 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001917 case Primitive::kPrimInt: {
1918 locations->SetInAt(0, Location::RequiresRegister());
1919 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1920 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1921 break;
1922 }
1923
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001924 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001925 locations->SetInAt(0, Location::RequiresRegister());
1926 locations->SetInAt(1, Location::Any());
1927 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001928 break;
1929 }
1930
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001931 case Primitive::kPrimFloat:
1932 case Primitive::kPrimDouble: {
1933 locations->SetInAt(0, Location::RequiresFpuRegister());
Calin Juravle3173c8a2015-02-23 15:53:39 +00001934 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001935 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001936 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001937 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001938
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001939 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001940 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1941 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001942 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001943}
1944
1945void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
1946 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001947 Location first = locations->InAt(0);
1948 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05001949 Location out = locations->Out();
1950
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001951 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001952 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001953 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001954 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1955 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
Mark Mendell33bf2452015-05-27 10:08:24 -04001956 } else if (out.AsRegister<Register>() == second.AsRegister<Register>()) {
1957 __ addl(out.AsRegister<Register>(), first.AsRegister<Register>());
Mark Mendell09b84632015-02-13 17:48:38 -05001958 } else {
1959 __ leal(out.AsRegister<Register>(), Address(
1960 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
1961 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001962 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001963 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
1964 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1965 __ addl(out.AsRegister<Register>(), Immediate(value));
1966 } else {
1967 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
1968 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001969 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05001970 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001971 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001972 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001973 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001974 }
1975
1976 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001977 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001978 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1979 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001980 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001981 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
1982 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001983 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001984 } else {
1985 DCHECK(second.IsConstant()) << second;
1986 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1987 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
1988 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001989 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001990 break;
1991 }
1992
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001993 case Primitive::kPrimFloat: {
1994 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001995 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001996 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001997 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001998 }
1999
2000 case Primitive::kPrimDouble: {
2001 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002002 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002003 }
2004 break;
2005 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002006
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002007 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01002008 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00002009 }
2010}
2011
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002012void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002013 LocationSummary* locations =
2014 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002015 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002016 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002017 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002018 locations->SetInAt(0, Location::RequiresRegister());
2019 locations->SetInAt(1, Location::Any());
2020 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002021 break;
2022 }
Calin Juravle11351682014-10-23 15:38:15 +01002023 case Primitive::kPrimFloat:
2024 case Primitive::kPrimDouble: {
2025 locations->SetInAt(0, Location::RequiresFpuRegister());
2026 locations->SetInAt(1, Location::RequiresFpuRegister());
2027 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002028 break;
Calin Juravle11351682014-10-23 15:38:15 +01002029 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002030
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002031 default:
Calin Juravle11351682014-10-23 15:38:15 +01002032 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002033 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002034}
2035
2036void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
2037 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002038 Location first = locations->InAt(0);
2039 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01002040 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002041 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002042 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002043 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002044 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002045 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00002046 __ subl(first.AsRegister<Register>(),
2047 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002048 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002049 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002050 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002051 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002052 }
2053
2054 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00002055 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01002056 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
2057 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002058 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01002059 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002060 __ sbbl(first.AsRegisterPairHigh<Register>(),
2061 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002062 } else {
2063 DCHECK(second.IsConstant()) << second;
2064 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2065 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2066 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002067 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002068 break;
2069 }
2070
Calin Juravle11351682014-10-23 15:38:15 +01002071 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002072 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002073 break;
Calin Juravle11351682014-10-23 15:38:15 +01002074 }
2075
2076 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002077 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002078 break;
2079 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002080
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002081 default:
Calin Juravle11351682014-10-23 15:38:15 +01002082 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002083 }
2084}
2085
Calin Juravle34bacdf2014-10-07 20:23:36 +01002086void LocationsBuilderX86::VisitMul(HMul* mul) {
2087 LocationSummary* locations =
2088 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2089 switch (mul->GetResultType()) {
2090 case Primitive::kPrimInt:
2091 locations->SetInAt(0, Location::RequiresRegister());
2092 locations->SetInAt(1, Location::Any());
2093 locations->SetOut(Location::SameAsFirstInput());
2094 break;
2095 case Primitive::kPrimLong: {
2096 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002097 locations->SetInAt(1, Location::Any());
2098 locations->SetOut(Location::SameAsFirstInput());
2099 // Needed for imul on 32bits with 64bits output.
2100 locations->AddTemp(Location::RegisterLocation(EAX));
2101 locations->AddTemp(Location::RegisterLocation(EDX));
2102 break;
2103 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002104 case Primitive::kPrimFloat:
2105 case Primitive::kPrimDouble: {
2106 locations->SetInAt(0, Location::RequiresFpuRegister());
2107 locations->SetInAt(1, Location::RequiresFpuRegister());
2108 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002109 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002110 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002111
2112 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002113 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002114 }
2115}
2116
2117void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2118 LocationSummary* locations = mul->GetLocations();
2119 Location first = locations->InAt(0);
2120 Location second = locations->InAt(1);
2121 DCHECK(first.Equals(locations->Out()));
2122
2123 switch (mul->GetResultType()) {
2124 case Primitive::kPrimInt: {
2125 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002126 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002127 } else if (second.IsConstant()) {
2128 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002129 __ imull(first.AsRegister<Register>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002130 } else {
2131 DCHECK(second.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002132 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002133 }
2134 break;
2135 }
2136
2137 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002138 Register in1_hi = first.AsRegisterPairHigh<Register>();
2139 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002140 Register eax = locations->GetTemp(0).AsRegister<Register>();
2141 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002142
2143 DCHECK_EQ(EAX, eax);
2144 DCHECK_EQ(EDX, edx);
2145
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002146 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002147 // output: in1
2148 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2149 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2150 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002151 if (second.IsConstant()) {
2152 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002153
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002154 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2155 int32_t low_value = Low32Bits(value);
2156 int32_t high_value = High32Bits(value);
2157 Immediate low(low_value);
2158 Immediate high(high_value);
2159
2160 __ movl(eax, high);
2161 // eax <- in1.lo * in2.hi
2162 __ imull(eax, in1_lo);
2163 // in1.hi <- in1.hi * in2.lo
2164 __ imull(in1_hi, low);
2165 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2166 __ addl(in1_hi, eax);
2167 // move in2_lo to eax to prepare for double precision
2168 __ movl(eax, low);
2169 // edx:eax <- in1.lo * in2.lo
2170 __ mull(in1_lo);
2171 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2172 __ addl(in1_hi, edx);
2173 // in1.lo <- (in1.lo * in2.lo)[31:0];
2174 __ movl(in1_lo, eax);
2175 } else if (second.IsRegisterPair()) {
2176 Register in2_hi = second.AsRegisterPairHigh<Register>();
2177 Register in2_lo = second.AsRegisterPairLow<Register>();
2178
2179 __ movl(eax, in2_hi);
2180 // eax <- in1.lo * in2.hi
2181 __ imull(eax, in1_lo);
2182 // in1.hi <- in1.hi * in2.lo
2183 __ imull(in1_hi, in2_lo);
2184 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2185 __ addl(in1_hi, eax);
2186 // move in1_lo to eax to prepare for double precision
2187 __ movl(eax, in1_lo);
2188 // edx:eax <- in1.lo * in2.lo
2189 __ mull(in2_lo);
2190 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2191 __ addl(in1_hi, edx);
2192 // in1.lo <- (in1.lo * in2.lo)[31:0];
2193 __ movl(in1_lo, eax);
2194 } else {
2195 DCHECK(second.IsDoubleStackSlot()) << second;
2196 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2197 Address in2_lo(ESP, second.GetStackIndex());
2198
2199 __ movl(eax, in2_hi);
2200 // eax <- in1.lo * in2.hi
2201 __ imull(eax, in1_lo);
2202 // in1.hi <- in1.hi * in2.lo
2203 __ imull(in1_hi, in2_lo);
2204 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2205 __ addl(in1_hi, eax);
2206 // move in1_lo to eax to prepare for double precision
2207 __ movl(eax, in1_lo);
2208 // edx:eax <- in1.lo * in2.lo
2209 __ mull(in2_lo);
2210 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2211 __ addl(in1_hi, edx);
2212 // in1.lo <- (in1.lo * in2.lo)[31:0];
2213 __ movl(in1_lo, eax);
2214 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002215
2216 break;
2217 }
2218
Calin Juravleb5bfa962014-10-21 18:02:24 +01002219 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002220 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002221 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002222 }
2223
2224 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002225 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002226 break;
2227 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002228
2229 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002230 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002231 }
2232}
2233
Roland Levillain232ade02015-04-20 15:14:36 +01002234void InstructionCodeGeneratorX86::PushOntoFPStack(Location source,
2235 uint32_t temp_offset,
2236 uint32_t stack_adjustment,
2237 bool is_fp,
2238 bool is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002239 if (source.IsStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002240 DCHECK(!is_wide);
2241 if (is_fp) {
2242 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2243 } else {
2244 __ filds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2245 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002246 } else if (source.IsDoubleStackSlot()) {
Roland Levillain232ade02015-04-20 15:14:36 +01002247 DCHECK(is_wide);
2248 if (is_fp) {
2249 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2250 } else {
2251 __ fildl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2252 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002253 } else {
2254 // Write the value to the temporary location on the stack and load to FP stack.
Roland Levillain232ade02015-04-20 15:14:36 +01002255 if (!is_wide) {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002256 Location stack_temp = Location::StackSlot(temp_offset);
2257 codegen_->Move32(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002258 if (is_fp) {
2259 __ flds(Address(ESP, temp_offset));
2260 } else {
2261 __ filds(Address(ESP, temp_offset));
2262 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002263 } else {
2264 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2265 codegen_->Move64(stack_temp, source);
Roland Levillain232ade02015-04-20 15:14:36 +01002266 if (is_fp) {
2267 __ fldl(Address(ESP, temp_offset));
2268 } else {
2269 __ fildl(Address(ESP, temp_offset));
2270 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002271 }
2272 }
2273}
2274
2275void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2276 Primitive::Type type = rem->GetResultType();
2277 bool is_float = type == Primitive::kPrimFloat;
2278 size_t elem_size = Primitive::ComponentSize(type);
2279 LocationSummary* locations = rem->GetLocations();
2280 Location first = locations->InAt(0);
2281 Location second = locations->InAt(1);
2282 Location out = locations->Out();
2283
2284 // Create stack space for 2 elements.
2285 // TODO: enhance register allocator to ask for stack temporaries.
2286 __ subl(ESP, Immediate(2 * elem_size));
2287
2288 // Load the values to the FP stack in reverse order, using temporaries if needed.
Roland Levillain232ade02015-04-20 15:14:36 +01002289 const bool is_wide = !is_float;
2290 PushOntoFPStack(second, elem_size, 2 * elem_size, /* is_fp */ true, is_wide);
2291 PushOntoFPStack(first, 0, 2 * elem_size, /* is_fp */ true, is_wide);
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002292
2293 // Loop doing FPREM until we stabilize.
2294 Label retry;
2295 __ Bind(&retry);
2296 __ fprem();
2297
2298 // Move FP status to AX.
2299 __ fstsw();
2300
2301 // And see if the argument reduction is complete. This is signaled by the
2302 // C2 FPU flag bit set to 0.
2303 __ andl(EAX, Immediate(kC2ConditionMask));
2304 __ j(kNotEqual, &retry);
2305
2306 // We have settled on the final value. Retrieve it into an XMM register.
2307 // Store FP top of stack to real stack.
2308 if (is_float) {
2309 __ fsts(Address(ESP, 0));
2310 } else {
2311 __ fstl(Address(ESP, 0));
2312 }
2313
2314 // Pop the 2 items from the FP stack.
2315 __ fucompp();
2316
2317 // Load the value from the stack into an XMM register.
2318 DCHECK(out.IsFpuRegister()) << out;
2319 if (is_float) {
2320 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2321 } else {
2322 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2323 }
2324
2325 // And remove the temporary stack space we allocated.
2326 __ addl(ESP, Immediate(2 * elem_size));
2327}
2328
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002329
2330void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2331 DCHECK(instruction->IsDiv() || instruction->IsRem());
2332
2333 LocationSummary* locations = instruction->GetLocations();
2334 DCHECK(locations->InAt(1).IsConstant());
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002335 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002336
2337 Register out_register = locations->Out().AsRegister<Register>();
2338 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002339 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002340
2341 DCHECK(imm == 1 || imm == -1);
2342
2343 if (instruction->IsRem()) {
2344 __ xorl(out_register, out_register);
2345 } else {
2346 __ movl(out_register, input_register);
2347 if (imm == -1) {
2348 __ negl(out_register);
2349 }
2350 }
2351}
2352
2353
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002354void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002355 LocationSummary* locations = instruction->GetLocations();
2356
2357 Register out_register = locations->Out().AsRegister<Register>();
2358 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002359 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002360
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002361 DCHECK(IsPowerOfTwo(std::abs(imm)));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002362 Register num = locations->GetTemp(0).AsRegister<Register>();
2363
2364 __ leal(num, Address(input_register, std::abs(imm) - 1));
2365 __ testl(input_register, input_register);
2366 __ cmovl(kGreaterEqual, num, input_register);
2367 int shift = CTZ(imm);
2368 __ sarl(num, Immediate(shift));
2369
2370 if (imm < 0) {
2371 __ negl(num);
2372 }
2373
2374 __ movl(out_register, num);
2375}
2376
2377void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2378 DCHECK(instruction->IsDiv() || instruction->IsRem());
2379
2380 LocationSummary* locations = instruction->GetLocations();
2381 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2382
2383 Register eax = locations->InAt(0).AsRegister<Register>();
2384 Register out = locations->Out().AsRegister<Register>();
2385 Register num;
2386 Register edx;
2387
2388 if (instruction->IsDiv()) {
2389 edx = locations->GetTemp(0).AsRegister<Register>();
2390 num = locations->GetTemp(1).AsRegister<Register>();
2391 } else {
2392 edx = locations->Out().AsRegister<Register>();
2393 num = locations->GetTemp(0).AsRegister<Register>();
2394 }
2395
2396 DCHECK_EQ(EAX, eax);
2397 DCHECK_EQ(EDX, edx);
2398 if (instruction->IsDiv()) {
2399 DCHECK_EQ(EAX, out);
2400 } else {
2401 DCHECK_EQ(EDX, out);
2402 }
2403
2404 int64_t magic;
2405 int shift;
2406 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2407
2408 Label ndiv;
2409 Label end;
2410 // If numerator is 0, the result is 0, no computation needed.
2411 __ testl(eax, eax);
2412 __ j(kNotEqual, &ndiv);
2413
2414 __ xorl(out, out);
2415 __ jmp(&end);
2416
2417 __ Bind(&ndiv);
2418
2419 // Save the numerator.
2420 __ movl(num, eax);
2421
2422 // EAX = magic
2423 __ movl(eax, Immediate(magic));
2424
2425 // EDX:EAX = magic * numerator
2426 __ imull(num);
2427
2428 if (imm > 0 && magic < 0) {
2429 // EDX += num
2430 __ addl(edx, num);
2431 } else if (imm < 0 && magic > 0) {
2432 __ subl(edx, num);
2433 }
2434
2435 // Shift if needed.
2436 if (shift != 0) {
2437 __ sarl(edx, Immediate(shift));
2438 }
2439
2440 // EDX += 1 if EDX < 0
2441 __ movl(eax, edx);
2442 __ shrl(edx, Immediate(31));
2443 __ addl(edx, eax);
2444
2445 if (instruction->IsRem()) {
2446 __ movl(eax, num);
2447 __ imull(edx, Immediate(imm));
2448 __ subl(eax, edx);
2449 __ movl(edx, eax);
2450 } else {
2451 __ movl(eax, edx);
2452 }
2453 __ Bind(&end);
2454}
2455
Calin Juravlebacfec32014-11-14 15:54:36 +00002456void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2457 DCHECK(instruction->IsDiv() || instruction->IsRem());
2458
2459 LocationSummary* locations = instruction->GetLocations();
2460 Location out = locations->Out();
2461 Location first = locations->InAt(0);
2462 Location second = locations->InAt(1);
2463 bool is_div = instruction->IsDiv();
2464
2465 switch (instruction->GetResultType()) {
2466 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002467 DCHECK_EQ(EAX, first.AsRegister<Register>());
2468 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002469
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002470 if (instruction->InputAt(1)->IsIntConstant()) {
2471 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002472
2473 if (imm == 0) {
2474 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
2475 } else if (imm == 1 || imm == -1) {
2476 DivRemOneOrMinusOne(instruction);
2477 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002478 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002479 } else {
2480 DCHECK(imm <= -2 || imm >= 2);
2481 GenerateDivRemWithAnyConstant(instruction);
2482 }
2483 } else {
2484 SlowPathCodeX86* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002485 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002486 is_div);
2487 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002488
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002489 Register second_reg = second.AsRegister<Register>();
2490 // 0x80000000/-1 triggers an arithmetic exception!
2491 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2492 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002493
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002494 __ cmpl(second_reg, Immediate(-1));
2495 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002496
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002497 // edx:eax <- sign-extended of eax
2498 __ cdq();
2499 // eax = quotient, edx = remainder
2500 __ idivl(second_reg);
2501 __ Bind(slow_path->GetExitLabel());
2502 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002503 break;
2504 }
2505
2506 case Primitive::kPrimLong: {
2507 InvokeRuntimeCallingConvention calling_convention;
2508 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2509 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2510 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2511 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2512 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2513 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2514
2515 if (is_div) {
2516 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv)));
2517 } else {
2518 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod)));
2519 }
2520 uint32_t dex_pc = is_div
2521 ? instruction->AsDiv()->GetDexPc()
2522 : instruction->AsRem()->GetDexPc();
2523 codegen_->RecordPcInfo(instruction, dex_pc);
2524
2525 break;
2526 }
2527
2528 default:
2529 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
2530 }
2531}
2532
Calin Juravle7c4954d2014-10-28 16:57:40 +00002533void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002534 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002535 ? LocationSummary::kCall
2536 : LocationSummary::kNoCall;
2537 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2538
Calin Juravle7c4954d2014-10-28 16:57:40 +00002539 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002540 case Primitive::kPrimInt: {
2541 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002542 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002543 locations->SetOut(Location::SameAsFirstInput());
2544 // Intel uses edx:eax as the dividend.
2545 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002546 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2547 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
2548 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002549 if (div->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002550 locations->AddTemp(Location::RequiresRegister());
2551 }
Calin Juravled0d48522014-11-04 16:40:20 +00002552 break;
2553 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002554 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002555 InvokeRuntimeCallingConvention calling_convention;
2556 locations->SetInAt(0, Location::RegisterPairLocation(
2557 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2558 locations->SetInAt(1, Location::RegisterPairLocation(
2559 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2560 // Runtime helper puts the result in EAX, EDX.
2561 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002562 break;
2563 }
2564 case Primitive::kPrimFloat:
2565 case Primitive::kPrimDouble: {
2566 locations->SetInAt(0, Location::RequiresFpuRegister());
2567 locations->SetInAt(1, Location::RequiresFpuRegister());
2568 locations->SetOut(Location::SameAsFirstInput());
2569 break;
2570 }
2571
2572 default:
2573 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2574 }
2575}
2576
2577void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
2578 LocationSummary* locations = div->GetLocations();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002579 Location out = locations->Out();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002580 Location first = locations->InAt(0);
2581 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002582
2583 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002584 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00002585 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002586 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002587 break;
2588 }
2589
2590 case Primitive::kPrimFloat: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002591 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002592 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002593 break;
2594 }
2595
2596 case Primitive::kPrimDouble: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002597 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002598 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002599 break;
2600 }
2601
2602 default:
2603 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2604 }
2605}
2606
Calin Juravlebacfec32014-11-14 15:54:36 +00002607void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002608 Primitive::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002609
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002610 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
2611 ? LocationSummary::kCall
2612 : LocationSummary::kNoCall;
2613 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00002614
Calin Juravled2ec87d2014-12-08 14:24:46 +00002615 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002616 case Primitive::kPrimInt: {
2617 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002618 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002619 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002620 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2621 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
2622 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002623 if (rem->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002624 locations->AddTemp(Location::RequiresRegister());
2625 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002626 break;
2627 }
2628 case Primitive::kPrimLong: {
2629 InvokeRuntimeCallingConvention calling_convention;
2630 locations->SetInAt(0, Location::RegisterPairLocation(
2631 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2632 locations->SetInAt(1, Location::RegisterPairLocation(
2633 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2634 // Runtime helper puts the result in EAX, EDX.
2635 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2636 break;
2637 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002638 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002639 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002640 locations->SetInAt(0, Location::Any());
2641 locations->SetInAt(1, Location::Any());
2642 locations->SetOut(Location::RequiresFpuRegister());
2643 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002644 break;
2645 }
2646
2647 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002648 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002649 }
2650}
2651
2652void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
2653 Primitive::Type type = rem->GetResultType();
2654 switch (type) {
2655 case Primitive::kPrimInt:
2656 case Primitive::kPrimLong: {
2657 GenerateDivRemIntegral(rem);
2658 break;
2659 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002660 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00002661 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002662 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00002663 break;
2664 }
2665 default:
2666 LOG(FATAL) << "Unexpected rem type " << type;
2667 }
2668}
2669
Calin Juravled0d48522014-11-04 16:40:20 +00002670void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2671 LocationSummary* locations =
2672 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002673 switch (instruction->GetType()) {
2674 case Primitive::kPrimInt: {
2675 locations->SetInAt(0, Location::Any());
2676 break;
2677 }
2678 case Primitive::kPrimLong: {
2679 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2680 if (!instruction->IsConstant()) {
2681 locations->AddTemp(Location::RequiresRegister());
2682 }
2683 break;
2684 }
2685 default:
2686 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2687 }
Calin Juravled0d48522014-11-04 16:40:20 +00002688 if (instruction->HasUses()) {
2689 locations->SetOut(Location::SameAsFirstInput());
2690 }
2691}
2692
2693void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2694 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
2695 codegen_->AddSlowPath(slow_path);
2696
2697 LocationSummary* locations = instruction->GetLocations();
2698 Location value = locations->InAt(0);
2699
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002700 switch (instruction->GetType()) {
2701 case Primitive::kPrimInt: {
2702 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002703 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002704 __ j(kEqual, slow_path->GetEntryLabel());
2705 } else if (value.IsStackSlot()) {
2706 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
2707 __ j(kEqual, slow_path->GetEntryLabel());
2708 } else {
2709 DCHECK(value.IsConstant()) << value;
2710 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2711 __ jmp(slow_path->GetEntryLabel());
2712 }
2713 }
2714 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002715 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002716 case Primitive::kPrimLong: {
2717 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002718 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002719 __ movl(temp, value.AsRegisterPairLow<Register>());
2720 __ orl(temp, value.AsRegisterPairHigh<Register>());
2721 __ j(kEqual, slow_path->GetEntryLabel());
2722 } else {
2723 DCHECK(value.IsConstant()) << value;
2724 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2725 __ jmp(slow_path->GetEntryLabel());
2726 }
2727 }
2728 break;
2729 }
2730 default:
2731 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002732 }
Calin Juravled0d48522014-11-04 16:40:20 +00002733}
2734
Calin Juravle9aec02f2014-11-18 23:06:35 +00002735void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
2736 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2737
2738 LocationSummary* locations =
2739 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2740
2741 switch (op->GetResultType()) {
Mark P Mendell73945692015-04-29 14:56:17 +00002742 case Primitive::kPrimInt:
Calin Juravle9aec02f2014-11-18 23:06:35 +00002743 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00002744 // Can't have Location::Any() and output SameAsFirstInput()
Calin Juravle9aec02f2014-11-18 23:06:35 +00002745 locations->SetInAt(0, Location::RequiresRegister());
Mark P Mendell73945692015-04-29 14:56:17 +00002746 // The shift count needs to be in CL or a constant.
2747 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
Calin Juravle9aec02f2014-11-18 23:06:35 +00002748 locations->SetOut(Location::SameAsFirstInput());
2749 break;
2750 }
2751 default:
2752 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2753 }
2754}
2755
2756void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
2757 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2758
2759 LocationSummary* locations = op->GetLocations();
2760 Location first = locations->InAt(0);
2761 Location second = locations->InAt(1);
2762 DCHECK(first.Equals(locations->Out()));
2763
2764 switch (op->GetResultType()) {
2765 case Primitive::kPrimInt: {
Mark P Mendell73945692015-04-29 14:56:17 +00002766 DCHECK(first.IsRegister());
Roland Levillainf9aac1e2015-04-10 18:12:48 +00002767 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002768 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002769 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002770 DCHECK_EQ(ECX, second_reg);
2771 if (op->IsShl()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00002772 __ shll(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002773 } else if (op->IsShr()) {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00002774 __ sarl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002775 } else {
Roland Levillainf9aac1e2015-04-10 18:12:48 +00002776 __ shrl(first_reg, second_reg);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002777 }
2778 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00002779 int32_t shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue;
2780 if (shift == 0) {
2781 return;
2782 }
2783 Immediate imm(shift);
Roland Levillainf9aac1e2015-04-10 18:12:48 +00002784 if (op->IsShl()) {
2785 __ shll(first_reg, imm);
2786 } else if (op->IsShr()) {
2787 __ sarl(first_reg, imm);
2788 } else {
2789 __ shrl(first_reg, imm);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002790 }
2791 }
2792 break;
2793 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00002794 case Primitive::kPrimLong: {
Mark P Mendell73945692015-04-29 14:56:17 +00002795 if (second.IsRegister()) {
2796 Register second_reg = second.AsRegister<Register>();
2797 DCHECK_EQ(ECX, second_reg);
2798 if (op->IsShl()) {
2799 GenerateShlLong(first, second_reg);
2800 } else if (op->IsShr()) {
2801 GenerateShrLong(first, second_reg);
2802 } else {
2803 GenerateUShrLong(first, second_reg);
2804 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00002805 } else {
Mark P Mendell73945692015-04-29 14:56:17 +00002806 // Shift by a constant.
2807 int shift = second.GetConstant()->AsIntConstant()->GetValue() & kMaxLongShiftValue;
2808 // Nothing to do if the shift is 0, as the input is already the output.
2809 if (shift != 0) {
2810 if (op->IsShl()) {
2811 GenerateShlLong(first, shift);
2812 } else if (op->IsShr()) {
2813 GenerateShrLong(first, shift);
2814 } else {
2815 GenerateUShrLong(first, shift);
2816 }
2817 }
Roland Levillainf9aac1e2015-04-10 18:12:48 +00002818 }
2819 break;
2820 }
Calin Juravle9aec02f2014-11-18 23:06:35 +00002821 default:
2822 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2823 }
2824}
2825
Mark P Mendell73945692015-04-29 14:56:17 +00002826void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, int shift) {
2827 Register low = loc.AsRegisterPairLow<Register>();
2828 Register high = loc.AsRegisterPairHigh<Register>();
Mark Mendellba56d062015-05-05 21:34:03 -04002829 if (shift == 1) {
2830 // This is just an addition.
2831 __ addl(low, low);
2832 __ adcl(high, high);
2833 } else if (shift == 32) {
Mark P Mendell73945692015-04-29 14:56:17 +00002834 // Shift by 32 is easy. High gets low, and low gets 0.
2835 codegen_->EmitParallelMoves(
2836 loc.ToLow(),
2837 loc.ToHigh(),
2838 Primitive::kPrimInt,
2839 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
2840 loc.ToLow(),
2841 Primitive::kPrimInt);
2842 } else if (shift > 32) {
2843 // Low part becomes 0. High part is low part << (shift-32).
2844 __ movl(high, low);
2845 __ shll(high, Immediate(shift - 32));
2846 __ xorl(low, low);
2847 } else {
2848 // Between 1 and 31.
2849 __ shld(high, low, Immediate(shift));
2850 __ shll(low, Immediate(shift));
2851 }
2852}
2853
Calin Juravle9aec02f2014-11-18 23:06:35 +00002854void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
2855 Label done;
2856 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
2857 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
2858 __ testl(shifter, Immediate(32));
2859 __ j(kEqual, &done);
2860 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
2861 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
2862 __ Bind(&done);
2863}
2864
Mark P Mendell73945692015-04-29 14:56:17 +00002865void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, int shift) {
2866 Register low = loc.AsRegisterPairLow<Register>();
2867 Register high = loc.AsRegisterPairHigh<Register>();
2868 if (shift == 32) {
2869 // Need to copy the sign.
2870 DCHECK_NE(low, high);
2871 __ movl(low, high);
2872 __ sarl(high, Immediate(31));
2873 } else if (shift > 32) {
2874 DCHECK_NE(low, high);
2875 // High part becomes sign. Low part is shifted by shift - 32.
2876 __ movl(low, high);
2877 __ sarl(high, Immediate(31));
2878 __ sarl(low, Immediate(shift - 32));
2879 } else {
2880 // Between 1 and 31.
2881 __ shrd(low, high, Immediate(shift));
2882 __ sarl(high, Immediate(shift));
2883 }
2884}
2885
Calin Juravle9aec02f2014-11-18 23:06:35 +00002886void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
2887 Label done;
2888 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2889 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
2890 __ testl(shifter, Immediate(32));
2891 __ j(kEqual, &done);
2892 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2893 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
2894 __ Bind(&done);
2895}
2896
Mark P Mendell73945692015-04-29 14:56:17 +00002897void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, int shift) {
2898 Register low = loc.AsRegisterPairLow<Register>();
2899 Register high = loc.AsRegisterPairHigh<Register>();
2900 if (shift == 32) {
2901 // Shift by 32 is easy. Low gets high, and high gets 0.
2902 codegen_->EmitParallelMoves(
2903 loc.ToHigh(),
2904 loc.ToLow(),
2905 Primitive::kPrimInt,
2906 Location::ConstantLocation(GetGraph()->GetIntConstant(0)),
2907 loc.ToHigh(),
2908 Primitive::kPrimInt);
2909 } else if (shift > 32) {
2910 // Low part is high >> (shift - 32). High part becomes 0.
2911 __ movl(low, high);
2912 __ shrl(low, Immediate(shift - 32));
2913 __ xorl(high, high);
2914 } else {
2915 // Between 1 and 31.
2916 __ shrd(low, high, Immediate(shift));
2917 __ shrl(high, Immediate(shift));
2918 }
2919}
2920
Calin Juravle9aec02f2014-11-18 23:06:35 +00002921void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
2922 Label done;
2923 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2924 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
2925 __ testl(shifter, Immediate(32));
2926 __ j(kEqual, &done);
2927 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2928 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
2929 __ Bind(&done);
2930}
2931
2932void LocationsBuilderX86::VisitShl(HShl* shl) {
2933 HandleShift(shl);
2934}
2935
2936void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
2937 HandleShift(shl);
2938}
2939
2940void LocationsBuilderX86::VisitShr(HShr* shr) {
2941 HandleShift(shr);
2942}
2943
2944void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
2945 HandleShift(shr);
2946}
2947
2948void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
2949 HandleShift(ushr);
2950}
2951
2952void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
2953 HandleShift(ushr);
2954}
2955
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002956void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002957 LocationSummary* locations =
2958 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002959 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002960 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002961 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2962 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002963}
2964
2965void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
2966 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002967 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002968 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002969
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002970 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002971
Nicolas Geoffray39468442014-09-02 15:17:15 +01002972 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002973 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002974}
2975
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002976void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
2977 LocationSummary* locations =
2978 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2979 locations->SetOut(Location::RegisterLocation(EAX));
2980 InvokeRuntimeCallingConvention calling_convention;
2981 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002982 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2983 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002984}
2985
2986void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
2987 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002988 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002989 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
2990
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002991 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002992
2993 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2994 DCHECK(!codegen_->IsLeafMethod());
2995}
2996
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002997void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002998 LocationSummary* locations =
2999 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003000 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
3001 if (location.IsStackSlot()) {
3002 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
3003 } else if (location.IsDoubleStackSlot()) {
3004 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003005 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01003006 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003007}
3008
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01003009void InstructionCodeGeneratorX86::VisitParameterValue(
3010 HParameterValue* instruction ATTRIBUTE_UNUSED) {
3011}
3012
3013void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) {
3014 LocationSummary* locations =
3015 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3016 locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument));
3017}
3018
3019void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01003020}
3021
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003022void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003023 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003024 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003025 locations->SetInAt(0, Location::RequiresRegister());
3026 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003027}
3028
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003029void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
3030 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01003031 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01003032 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01003033 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00003034 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003035 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00003036 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003037 break;
3038
3039 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01003040 __ notl(out.AsRegisterPairLow<Register>());
3041 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01003042 break;
3043
3044 default:
3045 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
3046 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01003047}
3048
David Brazdil66d126e2015-04-03 16:02:44 +01003049void LocationsBuilderX86::VisitBooleanNot(HBooleanNot* bool_not) {
3050 LocationSummary* locations =
3051 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall);
3052 locations->SetInAt(0, Location::RequiresRegister());
3053 locations->SetOut(Location::SameAsFirstInput());
3054}
3055
3056void InstructionCodeGeneratorX86::VisitBooleanNot(HBooleanNot* bool_not) {
David Brazdil66d126e2015-04-03 16:02:44 +01003057 LocationSummary* locations = bool_not->GetLocations();
3058 Location in = locations->InAt(0);
3059 Location out = locations->Out();
3060 DCHECK(in.Equals(out));
3061 __ xorl(out.AsRegister<Register>(), Immediate(1));
3062}
3063
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003064void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003065 LocationSummary* locations =
3066 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00003067 switch (compare->InputAt(0)->GetType()) {
3068 case Primitive::kPrimLong: {
3069 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00003070 locations->SetInAt(1, Location::Any());
3071 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
3072 break;
3073 }
3074 case Primitive::kPrimFloat:
3075 case Primitive::kPrimDouble: {
3076 locations->SetInAt(0, Location::RequiresFpuRegister());
3077 locations->SetInAt(1, Location::RequiresFpuRegister());
3078 locations->SetOut(Location::RequiresRegister());
3079 break;
3080 }
3081 default:
3082 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
3083 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003084}
3085
3086void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003087 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003088 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00003089 Location left = locations->InAt(0);
3090 Location right = locations->InAt(1);
3091
3092 Label less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003093 switch (compare->InputAt(0)->GetType()) {
3094 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003095 Register left_low = left.AsRegisterPairLow<Register>();
3096 Register left_high = left.AsRegisterPairHigh<Register>();
3097 int32_t val_low = 0;
3098 int32_t val_high = 0;
3099 bool right_is_const = false;
3100
3101 if (right.IsConstant()) {
3102 DCHECK(right.GetConstant()->IsLongConstant());
3103 right_is_const = true;
3104 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
3105 val_low = Low32Bits(val);
3106 val_high = High32Bits(val);
3107 }
3108
Calin Juravleddb7df22014-11-25 20:56:51 +00003109 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003110 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003111 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003112 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003113 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003114 DCHECK(right_is_const) << right;
3115 if (val_high == 0) {
3116 __ testl(left_high, left_high);
3117 } else {
3118 __ cmpl(left_high, Immediate(val_high));
3119 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003120 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003121 __ j(kLess, &less); // Signed compare.
3122 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003123 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003124 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003125 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003126 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003127 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003128 DCHECK(right_is_const) << right;
3129 if (val_low == 0) {
3130 __ testl(left_low, left_low);
3131 } else {
3132 __ cmpl(left_low, Immediate(val_low));
3133 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003134 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003135 break;
3136 }
3137 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003138 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003139 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
3140 break;
3141 }
3142 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003143 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00003144 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003145 break;
3146 }
3147 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00003148 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003149 }
Calin Juravleddb7df22014-11-25 20:56:51 +00003150 __ movl(out, Immediate(0));
3151 __ j(kEqual, &done);
3152 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
3153
3154 __ Bind(&greater);
3155 __ movl(out, Immediate(1));
3156 __ jmp(&done);
3157
3158 __ Bind(&less);
3159 __ movl(out, Immediate(-1));
3160
3161 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01003162}
3163
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003164void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003165 LocationSummary* locations =
3166 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01003167 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
3168 locations->SetInAt(i, Location::Any());
3169 }
3170 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003171}
3172
3173void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003174 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003175 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01003176}
3177
Calin Juravle52c48962014-12-16 17:02:57 +00003178void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
3179 /*
3180 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
3181 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
3182 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
3183 */
3184 switch (kind) {
3185 case MemBarrierKind::kAnyAny: {
3186 __ mfence();
3187 break;
3188 }
3189 case MemBarrierKind::kAnyStore:
3190 case MemBarrierKind::kLoadAny:
3191 case MemBarrierKind::kStoreStore: {
3192 // nop
3193 break;
3194 }
3195 default:
3196 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01003197 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003198}
3199
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003200
Mark Mendell09ed1a32015-03-25 08:30:06 -04003201void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
3202 Register temp) {
3203 // TODO: Implement all kinds of calls:
3204 // 1) boot -> boot
3205 // 2) app -> boot
3206 // 3) app -> app
3207 //
3208 // Currently we implement the app -> app logic, which looks up in the resolve cache.
Jeff Hao848f70a2014-01-15 13:49:50 -08003209
3210 if (invoke->IsStringInit()) {
3211 // temp = thread->string_init_entrypoint
3212 __ fs()->movl(temp, Address::Absolute(invoke->GetStringInitOffset()));
Mark Mendell09ed1a32015-03-25 08:30:06 -04003213 // (temp + offset_of_quick_compiled_code)()
3214 __ call(Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07003215 temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
Mark Mendell09ed1a32015-03-25 08:30:06 -04003216 } else {
Jeff Hao848f70a2014-01-15 13:49:50 -08003217 // temp = method;
3218 LoadCurrentMethod(temp);
3219 if (!invoke->IsRecursive()) {
3220 // temp = temp->dex_cache_resolved_methods_;
Mathieu Chartiere401d142015-04-22 13:56:20 -07003221 __ movl(temp, Address(temp, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
Jeff Hao848f70a2014-01-15 13:49:50 -08003222 // temp = temp[index_in_cache]
Mathieu Chartiere401d142015-04-22 13:56:20 -07003223 __ movl(temp, Address(temp,
3224 CodeGenerator::GetCachePointerOffset(invoke->GetDexMethodIndex())));
Jeff Hao848f70a2014-01-15 13:49:50 -08003225 // (temp + offset_of_quick_compiled_code)()
3226 __ call(Address(temp,
Mathieu Chartiere401d142015-04-22 13:56:20 -07003227 ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
Jeff Hao848f70a2014-01-15 13:49:50 -08003228 } else {
3229 __ call(GetFrameEntryLabel());
3230 }
Mark Mendell09ed1a32015-03-25 08:30:06 -04003231 }
3232
3233 DCHECK(!IsLeafMethod());
Mark Mendell09ed1a32015-03-25 08:30:06 -04003234}
3235
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003236void CodeGeneratorX86::MarkGCCard(Register temp,
3237 Register card,
3238 Register object,
3239 Register value,
3240 bool value_can_be_null) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003241 Label is_null;
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003242 if (value_can_be_null) {
3243 __ testl(value, value);
3244 __ j(kEqual, &is_null);
3245 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003246 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3247 __ movl(temp, object);
3248 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003249 __ movb(Address(temp, card, TIMES_1, 0),
3250 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003251 if (value_can_be_null) {
3252 __ Bind(&is_null);
3253 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003254}
3255
Calin Juravle52c48962014-12-16 17:02:57 +00003256void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3257 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003258 LocationSummary* locations =
3259 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003260 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003261
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003262 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3263 locations->SetOut(Location::RequiresFpuRegister());
3264 } else {
3265 // The output overlaps in case of long: we don't want the low move to overwrite
3266 // the object's location.
3267 locations->SetOut(Location::RequiresRegister(),
3268 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3269 : Location::kNoOutputOverlap);
3270 }
Calin Juravle52c48962014-12-16 17:02:57 +00003271
3272 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3273 // Long values can be loaded atomically into an XMM using movsd.
3274 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3275 // and then copy the XMM into the output 32bits at a time).
3276 locations->AddTemp(Location::RequiresFpuRegister());
3277 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003278}
3279
Calin Juravle52c48962014-12-16 17:02:57 +00003280void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3281 const FieldInfo& field_info) {
3282 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003283
Calin Juravle52c48962014-12-16 17:02:57 +00003284 LocationSummary* locations = instruction->GetLocations();
3285 Register base = locations->InAt(0).AsRegister<Register>();
3286 Location out = locations->Out();
3287 bool is_volatile = field_info.IsVolatile();
3288 Primitive::Type field_type = field_info.GetFieldType();
3289 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3290
3291 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003292 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003293 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003294 break;
3295 }
3296
3297 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003298 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003299 break;
3300 }
3301
3302 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003303 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003304 break;
3305 }
3306
3307 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003308 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003309 break;
3310 }
3311
3312 case Primitive::kPrimInt:
3313 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003314 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003315 break;
3316 }
3317
3318 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00003319 if (is_volatile) {
3320 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3321 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003322 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003323 __ movd(out.AsRegisterPairLow<Register>(), temp);
3324 __ psrlq(temp, Immediate(32));
3325 __ movd(out.AsRegisterPairHigh<Register>(), temp);
3326 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003327 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003328 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003329 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003330 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
3331 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003332 break;
3333 }
3334
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003335 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003336 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003337 break;
3338 }
3339
3340 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003341 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003342 break;
3343 }
3344
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003345 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003346 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003347 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003348 }
Calin Juravle52c48962014-12-16 17:02:57 +00003349
Calin Juravle77520bc2015-01-12 18:45:46 +00003350 // Longs are handled in the switch.
3351 if (field_type != Primitive::kPrimLong) {
3352 codegen_->MaybeRecordImplicitNullCheck(instruction);
3353 }
3354
Calin Juravle52c48962014-12-16 17:02:57 +00003355 if (is_volatile) {
3356 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3357 }
3358}
3359
3360void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3361 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3362
3363 LocationSummary* locations =
3364 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3365 locations->SetInAt(0, Location::RequiresRegister());
3366 bool is_volatile = field_info.IsVolatile();
3367 Primitive::Type field_type = field_info.GetFieldType();
3368 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
3369 || (field_type == Primitive::kPrimByte);
3370
3371 // The register allocator does not support multiple
3372 // inputs that die at entry with one in a specific register.
3373 if (is_byte_type) {
3374 // Ensure the value is in a byte register.
3375 locations->SetInAt(1, Location::RegisterLocation(EAX));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003376 } else if (Primitive::IsFloatingPointType(field_type)) {
3377 locations->SetInAt(1, Location::RequiresFpuRegister());
Calin Juravle52c48962014-12-16 17:02:57 +00003378 } else {
3379 locations->SetInAt(1, Location::RequiresRegister());
3380 }
3381 // Temporary registers for the write barrier.
3382 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3383 locations->AddTemp(Location::RequiresRegister());
3384 // Ensure the card is in a byte register.
3385 locations->AddTemp(Location::RegisterLocation(ECX));
3386 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
3387 // 64bits value can be atomically written to an address with movsd and an XMM register.
3388 // We need two XMM registers because there's no easier way to (bit) copy a register pair
3389 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
3390 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
3391 // isolated cases when we need this it isn't worth adding the extra complexity.
3392 locations->AddTemp(Location::RequiresFpuRegister());
3393 locations->AddTemp(Location::RequiresFpuRegister());
3394 }
3395}
3396
3397void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003398 const FieldInfo& field_info,
3399 bool value_can_be_null) {
Calin Juravle52c48962014-12-16 17:02:57 +00003400 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3401
3402 LocationSummary* locations = instruction->GetLocations();
3403 Register base = locations->InAt(0).AsRegister<Register>();
3404 Location value = locations->InAt(1);
3405 bool is_volatile = field_info.IsVolatile();
3406 Primitive::Type field_type = field_info.GetFieldType();
3407 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3408
3409 if (is_volatile) {
3410 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3411 }
3412
3413 switch (field_type) {
3414 case Primitive::kPrimBoolean:
3415 case Primitive::kPrimByte: {
3416 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
3417 break;
3418 }
3419
3420 case Primitive::kPrimShort:
3421 case Primitive::kPrimChar: {
3422 __ movw(Address(base, offset), value.AsRegister<Register>());
3423 break;
3424 }
3425
3426 case Primitive::kPrimInt:
3427 case Primitive::kPrimNot: {
3428 __ movl(Address(base, offset), value.AsRegister<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003429 break;
3430 }
3431
3432 case Primitive::kPrimLong: {
3433 if (is_volatile) {
3434 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3435 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
3436 __ movd(temp1, value.AsRegisterPairLow<Register>());
3437 __ movd(temp2, value.AsRegisterPairHigh<Register>());
3438 __ punpckldq(temp1, temp2);
3439 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00003440 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003441 } else {
3442 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003443 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003444 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
3445 }
3446 break;
3447 }
3448
3449 case Primitive::kPrimFloat: {
3450 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3451 break;
3452 }
3453
3454 case Primitive::kPrimDouble: {
3455 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3456 break;
3457 }
3458
3459 case Primitive::kPrimVoid:
3460 LOG(FATAL) << "Unreachable type " << field_type;
3461 UNREACHABLE();
3462 }
3463
Calin Juravle77520bc2015-01-12 18:45:46 +00003464 // Longs are handled in the switch.
3465 if (field_type != Primitive::kPrimLong) {
3466 codegen_->MaybeRecordImplicitNullCheck(instruction);
3467 }
3468
3469 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3470 Register temp = locations->GetTemp(0).AsRegister<Register>();
3471 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003472 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>(), value_can_be_null);
Calin Juravle77520bc2015-01-12 18:45:46 +00003473 }
3474
Calin Juravle52c48962014-12-16 17:02:57 +00003475 if (is_volatile) {
3476 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3477 }
3478}
3479
3480void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3481 HandleFieldGet(instruction, instruction->GetFieldInfo());
3482}
3483
3484void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3485 HandleFieldGet(instruction, instruction->GetFieldInfo());
3486}
3487
3488void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3489 HandleFieldSet(instruction, instruction->GetFieldInfo());
3490}
3491
3492void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003493 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003494}
3495
3496void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3497 HandleFieldSet(instruction, instruction->GetFieldInfo());
3498}
3499
3500void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003501 HandleFieldSet(instruction, instruction->GetFieldInfo(), instruction->GetValueCanBeNull());
Calin Juravle52c48962014-12-16 17:02:57 +00003502}
3503
3504void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3505 HandleFieldGet(instruction, instruction->GetFieldInfo());
3506}
3507
3508void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3509 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003510}
3511
3512void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003513 LocationSummary* locations =
3514 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003515 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3516 ? Location::RequiresRegister()
3517 : Location::Any();
3518 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003519 if (instruction->HasUses()) {
3520 locations->SetOut(Location::SameAsFirstInput());
3521 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003522}
3523
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003524void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003525 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3526 return;
3527 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003528 LocationSummary* locations = instruction->GetLocations();
3529 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003530
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003531 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
3532 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3533}
3534
3535void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003536 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003537 codegen_->AddSlowPath(slow_path);
3538
3539 LocationSummary* locations = instruction->GetLocations();
3540 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003541
3542 if (obj.IsRegister()) {
Mark Mendell42514f62015-03-31 11:34:22 -04003543 __ testl(obj.AsRegister<Register>(), obj.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003544 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003545 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003546 } else {
3547 DCHECK(obj.IsConstant()) << obj;
3548 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3549 __ jmp(slow_path->GetEntryLabel());
3550 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003551 }
3552 __ j(kEqual, slow_path->GetEntryLabel());
3553}
3554
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003555void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
3556 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3557 GenerateImplicitNullCheck(instruction);
3558 } else {
3559 GenerateExplicitNullCheck(instruction);
3560 }
3561}
3562
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003563void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003564 LocationSummary* locations =
3565 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003566 locations->SetInAt(0, Location::RequiresRegister());
3567 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003568 if (Primitive::IsFloatingPointType(instruction->GetType())) {
3569 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
3570 } else {
3571 // The output overlaps in case of long: we don't want the low move to overwrite
3572 // the array's location.
3573 locations->SetOut(Location::RequiresRegister(),
3574 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3575 : Location::kNoOutputOverlap);
3576 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003577}
3578
3579void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
3580 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003581 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003582 Location index = locations->InAt(1);
3583
Calin Juravle77520bc2015-01-12 18:45:46 +00003584 Primitive::Type type = instruction->GetType();
3585 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003586 case Primitive::kPrimBoolean: {
3587 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003588 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003589 if (index.IsConstant()) {
3590 __ movzxb(out, Address(obj,
3591 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3592 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003593 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003594 }
3595 break;
3596 }
3597
3598 case Primitive::kPrimByte: {
3599 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003600 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003601 if (index.IsConstant()) {
3602 __ movsxb(out, Address(obj,
3603 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3604 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003605 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003606 }
3607 break;
3608 }
3609
3610 case Primitive::kPrimShort: {
3611 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003612 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003613 if (index.IsConstant()) {
3614 __ movsxw(out, Address(obj,
3615 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3616 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003617 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003618 }
3619 break;
3620 }
3621
3622 case Primitive::kPrimChar: {
3623 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003624 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003625 if (index.IsConstant()) {
3626 __ movzxw(out, Address(obj,
3627 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3628 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003629 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003630 }
3631 break;
3632 }
3633
3634 case Primitive::kPrimInt:
3635 case Primitive::kPrimNot: {
3636 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003637 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003638 if (index.IsConstant()) {
3639 __ movl(out, Address(obj,
3640 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3641 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003642 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003643 }
3644 break;
3645 }
3646
3647 case Primitive::kPrimLong: {
3648 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003649 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003650 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003651 if (index.IsConstant()) {
3652 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003653 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003654 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003655 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003656 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003657 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003658 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003659 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003660 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003661 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003662 }
3663 break;
3664 }
3665
Mark Mendell7c8d0092015-01-26 11:21:33 -05003666 case Primitive::kPrimFloat: {
3667 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3668 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3669 if (index.IsConstant()) {
3670 __ movss(out, Address(obj,
3671 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3672 } else {
3673 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
3674 }
3675 break;
3676 }
3677
3678 case Primitive::kPrimDouble: {
3679 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3680 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3681 if (index.IsConstant()) {
3682 __ movsd(out, Address(obj,
3683 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3684 } else {
3685 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
3686 }
3687 break;
3688 }
3689
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003690 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00003691 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003692 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003693 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003694
3695 if (type != Primitive::kPrimLong) {
3696 codegen_->MaybeRecordImplicitNullCheck(instruction);
3697 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003698}
3699
3700void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05003701 // This location builder might end up asking to up to four registers, which is
3702 // not currently possible for baseline. The situation in which we need four
3703 // registers cannot be met by baseline though, because it has not run any
3704 // optimization.
3705
Nicolas Geoffray39468442014-09-02 15:17:15 +01003706 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003707 bool needs_write_barrier =
3708 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3709
Mark Mendell5f874182015-03-04 15:42:45 -05003710 bool needs_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003711
Nicolas Geoffray39468442014-09-02 15:17:15 +01003712 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3713 instruction,
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003714 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003715
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003716 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003717 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003718 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3719 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3720 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003721 } else {
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003722 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
3723 || (value_type == Primitive::kPrimByte);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003724 // We need the inputs to be different than the output in case of long operation.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003725 // In case of a byte operation, the register allocator does not support multiple
3726 // inputs that die at entry with one in a specific register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003727 locations->SetInAt(0, Location::RequiresRegister());
3728 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003729 if (is_byte_type) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003730 // Ensure the value is in a byte register.
3731 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003732 } else if (Primitive::IsFloatingPointType(value_type)) {
3733 locations->SetInAt(2, Location::RequiresFpuRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003734 } else {
Alexandre Rames88c13cd2015-04-14 17:35:39 +01003735 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003736 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003737 // Temporary registers for the write barrier.
3738 if (needs_write_barrier) {
3739 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003740 // Ensure the card is in a byte register.
3741 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003742 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003743 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003744}
3745
3746void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
3747 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003748 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003749 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003750 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003751 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003752 bool needs_runtime_call = locations->WillCall();
3753 bool needs_write_barrier =
3754 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003755
3756 switch (value_type) {
3757 case Primitive::kPrimBoolean:
3758 case Primitive::kPrimByte: {
3759 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003760 if (index.IsConstant()) {
3761 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003762 if (value.IsRegister()) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003763 __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003764 } else {
3765 __ movb(Address(obj, offset),
3766 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3767 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003768 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003769 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003770 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003771 value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003772 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003773 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003774 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3775 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003776 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003777 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003778 break;
3779 }
3780
3781 case Primitive::kPrimShort:
3782 case Primitive::kPrimChar: {
3783 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003784 if (index.IsConstant()) {
3785 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003786 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003787 __ movw(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003788 } else {
3789 __ movw(Address(obj, offset),
3790 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3791 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003792 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003793 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003794 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
3795 value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003796 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003797 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003798 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3799 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003800 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003801 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003802 break;
3803 }
3804
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003805 case Primitive::kPrimInt:
3806 case Primitive::kPrimNot: {
3807 if (!needs_runtime_call) {
3808 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3809 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003810 size_t offset =
3811 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003812 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003813 __ movl(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003814 } else {
3815 DCHECK(value.IsConstant()) << value;
3816 __ movl(Address(obj, offset),
3817 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3818 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003819 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003820 DCHECK(index.IsRegister()) << index;
3821 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003822 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3823 value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003824 } else {
3825 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003826 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003827 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3828 }
3829 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003830 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003831
3832 if (needs_write_barrier) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003833 Register temp = locations->GetTemp(0).AsRegister<Register>();
3834 Register card = locations->GetTemp(1).AsRegister<Register>();
Nicolas Geoffray07276db2015-05-18 14:22:09 +01003835 codegen_->MarkGCCard(
3836 temp, card, obj, value.AsRegister<Register>(), instruction->GetValueCanBeNull());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003837 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003838 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003839 DCHECK_EQ(value_type, Primitive::kPrimNot);
3840 DCHECK(!codegen_->IsLeafMethod());
3841 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
3842 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003843 }
3844 break;
3845 }
3846
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003847 case Primitive::kPrimLong: {
3848 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003849 if (index.IsConstant()) {
3850 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003851 if (value.IsRegisterPair()) {
3852 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003853 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003854 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003855 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003856 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003857 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
3858 __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003859 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003860 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
3861 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003862 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003863 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003864 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003865 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003866 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003867 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003868 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003869 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003870 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003871 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003872 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003873 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003874 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003875 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003876 Immediate(High32Bits(val)));
3877 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003878 }
3879 break;
3880 }
3881
Mark Mendell7c8d0092015-01-26 11:21:33 -05003882 case Primitive::kPrimFloat: {
3883 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3884 DCHECK(value.IsFpuRegister());
3885 if (index.IsConstant()) {
3886 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3887 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3888 } else {
3889 __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3890 value.AsFpuRegister<XmmRegister>());
3891 }
3892 break;
3893 }
3894
3895 case Primitive::kPrimDouble: {
3896 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3897 DCHECK(value.IsFpuRegister());
3898 if (index.IsConstant()) {
3899 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3900 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3901 } else {
3902 __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3903 value.AsFpuRegister<XmmRegister>());
3904 }
3905 break;
3906 }
3907
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003908 case Primitive::kPrimVoid:
3909 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003910 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003911 }
3912}
3913
3914void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
3915 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003916 locations->SetInAt(0, Location::RequiresRegister());
3917 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003918}
3919
3920void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
3921 LocationSummary* locations = instruction->GetLocations();
3922 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003923 Register obj = locations->InAt(0).AsRegister<Register>();
3924 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003925 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003926 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003927}
3928
3929void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003930 LocationSummary* locations =
3931 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003932 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Mark Mendell99dbd682015-04-22 16:18:52 -04003933 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003934 if (instruction->HasUses()) {
3935 locations->SetOut(Location::SameAsFirstInput());
3936 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003937}
3938
3939void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
3940 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003941 Location index_loc = locations->InAt(0);
3942 Location length_loc = locations->InAt(1);
3943 SlowPathCodeX86* slow_path =
3944 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003945
Mark Mendell99dbd682015-04-22 16:18:52 -04003946 if (length_loc.IsConstant()) {
3947 int32_t length = CodeGenerator::GetInt32ValueOf(length_loc.GetConstant());
3948 if (index_loc.IsConstant()) {
3949 // BCE will remove the bounds check if we are guarenteed to pass.
3950 int32_t index = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3951 if (index < 0 || index >= length) {
3952 codegen_->AddSlowPath(slow_path);
3953 __ jmp(slow_path->GetEntryLabel());
3954 } else {
3955 // Some optimization after BCE may have generated this, and we should not
3956 // generate a bounds check if it is a valid range.
3957 }
3958 return;
3959 }
3960
3961 // We have to reverse the jump condition because the length is the constant.
3962 Register index_reg = index_loc.AsRegister<Register>();
3963 __ cmpl(index_reg, Immediate(length));
3964 codegen_->AddSlowPath(slow_path);
3965 __ j(kAboveEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003966 } else {
Mark Mendell99dbd682015-04-22 16:18:52 -04003967 Register length = length_loc.AsRegister<Register>();
3968 if (index_loc.IsConstant()) {
3969 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3970 __ cmpl(length, Immediate(value));
3971 } else {
3972 __ cmpl(length, index_loc.AsRegister<Register>());
3973 }
3974 codegen_->AddSlowPath(slow_path);
3975 __ j(kBelowEqual, slow_path->GetEntryLabel());
Mark Mendellf60c90b2015-03-04 15:12:59 -05003976 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003977}
3978
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003979void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
3980 temp->SetLocations(nullptr);
3981}
3982
3983void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
3984 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003985 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003986}
3987
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003988void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003989 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003990 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003991}
3992
3993void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003994 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3995}
3996
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003997void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
3998 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3999}
4000
4001void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004002 HBasicBlock* block = instruction->GetBlock();
4003 if (block->GetLoopInformation() != nullptr) {
4004 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
4005 // The back edge will generate the suspend check.
4006 return;
4007 }
4008 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
4009 // The goto will generate the suspend check.
4010 return;
4011 }
4012 GenerateSuspendCheck(instruction, nullptr);
4013}
4014
4015void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
4016 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004017 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffraydb216f42015-05-05 17:02:20 +01004018 down_cast<SuspendCheckSlowPathX86*>(instruction->GetSlowPath());
4019 if (slow_path == nullptr) {
4020 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
4021 instruction->SetSlowPath(slow_path);
4022 codegen_->AddSlowPath(slow_path);
4023 if (successor != nullptr) {
4024 DCHECK(successor->IsLoopHeader());
4025 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction);
4026 }
4027 } else {
4028 DCHECK_EQ(slow_path->GetSuccessor(), successor);
4029 }
4030
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004031 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004032 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01004033 if (successor == nullptr) {
4034 __ j(kNotEqual, slow_path->GetEntryLabel());
4035 __ Bind(slow_path->GetReturnLabel());
4036 } else {
4037 __ j(kEqual, codegen_->GetLabelOf(successor));
4038 __ jmp(slow_path->GetEntryLabel());
4039 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00004040}
4041
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004042X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
4043 return codegen_->GetAssembler();
4044}
4045
Mark Mendell7c8d0092015-01-26 11:21:33 -05004046void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004047 ScratchRegisterScope ensure_scratch(
4048 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4049 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4050 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4051 __ movl(temp_reg, Address(ESP, src + stack_offset));
4052 __ movl(Address(ESP, dst + stack_offset), temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004053}
4054
4055void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004056 ScratchRegisterScope ensure_scratch(
4057 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4058 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4059 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4060 __ movl(temp_reg, Address(ESP, src + stack_offset));
4061 __ movl(Address(ESP, dst + stack_offset), temp_reg);
4062 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
4063 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004064}
4065
4066void ParallelMoveResolverX86::EmitMove(size_t index) {
4067 MoveOperands* move = moves_.Get(index);
4068 Location source = move->GetSource();
4069 Location destination = move->GetDestination();
4070
4071 if (source.IsRegister()) {
4072 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004073 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004074 } else {
4075 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004076 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004077 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004078 } else if (source.IsFpuRegister()) {
4079 if (destination.IsFpuRegister()) {
4080 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4081 } else if (destination.IsStackSlot()) {
4082 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4083 } else {
4084 DCHECK(destination.IsDoubleStackSlot());
4085 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
4086 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004087 } else if (source.IsStackSlot()) {
4088 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004089 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004090 } else if (destination.IsFpuRegister()) {
4091 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004092 } else {
4093 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004094 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
4095 }
4096 } else if (source.IsDoubleStackSlot()) {
4097 if (destination.IsFpuRegister()) {
4098 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
4099 } else {
4100 DCHECK(destination.IsDoubleStackSlot()) << destination;
4101 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004102 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004103 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004104 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00004105 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004106 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004107 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05004108 if (value == 0) {
4109 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
4110 } else {
4111 __ movl(destination.AsRegister<Register>(), Immediate(value));
4112 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004113 } else {
4114 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05004115 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05004116 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004117 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004118 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004119 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004120 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004121 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004122 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4123 if (value == 0) {
4124 // Easy handling of 0.0.
4125 __ xorps(dest, dest);
4126 } else {
4127 ScratchRegisterScope ensure_scratch(
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004128 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4129 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
4130 __ movl(temp, Immediate(value));
4131 __ movd(dest, temp);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004132 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05004133 } else {
4134 DCHECK(destination.IsStackSlot()) << destination;
4135 __ movl(Address(ESP, destination.GetStackIndex()), imm);
4136 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004137 } else if (constant->IsLongConstant()) {
4138 int64_t value = constant->AsLongConstant()->GetValue();
4139 int32_t low_value = Low32Bits(value);
4140 int32_t high_value = High32Bits(value);
4141 Immediate low(low_value);
4142 Immediate high(high_value);
4143 if (destination.IsDoubleStackSlot()) {
4144 __ movl(Address(ESP, destination.GetStackIndex()), low);
4145 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4146 } else {
4147 __ movl(destination.AsRegisterPairLow<Register>(), low);
4148 __ movl(destination.AsRegisterPairHigh<Register>(), high);
4149 }
4150 } else {
4151 DCHECK(constant->IsDoubleConstant());
4152 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00004153 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004154 int32_t low_value = Low32Bits(value);
4155 int32_t high_value = High32Bits(value);
4156 Immediate low(low_value);
4157 Immediate high(high_value);
4158 if (destination.IsFpuRegister()) {
4159 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
4160 if (value == 0) {
4161 // Easy handling of 0.0.
4162 __ xorpd(dest, dest);
4163 } else {
4164 __ pushl(high);
4165 __ pushl(low);
4166 __ movsd(dest, Address(ESP, 0));
4167 __ addl(ESP, Immediate(8));
4168 }
4169 } else {
4170 DCHECK(destination.IsDoubleStackSlot()) << destination;
4171 __ movl(Address(ESP, destination.GetStackIndex()), low);
4172 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
4173 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01004174 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004175 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00004176 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004177 }
4178}
4179
Mark Mendella5c19ce2015-04-01 12:51:05 -04004180void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004181 Register suggested_scratch = reg == EAX ? EBX : EAX;
4182 ScratchRegisterScope ensure_scratch(
4183 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
4184
4185 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4186 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
4187 __ movl(Address(ESP, mem + stack_offset), reg);
4188 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004189}
4190
Mark Mendell7c8d0092015-01-26 11:21:33 -05004191void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004192 ScratchRegisterScope ensure_scratch(
4193 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
4194
4195 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
4196 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
4197 __ movl(temp_reg, Address(ESP, mem + stack_offset));
4198 __ movss(Address(ESP, mem + stack_offset), reg);
4199 __ movd(reg, temp_reg);
Mark Mendell7c8d0092015-01-26 11:21:33 -05004200}
4201
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004202void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004203 ScratchRegisterScope ensure_scratch1(
4204 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004205
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004206 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
4207 ScratchRegisterScope ensure_scratch2(
4208 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01004209
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004210 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
4211 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
4212 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
4213 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
4214 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
4215 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004216}
4217
4218void ParallelMoveResolverX86::EmitSwap(size_t index) {
4219 MoveOperands* move = moves_.Get(index);
4220 Location source = move->GetSource();
4221 Location destination = move->GetDestination();
4222
4223 if (source.IsRegister() && destination.IsRegister()) {
Guillaume Sancheze14590b2015-04-15 18:57:27 +00004224 __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004225 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004226 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004227 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004228 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004229 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
4230 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05004231 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
4232 // Use XOR Swap algorithm to avoid a temporary.
4233 DCHECK_NE(source.reg(), destination.reg());
4234 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4235 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
4236 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
4237 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
4238 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
4239 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
4240 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004241 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
4242 // Take advantage of the 16 bytes in the XMM register.
4243 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
4244 Address stack(ESP, destination.GetStackIndex());
4245 // Load the double into the high doubleword.
4246 __ movhpd(reg, stack);
4247
4248 // Store the low double into the destination.
4249 __ movsd(stack, reg);
4250
4251 // Move the high double to the low double.
4252 __ psrldq(reg, Immediate(8));
4253 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
4254 // Take advantage of the 16 bytes in the XMM register.
4255 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
4256 Address stack(ESP, source.GetStackIndex());
4257 // Load the double into the high doubleword.
4258 __ movhpd(reg, stack);
4259
4260 // Store the low double into the destination.
4261 __ movsd(stack, reg);
4262
4263 // Move the high double to the low double.
4264 __ psrldq(reg, Immediate(8));
4265 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
4266 Exchange(destination.GetStackIndex(), source.GetStackIndex());
4267 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004268 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05004269 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01004270 }
4271}
4272
4273void ParallelMoveResolverX86::SpillScratch(int reg) {
4274 __ pushl(static_cast<Register>(reg));
4275}
4276
4277void ParallelMoveResolverX86::RestoreScratch(int reg) {
4278 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004279}
4280
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004281void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004282 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4283 ? LocationSummary::kCallOnSlowPath
4284 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004285 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004286 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004287 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004288 locations->SetOut(Location::RequiresRegister());
4289}
4290
4291void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004292 LocationSummary* locations = cls->GetLocations();
4293 Register out = locations->Out().AsRegister<Register>();
4294 Register current_method = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004295 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004296 DCHECK(!cls->CanCallRuntime());
4297 DCHECK(!cls->MustGenerateClinitCheck());
Mathieu Chartiere401d142015-04-22 13:56:20 -07004298 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004299 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004300 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray76b1e172015-05-27 17:18:33 +01004301 __ movl(out, Address(
Mathieu Chartiere401d142015-04-22 13:56:20 -07004302 current_method, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004303 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004304
4305 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
4306 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4307 codegen_->AddSlowPath(slow_path);
4308 __ testl(out, out);
4309 __ j(kEqual, slow_path->GetEntryLabel());
4310 if (cls->MustGenerateClinitCheck()) {
4311 GenerateClassInitializationCheck(slow_path, out);
4312 } else {
4313 __ Bind(slow_path->GetExitLabel());
4314 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004315 }
4316}
4317
4318void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
4319 LocationSummary* locations =
4320 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4321 locations->SetInAt(0, Location::RequiresRegister());
4322 if (check->HasUses()) {
4323 locations->SetOut(Location::SameAsFirstInput());
4324 }
4325}
4326
4327void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004328 // We assume the class to not be null.
4329 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
4330 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004331 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004332 GenerateClassInitializationCheck(slow_path,
4333 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004334}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004335
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004336void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
4337 SlowPathCodeX86* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004338 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4339 Immediate(mirror::Class::kStatusInitialized));
4340 __ j(kLess, slow_path->GetEntryLabel());
4341 __ Bind(slow_path->GetExitLabel());
4342 // No need for memory fence, thanks to the X86 memory model.
4343}
4344
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004345void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
4346 LocationSummary* locations =
4347 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004348 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004349 locations->SetOut(Location::RequiresRegister());
4350}
4351
4352void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
4353 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
4354 codegen_->AddSlowPath(slow_path);
4355
Nicolas Geoffrayfbdaa302015-05-29 12:06:56 +01004356 LocationSummary* locations = load->GetLocations();
4357 Register out = locations->Out().AsRegister<Register>();
4358 Register current_method = locations->InAt(0).AsRegister<Register>();
Mathieu Chartiere401d142015-04-22 13:56:20 -07004359 __ movl(out, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
Mathieu Chartiereace4582014-11-24 18:29:54 -08004360 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004361 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
4362 __ testl(out, out);
4363 __ j(kEqual, slow_path->GetEntryLabel());
4364 __ Bind(slow_path->GetExitLabel());
4365}
4366
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004367void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
4368 LocationSummary* locations =
4369 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4370 locations->SetOut(Location::RequiresRegister());
4371}
4372
4373void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
4374 Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004375 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004376 __ fs()->movl(address, Immediate(0));
4377}
4378
4379void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
4380 LocationSummary* locations =
4381 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4382 InvokeRuntimeCallingConvention calling_convention;
4383 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4384}
4385
4386void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
4387 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
4388 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4389}
4390
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004391void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004392 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4393 ? LocationSummary::kNoCall
4394 : LocationSummary::kCallOnSlowPath;
4395 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4396 locations->SetInAt(0, Location::RequiresRegister());
4397 locations->SetInAt(1, Location::Any());
4398 locations->SetOut(Location::RequiresRegister());
4399}
4400
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004401void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004402 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004403 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004404 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004405 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004406 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4407 Label done, zero;
4408 SlowPathCodeX86* slow_path = nullptr;
4409
4410 // Return 0 if `obj` is null.
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004411 // Avoid null check if we know obj is not null.
4412 if (instruction->MustDoNullCheck()) {
4413 __ testl(obj, obj);
4414 __ j(kEqual, &zero);
4415 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004416 __ movl(out, Address(obj, class_offset));
4417 // Compare the class of `obj` with `cls`.
4418 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004419 __ cmpl(out, cls.AsRegister<Register>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004420 } else {
4421 DCHECK(cls.IsStackSlot()) << cls;
4422 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
4423 }
4424
4425 if (instruction->IsClassFinal()) {
4426 // Classes must be equal for the instanceof to succeed.
4427 __ j(kNotEqual, &zero);
4428 __ movl(out, Immediate(1));
4429 __ jmp(&done);
4430 } else {
4431 // If the classes are not equal, we go into a slow path.
4432 DCHECK(locations->OnlyCallsOnSlowPath());
4433 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004434 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004435 codegen_->AddSlowPath(slow_path);
4436 __ j(kNotEqual, slow_path->GetEntryLabel());
4437 __ movl(out, Immediate(1));
4438 __ jmp(&done);
4439 }
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004440
4441 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) {
4442 __ Bind(&zero);
4443 __ movl(out, Immediate(0));
4444 }
4445
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004446 if (slow_path != nullptr) {
4447 __ Bind(slow_path->GetExitLabel());
4448 }
4449 __ Bind(&done);
4450}
4451
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004452void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
4453 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4454 instruction, LocationSummary::kCallOnSlowPath);
4455 locations->SetInAt(0, Location::RequiresRegister());
4456 locations->SetInAt(1, Location::Any());
4457 locations->AddTemp(Location::RequiresRegister());
4458}
4459
4460void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
4461 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004462 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004463 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004464 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004465 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4466 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
4467 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4468 codegen_->AddSlowPath(slow_path);
4469
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004470 // Avoid null check if we know obj is not null.
4471 if (instruction->MustDoNullCheck()) {
4472 __ testl(obj, obj);
4473 __ j(kEqual, slow_path->GetExitLabel());
4474 }
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004475
Guillaume "Vermeille" Sanchezaf888352015-04-20 14:41:30 +01004476 __ movl(temp, Address(obj, class_offset));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004477 // Compare the class of `obj` with `cls`.
4478 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004479 __ cmpl(temp, cls.AsRegister<Register>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004480 } else {
4481 DCHECK(cls.IsStackSlot()) << cls;
4482 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
4483 }
4484
4485 __ j(kNotEqual, slow_path->GetEntryLabel());
4486 __ Bind(slow_path->GetExitLabel());
4487}
4488
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004489void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4490 LocationSummary* locations =
4491 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4492 InvokeRuntimeCallingConvention calling_convention;
4493 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4494}
4495
4496void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4497 __ fs()->call(Address::Absolute(instruction->IsEnter()
4498 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject)
4499 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject)));
4500 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4501}
4502
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004503void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4504void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4505void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4506
4507void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4508 LocationSummary* locations =
4509 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4510 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4511 || instruction->GetResultType() == Primitive::kPrimLong);
4512 locations->SetInAt(0, Location::RequiresRegister());
4513 locations->SetInAt(1, Location::Any());
4514 locations->SetOut(Location::SameAsFirstInput());
4515}
4516
4517void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
4518 HandleBitwiseOperation(instruction);
4519}
4520
4521void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
4522 HandleBitwiseOperation(instruction);
4523}
4524
4525void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
4526 HandleBitwiseOperation(instruction);
4527}
4528
4529void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4530 LocationSummary* locations = instruction->GetLocations();
4531 Location first = locations->InAt(0);
4532 Location second = locations->InAt(1);
4533 DCHECK(first.Equals(locations->Out()));
4534
4535 if (instruction->GetResultType() == Primitive::kPrimInt) {
4536 if (second.IsRegister()) {
4537 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004538 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004539 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004540 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004541 } else {
4542 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004543 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004544 }
4545 } else if (second.IsConstant()) {
4546 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004547 __ andl(first.AsRegister<Register>(),
4548 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004549 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004550 __ orl(first.AsRegister<Register>(),
4551 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004552 } else {
4553 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00004554 __ xorl(first.AsRegister<Register>(),
4555 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004556 }
4557 } else {
4558 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004559 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004560 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004561 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004562 } else {
4563 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004564 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004565 }
4566 }
4567 } else {
4568 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4569 if (second.IsRegisterPair()) {
4570 if (instruction->IsAnd()) {
4571 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4572 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4573 } else if (instruction->IsOr()) {
4574 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4575 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4576 } else {
4577 DCHECK(instruction->IsXor());
4578 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4579 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4580 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004581 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004582 if (instruction->IsAnd()) {
4583 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4584 __ andl(first.AsRegisterPairHigh<Register>(),
4585 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4586 } else if (instruction->IsOr()) {
4587 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4588 __ orl(first.AsRegisterPairHigh<Register>(),
4589 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4590 } else {
4591 DCHECK(instruction->IsXor());
4592 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4593 __ xorl(first.AsRegisterPairHigh<Register>(),
4594 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4595 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004596 } else {
4597 DCHECK(second.IsConstant()) << second;
4598 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004599 int32_t low_value = Low32Bits(value);
4600 int32_t high_value = High32Bits(value);
4601 Immediate low(low_value);
4602 Immediate high(high_value);
4603 Register first_low = first.AsRegisterPairLow<Register>();
4604 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004605 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004606 if (low_value == 0) {
4607 __ xorl(first_low, first_low);
4608 } else if (low_value != -1) {
4609 __ andl(first_low, low);
4610 }
4611 if (high_value == 0) {
4612 __ xorl(first_high, first_high);
4613 } else if (high_value != -1) {
4614 __ andl(first_high, high);
4615 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004616 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004617 if (low_value != 0) {
4618 __ orl(first_low, low);
4619 }
4620 if (high_value != 0) {
4621 __ orl(first_high, high);
4622 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004623 } else {
4624 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004625 if (low_value != 0) {
4626 __ xorl(first_low, low);
4627 }
4628 if (high_value != 0) {
4629 __ xorl(first_high, high);
4630 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004631 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004632 }
4633 }
4634}
4635
Calin Juravleb1498f62015-02-16 13:13:29 +00004636void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
4637 // Nothing to do, this should be removed during prepare for register allocator.
4638 UNUSED(instruction);
4639 LOG(FATAL) << "Unreachable";
4640}
4641
4642void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
4643 // Nothing to do, this should be removed during prepare for register allocator.
4644 UNUSED(instruction);
4645 LOG(FATAL) << "Unreachable";
4646}
4647
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004648} // namespace x86
4649} // namespace art