blob: b18cdd5cde66da80cc00e305596b042a329e4344 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_x86.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010018
19#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +000020#include "entrypoints/quick/quick_entrypoints_enum.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010021#include "gc/accounting/card_table.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040022#include "intrinsics.h"
23#include "intrinsics_x86.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070024#include "mirror/array-inl.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010025#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010026#include "mirror/class.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010027#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000028#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010029#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000030#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010031#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010034
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace x86 {
36
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010037static constexpr int kCurrentMethodStackOffset = 0;
38
Calin Juravled6fb6cf2014-11-11 19:07:44 +000039static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX, EBX };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010040static constexpr size_t kRuntimeParameterCoreRegistersLength =
41 arraysize(kRuntimeParameterCoreRegisters);
Mark Mendell5f874182015-03-04 15:42:45 -050042static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
Mark P Mendell966c3ae2015-01-27 15:45:27 +000043static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { XMM0, XMM1, XMM2, XMM3 };
44static constexpr size_t kRuntimeParameterFpuRegistersLength =
45 arraysize(kRuntimeParameterFpuRegisters);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010046
Mark Mendell24f2dfa2015-01-14 19:51:45 -050047static constexpr int kC2ConditionMask = 0x400;
48
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000049static constexpr int kFakeReturnRegister = Register(8);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +000050
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010051class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010052 public:
53 InvokeRuntimeCallingConvention()
54 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010055 kRuntimeParameterCoreRegistersLength,
56 kRuntimeParameterFpuRegisters,
57 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010058
59 private:
60 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
61};
62
Nicolas Geoffraye5038322014-07-04 09:41:32 +010063#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
64
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010065class NullCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010066 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010067 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010068
Alexandre Rames2ed20af2015-03-06 13:55:35 +000069 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010070 __ Bind(GetEntryLabel());
71 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
Nicolas Geoffray39468442014-09-02 15:17:15 +010072 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010073 }
74
75 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010076 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010077 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
78};
79
Calin Juravled0d48522014-11-04 16:40:20 +000080class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
81 public:
82 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
83
Alexandre Rames2ed20af2015-03-06 13:55:35 +000084 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000085 __ Bind(GetEntryLabel());
86 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
87 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
88 }
89
90 private:
91 HDivZeroCheck* const instruction_;
92 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
93};
94
Calin Juravlebacfec32014-11-14 15:54:36 +000095class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 {
Calin Juravled0d48522014-11-04 16:40:20 +000096 public:
Calin Juravlebacfec32014-11-14 15:54:36 +000097 explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +000098
Alexandre Rames2ed20af2015-03-06 13:55:35 +000099 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +0000100 __ Bind(GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +0000101 if (is_div_) {
102 __ negl(reg_);
103 } else {
104 __ movl(reg_, Immediate(0));
105 }
Calin Juravled0d48522014-11-04 16:40:20 +0000106 __ jmp(GetExitLabel());
107 }
108
109 private:
110 Register reg_;
Calin Juravlebacfec32014-11-14 15:54:36 +0000111 bool is_div_;
112 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
Calin Juravled0d48522014-11-04 16:40:20 +0000113};
114
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100115class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100116 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100117 BoundsCheckSlowPathX86(HBoundsCheck* instruction,
118 Location index_location,
119 Location length_location)
Roland Levillain199f3362014-11-27 17:15:16 +0000120 : instruction_(instruction),
121 index_location_(index_location),
122 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100123
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000124 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100125 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100126 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000127 // We're moving two locations to locations that could overlap, so we need a parallel
128 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100129 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000130 x86_codegen->EmitParallelMoves(
131 index_location_,
132 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
133 length_location_,
134 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100135 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100136 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100137 }
138
139 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100140 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100141 const Location index_location_;
142 const Location length_location_;
143
144 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
145};
146
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100147class SuspendCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000148 public:
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000149 SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100150 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000151
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000152 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100153 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000154 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000155 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000156 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
157 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000158 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100159 if (successor_ == nullptr) {
160 __ jmp(GetReturnLabel());
161 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100162 __ jmp(x86_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100163 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000164 }
165
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100166 Label* GetReturnLabel() {
167 DCHECK(successor_ == nullptr);
168 return &return_label_;
169 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000170
171 private:
172 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100173 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000174 Label return_label_;
175
176 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
177};
178
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000179class LoadStringSlowPathX86 : public SlowPathCodeX86 {
180 public:
181 explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {}
182
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000183 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000184 LocationSummary* locations = instruction_->GetLocations();
185 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
186
187 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
188 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000189 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000190
191 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800192 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
193 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000194 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString)));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000195 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000196 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000197 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000198
199 __ jmp(GetExitLabel());
200 }
201
202 private:
203 HLoadString* const instruction_;
204
205 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
206};
207
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000208class LoadClassSlowPathX86 : public SlowPathCodeX86 {
209 public:
210 LoadClassSlowPathX86(HLoadClass* cls,
211 HInstruction* at,
212 uint32_t dex_pc,
213 bool do_clinit)
214 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
215 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
216 }
217
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000218 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000219 LocationSummary* locations = at_->GetLocations();
220 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
221 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000222 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000223
224 InvokeRuntimeCallingConvention calling_convention;
225 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
226 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
227 __ fs()->call(Address::Absolute(do_clinit_
228 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage)
229 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType)));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000230 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000231
232 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000233 Location out = locations->Out();
234 if (out.IsValid()) {
235 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
236 x86_codegen->Move32(out, Location::RegisterLocation(EAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000237 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000238
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000239 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000240 __ jmp(GetExitLabel());
241 }
242
243 private:
244 // The class this slow path will load.
245 HLoadClass* const cls_;
246
247 // The instruction where this slow path is happening.
248 // (Might be the load class or an initialization check).
249 HInstruction* const at_;
250
251 // The dex PC of `at_`.
252 const uint32_t dex_pc_;
253
254 // Whether to initialize the class.
255 const bool do_clinit_;
256
257 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
258};
259
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000260class TypeCheckSlowPathX86 : public SlowPathCodeX86 {
261 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000262 TypeCheckSlowPathX86(HInstruction* instruction,
263 Location class_to_check,
264 Location object_class,
265 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000266 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000267 class_to_check_(class_to_check),
268 object_class_(object_class),
269 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000270
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000271 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000272 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000273 DCHECK(instruction_->IsCheckCast()
274 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000275
276 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
277 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000278 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000279
280 // We're moving two locations to locations that could overlap, so we need a parallel
281 // move resolver.
282 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000283 x86_codegen->EmitParallelMoves(
284 class_to_check_,
285 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
286 object_class_,
287 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000288
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000289 if (instruction_->IsInstanceOf()) {
Roland Levillain199f3362014-11-27 17:15:16 +0000290 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize,
291 pInstanceofNonTrivial)));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000292 } else {
293 DCHECK(instruction_->IsCheckCast());
294 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast)));
295 }
296
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000297 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000298 if (instruction_->IsInstanceOf()) {
299 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
300 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000301 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000302
303 __ jmp(GetExitLabel());
304 }
305
306 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000307 HInstruction* const instruction_;
308 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000309 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000310 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000311
312 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
313};
314
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100315#undef __
316#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
317
Dave Allison20dfc792014-06-16 20:44:29 -0700318inline Condition X86Condition(IfCondition cond) {
319 switch (cond) {
320 case kCondEQ: return kEqual;
321 case kCondNE: return kNotEqual;
322 case kCondLT: return kLess;
323 case kCondLE: return kLessEqual;
324 case kCondGT: return kGreater;
325 case kCondGE: return kGreaterEqual;
326 default:
327 LOG(FATAL) << "Unknown if condition";
328 }
329 return kEqual;
330}
331
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100332void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
333 stream << X86ManagedRegister::FromCpuRegister(Register(reg));
334}
335
336void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
337 stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
338}
339
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100340size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
341 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
342 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100343}
344
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100345size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
346 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
347 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100348}
349
Mark Mendell7c8d0092015-01-26 11:21:33 -0500350size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
351 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
352 return GetFloatingPointSpillSlotSize();
353}
354
355size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
356 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
357 return GetFloatingPointSpillSlotSize();
358}
359
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000360CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options)
Mark Mendell5f874182015-03-04 15:42:45 -0500361 : CodeGenerator(graph,
362 kNumberOfCpuRegisters,
363 kNumberOfXmmRegisters,
364 kNumberOfRegisterPairs,
365 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
366 arraysize(kCoreCalleeSaves))
367 | (1 << kFakeReturnRegister),
368 0,
369 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100370 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100371 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100372 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000373 move_resolver_(graph->GetArena(), this) {
374 // Use a fake return address register to mimic Quick.
375 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100376}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100377
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100378Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100379 switch (type) {
380 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100381 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100382 X86ManagedRegister pair =
383 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100384 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
385 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100386 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
387 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100388 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100389 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100390 }
391
392 case Primitive::kPrimByte:
393 case Primitive::kPrimBoolean:
394 case Primitive::kPrimChar:
395 case Primitive::kPrimShort:
396 case Primitive::kPrimInt:
397 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100398 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100399 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100400 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100401 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
402 X86ManagedRegister current =
403 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
404 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100405 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100406 }
407 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100408 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100409 }
410
411 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100412 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100413 return Location::FpuRegisterLocation(
414 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100415 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100416
417 case Primitive::kPrimVoid:
418 LOG(FATAL) << "Unreachable type " << type;
419 }
420
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100421 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100422}
423
Mark Mendell5f874182015-03-04 15:42:45 -0500424void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100425 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100426 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100427
428 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100429 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100430
Mark Mendell5f874182015-03-04 15:42:45 -0500431 if (is_baseline) {
432 blocked_core_registers_[EBP] = true;
433 blocked_core_registers_[ESI] = true;
434 blocked_core_registers_[EDI] = true;
435 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100436
437 UpdateBlockedPairRegisters();
438}
439
440void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
441 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
442 X86ManagedRegister current =
443 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
444 if (blocked_core_registers_[current.AsRegisterPairLow()]
445 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
446 blocked_register_pairs_[i] = true;
447 }
448 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100449}
450
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100451InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
452 : HGraphVisitor(graph),
453 assembler_(codegen->GetAssembler()),
454 codegen_(codegen) {}
455
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000456void CodeGeneratorX86::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000457 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000458 bool skip_overflow_check =
459 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000460 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000461
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000462 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100463 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100464 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100465 }
466
Mark Mendell5f874182015-03-04 15:42:45 -0500467 if (HasEmptyFrame()) {
468 return;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000469 }
Mark Mendell5f874182015-03-04 15:42:45 -0500470
471 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
472 Register reg = kCoreCalleeSaves[i];
473 if (allocated_registers_.ContainsCoreRegister(reg)) {
474 __ pushl(reg);
475 }
476 }
477
478 __ subl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize()));
479 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000480}
481
482void CodeGeneratorX86::GenerateFrameExit() {
Mark Mendell5f874182015-03-04 15:42:45 -0500483 if (HasEmptyFrame()) {
484 return;
485 }
486
487 __ addl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize()));
488
489 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
490 Register reg = kCoreCalleeSaves[i];
491 if (allocated_registers_.ContainsCoreRegister(reg)) {
492 __ popl(reg);
493 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000494 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000495}
496
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100497void CodeGeneratorX86::Bind(HBasicBlock* block) {
498 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000499}
500
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100501void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000502 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100503 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000504}
505
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100506Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
507 switch (load->GetType()) {
508 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100509 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100510 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
511 break;
512
513 case Primitive::kPrimInt:
514 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100515 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100516 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100517
518 case Primitive::kPrimBoolean:
519 case Primitive::kPrimByte:
520 case Primitive::kPrimChar:
521 case Primitive::kPrimShort:
522 case Primitive::kPrimVoid:
523 LOG(FATAL) << "Unexpected type " << load->GetType();
524 }
525
526 LOG(FATAL) << "Unreachable";
527 return Location();
528}
529
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100530Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
531 switch (type) {
532 case Primitive::kPrimBoolean:
533 case Primitive::kPrimByte:
534 case Primitive::kPrimChar:
535 case Primitive::kPrimShort:
536 case Primitive::kPrimInt:
537 case Primitive::kPrimNot: {
538 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000539 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100540 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100541 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100542 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000543 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100544 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100545 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100546
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000547 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100548 uint32_t index = gp_index_;
549 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000550 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100551 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100552 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
553 calling_convention.GetRegisterPairAt(index));
554 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100555 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000556 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
557 }
558 }
559
560 case Primitive::kPrimFloat: {
561 uint32_t index = fp_index_++;
562 stack_index_++;
563 if (index < calling_convention.GetNumberOfFpuRegisters()) {
564 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
565 } else {
566 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
567 }
568 }
569
570 case Primitive::kPrimDouble: {
571 uint32_t index = fp_index_++;
572 stack_index_ += 2;
573 if (index < calling_convention.GetNumberOfFpuRegisters()) {
574 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
575 } else {
576 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100577 }
578 }
579
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100580 case Primitive::kPrimVoid:
581 LOG(FATAL) << "Unexpected parameter type " << type;
582 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100583 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100584 return Location();
585}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100586
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100587void CodeGeneratorX86::Move32(Location destination, Location source) {
588 if (source.Equals(destination)) {
589 return;
590 }
591 if (destination.IsRegister()) {
592 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000593 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100594 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000595 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100596 } else {
597 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000598 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100599 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100600 } else if (destination.IsFpuRegister()) {
601 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000602 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100603 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000604 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100605 } else {
606 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000607 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100608 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100609 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000610 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100611 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000612 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100613 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000614 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500615 } else if (source.IsConstant()) {
616 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000617 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -0500618 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100619 } else {
620 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100621 __ pushl(Address(ESP, source.GetStackIndex()));
622 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100623 }
624 }
625}
626
627void CodeGeneratorX86::Move64(Location destination, Location source) {
628 if (source.Equals(destination)) {
629 return;
630 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100631 if (destination.IsRegisterPair()) {
632 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000633 EmitParallelMoves(
634 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
635 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
636 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
637 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100638 } else if (source.IsFpuRegister()) {
639 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100640 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000641 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100642 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100643 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
644 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100645 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
646 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100647 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500648 if (source.IsFpuRegister()) {
649 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
650 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000651 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100652 } else {
653 LOG(FATAL) << "Unimplemented";
654 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100655 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000656 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100657 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000658 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100659 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100660 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100661 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100662 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000663 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000664 } else if (source.IsConstant()) {
665 HConstant* constant = source.GetConstant();
666 int64_t value;
667 if (constant->IsLongConstant()) {
668 value = constant->AsLongConstant()->GetValue();
669 } else {
670 DCHECK(constant->IsDoubleConstant());
Roland Levillainda4d79b2015-03-24 14:36:11 +0000671 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000672 }
673 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
674 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100675 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000676 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000677 EmitParallelMoves(
678 Location::StackSlot(source.GetStackIndex()),
679 Location::StackSlot(destination.GetStackIndex()),
680 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
681 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100682 }
683 }
684}
685
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100686void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000687 LocationSummary* locations = instruction->GetLocations();
688 if (locations != nullptr && locations->Out().Equals(location)) {
689 return;
690 }
691
692 if (locations != nullptr && locations->Out().IsConstant()) {
693 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000694 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
695 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000696 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000697 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000698 } else if (location.IsStackSlot()) {
699 __ movl(Address(ESP, location.GetStackIndex()), imm);
700 } else {
701 DCHECK(location.IsConstant());
702 DCHECK_EQ(location.GetConstant(), const_to_move);
703 }
704 } else if (const_to_move->IsLongConstant()) {
705 int64_t value = const_to_move->AsLongConstant()->GetValue();
706 if (location.IsRegisterPair()) {
707 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
708 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
709 } else if (location.IsDoubleStackSlot()) {
710 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000711 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
712 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000713 } else {
714 DCHECK(location.IsConstant());
715 DCHECK_EQ(location.GetConstant(), instruction);
716 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100717 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000718 } else if (instruction->IsTemporary()) {
719 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000720 if (temp_location.IsStackSlot()) {
721 Move32(location, temp_location);
722 } else {
723 DCHECK(temp_location.IsDoubleStackSlot());
724 Move64(location, temp_location);
725 }
Roland Levillain476df552014-10-09 17:51:36 +0100726 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100727 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100728 switch (instruction->GetType()) {
729 case Primitive::kPrimBoolean:
730 case Primitive::kPrimByte:
731 case Primitive::kPrimChar:
732 case Primitive::kPrimShort:
733 case Primitive::kPrimInt:
734 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100735 case Primitive::kPrimFloat:
736 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100737 break;
738
739 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100740 case Primitive::kPrimDouble:
741 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100742 break;
743
744 default:
745 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
746 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000747 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100748 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100749 switch (instruction->GetType()) {
750 case Primitive::kPrimBoolean:
751 case Primitive::kPrimByte:
752 case Primitive::kPrimChar:
753 case Primitive::kPrimShort:
754 case Primitive::kPrimInt:
755 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100756 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000757 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100758 break;
759
760 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100761 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000762 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100763 break;
764
765 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100766 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100767 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000768 }
769}
770
771void LocationsBuilderX86::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000772 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000773}
774
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000775void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000776 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100777 DCHECK(!successor->IsExitBlock());
778
779 HBasicBlock* block = got->GetBlock();
780 HInstruction* previous = got->GetPrevious();
781
782 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000783 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100784 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
785 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
786 return;
787 }
788
789 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
790 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
791 }
792 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000793 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000794 }
795}
796
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000797void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000798 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000799}
800
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000801void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700802 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000803}
804
Andreas Gampe0ba62732015-03-24 02:39:46 +0000805void LocationsBuilderX86::VisitIf(HIf* if_instr) {
806 LocationSummary* locations =
807 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
808 HInstruction* cond = if_instr->InputAt(0);
809 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
810 locations->SetInAt(0, Location::Any());
811 }
812}
813
814void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
815 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100816 if (cond->IsIntConstant()) {
817 // Constant condition, statically compared against 1.
818 int32_t cond_value = cond->AsIntConstant()->GetValue();
819 if (cond_value == 1) {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000820 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
821 if_instr->IfTrueSuccessor())) {
822 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100823 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100824 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100825 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100826 DCHECK_EQ(cond_value, 0);
827 }
828 } else {
829 bool materialized =
830 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
831 // Moves do not affect the eflags register, so if the condition is
832 // evaluated just before the if, we don't need to evaluate it
833 // again.
834 bool eflags_set = cond->IsCondition()
Andreas Gampe0ba62732015-03-24 02:39:46 +0000835 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100836 if (materialized) {
837 if (!eflags_set) {
838 // Materialized condition, compare against 0.
Andreas Gampe0ba62732015-03-24 02:39:46 +0000839 Location lhs = if_instr->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100840 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -0500841 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100842 } else {
843 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
844 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000845 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100846 } else {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000847 __ j(X86Condition(cond->AsCondition()->GetCondition()),
848 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100849 }
850 } else {
851 Location lhs = cond->GetLocations()->InAt(0);
852 Location rhs = cond->GetLocations()->InAt(1);
853 // LHS is guaranteed to be in a register (see
854 // LocationsBuilderX86::VisitCondition).
855 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000856 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100857 } else if (rhs.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -0500858 int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue();
859 if (constant == 0) {
860 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
861 } else {
862 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
863 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100864 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000865 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100866 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000867 __ j(X86Condition(cond->AsCondition()->GetCondition()),
868 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700869 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100870 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000871 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
872 if_instr->IfFalseSuccessor())) {
873 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000874 }
875}
876
877void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000878 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000879}
880
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000881void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
882 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000883}
884
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000885void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100886 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000887}
888
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000889void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100890 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700891 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000892}
893
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100894void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100895 LocationSummary* locations =
896 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100897 switch (store->InputAt(1)->GetType()) {
898 case Primitive::kPrimBoolean:
899 case Primitive::kPrimByte:
900 case Primitive::kPrimChar:
901 case Primitive::kPrimShort:
902 case Primitive::kPrimInt:
903 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100904 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100905 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
906 break;
907
908 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100909 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100910 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
911 break;
912
913 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100914 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100915 }
916 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000917}
918
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000919void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700920 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000921}
922
Dave Allison20dfc792014-06-16 20:44:29 -0700923void LocationsBuilderX86::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100924 LocationSummary* locations =
925 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100926 locations->SetInAt(0, Location::RequiresRegister());
927 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100928 if (comp->NeedsMaterialization()) {
Mark Mendell5f874182015-03-04 15:42:45 -0500929 // We need a byte register.
930 locations->SetOut(Location::RegisterLocation(ECX));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100931 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000932}
933
Dave Allison20dfc792014-06-16 20:44:29 -0700934void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
935 if (comp->NeedsMaterialization()) {
936 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000937 Register reg = locations->Out().AsRegister<Register>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100938 // Clear register: setcc only sets the low byte.
939 __ xorl(reg, reg);
Mark Mendell09b84632015-02-13 17:48:38 -0500940 Location lhs = locations->InAt(0);
941 Location rhs = locations->InAt(1);
942 if (rhs.IsRegister()) {
943 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
944 } else if (rhs.IsConstant()) {
Mingyao Yang8928cab2015-03-03 16:15:23 -0800945 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -0500946 if (constant == 0) {
947 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
948 } else {
949 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
950 }
Dave Allison20dfc792014-06-16 20:44:29 -0700951 } else {
Mark Mendell09b84632015-02-13 17:48:38 -0500952 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Dave Allison20dfc792014-06-16 20:44:29 -0700953 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000954 __ setb(X86Condition(comp->GetCondition()), reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100955 }
Dave Allison20dfc792014-06-16 20:44:29 -0700956}
957
958void LocationsBuilderX86::VisitEqual(HEqual* comp) {
959 VisitCondition(comp);
960}
961
962void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
963 VisitCondition(comp);
964}
965
966void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
967 VisitCondition(comp);
968}
969
970void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
971 VisitCondition(comp);
972}
973
974void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
975 VisitCondition(comp);
976}
977
978void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
979 VisitCondition(comp);
980}
981
982void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
983 VisitCondition(comp);
984}
985
986void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
987 VisitCondition(comp);
988}
989
990void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
991 VisitCondition(comp);
992}
993
994void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
995 VisitCondition(comp);
996}
997
998void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
999 VisitCondition(comp);
1000}
1001
1002void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
1003 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001004}
1005
1006void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001007 LocationSummary* locations =
1008 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001009 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001010}
1011
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001012void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +01001013 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001014 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001015}
1016
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001017void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1018 LocationSummary* locations =
1019 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1020 locations->SetOut(Location::ConstantLocation(constant));
1021}
1022
1023void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1024 // Will be generated at use site.
1025 UNUSED(constant);
1026}
1027
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001028void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001029 LocationSummary* locations =
1030 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001031 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001032}
1033
1034void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1035 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001036 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001037}
1038
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001039void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1040 LocationSummary* locations =
1041 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1042 locations->SetOut(Location::ConstantLocation(constant));
1043}
1044
1045void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1046 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001047 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001048}
1049
1050void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1051 LocationSummary* locations =
1052 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1053 locations->SetOut(Location::ConstantLocation(constant));
1054}
1055
1056void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1057 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001058 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001059}
1060
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001061void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001062 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001063}
1064
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001065void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001066 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001067 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001068 __ ret();
1069}
1070
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001071void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001072 LocationSummary* locations =
1073 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001074 switch (ret->InputAt(0)->GetType()) {
1075 case Primitive::kPrimBoolean:
1076 case Primitive::kPrimByte:
1077 case Primitive::kPrimChar:
1078 case Primitive::kPrimShort:
1079 case Primitive::kPrimInt:
1080 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001081 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001082 break;
1083
1084 case Primitive::kPrimLong:
1085 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001086 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001087 break;
1088
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001089 case Primitive::kPrimFloat:
1090 case Primitive::kPrimDouble:
1091 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001092 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001093 break;
1094
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001095 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001096 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001097 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001098}
1099
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001100void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001101 if (kIsDebugBuild) {
1102 switch (ret->InputAt(0)->GetType()) {
1103 case Primitive::kPrimBoolean:
1104 case Primitive::kPrimByte:
1105 case Primitive::kPrimChar:
1106 case Primitive::kPrimShort:
1107 case Primitive::kPrimInt:
1108 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001109 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001110 break;
1111
1112 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001113 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1114 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001115 break;
1116
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001117 case Primitive::kPrimFloat:
1118 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001119 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001120 break;
1121
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001122 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001123 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001124 }
1125 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001126 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001127 __ ret();
1128}
1129
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001130void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendell09ed1a32015-03-25 08:30:06 -04001131 IntrinsicLocationsBuilderX86 intrinsic(GetGraph()->GetArena());
1132 if (intrinsic.TryDispatch(invoke)) {
1133 return;
1134 }
1135
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001136 HandleInvoke(invoke);
1137}
1138
Mark Mendell09ed1a32015-03-25 08:30:06 -04001139static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1140 if (invoke->GetLocations()->Intrinsified()) {
1141 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1142 intrinsic.Dispatch(invoke);
1143 return true;
1144 }
1145 return false;
1146}
1147
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001148void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendell09ed1a32015-03-25 08:30:06 -04001149 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1150 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001151 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001152
Mark Mendell09ed1a32015-03-25 08:30:06 -04001153 codegen_->GenerateStaticOrDirectCall(
1154 invoke, invoke->GetLocations()->GetTemp(0).AsRegister<Register>());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001155}
1156
1157void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1158 HandleInvoke(invoke);
1159}
1160
1161void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001162 LocationSummary* locations =
1163 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001164 locations->AddTemp(Location::RegisterLocation(EAX));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001165
1166 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001167 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001168 HInstruction* input = invoke->InputAt(i);
1169 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1170 }
1171
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001172 switch (invoke->GetType()) {
1173 case Primitive::kPrimBoolean:
1174 case Primitive::kPrimByte:
1175 case Primitive::kPrimChar:
1176 case Primitive::kPrimShort:
1177 case Primitive::kPrimInt:
1178 case Primitive::kPrimNot:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001179 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001180 break;
1181
1182 case Primitive::kPrimLong:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001183 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001184 break;
1185
1186 case Primitive::kPrimVoid:
1187 break;
1188
1189 case Primitive::kPrimDouble:
1190 case Primitive::kPrimFloat:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001191 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001192 break;
1193 }
1194
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001195 invoke->SetLocations(locations);
1196}
1197
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001198void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001199 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001200 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1201 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1202 LocationSummary* locations = invoke->GetLocations();
1203 Location receiver = locations->InAt(0);
1204 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1205 // temp = object->GetClass();
1206 if (receiver.IsStackSlot()) {
1207 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1208 __ movl(temp, Address(temp, class_offset));
1209 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001210 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001211 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001212 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001213 // temp = temp->GetMethodAt(method_offset);
1214 __ movl(temp, Address(temp, method_offset));
1215 // call temp->GetEntryPoint();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001216 __ call(Address(
1217 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001218
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001219 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001220 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001221}
1222
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001223void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1224 HandleInvoke(invoke);
1225 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001226 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001227}
1228
1229void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1230 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001231 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001232 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1233 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1234 LocationSummary* locations = invoke->GetLocations();
1235 Location receiver = locations->InAt(0);
1236 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1237
1238 // Set the hidden argument.
1239 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001240 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001241
1242 // temp = object->GetClass();
1243 if (receiver.IsStackSlot()) {
1244 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1245 __ movl(temp, Address(temp, class_offset));
1246 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001247 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001248 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001249 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001250 // temp = temp->GetImtEntryAt(method_offset);
1251 __ movl(temp, Address(temp, method_offset));
1252 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001253 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001254 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001255
1256 DCHECK(!codegen_->IsLeafMethod());
1257 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1258}
1259
Roland Levillain88cb1752014-10-20 16:36:47 +01001260void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1261 LocationSummary* locations =
1262 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1263 switch (neg->GetResultType()) {
1264 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001265 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001266 locations->SetInAt(0, Location::RequiresRegister());
1267 locations->SetOut(Location::SameAsFirstInput());
1268 break;
1269
Roland Levillain88cb1752014-10-20 16:36:47 +01001270 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001271 locations->SetInAt(0, Location::RequiresFpuRegister());
1272 locations->SetOut(Location::SameAsFirstInput());
1273 locations->AddTemp(Location::RequiresRegister());
1274 locations->AddTemp(Location::RequiresFpuRegister());
1275 break;
1276
Roland Levillain88cb1752014-10-20 16:36:47 +01001277 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001278 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001279 locations->SetOut(Location::SameAsFirstInput());
1280 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001281 break;
1282
1283 default:
1284 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1285 }
1286}
1287
1288void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1289 LocationSummary* locations = neg->GetLocations();
1290 Location out = locations->Out();
1291 Location in = locations->InAt(0);
1292 switch (neg->GetResultType()) {
1293 case Primitive::kPrimInt:
1294 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001295 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001296 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001297 break;
1298
1299 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001300 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001301 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001302 __ negl(out.AsRegisterPairLow<Register>());
1303 // Negation is similar to subtraction from zero. The least
1304 // significant byte triggers a borrow when it is different from
1305 // zero; to take it into account, add 1 to the most significant
1306 // byte if the carry flag (CF) is set to 1 after the first NEGL
1307 // operation.
1308 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1309 __ negl(out.AsRegisterPairHigh<Register>());
1310 break;
1311
Roland Levillain5368c212014-11-27 15:03:41 +00001312 case Primitive::kPrimFloat: {
1313 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001314 Register constant = locations->GetTemp(0).AsRegister<Register>();
1315 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001316 // Implement float negation with an exclusive or with value
1317 // 0x80000000 (mask for bit 31, representing the sign of a
1318 // single-precision floating-point number).
1319 __ movl(constant, Immediate(INT32_C(0x80000000)));
1320 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001321 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001322 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001323 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001324
Roland Levillain5368c212014-11-27 15:03:41 +00001325 case Primitive::kPrimDouble: {
1326 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001327 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001328 // Implement double negation with an exclusive or with value
1329 // 0x8000000000000000 (mask for bit 63, representing the sign of
1330 // a double-precision floating-point number).
1331 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001332 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001333 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001334 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001335
1336 default:
1337 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1338 }
1339}
1340
Roland Levillaindff1f282014-11-05 14:15:05 +00001341void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001342 Primitive::Type result_type = conversion->GetResultType();
1343 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001344 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001345
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001346 // The float-to-long and double-to-long type conversions rely on a
1347 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001348 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001349 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1350 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001351 ? LocationSummary::kCall
1352 : LocationSummary::kNoCall;
1353 LocationSummary* locations =
1354 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1355
David Brazdilb2bd1c52015-03-25 11:17:37 +00001356 // The Java language does not allow treating boolean as an integral type but
1357 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001358
Roland Levillaindff1f282014-11-05 14:15:05 +00001359 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001360 case Primitive::kPrimByte:
1361 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001362 case Primitive::kPrimBoolean:
1363 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001364 case Primitive::kPrimShort:
1365 case Primitive::kPrimInt:
1366 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001367 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001368 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1369 // Make the output overlap to please the register allocator. This greatly simplifies
1370 // the validation of the linear scan implementation
1371 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001372 break;
1373
1374 default:
1375 LOG(FATAL) << "Unexpected type conversion from " << input_type
1376 << " to " << result_type;
1377 }
1378 break;
1379
Roland Levillain01a8d712014-11-14 16:27:39 +00001380 case Primitive::kPrimShort:
1381 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001382 case Primitive::kPrimBoolean:
1383 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001384 case Primitive::kPrimByte:
1385 case Primitive::kPrimInt:
1386 case Primitive::kPrimChar:
1387 // Processing a Dex `int-to-short' instruction.
1388 locations->SetInAt(0, Location::Any());
1389 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1390 break;
1391
1392 default:
1393 LOG(FATAL) << "Unexpected type conversion from " << input_type
1394 << " to " << result_type;
1395 }
1396 break;
1397
Roland Levillain946e1432014-11-11 17:35:19 +00001398 case Primitive::kPrimInt:
1399 switch (input_type) {
1400 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001401 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001402 locations->SetInAt(0, Location::Any());
1403 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1404 break;
1405
1406 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001407 // Processing a Dex `float-to-int' instruction.
1408 locations->SetInAt(0, Location::RequiresFpuRegister());
1409 locations->SetOut(Location::RequiresRegister());
1410 locations->AddTemp(Location::RequiresFpuRegister());
1411 break;
1412
Roland Levillain946e1432014-11-11 17:35:19 +00001413 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001414 // Processing a Dex `double-to-int' instruction.
1415 locations->SetInAt(0, Location::RequiresFpuRegister());
1416 locations->SetOut(Location::RequiresRegister());
1417 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001418 break;
1419
1420 default:
1421 LOG(FATAL) << "Unexpected type conversion from " << input_type
1422 << " to " << result_type;
1423 }
1424 break;
1425
Roland Levillaindff1f282014-11-05 14:15:05 +00001426 case Primitive::kPrimLong:
1427 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001428 case Primitive::kPrimBoolean:
1429 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001430 case Primitive::kPrimByte:
1431 case Primitive::kPrimShort:
1432 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001433 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001434 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001435 locations->SetInAt(0, Location::RegisterLocation(EAX));
1436 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1437 break;
1438
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001439 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001440 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001441 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001442 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001443 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1444 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1445
Vladimir Marko949c91f2015-01-27 10:48:44 +00001446 // The runtime helper puts the result in EAX, EDX.
1447 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001448 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001449 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001450
1451 default:
1452 LOG(FATAL) << "Unexpected type conversion from " << input_type
1453 << " to " << result_type;
1454 }
1455 break;
1456
Roland Levillain981e4542014-11-14 11:47:14 +00001457 case Primitive::kPrimChar:
1458 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001459 case Primitive::kPrimBoolean:
1460 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001461 case Primitive::kPrimByte:
1462 case Primitive::kPrimShort:
1463 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001464 // Processing a Dex `int-to-char' instruction.
1465 locations->SetInAt(0, Location::Any());
1466 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1467 break;
1468
1469 default:
1470 LOG(FATAL) << "Unexpected type conversion from " << input_type
1471 << " to " << result_type;
1472 }
1473 break;
1474
Roland Levillaindff1f282014-11-05 14:15:05 +00001475 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001476 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001477 case Primitive::kPrimBoolean:
1478 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001479 case Primitive::kPrimByte:
1480 case Primitive::kPrimShort:
1481 case Primitive::kPrimInt:
1482 case Primitive::kPrimChar:
1483 // Processing a Dex `int-to-float' instruction.
1484 locations->SetInAt(0, Location::RequiresRegister());
1485 locations->SetOut(Location::RequiresFpuRegister());
1486 break;
1487
1488 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001489 // Processing a Dex `long-to-float' instruction.
1490 locations->SetInAt(0, Location::RequiresRegister());
1491 locations->SetOut(Location::RequiresFpuRegister());
1492 locations->AddTemp(Location::RequiresFpuRegister());
1493 locations->AddTemp(Location::RequiresFpuRegister());
1494 break;
1495
Roland Levillaincff13742014-11-17 14:32:17 +00001496 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001497 // Processing a Dex `double-to-float' instruction.
1498 locations->SetInAt(0, Location::RequiresFpuRegister());
1499 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001500 break;
1501
1502 default:
1503 LOG(FATAL) << "Unexpected type conversion from " << input_type
1504 << " to " << result_type;
1505 };
1506 break;
1507
Roland Levillaindff1f282014-11-05 14:15:05 +00001508 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001509 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001510 case Primitive::kPrimBoolean:
1511 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001512 case Primitive::kPrimByte:
1513 case Primitive::kPrimShort:
1514 case Primitive::kPrimInt:
1515 case Primitive::kPrimChar:
1516 // Processing a Dex `int-to-double' instruction.
1517 locations->SetInAt(0, Location::RequiresRegister());
1518 locations->SetOut(Location::RequiresFpuRegister());
1519 break;
1520
1521 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001522 // Processing a Dex `long-to-double' instruction.
1523 locations->SetInAt(0, Location::RequiresRegister());
1524 locations->SetOut(Location::RequiresFpuRegister());
1525 locations->AddTemp(Location::RequiresFpuRegister());
1526 locations->AddTemp(Location::RequiresFpuRegister());
1527 break;
1528
Roland Levillaincff13742014-11-17 14:32:17 +00001529 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001530 // Processing a Dex `float-to-double' instruction.
1531 locations->SetInAt(0, Location::RequiresFpuRegister());
1532 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001533 break;
1534
1535 default:
1536 LOG(FATAL) << "Unexpected type conversion from " << input_type
1537 << " to " << result_type;
1538 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001539 break;
1540
1541 default:
1542 LOG(FATAL) << "Unexpected type conversion from " << input_type
1543 << " to " << result_type;
1544 }
1545}
1546
1547void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
1548 LocationSummary* locations = conversion->GetLocations();
1549 Location out = locations->Out();
1550 Location in = locations->InAt(0);
1551 Primitive::Type result_type = conversion->GetResultType();
1552 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001553 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001554 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001555 case Primitive::kPrimByte:
1556 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001557 case Primitive::kPrimBoolean:
1558 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001559 case Primitive::kPrimShort:
1560 case Primitive::kPrimInt:
1561 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001562 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001563 if (in.IsRegister()) {
1564 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001565 } else {
1566 DCHECK(in.GetConstant()->IsIntConstant());
1567 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1568 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
1569 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00001570 break;
1571
1572 default:
1573 LOG(FATAL) << "Unexpected type conversion from " << input_type
1574 << " to " << result_type;
1575 }
1576 break;
1577
Roland Levillain01a8d712014-11-14 16:27:39 +00001578 case Primitive::kPrimShort:
1579 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001580 case Primitive::kPrimBoolean:
1581 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001582 case Primitive::kPrimByte:
1583 case Primitive::kPrimInt:
1584 case Primitive::kPrimChar:
1585 // Processing a Dex `int-to-short' instruction.
1586 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001587 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001588 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001589 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00001590 } else {
1591 DCHECK(in.GetConstant()->IsIntConstant());
1592 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001593 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00001594 }
1595 break;
1596
1597 default:
1598 LOG(FATAL) << "Unexpected type conversion from " << input_type
1599 << " to " << result_type;
1600 }
1601 break;
1602
Roland Levillain946e1432014-11-11 17:35:19 +00001603 case Primitive::kPrimInt:
1604 switch (input_type) {
1605 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001606 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001607 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001608 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001609 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001610 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00001611 } else {
1612 DCHECK(in.IsConstant());
1613 DCHECK(in.GetConstant()->IsLongConstant());
1614 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001615 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001616 }
1617 break;
1618
Roland Levillain3f8f9362014-12-02 17:45:01 +00001619 case Primitive::kPrimFloat: {
1620 // Processing a Dex `float-to-int' instruction.
1621 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1622 Register output = out.AsRegister<Register>();
1623 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1624 Label done, nan;
1625
1626 __ movl(output, Immediate(kPrimIntMax));
1627 // temp = int-to-float(output)
1628 __ cvtsi2ss(temp, output);
1629 // if input >= temp goto done
1630 __ comiss(input, temp);
1631 __ j(kAboveEqual, &done);
1632 // if input == NaN goto nan
1633 __ j(kUnordered, &nan);
1634 // output = float-to-int-truncate(input)
1635 __ cvttss2si(output, input);
1636 __ jmp(&done);
1637 __ Bind(&nan);
1638 // output = 0
1639 __ xorl(output, output);
1640 __ Bind(&done);
1641 break;
1642 }
1643
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001644 case Primitive::kPrimDouble: {
1645 // Processing a Dex `double-to-int' instruction.
1646 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1647 Register output = out.AsRegister<Register>();
1648 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1649 Label done, nan;
1650
1651 __ movl(output, Immediate(kPrimIntMax));
1652 // temp = int-to-double(output)
1653 __ cvtsi2sd(temp, output);
1654 // if input >= temp goto done
1655 __ comisd(input, temp);
1656 __ j(kAboveEqual, &done);
1657 // if input == NaN goto nan
1658 __ j(kUnordered, &nan);
1659 // output = double-to-int-truncate(input)
1660 __ cvttsd2si(output, input);
1661 __ jmp(&done);
1662 __ Bind(&nan);
1663 // output = 0
1664 __ xorl(output, output);
1665 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001666 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001667 }
Roland Levillain946e1432014-11-11 17:35:19 +00001668
1669 default:
1670 LOG(FATAL) << "Unexpected type conversion from " << input_type
1671 << " to " << result_type;
1672 }
1673 break;
1674
Roland Levillaindff1f282014-11-05 14:15:05 +00001675 case Primitive::kPrimLong:
1676 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001677 case Primitive::kPrimBoolean:
1678 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001679 case Primitive::kPrimByte:
1680 case Primitive::kPrimShort:
1681 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001682 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001683 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001684 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
1685 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001686 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00001687 __ cdq();
1688 break;
1689
1690 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001691 // Processing a Dex `float-to-long' instruction.
1692 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l)));
Roland Levillain624279f2014-12-04 11:54:28 +00001693 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
1694 break;
1695
Roland Levillaindff1f282014-11-05 14:15:05 +00001696 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001697 // Processing a Dex `double-to-long' instruction.
1698 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l)));
1699 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
Roland Levillaindff1f282014-11-05 14:15:05 +00001700 break;
1701
1702 default:
1703 LOG(FATAL) << "Unexpected type conversion from " << input_type
1704 << " to " << result_type;
1705 }
1706 break;
1707
Roland Levillain981e4542014-11-14 11:47:14 +00001708 case Primitive::kPrimChar:
1709 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001710 case Primitive::kPrimBoolean:
1711 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001712 case Primitive::kPrimByte:
1713 case Primitive::kPrimShort:
1714 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001715 // Processing a Dex `Process a Dex `int-to-char'' instruction.
1716 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001717 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00001718 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001719 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00001720 } else {
1721 DCHECK(in.GetConstant()->IsIntConstant());
1722 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001723 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00001724 }
1725 break;
1726
1727 default:
1728 LOG(FATAL) << "Unexpected type conversion from " << input_type
1729 << " to " << result_type;
1730 }
1731 break;
1732
Roland Levillaindff1f282014-11-05 14:15:05 +00001733 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001734 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001735 case Primitive::kPrimBoolean:
1736 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001737 case Primitive::kPrimByte:
1738 case Primitive::kPrimShort:
1739 case Primitive::kPrimInt:
1740 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001741 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001742 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001743 break;
1744
Roland Levillain6d0e4832014-11-27 18:31:21 +00001745 case Primitive::kPrimLong: {
1746 // Processing a Dex `long-to-float' instruction.
1747 Register low = in.AsRegisterPairLow<Register>();
1748 Register high = in.AsRegisterPairHigh<Register>();
1749 XmmRegister result = out.AsFpuRegister<XmmRegister>();
1750 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1751 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
1752
1753 // Operations use doubles for precision reasons (each 32-bit
1754 // half of a long fits in the 53-bit mantissa of a double,
1755 // but not in the 24-bit mantissa of a float). This is
1756 // especially important for the low bits. The result is
1757 // eventually converted to float.
1758
1759 // low = low - 2^31 (to prevent bit 31 of `low` to be
1760 // interpreted as a sign bit)
1761 __ subl(low, Immediate(0x80000000));
1762 // temp = int-to-double(high)
1763 __ cvtsi2sd(temp, high);
1764 // temp = temp * 2^32
1765 __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
1766 __ mulsd(temp, constant);
1767 // result = int-to-double(low)
1768 __ cvtsi2sd(result, low);
1769 // result = result + 2^31 (restore the original value of `low`)
1770 __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
1771 __ addsd(result, constant);
1772 // result = result + temp
1773 __ addsd(result, temp);
1774 // result = double-to-float(result)
1775 __ cvtsd2ss(result, result);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001776 // Restore low.
1777 __ addl(low, Immediate(0x80000000));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001778 break;
1779 }
1780
Roland Levillaincff13742014-11-17 14:32:17 +00001781 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001782 // Processing a Dex `double-to-float' instruction.
1783 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001784 break;
1785
1786 default:
1787 LOG(FATAL) << "Unexpected type conversion from " << input_type
1788 << " to " << result_type;
1789 };
1790 break;
1791
Roland Levillaindff1f282014-11-05 14:15:05 +00001792 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001793 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001794 case Primitive::kPrimBoolean:
1795 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001796 case Primitive::kPrimByte:
1797 case Primitive::kPrimShort:
1798 case Primitive::kPrimInt:
1799 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001800 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001801 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001802 break;
1803
Roland Levillain647b9ed2014-11-27 12:06:00 +00001804 case Primitive::kPrimLong: {
1805 // Processing a Dex `long-to-double' instruction.
1806 Register low = in.AsRegisterPairLow<Register>();
1807 Register high = in.AsRegisterPairHigh<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001808 XmmRegister result = out.AsFpuRegister<XmmRegister>();
1809 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1810 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001811
Roland Levillain647b9ed2014-11-27 12:06:00 +00001812 // low = low - 2^31 (to prevent bit 31 of `low` to be
1813 // interpreted as a sign bit)
1814 __ subl(low, Immediate(0x80000000));
1815 // temp = int-to-double(high)
1816 __ cvtsi2sd(temp, high);
1817 // temp = temp * 2^32
Roland Levillain6d0e4832014-11-27 18:31:21 +00001818 __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001819 __ mulsd(temp, constant);
1820 // result = int-to-double(low)
1821 __ cvtsi2sd(result, low);
1822 // result = result + 2^31 (restore the original value of `low`)
Roland Levillain6d0e4832014-11-27 18:31:21 +00001823 __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001824 __ addsd(result, constant);
1825 // result = result + temp
1826 __ addsd(result, temp);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001827 // Restore low.
1828 __ addl(low, Immediate(0x80000000));
Roland Levillain647b9ed2014-11-27 12:06:00 +00001829 break;
1830 }
1831
Roland Levillaincff13742014-11-17 14:32:17 +00001832 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001833 // Processing a Dex `float-to-double' instruction.
1834 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001835 break;
1836
1837 default:
1838 LOG(FATAL) << "Unexpected type conversion from " << input_type
1839 << " to " << result_type;
1840 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001841 break;
1842
1843 default:
1844 LOG(FATAL) << "Unexpected type conversion from " << input_type
1845 << " to " << result_type;
1846 }
1847}
1848
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001849void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001850 LocationSummary* locations =
1851 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001852 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001853 case Primitive::kPrimInt: {
1854 locations->SetInAt(0, Location::RequiresRegister());
1855 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1856 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1857 break;
1858 }
1859
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001860 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001861 locations->SetInAt(0, Location::RequiresRegister());
1862 locations->SetInAt(1, Location::Any());
1863 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001864 break;
1865 }
1866
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001867 case Primitive::kPrimFloat:
1868 case Primitive::kPrimDouble: {
1869 locations->SetInAt(0, Location::RequiresFpuRegister());
Calin Juravle3173c8a2015-02-23 15:53:39 +00001870 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001871 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001872 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001873 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001874
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001875 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001876 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1877 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001878 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001879}
1880
1881void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
1882 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001883 Location first = locations->InAt(0);
1884 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05001885 Location out = locations->Out();
1886
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001887 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001888 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001889 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001890 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1891 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
1892 } else {
1893 __ leal(out.AsRegister<Register>(), Address(
1894 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
1895 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001896 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001897 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
1898 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1899 __ addl(out.AsRegister<Register>(), Immediate(value));
1900 } else {
1901 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
1902 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001903 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05001904 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001905 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001906 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001907 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001908 }
1909
1910 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001911 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001912 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1913 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001914 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001915 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
1916 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001917 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001918 } else {
1919 DCHECK(second.IsConstant()) << second;
1920 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1921 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
1922 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001923 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001924 break;
1925 }
1926
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001927 case Primitive::kPrimFloat: {
1928 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001929 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001930 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001931 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001932 }
1933
1934 case Primitive::kPrimDouble: {
1935 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001936 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001937 }
1938 break;
1939 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001940
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001941 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001942 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001943 }
1944}
1945
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001946void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001947 LocationSummary* locations =
1948 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001949 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001950 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001951 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001952 locations->SetInAt(0, Location::RequiresRegister());
1953 locations->SetInAt(1, Location::Any());
1954 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001955 break;
1956 }
Calin Juravle11351682014-10-23 15:38:15 +01001957 case Primitive::kPrimFloat:
1958 case Primitive::kPrimDouble: {
1959 locations->SetInAt(0, Location::RequiresFpuRegister());
1960 locations->SetInAt(1, Location::RequiresFpuRegister());
1961 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001962 break;
Calin Juravle11351682014-10-23 15:38:15 +01001963 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001964
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001965 default:
Calin Juravle11351682014-10-23 15:38:15 +01001966 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001967 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001968}
1969
1970void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
1971 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001972 Location first = locations->InAt(0);
1973 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01001974 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001975 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001976 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001977 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001978 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001979 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001980 __ subl(first.AsRegister<Register>(),
1981 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001982 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001983 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001984 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001985 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001986 }
1987
1988 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001989 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01001990 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1991 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001992 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01001993 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001994 __ sbbl(first.AsRegisterPairHigh<Register>(),
1995 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001996 } else {
1997 DCHECK(second.IsConstant()) << second;
1998 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1999 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
2000 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002001 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002002 break;
2003 }
2004
Calin Juravle11351682014-10-23 15:38:15 +01002005 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002006 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002007 break;
Calin Juravle11351682014-10-23 15:38:15 +01002008 }
2009
2010 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002011 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01002012 break;
2013 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01002014
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002015 default:
Calin Juravle11351682014-10-23 15:38:15 +01002016 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002017 }
2018}
2019
Calin Juravle34bacdf2014-10-07 20:23:36 +01002020void LocationsBuilderX86::VisitMul(HMul* mul) {
2021 LocationSummary* locations =
2022 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2023 switch (mul->GetResultType()) {
2024 case Primitive::kPrimInt:
2025 locations->SetInAt(0, Location::RequiresRegister());
2026 locations->SetInAt(1, Location::Any());
2027 locations->SetOut(Location::SameAsFirstInput());
2028 break;
2029 case Primitive::kPrimLong: {
2030 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002031 locations->SetInAt(1, Location::Any());
2032 locations->SetOut(Location::SameAsFirstInput());
2033 // Needed for imul on 32bits with 64bits output.
2034 locations->AddTemp(Location::RegisterLocation(EAX));
2035 locations->AddTemp(Location::RegisterLocation(EDX));
2036 break;
2037 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002038 case Primitive::kPrimFloat:
2039 case Primitive::kPrimDouble: {
2040 locations->SetInAt(0, Location::RequiresFpuRegister());
2041 locations->SetInAt(1, Location::RequiresFpuRegister());
2042 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002043 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002044 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002045
2046 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002047 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002048 }
2049}
2050
2051void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2052 LocationSummary* locations = mul->GetLocations();
2053 Location first = locations->InAt(0);
2054 Location second = locations->InAt(1);
2055 DCHECK(first.Equals(locations->Out()));
2056
2057 switch (mul->GetResultType()) {
2058 case Primitive::kPrimInt: {
2059 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002060 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002061 } else if (second.IsConstant()) {
2062 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002063 __ imull(first.AsRegister<Register>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002064 } else {
2065 DCHECK(second.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002066 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002067 }
2068 break;
2069 }
2070
2071 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002072 Register in1_hi = first.AsRegisterPairHigh<Register>();
2073 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002074 Register eax = locations->GetTemp(0).AsRegister<Register>();
2075 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002076
2077 DCHECK_EQ(EAX, eax);
2078 DCHECK_EQ(EDX, edx);
2079
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002080 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002081 // output: in1
2082 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2083 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2084 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002085 if (second.IsConstant()) {
2086 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002087
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002088 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2089 int32_t low_value = Low32Bits(value);
2090 int32_t high_value = High32Bits(value);
2091 Immediate low(low_value);
2092 Immediate high(high_value);
2093
2094 __ movl(eax, high);
2095 // eax <- in1.lo * in2.hi
2096 __ imull(eax, in1_lo);
2097 // in1.hi <- in1.hi * in2.lo
2098 __ imull(in1_hi, low);
2099 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2100 __ addl(in1_hi, eax);
2101 // move in2_lo to eax to prepare for double precision
2102 __ movl(eax, low);
2103 // edx:eax <- in1.lo * in2.lo
2104 __ mull(in1_lo);
2105 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2106 __ addl(in1_hi, edx);
2107 // in1.lo <- (in1.lo * in2.lo)[31:0];
2108 __ movl(in1_lo, eax);
2109 } else if (second.IsRegisterPair()) {
2110 Register in2_hi = second.AsRegisterPairHigh<Register>();
2111 Register in2_lo = second.AsRegisterPairLow<Register>();
2112
2113 __ movl(eax, in2_hi);
2114 // eax <- in1.lo * in2.hi
2115 __ imull(eax, in1_lo);
2116 // in1.hi <- in1.hi * in2.lo
2117 __ imull(in1_hi, in2_lo);
2118 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2119 __ addl(in1_hi, eax);
2120 // move in1_lo to eax to prepare for double precision
2121 __ movl(eax, in1_lo);
2122 // edx:eax <- in1.lo * in2.lo
2123 __ mull(in2_lo);
2124 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2125 __ addl(in1_hi, edx);
2126 // in1.lo <- (in1.lo * in2.lo)[31:0];
2127 __ movl(in1_lo, eax);
2128 } else {
2129 DCHECK(second.IsDoubleStackSlot()) << second;
2130 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2131 Address in2_lo(ESP, second.GetStackIndex());
2132
2133 __ movl(eax, in2_hi);
2134 // eax <- in1.lo * in2.hi
2135 __ imull(eax, in1_lo);
2136 // in1.hi <- in1.hi * in2.lo
2137 __ imull(in1_hi, in2_lo);
2138 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2139 __ addl(in1_hi, eax);
2140 // move in1_lo to eax to prepare for double precision
2141 __ movl(eax, in1_lo);
2142 // edx:eax <- in1.lo * in2.lo
2143 __ mull(in2_lo);
2144 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2145 __ addl(in1_hi, edx);
2146 // in1.lo <- (in1.lo * in2.lo)[31:0];
2147 __ movl(in1_lo, eax);
2148 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002149
2150 break;
2151 }
2152
Calin Juravleb5bfa962014-10-21 18:02:24 +01002153 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002154 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002155 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002156 }
2157
2158 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002159 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002160 break;
2161 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002162
2163 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002164 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002165 }
2166}
2167
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002168void InstructionCodeGeneratorX86::PushOntoFPStack(Location source, uint32_t temp_offset,
2169 uint32_t stack_adjustment, bool is_float) {
2170 if (source.IsStackSlot()) {
2171 DCHECK(is_float);
2172 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2173 } else if (source.IsDoubleStackSlot()) {
2174 DCHECK(!is_float);
2175 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2176 } else {
2177 // Write the value to the temporary location on the stack and load to FP stack.
2178 if (is_float) {
2179 Location stack_temp = Location::StackSlot(temp_offset);
2180 codegen_->Move32(stack_temp, source);
2181 __ flds(Address(ESP, temp_offset));
2182 } else {
2183 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2184 codegen_->Move64(stack_temp, source);
2185 __ fldl(Address(ESP, temp_offset));
2186 }
2187 }
2188}
2189
2190void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2191 Primitive::Type type = rem->GetResultType();
2192 bool is_float = type == Primitive::kPrimFloat;
2193 size_t elem_size = Primitive::ComponentSize(type);
2194 LocationSummary* locations = rem->GetLocations();
2195 Location first = locations->InAt(0);
2196 Location second = locations->InAt(1);
2197 Location out = locations->Out();
2198
2199 // Create stack space for 2 elements.
2200 // TODO: enhance register allocator to ask for stack temporaries.
2201 __ subl(ESP, Immediate(2 * elem_size));
2202
2203 // Load the values to the FP stack in reverse order, using temporaries if needed.
2204 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2205 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2206
2207 // Loop doing FPREM until we stabilize.
2208 Label retry;
2209 __ Bind(&retry);
2210 __ fprem();
2211
2212 // Move FP status to AX.
2213 __ fstsw();
2214
2215 // And see if the argument reduction is complete. This is signaled by the
2216 // C2 FPU flag bit set to 0.
2217 __ andl(EAX, Immediate(kC2ConditionMask));
2218 __ j(kNotEqual, &retry);
2219
2220 // We have settled on the final value. Retrieve it into an XMM register.
2221 // Store FP top of stack to real stack.
2222 if (is_float) {
2223 __ fsts(Address(ESP, 0));
2224 } else {
2225 __ fstl(Address(ESP, 0));
2226 }
2227
2228 // Pop the 2 items from the FP stack.
2229 __ fucompp();
2230
2231 // Load the value from the stack into an XMM register.
2232 DCHECK(out.IsFpuRegister()) << out;
2233 if (is_float) {
2234 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2235 } else {
2236 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2237 }
2238
2239 // And remove the temporary stack space we allocated.
2240 __ addl(ESP, Immediate(2 * elem_size));
2241}
2242
Calin Juravlebacfec32014-11-14 15:54:36 +00002243void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2244 DCHECK(instruction->IsDiv() || instruction->IsRem());
2245
2246 LocationSummary* locations = instruction->GetLocations();
2247 Location out = locations->Out();
2248 Location first = locations->InAt(0);
2249 Location second = locations->InAt(1);
2250 bool is_div = instruction->IsDiv();
2251
2252 switch (instruction->GetResultType()) {
2253 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002254 Register second_reg = second.AsRegister<Register>();
2255 DCHECK_EQ(EAX, first.AsRegister<Register>());
2256 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002257
2258 SlowPathCodeX86* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002259 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
2260 is_div);
Calin Juravlebacfec32014-11-14 15:54:36 +00002261 codegen_->AddSlowPath(slow_path);
2262
2263 // 0x80000000/-1 triggers an arithmetic exception!
2264 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2265 // it's safe to just use negl instead of more complex comparisons.
2266
2267 __ cmpl(second_reg, Immediate(-1));
2268 __ j(kEqual, slow_path->GetEntryLabel());
2269
2270 // edx:eax <- sign-extended of eax
2271 __ cdq();
2272 // eax = quotient, edx = remainder
2273 __ idivl(second_reg);
2274
2275 __ Bind(slow_path->GetExitLabel());
2276 break;
2277 }
2278
2279 case Primitive::kPrimLong: {
2280 InvokeRuntimeCallingConvention calling_convention;
2281 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2282 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2283 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2284 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2285 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2286 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2287
2288 if (is_div) {
2289 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv)));
2290 } else {
2291 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod)));
2292 }
2293 uint32_t dex_pc = is_div
2294 ? instruction->AsDiv()->GetDexPc()
2295 : instruction->AsRem()->GetDexPc();
2296 codegen_->RecordPcInfo(instruction, dex_pc);
2297
2298 break;
2299 }
2300
2301 default:
2302 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
2303 }
2304}
2305
Calin Juravle7c4954d2014-10-28 16:57:40 +00002306void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002307 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002308 ? LocationSummary::kCall
2309 : LocationSummary::kNoCall;
2310 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2311
Calin Juravle7c4954d2014-10-28 16:57:40 +00002312 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002313 case Primitive::kPrimInt: {
2314 locations->SetInAt(0, Location::RegisterLocation(EAX));
2315 locations->SetInAt(1, Location::RequiresRegister());
2316 locations->SetOut(Location::SameAsFirstInput());
2317 // Intel uses edx:eax as the dividend.
2318 locations->AddTemp(Location::RegisterLocation(EDX));
2319 break;
2320 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002321 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002322 InvokeRuntimeCallingConvention calling_convention;
2323 locations->SetInAt(0, Location::RegisterPairLocation(
2324 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2325 locations->SetInAt(1, Location::RegisterPairLocation(
2326 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2327 // Runtime helper puts the result in EAX, EDX.
2328 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002329 break;
2330 }
2331 case Primitive::kPrimFloat:
2332 case Primitive::kPrimDouble: {
2333 locations->SetInAt(0, Location::RequiresFpuRegister());
2334 locations->SetInAt(1, Location::RequiresFpuRegister());
2335 locations->SetOut(Location::SameAsFirstInput());
2336 break;
2337 }
2338
2339 default:
2340 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2341 }
2342}
2343
2344void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
2345 LocationSummary* locations = div->GetLocations();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002346 Location out = locations->Out();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002347 Location first = locations->InAt(0);
2348 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002349
2350 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002351 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00002352 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002353 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002354 break;
2355 }
2356
2357 case Primitive::kPrimFloat: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002358 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002359 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002360 break;
2361 }
2362
2363 case Primitive::kPrimDouble: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002364 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002365 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002366 break;
2367 }
2368
2369 default:
2370 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2371 }
2372}
2373
Calin Juravlebacfec32014-11-14 15:54:36 +00002374void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002375 Primitive::Type type = rem->GetResultType();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002376 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
2377 ? LocationSummary::kCall
2378 : LocationSummary::kNoCall;
2379 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00002380
Calin Juravled2ec87d2014-12-08 14:24:46 +00002381 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002382 case Primitive::kPrimInt: {
2383 locations->SetInAt(0, Location::RegisterLocation(EAX));
2384 locations->SetInAt(1, Location::RequiresRegister());
2385 locations->SetOut(Location::RegisterLocation(EDX));
2386 break;
2387 }
2388 case Primitive::kPrimLong: {
2389 InvokeRuntimeCallingConvention calling_convention;
2390 locations->SetInAt(0, Location::RegisterPairLocation(
2391 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2392 locations->SetInAt(1, Location::RegisterPairLocation(
2393 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2394 // Runtime helper puts the result in EAX, EDX.
2395 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2396 break;
2397 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002398 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002399 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002400 locations->SetInAt(0, Location::Any());
2401 locations->SetInAt(1, Location::Any());
2402 locations->SetOut(Location::RequiresFpuRegister());
2403 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002404 break;
2405 }
2406
2407 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002408 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002409 }
2410}
2411
2412void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
2413 Primitive::Type type = rem->GetResultType();
2414 switch (type) {
2415 case Primitive::kPrimInt:
2416 case Primitive::kPrimLong: {
2417 GenerateDivRemIntegral(rem);
2418 break;
2419 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002420 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00002421 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002422 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00002423 break;
2424 }
2425 default:
2426 LOG(FATAL) << "Unexpected rem type " << type;
2427 }
2428}
2429
Calin Juravled0d48522014-11-04 16:40:20 +00002430void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2431 LocationSummary* locations =
2432 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002433 switch (instruction->GetType()) {
2434 case Primitive::kPrimInt: {
2435 locations->SetInAt(0, Location::Any());
2436 break;
2437 }
2438 case Primitive::kPrimLong: {
2439 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2440 if (!instruction->IsConstant()) {
2441 locations->AddTemp(Location::RequiresRegister());
2442 }
2443 break;
2444 }
2445 default:
2446 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2447 }
Calin Juravled0d48522014-11-04 16:40:20 +00002448 if (instruction->HasUses()) {
2449 locations->SetOut(Location::SameAsFirstInput());
2450 }
2451}
2452
2453void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2454 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
2455 codegen_->AddSlowPath(slow_path);
2456
2457 LocationSummary* locations = instruction->GetLocations();
2458 Location value = locations->InAt(0);
2459
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002460 switch (instruction->GetType()) {
2461 case Primitive::kPrimInt: {
2462 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002463 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002464 __ j(kEqual, slow_path->GetEntryLabel());
2465 } else if (value.IsStackSlot()) {
2466 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
2467 __ j(kEqual, slow_path->GetEntryLabel());
2468 } else {
2469 DCHECK(value.IsConstant()) << value;
2470 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2471 __ jmp(slow_path->GetEntryLabel());
2472 }
2473 }
2474 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002475 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002476 case Primitive::kPrimLong: {
2477 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002478 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002479 __ movl(temp, value.AsRegisterPairLow<Register>());
2480 __ orl(temp, value.AsRegisterPairHigh<Register>());
2481 __ j(kEqual, slow_path->GetEntryLabel());
2482 } else {
2483 DCHECK(value.IsConstant()) << value;
2484 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2485 __ jmp(slow_path->GetEntryLabel());
2486 }
2487 }
2488 break;
2489 }
2490 default:
2491 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002492 }
Calin Juravled0d48522014-11-04 16:40:20 +00002493}
2494
Calin Juravle9aec02f2014-11-18 23:06:35 +00002495void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
2496 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2497
2498 LocationSummary* locations =
2499 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2500
2501 switch (op->GetResultType()) {
2502 case Primitive::kPrimInt: {
2503 locations->SetInAt(0, Location::RequiresRegister());
2504 // The shift count needs to be in CL.
2505 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
2506 locations->SetOut(Location::SameAsFirstInput());
2507 break;
2508 }
2509 case Primitive::kPrimLong: {
2510 locations->SetInAt(0, Location::RequiresRegister());
2511 // The shift count needs to be in CL.
2512 locations->SetInAt(1, Location::RegisterLocation(ECX));
2513 locations->SetOut(Location::SameAsFirstInput());
2514 break;
2515 }
2516 default:
2517 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2518 }
2519}
2520
2521void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
2522 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2523
2524 LocationSummary* locations = op->GetLocations();
2525 Location first = locations->InAt(0);
2526 Location second = locations->InAt(1);
2527 DCHECK(first.Equals(locations->Out()));
2528
2529 switch (op->GetResultType()) {
2530 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002531 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002532 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002533 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002534 DCHECK_EQ(ECX, second_reg);
2535 if (op->IsShl()) {
2536 __ shll(first_reg, second_reg);
2537 } else if (op->IsShr()) {
2538 __ sarl(first_reg, second_reg);
2539 } else {
2540 __ shrl(first_reg, second_reg);
2541 }
2542 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002543 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002544 if (op->IsShl()) {
2545 __ shll(first_reg, imm);
2546 } else if (op->IsShr()) {
2547 __ sarl(first_reg, imm);
2548 } else {
2549 __ shrl(first_reg, imm);
2550 }
2551 }
2552 break;
2553 }
2554 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002555 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002556 DCHECK_EQ(ECX, second_reg);
2557 if (op->IsShl()) {
2558 GenerateShlLong(first, second_reg);
2559 } else if (op->IsShr()) {
2560 GenerateShrLong(first, second_reg);
2561 } else {
2562 GenerateUShrLong(first, second_reg);
2563 }
2564 break;
2565 }
2566 default:
2567 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2568 }
2569}
2570
2571void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
2572 Label done;
2573 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
2574 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
2575 __ testl(shifter, Immediate(32));
2576 __ j(kEqual, &done);
2577 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
2578 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
2579 __ Bind(&done);
2580}
2581
2582void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
2583 Label done;
2584 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2585 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
2586 __ testl(shifter, Immediate(32));
2587 __ j(kEqual, &done);
2588 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2589 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
2590 __ Bind(&done);
2591}
2592
2593void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
2594 Label done;
2595 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2596 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
2597 __ testl(shifter, Immediate(32));
2598 __ j(kEqual, &done);
2599 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2600 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
2601 __ Bind(&done);
2602}
2603
2604void LocationsBuilderX86::VisitShl(HShl* shl) {
2605 HandleShift(shl);
2606}
2607
2608void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
2609 HandleShift(shl);
2610}
2611
2612void LocationsBuilderX86::VisitShr(HShr* shr) {
2613 HandleShift(shr);
2614}
2615
2616void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
2617 HandleShift(shr);
2618}
2619
2620void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
2621 HandleShift(ushr);
2622}
2623
2624void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
2625 HandleShift(ushr);
2626}
2627
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002628void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002629 LocationSummary* locations =
2630 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002631 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002632 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002633 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2634 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002635}
2636
2637void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
2638 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002639 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002640 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002641
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002642 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002643
Nicolas Geoffray39468442014-09-02 15:17:15 +01002644 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002645 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002646}
2647
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002648void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
2649 LocationSummary* locations =
2650 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2651 locations->SetOut(Location::RegisterLocation(EAX));
2652 InvokeRuntimeCallingConvention calling_convention;
2653 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002654 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2655 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002656}
2657
2658void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
2659 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002660 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002661 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
2662
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002663 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002664
2665 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2666 DCHECK(!codegen_->IsLeafMethod());
2667}
2668
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002669void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002670 LocationSummary* locations =
2671 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002672 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2673 if (location.IsStackSlot()) {
2674 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2675 } else if (location.IsDoubleStackSlot()) {
2676 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002677 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002678 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002679}
2680
2681void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002682 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002683}
2684
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002685void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002686 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002687 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002688 locations->SetInAt(0, Location::RequiresRegister());
2689 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002690}
2691
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002692void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
2693 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01002694 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002695 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01002696 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002697 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002698 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002699 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002700 break;
2701
2702 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002703 __ notl(out.AsRegisterPairLow<Register>());
2704 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002705 break;
2706
2707 default:
2708 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2709 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002710}
2711
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002712void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002713 LocationSummary* locations =
2714 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002715 switch (compare->InputAt(0)->GetType()) {
2716 case Primitive::kPrimLong: {
2717 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00002718 locations->SetInAt(1, Location::Any());
2719 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2720 break;
2721 }
2722 case Primitive::kPrimFloat:
2723 case Primitive::kPrimDouble: {
2724 locations->SetInAt(0, Location::RequiresFpuRegister());
2725 locations->SetInAt(1, Location::RequiresFpuRegister());
2726 locations->SetOut(Location::RequiresRegister());
2727 break;
2728 }
2729 default:
2730 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2731 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002732}
2733
2734void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002735 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002736 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002737 Location left = locations->InAt(0);
2738 Location right = locations->InAt(1);
2739
2740 Label less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002741 switch (compare->InputAt(0)->GetType()) {
2742 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002743 Register left_low = left.AsRegisterPairLow<Register>();
2744 Register left_high = left.AsRegisterPairHigh<Register>();
2745 int32_t val_low = 0;
2746 int32_t val_high = 0;
2747 bool right_is_const = false;
2748
2749 if (right.IsConstant()) {
2750 DCHECK(right.GetConstant()->IsLongConstant());
2751 right_is_const = true;
2752 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
2753 val_low = Low32Bits(val);
2754 val_high = High32Bits(val);
2755 }
2756
Calin Juravleddb7df22014-11-25 20:56:51 +00002757 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002758 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002759 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002760 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002761 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002762 DCHECK(right_is_const) << right;
2763 if (val_high == 0) {
2764 __ testl(left_high, left_high);
2765 } else {
2766 __ cmpl(left_high, Immediate(val_high));
2767 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002768 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002769 __ j(kLess, &less); // Signed compare.
2770 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002771 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002772 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002773 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002774 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002775 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002776 DCHECK(right_is_const) << right;
2777 if (val_low == 0) {
2778 __ testl(left_low, left_low);
2779 } else {
2780 __ cmpl(left_low, Immediate(val_low));
2781 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002782 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002783 break;
2784 }
2785 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002786 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002787 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
2788 break;
2789 }
2790 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002791 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002792 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002793 break;
2794 }
2795 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002796 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002797 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002798 __ movl(out, Immediate(0));
2799 __ j(kEqual, &done);
2800 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
2801
2802 __ Bind(&greater);
2803 __ movl(out, Immediate(1));
2804 __ jmp(&done);
2805
2806 __ Bind(&less);
2807 __ movl(out, Immediate(-1));
2808
2809 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002810}
2811
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002812void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002813 LocationSummary* locations =
2814 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002815 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2816 locations->SetInAt(i, Location::Any());
2817 }
2818 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002819}
2820
2821void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002822 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002823 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002824}
2825
Calin Juravle52c48962014-12-16 17:02:57 +00002826void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
2827 /*
2828 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2829 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2830 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2831 */
2832 switch (kind) {
2833 case MemBarrierKind::kAnyAny: {
2834 __ mfence();
2835 break;
2836 }
2837 case MemBarrierKind::kAnyStore:
2838 case MemBarrierKind::kLoadAny:
2839 case MemBarrierKind::kStoreStore: {
2840 // nop
2841 break;
2842 }
2843 default:
2844 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002845 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002846}
2847
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002848
Mark Mendell09ed1a32015-03-25 08:30:06 -04002849void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
2850 Register temp) {
2851 // TODO: Implement all kinds of calls:
2852 // 1) boot -> boot
2853 // 2) app -> boot
2854 // 3) app -> app
2855 //
2856 // Currently we implement the app -> app logic, which looks up in the resolve cache.
2857 // temp = method;
2858 LoadCurrentMethod(temp);
2859 if (!invoke->IsRecursive()) {
2860 // temp = temp->dex_cache_resolved_methods_;
2861 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
2862 // temp = temp[index_in_cache]
2863 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
2864 // (temp + offset_of_quick_compiled_code)()
2865 __ call(Address(
2866 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
2867 } else {
2868 __ call(GetFrameEntryLabel());
2869 }
2870
2871 DCHECK(!IsLeafMethod());
2872 RecordPcInfo(invoke, invoke->GetDexPc());
2873}
2874
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002875void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002876 Label is_null;
2877 __ testl(value, value);
2878 __ j(kEqual, &is_null);
2879 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
2880 __ movl(temp, object);
2881 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00002882 __ movb(Address(temp, card, TIMES_1, 0),
2883 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01002884 __ Bind(&is_null);
2885}
2886
Calin Juravle52c48962014-12-16 17:02:57 +00002887void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
2888 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01002889 LocationSummary* locations =
2890 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01002891 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002892
2893 // The output overlaps in case of long: we don't want the low move to overwrite
2894 // the object's location.
2895 locations->SetOut(Location::RequiresRegister(),
2896 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
2897 : Location::kNoOutputOverlap);
Calin Juravle52c48962014-12-16 17:02:57 +00002898
2899 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
2900 // Long values can be loaded atomically into an XMM using movsd.
2901 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
2902 // and then copy the XMM into the output 32bits at a time).
2903 locations->AddTemp(Location::RequiresFpuRegister());
2904 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002905}
2906
Calin Juravle52c48962014-12-16 17:02:57 +00002907void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
2908 const FieldInfo& field_info) {
2909 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002910
Calin Juravle52c48962014-12-16 17:02:57 +00002911 LocationSummary* locations = instruction->GetLocations();
2912 Register base = locations->InAt(0).AsRegister<Register>();
2913 Location out = locations->Out();
2914 bool is_volatile = field_info.IsVolatile();
2915 Primitive::Type field_type = field_info.GetFieldType();
2916 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
2917
2918 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002919 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00002920 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002921 break;
2922 }
2923
2924 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00002925 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002926 break;
2927 }
2928
2929 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00002930 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002931 break;
2932 }
2933
2934 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00002935 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002936 break;
2937 }
2938
2939 case Primitive::kPrimInt:
2940 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00002941 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002942 break;
2943 }
2944
2945 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00002946 if (is_volatile) {
2947 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
2948 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00002949 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002950 __ movd(out.AsRegisterPairLow<Register>(), temp);
2951 __ psrlq(temp, Immediate(32));
2952 __ movd(out.AsRegisterPairHigh<Register>(), temp);
2953 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002954 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00002955 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00002956 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00002957 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
2958 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002959 break;
2960 }
2961
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002962 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00002963 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002964 break;
2965 }
2966
2967 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00002968 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00002969 break;
2970 }
2971
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002972 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00002973 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07002974 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002975 }
Calin Juravle52c48962014-12-16 17:02:57 +00002976
Calin Juravle77520bc2015-01-12 18:45:46 +00002977 // Longs are handled in the switch.
2978 if (field_type != Primitive::kPrimLong) {
2979 codegen_->MaybeRecordImplicitNullCheck(instruction);
2980 }
2981
Calin Juravle52c48962014-12-16 17:02:57 +00002982 if (is_volatile) {
2983 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
2984 }
2985}
2986
2987void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
2988 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
2989
2990 LocationSummary* locations =
2991 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2992 locations->SetInAt(0, Location::RequiresRegister());
2993 bool is_volatile = field_info.IsVolatile();
2994 Primitive::Type field_type = field_info.GetFieldType();
2995 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
2996 || (field_type == Primitive::kPrimByte);
2997
2998 // The register allocator does not support multiple
2999 // inputs that die at entry with one in a specific register.
3000 if (is_byte_type) {
3001 // Ensure the value is in a byte register.
3002 locations->SetInAt(1, Location::RegisterLocation(EAX));
3003 } else {
3004 locations->SetInAt(1, Location::RequiresRegister());
3005 }
3006 // Temporary registers for the write barrier.
3007 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3008 locations->AddTemp(Location::RequiresRegister());
3009 // Ensure the card is in a byte register.
3010 locations->AddTemp(Location::RegisterLocation(ECX));
3011 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
3012 // 64bits value can be atomically written to an address with movsd and an XMM register.
3013 // We need two XMM registers because there's no easier way to (bit) copy a register pair
3014 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
3015 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
3016 // isolated cases when we need this it isn't worth adding the extra complexity.
3017 locations->AddTemp(Location::RequiresFpuRegister());
3018 locations->AddTemp(Location::RequiresFpuRegister());
3019 }
3020}
3021
3022void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
3023 const FieldInfo& field_info) {
3024 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3025
3026 LocationSummary* locations = instruction->GetLocations();
3027 Register base = locations->InAt(0).AsRegister<Register>();
3028 Location value = locations->InAt(1);
3029 bool is_volatile = field_info.IsVolatile();
3030 Primitive::Type field_type = field_info.GetFieldType();
3031 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3032
3033 if (is_volatile) {
3034 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3035 }
3036
3037 switch (field_type) {
3038 case Primitive::kPrimBoolean:
3039 case Primitive::kPrimByte: {
3040 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
3041 break;
3042 }
3043
3044 case Primitive::kPrimShort:
3045 case Primitive::kPrimChar: {
3046 __ movw(Address(base, offset), value.AsRegister<Register>());
3047 break;
3048 }
3049
3050 case Primitive::kPrimInt:
3051 case Primitive::kPrimNot: {
3052 __ movl(Address(base, offset), value.AsRegister<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003053 break;
3054 }
3055
3056 case Primitive::kPrimLong: {
3057 if (is_volatile) {
3058 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3059 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
3060 __ movd(temp1, value.AsRegisterPairLow<Register>());
3061 __ movd(temp2, value.AsRegisterPairHigh<Register>());
3062 __ punpckldq(temp1, temp2);
3063 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00003064 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003065 } else {
3066 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003067 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003068 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
3069 }
3070 break;
3071 }
3072
3073 case Primitive::kPrimFloat: {
3074 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3075 break;
3076 }
3077
3078 case Primitive::kPrimDouble: {
3079 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3080 break;
3081 }
3082
3083 case Primitive::kPrimVoid:
3084 LOG(FATAL) << "Unreachable type " << field_type;
3085 UNREACHABLE();
3086 }
3087
Calin Juravle77520bc2015-01-12 18:45:46 +00003088 // Longs are handled in the switch.
3089 if (field_type != Primitive::kPrimLong) {
3090 codegen_->MaybeRecordImplicitNullCheck(instruction);
3091 }
3092
3093 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3094 Register temp = locations->GetTemp(0).AsRegister<Register>();
3095 Register card = locations->GetTemp(1).AsRegister<Register>();
3096 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
3097 }
3098
Calin Juravle52c48962014-12-16 17:02:57 +00003099 if (is_volatile) {
3100 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3101 }
3102}
3103
3104void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3105 HandleFieldGet(instruction, instruction->GetFieldInfo());
3106}
3107
3108void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3109 HandleFieldGet(instruction, instruction->GetFieldInfo());
3110}
3111
3112void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3113 HandleFieldSet(instruction, instruction->GetFieldInfo());
3114}
3115
3116void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3117 HandleFieldSet(instruction, instruction->GetFieldInfo());
3118}
3119
3120void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3121 HandleFieldSet(instruction, instruction->GetFieldInfo());
3122}
3123
3124void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3125 HandleFieldSet(instruction, instruction->GetFieldInfo());
3126}
3127
3128void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3129 HandleFieldGet(instruction, instruction->GetFieldInfo());
3130}
3131
3132void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3133 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003134}
3135
3136void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003137 LocationSummary* locations =
3138 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003139 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3140 ? Location::RequiresRegister()
3141 : Location::Any();
3142 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003143 if (instruction->HasUses()) {
3144 locations->SetOut(Location::SameAsFirstInput());
3145 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003146}
3147
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003148void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003149 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3150 return;
3151 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003152 LocationSummary* locations = instruction->GetLocations();
3153 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003154
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003155 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
3156 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3157}
3158
3159void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003160 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003161 codegen_->AddSlowPath(slow_path);
3162
3163 LocationSummary* locations = instruction->GetLocations();
3164 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003165
3166 if (obj.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003167 __ cmpl(obj.AsRegister<Register>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003168 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003169 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003170 } else {
3171 DCHECK(obj.IsConstant()) << obj;
3172 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3173 __ jmp(slow_path->GetEntryLabel());
3174 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003175 }
3176 __ j(kEqual, slow_path->GetEntryLabel());
3177}
3178
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003179void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
3180 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3181 GenerateImplicitNullCheck(instruction);
3182 } else {
3183 GenerateExplicitNullCheck(instruction);
3184 }
3185}
3186
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003187void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003188 LocationSummary* locations =
3189 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003190 locations->SetInAt(0, Location::RequiresRegister());
3191 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003192 // The output overlaps in case of long: we don't want the low move to overwrite
3193 // the array's location.
3194 locations->SetOut(Location::RequiresRegister(),
3195 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3196 : Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003197}
3198
3199void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
3200 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003201 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003202 Location index = locations->InAt(1);
3203
Calin Juravle77520bc2015-01-12 18:45:46 +00003204 Primitive::Type type = instruction->GetType();
3205 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003206 case Primitive::kPrimBoolean: {
3207 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003208 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003209 if (index.IsConstant()) {
3210 __ movzxb(out, Address(obj,
3211 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3212 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003213 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003214 }
3215 break;
3216 }
3217
3218 case Primitive::kPrimByte: {
3219 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003220 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003221 if (index.IsConstant()) {
3222 __ movsxb(out, Address(obj,
3223 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3224 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003225 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003226 }
3227 break;
3228 }
3229
3230 case Primitive::kPrimShort: {
3231 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003232 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003233 if (index.IsConstant()) {
3234 __ movsxw(out, Address(obj,
3235 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3236 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003237 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003238 }
3239 break;
3240 }
3241
3242 case Primitive::kPrimChar: {
3243 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003244 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003245 if (index.IsConstant()) {
3246 __ movzxw(out, Address(obj,
3247 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3248 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003249 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003250 }
3251 break;
3252 }
3253
3254 case Primitive::kPrimInt:
3255 case Primitive::kPrimNot: {
3256 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003257 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003258 if (index.IsConstant()) {
3259 __ movl(out, Address(obj,
3260 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3261 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003262 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003263 }
3264 break;
3265 }
3266
3267 case Primitive::kPrimLong: {
3268 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003269 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003270 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003271 if (index.IsConstant()) {
3272 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003273 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003274 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003275 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003276 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003277 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003278 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003279 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003280 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003281 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003282 }
3283 break;
3284 }
3285
Mark Mendell7c8d0092015-01-26 11:21:33 -05003286 case Primitive::kPrimFloat: {
3287 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3288 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3289 if (index.IsConstant()) {
3290 __ movss(out, Address(obj,
3291 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3292 } else {
3293 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
3294 }
3295 break;
3296 }
3297
3298 case Primitive::kPrimDouble: {
3299 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3300 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3301 if (index.IsConstant()) {
3302 __ movsd(out, Address(obj,
3303 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3304 } else {
3305 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
3306 }
3307 break;
3308 }
3309
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003310 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00003311 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003312 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003313 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003314
3315 if (type != Primitive::kPrimLong) {
3316 codegen_->MaybeRecordImplicitNullCheck(instruction);
3317 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003318}
3319
3320void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05003321 // This location builder might end up asking to up to four registers, which is
3322 // not currently possible for baseline. The situation in which we need four
3323 // registers cannot be met by baseline though, because it has not run any
3324 // optimization.
3325
Nicolas Geoffray39468442014-09-02 15:17:15 +01003326 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003327 bool needs_write_barrier =
3328 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3329
Mark Mendell5f874182015-03-04 15:42:45 -05003330 bool needs_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003331
Nicolas Geoffray39468442014-09-02 15:17:15 +01003332 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3333 instruction,
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003334 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003335
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003336 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003337 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003338 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3339 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3340 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003341 } else {
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003342 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
3343 || (value_type == Primitive::kPrimByte);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003344 // We need the inputs to be different than the output in case of long operation.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003345 // In case of a byte operation, the register allocator does not support multiple
3346 // inputs that die at entry with one in a specific register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003347 locations->SetInAt(0, Location::RequiresRegister());
3348 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003349 if (is_byte_type) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003350 // Ensure the value is in a byte register.
3351 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003352 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003353 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003354 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003355 // Temporary registers for the write barrier.
3356 if (needs_write_barrier) {
3357 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003358 // Ensure the card is in a byte register.
3359 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003360 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003361 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003362}
3363
3364void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
3365 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003366 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003367 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003368 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003369 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003370 bool needs_runtime_call = locations->WillCall();
3371 bool needs_write_barrier =
3372 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003373
3374 switch (value_type) {
3375 case Primitive::kPrimBoolean:
3376 case Primitive::kPrimByte: {
3377 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003378 if (index.IsConstant()) {
3379 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003380 if (value.IsRegister()) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003381 __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003382 } else {
3383 __ movb(Address(obj, offset),
3384 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3385 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003386 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003387 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003388 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003389 value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003390 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003391 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003392 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3393 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003394 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003395 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003396 break;
3397 }
3398
3399 case Primitive::kPrimShort:
3400 case Primitive::kPrimChar: {
3401 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003402 if (index.IsConstant()) {
3403 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003404 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003405 __ movw(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003406 } else {
3407 __ movw(Address(obj, offset),
3408 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3409 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003410 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003411 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003412 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
3413 value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003414 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003415 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003416 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3417 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003418 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003419 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003420 break;
3421 }
3422
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003423 case Primitive::kPrimInt:
3424 case Primitive::kPrimNot: {
3425 if (!needs_runtime_call) {
3426 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3427 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003428 size_t offset =
3429 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003430 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003431 __ movl(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003432 } else {
3433 DCHECK(value.IsConstant()) << value;
3434 __ movl(Address(obj, offset),
3435 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3436 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003437 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003438 DCHECK(index.IsRegister()) << index;
3439 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003440 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3441 value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003442 } else {
3443 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003444 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003445 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3446 }
3447 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003448 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003449
3450 if (needs_write_barrier) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003451 Register temp = locations->GetTemp(0).AsRegister<Register>();
3452 Register card = locations->GetTemp(1).AsRegister<Register>();
3453 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003454 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003455 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003456 DCHECK_EQ(value_type, Primitive::kPrimNot);
3457 DCHECK(!codegen_->IsLeafMethod());
3458 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
3459 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003460 }
3461 break;
3462 }
3463
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003464 case Primitive::kPrimLong: {
3465 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003466 if (index.IsConstant()) {
3467 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003468 if (value.IsRegisterPair()) {
3469 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003470 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003471 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003472 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003473 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003474 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
3475 __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003476 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003477 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
3478 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003479 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003480 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003481 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003482 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003483 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003484 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003485 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003486 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003487 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003488 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003489 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003490 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003491 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003492 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003493 Immediate(High32Bits(val)));
3494 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003495 }
3496 break;
3497 }
3498
Mark Mendell7c8d0092015-01-26 11:21:33 -05003499 case Primitive::kPrimFloat: {
3500 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3501 DCHECK(value.IsFpuRegister());
3502 if (index.IsConstant()) {
3503 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3504 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3505 } else {
3506 __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3507 value.AsFpuRegister<XmmRegister>());
3508 }
3509 break;
3510 }
3511
3512 case Primitive::kPrimDouble: {
3513 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3514 DCHECK(value.IsFpuRegister());
3515 if (index.IsConstant()) {
3516 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3517 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3518 } else {
3519 __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3520 value.AsFpuRegister<XmmRegister>());
3521 }
3522 break;
3523 }
3524
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003525 case Primitive::kPrimVoid:
3526 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003527 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003528 }
3529}
3530
3531void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
3532 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003533 locations->SetInAt(0, Location::RequiresRegister());
3534 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003535 instruction->SetLocations(locations);
3536}
3537
3538void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
3539 LocationSummary* locations = instruction->GetLocations();
3540 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003541 Register obj = locations->InAt(0).AsRegister<Register>();
3542 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003543 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003544 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003545}
3546
3547void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003548 LocationSummary* locations =
3549 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003550 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003551 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003552 if (instruction->HasUses()) {
3553 locations->SetOut(Location::SameAsFirstInput());
3554 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003555}
3556
3557void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
3558 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003559 Location index_loc = locations->InAt(0);
3560 Location length_loc = locations->InAt(1);
3561 SlowPathCodeX86* slow_path =
3562 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003563 codegen_->AddSlowPath(slow_path);
3564
Mark Mendellf60c90b2015-03-04 15:12:59 -05003565 Register length = length_loc.AsRegister<Register>();
3566 if (index_loc.IsConstant()) {
3567 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3568 __ cmpl(length, Immediate(value));
3569 } else {
3570 __ cmpl(length, index_loc.AsRegister<Register>());
3571 }
3572 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003573}
3574
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003575void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
3576 temp->SetLocations(nullptr);
3577}
3578
3579void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
3580 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003581 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003582}
3583
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003584void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003585 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003586 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003587}
3588
3589void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003590 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3591}
3592
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003593void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
3594 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3595}
3596
3597void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003598 HBasicBlock* block = instruction->GetBlock();
3599 if (block->GetLoopInformation() != nullptr) {
3600 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3601 // The back edge will generate the suspend check.
3602 return;
3603 }
3604 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3605 // The goto will generate the suspend check.
3606 return;
3607 }
3608 GenerateSuspendCheck(instruction, nullptr);
3609}
3610
3611void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
3612 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003613 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003614 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003615 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003616 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003617 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003618 if (successor == nullptr) {
3619 __ j(kNotEqual, slow_path->GetEntryLabel());
3620 __ Bind(slow_path->GetReturnLabel());
3621 } else {
3622 __ j(kEqual, codegen_->GetLabelOf(successor));
3623 __ jmp(slow_path->GetEntryLabel());
3624 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003625}
3626
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003627X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
3628 return codegen_->GetAssembler();
3629}
3630
Mark Mendell7c8d0092015-01-26 11:21:33 -05003631void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003632 ScratchRegisterScope ensure_scratch(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003633 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003634 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003635 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
Mark Mendell7c8d0092015-01-26 11:21:33 -05003636 __ movl(temp_reg, Address(ESP, src + stack_offset));
3637 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3638}
3639
3640void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
3641 ScratchRegisterScope ensure_scratch(
3642 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3643 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3644 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3645 __ movl(temp_reg, Address(ESP, src + stack_offset));
3646 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3647 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
3648 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003649}
3650
3651void ParallelMoveResolverX86::EmitMove(size_t index) {
3652 MoveOperands* move = moves_.Get(index);
3653 Location source = move->GetSource();
3654 Location destination = move->GetDestination();
3655
3656 if (source.IsRegister()) {
3657 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003658 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003659 } else {
3660 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003661 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003662 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003663 } else if (source.IsFpuRegister()) {
3664 if (destination.IsFpuRegister()) {
3665 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3666 } else if (destination.IsStackSlot()) {
3667 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3668 } else {
3669 DCHECK(destination.IsDoubleStackSlot());
3670 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3671 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003672 } else if (source.IsStackSlot()) {
3673 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003674 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003675 } else if (destination.IsFpuRegister()) {
3676 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003677 } else {
3678 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003679 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
3680 }
3681 } else if (source.IsDoubleStackSlot()) {
3682 if (destination.IsFpuRegister()) {
3683 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
3684 } else {
3685 DCHECK(destination.IsDoubleStackSlot()) << destination;
3686 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003687 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003688 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003689 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003690 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003691 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05003692 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003693 if (value == 0) {
3694 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
3695 } else {
3696 __ movl(destination.AsRegister<Register>(), Immediate(value));
3697 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003698 } else {
3699 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05003700 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003701 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003702 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003703 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003704 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003705 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05003706 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003707 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3708 if (value == 0) {
3709 // Easy handling of 0.0.
3710 __ xorps(dest, dest);
3711 } else {
3712 ScratchRegisterScope ensure_scratch(
3713 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3714 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
3715 __ movl(temp, Immediate(value));
3716 __ movd(dest, temp);
3717 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003718 } else {
3719 DCHECK(destination.IsStackSlot()) << destination;
3720 __ movl(Address(ESP, destination.GetStackIndex()), imm);
3721 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003722 } else if (constant->IsLongConstant()) {
3723 int64_t value = constant->AsLongConstant()->GetValue();
3724 int32_t low_value = Low32Bits(value);
3725 int32_t high_value = High32Bits(value);
3726 Immediate low(low_value);
3727 Immediate high(high_value);
3728 if (destination.IsDoubleStackSlot()) {
3729 __ movl(Address(ESP, destination.GetStackIndex()), low);
3730 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
3731 } else {
3732 __ movl(destination.AsRegisterPairLow<Register>(), low);
3733 __ movl(destination.AsRegisterPairHigh<Register>(), high);
3734 }
3735 } else {
3736 DCHECK(constant->IsDoubleConstant());
3737 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003738 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003739 int32_t low_value = Low32Bits(value);
3740 int32_t high_value = High32Bits(value);
3741 Immediate low(low_value);
3742 Immediate high(high_value);
3743 if (destination.IsFpuRegister()) {
3744 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3745 if (value == 0) {
3746 // Easy handling of 0.0.
3747 __ xorpd(dest, dest);
3748 } else {
3749 __ pushl(high);
3750 __ pushl(low);
3751 __ movsd(dest, Address(ESP, 0));
3752 __ addl(ESP, Immediate(8));
3753 }
3754 } else {
3755 DCHECK(destination.IsDoubleStackSlot()) << destination;
3756 __ movl(Address(ESP, destination.GetStackIndex()), low);
3757 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
3758 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003759 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003760 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00003761 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003762 }
3763}
3764
3765void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003766 Register suggested_scratch = reg == EAX ? EBX : EAX;
3767 ScratchRegisterScope ensure_scratch(
3768 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3769
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003770 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3771 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
3772 __ movl(Address(ESP, mem + stack_offset), reg);
3773 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
3774}
3775
Mark Mendell7c8d0092015-01-26 11:21:33 -05003776void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
3777 ScratchRegisterScope ensure_scratch(
3778 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3779
3780 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3781 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3782 __ movl(temp_reg, Address(ESP, mem + stack_offset));
3783 __ movss(Address(ESP, mem + stack_offset), reg);
3784 __ movd(reg, temp_reg);
3785}
3786
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003787void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
3788 ScratchRegisterScope ensure_scratch1(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003789 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3790
3791 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003792 ScratchRegisterScope ensure_scratch2(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003793 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3794
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003795 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
3796 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
3797 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
3798 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
3799 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
3800 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
3801}
3802
3803void ParallelMoveResolverX86::EmitSwap(size_t index) {
3804 MoveOperands* move = moves_.Get(index);
3805 Location source = move->GetSource();
3806 Location destination = move->GetDestination();
3807
3808 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003809 __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003810 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003811 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003812 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003813 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003814 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3815 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003816 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
3817 // Use XOR Swap algorithm to avoid a temporary.
3818 DCHECK_NE(source.reg(), destination.reg());
3819 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3820 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3821 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3822 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
3823 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
3824 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
3825 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003826 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
3827 // Take advantage of the 16 bytes in the XMM register.
3828 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
3829 Address stack(ESP, destination.GetStackIndex());
3830 // Load the double into the high doubleword.
3831 __ movhpd(reg, stack);
3832
3833 // Store the low double into the destination.
3834 __ movsd(stack, reg);
3835
3836 // Move the high double to the low double.
3837 __ psrldq(reg, Immediate(8));
3838 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
3839 // Take advantage of the 16 bytes in the XMM register.
3840 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
3841 Address stack(ESP, source.GetStackIndex());
3842 // Load the double into the high doubleword.
3843 __ movhpd(reg, stack);
3844
3845 // Store the low double into the destination.
3846 __ movsd(stack, reg);
3847
3848 // Move the high double to the low double.
3849 __ psrldq(reg, Immediate(8));
3850 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
3851 Exchange(destination.GetStackIndex(), source.GetStackIndex());
3852 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003853 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003854 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003855 }
3856}
3857
3858void ParallelMoveResolverX86::SpillScratch(int reg) {
3859 __ pushl(static_cast<Register>(reg));
3860}
3861
3862void ParallelMoveResolverX86::RestoreScratch(int reg) {
3863 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003864}
3865
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003866void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003867 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
3868 ? LocationSummary::kCallOnSlowPath
3869 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003870 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003871 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003872 locations->SetOut(Location::RequiresRegister());
3873}
3874
3875void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003876 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003877 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003878 DCHECK(!cls->CanCallRuntime());
3879 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003880 codegen_->LoadCurrentMethod(out);
3881 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3882 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003883 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003884 codegen_->LoadCurrentMethod(out);
3885 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
3886 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003887
3888 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
3889 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
3890 codegen_->AddSlowPath(slow_path);
3891 __ testl(out, out);
3892 __ j(kEqual, slow_path->GetEntryLabel());
3893 if (cls->MustGenerateClinitCheck()) {
3894 GenerateClassInitializationCheck(slow_path, out);
3895 } else {
3896 __ Bind(slow_path->GetExitLabel());
3897 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003898 }
3899}
3900
3901void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
3902 LocationSummary* locations =
3903 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
3904 locations->SetInAt(0, Location::RequiresRegister());
3905 if (check->HasUses()) {
3906 locations->SetOut(Location::SameAsFirstInput());
3907 }
3908}
3909
3910void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003911 // We assume the class to not be null.
3912 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
3913 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003914 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00003915 GenerateClassInitializationCheck(slow_path,
3916 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003917}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003918
Nicolas Geoffray424f6762014-11-03 14:51:25 +00003919void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
3920 SlowPathCodeX86* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01003921 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
3922 Immediate(mirror::Class::kStatusInitialized));
3923 __ j(kLess, slow_path->GetEntryLabel());
3924 __ Bind(slow_path->GetExitLabel());
3925 // No need for memory fence, thanks to the X86 memory model.
3926}
3927
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003928void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
3929 LocationSummary* locations =
3930 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
3931 locations->SetOut(Location::RequiresRegister());
3932}
3933
3934void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
3935 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
3936 codegen_->AddSlowPath(slow_path);
3937
Roland Levillain271ab9c2014-11-27 15:23:57 +00003938 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003939 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08003940 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
3941 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00003942 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
3943 __ testl(out, out);
3944 __ j(kEqual, slow_path->GetEntryLabel());
3945 __ Bind(slow_path->GetExitLabel());
3946}
3947
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003948void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
3949 LocationSummary* locations =
3950 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
3951 locations->SetOut(Location::RequiresRegister());
3952}
3953
3954void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
3955 Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003956 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00003957 __ fs()->movl(address, Immediate(0));
3958}
3959
3960void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
3961 LocationSummary* locations =
3962 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
3963 InvokeRuntimeCallingConvention calling_convention;
3964 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3965}
3966
3967void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
3968 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
3969 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3970}
3971
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003972void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003973 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
3974 ? LocationSummary::kNoCall
3975 : LocationSummary::kCallOnSlowPath;
3976 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
3977 locations->SetInAt(0, Location::RequiresRegister());
3978 locations->SetInAt(1, Location::Any());
3979 locations->SetOut(Location::RequiresRegister());
3980}
3981
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00003982void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003983 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003984 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003985 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003986 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003987 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
3988 Label done, zero;
3989 SlowPathCodeX86* slow_path = nullptr;
3990
3991 // Return 0 if `obj` is null.
3992 // TODO: avoid this check if we know obj is not null.
3993 __ testl(obj, obj);
3994 __ j(kEqual, &zero);
3995 __ movl(out, Address(obj, class_offset));
3996 // Compare the class of `obj` with `cls`.
3997 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003998 __ cmpl(out, cls.AsRegister<Register>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00003999 } else {
4000 DCHECK(cls.IsStackSlot()) << cls;
4001 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
4002 }
4003
4004 if (instruction->IsClassFinal()) {
4005 // Classes must be equal for the instanceof to succeed.
4006 __ j(kNotEqual, &zero);
4007 __ movl(out, Immediate(1));
4008 __ jmp(&done);
4009 } else {
4010 // If the classes are not equal, we go into a slow path.
4011 DCHECK(locations->OnlyCallsOnSlowPath());
4012 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004013 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004014 codegen_->AddSlowPath(slow_path);
4015 __ j(kNotEqual, slow_path->GetEntryLabel());
4016 __ movl(out, Immediate(1));
4017 __ jmp(&done);
4018 }
4019 __ Bind(&zero);
4020 __ movl(out, Immediate(0));
4021 if (slow_path != nullptr) {
4022 __ Bind(slow_path->GetExitLabel());
4023 }
4024 __ Bind(&done);
4025}
4026
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004027void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
4028 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4029 instruction, LocationSummary::kCallOnSlowPath);
4030 locations->SetInAt(0, Location::RequiresRegister());
4031 locations->SetInAt(1, Location::Any());
4032 locations->AddTemp(Location::RequiresRegister());
4033}
4034
4035void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
4036 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004037 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004038 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004039 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004040 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4041 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
4042 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4043 codegen_->AddSlowPath(slow_path);
4044
4045 // TODO: avoid this check if we know obj is not null.
4046 __ testl(obj, obj);
4047 __ j(kEqual, slow_path->GetExitLabel());
4048 __ movl(temp, Address(obj, class_offset));
4049
4050 // Compare the class of `obj` with `cls`.
4051 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004052 __ cmpl(temp, cls.AsRegister<Register>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004053 } else {
4054 DCHECK(cls.IsStackSlot()) << cls;
4055 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
4056 }
4057
4058 __ j(kNotEqual, slow_path->GetEntryLabel());
4059 __ Bind(slow_path->GetExitLabel());
4060}
4061
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004062void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4063 LocationSummary* locations =
4064 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4065 InvokeRuntimeCallingConvention calling_convention;
4066 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4067}
4068
4069void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4070 __ fs()->call(Address::Absolute(instruction->IsEnter()
4071 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject)
4072 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject)));
4073 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4074}
4075
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004076void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4077void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4078void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4079
4080void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4081 LocationSummary* locations =
4082 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4083 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4084 || instruction->GetResultType() == Primitive::kPrimLong);
4085 locations->SetInAt(0, Location::RequiresRegister());
4086 locations->SetInAt(1, Location::Any());
4087 locations->SetOut(Location::SameAsFirstInput());
4088}
4089
4090void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
4091 HandleBitwiseOperation(instruction);
4092}
4093
4094void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
4095 HandleBitwiseOperation(instruction);
4096}
4097
4098void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
4099 HandleBitwiseOperation(instruction);
4100}
4101
4102void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4103 LocationSummary* locations = instruction->GetLocations();
4104 Location first = locations->InAt(0);
4105 Location second = locations->InAt(1);
4106 DCHECK(first.Equals(locations->Out()));
4107
4108 if (instruction->GetResultType() == Primitive::kPrimInt) {
4109 if (second.IsRegister()) {
4110 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004111 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004112 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004113 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004114 } else {
4115 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004116 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004117 }
4118 } else if (second.IsConstant()) {
4119 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004120 __ andl(first.AsRegister<Register>(),
4121 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004122 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004123 __ orl(first.AsRegister<Register>(),
4124 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004125 } else {
4126 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00004127 __ xorl(first.AsRegister<Register>(),
4128 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004129 }
4130 } else {
4131 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004132 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004133 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004134 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004135 } else {
4136 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004137 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004138 }
4139 }
4140 } else {
4141 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4142 if (second.IsRegisterPair()) {
4143 if (instruction->IsAnd()) {
4144 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4145 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4146 } else if (instruction->IsOr()) {
4147 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4148 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4149 } else {
4150 DCHECK(instruction->IsXor());
4151 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4152 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4153 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004154 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004155 if (instruction->IsAnd()) {
4156 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4157 __ andl(first.AsRegisterPairHigh<Register>(),
4158 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4159 } else if (instruction->IsOr()) {
4160 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4161 __ orl(first.AsRegisterPairHigh<Register>(),
4162 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4163 } else {
4164 DCHECK(instruction->IsXor());
4165 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4166 __ xorl(first.AsRegisterPairHigh<Register>(),
4167 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4168 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004169 } else {
4170 DCHECK(second.IsConstant()) << second;
4171 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004172 int32_t low_value = Low32Bits(value);
4173 int32_t high_value = High32Bits(value);
4174 Immediate low(low_value);
4175 Immediate high(high_value);
4176 Register first_low = first.AsRegisterPairLow<Register>();
4177 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004178 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004179 if (low_value == 0) {
4180 __ xorl(first_low, first_low);
4181 } else if (low_value != -1) {
4182 __ andl(first_low, low);
4183 }
4184 if (high_value == 0) {
4185 __ xorl(first_high, first_high);
4186 } else if (high_value != -1) {
4187 __ andl(first_high, high);
4188 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004189 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004190 if (low_value != 0) {
4191 __ orl(first_low, low);
4192 }
4193 if (high_value != 0) {
4194 __ orl(first_high, high);
4195 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004196 } else {
4197 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004198 if (low_value != 0) {
4199 __ xorl(first_low, low);
4200 }
4201 if (high_value != 0) {
4202 __ xorl(first_high, high);
4203 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004204 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004205 }
4206 }
4207}
4208
Calin Juravleb1498f62015-02-16 13:13:29 +00004209void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
4210 // Nothing to do, this should be removed during prepare for register allocator.
4211 UNUSED(instruction);
4212 LOG(FATAL) << "Unreachable";
4213}
4214
4215void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
4216 // Nothing to do, this should be removed during prepare for register allocator.
4217 UNUSED(instruction);
4218 LOG(FATAL) << "Unreachable";
4219}
4220
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004221} // namespace x86
4222} // namespace art