blob: 063550be92b6569fc5968aa82b5d4e879a6ca0d1 [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 Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070021#include "mirror/array-inl.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010022#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010023#include "mirror/class.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010024#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000025#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010026#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000027#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010028#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000030namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010031
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032namespace x86 {
33
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010034static constexpr int kCurrentMethodStackOffset = 0;
35
Calin Juravled6fb6cf2014-11-11 19:07:44 +000036static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX, EBX };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010037static constexpr size_t kRuntimeParameterCoreRegistersLength =
38 arraysize(kRuntimeParameterCoreRegisters);
Mark P Mendell966c3ae2015-01-27 15:45:27 +000039static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 };
40static constexpr size_t kRuntimeParameterFpuRegistersLength =
41 arraysize(kRuntimeParameterFpuRegisters);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010042
Mark Mendell24f2dfa2015-01-14 19:51:45 -050043static constexpr int kC2ConditionMask = 0x400;
44
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +000045// Marker for places that can be updated once we don't follow the quick ABI.
46static constexpr bool kFollowsQuickABI = true;
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000047static constexpr int kFakeReturnRegister = Register(8);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +000048
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010049class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010050 public:
51 InvokeRuntimeCallingConvention()
52 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010053 kRuntimeParameterCoreRegistersLength,
54 kRuntimeParameterFpuRegisters,
55 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010056
57 private:
58 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
59};
60
Nicolas Geoffraye5038322014-07-04 09:41:32 +010061#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
62
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010063class SlowPathCodeX86 : public SlowPathCode {
64 public:
65 SlowPathCodeX86() : entry_label_(), exit_label_() {}
66
67 Label* GetEntryLabel() { return &entry_label_; }
68 Label* GetExitLabel() { return &exit_label_; }
69
70 private:
71 Label entry_label_;
72 Label exit_label_;
73
74 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86);
75};
76
77class NullCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010078 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010079 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010080
81 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
82 __ Bind(GetEntryLabel());
83 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
Nicolas Geoffray39468442014-09-02 15:17:15 +010084 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010085 }
86
87 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010088 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010089 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
90};
91
Calin Juravled0d48522014-11-04 16:40:20 +000092class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
93 public:
94 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
95
96 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
97 __ Bind(GetEntryLabel());
98 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
99 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
100 }
101
102 private:
103 HDivZeroCheck* const instruction_;
104 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
105};
106
Calin Juravlebacfec32014-11-14 15:54:36 +0000107class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 {
Calin Juravled0d48522014-11-04 16:40:20 +0000108 public:
Calin Juravlebacfec32014-11-14 15:54:36 +0000109 explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +0000110
111 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
112 __ Bind(GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +0000113 if (is_div_) {
114 __ negl(reg_);
115 } else {
116 __ movl(reg_, Immediate(0));
117 }
Calin Juravled0d48522014-11-04 16:40:20 +0000118 __ jmp(GetExitLabel());
119 }
120
121 private:
122 Register reg_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000123 bool is_div_;
124 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
Calin Juravled0d48522014-11-04 16:40:20 +0000125};
126
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100127class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100128 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100129 BoundsCheckSlowPathX86(HBoundsCheck* instruction,
130 Location index_location,
131 Location length_location)
Roland Levillain199f3362014-11-27 17:15:16 +0000132 : instruction_(instruction),
133 index_location_(index_location),
134 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100135
136 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100137 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100138 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000139 // We're moving two locations to locations that could overlap, so we need a parallel
140 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100141 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000142 x86_codegen->EmitParallelMoves(
143 index_location_,
144 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
145 length_location_,
146 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100147 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100148 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100149 }
150
151 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100152 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100153 const Location index_location_;
154 const Location length_location_;
155
156 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
157};
158
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100159class SuspendCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000160 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100161 explicit SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
162 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000163
164 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100165 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000166 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100167 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000168 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
169 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100170 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100171 if (successor_ == nullptr) {
172 __ jmp(GetReturnLabel());
173 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100174 __ jmp(x86_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100175 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000176 }
177
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100178 Label* GetReturnLabel() {
179 DCHECK(successor_ == nullptr);
180 return &return_label_;
181 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000182
183 private:
184 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100185 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000186 Label return_label_;
187
188 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
189};
190
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000191class LoadStringSlowPathX86 : public SlowPathCodeX86 {
192 public:
193 explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {}
194
195 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
196 LocationSummary* locations = instruction_->GetLocations();
197 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
198
199 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
200 __ Bind(GetEntryLabel());
201 codegen->SaveLiveRegisters(locations);
202
203 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800204 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
205 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000206 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString)));
207 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
208 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
209 codegen->RestoreLiveRegisters(locations);
210
211 __ jmp(GetExitLabel());
212 }
213
214 private:
215 HLoadString* const instruction_;
216
217 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
218};
219
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000220class LoadClassSlowPathX86 : public SlowPathCodeX86 {
221 public:
222 LoadClassSlowPathX86(HLoadClass* cls,
223 HInstruction* at,
224 uint32_t dex_pc,
225 bool do_clinit)
226 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
227 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
228 }
229
230 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
231 LocationSummary* locations = at_->GetLocations();
232 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
233 __ Bind(GetEntryLabel());
234 codegen->SaveLiveRegisters(locations);
235
236 InvokeRuntimeCallingConvention calling_convention;
237 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
238 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
239 __ fs()->call(Address::Absolute(do_clinit_
240 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage)
241 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType)));
242 codegen->RecordPcInfo(at_, dex_pc_);
243
244 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000245 Location out = locations->Out();
246 if (out.IsValid()) {
247 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
248 x86_codegen->Move32(out, Location::RegisterLocation(EAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000249 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000250
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000251 codegen->RestoreLiveRegisters(locations);
252 __ jmp(GetExitLabel());
253 }
254
255 private:
256 // The class this slow path will load.
257 HLoadClass* const cls_;
258
259 // The instruction where this slow path is happening.
260 // (Might be the load class or an initialization check).
261 HInstruction* const at_;
262
263 // The dex PC of `at_`.
264 const uint32_t dex_pc_;
265
266 // Whether to initialize the class.
267 const bool do_clinit_;
268
269 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
270};
271
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000272class TypeCheckSlowPathX86 : public SlowPathCodeX86 {
273 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000274 TypeCheckSlowPathX86(HInstruction* instruction,
275 Location class_to_check,
276 Location object_class,
277 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000278 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000279 class_to_check_(class_to_check),
280 object_class_(object_class),
281 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000282
283 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
284 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000285 DCHECK(instruction_->IsCheckCast()
286 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000287
288 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
289 __ Bind(GetEntryLabel());
290 codegen->SaveLiveRegisters(locations);
291
292 // We're moving two locations to locations that could overlap, so we need a parallel
293 // move resolver.
294 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000295 x86_codegen->EmitParallelMoves(
296 class_to_check_,
297 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
298 object_class_,
299 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000300
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000301 if (instruction_->IsInstanceOf()) {
Roland Levillain199f3362014-11-27 17:15:16 +0000302 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize,
303 pInstanceofNonTrivial)));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000304 } else {
305 DCHECK(instruction_->IsCheckCast());
306 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast)));
307 }
308
309 codegen->RecordPcInfo(instruction_, dex_pc_);
310 if (instruction_->IsInstanceOf()) {
311 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
312 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000313 codegen->RestoreLiveRegisters(locations);
314
315 __ jmp(GetExitLabel());
316 }
317
318 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000319 HInstruction* const instruction_;
320 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000321 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000322 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000323
324 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
325};
326
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100327#undef __
328#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
329
Dave Allison20dfc792014-06-16 20:44:29 -0700330inline Condition X86Condition(IfCondition cond) {
331 switch (cond) {
332 case kCondEQ: return kEqual;
333 case kCondNE: return kNotEqual;
334 case kCondLT: return kLess;
335 case kCondLE: return kLessEqual;
336 case kCondGT: return kGreater;
337 case kCondGE: return kGreaterEqual;
338 default:
339 LOG(FATAL) << "Unknown if condition";
340 }
341 return kEqual;
342}
343
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100344void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
345 stream << X86ManagedRegister::FromCpuRegister(Register(reg));
346}
347
348void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
349 stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
350}
351
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100352size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
353 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
354 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100355}
356
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100357size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
358 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
359 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100360}
361
Mark Mendell7c8d0092015-01-26 11:21:33 -0500362size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
363 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
364 return GetFloatingPointSpillSlotSize();
365}
366
367size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
368 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
369 return GetFloatingPointSpillSlotSize();
370}
371
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000372CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options)
373 : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfXmmRegisters,
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000374 kNumberOfRegisterPairs, (1 << kFakeReturnRegister), 0, compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100375 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100376 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100377 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000378 move_resolver_(graph->GetArena(), this) {
379 // Use a fake return address register to mimic Quick.
380 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100381}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100382
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100383Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100384 switch (type) {
385 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100386 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100387 X86ManagedRegister pair =
388 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100389 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
390 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100391 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
392 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100393 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100394 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100395 }
396
397 case Primitive::kPrimByte:
398 case Primitive::kPrimBoolean:
399 case Primitive::kPrimChar:
400 case Primitive::kPrimShort:
401 case Primitive::kPrimInt:
402 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100403 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100404 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100405 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100406 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
407 X86ManagedRegister current =
408 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
409 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100410 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100411 }
412 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100413 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100414 }
415
416 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100417 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100418 return Location::FpuRegisterLocation(
419 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100420 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100421
422 case Primitive::kPrimVoid:
423 LOG(FATAL) << "Unreachable type " << type;
424 }
425
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100426 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100427}
428
Nicolas Geoffray98893962015-01-21 12:32:32 +0000429void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline ATTRIBUTE_UNUSED) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100430 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100431 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100432
433 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100434 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100435
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000436 // TODO: We currently don't use Quick's callee saved registers.
437 DCHECK(kFollowsQuickABI);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100438 blocked_core_registers_[EBP] = true;
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000439 blocked_core_registers_[ESI] = true;
440 blocked_core_registers_[EDI] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100441
442 UpdateBlockedPairRegisters();
443}
444
445void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
446 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
447 X86ManagedRegister current =
448 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
449 if (blocked_core_registers_[current.AsRegisterPairLow()]
450 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
451 blocked_register_pairs_[i] = true;
452 }
453 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100454}
455
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100456InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
457 : HGraphVisitor(graph),
458 assembler_(codegen->GetAssembler()),
459 codegen_(codegen) {}
460
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000461void CodeGeneratorX86::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000462 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000463 bool skip_overflow_check =
464 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000465 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000466
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000467 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100468 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100469 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100470 }
471
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000472 __ subl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100473 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000474}
475
476void CodeGeneratorX86::GenerateFrameExit() {
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000477 __ addl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize()));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000478}
479
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100480void CodeGeneratorX86::Bind(HBasicBlock* block) {
481 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000482}
483
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100484void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
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 if (index + 1 == calling_convention.GetNumberOfRegisters()) {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000538 // stack_index_ is the right offset for the memory.
539 return Location::QuickParameter(index, stack_index_ - 2);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100540 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000541 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
542 }
543 }
544
545 case Primitive::kPrimFloat: {
546 uint32_t index = fp_index_++;
547 stack_index_++;
548 if (index < calling_convention.GetNumberOfFpuRegisters()) {
549 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
550 } else {
551 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
552 }
553 }
554
555 case Primitive::kPrimDouble: {
556 uint32_t index = fp_index_++;
557 stack_index_ += 2;
558 if (index < calling_convention.GetNumberOfFpuRegisters()) {
559 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
560 } else {
561 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100562 }
563 }
564
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100565 case Primitive::kPrimVoid:
566 LOG(FATAL) << "Unexpected parameter type " << type;
567 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100568 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100569 return Location();
570}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100571
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100572void CodeGeneratorX86::Move32(Location destination, Location source) {
573 if (source.Equals(destination)) {
574 return;
575 }
576 if (destination.IsRegister()) {
577 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000578 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100579 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000580 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100581 } else {
582 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000583 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100584 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100585 } else if (destination.IsFpuRegister()) {
586 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000587 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100588 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000589 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100590 } else {
591 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000592 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100593 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100594 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000595 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100596 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000597 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100598 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000599 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500600 } else if (source.IsConstant()) {
601 HConstant* constant = source.GetConstant();
602 int32_t value;
603 if (constant->IsIntConstant()) {
604 value = constant->AsIntConstant()->GetValue();
605 } else {
606 DCHECK(constant->IsFloatConstant());
607 value = bit_cast<float, int32_t>(constant->AsFloatConstant()->GetValue());
608 }
609 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100610 } else {
611 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100612 __ pushl(Address(ESP, source.GetStackIndex()));
613 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100614 }
615 }
616}
617
618void CodeGeneratorX86::Move64(Location destination, Location source) {
619 if (source.Equals(destination)) {
620 return;
621 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100622 if (destination.IsRegisterPair()) {
623 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000624 EmitParallelMoves(
625 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
626 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
627 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
628 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100629 } else if (source.IsFpuRegister()) {
630 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100631 } else if (source.IsQuickParameter()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000632 uint16_t register_index = source.GetQuickParameterRegisterIndex();
633 uint16_t stack_index = source.GetQuickParameterStackIndex();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100634 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000635 EmitParallelMoves(
636 Location::RegisterLocation(calling_convention.GetRegisterAt(register_index)),
637 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()),
638 Location::StackSlot(
639 calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize()),
640 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100641 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000642 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100643 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100644 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
645 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100646 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
647 }
648 } else if (destination.IsQuickParameter()) {
649 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000650 uint16_t register_index = destination.GetQuickParameterRegisterIndex();
651 uint16_t stack_index = destination.GetQuickParameterStackIndex();
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000652 if (source.IsRegisterPair()) {
653 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100654 } else if (source.IsFpuRegister()) {
655 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100656 } else {
657 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000658 EmitParallelMoves(
659 Location::StackSlot(source.GetStackIndex()),
Nicolas Geoffray425f2392015-01-08 14:52:29 +0000660 Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index)),
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000661 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
662 Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index + 1)));
Nicolas Geoffray425f2392015-01-08 14:52:29 +0000663 __ movl(calling_convention.GetRegisterAt(register_index), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100664 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100665 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500666 if (source.IsFpuRegister()) {
667 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
668 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000669 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100670 } else {
671 LOG(FATAL) << "Unimplemented";
672 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100673 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000674 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100675 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000676 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100677 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100678 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100679 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100680 } else if (source.IsQuickParameter()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000681 // No conflict possible, so just do the move.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100682 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000683 uint16_t register_index = source.GetQuickParameterRegisterIndex();
684 uint16_t stack_index = source.GetQuickParameterStackIndex();
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000685 // Just move the low part. The only time a source is a quick parameter is
686 // when moving the parameter to its stack locations. And the (Java) caller
687 // of this method has already done that.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100688 __ movl(Address(ESP, destination.GetStackIndex()),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000689 calling_convention.GetRegisterAt(register_index));
690 DCHECK_EQ(calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100691 static_cast<size_t>(destination.GetHighStackIndex(kX86WordSize)));
692 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000693 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100694 } else {
695 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000696 EmitParallelMoves(
697 Location::StackSlot(source.GetStackIndex()),
698 Location::StackSlot(destination.GetStackIndex()),
699 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
700 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100701 }
702 }
703}
704
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100705void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000706 LocationSummary* locations = instruction->GetLocations();
707 if (locations != nullptr && locations->Out().Equals(location)) {
708 return;
709 }
710
711 if (locations != nullptr && locations->Out().IsConstant()) {
712 HConstant* const_to_move = locations->Out().GetConstant();
713 if (const_to_move->IsIntConstant()) {
714 Immediate imm(const_to_move->AsIntConstant()->GetValue());
715 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000716 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000717 } else if (location.IsStackSlot()) {
718 __ movl(Address(ESP, location.GetStackIndex()), imm);
719 } else {
720 DCHECK(location.IsConstant());
721 DCHECK_EQ(location.GetConstant(), const_to_move);
722 }
723 } else if (const_to_move->IsLongConstant()) {
724 int64_t value = const_to_move->AsLongConstant()->GetValue();
725 if (location.IsRegisterPair()) {
726 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
727 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
728 } else if (location.IsDoubleStackSlot()) {
729 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000730 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
731 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000732 } else {
733 DCHECK(location.IsConstant());
734 DCHECK_EQ(location.GetConstant(), instruction);
735 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100736 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000737 } else if (instruction->IsTemporary()) {
738 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000739 if (temp_location.IsStackSlot()) {
740 Move32(location, temp_location);
741 } else {
742 DCHECK(temp_location.IsDoubleStackSlot());
743 Move64(location, temp_location);
744 }
Roland Levillain476df552014-10-09 17:51:36 +0100745 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100746 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100747 switch (instruction->GetType()) {
748 case Primitive::kPrimBoolean:
749 case Primitive::kPrimByte:
750 case Primitive::kPrimChar:
751 case Primitive::kPrimShort:
752 case Primitive::kPrimInt:
753 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100754 case Primitive::kPrimFloat:
755 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100756 break;
757
758 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100759 case Primitive::kPrimDouble:
760 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100761 break;
762
763 default:
764 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
765 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000766 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100767 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100768 switch (instruction->GetType()) {
769 case Primitive::kPrimBoolean:
770 case Primitive::kPrimByte:
771 case Primitive::kPrimChar:
772 case Primitive::kPrimShort:
773 case Primitive::kPrimInt:
774 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100775 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000776 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100777 break;
778
779 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100780 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000781 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100782 break;
783
784 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100785 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100786 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000787 }
788}
789
790void LocationsBuilderX86::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000791 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000792}
793
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000794void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000795 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100796 DCHECK(!successor->IsExitBlock());
797
798 HBasicBlock* block = got->GetBlock();
799 HInstruction* previous = got->GetPrevious();
800
801 HLoopInformation* info = block->GetLoopInformation();
802 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
803 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
804 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
805 return;
806 }
807
808 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
809 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
810 }
811 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000812 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000813 }
814}
815
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000816void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000817 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000818}
819
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000820void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700821 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000822 if (kIsDebugBuild) {
823 __ Comment("Unreachable");
824 __ int3();
825 }
826}
827
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000828void LocationsBuilderX86::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100829 LocationSummary* locations =
830 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100831 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100832 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100833 locations->SetInAt(0, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100834 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000835}
836
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000837void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700838 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100839 if (cond->IsIntConstant()) {
840 // Constant condition, statically compared against 1.
841 int32_t cond_value = cond->AsIntConstant()->GetValue();
842 if (cond_value == 1) {
843 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
844 if_instr->IfTrueSuccessor())) {
845 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100846 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100847 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100848 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100849 DCHECK_EQ(cond_value, 0);
850 }
851 } else {
852 bool materialized =
853 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
854 // Moves do not affect the eflags register, so if the condition is
855 // evaluated just before the if, we don't need to evaluate it
856 // again.
857 bool eflags_set = cond->IsCondition()
858 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
859 if (materialized) {
860 if (!eflags_set) {
861 // Materialized condition, compare against 0.
862 Location lhs = if_instr->GetLocations()->InAt(0);
863 if (lhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000864 __ cmpl(lhs.AsRegister<Register>(), Immediate(0));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100865 } else {
866 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
867 }
868 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
869 } else {
870 __ j(X86Condition(cond->AsCondition()->GetCondition()),
871 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
872 }
873 } else {
874 Location lhs = cond->GetLocations()->InAt(0);
875 Location rhs = cond->GetLocations()->InAt(1);
876 // LHS is guaranteed to be in a register (see
877 // LocationsBuilderX86::VisitCondition).
878 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000879 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100880 } else if (rhs.IsConstant()) {
881 HIntConstant* instruction = rhs.GetConstant()->AsIntConstant();
882 Immediate imm(instruction->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000883 __ cmpl(lhs.AsRegister<Register>(), imm);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100884 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000885 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100886 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100887 __ j(X86Condition(cond->AsCondition()->GetCondition()),
888 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700889 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100890 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100891 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
892 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700893 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000894 }
895}
896
897void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000898 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000899}
900
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000901void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
902 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000903}
904
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000905void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100906 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000907}
908
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000909void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100910 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700911 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000912}
913
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100914void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100915 LocationSummary* locations =
916 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100917 switch (store->InputAt(1)->GetType()) {
918 case Primitive::kPrimBoolean:
919 case Primitive::kPrimByte:
920 case Primitive::kPrimChar:
921 case Primitive::kPrimShort:
922 case Primitive::kPrimInt:
923 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100924 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100925 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
926 break;
927
928 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100929 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100930 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
931 break;
932
933 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100934 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100935 }
936 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000937}
938
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000939void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700940 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000941}
942
Dave Allison20dfc792014-06-16 20:44:29 -0700943void LocationsBuilderX86::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100944 LocationSummary* locations =
945 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100946 locations->SetInAt(0, Location::RequiresRegister());
947 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100948 if (comp->NeedsMaterialization()) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000949 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100950 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000951}
952
Dave Allison20dfc792014-06-16 20:44:29 -0700953void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
954 if (comp->NeedsMaterialization()) {
955 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000956 Register reg = locations->Out().AsRegister<Register>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100957 // Clear register: setcc only sets the low byte.
958 __ xorl(reg, reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700959 if (locations->InAt(1).IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000960 __ cmpl(locations->InAt(0).AsRegister<Register>(),
961 locations->InAt(1).AsRegister<Register>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100962 } else if (locations->InAt(1).IsConstant()) {
963 HConstant* instruction = locations->InAt(1).GetConstant();
964 Immediate imm(instruction->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000965 __ cmpl(locations->InAt(0).AsRegister<Register>(), imm);
Dave Allison20dfc792014-06-16 20:44:29 -0700966 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000967 __ cmpl(locations->InAt(0).AsRegister<Register>(),
Dave Allison20dfc792014-06-16 20:44:29 -0700968 Address(ESP, locations->InAt(1).GetStackIndex()));
969 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000970 __ setb(X86Condition(comp->GetCondition()), reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100971 }
Dave Allison20dfc792014-06-16 20:44:29 -0700972}
973
974void LocationsBuilderX86::VisitEqual(HEqual* comp) {
975 VisitCondition(comp);
976}
977
978void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
979 VisitCondition(comp);
980}
981
982void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
983 VisitCondition(comp);
984}
985
986void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
987 VisitCondition(comp);
988}
989
990void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
991 VisitCondition(comp);
992}
993
994void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
995 VisitCondition(comp);
996}
997
998void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
999 VisitCondition(comp);
1000}
1001
1002void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
1003 VisitCondition(comp);
1004}
1005
1006void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
1007 VisitCondition(comp);
1008}
1009
1010void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
1011 VisitCondition(comp);
1012}
1013
1014void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1015 VisitCondition(comp);
1016}
1017
1018void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1019 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001020}
1021
1022void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001023 LocationSummary* locations =
1024 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001025 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001026}
1027
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001028void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001029 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001030 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001031}
1032
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001033void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001034 LocationSummary* locations =
1035 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001036 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001037}
1038
1039void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1040 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001041 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001042}
1043
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001044void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1045 LocationSummary* locations =
1046 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1047 locations->SetOut(Location::ConstantLocation(constant));
1048}
1049
1050void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1051 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001052 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001053}
1054
1055void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1056 LocationSummary* locations =
1057 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1058 locations->SetOut(Location::ConstantLocation(constant));
1059}
1060
1061void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1062 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001063 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001064}
1065
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001066void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001067 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001068}
1069
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001070void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001071 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001072 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001073 __ ret();
1074}
1075
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001076void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001077 LocationSummary* locations =
1078 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001079 switch (ret->InputAt(0)->GetType()) {
1080 case Primitive::kPrimBoolean:
1081 case Primitive::kPrimByte:
1082 case Primitive::kPrimChar:
1083 case Primitive::kPrimShort:
1084 case Primitive::kPrimInt:
1085 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001086 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001087 break;
1088
1089 case Primitive::kPrimLong:
1090 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001091 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001092 break;
1093
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001094 case Primitive::kPrimFloat:
1095 case Primitive::kPrimDouble:
1096 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001097 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001098 break;
1099
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001100 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001101 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001102 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001103}
1104
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001105void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001106 if (kIsDebugBuild) {
1107 switch (ret->InputAt(0)->GetType()) {
1108 case Primitive::kPrimBoolean:
1109 case Primitive::kPrimByte:
1110 case Primitive::kPrimChar:
1111 case Primitive::kPrimShort:
1112 case Primitive::kPrimInt:
1113 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001114 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001115 break;
1116
1117 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001118 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1119 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001120 break;
1121
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001122 case Primitive::kPrimFloat:
1123 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001124 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001125 break;
1126
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001127 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001128 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001129 }
1130 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001131 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001132 __ ret();
1133}
1134
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001135void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001136 HandleInvoke(invoke);
1137}
1138
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001139void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001140 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001141
1142 // TODO: Implement all kinds of calls:
1143 // 1) boot -> boot
1144 // 2) app -> boot
1145 // 3) app -> app
1146 //
1147 // Currently we implement the app -> app logic, which looks up in the resolve cache.
1148
1149 // temp = method;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001150 codegen_->LoadCurrentMethod(temp);
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001151 if (!invoke->IsRecursive()) {
1152 // temp = temp->dex_cache_resolved_methods_;
1153 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
1154 // temp = temp[index_in_cache]
1155 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
1156 // (temp + offset_of_quick_compiled_code)()
1157 __ call(Address(
1158 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
1159 } else {
1160 __ call(codegen_->GetFrameEntryLabel());
1161 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001162
1163 DCHECK(!codegen_->IsLeafMethod());
1164 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1165}
1166
1167void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1168 HandleInvoke(invoke);
1169}
1170
1171void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001172 LocationSummary* locations =
1173 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001174 locations->AddTemp(Location::RegisterLocation(EAX));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001175
1176 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001177 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001178 HInstruction* input = invoke->InputAt(i);
1179 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1180 }
1181
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001182 switch (invoke->GetType()) {
1183 case Primitive::kPrimBoolean:
1184 case Primitive::kPrimByte:
1185 case Primitive::kPrimChar:
1186 case Primitive::kPrimShort:
1187 case Primitive::kPrimInt:
1188 case Primitive::kPrimNot:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001189 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001190 break;
1191
1192 case Primitive::kPrimLong:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001193 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001194 break;
1195
1196 case Primitive::kPrimVoid:
1197 break;
1198
1199 case Primitive::kPrimDouble:
1200 case Primitive::kPrimFloat:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001201 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001202 break;
1203 }
1204
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001205 invoke->SetLocations(locations);
1206}
1207
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001208void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001209 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001210 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1211 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1212 LocationSummary* locations = invoke->GetLocations();
1213 Location receiver = locations->InAt(0);
1214 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1215 // temp = object->GetClass();
1216 if (receiver.IsStackSlot()) {
1217 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1218 __ movl(temp, Address(temp, class_offset));
1219 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001220 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001221 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001222 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001223 // temp = temp->GetMethodAt(method_offset);
1224 __ movl(temp, Address(temp, method_offset));
1225 // call temp->GetEntryPoint();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001226 __ call(Address(
1227 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001228
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001229 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001230 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001231}
1232
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001233void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1234 HandleInvoke(invoke);
1235 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001236 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001237}
1238
1239void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1240 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001241 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001242 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1243 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1244 LocationSummary* locations = invoke->GetLocations();
1245 Location receiver = locations->InAt(0);
1246 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1247
1248 // Set the hidden argument.
1249 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001250 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001251
1252 // temp = object->GetClass();
1253 if (receiver.IsStackSlot()) {
1254 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1255 __ movl(temp, Address(temp, class_offset));
1256 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001257 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001258 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001259 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001260 // temp = temp->GetImtEntryAt(method_offset);
1261 __ movl(temp, Address(temp, method_offset));
1262 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001263 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001264 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001265
1266 DCHECK(!codegen_->IsLeafMethod());
1267 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1268}
1269
Roland Levillain88cb1752014-10-20 16:36:47 +01001270void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1271 LocationSummary* locations =
1272 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1273 switch (neg->GetResultType()) {
1274 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001275 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001276 locations->SetInAt(0, Location::RequiresRegister());
1277 locations->SetOut(Location::SameAsFirstInput());
1278 break;
1279
Roland Levillain88cb1752014-10-20 16:36:47 +01001280 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001281 locations->SetInAt(0, Location::RequiresFpuRegister());
1282 locations->SetOut(Location::SameAsFirstInput());
1283 locations->AddTemp(Location::RequiresRegister());
1284 locations->AddTemp(Location::RequiresFpuRegister());
1285 break;
1286
Roland Levillain88cb1752014-10-20 16:36:47 +01001287 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001288 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001289 locations->SetOut(Location::SameAsFirstInput());
1290 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001291 break;
1292
1293 default:
1294 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1295 }
1296}
1297
1298void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1299 LocationSummary* locations = neg->GetLocations();
1300 Location out = locations->Out();
1301 Location in = locations->InAt(0);
1302 switch (neg->GetResultType()) {
1303 case Primitive::kPrimInt:
1304 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001305 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001306 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001307 break;
1308
1309 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001310 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001311 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001312 __ negl(out.AsRegisterPairLow<Register>());
1313 // Negation is similar to subtraction from zero. The least
1314 // significant byte triggers a borrow when it is different from
1315 // zero; to take it into account, add 1 to the most significant
1316 // byte if the carry flag (CF) is set to 1 after the first NEGL
1317 // operation.
1318 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1319 __ negl(out.AsRegisterPairHigh<Register>());
1320 break;
1321
Roland Levillain5368c212014-11-27 15:03:41 +00001322 case Primitive::kPrimFloat: {
1323 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001324 Register constant = locations->GetTemp(0).AsRegister<Register>();
1325 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001326 // Implement float negation with an exclusive or with value
1327 // 0x80000000 (mask for bit 31, representing the sign of a
1328 // single-precision floating-point number).
1329 __ movl(constant, Immediate(INT32_C(0x80000000)));
1330 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001331 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001332 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001333 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001334
Roland Levillain5368c212014-11-27 15:03:41 +00001335 case Primitive::kPrimDouble: {
1336 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001337 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001338 // Implement double negation with an exclusive or with value
1339 // 0x8000000000000000 (mask for bit 63, representing the sign of
1340 // a double-precision floating-point number).
1341 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001342 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001343 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001344 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001345
1346 default:
1347 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1348 }
1349}
1350
Roland Levillaindff1f282014-11-05 14:15:05 +00001351void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001352 Primitive::Type result_type = conversion->GetResultType();
1353 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001354 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001355
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001356 // The float-to-long and double-to-long type conversions rely on a
1357 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001358 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001359 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1360 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001361 ? LocationSummary::kCall
1362 : LocationSummary::kNoCall;
1363 LocationSummary* locations =
1364 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1365
Roland Levillaindff1f282014-11-05 14:15:05 +00001366 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001367 case Primitive::kPrimByte:
1368 switch (input_type) {
1369 case Primitive::kPrimShort:
1370 case Primitive::kPrimInt:
1371 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001372 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001373 locations->SetInAt(0, Location::Any());
Roland Levillain51d3fc42014-11-13 14:11:42 +00001374 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1375 break;
1376
1377 default:
1378 LOG(FATAL) << "Unexpected type conversion from " << input_type
1379 << " to " << result_type;
1380 }
1381 break;
1382
Roland Levillain01a8d712014-11-14 16:27:39 +00001383 case Primitive::kPrimShort:
1384 switch (input_type) {
1385 case Primitive::kPrimByte:
1386 case Primitive::kPrimInt:
1387 case Primitive::kPrimChar:
1388 // Processing a Dex `int-to-short' instruction.
1389 locations->SetInAt(0, Location::Any());
1390 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1391 break;
1392
1393 default:
1394 LOG(FATAL) << "Unexpected type conversion from " << input_type
1395 << " to " << result_type;
1396 }
1397 break;
1398
Roland Levillain946e1432014-11-11 17:35:19 +00001399 case Primitive::kPrimInt:
1400 switch (input_type) {
1401 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001402 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001403 locations->SetInAt(0, Location::Any());
1404 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1405 break;
1406
1407 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001408 // Processing a Dex `float-to-int' instruction.
1409 locations->SetInAt(0, Location::RequiresFpuRegister());
1410 locations->SetOut(Location::RequiresRegister());
1411 locations->AddTemp(Location::RequiresFpuRegister());
1412 break;
1413
Roland Levillain946e1432014-11-11 17:35:19 +00001414 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001415 // Processing a Dex `double-to-int' instruction.
1416 locations->SetInAt(0, Location::RequiresFpuRegister());
1417 locations->SetOut(Location::RequiresRegister());
1418 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001419 break;
1420
1421 default:
1422 LOG(FATAL) << "Unexpected type conversion from " << input_type
1423 << " to " << result_type;
1424 }
1425 break;
1426
Roland Levillaindff1f282014-11-05 14:15:05 +00001427 case Primitive::kPrimLong:
1428 switch (input_type) {
1429 case Primitive::kPrimByte:
1430 case Primitive::kPrimShort:
1431 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001432 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001433 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001434 locations->SetInAt(0, Location::RegisterLocation(EAX));
1435 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1436 break;
1437
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001438 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001439 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001440 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001441 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001442 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1443 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1444
Vladimir Marko949c91f2015-01-27 10:48:44 +00001445 // The runtime helper puts the result in EAX, EDX.
1446 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001447 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001448 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001449
1450 default:
1451 LOG(FATAL) << "Unexpected type conversion from " << input_type
1452 << " to " << result_type;
1453 }
1454 break;
1455
Roland Levillain981e4542014-11-14 11:47:14 +00001456 case Primitive::kPrimChar:
1457 switch (input_type) {
1458 case Primitive::kPrimByte:
1459 case Primitive::kPrimShort:
1460 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001461 // Processing a Dex `int-to-char' instruction.
1462 locations->SetInAt(0, Location::Any());
1463 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1464 break;
1465
1466 default:
1467 LOG(FATAL) << "Unexpected type conversion from " << input_type
1468 << " to " << result_type;
1469 }
1470 break;
1471
Roland Levillaindff1f282014-11-05 14:15:05 +00001472 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001473 switch (input_type) {
1474 case Primitive::kPrimByte:
1475 case Primitive::kPrimShort:
1476 case Primitive::kPrimInt:
1477 case Primitive::kPrimChar:
1478 // Processing a Dex `int-to-float' instruction.
1479 locations->SetInAt(0, Location::RequiresRegister());
1480 locations->SetOut(Location::RequiresFpuRegister());
1481 break;
1482
1483 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001484 // Processing a Dex `long-to-float' instruction.
1485 locations->SetInAt(0, Location::RequiresRegister());
1486 locations->SetOut(Location::RequiresFpuRegister());
1487 locations->AddTemp(Location::RequiresFpuRegister());
1488 locations->AddTemp(Location::RequiresFpuRegister());
1489 break;
1490
Roland Levillaincff13742014-11-17 14:32:17 +00001491 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001492 // Processing a Dex `double-to-float' instruction.
1493 locations->SetInAt(0, Location::RequiresFpuRegister());
1494 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001495 break;
1496
1497 default:
1498 LOG(FATAL) << "Unexpected type conversion from " << input_type
1499 << " to " << result_type;
1500 };
1501 break;
1502
Roland Levillaindff1f282014-11-05 14:15:05 +00001503 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001504 switch (input_type) {
1505 case Primitive::kPrimByte:
1506 case Primitive::kPrimShort:
1507 case Primitive::kPrimInt:
1508 case Primitive::kPrimChar:
1509 // Processing a Dex `int-to-double' instruction.
1510 locations->SetInAt(0, Location::RequiresRegister());
1511 locations->SetOut(Location::RequiresFpuRegister());
1512 break;
1513
1514 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001515 // Processing a Dex `long-to-double' instruction.
1516 locations->SetInAt(0, Location::RequiresRegister());
1517 locations->SetOut(Location::RequiresFpuRegister());
1518 locations->AddTemp(Location::RequiresFpuRegister());
1519 locations->AddTemp(Location::RequiresFpuRegister());
1520 break;
1521
Roland Levillaincff13742014-11-17 14:32:17 +00001522 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001523 // Processing a Dex `float-to-double' instruction.
1524 locations->SetInAt(0, Location::RequiresFpuRegister());
1525 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001526 break;
1527
1528 default:
1529 LOG(FATAL) << "Unexpected type conversion from " << input_type
1530 << " to " << result_type;
1531 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001532 break;
1533
1534 default:
1535 LOG(FATAL) << "Unexpected type conversion from " << input_type
1536 << " to " << result_type;
1537 }
1538}
1539
1540void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
1541 LocationSummary* locations = conversion->GetLocations();
1542 Location out = locations->Out();
1543 Location in = locations->InAt(0);
1544 Primitive::Type result_type = conversion->GetResultType();
1545 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001546 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001547 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001548 case Primitive::kPrimByte:
1549 switch (input_type) {
1550 case Primitive::kPrimShort:
1551 case Primitive::kPrimInt:
1552 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001553 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001554 if (in.IsRegister()) {
1555 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
1556 } else if (in.IsStackSlot()) {
1557 __ movsxb(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
1558 } else {
1559 DCHECK(in.GetConstant()->IsIntConstant());
1560 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1561 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
1562 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00001563 break;
1564
1565 default:
1566 LOG(FATAL) << "Unexpected type conversion from " << input_type
1567 << " to " << result_type;
1568 }
1569 break;
1570
Roland Levillain01a8d712014-11-14 16:27:39 +00001571 case Primitive::kPrimShort:
1572 switch (input_type) {
1573 case Primitive::kPrimByte:
1574 case Primitive::kPrimInt:
1575 case Primitive::kPrimChar:
1576 // Processing a Dex `int-to-short' instruction.
1577 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001578 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001579 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001580 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00001581 } else {
1582 DCHECK(in.GetConstant()->IsIntConstant());
1583 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001584 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00001585 }
1586 break;
1587
1588 default:
1589 LOG(FATAL) << "Unexpected type conversion from " << input_type
1590 << " to " << result_type;
1591 }
1592 break;
1593
Roland Levillain946e1432014-11-11 17:35:19 +00001594 case Primitive::kPrimInt:
1595 switch (input_type) {
1596 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001597 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001598 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001599 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001600 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001601 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00001602 } else {
1603 DCHECK(in.IsConstant());
1604 DCHECK(in.GetConstant()->IsLongConstant());
1605 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001606 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001607 }
1608 break;
1609
Roland Levillain3f8f9362014-12-02 17:45:01 +00001610 case Primitive::kPrimFloat: {
1611 // Processing a Dex `float-to-int' instruction.
1612 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1613 Register output = out.AsRegister<Register>();
1614 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1615 Label done, nan;
1616
1617 __ movl(output, Immediate(kPrimIntMax));
1618 // temp = int-to-float(output)
1619 __ cvtsi2ss(temp, output);
1620 // if input >= temp goto done
1621 __ comiss(input, temp);
1622 __ j(kAboveEqual, &done);
1623 // if input == NaN goto nan
1624 __ j(kUnordered, &nan);
1625 // output = float-to-int-truncate(input)
1626 __ cvttss2si(output, input);
1627 __ jmp(&done);
1628 __ Bind(&nan);
1629 // output = 0
1630 __ xorl(output, output);
1631 __ Bind(&done);
1632 break;
1633 }
1634
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001635 case Primitive::kPrimDouble: {
1636 // Processing a Dex `double-to-int' instruction.
1637 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1638 Register output = out.AsRegister<Register>();
1639 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1640 Label done, nan;
1641
1642 __ movl(output, Immediate(kPrimIntMax));
1643 // temp = int-to-double(output)
1644 __ cvtsi2sd(temp, output);
1645 // if input >= temp goto done
1646 __ comisd(input, temp);
1647 __ j(kAboveEqual, &done);
1648 // if input == NaN goto nan
1649 __ j(kUnordered, &nan);
1650 // output = double-to-int-truncate(input)
1651 __ cvttsd2si(output, input);
1652 __ jmp(&done);
1653 __ Bind(&nan);
1654 // output = 0
1655 __ xorl(output, output);
1656 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001657 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001658 }
Roland Levillain946e1432014-11-11 17:35:19 +00001659
1660 default:
1661 LOG(FATAL) << "Unexpected type conversion from " << input_type
1662 << " to " << result_type;
1663 }
1664 break;
1665
Roland Levillaindff1f282014-11-05 14:15:05 +00001666 case Primitive::kPrimLong:
1667 switch (input_type) {
1668 case Primitive::kPrimByte:
1669 case Primitive::kPrimShort:
1670 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001671 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001672 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001673 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
1674 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001675 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00001676 __ cdq();
1677 break;
1678
1679 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001680 // Processing a Dex `float-to-long' instruction.
1681 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l)));
Roland Levillain624279f2014-12-04 11:54:28 +00001682 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
1683 break;
1684
Roland Levillaindff1f282014-11-05 14:15:05 +00001685 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001686 // Processing a Dex `double-to-long' instruction.
1687 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l)));
1688 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
Roland Levillaindff1f282014-11-05 14:15:05 +00001689 break;
1690
1691 default:
1692 LOG(FATAL) << "Unexpected type conversion from " << input_type
1693 << " to " << result_type;
1694 }
1695 break;
1696
Roland Levillain981e4542014-11-14 11:47:14 +00001697 case Primitive::kPrimChar:
1698 switch (input_type) {
1699 case Primitive::kPrimByte:
1700 case Primitive::kPrimShort:
1701 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001702 // Processing a Dex `Process a Dex `int-to-char'' instruction.
1703 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001704 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00001705 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001706 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00001707 } else {
1708 DCHECK(in.GetConstant()->IsIntConstant());
1709 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001710 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00001711 }
1712 break;
1713
1714 default:
1715 LOG(FATAL) << "Unexpected type conversion from " << input_type
1716 << " to " << result_type;
1717 }
1718 break;
1719
Roland Levillaindff1f282014-11-05 14:15:05 +00001720 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001721 switch (input_type) {
Roland Levillaincff13742014-11-17 14:32:17 +00001722 case Primitive::kPrimByte:
1723 case Primitive::kPrimShort:
1724 case Primitive::kPrimInt:
1725 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001726 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001727 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001728 break;
1729
Roland Levillain6d0e4832014-11-27 18:31:21 +00001730 case Primitive::kPrimLong: {
1731 // Processing a Dex `long-to-float' instruction.
1732 Register low = in.AsRegisterPairLow<Register>();
1733 Register high = in.AsRegisterPairHigh<Register>();
1734 XmmRegister result = out.AsFpuRegister<XmmRegister>();
1735 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1736 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
1737
1738 // Operations use doubles for precision reasons (each 32-bit
1739 // half of a long fits in the 53-bit mantissa of a double,
1740 // but not in the 24-bit mantissa of a float). This is
1741 // especially important for the low bits. The result is
1742 // eventually converted to float.
1743
1744 // low = low - 2^31 (to prevent bit 31 of `low` to be
1745 // interpreted as a sign bit)
1746 __ subl(low, Immediate(0x80000000));
1747 // temp = int-to-double(high)
1748 __ cvtsi2sd(temp, high);
1749 // temp = temp * 2^32
1750 __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
1751 __ mulsd(temp, constant);
1752 // result = int-to-double(low)
1753 __ cvtsi2sd(result, low);
1754 // result = result + 2^31 (restore the original value of `low`)
1755 __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
1756 __ addsd(result, constant);
1757 // result = result + temp
1758 __ addsd(result, temp);
1759 // result = double-to-float(result)
1760 __ cvtsd2ss(result, result);
1761 break;
1762 }
1763
Roland Levillaincff13742014-11-17 14:32:17 +00001764 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001765 // Processing a Dex `double-to-float' instruction.
1766 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001767 break;
1768
1769 default:
1770 LOG(FATAL) << "Unexpected type conversion from " << input_type
1771 << " to " << result_type;
1772 };
1773 break;
1774
Roland Levillaindff1f282014-11-05 14:15:05 +00001775 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001776 switch (input_type) {
Roland Levillaincff13742014-11-17 14:32:17 +00001777 case Primitive::kPrimByte:
1778 case Primitive::kPrimShort:
1779 case Primitive::kPrimInt:
1780 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001781 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001782 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001783 break;
1784
Roland Levillain647b9ed2014-11-27 12:06:00 +00001785 case Primitive::kPrimLong: {
1786 // Processing a Dex `long-to-double' instruction.
1787 Register low = in.AsRegisterPairLow<Register>();
1788 Register high = in.AsRegisterPairHigh<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001789 XmmRegister result = out.AsFpuRegister<XmmRegister>();
1790 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1791 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001792
Roland Levillain647b9ed2014-11-27 12:06:00 +00001793 // low = low - 2^31 (to prevent bit 31 of `low` to be
1794 // interpreted as a sign bit)
1795 __ subl(low, Immediate(0x80000000));
1796 // temp = int-to-double(high)
1797 __ cvtsi2sd(temp, high);
1798 // temp = temp * 2^32
Roland Levillain6d0e4832014-11-27 18:31:21 +00001799 __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001800 __ mulsd(temp, constant);
1801 // result = int-to-double(low)
1802 __ cvtsi2sd(result, low);
1803 // result = result + 2^31 (restore the original value of `low`)
Roland Levillain6d0e4832014-11-27 18:31:21 +00001804 __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001805 __ addsd(result, constant);
1806 // result = result + temp
1807 __ addsd(result, temp);
1808 break;
1809 }
1810
Roland Levillaincff13742014-11-17 14:32:17 +00001811 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001812 // Processing a Dex `float-to-double' instruction.
1813 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001814 break;
1815
1816 default:
1817 LOG(FATAL) << "Unexpected type conversion from " << input_type
1818 << " to " << result_type;
1819 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001820 break;
1821
1822 default:
1823 LOG(FATAL) << "Unexpected type conversion from " << input_type
1824 << " to " << result_type;
1825 }
1826}
1827
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001828void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001829 LocationSummary* locations =
1830 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001831 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001832 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001833 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001834 locations->SetInAt(0, Location::RequiresRegister());
1835 locations->SetInAt(1, Location::Any());
1836 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001837 break;
1838 }
1839
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001840 case Primitive::kPrimFloat:
1841 case Primitive::kPrimDouble: {
1842 locations->SetInAt(0, Location::RequiresFpuRegister());
1843 locations->SetInAt(1, Location::Any());
1844 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001845 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001846 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001847
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001848 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001849 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1850 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001851 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001852}
1853
1854void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
1855 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001856 Location first = locations->InAt(0);
1857 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01001858 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001859 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001860 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001861 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001862 __ addl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001863 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001864 __ addl(first.AsRegister<Register>(),
1865 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001866 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001867 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001868 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001869 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001870 }
1871
1872 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001873 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001874 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1875 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001876 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001877 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
1878 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001879 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001880 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001881 break;
1882 }
1883
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001884 case Primitive::kPrimFloat: {
1885 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001886 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001887 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001888 __ addss(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001889 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001890 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001891 }
1892
1893 case Primitive::kPrimDouble: {
1894 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001895 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001896 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001897 __ addsd(first.AsFpuRegister<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001898 }
1899 break;
1900 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001901
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001902 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001903 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001904 }
1905}
1906
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001907void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001908 LocationSummary* locations =
1909 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001910 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001911 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001912 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001913 locations->SetInAt(0, Location::RequiresRegister());
1914 locations->SetInAt(1, Location::Any());
1915 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001916 break;
1917 }
Calin Juravle11351682014-10-23 15:38:15 +01001918 case Primitive::kPrimFloat:
1919 case Primitive::kPrimDouble: {
1920 locations->SetInAt(0, Location::RequiresFpuRegister());
1921 locations->SetInAt(1, Location::RequiresFpuRegister());
1922 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001923 break;
Calin Juravle11351682014-10-23 15:38:15 +01001924 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001925
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001926 default:
Calin Juravle11351682014-10-23 15:38:15 +01001927 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001928 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001929}
1930
1931void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
1932 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001933 Location first = locations->InAt(0);
1934 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01001935 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001936 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001937 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001938 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001939 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001940 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001941 __ subl(first.AsRegister<Register>(),
1942 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001943 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001944 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001945 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001946 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001947 }
1948
1949 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001950 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01001951 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1952 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001953 } else {
Calin Juravle11351682014-10-23 15:38:15 +01001954 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001955 __ sbbl(first.AsRegisterPairHigh<Register>(),
1956 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001957 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001958 break;
1959 }
1960
Calin Juravle11351682014-10-23 15:38:15 +01001961 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001962 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001963 break;
Calin Juravle11351682014-10-23 15:38:15 +01001964 }
1965
1966 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001967 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01001968 break;
1969 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001970
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001971 default:
Calin Juravle11351682014-10-23 15:38:15 +01001972 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001973 }
1974}
1975
Calin Juravle34bacdf2014-10-07 20:23:36 +01001976void LocationsBuilderX86::VisitMul(HMul* mul) {
1977 LocationSummary* locations =
1978 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1979 switch (mul->GetResultType()) {
1980 case Primitive::kPrimInt:
1981 locations->SetInAt(0, Location::RequiresRegister());
1982 locations->SetInAt(1, Location::Any());
1983 locations->SetOut(Location::SameAsFirstInput());
1984 break;
1985 case Primitive::kPrimLong: {
1986 locations->SetInAt(0, Location::RequiresRegister());
1987 // TODO: Currently this handles only stack operands:
1988 // - we don't have enough registers because we currently use Quick ABI.
1989 // - by the time we have a working register allocator we will probably change the ABI
1990 // and fix the above.
1991 // - we don't have a way yet to request operands on stack but the base line compiler
1992 // will leave the operands on the stack with Any().
1993 locations->SetInAt(1, Location::Any());
1994 locations->SetOut(Location::SameAsFirstInput());
1995 // Needed for imul on 32bits with 64bits output.
1996 locations->AddTemp(Location::RegisterLocation(EAX));
1997 locations->AddTemp(Location::RegisterLocation(EDX));
1998 break;
1999 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002000 case Primitive::kPrimFloat:
2001 case Primitive::kPrimDouble: {
2002 locations->SetInAt(0, Location::RequiresFpuRegister());
2003 locations->SetInAt(1, Location::RequiresFpuRegister());
2004 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002005 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002006 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002007
2008 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002009 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002010 }
2011}
2012
2013void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2014 LocationSummary* locations = mul->GetLocations();
2015 Location first = locations->InAt(0);
2016 Location second = locations->InAt(1);
2017 DCHECK(first.Equals(locations->Out()));
2018
2019 switch (mul->GetResultType()) {
2020 case Primitive::kPrimInt: {
2021 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002022 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002023 } else if (second.IsConstant()) {
2024 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002025 __ imull(first.AsRegister<Register>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002026 } else {
2027 DCHECK(second.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002028 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002029 }
2030 break;
2031 }
2032
2033 case Primitive::kPrimLong: {
2034 DCHECK(second.IsDoubleStackSlot());
2035
2036 Register in1_hi = first.AsRegisterPairHigh<Register>();
2037 Register in1_lo = first.AsRegisterPairLow<Register>();
2038 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2039 Address in2_lo(ESP, second.GetStackIndex());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002040 Register eax = locations->GetTemp(0).AsRegister<Register>();
2041 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002042
2043 DCHECK_EQ(EAX, eax);
2044 DCHECK_EQ(EDX, edx);
2045
2046 // input: in1 - 64 bits, in2 - 64 bits
2047 // output: in1
2048 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2049 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2050 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
2051
2052 __ movl(eax, in2_hi);
2053 // eax <- in1.lo * in2.hi
2054 __ imull(eax, in1_lo);
2055 // in1.hi <- in1.hi * in2.lo
2056 __ imull(in1_hi, in2_lo);
2057 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2058 __ addl(in1_hi, eax);
2059 // move in1_lo to eax to prepare for double precision
2060 __ movl(eax, in1_lo);
2061 // edx:eax <- in1.lo * in2.lo
2062 __ mull(in2_lo);
2063 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2064 __ addl(in1_hi, edx);
2065 // in1.lo <- (in1.lo * in2.lo)[31:0];
2066 __ movl(in1_lo, eax);
2067
2068 break;
2069 }
2070
Calin Juravleb5bfa962014-10-21 18:02:24 +01002071 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002072 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002073 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002074 }
2075
2076 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002077 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002078 break;
2079 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002080
2081 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002082 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002083 }
2084}
2085
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002086void InstructionCodeGeneratorX86::PushOntoFPStack(Location source, uint32_t temp_offset,
2087 uint32_t stack_adjustment, bool is_float) {
2088 if (source.IsStackSlot()) {
2089 DCHECK(is_float);
2090 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2091 } else if (source.IsDoubleStackSlot()) {
2092 DCHECK(!is_float);
2093 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2094 } else {
2095 // Write the value to the temporary location on the stack and load to FP stack.
2096 if (is_float) {
2097 Location stack_temp = Location::StackSlot(temp_offset);
2098 codegen_->Move32(stack_temp, source);
2099 __ flds(Address(ESP, temp_offset));
2100 } else {
2101 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2102 codegen_->Move64(stack_temp, source);
2103 __ fldl(Address(ESP, temp_offset));
2104 }
2105 }
2106}
2107
2108void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2109 Primitive::Type type = rem->GetResultType();
2110 bool is_float = type == Primitive::kPrimFloat;
2111 size_t elem_size = Primitive::ComponentSize(type);
2112 LocationSummary* locations = rem->GetLocations();
2113 Location first = locations->InAt(0);
2114 Location second = locations->InAt(1);
2115 Location out = locations->Out();
2116
2117 // Create stack space for 2 elements.
2118 // TODO: enhance register allocator to ask for stack temporaries.
2119 __ subl(ESP, Immediate(2 * elem_size));
2120
2121 // Load the values to the FP stack in reverse order, using temporaries if needed.
2122 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2123 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2124
2125 // Loop doing FPREM until we stabilize.
2126 Label retry;
2127 __ Bind(&retry);
2128 __ fprem();
2129
2130 // Move FP status to AX.
2131 __ fstsw();
2132
2133 // And see if the argument reduction is complete. This is signaled by the
2134 // C2 FPU flag bit set to 0.
2135 __ andl(EAX, Immediate(kC2ConditionMask));
2136 __ j(kNotEqual, &retry);
2137
2138 // We have settled on the final value. Retrieve it into an XMM register.
2139 // Store FP top of stack to real stack.
2140 if (is_float) {
2141 __ fsts(Address(ESP, 0));
2142 } else {
2143 __ fstl(Address(ESP, 0));
2144 }
2145
2146 // Pop the 2 items from the FP stack.
2147 __ fucompp();
2148
2149 // Load the value from the stack into an XMM register.
2150 DCHECK(out.IsFpuRegister()) << out;
2151 if (is_float) {
2152 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2153 } else {
2154 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2155 }
2156
2157 // And remove the temporary stack space we allocated.
2158 __ addl(ESP, Immediate(2 * elem_size));
2159}
2160
Calin Juravlebacfec32014-11-14 15:54:36 +00002161void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2162 DCHECK(instruction->IsDiv() || instruction->IsRem());
2163
2164 LocationSummary* locations = instruction->GetLocations();
2165 Location out = locations->Out();
2166 Location first = locations->InAt(0);
2167 Location second = locations->InAt(1);
2168 bool is_div = instruction->IsDiv();
2169
2170 switch (instruction->GetResultType()) {
2171 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002172 Register second_reg = second.AsRegister<Register>();
2173 DCHECK_EQ(EAX, first.AsRegister<Register>());
2174 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002175
2176 SlowPathCodeX86* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002177 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
2178 is_div);
Calin Juravlebacfec32014-11-14 15:54:36 +00002179 codegen_->AddSlowPath(slow_path);
2180
2181 // 0x80000000/-1 triggers an arithmetic exception!
2182 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2183 // it's safe to just use negl instead of more complex comparisons.
2184
2185 __ cmpl(second_reg, Immediate(-1));
2186 __ j(kEqual, slow_path->GetEntryLabel());
2187
2188 // edx:eax <- sign-extended of eax
2189 __ cdq();
2190 // eax = quotient, edx = remainder
2191 __ idivl(second_reg);
2192
2193 __ Bind(slow_path->GetExitLabel());
2194 break;
2195 }
2196
2197 case Primitive::kPrimLong: {
2198 InvokeRuntimeCallingConvention calling_convention;
2199 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2200 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2201 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2202 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2203 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2204 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2205
2206 if (is_div) {
2207 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv)));
2208 } else {
2209 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod)));
2210 }
2211 uint32_t dex_pc = is_div
2212 ? instruction->AsDiv()->GetDexPc()
2213 : instruction->AsRem()->GetDexPc();
2214 codegen_->RecordPcInfo(instruction, dex_pc);
2215
2216 break;
2217 }
2218
2219 default:
2220 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
2221 }
2222}
2223
Calin Juravle7c4954d2014-10-28 16:57:40 +00002224void LocationsBuilderX86::VisitDiv(HDiv* div) {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002225 LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong
2226 ? LocationSummary::kCall
2227 : LocationSummary::kNoCall;
2228 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2229
Calin Juravle7c4954d2014-10-28 16:57:40 +00002230 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002231 case Primitive::kPrimInt: {
2232 locations->SetInAt(0, Location::RegisterLocation(EAX));
2233 locations->SetInAt(1, Location::RequiresRegister());
2234 locations->SetOut(Location::SameAsFirstInput());
2235 // Intel uses edx:eax as the dividend.
2236 locations->AddTemp(Location::RegisterLocation(EDX));
2237 break;
2238 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002239 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002240 InvokeRuntimeCallingConvention calling_convention;
2241 locations->SetInAt(0, Location::RegisterPairLocation(
2242 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2243 locations->SetInAt(1, Location::RegisterPairLocation(
2244 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2245 // Runtime helper puts the result in EAX, EDX.
2246 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002247 break;
2248 }
2249 case Primitive::kPrimFloat:
2250 case Primitive::kPrimDouble: {
2251 locations->SetInAt(0, Location::RequiresFpuRegister());
2252 locations->SetInAt(1, Location::RequiresFpuRegister());
2253 locations->SetOut(Location::SameAsFirstInput());
2254 break;
2255 }
2256
2257 default:
2258 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2259 }
2260}
2261
2262void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
2263 LocationSummary* locations = div->GetLocations();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002264 Location out = locations->Out();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002265 Location first = locations->InAt(0);
2266 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002267
2268 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002269 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00002270 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002271 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002272 break;
2273 }
2274
2275 case Primitive::kPrimFloat: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002276 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002277 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002278 break;
2279 }
2280
2281 case Primitive::kPrimDouble: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002282 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002283 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002284 break;
2285 }
2286
2287 default:
2288 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2289 }
2290}
2291
Calin Juravlebacfec32014-11-14 15:54:36 +00002292void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002293 Primitive::Type type = rem->GetResultType();
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002294 LocationSummary* locations =
2295 new (GetGraph()->GetArena()) LocationSummary(rem, LocationSummary::kNoCall);
Calin Juravlebacfec32014-11-14 15:54:36 +00002296
Calin Juravled2ec87d2014-12-08 14:24:46 +00002297 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002298 case Primitive::kPrimInt: {
2299 locations->SetInAt(0, Location::RegisterLocation(EAX));
2300 locations->SetInAt(1, Location::RequiresRegister());
2301 locations->SetOut(Location::RegisterLocation(EDX));
2302 break;
2303 }
2304 case Primitive::kPrimLong: {
2305 InvokeRuntimeCallingConvention calling_convention;
2306 locations->SetInAt(0, Location::RegisterPairLocation(
2307 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2308 locations->SetInAt(1, Location::RegisterPairLocation(
2309 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2310 // Runtime helper puts the result in EAX, EDX.
2311 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2312 break;
2313 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002314 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002315 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002316 locations->SetInAt(0, Location::Any());
2317 locations->SetInAt(1, Location::Any());
2318 locations->SetOut(Location::RequiresFpuRegister());
2319 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002320 break;
2321 }
2322
2323 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002324 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002325 }
2326}
2327
2328void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
2329 Primitive::Type type = rem->GetResultType();
2330 switch (type) {
2331 case Primitive::kPrimInt:
2332 case Primitive::kPrimLong: {
2333 GenerateDivRemIntegral(rem);
2334 break;
2335 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002336 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00002337 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002338 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00002339 break;
2340 }
2341 default:
2342 LOG(FATAL) << "Unexpected rem type " << type;
2343 }
2344}
2345
Calin Juravled0d48522014-11-04 16:40:20 +00002346void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2347 LocationSummary* locations =
2348 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002349 switch (instruction->GetType()) {
2350 case Primitive::kPrimInt: {
2351 locations->SetInAt(0, Location::Any());
2352 break;
2353 }
2354 case Primitive::kPrimLong: {
2355 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2356 if (!instruction->IsConstant()) {
2357 locations->AddTemp(Location::RequiresRegister());
2358 }
2359 break;
2360 }
2361 default:
2362 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2363 }
Calin Juravled0d48522014-11-04 16:40:20 +00002364 if (instruction->HasUses()) {
2365 locations->SetOut(Location::SameAsFirstInput());
2366 }
2367}
2368
2369void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2370 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
2371 codegen_->AddSlowPath(slow_path);
2372
2373 LocationSummary* locations = instruction->GetLocations();
2374 Location value = locations->InAt(0);
2375
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002376 switch (instruction->GetType()) {
2377 case Primitive::kPrimInt: {
2378 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002379 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002380 __ j(kEqual, slow_path->GetEntryLabel());
2381 } else if (value.IsStackSlot()) {
2382 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
2383 __ j(kEqual, slow_path->GetEntryLabel());
2384 } else {
2385 DCHECK(value.IsConstant()) << value;
2386 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2387 __ jmp(slow_path->GetEntryLabel());
2388 }
2389 }
2390 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002391 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002392 case Primitive::kPrimLong: {
2393 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002394 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002395 __ movl(temp, value.AsRegisterPairLow<Register>());
2396 __ orl(temp, value.AsRegisterPairHigh<Register>());
2397 __ j(kEqual, slow_path->GetEntryLabel());
2398 } else {
2399 DCHECK(value.IsConstant()) << value;
2400 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2401 __ jmp(slow_path->GetEntryLabel());
2402 }
2403 }
2404 break;
2405 }
2406 default:
2407 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002408 }
Calin Juravled0d48522014-11-04 16:40:20 +00002409}
2410
Calin Juravle9aec02f2014-11-18 23:06:35 +00002411void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
2412 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2413
2414 LocationSummary* locations =
2415 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2416
2417 switch (op->GetResultType()) {
2418 case Primitive::kPrimInt: {
2419 locations->SetInAt(0, Location::RequiresRegister());
2420 // The shift count needs to be in CL.
2421 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
2422 locations->SetOut(Location::SameAsFirstInput());
2423 break;
2424 }
2425 case Primitive::kPrimLong: {
2426 locations->SetInAt(0, Location::RequiresRegister());
2427 // The shift count needs to be in CL.
2428 locations->SetInAt(1, Location::RegisterLocation(ECX));
2429 locations->SetOut(Location::SameAsFirstInput());
2430 break;
2431 }
2432 default:
2433 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2434 }
2435}
2436
2437void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
2438 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2439
2440 LocationSummary* locations = op->GetLocations();
2441 Location first = locations->InAt(0);
2442 Location second = locations->InAt(1);
2443 DCHECK(first.Equals(locations->Out()));
2444
2445 switch (op->GetResultType()) {
2446 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002447 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002448 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002449 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002450 DCHECK_EQ(ECX, second_reg);
2451 if (op->IsShl()) {
2452 __ shll(first_reg, second_reg);
2453 } else if (op->IsShr()) {
2454 __ sarl(first_reg, second_reg);
2455 } else {
2456 __ shrl(first_reg, second_reg);
2457 }
2458 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002459 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002460 if (op->IsShl()) {
2461 __ shll(first_reg, imm);
2462 } else if (op->IsShr()) {
2463 __ sarl(first_reg, imm);
2464 } else {
2465 __ shrl(first_reg, imm);
2466 }
2467 }
2468 break;
2469 }
2470 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002471 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002472 DCHECK_EQ(ECX, second_reg);
2473 if (op->IsShl()) {
2474 GenerateShlLong(first, second_reg);
2475 } else if (op->IsShr()) {
2476 GenerateShrLong(first, second_reg);
2477 } else {
2478 GenerateUShrLong(first, second_reg);
2479 }
2480 break;
2481 }
2482 default:
2483 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2484 }
2485}
2486
2487void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
2488 Label done;
2489 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
2490 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
2491 __ testl(shifter, Immediate(32));
2492 __ j(kEqual, &done);
2493 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
2494 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
2495 __ Bind(&done);
2496}
2497
2498void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
2499 Label done;
2500 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2501 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
2502 __ testl(shifter, Immediate(32));
2503 __ j(kEqual, &done);
2504 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2505 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
2506 __ Bind(&done);
2507}
2508
2509void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
2510 Label done;
2511 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2512 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
2513 __ testl(shifter, Immediate(32));
2514 __ j(kEqual, &done);
2515 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2516 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
2517 __ Bind(&done);
2518}
2519
2520void LocationsBuilderX86::VisitShl(HShl* shl) {
2521 HandleShift(shl);
2522}
2523
2524void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
2525 HandleShift(shl);
2526}
2527
2528void LocationsBuilderX86::VisitShr(HShr* shr) {
2529 HandleShift(shr);
2530}
2531
2532void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
2533 HandleShift(shr);
2534}
2535
2536void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
2537 HandleShift(ushr);
2538}
2539
2540void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
2541 HandleShift(ushr);
2542}
2543
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002544void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002545 LocationSummary* locations =
2546 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002547 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002548 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002549 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2550 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002551}
2552
2553void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
2554 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002555 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002556 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002557
Nicolas Geoffray707c8092014-04-04 10:50:14 +01002558 __ fs()->call(
2559 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocObjectWithAccessCheck)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002560
Nicolas Geoffray39468442014-09-02 15:17:15 +01002561 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002562 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002563}
2564
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002565void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
2566 LocationSummary* locations =
2567 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2568 locations->SetOut(Location::RegisterLocation(EAX));
2569 InvokeRuntimeCallingConvention calling_convention;
2570 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002571 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2572 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002573}
2574
2575void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
2576 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002577 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002578 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
2579
2580 __ fs()->call(
2581 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocArrayWithAccessCheck)));
2582
2583 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2584 DCHECK(!codegen_->IsLeafMethod());
2585}
2586
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002587void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002588 LocationSummary* locations =
2589 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002590 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2591 if (location.IsStackSlot()) {
2592 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2593 } else if (location.IsDoubleStackSlot()) {
2594 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002595 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002596 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002597}
2598
2599void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002600 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002601}
2602
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002603void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002604 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002605 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002606 locations->SetInAt(0, Location::RequiresRegister());
2607 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002608}
2609
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002610void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
2611 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01002612 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002613 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01002614 DCHECK(in.Equals(out));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002615 switch (not_->InputAt(0)->GetType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002616 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002617 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002618 break;
2619
2620 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002621 __ notl(out.AsRegisterPairLow<Register>());
2622 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002623 break;
2624
2625 default:
2626 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2627 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002628}
2629
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002630void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002631 LocationSummary* locations =
2632 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002633 switch (compare->InputAt(0)->GetType()) {
2634 case Primitive::kPrimLong: {
2635 locations->SetInAt(0, Location::RequiresRegister());
2636 // TODO: we set any here but we don't handle constants
2637 locations->SetInAt(1, Location::Any());
2638 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2639 break;
2640 }
2641 case Primitive::kPrimFloat:
2642 case Primitive::kPrimDouble: {
2643 locations->SetInAt(0, Location::RequiresFpuRegister());
2644 locations->SetInAt(1, Location::RequiresFpuRegister());
2645 locations->SetOut(Location::RequiresRegister());
2646 break;
2647 }
2648 default:
2649 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2650 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002651}
2652
2653void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002654 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002655 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002656 Location left = locations->InAt(0);
2657 Location right = locations->InAt(1);
2658
2659 Label less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002660 switch (compare->InputAt(0)->GetType()) {
2661 case Primitive::kPrimLong: {
Calin Juravleddb7df22014-11-25 20:56:51 +00002662 if (right.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002663 __ cmpl(left.AsRegisterPairHigh<Register>(), right.AsRegisterPairHigh<Register>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002664 } else {
2665 DCHECK(right.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002666 __ cmpl(left.AsRegisterPairHigh<Register>(),
2667 Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002668 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002669 __ j(kLess, &less); // Signed compare.
2670 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002671 if (right.IsRegisterPair()) {
2672 __ cmpl(left.AsRegisterPairLow<Register>(), right.AsRegisterPairLow<Register>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002673 } else {
2674 DCHECK(right.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002675 __ cmpl(left.AsRegisterPairLow<Register>(), Address(ESP, right.GetStackIndex()));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002676 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002677 break;
2678 }
2679 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002680 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002681 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
2682 break;
2683 }
2684 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002685 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002686 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002687 break;
2688 }
2689 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002690 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002691 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002692 __ movl(out, Immediate(0));
2693 __ j(kEqual, &done);
2694 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
2695
2696 __ Bind(&greater);
2697 __ movl(out, Immediate(1));
2698 __ jmp(&done);
2699
2700 __ Bind(&less);
2701 __ movl(out, Immediate(-1));
2702
2703 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002704}
2705
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002706void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002707 LocationSummary* locations =
2708 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002709 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2710 locations->SetInAt(i, Location::Any());
2711 }
2712 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002713}
2714
2715void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002716 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002717 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002718}
2719
Calin Juravle52c48962014-12-16 17:02:57 +00002720void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
2721 /*
2722 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2723 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2724 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2725 */
2726 switch (kind) {
2727 case MemBarrierKind::kAnyAny: {
2728 __ mfence();
2729 break;
2730 }
2731 case MemBarrierKind::kAnyStore:
2732 case MemBarrierKind::kLoadAny:
2733 case MemBarrierKind::kStoreStore: {
2734 // nop
2735 break;
2736 }
2737 default:
2738 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002739 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002740}
2741
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002742
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002743void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002744 Label is_null;
2745 __ testl(value, value);
2746 __ j(kEqual, &is_null);
2747 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
2748 __ movl(temp, object);
2749 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002750 __ movb(Address(temp, card, TIMES_1, 0),
2751 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002752 __ Bind(&is_null);
2753}
2754
Calin Juravle52c48962014-12-16 17:02:57 +00002755void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
2756 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002757 LocationSummary* locations =
2758 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002759 locations->SetInAt(0, Location::RequiresRegister());
2760 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Calin Juravle52c48962014-12-16 17:02:57 +00002761
2762 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
2763 // Long values can be loaded atomically into an XMM using movsd.
2764 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
2765 // and then copy the XMM into the output 32bits at a time).
2766 locations->AddTemp(Location::RequiresFpuRegister());
2767 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002768}
2769
Calin Juravle52c48962014-12-16 17:02:57 +00002770void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
2771 const FieldInfo& field_info) {
2772 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002773
Calin Juravle52c48962014-12-16 17:02:57 +00002774 LocationSummary* locations = instruction->GetLocations();
2775 Register base = locations->InAt(0).AsRegister<Register>();
2776 Location out = locations->Out();
2777 bool is_volatile = field_info.IsVolatile();
2778 Primitive::Type field_type = field_info.GetFieldType();
2779 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2780
2781 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002782 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00002783 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002784 break;
2785 }
2786
2787 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002788 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002789 break;
2790 }
2791
2792 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00002793 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002794 break;
2795 }
2796
2797 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002798 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002799 break;
2800 }
2801
2802 case Primitive::kPrimInt:
2803 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002804 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002805 break;
2806 }
2807
2808 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002809 if (is_volatile) {
2810 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2811 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00002812 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002813 __ movd(out.AsRegisterPairLow<Register>(), temp);
2814 __ psrlq(temp, Immediate(32));
2815 __ movd(out.AsRegisterPairHigh<Register>(), temp);
2816 } else {
2817 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00002818 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002819 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
2820 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002821 break;
2822 }
2823
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002824 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002825 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002826 break;
2827 }
2828
2829 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002830 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002831 break;
2832 }
2833
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002834 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00002835 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002836 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002837 }
Calin Juravle52c48962014-12-16 17:02:57 +00002838
Calin Juravle77520bc2015-01-12 18:45:46 +00002839 // Longs are handled in the switch.
2840 if (field_type != Primitive::kPrimLong) {
2841 codegen_->MaybeRecordImplicitNullCheck(instruction);
2842 }
2843
Calin Juravle52c48962014-12-16 17:02:57 +00002844 if (is_volatile) {
2845 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2846 }
2847}
2848
2849void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2850 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2851
2852 LocationSummary* locations =
2853 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2854 locations->SetInAt(0, Location::RequiresRegister());
2855 bool is_volatile = field_info.IsVolatile();
2856 Primitive::Type field_type = field_info.GetFieldType();
2857 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
2858 || (field_type == Primitive::kPrimByte);
2859
2860 // The register allocator does not support multiple
2861 // inputs that die at entry with one in a specific register.
2862 if (is_byte_type) {
2863 // Ensure the value is in a byte register.
2864 locations->SetInAt(1, Location::RegisterLocation(EAX));
2865 } else {
2866 locations->SetInAt(1, Location::RequiresRegister());
2867 }
2868 // Temporary registers for the write barrier.
2869 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2870 locations->AddTemp(Location::RequiresRegister());
2871 // Ensure the card is in a byte register.
2872 locations->AddTemp(Location::RegisterLocation(ECX));
2873 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
2874 // 64bits value can be atomically written to an address with movsd and an XMM register.
2875 // We need two XMM registers because there's no easier way to (bit) copy a register pair
2876 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
2877 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
2878 // isolated cases when we need this it isn't worth adding the extra complexity.
2879 locations->AddTemp(Location::RequiresFpuRegister());
2880 locations->AddTemp(Location::RequiresFpuRegister());
2881 }
2882}
2883
2884void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
2885 const FieldInfo& field_info) {
2886 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2887
2888 LocationSummary* locations = instruction->GetLocations();
2889 Register base = locations->InAt(0).AsRegister<Register>();
2890 Location value = locations->InAt(1);
2891 bool is_volatile = field_info.IsVolatile();
2892 Primitive::Type field_type = field_info.GetFieldType();
2893 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2894
2895 if (is_volatile) {
2896 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
2897 }
2898
2899 switch (field_type) {
2900 case Primitive::kPrimBoolean:
2901 case Primitive::kPrimByte: {
2902 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
2903 break;
2904 }
2905
2906 case Primitive::kPrimShort:
2907 case Primitive::kPrimChar: {
2908 __ movw(Address(base, offset), value.AsRegister<Register>());
2909 break;
2910 }
2911
2912 case Primitive::kPrimInt:
2913 case Primitive::kPrimNot: {
2914 __ movl(Address(base, offset), value.AsRegister<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00002915 break;
2916 }
2917
2918 case Primitive::kPrimLong: {
2919 if (is_volatile) {
2920 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2921 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
2922 __ movd(temp1, value.AsRegisterPairLow<Register>());
2923 __ movd(temp2, value.AsRegisterPairHigh<Register>());
2924 __ punpckldq(temp1, temp2);
2925 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00002926 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002927 } else {
2928 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00002929 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002930 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
2931 }
2932 break;
2933 }
2934
2935 case Primitive::kPrimFloat: {
2936 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
2937 break;
2938 }
2939
2940 case Primitive::kPrimDouble: {
2941 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
2942 break;
2943 }
2944
2945 case Primitive::kPrimVoid:
2946 LOG(FATAL) << "Unreachable type " << field_type;
2947 UNREACHABLE();
2948 }
2949
Calin Juravle77520bc2015-01-12 18:45:46 +00002950 // Longs are handled in the switch.
2951 if (field_type != Primitive::kPrimLong) {
2952 codegen_->MaybeRecordImplicitNullCheck(instruction);
2953 }
2954
2955 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
2956 Register temp = locations->GetTemp(0).AsRegister<Register>();
2957 Register card = locations->GetTemp(1).AsRegister<Register>();
2958 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
2959 }
2960
Calin Juravle52c48962014-12-16 17:02:57 +00002961 if (is_volatile) {
2962 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
2963 }
2964}
2965
2966void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2967 HandleFieldGet(instruction, instruction->GetFieldInfo());
2968}
2969
2970void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2971 HandleFieldGet(instruction, instruction->GetFieldInfo());
2972}
2973
2974void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2975 HandleFieldSet(instruction, instruction->GetFieldInfo());
2976}
2977
2978void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2979 HandleFieldSet(instruction, instruction->GetFieldInfo());
2980}
2981
2982void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2983 HandleFieldSet(instruction, instruction->GetFieldInfo());
2984}
2985
2986void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
2987 HandleFieldSet(instruction, instruction->GetFieldInfo());
2988}
2989
2990void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
2991 HandleFieldGet(instruction, instruction->GetFieldInfo());
2992}
2993
2994void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
2995 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002996}
2997
2998void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002999 LocationSummary* locations =
3000 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003001 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3002 ? Location::RequiresRegister()
3003 : Location::Any();
3004 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003005 if (instruction->HasUses()) {
3006 locations->SetOut(Location::SameAsFirstInput());
3007 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003008}
3009
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003010void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003011 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3012 return;
3013 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003014 LocationSummary* locations = instruction->GetLocations();
3015 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003016
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003017 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
3018 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3019}
3020
3021void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003022 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003023 codegen_->AddSlowPath(slow_path);
3024
3025 LocationSummary* locations = instruction->GetLocations();
3026 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003027
3028 if (obj.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003029 __ cmpl(obj.AsRegister<Register>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003030 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003031 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003032 } else {
3033 DCHECK(obj.IsConstant()) << obj;
3034 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3035 __ jmp(slow_path->GetEntryLabel());
3036 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003037 }
3038 __ j(kEqual, slow_path->GetEntryLabel());
3039}
3040
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003041void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
3042 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3043 GenerateImplicitNullCheck(instruction);
3044 } else {
3045 GenerateExplicitNullCheck(instruction);
3046 }
3047}
3048
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003049void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003050 LocationSummary* locations =
3051 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003052 locations->SetInAt(0, Location::RequiresRegister());
3053 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
3054 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003055}
3056
3057void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
3058 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003059 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003060 Location index = locations->InAt(1);
3061
Calin Juravle77520bc2015-01-12 18:45:46 +00003062 Primitive::Type type = instruction->GetType();
3063 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003064 case Primitive::kPrimBoolean: {
3065 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003066 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003067 if (index.IsConstant()) {
3068 __ movzxb(out, Address(obj,
3069 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3070 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003071 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003072 }
3073 break;
3074 }
3075
3076 case Primitive::kPrimByte: {
3077 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003078 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003079 if (index.IsConstant()) {
3080 __ movsxb(out, Address(obj,
3081 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3082 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003083 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003084 }
3085 break;
3086 }
3087
3088 case Primitive::kPrimShort: {
3089 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003090 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003091 if (index.IsConstant()) {
3092 __ movsxw(out, Address(obj,
3093 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3094 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003095 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003096 }
3097 break;
3098 }
3099
3100 case Primitive::kPrimChar: {
3101 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003102 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003103 if (index.IsConstant()) {
3104 __ movzxw(out, Address(obj,
3105 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3106 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003107 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003108 }
3109 break;
3110 }
3111
3112 case Primitive::kPrimInt:
3113 case Primitive::kPrimNot: {
3114 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003115 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003116 if (index.IsConstant()) {
3117 __ movl(out, Address(obj,
3118 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3119 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003120 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003121 }
3122 break;
3123 }
3124
3125 case Primitive::kPrimLong: {
3126 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003127 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003128 if (index.IsConstant()) {
3129 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003130 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003131 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003132 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003133 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003134 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003135 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003136 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003137 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003138 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003139 }
3140 break;
3141 }
3142
Mark Mendell7c8d0092015-01-26 11:21:33 -05003143 case Primitive::kPrimFloat: {
3144 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3145 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3146 if (index.IsConstant()) {
3147 __ movss(out, Address(obj,
3148 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3149 } else {
3150 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
3151 }
3152 break;
3153 }
3154
3155 case Primitive::kPrimDouble: {
3156 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3157 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3158 if (index.IsConstant()) {
3159 __ movsd(out, Address(obj,
3160 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3161 } else {
3162 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
3163 }
3164 break;
3165 }
3166
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003167 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00003168 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003169 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003170 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003171
3172 if (type != Primitive::kPrimLong) {
3173 codegen_->MaybeRecordImplicitNullCheck(instruction);
3174 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003175}
3176
3177void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003178 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003179 bool needs_write_barrier =
3180 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3181
3182 DCHECK(kFollowsQuickABI);
3183 bool not_enough_registers = needs_write_barrier
3184 && !instruction->GetValue()->IsConstant()
3185 && !instruction->GetIndex()->IsConstant();
3186 bool needs_runtime_call = instruction->NeedsTypeCheck() || not_enough_registers;
3187
Nicolas Geoffray39468442014-09-02 15:17:15 +01003188 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3189 instruction,
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003190 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003191
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003192 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003193 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003194 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3195 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3196 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003197 } else {
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003198 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
3199 || (value_type == Primitive::kPrimByte);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003200 // We need the inputs to be different than the output in case of long operation.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003201 // In case of a byte operation, the register allocator does not support multiple
3202 // inputs that die at entry with one in a specific register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003203 locations->SetInAt(0, Location::RequiresRegister());
3204 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003205 if (is_byte_type) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003206 // Ensure the value is in a byte register.
3207 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003208 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003209 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003210 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003211 // Temporary registers for the write barrier.
3212 if (needs_write_barrier) {
3213 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003214 // Ensure the card is in a byte register.
3215 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003216 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003217 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003218}
3219
3220void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
3221 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003222 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003223 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003224 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003225 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003226 bool needs_runtime_call = locations->WillCall();
3227 bool needs_write_barrier =
3228 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003229
3230 switch (value_type) {
3231 case Primitive::kPrimBoolean:
3232 case Primitive::kPrimByte: {
3233 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003234 if (index.IsConstant()) {
3235 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003236 if (value.IsRegister()) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003237 __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003238 } else {
3239 __ movb(Address(obj, offset),
3240 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3241 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003242 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003243 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003244 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003245 value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003246 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003247 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003248 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3249 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003250 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003251 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003252 break;
3253 }
3254
3255 case Primitive::kPrimShort:
3256 case Primitive::kPrimChar: {
3257 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003258 if (index.IsConstant()) {
3259 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003260 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003261 __ movw(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003262 } else {
3263 __ movw(Address(obj, offset),
3264 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3265 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003266 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003267 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003268 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
3269 value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003270 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003271 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003272 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3273 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003274 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003275 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003276 break;
3277 }
3278
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003279 case Primitive::kPrimInt:
3280 case Primitive::kPrimNot: {
3281 if (!needs_runtime_call) {
3282 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3283 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003284 size_t offset =
3285 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003286 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003287 __ movl(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003288 } else {
3289 DCHECK(value.IsConstant()) << value;
3290 __ movl(Address(obj, offset),
3291 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3292 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003293 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003294 DCHECK(index.IsRegister()) << index;
3295 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003296 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3297 value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003298 } else {
3299 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003300 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003301 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3302 }
3303 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003304 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003305
3306 if (needs_write_barrier) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003307 Register temp = locations->GetTemp(0).AsRegister<Register>();
3308 Register card = locations->GetTemp(1).AsRegister<Register>();
3309 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003310 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003311 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003312 DCHECK_EQ(value_type, Primitive::kPrimNot);
3313 DCHECK(!codegen_->IsLeafMethod());
3314 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
3315 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003316 }
3317 break;
3318 }
3319
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003320 case Primitive::kPrimLong: {
3321 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003322 if (index.IsConstant()) {
3323 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003324 if (value.IsRegisterPair()) {
3325 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003326 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003327 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003328 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003329 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003330 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
3331 __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003332 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003333 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
3334 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003335 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003336 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003337 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003338 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003339 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003340 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003341 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003342 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003343 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003344 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003345 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003346 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003347 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003348 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003349 Immediate(High32Bits(val)));
3350 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003351 }
3352 break;
3353 }
3354
Mark Mendell7c8d0092015-01-26 11:21:33 -05003355 case Primitive::kPrimFloat: {
3356 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3357 DCHECK(value.IsFpuRegister());
3358 if (index.IsConstant()) {
3359 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3360 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3361 } else {
3362 __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3363 value.AsFpuRegister<XmmRegister>());
3364 }
3365 break;
3366 }
3367
3368 case Primitive::kPrimDouble: {
3369 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3370 DCHECK(value.IsFpuRegister());
3371 if (index.IsConstant()) {
3372 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3373 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3374 } else {
3375 __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3376 value.AsFpuRegister<XmmRegister>());
3377 }
3378 break;
3379 }
3380
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003381 case Primitive::kPrimVoid:
3382 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003383 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003384 }
3385}
3386
3387void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
3388 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003389 locations->SetInAt(0, Location::RequiresRegister());
3390 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003391 instruction->SetLocations(locations);
3392}
3393
3394void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
3395 LocationSummary* locations = instruction->GetLocations();
3396 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003397 Register obj = locations->InAt(0).AsRegister<Register>();
3398 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003399 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003400 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003401}
3402
3403void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003404 LocationSummary* locations =
3405 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003406 locations->SetInAt(0, Location::RequiresRegister());
3407 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003408 if (instruction->HasUses()) {
3409 locations->SetOut(Location::SameAsFirstInput());
3410 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003411}
3412
3413void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
3414 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003415 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(
Nicolas Geoffray39468442014-09-02 15:17:15 +01003416 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003417 codegen_->AddSlowPath(slow_path);
3418
Roland Levillain271ab9c2014-11-27 15:23:57 +00003419 Register index = locations->InAt(0).AsRegister<Register>();
3420 Register length = locations->InAt(1).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003421
3422 __ cmpl(index, length);
3423 __ j(kAboveEqual, slow_path->GetEntryLabel());
3424}
3425
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003426void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
3427 temp->SetLocations(nullptr);
3428}
3429
3430void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
3431 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003432 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003433}
3434
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003435void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003436 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003437 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003438}
3439
3440void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003441 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3442}
3443
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003444void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
3445 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3446}
3447
3448void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003449 HBasicBlock* block = instruction->GetBlock();
3450 if (block->GetLoopInformation() != nullptr) {
3451 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3452 // The back edge will generate the suspend check.
3453 return;
3454 }
3455 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3456 // The goto will generate the suspend check.
3457 return;
3458 }
3459 GenerateSuspendCheck(instruction, nullptr);
3460}
3461
3462void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
3463 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003464 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003465 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003466 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003467 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003468 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003469 if (successor == nullptr) {
3470 __ j(kNotEqual, slow_path->GetEntryLabel());
3471 __ Bind(slow_path->GetReturnLabel());
3472 } else {
3473 __ j(kEqual, codegen_->GetLabelOf(successor));
3474 __ jmp(slow_path->GetEntryLabel());
3475 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003476}
3477
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003478X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
3479 return codegen_->GetAssembler();
3480}
3481
Mark Mendell7c8d0092015-01-26 11:21:33 -05003482void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003483 ScratchRegisterScope ensure_scratch(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003484 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003485 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003486 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
Mark Mendell7c8d0092015-01-26 11:21:33 -05003487 __ movl(temp_reg, Address(ESP, src + stack_offset));
3488 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3489}
3490
3491void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
3492 ScratchRegisterScope ensure_scratch(
3493 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3494 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3495 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3496 __ movl(temp_reg, Address(ESP, src + stack_offset));
3497 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3498 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
3499 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003500}
3501
3502void ParallelMoveResolverX86::EmitMove(size_t index) {
3503 MoveOperands* move = moves_.Get(index);
3504 Location source = move->GetSource();
3505 Location destination = move->GetDestination();
3506
3507 if (source.IsRegister()) {
3508 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003509 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003510 } else {
3511 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003512 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003513 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003514 } else if (source.IsFpuRegister()) {
3515 if (destination.IsFpuRegister()) {
3516 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3517 } else if (destination.IsStackSlot()) {
3518 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3519 } else {
3520 DCHECK(destination.IsDoubleStackSlot());
3521 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3522 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003523 } else if (source.IsStackSlot()) {
3524 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003525 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003526 } else if (destination.IsFpuRegister()) {
3527 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003528 } else {
3529 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003530 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
3531 }
3532 } else if (source.IsDoubleStackSlot()) {
3533 if (destination.IsFpuRegister()) {
3534 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
3535 } else {
3536 DCHECK(destination.IsDoubleStackSlot()) << destination;
3537 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003538 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003539 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003540 HConstant* constant = source.GetConstant();
3541 if (constant->IsIntConstant()) {
3542 Immediate imm(constant->AsIntConstant()->GetValue());
3543 if (destination.IsRegister()) {
3544 __ movl(destination.AsRegister<Register>(), imm);
3545 } else {
3546 DCHECK(destination.IsStackSlot()) << destination;
3547 __ movl(Address(ESP, destination.GetStackIndex()), imm);
3548 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003549 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003550 DCHECK(constant->IsFloatConstant());
3551 float value = constant->AsFloatConstant()->GetValue();
3552 Immediate imm(bit_cast<float, int32_t>(value));
3553 if (destination.IsFpuRegister()) {
3554 ScratchRegisterScope ensure_scratch(
3555 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3556 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
3557 __ movl(temp, imm);
3558 __ movd(destination.AsFpuRegister<XmmRegister>(), temp);
3559 } else {
3560 DCHECK(destination.IsStackSlot()) << destination;
3561 __ movl(Address(ESP, destination.GetStackIndex()), imm);
3562 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003563 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003564 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00003565 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003566 }
3567}
3568
3569void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003570 Register suggested_scratch = reg == EAX ? EBX : EAX;
3571 ScratchRegisterScope ensure_scratch(
3572 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3573
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003574 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3575 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
3576 __ movl(Address(ESP, mem + stack_offset), reg);
3577 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
3578}
3579
Mark Mendell7c8d0092015-01-26 11:21:33 -05003580void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
3581 ScratchRegisterScope ensure_scratch(
3582 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3583
3584 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3585 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3586 __ movl(temp_reg, Address(ESP, mem + stack_offset));
3587 __ movss(Address(ESP, mem + stack_offset), reg);
3588 __ movd(reg, temp_reg);
3589}
3590
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003591void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
3592 ScratchRegisterScope ensure_scratch1(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003593 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3594
3595 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003596 ScratchRegisterScope ensure_scratch2(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003597 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3598
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003599 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
3600 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
3601 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
3602 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
3603 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
3604 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
3605}
3606
3607void ParallelMoveResolverX86::EmitSwap(size_t index) {
3608 MoveOperands* move = moves_.Get(index);
3609 Location source = move->GetSource();
3610 Location destination = move->GetDestination();
3611
3612 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003613 __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003614 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003615 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003616 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003617 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003618 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3619 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003620 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
3621 // Use XOR Swap algorithm to avoid a temporary.
3622 DCHECK_NE(source.reg(), destination.reg());
3623 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3624 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3625 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3626 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
3627 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
3628 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
3629 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003630 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003631 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003632 }
3633}
3634
3635void ParallelMoveResolverX86::SpillScratch(int reg) {
3636 __ pushl(static_cast<Register>(reg));
3637}
3638
3639void ParallelMoveResolverX86::RestoreScratch(int reg) {
3640 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003641}
3642
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003643void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003644 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3645 ? LocationSummary::kCallOnSlowPath
3646 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003647 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003648 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003649 locations->SetOut(Location::RequiresRegister());
3650}
3651
3652void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003653 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003654 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003655 DCHECK(!cls->CanCallRuntime());
3656 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003657 codegen_->LoadCurrentMethod(out);
3658 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3659 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003660 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003661 codegen_->LoadCurrentMethod(out);
3662 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3663 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003664
3665 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
3666 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3667 codegen_->AddSlowPath(slow_path);
3668 __ testl(out, out);
3669 __ j(kEqual, slow_path->GetEntryLabel());
3670 if (cls->MustGenerateClinitCheck()) {
3671 GenerateClassInitializationCheck(slow_path, out);
3672 } else {
3673 __ Bind(slow_path->GetExitLabel());
3674 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003675 }
3676}
3677
3678void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
3679 LocationSummary* locations =
3680 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3681 locations->SetInAt(0, Location::RequiresRegister());
3682 if (check->HasUses()) {
3683 locations->SetOut(Location::SameAsFirstInput());
3684 }
3685}
3686
3687void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003688 // We assume the class to not be null.
3689 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
3690 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003691 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003692 GenerateClassInitializationCheck(slow_path,
3693 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003694}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003695
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003696void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
3697 SlowPathCodeX86* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003698 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3699 Immediate(mirror::Class::kStatusInitialized));
3700 __ j(kLess, slow_path->GetEntryLabel());
3701 __ Bind(slow_path->GetExitLabel());
3702 // No need for memory fence, thanks to the X86 memory model.
3703}
3704
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003705void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
3706 LocationSummary* locations =
3707 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3708 locations->SetOut(Location::RequiresRegister());
3709}
3710
3711void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
3712 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
3713 codegen_->AddSlowPath(slow_path);
3714
Roland Levillain271ab9c2014-11-27 15:23:57 +00003715 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003716 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08003717 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3718 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003719 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3720 __ testl(out, out);
3721 __ j(kEqual, slow_path->GetEntryLabel());
3722 __ Bind(slow_path->GetExitLabel());
3723}
3724
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003725void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
3726 LocationSummary* locations =
3727 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3728 locations->SetOut(Location::RequiresRegister());
3729}
3730
3731void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
3732 Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003733 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003734 __ fs()->movl(address, Immediate(0));
3735}
3736
3737void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
3738 LocationSummary* locations =
3739 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3740 InvokeRuntimeCallingConvention calling_convention;
3741 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3742}
3743
3744void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
3745 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
3746 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3747}
3748
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003749void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003750 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3751 ? LocationSummary::kNoCall
3752 : LocationSummary::kCallOnSlowPath;
3753 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3754 locations->SetInAt(0, Location::RequiresRegister());
3755 locations->SetInAt(1, Location::Any());
3756 locations->SetOut(Location::RequiresRegister());
3757}
3758
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003759void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003760 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003761 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003762 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003763 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003764 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3765 Label done, zero;
3766 SlowPathCodeX86* slow_path = nullptr;
3767
3768 // Return 0 if `obj` is null.
3769 // TODO: avoid this check if we know obj is not null.
3770 __ testl(obj, obj);
3771 __ j(kEqual, &zero);
3772 __ movl(out, Address(obj, class_offset));
3773 // Compare the class of `obj` with `cls`.
3774 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003775 __ cmpl(out, cls.AsRegister<Register>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003776 } else {
3777 DCHECK(cls.IsStackSlot()) << cls;
3778 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
3779 }
3780
3781 if (instruction->IsClassFinal()) {
3782 // Classes must be equal for the instanceof to succeed.
3783 __ j(kNotEqual, &zero);
3784 __ movl(out, Immediate(1));
3785 __ jmp(&done);
3786 } else {
3787 // If the classes are not equal, we go into a slow path.
3788 DCHECK(locations->OnlyCallsOnSlowPath());
3789 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003790 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003791 codegen_->AddSlowPath(slow_path);
3792 __ j(kNotEqual, slow_path->GetEntryLabel());
3793 __ movl(out, Immediate(1));
3794 __ jmp(&done);
3795 }
3796 __ Bind(&zero);
3797 __ movl(out, Immediate(0));
3798 if (slow_path != nullptr) {
3799 __ Bind(slow_path->GetExitLabel());
3800 }
3801 __ Bind(&done);
3802}
3803
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003804void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
3805 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3806 instruction, LocationSummary::kCallOnSlowPath);
3807 locations->SetInAt(0, Location::RequiresRegister());
3808 locations->SetInAt(1, Location::Any());
3809 locations->AddTemp(Location::RequiresRegister());
3810}
3811
3812void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
3813 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003814 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003815 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003816 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003817 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3818 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
3819 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
3820 codegen_->AddSlowPath(slow_path);
3821
3822 // TODO: avoid this check if we know obj is not null.
3823 __ testl(obj, obj);
3824 __ j(kEqual, slow_path->GetExitLabel());
3825 __ movl(temp, Address(obj, class_offset));
3826
3827 // Compare the class of `obj` with `cls`.
3828 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003829 __ cmpl(temp, cls.AsRegister<Register>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003830 } else {
3831 DCHECK(cls.IsStackSlot()) << cls;
3832 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
3833 }
3834
3835 __ j(kNotEqual, slow_path->GetEntryLabel());
3836 __ Bind(slow_path->GetExitLabel());
3837}
3838
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00003839void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
3840 LocationSummary* locations =
3841 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3842 InvokeRuntimeCallingConvention calling_convention;
3843 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3844}
3845
3846void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
3847 __ fs()->call(Address::Absolute(instruction->IsEnter()
3848 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject)
3849 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject)));
3850 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3851}
3852
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003853void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
3854void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
3855void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
3856
3857void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
3858 LocationSummary* locations =
3859 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3860 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
3861 || instruction->GetResultType() == Primitive::kPrimLong);
3862 locations->SetInAt(0, Location::RequiresRegister());
3863 locations->SetInAt(1, Location::Any());
3864 locations->SetOut(Location::SameAsFirstInput());
3865}
3866
3867void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
3868 HandleBitwiseOperation(instruction);
3869}
3870
3871void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
3872 HandleBitwiseOperation(instruction);
3873}
3874
3875void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
3876 HandleBitwiseOperation(instruction);
3877}
3878
3879void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
3880 LocationSummary* locations = instruction->GetLocations();
3881 Location first = locations->InAt(0);
3882 Location second = locations->InAt(1);
3883 DCHECK(first.Equals(locations->Out()));
3884
3885 if (instruction->GetResultType() == Primitive::kPrimInt) {
3886 if (second.IsRegister()) {
3887 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003888 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003889 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003890 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003891 } else {
3892 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003893 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003894 }
3895 } else if (second.IsConstant()) {
3896 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003897 __ andl(first.AsRegister<Register>(),
3898 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003899 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003900 __ orl(first.AsRegister<Register>(),
3901 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003902 } else {
3903 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00003904 __ xorl(first.AsRegister<Register>(),
3905 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003906 }
3907 } else {
3908 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003909 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003910 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003911 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003912 } else {
3913 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003914 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00003915 }
3916 }
3917 } else {
3918 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
3919 if (second.IsRegisterPair()) {
3920 if (instruction->IsAnd()) {
3921 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
3922 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
3923 } else if (instruction->IsOr()) {
3924 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
3925 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
3926 } else {
3927 DCHECK(instruction->IsXor());
3928 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
3929 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
3930 }
3931 } else {
3932 if (instruction->IsAnd()) {
3933 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
3934 __ andl(first.AsRegisterPairHigh<Register>(),
3935 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
3936 } else if (instruction->IsOr()) {
3937 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
3938 __ orl(first.AsRegisterPairHigh<Register>(),
3939 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
3940 } else {
3941 DCHECK(instruction->IsXor());
3942 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
3943 __ xorl(first.AsRegisterPairHigh<Register>(),
3944 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
3945 }
3946 }
3947 }
3948}
3949
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00003950} // namespace x86
3951} // namespace art