blob: 8d0ca0beb967d39c37c52fb13e991500a3116d68 [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
19#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +000020#include "entrypoints/quick/quick_entrypoints_enum.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010021#include "gc/accounting/card_table.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040022#include "intrinsics.h"
23#include "intrinsics_x86.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070024#include "mirror/array-inl.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010025#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010026#include "mirror/class.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010027#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000028#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010029#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000030#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010031#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010034
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace x86 {
36
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010037static constexpr int kCurrentMethodStackOffset = 0;
38
Mark Mendell5f874182015-03-04 15:42:45 -050039static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010040
Mark Mendell24f2dfa2015-01-14 19:51:45 -050041static constexpr int kC2ConditionMask = 0x400;
42
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000043static constexpr int kFakeReturnRegister = Register(8);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +000044
Nicolas Geoffraye5038322014-07-04 09:41:32 +010045#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
46
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010047class NullCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010048 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010049 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010050
Alexandre Rames2ed20af2015-03-06 13:55:35 +000051 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010052 __ Bind(GetEntryLabel());
53 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
Nicolas Geoffray39468442014-09-02 15:17:15 +010054 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010055 }
56
57 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010058 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010059 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
60};
61
Calin Juravled0d48522014-11-04 16:40:20 +000062class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
63 public:
64 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
65
Alexandre Rames2ed20af2015-03-06 13:55:35 +000066 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000067 __ Bind(GetEntryLabel());
68 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
69 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
70 }
71
72 private:
73 HDivZeroCheck* const instruction_;
74 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
75};
76
Calin Juravlebacfec32014-11-14 15:54:36 +000077class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 {
Calin Juravled0d48522014-11-04 16:40:20 +000078 public:
Calin Juravlebacfec32014-11-14 15:54:36 +000079 explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +000080
Alexandre Rames2ed20af2015-03-06 13:55:35 +000081 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000082 __ Bind(GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +000083 if (is_div_) {
84 __ negl(reg_);
85 } else {
86 __ movl(reg_, Immediate(0));
87 }
Calin Juravled0d48522014-11-04 16:40:20 +000088 __ jmp(GetExitLabel());
89 }
90
91 private:
92 Register reg_;
Calin Juravlebacfec32014-11-14 15:54:36 +000093 bool is_div_;
94 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
Calin Juravled0d48522014-11-04 16:40:20 +000095};
96
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010097class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010098 public:
Roland Levillain5799fc02014-09-25 12:15:20 +010099 BoundsCheckSlowPathX86(HBoundsCheck* instruction,
100 Location index_location,
101 Location length_location)
Roland Levillain199f3362014-11-27 17:15:16 +0000102 : instruction_(instruction),
103 index_location_(index_location),
104 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100105
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000106 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100107 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100108 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000109 // We're moving two locations to locations that could overlap, so we need a parallel
110 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100111 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000112 x86_codegen->EmitParallelMoves(
113 index_location_,
114 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
115 length_location_,
116 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100117 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100118 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100119 }
120
121 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100122 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100123 const Location index_location_;
124 const Location length_location_;
125
126 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
127};
128
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100129class SuspendCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000130 public:
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000131 SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100132 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000133
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000134 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100135 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000136 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000137 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000138 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
139 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000140 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100141 if (successor_ == nullptr) {
142 __ jmp(GetReturnLabel());
143 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100144 __ jmp(x86_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100145 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000146 }
147
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100148 Label* GetReturnLabel() {
149 DCHECK(successor_ == nullptr);
150 return &return_label_;
151 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000152
153 private:
154 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100155 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000156 Label return_label_;
157
158 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
159};
160
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000161class LoadStringSlowPathX86 : public SlowPathCodeX86 {
162 public:
163 explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {}
164
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000165 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000166 LocationSummary* locations = instruction_->GetLocations();
167 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
168
169 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
170 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000171 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000172
173 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800174 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
175 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000176 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString)));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000177 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000178 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000179 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000180
181 __ jmp(GetExitLabel());
182 }
183
184 private:
185 HLoadString* const instruction_;
186
187 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
188};
189
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000190class LoadClassSlowPathX86 : public SlowPathCodeX86 {
191 public:
192 LoadClassSlowPathX86(HLoadClass* cls,
193 HInstruction* at,
194 uint32_t dex_pc,
195 bool do_clinit)
196 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
197 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
198 }
199
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000200 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000201 LocationSummary* locations = at_->GetLocations();
202 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
203 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000204 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000205
206 InvokeRuntimeCallingConvention calling_convention;
207 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
208 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
209 __ fs()->call(Address::Absolute(do_clinit_
210 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage)
211 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType)));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000212 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000213
214 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000215 Location out = locations->Out();
216 if (out.IsValid()) {
217 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
218 x86_codegen->Move32(out, Location::RegisterLocation(EAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000219 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000220
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000221 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000222 __ jmp(GetExitLabel());
223 }
224
225 private:
226 // The class this slow path will load.
227 HLoadClass* const cls_;
228
229 // The instruction where this slow path is happening.
230 // (Might be the load class or an initialization check).
231 HInstruction* const at_;
232
233 // The dex PC of `at_`.
234 const uint32_t dex_pc_;
235
236 // Whether to initialize the class.
237 const bool do_clinit_;
238
239 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
240};
241
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000242class TypeCheckSlowPathX86 : public SlowPathCodeX86 {
243 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000244 TypeCheckSlowPathX86(HInstruction* instruction,
245 Location class_to_check,
246 Location object_class,
247 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000248 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000249 class_to_check_(class_to_check),
250 object_class_(object_class),
251 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000252
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000253 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000254 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000255 DCHECK(instruction_->IsCheckCast()
256 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000257
258 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
259 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000260 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000261
262 // We're moving two locations to locations that could overlap, so we need a parallel
263 // move resolver.
264 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000265 x86_codegen->EmitParallelMoves(
266 class_to_check_,
267 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
268 object_class_,
269 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000270
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000271 if (instruction_->IsInstanceOf()) {
Roland Levillain199f3362014-11-27 17:15:16 +0000272 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize,
273 pInstanceofNonTrivial)));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000274 } else {
275 DCHECK(instruction_->IsCheckCast());
276 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast)));
277 }
278
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000279 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000280 if (instruction_->IsInstanceOf()) {
281 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
282 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000283 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000284
285 __ jmp(GetExitLabel());
286 }
287
288 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000289 HInstruction* const instruction_;
290 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000291 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000292 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000293
294 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
295};
296
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100297#undef __
298#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
299
Dave Allison20dfc792014-06-16 20:44:29 -0700300inline Condition X86Condition(IfCondition cond) {
301 switch (cond) {
302 case kCondEQ: return kEqual;
303 case kCondNE: return kNotEqual;
304 case kCondLT: return kLess;
305 case kCondLE: return kLessEqual;
306 case kCondGT: return kGreater;
307 case kCondGE: return kGreaterEqual;
308 default:
309 LOG(FATAL) << "Unknown if condition";
310 }
311 return kEqual;
312}
313
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100314void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
315 stream << X86ManagedRegister::FromCpuRegister(Register(reg));
316}
317
318void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
319 stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
320}
321
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100322size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
323 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
324 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100325}
326
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100327size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
328 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
329 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100330}
331
Mark Mendell7c8d0092015-01-26 11:21:33 -0500332size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
333 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
334 return GetFloatingPointSpillSlotSize();
335}
336
337size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
338 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
339 return GetFloatingPointSpillSlotSize();
340}
341
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000342CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options)
Mark Mendell5f874182015-03-04 15:42:45 -0500343 : CodeGenerator(graph,
344 kNumberOfCpuRegisters,
345 kNumberOfXmmRegisters,
346 kNumberOfRegisterPairs,
347 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
348 arraysize(kCoreCalleeSaves))
349 | (1 << kFakeReturnRegister),
350 0,
351 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100352 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100353 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100354 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000355 move_resolver_(graph->GetArena(), this) {
356 // Use a fake return address register to mimic Quick.
357 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100358}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100359
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100360Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100361 switch (type) {
362 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100363 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100364 X86ManagedRegister pair =
365 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100366 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
367 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100368 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
369 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100370 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100371 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100372 }
373
374 case Primitive::kPrimByte:
375 case Primitive::kPrimBoolean:
376 case Primitive::kPrimChar:
377 case Primitive::kPrimShort:
378 case Primitive::kPrimInt:
379 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100380 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100381 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100382 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100383 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
384 X86ManagedRegister current =
385 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
386 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100387 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100388 }
389 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100390 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100391 }
392
393 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100394 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100395 return Location::FpuRegisterLocation(
396 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100397 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100398
399 case Primitive::kPrimVoid:
400 LOG(FATAL) << "Unreachable type " << type;
401 }
402
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100403 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100404}
405
Mark Mendell5f874182015-03-04 15:42:45 -0500406void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100407 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100408 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100409
410 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100411 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100412
Mark Mendell5f874182015-03-04 15:42:45 -0500413 if (is_baseline) {
414 blocked_core_registers_[EBP] = true;
415 blocked_core_registers_[ESI] = true;
416 blocked_core_registers_[EDI] = true;
417 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100418
419 UpdateBlockedPairRegisters();
420}
421
422void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
423 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
424 X86ManagedRegister current =
425 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
426 if (blocked_core_registers_[current.AsRegisterPairLow()]
427 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
428 blocked_register_pairs_[i] = true;
429 }
430 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100431}
432
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100433InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
434 : HGraphVisitor(graph),
435 assembler_(codegen->GetAssembler()),
436 codegen_(codegen) {}
437
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000438void CodeGeneratorX86::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000439 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000440 bool skip_overflow_check =
441 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000442 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000443
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000444 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100445 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100446 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100447 }
448
Mark Mendell5f874182015-03-04 15:42:45 -0500449 if (HasEmptyFrame()) {
450 return;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000451 }
Mark Mendell5f874182015-03-04 15:42:45 -0500452
453 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
454 Register reg = kCoreCalleeSaves[i];
455 if (allocated_registers_.ContainsCoreRegister(reg)) {
456 __ pushl(reg);
457 }
458 }
459
460 __ subl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize()));
461 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000462}
463
464void CodeGeneratorX86::GenerateFrameExit() {
Mark Mendell5f874182015-03-04 15:42:45 -0500465 if (HasEmptyFrame()) {
466 return;
467 }
468
469 __ addl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize()));
470
471 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
472 Register reg = kCoreCalleeSaves[i];
473 if (allocated_registers_.ContainsCoreRegister(reg)) {
474 __ popl(reg);
475 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000476 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000477}
478
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100479void CodeGeneratorX86::Bind(HBasicBlock* block) {
480 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000481}
482
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100483void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000484 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100485 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000486}
487
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100488Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
489 switch (load->GetType()) {
490 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100491 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100492 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
493 break;
494
495 case Primitive::kPrimInt:
496 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100497 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100498 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100499
500 case Primitive::kPrimBoolean:
501 case Primitive::kPrimByte:
502 case Primitive::kPrimChar:
503 case Primitive::kPrimShort:
504 case Primitive::kPrimVoid:
505 LOG(FATAL) << "Unexpected type " << load->GetType();
506 }
507
508 LOG(FATAL) << "Unreachable";
509 return Location();
510}
511
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100512Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
513 switch (type) {
514 case Primitive::kPrimBoolean:
515 case Primitive::kPrimByte:
516 case Primitive::kPrimChar:
517 case Primitive::kPrimShort:
518 case Primitive::kPrimInt:
519 case Primitive::kPrimNot: {
520 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000521 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100522 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100523 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100524 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000525 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100526 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100527 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100528
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000529 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100530 uint32_t index = gp_index_;
531 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000532 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100533 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100534 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
535 calling_convention.GetRegisterPairAt(index));
536 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100537 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000538 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
539 }
540 }
541
542 case Primitive::kPrimFloat: {
543 uint32_t index = fp_index_++;
544 stack_index_++;
545 if (index < calling_convention.GetNumberOfFpuRegisters()) {
546 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
547 } else {
548 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
549 }
550 }
551
552 case Primitive::kPrimDouble: {
553 uint32_t index = fp_index_++;
554 stack_index_ += 2;
555 if (index < calling_convention.GetNumberOfFpuRegisters()) {
556 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
557 } else {
558 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100559 }
560 }
561
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100562 case Primitive::kPrimVoid:
563 LOG(FATAL) << "Unexpected parameter type " << type;
564 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100565 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100566 return Location();
567}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100568
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100569void CodeGeneratorX86::Move32(Location destination, Location source) {
570 if (source.Equals(destination)) {
571 return;
572 }
573 if (destination.IsRegister()) {
574 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000575 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100576 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000577 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100578 } else {
579 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000580 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100581 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100582 } else if (destination.IsFpuRegister()) {
583 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000584 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100585 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000586 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100587 } else {
588 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000589 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100590 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100591 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000592 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100593 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000594 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100595 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000596 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500597 } else if (source.IsConstant()) {
598 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000599 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -0500600 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100601 } else {
602 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100603 __ pushl(Address(ESP, source.GetStackIndex()));
604 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100605 }
606 }
607}
608
609void CodeGeneratorX86::Move64(Location destination, Location source) {
610 if (source.Equals(destination)) {
611 return;
612 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100613 if (destination.IsRegisterPair()) {
614 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000615 EmitParallelMoves(
616 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
617 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
618 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
619 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100620 } else if (source.IsFpuRegister()) {
621 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100622 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000623 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100624 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100625 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
626 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100627 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
628 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100629 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500630 if (source.IsFpuRegister()) {
631 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
632 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000633 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100634 } else {
635 LOG(FATAL) << "Unimplemented";
636 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100637 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000638 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100639 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000640 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100641 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100642 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100643 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100644 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000645 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000646 } else if (source.IsConstant()) {
647 HConstant* constant = source.GetConstant();
648 int64_t value;
649 if (constant->IsLongConstant()) {
650 value = constant->AsLongConstant()->GetValue();
651 } else {
652 DCHECK(constant->IsDoubleConstant());
Roland Levillainda4d79b2015-03-24 14:36:11 +0000653 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000654 }
655 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
656 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100657 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000658 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000659 EmitParallelMoves(
660 Location::StackSlot(source.GetStackIndex()),
661 Location::StackSlot(destination.GetStackIndex()),
662 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
663 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100664 }
665 }
666}
667
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100668void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000669 LocationSummary* locations = instruction->GetLocations();
670 if (locations != nullptr && locations->Out().Equals(location)) {
671 return;
672 }
673
674 if (locations != nullptr && locations->Out().IsConstant()) {
675 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000676 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
677 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000678 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000679 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000680 } else if (location.IsStackSlot()) {
681 __ movl(Address(ESP, location.GetStackIndex()), imm);
682 } else {
683 DCHECK(location.IsConstant());
684 DCHECK_EQ(location.GetConstant(), const_to_move);
685 }
686 } else if (const_to_move->IsLongConstant()) {
687 int64_t value = const_to_move->AsLongConstant()->GetValue();
688 if (location.IsRegisterPair()) {
689 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
690 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
691 } else if (location.IsDoubleStackSlot()) {
692 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000693 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
694 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000695 } else {
696 DCHECK(location.IsConstant());
697 DCHECK_EQ(location.GetConstant(), instruction);
698 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100699 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000700 } else if (instruction->IsTemporary()) {
701 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000702 if (temp_location.IsStackSlot()) {
703 Move32(location, temp_location);
704 } else {
705 DCHECK(temp_location.IsDoubleStackSlot());
706 Move64(location, temp_location);
707 }
Roland Levillain476df552014-10-09 17:51:36 +0100708 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100709 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100710 switch (instruction->GetType()) {
711 case Primitive::kPrimBoolean:
712 case Primitive::kPrimByte:
713 case Primitive::kPrimChar:
714 case Primitive::kPrimShort:
715 case Primitive::kPrimInt:
716 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100717 case Primitive::kPrimFloat:
718 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100719 break;
720
721 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100722 case Primitive::kPrimDouble:
723 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100724 break;
725
726 default:
727 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
728 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000729 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100730 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100731 switch (instruction->GetType()) {
732 case Primitive::kPrimBoolean:
733 case Primitive::kPrimByte:
734 case Primitive::kPrimChar:
735 case Primitive::kPrimShort:
736 case Primitive::kPrimInt:
737 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100738 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000739 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100740 break;
741
742 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100743 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000744 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100745 break;
746
747 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100748 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100749 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000750 }
751}
752
753void LocationsBuilderX86::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000754 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000755}
756
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000757void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000758 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100759 DCHECK(!successor->IsExitBlock());
760
761 HBasicBlock* block = got->GetBlock();
762 HInstruction* previous = got->GetPrevious();
763
764 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000765 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100766 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
767 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
768 return;
769 }
770
771 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
772 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
773 }
774 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000775 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000776 }
777}
778
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000779void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000780 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000781}
782
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000783void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700784 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000785}
786
Andreas Gampe0ba62732015-03-24 02:39:46 +0000787void LocationsBuilderX86::VisitIf(HIf* if_instr) {
788 LocationSummary* locations =
789 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
790 HInstruction* cond = if_instr->InputAt(0);
791 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
792 locations->SetInAt(0, Location::Any());
793 }
794}
795
796void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
797 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100798 if (cond->IsIntConstant()) {
799 // Constant condition, statically compared against 1.
800 int32_t cond_value = cond->AsIntConstant()->GetValue();
801 if (cond_value == 1) {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000802 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
803 if_instr->IfTrueSuccessor())) {
804 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100805 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100806 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100807 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100808 DCHECK_EQ(cond_value, 0);
809 }
810 } else {
811 bool materialized =
812 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
813 // Moves do not affect the eflags register, so if the condition is
814 // evaluated just before the if, we don't need to evaluate it
815 // again.
816 bool eflags_set = cond->IsCondition()
Andreas Gampe0ba62732015-03-24 02:39:46 +0000817 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100818 if (materialized) {
819 if (!eflags_set) {
820 // Materialized condition, compare against 0.
Andreas Gampe0ba62732015-03-24 02:39:46 +0000821 Location lhs = if_instr->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100822 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -0500823 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100824 } else {
825 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
826 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000827 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100828 } else {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000829 __ j(X86Condition(cond->AsCondition()->GetCondition()),
830 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100831 }
832 } else {
833 Location lhs = cond->GetLocations()->InAt(0);
834 Location rhs = cond->GetLocations()->InAt(1);
835 // LHS is guaranteed to be in a register (see
836 // LocationsBuilderX86::VisitCondition).
837 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000838 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100839 } else if (rhs.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -0500840 int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue();
841 if (constant == 0) {
842 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
843 } else {
844 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
845 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100846 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000847 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100848 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000849 __ j(X86Condition(cond->AsCondition()->GetCondition()),
850 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700851 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100852 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000853 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
854 if_instr->IfFalseSuccessor())) {
855 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000856 }
857}
858
859void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000860 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000861}
862
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000863void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
864 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000865}
866
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000867void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100868 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000869}
870
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000871void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100872 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700873 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000874}
875
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100876void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100877 LocationSummary* locations =
878 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100879 switch (store->InputAt(1)->GetType()) {
880 case Primitive::kPrimBoolean:
881 case Primitive::kPrimByte:
882 case Primitive::kPrimChar:
883 case Primitive::kPrimShort:
884 case Primitive::kPrimInt:
885 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100886 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100887 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
888 break;
889
890 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100891 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100892 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
893 break;
894
895 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100896 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100897 }
898 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000899}
900
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000901void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700902 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000903}
904
Dave Allison20dfc792014-06-16 20:44:29 -0700905void LocationsBuilderX86::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100906 LocationSummary* locations =
907 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100908 locations->SetInAt(0, Location::RequiresRegister());
909 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100910 if (comp->NeedsMaterialization()) {
Mark Mendell5f874182015-03-04 15:42:45 -0500911 // We need a byte register.
912 locations->SetOut(Location::RegisterLocation(ECX));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100913 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000914}
915
Dave Allison20dfc792014-06-16 20:44:29 -0700916void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
917 if (comp->NeedsMaterialization()) {
918 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000919 Register reg = locations->Out().AsRegister<Register>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100920 // Clear register: setcc only sets the low byte.
921 __ xorl(reg, reg);
Mark Mendell09b84632015-02-13 17:48:38 -0500922 Location lhs = locations->InAt(0);
923 Location rhs = locations->InAt(1);
924 if (rhs.IsRegister()) {
925 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
926 } else if (rhs.IsConstant()) {
Mingyao Yang8928cab2015-03-03 16:15:23 -0800927 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -0500928 if (constant == 0) {
929 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
930 } else {
931 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
932 }
Dave Allison20dfc792014-06-16 20:44:29 -0700933 } else {
Mark Mendell09b84632015-02-13 17:48:38 -0500934 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Dave Allison20dfc792014-06-16 20:44:29 -0700935 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000936 __ setb(X86Condition(comp->GetCondition()), reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100937 }
Dave Allison20dfc792014-06-16 20:44:29 -0700938}
939
940void LocationsBuilderX86::VisitEqual(HEqual* comp) {
941 VisitCondition(comp);
942}
943
944void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
945 VisitCondition(comp);
946}
947
948void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
949 VisitCondition(comp);
950}
951
952void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
953 VisitCondition(comp);
954}
955
956void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
957 VisitCondition(comp);
958}
959
960void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
961 VisitCondition(comp);
962}
963
964void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
965 VisitCondition(comp);
966}
967
968void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
969 VisitCondition(comp);
970}
971
972void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
973 VisitCondition(comp);
974}
975
976void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
977 VisitCondition(comp);
978}
979
980void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
981 VisitCondition(comp);
982}
983
984void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
985 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000986}
987
988void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100989 LocationSummary* locations =
990 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100991 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000992}
993
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000994void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100995 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700996 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000997}
998
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000999void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1000 LocationSummary* locations =
1001 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1002 locations->SetOut(Location::ConstantLocation(constant));
1003}
1004
1005void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1006 // Will be generated at use site.
1007 UNUSED(constant);
1008}
1009
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001010void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001011 LocationSummary* locations =
1012 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001013 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001014}
1015
1016void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1017 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001018 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001019}
1020
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001021void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1022 LocationSummary* locations =
1023 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1024 locations->SetOut(Location::ConstantLocation(constant));
1025}
1026
1027void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1028 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001029 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001030}
1031
1032void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1033 LocationSummary* locations =
1034 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1035 locations->SetOut(Location::ConstantLocation(constant));
1036}
1037
1038void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1039 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001040 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001041}
1042
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001043void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001044 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001045}
1046
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001047void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001048 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001049 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001050 __ ret();
1051}
1052
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001053void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001054 LocationSummary* locations =
1055 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001056 switch (ret->InputAt(0)->GetType()) {
1057 case Primitive::kPrimBoolean:
1058 case Primitive::kPrimByte:
1059 case Primitive::kPrimChar:
1060 case Primitive::kPrimShort:
1061 case Primitive::kPrimInt:
1062 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001063 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001064 break;
1065
1066 case Primitive::kPrimLong:
1067 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001068 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001069 break;
1070
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001071 case Primitive::kPrimFloat:
1072 case Primitive::kPrimDouble:
1073 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001074 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001075 break;
1076
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001077 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001078 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001079 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001080}
1081
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001082void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001083 if (kIsDebugBuild) {
1084 switch (ret->InputAt(0)->GetType()) {
1085 case Primitive::kPrimBoolean:
1086 case Primitive::kPrimByte:
1087 case Primitive::kPrimChar:
1088 case Primitive::kPrimShort:
1089 case Primitive::kPrimInt:
1090 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001091 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001092 break;
1093
1094 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001095 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1096 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001097 break;
1098
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001099 case Primitive::kPrimFloat:
1100 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001101 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001102 break;
1103
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001104 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001105 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001106 }
1107 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001108 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001109 __ ret();
1110}
1111
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001112void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendell09ed1a32015-03-25 08:30:06 -04001113 IntrinsicLocationsBuilderX86 intrinsic(GetGraph()->GetArena());
1114 if (intrinsic.TryDispatch(invoke)) {
1115 return;
1116 }
1117
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001118 HandleInvoke(invoke);
1119}
1120
Mark Mendell09ed1a32015-03-25 08:30:06 -04001121static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1122 if (invoke->GetLocations()->Intrinsified()) {
1123 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1124 intrinsic.Dispatch(invoke);
1125 return true;
1126 }
1127 return false;
1128}
1129
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001130void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendell09ed1a32015-03-25 08:30:06 -04001131 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1132 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001133 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001134
Mark Mendell09ed1a32015-03-25 08:30:06 -04001135 codegen_->GenerateStaticOrDirectCall(
1136 invoke, invoke->GetLocations()->GetTemp(0).AsRegister<Register>());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001137}
1138
1139void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1140 HandleInvoke(invoke);
1141}
1142
1143void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001144 LocationSummary* locations =
1145 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001146 locations->AddTemp(Location::RegisterLocation(EAX));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001147
1148 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001149 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001150 HInstruction* input = invoke->InputAt(i);
1151 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1152 }
1153
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001154 switch (invoke->GetType()) {
1155 case Primitive::kPrimBoolean:
1156 case Primitive::kPrimByte:
1157 case Primitive::kPrimChar:
1158 case Primitive::kPrimShort:
1159 case Primitive::kPrimInt:
1160 case Primitive::kPrimNot:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001161 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001162 break;
1163
1164 case Primitive::kPrimLong:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001165 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001166 break;
1167
1168 case Primitive::kPrimVoid:
1169 break;
1170
1171 case Primitive::kPrimDouble:
1172 case Primitive::kPrimFloat:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001173 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001174 break;
1175 }
1176
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001177 invoke->SetLocations(locations);
1178}
1179
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001180void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001181 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001182 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1183 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1184 LocationSummary* locations = invoke->GetLocations();
1185 Location receiver = locations->InAt(0);
1186 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1187 // temp = object->GetClass();
1188 if (receiver.IsStackSlot()) {
1189 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1190 __ movl(temp, Address(temp, class_offset));
1191 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001192 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001193 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001194 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001195 // temp = temp->GetMethodAt(method_offset);
1196 __ movl(temp, Address(temp, method_offset));
1197 // call temp->GetEntryPoint();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001198 __ call(Address(
1199 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001200
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001201 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001202 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001203}
1204
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001205void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1206 HandleInvoke(invoke);
1207 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001208 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001209}
1210
1211void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1212 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001213 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001214 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1215 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1216 LocationSummary* locations = invoke->GetLocations();
1217 Location receiver = locations->InAt(0);
1218 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1219
1220 // Set the hidden argument.
1221 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001222 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001223
1224 // temp = object->GetClass();
1225 if (receiver.IsStackSlot()) {
1226 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1227 __ movl(temp, Address(temp, class_offset));
1228 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001229 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001230 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001231 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001232 // temp = temp->GetImtEntryAt(method_offset);
1233 __ movl(temp, Address(temp, method_offset));
1234 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001235 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001236 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001237
1238 DCHECK(!codegen_->IsLeafMethod());
1239 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1240}
1241
Roland Levillain88cb1752014-10-20 16:36:47 +01001242void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1243 LocationSummary* locations =
1244 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1245 switch (neg->GetResultType()) {
1246 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001247 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001248 locations->SetInAt(0, Location::RequiresRegister());
1249 locations->SetOut(Location::SameAsFirstInput());
1250 break;
1251
Roland Levillain88cb1752014-10-20 16:36:47 +01001252 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001253 locations->SetInAt(0, Location::RequiresFpuRegister());
1254 locations->SetOut(Location::SameAsFirstInput());
1255 locations->AddTemp(Location::RequiresRegister());
1256 locations->AddTemp(Location::RequiresFpuRegister());
1257 break;
1258
Roland Levillain88cb1752014-10-20 16:36:47 +01001259 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001260 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001261 locations->SetOut(Location::SameAsFirstInput());
1262 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001263 break;
1264
1265 default:
1266 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1267 }
1268}
1269
1270void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1271 LocationSummary* locations = neg->GetLocations();
1272 Location out = locations->Out();
1273 Location in = locations->InAt(0);
1274 switch (neg->GetResultType()) {
1275 case Primitive::kPrimInt:
1276 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001277 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001278 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001279 break;
1280
1281 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001282 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001283 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001284 __ negl(out.AsRegisterPairLow<Register>());
1285 // Negation is similar to subtraction from zero. The least
1286 // significant byte triggers a borrow when it is different from
1287 // zero; to take it into account, add 1 to the most significant
1288 // byte if the carry flag (CF) is set to 1 after the first NEGL
1289 // operation.
1290 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1291 __ negl(out.AsRegisterPairHigh<Register>());
1292 break;
1293
Roland Levillain5368c212014-11-27 15:03:41 +00001294 case Primitive::kPrimFloat: {
1295 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001296 Register constant = locations->GetTemp(0).AsRegister<Register>();
1297 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001298 // Implement float negation with an exclusive or with value
1299 // 0x80000000 (mask for bit 31, representing the sign of a
1300 // single-precision floating-point number).
1301 __ movl(constant, Immediate(INT32_C(0x80000000)));
1302 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001303 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001304 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001305 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001306
Roland Levillain5368c212014-11-27 15:03:41 +00001307 case Primitive::kPrimDouble: {
1308 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001309 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001310 // Implement double negation with an exclusive or with value
1311 // 0x8000000000000000 (mask for bit 63, representing the sign of
1312 // a double-precision floating-point number).
1313 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001314 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001315 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001316 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001317
1318 default:
1319 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1320 }
1321}
1322
Roland Levillaindff1f282014-11-05 14:15:05 +00001323void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001324 Primitive::Type result_type = conversion->GetResultType();
1325 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001326 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001327
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001328 // The float-to-long and double-to-long type conversions rely on a
1329 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001330 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001331 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1332 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001333 ? LocationSummary::kCall
1334 : LocationSummary::kNoCall;
1335 LocationSummary* locations =
1336 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1337
David Brazdilb2bd1c52015-03-25 11:17:37 +00001338 // The Java language does not allow treating boolean as an integral type but
1339 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001340
Roland Levillaindff1f282014-11-05 14:15:05 +00001341 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001342 case Primitive::kPrimByte:
1343 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001344 case Primitive::kPrimBoolean:
1345 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001346 case Primitive::kPrimShort:
1347 case Primitive::kPrimInt:
1348 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001349 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001350 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1351 // Make the output overlap to please the register allocator. This greatly simplifies
1352 // the validation of the linear scan implementation
1353 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001354 break;
1355
1356 default:
1357 LOG(FATAL) << "Unexpected type conversion from " << input_type
1358 << " to " << result_type;
1359 }
1360 break;
1361
Roland Levillain01a8d712014-11-14 16:27:39 +00001362 case Primitive::kPrimShort:
1363 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001364 case Primitive::kPrimBoolean:
1365 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001366 case Primitive::kPrimByte:
1367 case Primitive::kPrimInt:
1368 case Primitive::kPrimChar:
1369 // Processing a Dex `int-to-short' instruction.
1370 locations->SetInAt(0, Location::Any());
1371 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1372 break;
1373
1374 default:
1375 LOG(FATAL) << "Unexpected type conversion from " << input_type
1376 << " to " << result_type;
1377 }
1378 break;
1379
Roland Levillain946e1432014-11-11 17:35:19 +00001380 case Primitive::kPrimInt:
1381 switch (input_type) {
1382 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001383 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001384 locations->SetInAt(0, Location::Any());
1385 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1386 break;
1387
1388 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001389 // Processing a Dex `float-to-int' instruction.
1390 locations->SetInAt(0, Location::RequiresFpuRegister());
1391 locations->SetOut(Location::RequiresRegister());
1392 locations->AddTemp(Location::RequiresFpuRegister());
1393 break;
1394
Roland Levillain946e1432014-11-11 17:35:19 +00001395 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001396 // Processing a Dex `double-to-int' instruction.
1397 locations->SetInAt(0, Location::RequiresFpuRegister());
1398 locations->SetOut(Location::RequiresRegister());
1399 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001400 break;
1401
1402 default:
1403 LOG(FATAL) << "Unexpected type conversion from " << input_type
1404 << " to " << result_type;
1405 }
1406 break;
1407
Roland Levillaindff1f282014-11-05 14:15:05 +00001408 case Primitive::kPrimLong:
1409 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001410 case Primitive::kPrimBoolean:
1411 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001412 case Primitive::kPrimByte:
1413 case Primitive::kPrimShort:
1414 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001415 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001416 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001417 locations->SetInAt(0, Location::RegisterLocation(EAX));
1418 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1419 break;
1420
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001421 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001422 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001423 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001424 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001425 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1426 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1427
Vladimir Marko949c91f2015-01-27 10:48:44 +00001428 // The runtime helper puts the result in EAX, EDX.
1429 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001430 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001431 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001432
1433 default:
1434 LOG(FATAL) << "Unexpected type conversion from " << input_type
1435 << " to " << result_type;
1436 }
1437 break;
1438
Roland Levillain981e4542014-11-14 11:47:14 +00001439 case Primitive::kPrimChar:
1440 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001441 case Primitive::kPrimBoolean:
1442 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001443 case Primitive::kPrimByte:
1444 case Primitive::kPrimShort:
1445 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001446 // Processing a Dex `int-to-char' instruction.
1447 locations->SetInAt(0, Location::Any());
1448 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1449 break;
1450
1451 default:
1452 LOG(FATAL) << "Unexpected type conversion from " << input_type
1453 << " to " << result_type;
1454 }
1455 break;
1456
Roland Levillaindff1f282014-11-05 14:15:05 +00001457 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001458 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001459 case Primitive::kPrimBoolean:
1460 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001461 case Primitive::kPrimByte:
1462 case Primitive::kPrimShort:
1463 case Primitive::kPrimInt:
1464 case Primitive::kPrimChar:
1465 // Processing a Dex `int-to-float' instruction.
1466 locations->SetInAt(0, Location::RequiresRegister());
1467 locations->SetOut(Location::RequiresFpuRegister());
1468 break;
1469
1470 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001471 // Processing a Dex `long-to-float' instruction.
1472 locations->SetInAt(0, Location::RequiresRegister());
1473 locations->SetOut(Location::RequiresFpuRegister());
1474 locations->AddTemp(Location::RequiresFpuRegister());
1475 locations->AddTemp(Location::RequiresFpuRegister());
1476 break;
1477
Roland Levillaincff13742014-11-17 14:32:17 +00001478 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001479 // Processing a Dex `double-to-float' instruction.
1480 locations->SetInAt(0, Location::RequiresFpuRegister());
1481 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001482 break;
1483
1484 default:
1485 LOG(FATAL) << "Unexpected type conversion from " << input_type
1486 << " to " << result_type;
1487 };
1488 break;
1489
Roland Levillaindff1f282014-11-05 14:15:05 +00001490 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001491 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001492 case Primitive::kPrimBoolean:
1493 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001494 case Primitive::kPrimByte:
1495 case Primitive::kPrimShort:
1496 case Primitive::kPrimInt:
1497 case Primitive::kPrimChar:
1498 // Processing a Dex `int-to-double' instruction.
1499 locations->SetInAt(0, Location::RequiresRegister());
1500 locations->SetOut(Location::RequiresFpuRegister());
1501 break;
1502
1503 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001504 // Processing a Dex `long-to-double' instruction.
1505 locations->SetInAt(0, Location::RequiresRegister());
1506 locations->SetOut(Location::RequiresFpuRegister());
1507 locations->AddTemp(Location::RequiresFpuRegister());
1508 locations->AddTemp(Location::RequiresFpuRegister());
1509 break;
1510
Roland Levillaincff13742014-11-17 14:32:17 +00001511 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001512 // Processing a Dex `float-to-double' instruction.
1513 locations->SetInAt(0, Location::RequiresFpuRegister());
1514 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001515 break;
1516
1517 default:
1518 LOG(FATAL) << "Unexpected type conversion from " << input_type
1519 << " to " << result_type;
1520 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001521 break;
1522
1523 default:
1524 LOG(FATAL) << "Unexpected type conversion from " << input_type
1525 << " to " << result_type;
1526 }
1527}
1528
1529void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
1530 LocationSummary* locations = conversion->GetLocations();
1531 Location out = locations->Out();
1532 Location in = locations->InAt(0);
1533 Primitive::Type result_type = conversion->GetResultType();
1534 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001535 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001536 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001537 case Primitive::kPrimByte:
1538 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001539 case Primitive::kPrimBoolean:
1540 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001541 case Primitive::kPrimShort:
1542 case Primitive::kPrimInt:
1543 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001544 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001545 if (in.IsRegister()) {
1546 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001547 } else {
1548 DCHECK(in.GetConstant()->IsIntConstant());
1549 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1550 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
1551 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00001552 break;
1553
1554 default:
1555 LOG(FATAL) << "Unexpected type conversion from " << input_type
1556 << " to " << result_type;
1557 }
1558 break;
1559
Roland Levillain01a8d712014-11-14 16:27:39 +00001560 case Primitive::kPrimShort:
1561 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001562 case Primitive::kPrimBoolean:
1563 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001564 case Primitive::kPrimByte:
1565 case Primitive::kPrimInt:
1566 case Primitive::kPrimChar:
1567 // Processing a Dex `int-to-short' instruction.
1568 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001569 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001570 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001571 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00001572 } else {
1573 DCHECK(in.GetConstant()->IsIntConstant());
1574 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001575 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00001576 }
1577 break;
1578
1579 default:
1580 LOG(FATAL) << "Unexpected type conversion from " << input_type
1581 << " to " << result_type;
1582 }
1583 break;
1584
Roland Levillain946e1432014-11-11 17:35:19 +00001585 case Primitive::kPrimInt:
1586 switch (input_type) {
1587 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001588 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001589 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001590 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001591 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001592 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00001593 } else {
1594 DCHECK(in.IsConstant());
1595 DCHECK(in.GetConstant()->IsLongConstant());
1596 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001597 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001598 }
1599 break;
1600
Roland Levillain3f8f9362014-12-02 17:45:01 +00001601 case Primitive::kPrimFloat: {
1602 // Processing a Dex `float-to-int' instruction.
1603 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1604 Register output = out.AsRegister<Register>();
1605 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1606 Label done, nan;
1607
1608 __ movl(output, Immediate(kPrimIntMax));
1609 // temp = int-to-float(output)
1610 __ cvtsi2ss(temp, output);
1611 // if input >= temp goto done
1612 __ comiss(input, temp);
1613 __ j(kAboveEqual, &done);
1614 // if input == NaN goto nan
1615 __ j(kUnordered, &nan);
1616 // output = float-to-int-truncate(input)
1617 __ cvttss2si(output, input);
1618 __ jmp(&done);
1619 __ Bind(&nan);
1620 // output = 0
1621 __ xorl(output, output);
1622 __ Bind(&done);
1623 break;
1624 }
1625
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001626 case Primitive::kPrimDouble: {
1627 // Processing a Dex `double-to-int' instruction.
1628 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1629 Register output = out.AsRegister<Register>();
1630 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1631 Label done, nan;
1632
1633 __ movl(output, Immediate(kPrimIntMax));
1634 // temp = int-to-double(output)
1635 __ cvtsi2sd(temp, output);
1636 // if input >= temp goto done
1637 __ comisd(input, temp);
1638 __ j(kAboveEqual, &done);
1639 // if input == NaN goto nan
1640 __ j(kUnordered, &nan);
1641 // output = double-to-int-truncate(input)
1642 __ cvttsd2si(output, input);
1643 __ jmp(&done);
1644 __ Bind(&nan);
1645 // output = 0
1646 __ xorl(output, output);
1647 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001648 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001649 }
Roland Levillain946e1432014-11-11 17:35:19 +00001650
1651 default:
1652 LOG(FATAL) << "Unexpected type conversion from " << input_type
1653 << " to " << result_type;
1654 }
1655 break;
1656
Roland Levillaindff1f282014-11-05 14:15:05 +00001657 case Primitive::kPrimLong:
1658 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001659 case Primitive::kPrimBoolean:
1660 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001661 case Primitive::kPrimByte:
1662 case Primitive::kPrimShort:
1663 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001664 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001665 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001666 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
1667 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001668 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00001669 __ cdq();
1670 break;
1671
1672 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001673 // Processing a Dex `float-to-long' instruction.
1674 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l)));
Roland Levillain624279f2014-12-04 11:54:28 +00001675 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
1676 break;
1677
Roland Levillaindff1f282014-11-05 14:15:05 +00001678 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001679 // Processing a Dex `double-to-long' instruction.
1680 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l)));
1681 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
Roland Levillaindff1f282014-11-05 14:15:05 +00001682 break;
1683
1684 default:
1685 LOG(FATAL) << "Unexpected type conversion from " << input_type
1686 << " to " << result_type;
1687 }
1688 break;
1689
Roland Levillain981e4542014-11-14 11:47:14 +00001690 case Primitive::kPrimChar:
1691 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001692 case Primitive::kPrimBoolean:
1693 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001694 case Primitive::kPrimByte:
1695 case Primitive::kPrimShort:
1696 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001697 // Processing a Dex `Process a Dex `int-to-char'' instruction.
1698 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001699 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00001700 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001701 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00001702 } else {
1703 DCHECK(in.GetConstant()->IsIntConstant());
1704 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001705 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00001706 }
1707 break;
1708
1709 default:
1710 LOG(FATAL) << "Unexpected type conversion from " << input_type
1711 << " to " << result_type;
1712 }
1713 break;
1714
Roland Levillaindff1f282014-11-05 14:15:05 +00001715 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001716 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001717 case Primitive::kPrimBoolean:
1718 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001719 case Primitive::kPrimByte:
1720 case Primitive::kPrimShort:
1721 case Primitive::kPrimInt:
1722 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001723 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001724 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001725 break;
1726
Roland Levillain6d0e4832014-11-27 18:31:21 +00001727 case Primitive::kPrimLong: {
1728 // Processing a Dex `long-to-float' instruction.
1729 Register low = in.AsRegisterPairLow<Register>();
1730 Register high = in.AsRegisterPairHigh<Register>();
1731 XmmRegister result = out.AsFpuRegister<XmmRegister>();
1732 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1733 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
1734
1735 // Operations use doubles for precision reasons (each 32-bit
1736 // half of a long fits in the 53-bit mantissa of a double,
1737 // but not in the 24-bit mantissa of a float). This is
1738 // especially important for the low bits. The result is
1739 // eventually converted to float.
1740
1741 // low = low - 2^31 (to prevent bit 31 of `low` to be
1742 // interpreted as a sign bit)
1743 __ subl(low, Immediate(0x80000000));
1744 // temp = int-to-double(high)
1745 __ cvtsi2sd(temp, high);
1746 // temp = temp * 2^32
1747 __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
1748 __ mulsd(temp, constant);
1749 // result = int-to-double(low)
1750 __ cvtsi2sd(result, low);
1751 // result = result + 2^31 (restore the original value of `low`)
1752 __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
1753 __ addsd(result, constant);
1754 // result = result + temp
1755 __ addsd(result, temp);
1756 // result = double-to-float(result)
1757 __ cvtsd2ss(result, result);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001758 // Restore low.
1759 __ addl(low, Immediate(0x80000000));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001760 break;
1761 }
1762
Roland Levillaincff13742014-11-17 14:32:17 +00001763 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001764 // Processing a Dex `double-to-float' instruction.
1765 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001766 break;
1767
1768 default:
1769 LOG(FATAL) << "Unexpected type conversion from " << input_type
1770 << " to " << result_type;
1771 };
1772 break;
1773
Roland Levillaindff1f282014-11-05 14:15:05 +00001774 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001775 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001776 case Primitive::kPrimBoolean:
1777 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001778 case Primitive::kPrimByte:
1779 case Primitive::kPrimShort:
1780 case Primitive::kPrimInt:
1781 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001782 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001783 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001784 break;
1785
Roland Levillain647b9ed2014-11-27 12:06:00 +00001786 case Primitive::kPrimLong: {
1787 // Processing a Dex `long-to-double' instruction.
1788 Register low = in.AsRegisterPairLow<Register>();
1789 Register high = in.AsRegisterPairHigh<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001790 XmmRegister result = out.AsFpuRegister<XmmRegister>();
1791 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1792 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001793
Roland Levillain647b9ed2014-11-27 12:06:00 +00001794 // low = low - 2^31 (to prevent bit 31 of `low` to be
1795 // interpreted as a sign bit)
1796 __ subl(low, Immediate(0x80000000));
1797 // temp = int-to-double(high)
1798 __ cvtsi2sd(temp, high);
1799 // temp = temp * 2^32
Roland Levillain6d0e4832014-11-27 18:31:21 +00001800 __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001801 __ mulsd(temp, constant);
1802 // result = int-to-double(low)
1803 __ cvtsi2sd(result, low);
1804 // result = result + 2^31 (restore the original value of `low`)
Roland Levillain6d0e4832014-11-27 18:31:21 +00001805 __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001806 __ addsd(result, constant);
1807 // result = result + temp
1808 __ addsd(result, temp);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001809 // Restore low.
1810 __ addl(low, Immediate(0x80000000));
Roland Levillain647b9ed2014-11-27 12:06:00 +00001811 break;
1812 }
1813
Roland Levillaincff13742014-11-17 14:32:17 +00001814 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001815 // Processing a Dex `float-to-double' instruction.
1816 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001817 break;
1818
1819 default:
1820 LOG(FATAL) << "Unexpected type conversion from " << input_type
1821 << " to " << result_type;
1822 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001823 break;
1824
1825 default:
1826 LOG(FATAL) << "Unexpected type conversion from " << input_type
1827 << " to " << result_type;
1828 }
1829}
1830
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001831void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001832 LocationSummary* locations =
1833 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001834 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001835 case Primitive::kPrimInt: {
1836 locations->SetInAt(0, Location::RequiresRegister());
1837 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1838 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1839 break;
1840 }
1841
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001842 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001843 locations->SetInAt(0, Location::RequiresRegister());
1844 locations->SetInAt(1, Location::Any());
1845 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001846 break;
1847 }
1848
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001849 case Primitive::kPrimFloat:
1850 case Primitive::kPrimDouble: {
1851 locations->SetInAt(0, Location::RequiresFpuRegister());
Calin Juravle3173c8a2015-02-23 15:53:39 +00001852 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001853 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001854 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001855 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001856
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001857 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001858 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1859 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001860 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001861}
1862
1863void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
1864 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001865 Location first = locations->InAt(0);
1866 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05001867 Location out = locations->Out();
1868
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001869 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001870 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001871 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001872 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1873 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
1874 } else {
1875 __ leal(out.AsRegister<Register>(), Address(
1876 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
1877 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001878 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001879 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
1880 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1881 __ addl(out.AsRegister<Register>(), Immediate(value));
1882 } else {
1883 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
1884 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001885 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05001886 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001887 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001888 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001889 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001890 }
1891
1892 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001893 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001894 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1895 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001896 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001897 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
1898 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001899 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001900 } else {
1901 DCHECK(second.IsConstant()) << second;
1902 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1903 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
1904 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001905 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001906 break;
1907 }
1908
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001909 case Primitive::kPrimFloat: {
1910 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001911 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001912 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001913 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001914 }
1915
1916 case Primitive::kPrimDouble: {
1917 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001918 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001919 }
1920 break;
1921 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001922
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001923 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001924 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001925 }
1926}
1927
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001928void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001929 LocationSummary* locations =
1930 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001931 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001932 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001933 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001934 locations->SetInAt(0, Location::RequiresRegister());
1935 locations->SetInAt(1, Location::Any());
1936 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001937 break;
1938 }
Calin Juravle11351682014-10-23 15:38:15 +01001939 case Primitive::kPrimFloat:
1940 case Primitive::kPrimDouble: {
1941 locations->SetInAt(0, Location::RequiresFpuRegister());
1942 locations->SetInAt(1, Location::RequiresFpuRegister());
1943 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001944 break;
Calin Juravle11351682014-10-23 15:38:15 +01001945 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001946
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001947 default:
Calin Juravle11351682014-10-23 15:38:15 +01001948 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001949 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001950}
1951
1952void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
1953 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001954 Location first = locations->InAt(0);
1955 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01001956 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001957 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001958 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001959 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001960 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001961 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001962 __ subl(first.AsRegister<Register>(),
1963 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001964 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001965 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001966 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001967 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001968 }
1969
1970 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001971 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01001972 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1973 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001974 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01001975 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001976 __ sbbl(first.AsRegisterPairHigh<Register>(),
1977 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001978 } else {
1979 DCHECK(second.IsConstant()) << second;
1980 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1981 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
1982 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001983 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001984 break;
1985 }
1986
Calin Juravle11351682014-10-23 15:38:15 +01001987 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001988 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001989 break;
Calin Juravle11351682014-10-23 15:38:15 +01001990 }
1991
1992 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001993 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01001994 break;
1995 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001996
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001997 default:
Calin Juravle11351682014-10-23 15:38:15 +01001998 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001999 }
2000}
2001
Calin Juravle34bacdf2014-10-07 20:23:36 +01002002void LocationsBuilderX86::VisitMul(HMul* mul) {
2003 LocationSummary* locations =
2004 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2005 switch (mul->GetResultType()) {
2006 case Primitive::kPrimInt:
2007 locations->SetInAt(0, Location::RequiresRegister());
2008 locations->SetInAt(1, Location::Any());
2009 locations->SetOut(Location::SameAsFirstInput());
2010 break;
2011 case Primitive::kPrimLong: {
2012 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002013 locations->SetInAt(1, Location::Any());
2014 locations->SetOut(Location::SameAsFirstInput());
2015 // Needed for imul on 32bits with 64bits output.
2016 locations->AddTemp(Location::RegisterLocation(EAX));
2017 locations->AddTemp(Location::RegisterLocation(EDX));
2018 break;
2019 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002020 case Primitive::kPrimFloat:
2021 case Primitive::kPrimDouble: {
2022 locations->SetInAt(0, Location::RequiresFpuRegister());
2023 locations->SetInAt(1, Location::RequiresFpuRegister());
2024 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002025 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002026 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002027
2028 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002029 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002030 }
2031}
2032
2033void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2034 LocationSummary* locations = mul->GetLocations();
2035 Location first = locations->InAt(0);
2036 Location second = locations->InAt(1);
2037 DCHECK(first.Equals(locations->Out()));
2038
2039 switch (mul->GetResultType()) {
2040 case Primitive::kPrimInt: {
2041 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002042 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002043 } else if (second.IsConstant()) {
2044 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002045 __ imull(first.AsRegister<Register>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002046 } else {
2047 DCHECK(second.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002048 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002049 }
2050 break;
2051 }
2052
2053 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002054 Register in1_hi = first.AsRegisterPairHigh<Register>();
2055 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002056 Register eax = locations->GetTemp(0).AsRegister<Register>();
2057 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002058
2059 DCHECK_EQ(EAX, eax);
2060 DCHECK_EQ(EDX, edx);
2061
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002062 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002063 // output: in1
2064 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2065 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2066 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002067 if (second.IsConstant()) {
2068 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002069
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002070 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2071 int32_t low_value = Low32Bits(value);
2072 int32_t high_value = High32Bits(value);
2073 Immediate low(low_value);
2074 Immediate high(high_value);
2075
2076 __ movl(eax, high);
2077 // eax <- in1.lo * in2.hi
2078 __ imull(eax, in1_lo);
2079 // in1.hi <- in1.hi * in2.lo
2080 __ imull(in1_hi, low);
2081 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2082 __ addl(in1_hi, eax);
2083 // move in2_lo to eax to prepare for double precision
2084 __ movl(eax, low);
2085 // edx:eax <- in1.lo * in2.lo
2086 __ mull(in1_lo);
2087 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2088 __ addl(in1_hi, edx);
2089 // in1.lo <- (in1.lo * in2.lo)[31:0];
2090 __ movl(in1_lo, eax);
2091 } else if (second.IsRegisterPair()) {
2092 Register in2_hi = second.AsRegisterPairHigh<Register>();
2093 Register in2_lo = second.AsRegisterPairLow<Register>();
2094
2095 __ movl(eax, in2_hi);
2096 // eax <- in1.lo * in2.hi
2097 __ imull(eax, in1_lo);
2098 // in1.hi <- in1.hi * in2.lo
2099 __ imull(in1_hi, in2_lo);
2100 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2101 __ addl(in1_hi, eax);
2102 // move in1_lo to eax to prepare for double precision
2103 __ movl(eax, in1_lo);
2104 // edx:eax <- in1.lo * in2.lo
2105 __ mull(in2_lo);
2106 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2107 __ addl(in1_hi, edx);
2108 // in1.lo <- (in1.lo * in2.lo)[31:0];
2109 __ movl(in1_lo, eax);
2110 } else {
2111 DCHECK(second.IsDoubleStackSlot()) << second;
2112 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2113 Address in2_lo(ESP, second.GetStackIndex());
2114
2115 __ movl(eax, in2_hi);
2116 // eax <- in1.lo * in2.hi
2117 __ imull(eax, in1_lo);
2118 // in1.hi <- in1.hi * in2.lo
2119 __ imull(in1_hi, in2_lo);
2120 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2121 __ addl(in1_hi, eax);
2122 // move in1_lo to eax to prepare for double precision
2123 __ movl(eax, in1_lo);
2124 // edx:eax <- in1.lo * in2.lo
2125 __ mull(in2_lo);
2126 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2127 __ addl(in1_hi, edx);
2128 // in1.lo <- (in1.lo * in2.lo)[31:0];
2129 __ movl(in1_lo, eax);
2130 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002131
2132 break;
2133 }
2134
Calin Juravleb5bfa962014-10-21 18:02:24 +01002135 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002136 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002137 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002138 }
2139
2140 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002141 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002142 break;
2143 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002144
2145 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002146 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002147 }
2148}
2149
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002150void InstructionCodeGeneratorX86::PushOntoFPStack(Location source, uint32_t temp_offset,
2151 uint32_t stack_adjustment, bool is_float) {
2152 if (source.IsStackSlot()) {
2153 DCHECK(is_float);
2154 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2155 } else if (source.IsDoubleStackSlot()) {
2156 DCHECK(!is_float);
2157 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2158 } else {
2159 // Write the value to the temporary location on the stack and load to FP stack.
2160 if (is_float) {
2161 Location stack_temp = Location::StackSlot(temp_offset);
2162 codegen_->Move32(stack_temp, source);
2163 __ flds(Address(ESP, temp_offset));
2164 } else {
2165 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2166 codegen_->Move64(stack_temp, source);
2167 __ fldl(Address(ESP, temp_offset));
2168 }
2169 }
2170}
2171
2172void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2173 Primitive::Type type = rem->GetResultType();
2174 bool is_float = type == Primitive::kPrimFloat;
2175 size_t elem_size = Primitive::ComponentSize(type);
2176 LocationSummary* locations = rem->GetLocations();
2177 Location first = locations->InAt(0);
2178 Location second = locations->InAt(1);
2179 Location out = locations->Out();
2180
2181 // Create stack space for 2 elements.
2182 // TODO: enhance register allocator to ask for stack temporaries.
2183 __ subl(ESP, Immediate(2 * elem_size));
2184
2185 // Load the values to the FP stack in reverse order, using temporaries if needed.
2186 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2187 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2188
2189 // Loop doing FPREM until we stabilize.
2190 Label retry;
2191 __ Bind(&retry);
2192 __ fprem();
2193
2194 // Move FP status to AX.
2195 __ fstsw();
2196
2197 // And see if the argument reduction is complete. This is signaled by the
2198 // C2 FPU flag bit set to 0.
2199 __ andl(EAX, Immediate(kC2ConditionMask));
2200 __ j(kNotEqual, &retry);
2201
2202 // We have settled on the final value. Retrieve it into an XMM register.
2203 // Store FP top of stack to real stack.
2204 if (is_float) {
2205 __ fsts(Address(ESP, 0));
2206 } else {
2207 __ fstl(Address(ESP, 0));
2208 }
2209
2210 // Pop the 2 items from the FP stack.
2211 __ fucompp();
2212
2213 // Load the value from the stack into an XMM register.
2214 DCHECK(out.IsFpuRegister()) << out;
2215 if (is_float) {
2216 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2217 } else {
2218 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2219 }
2220
2221 // And remove the temporary stack space we allocated.
2222 __ addl(ESP, Immediate(2 * elem_size));
2223}
2224
Calin Juravlebacfec32014-11-14 15:54:36 +00002225void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2226 DCHECK(instruction->IsDiv() || instruction->IsRem());
2227
2228 LocationSummary* locations = instruction->GetLocations();
2229 Location out = locations->Out();
2230 Location first = locations->InAt(0);
2231 Location second = locations->InAt(1);
2232 bool is_div = instruction->IsDiv();
2233
2234 switch (instruction->GetResultType()) {
2235 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002236 Register second_reg = second.AsRegister<Register>();
2237 DCHECK_EQ(EAX, first.AsRegister<Register>());
2238 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002239
2240 SlowPathCodeX86* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002241 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
2242 is_div);
Calin Juravlebacfec32014-11-14 15:54:36 +00002243 codegen_->AddSlowPath(slow_path);
2244
2245 // 0x80000000/-1 triggers an arithmetic exception!
2246 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2247 // it's safe to just use negl instead of more complex comparisons.
2248
2249 __ cmpl(second_reg, Immediate(-1));
2250 __ j(kEqual, slow_path->GetEntryLabel());
2251
2252 // edx:eax <- sign-extended of eax
2253 __ cdq();
2254 // eax = quotient, edx = remainder
2255 __ idivl(second_reg);
2256
2257 __ Bind(slow_path->GetExitLabel());
2258 break;
2259 }
2260
2261 case Primitive::kPrimLong: {
2262 InvokeRuntimeCallingConvention calling_convention;
2263 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2264 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2265 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2266 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2267 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2268 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2269
2270 if (is_div) {
2271 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv)));
2272 } else {
2273 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod)));
2274 }
2275 uint32_t dex_pc = is_div
2276 ? instruction->AsDiv()->GetDexPc()
2277 : instruction->AsRem()->GetDexPc();
2278 codegen_->RecordPcInfo(instruction, dex_pc);
2279
2280 break;
2281 }
2282
2283 default:
2284 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
2285 }
2286}
2287
Calin Juravle7c4954d2014-10-28 16:57:40 +00002288void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002289 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002290 ? LocationSummary::kCall
2291 : LocationSummary::kNoCall;
2292 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2293
Calin Juravle7c4954d2014-10-28 16:57:40 +00002294 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002295 case Primitive::kPrimInt: {
2296 locations->SetInAt(0, Location::RegisterLocation(EAX));
2297 locations->SetInAt(1, Location::RequiresRegister());
2298 locations->SetOut(Location::SameAsFirstInput());
2299 // Intel uses edx:eax as the dividend.
2300 locations->AddTemp(Location::RegisterLocation(EDX));
2301 break;
2302 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002303 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002304 InvokeRuntimeCallingConvention calling_convention;
2305 locations->SetInAt(0, Location::RegisterPairLocation(
2306 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2307 locations->SetInAt(1, Location::RegisterPairLocation(
2308 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2309 // Runtime helper puts the result in EAX, EDX.
2310 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002311 break;
2312 }
2313 case Primitive::kPrimFloat:
2314 case Primitive::kPrimDouble: {
2315 locations->SetInAt(0, Location::RequiresFpuRegister());
2316 locations->SetInAt(1, Location::RequiresFpuRegister());
2317 locations->SetOut(Location::SameAsFirstInput());
2318 break;
2319 }
2320
2321 default:
2322 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2323 }
2324}
2325
2326void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
2327 LocationSummary* locations = div->GetLocations();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002328 Location out = locations->Out();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002329 Location first = locations->InAt(0);
2330 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002331
2332 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002333 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00002334 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002335 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002336 break;
2337 }
2338
2339 case Primitive::kPrimFloat: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002340 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002341 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002342 break;
2343 }
2344
2345 case Primitive::kPrimDouble: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002346 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002347 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002348 break;
2349 }
2350
2351 default:
2352 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2353 }
2354}
2355
Calin Juravlebacfec32014-11-14 15:54:36 +00002356void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002357 Primitive::Type type = rem->GetResultType();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002358 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
2359 ? LocationSummary::kCall
2360 : LocationSummary::kNoCall;
2361 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00002362
Calin Juravled2ec87d2014-12-08 14:24:46 +00002363 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002364 case Primitive::kPrimInt: {
2365 locations->SetInAt(0, Location::RegisterLocation(EAX));
2366 locations->SetInAt(1, Location::RequiresRegister());
2367 locations->SetOut(Location::RegisterLocation(EDX));
2368 break;
2369 }
2370 case Primitive::kPrimLong: {
2371 InvokeRuntimeCallingConvention calling_convention;
2372 locations->SetInAt(0, Location::RegisterPairLocation(
2373 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2374 locations->SetInAt(1, Location::RegisterPairLocation(
2375 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2376 // Runtime helper puts the result in EAX, EDX.
2377 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2378 break;
2379 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002380 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002381 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002382 locations->SetInAt(0, Location::Any());
2383 locations->SetInAt(1, Location::Any());
2384 locations->SetOut(Location::RequiresFpuRegister());
2385 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002386 break;
2387 }
2388
2389 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002390 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002391 }
2392}
2393
2394void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
2395 Primitive::Type type = rem->GetResultType();
2396 switch (type) {
2397 case Primitive::kPrimInt:
2398 case Primitive::kPrimLong: {
2399 GenerateDivRemIntegral(rem);
2400 break;
2401 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002402 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00002403 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002404 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00002405 break;
2406 }
2407 default:
2408 LOG(FATAL) << "Unexpected rem type " << type;
2409 }
2410}
2411
Calin Juravled0d48522014-11-04 16:40:20 +00002412void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2413 LocationSummary* locations =
2414 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002415 switch (instruction->GetType()) {
2416 case Primitive::kPrimInt: {
2417 locations->SetInAt(0, Location::Any());
2418 break;
2419 }
2420 case Primitive::kPrimLong: {
2421 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2422 if (!instruction->IsConstant()) {
2423 locations->AddTemp(Location::RequiresRegister());
2424 }
2425 break;
2426 }
2427 default:
2428 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2429 }
Calin Juravled0d48522014-11-04 16:40:20 +00002430 if (instruction->HasUses()) {
2431 locations->SetOut(Location::SameAsFirstInput());
2432 }
2433}
2434
2435void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2436 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
2437 codegen_->AddSlowPath(slow_path);
2438
2439 LocationSummary* locations = instruction->GetLocations();
2440 Location value = locations->InAt(0);
2441
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002442 switch (instruction->GetType()) {
2443 case Primitive::kPrimInt: {
2444 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002445 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002446 __ j(kEqual, slow_path->GetEntryLabel());
2447 } else if (value.IsStackSlot()) {
2448 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
2449 __ j(kEqual, slow_path->GetEntryLabel());
2450 } else {
2451 DCHECK(value.IsConstant()) << value;
2452 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2453 __ jmp(slow_path->GetEntryLabel());
2454 }
2455 }
2456 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002457 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002458 case Primitive::kPrimLong: {
2459 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002460 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002461 __ movl(temp, value.AsRegisterPairLow<Register>());
2462 __ orl(temp, value.AsRegisterPairHigh<Register>());
2463 __ j(kEqual, slow_path->GetEntryLabel());
2464 } else {
2465 DCHECK(value.IsConstant()) << value;
2466 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2467 __ jmp(slow_path->GetEntryLabel());
2468 }
2469 }
2470 break;
2471 }
2472 default:
2473 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002474 }
Calin Juravled0d48522014-11-04 16:40:20 +00002475}
2476
Calin Juravle9aec02f2014-11-18 23:06:35 +00002477void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
2478 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2479
2480 LocationSummary* locations =
2481 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2482
2483 switch (op->GetResultType()) {
2484 case Primitive::kPrimInt: {
2485 locations->SetInAt(0, Location::RequiresRegister());
2486 // The shift count needs to be in CL.
2487 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
2488 locations->SetOut(Location::SameAsFirstInput());
2489 break;
2490 }
2491 case Primitive::kPrimLong: {
2492 locations->SetInAt(0, Location::RequiresRegister());
2493 // The shift count needs to be in CL.
2494 locations->SetInAt(1, Location::RegisterLocation(ECX));
2495 locations->SetOut(Location::SameAsFirstInput());
2496 break;
2497 }
2498 default:
2499 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2500 }
2501}
2502
2503void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
2504 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2505
2506 LocationSummary* locations = op->GetLocations();
2507 Location first = locations->InAt(0);
2508 Location second = locations->InAt(1);
2509 DCHECK(first.Equals(locations->Out()));
2510
2511 switch (op->GetResultType()) {
2512 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002513 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002514 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002515 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002516 DCHECK_EQ(ECX, second_reg);
2517 if (op->IsShl()) {
2518 __ shll(first_reg, second_reg);
2519 } else if (op->IsShr()) {
2520 __ sarl(first_reg, second_reg);
2521 } else {
2522 __ shrl(first_reg, second_reg);
2523 }
2524 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002525 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002526 if (op->IsShl()) {
2527 __ shll(first_reg, imm);
2528 } else if (op->IsShr()) {
2529 __ sarl(first_reg, imm);
2530 } else {
2531 __ shrl(first_reg, imm);
2532 }
2533 }
2534 break;
2535 }
2536 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002537 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002538 DCHECK_EQ(ECX, second_reg);
2539 if (op->IsShl()) {
2540 GenerateShlLong(first, second_reg);
2541 } else if (op->IsShr()) {
2542 GenerateShrLong(first, second_reg);
2543 } else {
2544 GenerateUShrLong(first, second_reg);
2545 }
2546 break;
2547 }
2548 default:
2549 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2550 }
2551}
2552
2553void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
2554 Label done;
2555 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
2556 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
2557 __ testl(shifter, Immediate(32));
2558 __ j(kEqual, &done);
2559 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
2560 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
2561 __ Bind(&done);
2562}
2563
2564void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
2565 Label done;
2566 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2567 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
2568 __ testl(shifter, Immediate(32));
2569 __ j(kEqual, &done);
2570 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2571 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
2572 __ Bind(&done);
2573}
2574
2575void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
2576 Label done;
2577 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2578 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
2579 __ testl(shifter, Immediate(32));
2580 __ j(kEqual, &done);
2581 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2582 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
2583 __ Bind(&done);
2584}
2585
2586void LocationsBuilderX86::VisitShl(HShl* shl) {
2587 HandleShift(shl);
2588}
2589
2590void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
2591 HandleShift(shl);
2592}
2593
2594void LocationsBuilderX86::VisitShr(HShr* shr) {
2595 HandleShift(shr);
2596}
2597
2598void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
2599 HandleShift(shr);
2600}
2601
2602void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
2603 HandleShift(ushr);
2604}
2605
2606void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
2607 HandleShift(ushr);
2608}
2609
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002610void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002611 LocationSummary* locations =
2612 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002613 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002614 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002615 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2616 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002617}
2618
2619void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
2620 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002621 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002622 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002623
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002624 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002625
Nicolas Geoffray39468442014-09-02 15:17:15 +01002626 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002627 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002628}
2629
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002630void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
2631 LocationSummary* locations =
2632 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2633 locations->SetOut(Location::RegisterLocation(EAX));
2634 InvokeRuntimeCallingConvention calling_convention;
2635 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002636 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2637 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002638}
2639
2640void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
2641 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002642 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002643 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
2644
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002645 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002646
2647 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2648 DCHECK(!codegen_->IsLeafMethod());
2649}
2650
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002651void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002652 LocationSummary* locations =
2653 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002654 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2655 if (location.IsStackSlot()) {
2656 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2657 } else if (location.IsDoubleStackSlot()) {
2658 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002659 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002660 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002661}
2662
2663void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002664 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002665}
2666
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002667void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002668 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002669 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002670 locations->SetInAt(0, Location::RequiresRegister());
2671 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002672}
2673
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002674void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
2675 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01002676 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002677 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01002678 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002679 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002680 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002681 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002682 break;
2683
2684 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002685 __ notl(out.AsRegisterPairLow<Register>());
2686 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002687 break;
2688
2689 default:
2690 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2691 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002692}
2693
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002694void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002695 LocationSummary* locations =
2696 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002697 switch (compare->InputAt(0)->GetType()) {
2698 case Primitive::kPrimLong: {
2699 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00002700 locations->SetInAt(1, Location::Any());
2701 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2702 break;
2703 }
2704 case Primitive::kPrimFloat:
2705 case Primitive::kPrimDouble: {
2706 locations->SetInAt(0, Location::RequiresFpuRegister());
2707 locations->SetInAt(1, Location::RequiresFpuRegister());
2708 locations->SetOut(Location::RequiresRegister());
2709 break;
2710 }
2711 default:
2712 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2713 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002714}
2715
2716void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002717 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002718 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002719 Location left = locations->InAt(0);
2720 Location right = locations->InAt(1);
2721
2722 Label less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002723 switch (compare->InputAt(0)->GetType()) {
2724 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002725 Register left_low = left.AsRegisterPairLow<Register>();
2726 Register left_high = left.AsRegisterPairHigh<Register>();
2727 int32_t val_low = 0;
2728 int32_t val_high = 0;
2729 bool right_is_const = false;
2730
2731 if (right.IsConstant()) {
2732 DCHECK(right.GetConstant()->IsLongConstant());
2733 right_is_const = true;
2734 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
2735 val_low = Low32Bits(val);
2736 val_high = High32Bits(val);
2737 }
2738
Calin Juravleddb7df22014-11-25 20:56:51 +00002739 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002740 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002741 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002742 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002743 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002744 DCHECK(right_is_const) << right;
2745 if (val_high == 0) {
2746 __ testl(left_high, left_high);
2747 } else {
2748 __ cmpl(left_high, Immediate(val_high));
2749 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002750 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002751 __ j(kLess, &less); // Signed compare.
2752 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002753 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002754 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002755 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002756 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002757 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002758 DCHECK(right_is_const) << right;
2759 if (val_low == 0) {
2760 __ testl(left_low, left_low);
2761 } else {
2762 __ cmpl(left_low, Immediate(val_low));
2763 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002764 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002765 break;
2766 }
2767 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002768 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002769 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
2770 break;
2771 }
2772 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002773 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002774 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002775 break;
2776 }
2777 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002778 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002779 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002780 __ movl(out, Immediate(0));
2781 __ j(kEqual, &done);
2782 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
2783
2784 __ Bind(&greater);
2785 __ movl(out, Immediate(1));
2786 __ jmp(&done);
2787
2788 __ Bind(&less);
2789 __ movl(out, Immediate(-1));
2790
2791 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002792}
2793
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002794void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002795 LocationSummary* locations =
2796 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002797 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2798 locations->SetInAt(i, Location::Any());
2799 }
2800 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002801}
2802
2803void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002804 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002805 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002806}
2807
Calin Juravle52c48962014-12-16 17:02:57 +00002808void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
2809 /*
2810 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2811 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2812 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2813 */
2814 switch (kind) {
2815 case MemBarrierKind::kAnyAny: {
2816 __ mfence();
2817 break;
2818 }
2819 case MemBarrierKind::kAnyStore:
2820 case MemBarrierKind::kLoadAny:
2821 case MemBarrierKind::kStoreStore: {
2822 // nop
2823 break;
2824 }
2825 default:
2826 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002827 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002828}
2829
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002830
Mark Mendell09ed1a32015-03-25 08:30:06 -04002831void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
2832 Register temp) {
2833 // TODO: Implement all kinds of calls:
2834 // 1) boot -> boot
2835 // 2) app -> boot
2836 // 3) app -> app
2837 //
2838 // Currently we implement the app -> app logic, which looks up in the resolve cache.
2839 // temp = method;
2840 LoadCurrentMethod(temp);
2841 if (!invoke->IsRecursive()) {
2842 // temp = temp->dex_cache_resolved_methods_;
2843 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
2844 // temp = temp[index_in_cache]
2845 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
2846 // (temp + offset_of_quick_compiled_code)()
2847 __ call(Address(
2848 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
2849 } else {
2850 __ call(GetFrameEntryLabel());
2851 }
2852
2853 DCHECK(!IsLeafMethod());
2854 RecordPcInfo(invoke, invoke->GetDexPc());
2855}
2856
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002857void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002858 Label is_null;
2859 __ testl(value, value);
2860 __ j(kEqual, &is_null);
2861 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
2862 __ movl(temp, object);
2863 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002864 __ movb(Address(temp, card, TIMES_1, 0),
2865 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002866 __ Bind(&is_null);
2867}
2868
Calin Juravle52c48962014-12-16 17:02:57 +00002869void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
2870 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002871 LocationSummary* locations =
2872 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002873 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002874
2875 // The output overlaps in case of long: we don't want the low move to overwrite
2876 // the object's location.
2877 locations->SetOut(Location::RequiresRegister(),
2878 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
2879 : Location::kNoOutputOverlap);
Calin Juravle52c48962014-12-16 17:02:57 +00002880
2881 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
2882 // Long values can be loaded atomically into an XMM using movsd.
2883 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
2884 // and then copy the XMM into the output 32bits at a time).
2885 locations->AddTemp(Location::RequiresFpuRegister());
2886 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002887}
2888
Calin Juravle52c48962014-12-16 17:02:57 +00002889void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
2890 const FieldInfo& field_info) {
2891 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002892
Calin Juravle52c48962014-12-16 17:02:57 +00002893 LocationSummary* locations = instruction->GetLocations();
2894 Register base = locations->InAt(0).AsRegister<Register>();
2895 Location out = locations->Out();
2896 bool is_volatile = field_info.IsVolatile();
2897 Primitive::Type field_type = field_info.GetFieldType();
2898 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2899
2900 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002901 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00002902 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002903 break;
2904 }
2905
2906 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002907 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002908 break;
2909 }
2910
2911 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00002912 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002913 break;
2914 }
2915
2916 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002917 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002918 break;
2919 }
2920
2921 case Primitive::kPrimInt:
2922 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002923 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002924 break;
2925 }
2926
2927 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002928 if (is_volatile) {
2929 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2930 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00002931 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002932 __ movd(out.AsRegisterPairLow<Register>(), temp);
2933 __ psrlq(temp, Immediate(32));
2934 __ movd(out.AsRegisterPairHigh<Register>(), temp);
2935 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002936 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00002937 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00002938 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002939 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
2940 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002941 break;
2942 }
2943
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002944 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002945 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002946 break;
2947 }
2948
2949 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002950 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002951 break;
2952 }
2953
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002954 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00002955 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002956 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002957 }
Calin Juravle52c48962014-12-16 17:02:57 +00002958
Calin Juravle77520bc2015-01-12 18:45:46 +00002959 // Longs are handled in the switch.
2960 if (field_type != Primitive::kPrimLong) {
2961 codegen_->MaybeRecordImplicitNullCheck(instruction);
2962 }
2963
Calin Juravle52c48962014-12-16 17:02:57 +00002964 if (is_volatile) {
2965 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2966 }
2967}
2968
2969void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2970 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2971
2972 LocationSummary* locations =
2973 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2974 locations->SetInAt(0, Location::RequiresRegister());
2975 bool is_volatile = field_info.IsVolatile();
2976 Primitive::Type field_type = field_info.GetFieldType();
2977 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
2978 || (field_type == Primitive::kPrimByte);
2979
2980 // The register allocator does not support multiple
2981 // inputs that die at entry with one in a specific register.
2982 if (is_byte_type) {
2983 // Ensure the value is in a byte register.
2984 locations->SetInAt(1, Location::RegisterLocation(EAX));
2985 } else {
2986 locations->SetInAt(1, Location::RequiresRegister());
2987 }
2988 // Temporary registers for the write barrier.
2989 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2990 locations->AddTemp(Location::RequiresRegister());
2991 // Ensure the card is in a byte register.
2992 locations->AddTemp(Location::RegisterLocation(ECX));
2993 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
2994 // 64bits value can be atomically written to an address with movsd and an XMM register.
2995 // We need two XMM registers because there's no easier way to (bit) copy a register pair
2996 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
2997 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
2998 // isolated cases when we need this it isn't worth adding the extra complexity.
2999 locations->AddTemp(Location::RequiresFpuRegister());
3000 locations->AddTemp(Location::RequiresFpuRegister());
3001 }
3002}
3003
3004void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
3005 const FieldInfo& field_info) {
3006 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3007
3008 LocationSummary* locations = instruction->GetLocations();
3009 Register base = locations->InAt(0).AsRegister<Register>();
3010 Location value = locations->InAt(1);
3011 bool is_volatile = field_info.IsVolatile();
3012 Primitive::Type field_type = field_info.GetFieldType();
3013 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3014
3015 if (is_volatile) {
3016 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3017 }
3018
3019 switch (field_type) {
3020 case Primitive::kPrimBoolean:
3021 case Primitive::kPrimByte: {
3022 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
3023 break;
3024 }
3025
3026 case Primitive::kPrimShort:
3027 case Primitive::kPrimChar: {
3028 __ movw(Address(base, offset), value.AsRegister<Register>());
3029 break;
3030 }
3031
3032 case Primitive::kPrimInt:
3033 case Primitive::kPrimNot: {
3034 __ movl(Address(base, offset), value.AsRegister<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003035 break;
3036 }
3037
3038 case Primitive::kPrimLong: {
3039 if (is_volatile) {
3040 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3041 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
3042 __ movd(temp1, value.AsRegisterPairLow<Register>());
3043 __ movd(temp2, value.AsRegisterPairHigh<Register>());
3044 __ punpckldq(temp1, temp2);
3045 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00003046 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003047 } else {
3048 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003049 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003050 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
3051 }
3052 break;
3053 }
3054
3055 case Primitive::kPrimFloat: {
3056 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3057 break;
3058 }
3059
3060 case Primitive::kPrimDouble: {
3061 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3062 break;
3063 }
3064
3065 case Primitive::kPrimVoid:
3066 LOG(FATAL) << "Unreachable type " << field_type;
3067 UNREACHABLE();
3068 }
3069
Calin Juravle77520bc2015-01-12 18:45:46 +00003070 // Longs are handled in the switch.
3071 if (field_type != Primitive::kPrimLong) {
3072 codegen_->MaybeRecordImplicitNullCheck(instruction);
3073 }
3074
3075 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3076 Register temp = locations->GetTemp(0).AsRegister<Register>();
3077 Register card = locations->GetTemp(1).AsRegister<Register>();
3078 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
3079 }
3080
Calin Juravle52c48962014-12-16 17:02:57 +00003081 if (is_volatile) {
3082 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3083 }
3084}
3085
3086void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3087 HandleFieldGet(instruction, instruction->GetFieldInfo());
3088}
3089
3090void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3091 HandleFieldGet(instruction, instruction->GetFieldInfo());
3092}
3093
3094void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3095 HandleFieldSet(instruction, instruction->GetFieldInfo());
3096}
3097
3098void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3099 HandleFieldSet(instruction, instruction->GetFieldInfo());
3100}
3101
3102void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3103 HandleFieldSet(instruction, instruction->GetFieldInfo());
3104}
3105
3106void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3107 HandleFieldSet(instruction, instruction->GetFieldInfo());
3108}
3109
3110void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3111 HandleFieldGet(instruction, instruction->GetFieldInfo());
3112}
3113
3114void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3115 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003116}
3117
3118void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003119 LocationSummary* locations =
3120 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003121 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3122 ? Location::RequiresRegister()
3123 : Location::Any();
3124 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003125 if (instruction->HasUses()) {
3126 locations->SetOut(Location::SameAsFirstInput());
3127 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003128}
3129
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003130void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003131 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3132 return;
3133 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003134 LocationSummary* locations = instruction->GetLocations();
3135 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003136
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003137 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
3138 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3139}
3140
3141void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003142 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003143 codegen_->AddSlowPath(slow_path);
3144
3145 LocationSummary* locations = instruction->GetLocations();
3146 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003147
3148 if (obj.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003149 __ cmpl(obj.AsRegister<Register>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003150 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003151 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003152 } else {
3153 DCHECK(obj.IsConstant()) << obj;
3154 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3155 __ jmp(slow_path->GetEntryLabel());
3156 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003157 }
3158 __ j(kEqual, slow_path->GetEntryLabel());
3159}
3160
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003161void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
3162 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3163 GenerateImplicitNullCheck(instruction);
3164 } else {
3165 GenerateExplicitNullCheck(instruction);
3166 }
3167}
3168
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003169void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003170 LocationSummary* locations =
3171 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003172 locations->SetInAt(0, Location::RequiresRegister());
3173 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003174 // The output overlaps in case of long: we don't want the low move to overwrite
3175 // the array's location.
3176 locations->SetOut(Location::RequiresRegister(),
3177 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3178 : Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003179}
3180
3181void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
3182 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003183 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003184 Location index = locations->InAt(1);
3185
Calin Juravle77520bc2015-01-12 18:45:46 +00003186 Primitive::Type type = instruction->GetType();
3187 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003188 case Primitive::kPrimBoolean: {
3189 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003190 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003191 if (index.IsConstant()) {
3192 __ movzxb(out, Address(obj,
3193 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3194 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003195 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003196 }
3197 break;
3198 }
3199
3200 case Primitive::kPrimByte: {
3201 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003202 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003203 if (index.IsConstant()) {
3204 __ movsxb(out, Address(obj,
3205 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3206 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003207 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003208 }
3209 break;
3210 }
3211
3212 case Primitive::kPrimShort: {
3213 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003214 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003215 if (index.IsConstant()) {
3216 __ movsxw(out, Address(obj,
3217 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3218 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003219 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003220 }
3221 break;
3222 }
3223
3224 case Primitive::kPrimChar: {
3225 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003226 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003227 if (index.IsConstant()) {
3228 __ movzxw(out, Address(obj,
3229 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3230 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003231 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003232 }
3233 break;
3234 }
3235
3236 case Primitive::kPrimInt:
3237 case Primitive::kPrimNot: {
3238 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003239 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003240 if (index.IsConstant()) {
3241 __ movl(out, Address(obj,
3242 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3243 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003244 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003245 }
3246 break;
3247 }
3248
3249 case Primitive::kPrimLong: {
3250 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003251 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003252 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003253 if (index.IsConstant()) {
3254 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003255 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003256 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003257 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003258 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003259 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003260 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003261 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003262 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003263 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003264 }
3265 break;
3266 }
3267
Mark Mendell7c8d0092015-01-26 11:21:33 -05003268 case Primitive::kPrimFloat: {
3269 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3270 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3271 if (index.IsConstant()) {
3272 __ movss(out, Address(obj,
3273 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3274 } else {
3275 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
3276 }
3277 break;
3278 }
3279
3280 case Primitive::kPrimDouble: {
3281 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3282 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3283 if (index.IsConstant()) {
3284 __ movsd(out, Address(obj,
3285 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3286 } else {
3287 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
3288 }
3289 break;
3290 }
3291
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003292 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00003293 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003294 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003295 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003296
3297 if (type != Primitive::kPrimLong) {
3298 codegen_->MaybeRecordImplicitNullCheck(instruction);
3299 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003300}
3301
3302void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05003303 // This location builder might end up asking to up to four registers, which is
3304 // not currently possible for baseline. The situation in which we need four
3305 // registers cannot be met by baseline though, because it has not run any
3306 // optimization.
3307
Nicolas Geoffray39468442014-09-02 15:17:15 +01003308 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003309 bool needs_write_barrier =
3310 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3311
Mark Mendell5f874182015-03-04 15:42:45 -05003312 bool needs_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003313
Nicolas Geoffray39468442014-09-02 15:17:15 +01003314 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3315 instruction,
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003316 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003317
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003318 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003319 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003320 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3321 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3322 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003323 } else {
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003324 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
3325 || (value_type == Primitive::kPrimByte);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003326 // We need the inputs to be different than the output in case of long operation.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003327 // In case of a byte operation, the register allocator does not support multiple
3328 // inputs that die at entry with one in a specific register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003329 locations->SetInAt(0, Location::RequiresRegister());
3330 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003331 if (is_byte_type) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003332 // Ensure the value is in a byte register.
3333 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003334 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003335 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003336 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003337 // Temporary registers for the write barrier.
3338 if (needs_write_barrier) {
3339 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003340 // Ensure the card is in a byte register.
3341 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003342 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003343 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003344}
3345
3346void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
3347 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003348 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003349 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003350 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003351 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003352 bool needs_runtime_call = locations->WillCall();
3353 bool needs_write_barrier =
3354 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003355
3356 switch (value_type) {
3357 case Primitive::kPrimBoolean:
3358 case Primitive::kPrimByte: {
3359 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003360 if (index.IsConstant()) {
3361 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003362 if (value.IsRegister()) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003363 __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003364 } else {
3365 __ movb(Address(obj, offset),
3366 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3367 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003368 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003369 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003370 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003371 value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003372 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003373 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003374 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3375 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003376 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003377 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003378 break;
3379 }
3380
3381 case Primitive::kPrimShort:
3382 case Primitive::kPrimChar: {
3383 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003384 if (index.IsConstant()) {
3385 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003386 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003387 __ movw(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003388 } else {
3389 __ movw(Address(obj, offset),
3390 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3391 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003392 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003393 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003394 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
3395 value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003396 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003397 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003398 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3399 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003400 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003401 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003402 break;
3403 }
3404
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003405 case Primitive::kPrimInt:
3406 case Primitive::kPrimNot: {
3407 if (!needs_runtime_call) {
3408 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3409 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003410 size_t offset =
3411 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003412 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003413 __ movl(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003414 } else {
3415 DCHECK(value.IsConstant()) << value;
3416 __ movl(Address(obj, offset),
3417 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3418 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003419 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003420 DCHECK(index.IsRegister()) << index;
3421 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003422 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3423 value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003424 } else {
3425 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003426 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003427 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3428 }
3429 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003430 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003431
3432 if (needs_write_barrier) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003433 Register temp = locations->GetTemp(0).AsRegister<Register>();
3434 Register card = locations->GetTemp(1).AsRegister<Register>();
3435 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003436 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003437 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003438 DCHECK_EQ(value_type, Primitive::kPrimNot);
3439 DCHECK(!codegen_->IsLeafMethod());
3440 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
3441 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003442 }
3443 break;
3444 }
3445
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003446 case Primitive::kPrimLong: {
3447 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003448 if (index.IsConstant()) {
3449 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003450 if (value.IsRegisterPair()) {
3451 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003452 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003453 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003454 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003455 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003456 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
3457 __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003458 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003459 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
3460 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003461 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003462 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003463 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003464 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003465 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003466 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003467 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003468 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003469 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003470 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003471 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003472 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003473 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003474 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003475 Immediate(High32Bits(val)));
3476 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003477 }
3478 break;
3479 }
3480
Mark Mendell7c8d0092015-01-26 11:21:33 -05003481 case Primitive::kPrimFloat: {
3482 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3483 DCHECK(value.IsFpuRegister());
3484 if (index.IsConstant()) {
3485 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3486 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3487 } else {
3488 __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3489 value.AsFpuRegister<XmmRegister>());
3490 }
3491 break;
3492 }
3493
3494 case Primitive::kPrimDouble: {
3495 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3496 DCHECK(value.IsFpuRegister());
3497 if (index.IsConstant()) {
3498 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3499 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3500 } else {
3501 __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3502 value.AsFpuRegister<XmmRegister>());
3503 }
3504 break;
3505 }
3506
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003507 case Primitive::kPrimVoid:
3508 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003509 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003510 }
3511}
3512
3513void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
3514 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003515 locations->SetInAt(0, Location::RequiresRegister());
3516 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003517 instruction->SetLocations(locations);
3518}
3519
3520void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
3521 LocationSummary* locations = instruction->GetLocations();
3522 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003523 Register obj = locations->InAt(0).AsRegister<Register>();
3524 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003525 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003526 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003527}
3528
3529void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003530 LocationSummary* locations =
3531 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003532 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003533 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003534 if (instruction->HasUses()) {
3535 locations->SetOut(Location::SameAsFirstInput());
3536 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003537}
3538
3539void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
3540 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003541 Location index_loc = locations->InAt(0);
3542 Location length_loc = locations->InAt(1);
3543 SlowPathCodeX86* slow_path =
3544 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003545 codegen_->AddSlowPath(slow_path);
3546
Mark Mendellf60c90b2015-03-04 15:12:59 -05003547 Register length = length_loc.AsRegister<Register>();
3548 if (index_loc.IsConstant()) {
3549 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3550 __ cmpl(length, Immediate(value));
3551 } else {
3552 __ cmpl(length, index_loc.AsRegister<Register>());
3553 }
3554 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003555}
3556
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003557void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
3558 temp->SetLocations(nullptr);
3559}
3560
3561void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
3562 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003563 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003564}
3565
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003566void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003567 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003568 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003569}
3570
3571void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003572 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3573}
3574
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003575void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
3576 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3577}
3578
3579void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003580 HBasicBlock* block = instruction->GetBlock();
3581 if (block->GetLoopInformation() != nullptr) {
3582 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3583 // The back edge will generate the suspend check.
3584 return;
3585 }
3586 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3587 // The goto will generate the suspend check.
3588 return;
3589 }
3590 GenerateSuspendCheck(instruction, nullptr);
3591}
3592
3593void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
3594 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003595 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003596 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003597 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003598 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003599 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003600 if (successor == nullptr) {
3601 __ j(kNotEqual, slow_path->GetEntryLabel());
3602 __ Bind(slow_path->GetReturnLabel());
3603 } else {
3604 __ j(kEqual, codegen_->GetLabelOf(successor));
3605 __ jmp(slow_path->GetEntryLabel());
3606 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003607}
3608
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003609X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
3610 return codegen_->GetAssembler();
3611}
3612
Mark Mendell7c8d0092015-01-26 11:21:33 -05003613void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003614 ScratchRegisterScope ensure_scratch(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003615 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003616 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003617 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
Mark Mendell7c8d0092015-01-26 11:21:33 -05003618 __ movl(temp_reg, Address(ESP, src + stack_offset));
3619 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3620}
3621
3622void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
3623 ScratchRegisterScope ensure_scratch(
3624 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3625 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3626 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3627 __ movl(temp_reg, Address(ESP, src + stack_offset));
3628 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3629 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
3630 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003631}
3632
3633void ParallelMoveResolverX86::EmitMove(size_t index) {
3634 MoveOperands* move = moves_.Get(index);
3635 Location source = move->GetSource();
3636 Location destination = move->GetDestination();
3637
3638 if (source.IsRegister()) {
3639 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003640 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003641 } else {
3642 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003643 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003644 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003645 } else if (source.IsFpuRegister()) {
3646 if (destination.IsFpuRegister()) {
3647 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3648 } else if (destination.IsStackSlot()) {
3649 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3650 } else {
3651 DCHECK(destination.IsDoubleStackSlot());
3652 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3653 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003654 } else if (source.IsStackSlot()) {
3655 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003656 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003657 } else if (destination.IsFpuRegister()) {
3658 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003659 } else {
3660 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003661 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
3662 }
3663 } else if (source.IsDoubleStackSlot()) {
3664 if (destination.IsFpuRegister()) {
3665 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
3666 } else {
3667 DCHECK(destination.IsDoubleStackSlot()) << destination;
3668 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003669 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003670 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003671 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003672 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003673 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05003674 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003675 if (value == 0) {
3676 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
3677 } else {
3678 __ movl(destination.AsRegister<Register>(), Immediate(value));
3679 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003680 } else {
3681 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05003682 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003683 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003684 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003685 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003686 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003687 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05003688 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003689 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3690 if (value == 0) {
3691 // Easy handling of 0.0.
3692 __ xorps(dest, dest);
3693 } else {
3694 ScratchRegisterScope ensure_scratch(
3695 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3696 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
3697 __ movl(temp, Immediate(value));
3698 __ movd(dest, temp);
3699 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003700 } else {
3701 DCHECK(destination.IsStackSlot()) << destination;
3702 __ movl(Address(ESP, destination.GetStackIndex()), imm);
3703 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003704 } else if (constant->IsLongConstant()) {
3705 int64_t value = constant->AsLongConstant()->GetValue();
3706 int32_t low_value = Low32Bits(value);
3707 int32_t high_value = High32Bits(value);
3708 Immediate low(low_value);
3709 Immediate high(high_value);
3710 if (destination.IsDoubleStackSlot()) {
3711 __ movl(Address(ESP, destination.GetStackIndex()), low);
3712 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
3713 } else {
3714 __ movl(destination.AsRegisterPairLow<Register>(), low);
3715 __ movl(destination.AsRegisterPairHigh<Register>(), high);
3716 }
3717 } else {
3718 DCHECK(constant->IsDoubleConstant());
3719 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003720 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003721 int32_t low_value = Low32Bits(value);
3722 int32_t high_value = High32Bits(value);
3723 Immediate low(low_value);
3724 Immediate high(high_value);
3725 if (destination.IsFpuRegister()) {
3726 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3727 if (value == 0) {
3728 // Easy handling of 0.0.
3729 __ xorpd(dest, dest);
3730 } else {
3731 __ pushl(high);
3732 __ pushl(low);
3733 __ movsd(dest, Address(ESP, 0));
3734 __ addl(ESP, Immediate(8));
3735 }
3736 } else {
3737 DCHECK(destination.IsDoubleStackSlot()) << destination;
3738 __ movl(Address(ESP, destination.GetStackIndex()), low);
3739 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
3740 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003741 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003742 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00003743 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003744 }
3745}
3746
3747void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003748 Register suggested_scratch = reg == EAX ? EBX : EAX;
3749 ScratchRegisterScope ensure_scratch(
3750 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3751
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003752 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3753 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
3754 __ movl(Address(ESP, mem + stack_offset), reg);
3755 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
3756}
3757
Mark Mendell7c8d0092015-01-26 11:21:33 -05003758void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
3759 ScratchRegisterScope ensure_scratch(
3760 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3761
3762 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3763 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3764 __ movl(temp_reg, Address(ESP, mem + stack_offset));
3765 __ movss(Address(ESP, mem + stack_offset), reg);
3766 __ movd(reg, temp_reg);
3767}
3768
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003769void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
3770 ScratchRegisterScope ensure_scratch1(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003771 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3772
3773 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003774 ScratchRegisterScope ensure_scratch2(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003775 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3776
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003777 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
3778 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
3779 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
3780 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
3781 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
3782 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
3783}
3784
3785void ParallelMoveResolverX86::EmitSwap(size_t index) {
3786 MoveOperands* move = moves_.Get(index);
3787 Location source = move->GetSource();
3788 Location destination = move->GetDestination();
3789
3790 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003791 __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003792 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003793 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003794 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003795 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003796 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3797 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003798 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
3799 // Use XOR Swap algorithm to avoid a temporary.
3800 DCHECK_NE(source.reg(), destination.reg());
3801 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3802 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3803 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3804 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
3805 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
3806 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
3807 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003808 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
3809 // Take advantage of the 16 bytes in the XMM register.
3810 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
3811 Address stack(ESP, destination.GetStackIndex());
3812 // Load the double into the high doubleword.
3813 __ movhpd(reg, stack);
3814
3815 // Store the low double into the destination.
3816 __ movsd(stack, reg);
3817
3818 // Move the high double to the low double.
3819 __ psrldq(reg, Immediate(8));
3820 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
3821 // Take advantage of the 16 bytes in the XMM register.
3822 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
3823 Address stack(ESP, source.GetStackIndex());
3824 // Load the double into the high doubleword.
3825 __ movhpd(reg, stack);
3826
3827 // Store the low double into the destination.
3828 __ movsd(stack, reg);
3829
3830 // Move the high double to the low double.
3831 __ psrldq(reg, Immediate(8));
3832 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
3833 Exchange(destination.GetStackIndex(), source.GetStackIndex());
3834 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003835 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003836 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003837 }
3838}
3839
3840void ParallelMoveResolverX86::SpillScratch(int reg) {
3841 __ pushl(static_cast<Register>(reg));
3842}
3843
3844void ParallelMoveResolverX86::RestoreScratch(int reg) {
3845 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003846}
3847
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003848void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003849 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3850 ? LocationSummary::kCallOnSlowPath
3851 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003852 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003853 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003854 locations->SetOut(Location::RequiresRegister());
3855}
3856
3857void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003858 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003859 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003860 DCHECK(!cls->CanCallRuntime());
3861 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003862 codegen_->LoadCurrentMethod(out);
3863 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3864 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003865 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003866 codegen_->LoadCurrentMethod(out);
3867 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3868 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003869
3870 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
3871 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3872 codegen_->AddSlowPath(slow_path);
3873 __ testl(out, out);
3874 __ j(kEqual, slow_path->GetEntryLabel());
3875 if (cls->MustGenerateClinitCheck()) {
3876 GenerateClassInitializationCheck(slow_path, out);
3877 } else {
3878 __ Bind(slow_path->GetExitLabel());
3879 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003880 }
3881}
3882
3883void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
3884 LocationSummary* locations =
3885 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3886 locations->SetInAt(0, Location::RequiresRegister());
3887 if (check->HasUses()) {
3888 locations->SetOut(Location::SameAsFirstInput());
3889 }
3890}
3891
3892void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003893 // We assume the class to not be null.
3894 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
3895 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003896 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003897 GenerateClassInitializationCheck(slow_path,
3898 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003899}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003900
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003901void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
3902 SlowPathCodeX86* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003903 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3904 Immediate(mirror::Class::kStatusInitialized));
3905 __ j(kLess, slow_path->GetEntryLabel());
3906 __ Bind(slow_path->GetExitLabel());
3907 // No need for memory fence, thanks to the X86 memory model.
3908}
3909
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003910void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
3911 LocationSummary* locations =
3912 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3913 locations->SetOut(Location::RequiresRegister());
3914}
3915
3916void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
3917 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
3918 codegen_->AddSlowPath(slow_path);
3919
Roland Levillain271ab9c2014-11-27 15:23:57 +00003920 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003921 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08003922 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3923 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003924 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3925 __ testl(out, out);
3926 __ j(kEqual, slow_path->GetEntryLabel());
3927 __ Bind(slow_path->GetExitLabel());
3928}
3929
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003930void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
3931 LocationSummary* locations =
3932 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3933 locations->SetOut(Location::RequiresRegister());
3934}
3935
3936void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
3937 Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003938 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003939 __ fs()->movl(address, Immediate(0));
3940}
3941
3942void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
3943 LocationSummary* locations =
3944 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3945 InvokeRuntimeCallingConvention calling_convention;
3946 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3947}
3948
3949void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
3950 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
3951 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3952}
3953
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003954void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003955 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3956 ? LocationSummary::kNoCall
3957 : LocationSummary::kCallOnSlowPath;
3958 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3959 locations->SetInAt(0, Location::RequiresRegister());
3960 locations->SetInAt(1, Location::Any());
3961 locations->SetOut(Location::RequiresRegister());
3962}
3963
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003964void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003965 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003966 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003967 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003968 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003969 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3970 Label done, zero;
3971 SlowPathCodeX86* slow_path = nullptr;
3972
3973 // Return 0 if `obj` is null.
3974 // TODO: avoid this check if we know obj is not null.
3975 __ testl(obj, obj);
3976 __ j(kEqual, &zero);
3977 __ movl(out, Address(obj, class_offset));
3978 // Compare the class of `obj` with `cls`.
3979 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003980 __ cmpl(out, cls.AsRegister<Register>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003981 } else {
3982 DCHECK(cls.IsStackSlot()) << cls;
3983 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
3984 }
3985
3986 if (instruction->IsClassFinal()) {
3987 // Classes must be equal for the instanceof to succeed.
3988 __ j(kNotEqual, &zero);
3989 __ movl(out, Immediate(1));
3990 __ jmp(&done);
3991 } else {
3992 // If the classes are not equal, we go into a slow path.
3993 DCHECK(locations->OnlyCallsOnSlowPath());
3994 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003995 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003996 codegen_->AddSlowPath(slow_path);
3997 __ j(kNotEqual, slow_path->GetEntryLabel());
3998 __ movl(out, Immediate(1));
3999 __ jmp(&done);
4000 }
4001 __ Bind(&zero);
4002 __ movl(out, Immediate(0));
4003 if (slow_path != nullptr) {
4004 __ Bind(slow_path->GetExitLabel());
4005 }
4006 __ Bind(&done);
4007}
4008
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004009void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
4010 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4011 instruction, LocationSummary::kCallOnSlowPath);
4012 locations->SetInAt(0, Location::RequiresRegister());
4013 locations->SetInAt(1, Location::Any());
4014 locations->AddTemp(Location::RequiresRegister());
4015}
4016
4017void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
4018 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004019 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004020 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004021 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004022 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4023 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
4024 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4025 codegen_->AddSlowPath(slow_path);
4026
4027 // TODO: avoid this check if we know obj is not null.
4028 __ testl(obj, obj);
4029 __ j(kEqual, slow_path->GetExitLabel());
4030 __ movl(temp, Address(obj, class_offset));
4031
4032 // Compare the class of `obj` with `cls`.
4033 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004034 __ cmpl(temp, cls.AsRegister<Register>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004035 } else {
4036 DCHECK(cls.IsStackSlot()) << cls;
4037 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
4038 }
4039
4040 __ j(kNotEqual, slow_path->GetEntryLabel());
4041 __ Bind(slow_path->GetExitLabel());
4042}
4043
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004044void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4045 LocationSummary* locations =
4046 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4047 InvokeRuntimeCallingConvention calling_convention;
4048 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4049}
4050
4051void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4052 __ fs()->call(Address::Absolute(instruction->IsEnter()
4053 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject)
4054 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject)));
4055 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4056}
4057
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004058void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4059void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4060void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4061
4062void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4063 LocationSummary* locations =
4064 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4065 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4066 || instruction->GetResultType() == Primitive::kPrimLong);
4067 locations->SetInAt(0, Location::RequiresRegister());
4068 locations->SetInAt(1, Location::Any());
4069 locations->SetOut(Location::SameAsFirstInput());
4070}
4071
4072void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
4073 HandleBitwiseOperation(instruction);
4074}
4075
4076void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
4077 HandleBitwiseOperation(instruction);
4078}
4079
4080void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
4081 HandleBitwiseOperation(instruction);
4082}
4083
4084void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4085 LocationSummary* locations = instruction->GetLocations();
4086 Location first = locations->InAt(0);
4087 Location second = locations->InAt(1);
4088 DCHECK(first.Equals(locations->Out()));
4089
4090 if (instruction->GetResultType() == Primitive::kPrimInt) {
4091 if (second.IsRegister()) {
4092 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004093 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004094 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004095 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004096 } else {
4097 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004098 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004099 }
4100 } else if (second.IsConstant()) {
4101 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004102 __ andl(first.AsRegister<Register>(),
4103 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004104 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004105 __ orl(first.AsRegister<Register>(),
4106 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004107 } else {
4108 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00004109 __ xorl(first.AsRegister<Register>(),
4110 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004111 }
4112 } else {
4113 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004114 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004115 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004116 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004117 } else {
4118 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004119 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004120 }
4121 }
4122 } else {
4123 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4124 if (second.IsRegisterPair()) {
4125 if (instruction->IsAnd()) {
4126 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4127 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4128 } else if (instruction->IsOr()) {
4129 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4130 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4131 } else {
4132 DCHECK(instruction->IsXor());
4133 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4134 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4135 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004136 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004137 if (instruction->IsAnd()) {
4138 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4139 __ andl(first.AsRegisterPairHigh<Register>(),
4140 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4141 } else if (instruction->IsOr()) {
4142 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4143 __ orl(first.AsRegisterPairHigh<Register>(),
4144 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4145 } else {
4146 DCHECK(instruction->IsXor());
4147 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4148 __ xorl(first.AsRegisterPairHigh<Register>(),
4149 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4150 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004151 } else {
4152 DCHECK(second.IsConstant()) << second;
4153 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004154 int32_t low_value = Low32Bits(value);
4155 int32_t high_value = High32Bits(value);
4156 Immediate low(low_value);
4157 Immediate high(high_value);
4158 Register first_low = first.AsRegisterPairLow<Register>();
4159 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004160 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004161 if (low_value == 0) {
4162 __ xorl(first_low, first_low);
4163 } else if (low_value != -1) {
4164 __ andl(first_low, low);
4165 }
4166 if (high_value == 0) {
4167 __ xorl(first_high, first_high);
4168 } else if (high_value != -1) {
4169 __ andl(first_high, high);
4170 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004171 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004172 if (low_value != 0) {
4173 __ orl(first_low, low);
4174 }
4175 if (high_value != 0) {
4176 __ orl(first_high, high);
4177 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004178 } else {
4179 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004180 if (low_value != 0) {
4181 __ xorl(first_low, low);
4182 }
4183 if (high_value != 0) {
4184 __ xorl(first_high, high);
4185 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004186 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004187 }
4188 }
4189}
4190
Calin Juravleb1498f62015-02-16 13:13:29 +00004191void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
4192 // Nothing to do, this should be removed during prepare for register allocator.
4193 UNUSED(instruction);
4194 LOG(FATAL) << "Unreachable";
4195}
4196
4197void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
4198 // Nothing to do, this should be removed during prepare for register allocator.
4199 UNUSED(instruction);
4200 LOG(FATAL) << "Unreachable";
4201}
4202
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004203} // namespace x86
4204} // namespace art