blob: dac7221bc489c10adc880dd0f73c15276b553f02 [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
Guillaume Sanchez0f88e872015-03-30 17:55:45 +010019#include "code_generator_utils.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010020#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +000021#include "entrypoints/quick/quick_entrypoints_enum.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010022#include "gc/accounting/card_table.h"
Mark Mendell09ed1a32015-03-25 08:30:06 -040023#include "intrinsics.h"
24#include "intrinsics_x86.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070025#include "mirror/array-inl.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010026#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010027#include "mirror/class.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010028#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010030#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000031#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010032#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000033
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000034namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010035
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000036namespace x86 {
37
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010038static constexpr int kCurrentMethodStackOffset = 0;
39
Mark Mendell5f874182015-03-04 15:42:45 -050040static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI };
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010041
Mark Mendell24f2dfa2015-01-14 19:51:45 -050042static constexpr int kC2ConditionMask = 0x400;
43
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +000044static constexpr int kFakeReturnRegister = Register(8);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +000045
Nicolas Geoffraye5038322014-07-04 09:41:32 +010046#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
47
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010048class NullCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010049 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010050 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010051
Alexandre Rames2ed20af2015-03-06 13:55:35 +000052 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010053 __ Bind(GetEntryLabel());
54 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
Nicolas Geoffray39468442014-09-02 15:17:15 +010055 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010056 }
57
58 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010059 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010060 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
61};
62
Calin Juravled0d48522014-11-04 16:40:20 +000063class DivZeroCheckSlowPathX86 : public SlowPathCodeX86 {
64 public:
65 explicit DivZeroCheckSlowPathX86(HDivZeroCheck* instruction) : instruction_(instruction) {}
66
Alexandre Rames2ed20af2015-03-06 13:55:35 +000067 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000068 __ Bind(GetEntryLabel());
69 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowDivZero)));
70 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
71 }
72
73 private:
74 HDivZeroCheck* const instruction_;
75 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathX86);
76};
77
Calin Juravlebacfec32014-11-14 15:54:36 +000078class DivRemMinusOneSlowPathX86 : public SlowPathCodeX86 {
Calin Juravled0d48522014-11-04 16:40:20 +000079 public:
Calin Juravlebacfec32014-11-14 15:54:36 +000080 explicit DivRemMinusOneSlowPathX86(Register reg, bool is_div) : reg_(reg), is_div_(is_div) {}
Calin Juravled0d48522014-11-04 16:40:20 +000081
Alexandre Rames2ed20af2015-03-06 13:55:35 +000082 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Calin Juravled0d48522014-11-04 16:40:20 +000083 __ Bind(GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +000084 if (is_div_) {
85 __ negl(reg_);
86 } else {
87 __ movl(reg_, Immediate(0));
88 }
Calin Juravled0d48522014-11-04 16:40:20 +000089 __ jmp(GetExitLabel());
90 }
91
92 private:
93 Register reg_;
Calin Juravlebacfec32014-11-14 15:54:36 +000094 bool is_div_;
95 DISALLOW_COPY_AND_ASSIGN(DivRemMinusOneSlowPathX86);
Calin Juravled0d48522014-11-04 16:40:20 +000096};
97
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010098class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010099 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100100 BoundsCheckSlowPathX86(HBoundsCheck* instruction,
101 Location index_location,
102 Location length_location)
Roland Levillain199f3362014-11-27 17:15:16 +0000103 : instruction_(instruction),
104 index_location_(index_location),
105 length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100106
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000107 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100108 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100109 __ Bind(GetEntryLabel());
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000110 // We're moving two locations to locations that could overlap, so we need a parallel
111 // move resolver.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100112 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000113 x86_codegen->EmitParallelMoves(
114 index_location_,
115 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
116 length_location_,
117 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100118 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100119 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100120 }
121
122 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100123 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100124 const Location index_location_;
125 const Location length_location_;
126
127 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
128};
129
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100130class SuspendCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000131 public:
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000132 SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100133 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000134
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000135 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100136 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000137 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000138 SaveLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000139 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
140 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000141 RestoreLiveRegisters(codegen, instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100142 if (successor_ == nullptr) {
143 __ jmp(GetReturnLabel());
144 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100145 __ jmp(x86_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100146 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000147 }
148
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100149 Label* GetReturnLabel() {
150 DCHECK(successor_ == nullptr);
151 return &return_label_;
152 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000153
154 private:
155 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100156 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000157 Label return_label_;
158
159 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
160};
161
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000162class LoadStringSlowPathX86 : public SlowPathCodeX86 {
163 public:
164 explicit LoadStringSlowPathX86(HLoadString* instruction) : instruction_(instruction) {}
165
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000166 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000167 LocationSummary* locations = instruction_->GetLocations();
168 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
169
170 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
171 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000172 SaveLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000173
174 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -0800175 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
176 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction_->GetStringIndex()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000177 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pResolveString)));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000178 RecordPcInfo(codegen, instruction_, instruction_->GetDexPc());
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000179 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000180 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +0000181
182 __ jmp(GetExitLabel());
183 }
184
185 private:
186 HLoadString* const instruction_;
187
188 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86);
189};
190
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000191class LoadClassSlowPathX86 : public SlowPathCodeX86 {
192 public:
193 LoadClassSlowPathX86(HLoadClass* cls,
194 HInstruction* at,
195 uint32_t dex_pc,
196 bool do_clinit)
197 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) {
198 DCHECK(at->IsLoadClass() || at->IsClinitCheck());
199 }
200
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000201 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000202 LocationSummary* locations = at_->GetLocations();
203 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
204 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000205 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000206
207 InvokeRuntimeCallingConvention calling_convention;
208 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls_->GetTypeIndex()));
209 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
210 __ fs()->call(Address::Absolute(do_clinit_
211 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage)
212 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeType)));
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000213 RecordPcInfo(codegen, at_, dex_pc_);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000214
215 // Move the class to the desired location.
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000216 Location out = locations->Out();
217 if (out.IsValid()) {
218 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
219 x86_codegen->Move32(out, Location::RegisterLocation(EAX));
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000220 }
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000221
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000222 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray424f6762014-11-03 14:51:25 +0000223 __ jmp(GetExitLabel());
224 }
225
226 private:
227 // The class this slow path will load.
228 HLoadClass* const cls_;
229
230 // The instruction where this slow path is happening.
231 // (Might be the load class or an initialization check).
232 HInstruction* const at_;
233
234 // The dex PC of `at_`.
235 const uint32_t dex_pc_;
236
237 // Whether to initialize the class.
238 const bool do_clinit_;
239
240 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86);
241};
242
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000243class TypeCheckSlowPathX86 : public SlowPathCodeX86 {
244 public:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000245 TypeCheckSlowPathX86(HInstruction* instruction,
246 Location class_to_check,
247 Location object_class,
248 uint32_t dex_pc)
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000249 : instruction_(instruction),
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000250 class_to_check_(class_to_check),
251 object_class_(object_class),
252 dex_pc_(dex_pc) {}
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000253
Alexandre Rames2ed20af2015-03-06 13:55:35 +0000254 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000255 LocationSummary* locations = instruction_->GetLocations();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000256 DCHECK(instruction_->IsCheckCast()
257 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000258
259 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
260 __ Bind(GetEntryLabel());
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000261 SaveLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000262
263 // We're moving two locations to locations that could overlap, so we need a parallel
264 // move resolver.
265 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffrayf0e39372014-11-12 17:50:07 +0000266 x86_codegen->EmitParallelMoves(
267 class_to_check_,
268 Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
269 object_class_,
270 Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000271
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000272 if (instruction_->IsInstanceOf()) {
Roland Levillain199f3362014-11-27 17:15:16 +0000273 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize,
274 pInstanceofNonTrivial)));
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000275 } else {
276 DCHECK(instruction_->IsCheckCast());
277 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pCheckCast)));
278 }
279
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000280 RecordPcInfo(codegen, instruction_, dex_pc_);
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000281 if (instruction_->IsInstanceOf()) {
282 x86_codegen->Move32(locations->Out(), Location::RegisterLocation(EAX));
283 }
Nicolas Geoffraya8ac9132015-03-13 16:36:36 +0000284 RestoreLiveRegisters(codegen, locations);
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000285
286 __ jmp(GetExitLabel());
287 }
288
289 private:
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000290 HInstruction* const instruction_;
291 const Location class_to_check_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000292 const Location object_class_;
Nicolas Geoffray57a88d42014-11-10 15:09:21 +0000293 const uint32_t dex_pc_;
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +0000294
295 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathX86);
296};
297
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100298#undef __
299#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
300
Dave Allison20dfc792014-06-16 20:44:29 -0700301inline Condition X86Condition(IfCondition cond) {
302 switch (cond) {
303 case kCondEQ: return kEqual;
304 case kCondNE: return kNotEqual;
305 case kCondLT: return kLess;
306 case kCondLE: return kLessEqual;
307 case kCondGT: return kGreater;
308 case kCondGE: return kGreaterEqual;
309 default:
310 LOG(FATAL) << "Unknown if condition";
311 }
312 return kEqual;
313}
314
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100315void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
316 stream << X86ManagedRegister::FromCpuRegister(Register(reg));
317}
318
319void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
320 stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
321}
322
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100323size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
324 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
325 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100326}
327
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100328size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
329 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
330 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100331}
332
Mark Mendell7c8d0092015-01-26 11:21:33 -0500333size_t CodeGeneratorX86::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
334 __ movsd(Address(ESP, stack_index), XmmRegister(reg_id));
335 return GetFloatingPointSpillSlotSize();
336}
337
338size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) {
339 __ movsd(XmmRegister(reg_id), Address(ESP, stack_index));
340 return GetFloatingPointSpillSlotSize();
341}
342
Calin Juravlecd6dffe2015-01-08 17:35:35 +0000343CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, const CompilerOptions& compiler_options)
Mark Mendell5f874182015-03-04 15:42:45 -0500344 : CodeGenerator(graph,
345 kNumberOfCpuRegisters,
346 kNumberOfXmmRegisters,
347 kNumberOfRegisterPairs,
348 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves),
349 arraysize(kCoreCalleeSaves))
350 | (1 << kFakeReturnRegister),
351 0,
352 compiler_options),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100353 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100354 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100355 instruction_visitor_(graph, this),
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000356 move_resolver_(graph->GetArena(), this) {
357 // Use a fake return address register to mimic Quick.
358 AddAllocatedRegister(Location::RegisterLocation(kFakeReturnRegister));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100359}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100360
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100361Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100362 switch (type) {
363 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100364 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100365 X86ManagedRegister pair =
366 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100367 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
368 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100369 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
370 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100371 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100372 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100373 }
374
375 case Primitive::kPrimByte:
376 case Primitive::kPrimBoolean:
377 case Primitive::kPrimChar:
378 case Primitive::kPrimShort:
379 case Primitive::kPrimInt:
380 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100381 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100382 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100383 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100384 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
385 X86ManagedRegister current =
386 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
387 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100388 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100389 }
390 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100391 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100392 }
393
394 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100395 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100396 return Location::FpuRegisterLocation(
397 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100398 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100399
400 case Primitive::kPrimVoid:
401 LOG(FATAL) << "Unreachable type " << type;
402 }
403
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100404 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100405}
406
Mark Mendell5f874182015-03-04 15:42:45 -0500407void CodeGeneratorX86::SetupBlockedRegisters(bool is_baseline) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100408 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100409 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100410
411 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100412 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100413
Mark Mendell5f874182015-03-04 15:42:45 -0500414 if (is_baseline) {
415 blocked_core_registers_[EBP] = true;
416 blocked_core_registers_[ESI] = true;
417 blocked_core_registers_[EDI] = true;
418 }
Calin Juravle34bacdf2014-10-07 20:23:36 +0100419
420 UpdateBlockedPairRegisters();
421}
422
423void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
424 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
425 X86ManagedRegister current =
426 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
427 if (blocked_core_registers_[current.AsRegisterPairLow()]
428 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
429 blocked_register_pairs_[i] = true;
430 }
431 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100432}
433
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100434InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
435 : HGraphVisitor(graph),
436 assembler_(codegen->GetAssembler()),
437 codegen_(codegen) {}
438
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000439void CodeGeneratorX86::GenerateFrameEntry() {
Nicolas Geoffray1cf95282014-12-12 19:22:03 +0000440 __ Bind(&frame_entry_label_);
Roland Levillain199f3362014-11-27 17:15:16 +0000441 bool skip_overflow_check =
442 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000443 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks());
Calin Juravle93edf732015-01-20 20:14:07 +0000444
Nicolas Geoffrayd97dc402015-01-22 13:50:01 +0000445 if (!skip_overflow_check) {
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100446 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100447 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100448 }
449
Mark Mendell5f874182015-03-04 15:42:45 -0500450 if (HasEmptyFrame()) {
451 return;
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000452 }
Mark Mendell5f874182015-03-04 15:42:45 -0500453
454 for (int i = arraysize(kCoreCalleeSaves) - 1; i >= 0; --i) {
455 Register reg = kCoreCalleeSaves[i];
456 if (allocated_registers_.ContainsCoreRegister(reg)) {
457 __ pushl(reg);
458 }
459 }
460
461 __ subl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize()));
462 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000463}
464
465void CodeGeneratorX86::GenerateFrameExit() {
Mark Mendell5f874182015-03-04 15:42:45 -0500466 if (HasEmptyFrame()) {
467 return;
468 }
469
470 __ addl(ESP, Immediate(GetFrameSize() - FrameEntrySpillSize()));
471
472 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) {
473 Register reg = kCoreCalleeSaves[i];
474 if (allocated_registers_.ContainsCoreRegister(reg)) {
475 __ popl(reg);
476 }
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000477 }
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000478}
479
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100480void CodeGeneratorX86::Bind(HBasicBlock* block) {
481 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000482}
483
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100484void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
Nicolas Geoffrayc0572a42015-02-06 14:35:25 +0000485 DCHECK(RequiresCurrentMethod());
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100486 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000487}
488
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100489Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
490 switch (load->GetType()) {
491 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100492 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100493 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
494 break;
495
496 case Primitive::kPrimInt:
497 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100498 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100499 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100500
501 case Primitive::kPrimBoolean:
502 case Primitive::kPrimByte:
503 case Primitive::kPrimChar:
504 case Primitive::kPrimShort:
505 case Primitive::kPrimVoid:
506 LOG(FATAL) << "Unexpected type " << load->GetType();
507 }
508
509 LOG(FATAL) << "Unreachable";
510 return Location();
511}
512
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100513Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
514 switch (type) {
515 case Primitive::kPrimBoolean:
516 case Primitive::kPrimByte:
517 case Primitive::kPrimChar:
518 case Primitive::kPrimShort:
519 case Primitive::kPrimInt:
520 case Primitive::kPrimNot: {
521 uint32_t index = gp_index_++;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000522 stack_index_++;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100523 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100524 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100525 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000526 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100527 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100528 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100529
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000530 case Primitive::kPrimLong: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100531 uint32_t index = gp_index_;
532 gp_index_ += 2;
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000533 stack_index_ += 2;
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100534 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100535 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
536 calling_convention.GetRegisterPairAt(index));
537 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100538 } else {
Mark P Mendell966c3ae2015-01-27 15:45:27 +0000539 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
540 }
541 }
542
543 case Primitive::kPrimFloat: {
544 uint32_t index = fp_index_++;
545 stack_index_++;
546 if (index < calling_convention.GetNumberOfFpuRegisters()) {
547 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
548 } else {
549 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
550 }
551 }
552
553 case Primitive::kPrimDouble: {
554 uint32_t index = fp_index_++;
555 stack_index_ += 2;
556 if (index < calling_convention.GetNumberOfFpuRegisters()) {
557 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(index));
558 } else {
559 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100560 }
561 }
562
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100563 case Primitive::kPrimVoid:
564 LOG(FATAL) << "Unexpected parameter type " << type;
565 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100566 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100567 return Location();
568}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100569
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100570void CodeGeneratorX86::Move32(Location destination, Location source) {
571 if (source.Equals(destination)) {
572 return;
573 }
574 if (destination.IsRegister()) {
575 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000576 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100577 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000578 __ movd(destination.AsRegister<Register>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100579 } else {
580 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000581 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100582 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100583 } else if (destination.IsFpuRegister()) {
584 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000585 __ movd(destination.AsFpuRegister<XmmRegister>(), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100586 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000587 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100588 } else {
589 DCHECK(source.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +0000590 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100591 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100592 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000593 DCHECK(destination.IsStackSlot()) << destination;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100594 if (source.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000595 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100596 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000597 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Mark Mendell7c8d0092015-01-26 11:21:33 -0500598 } else if (source.IsConstant()) {
599 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000600 int32_t value = GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -0500601 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100602 } else {
603 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100604 __ pushl(Address(ESP, source.GetStackIndex()));
605 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100606 }
607 }
608}
609
610void CodeGeneratorX86::Move64(Location destination, Location source) {
611 if (source.Equals(destination)) {
612 return;
613 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100614 if (destination.IsRegisterPair()) {
615 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000616 EmitParallelMoves(
617 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()),
618 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()),
619 Location::RegisterLocation(source.AsRegisterPairLow<Register>()),
620 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100621 } else if (source.IsFpuRegister()) {
622 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100623 } else {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000624 // No conflict possible, so just do the moves.
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100625 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100626 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
627 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100628 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
629 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100630 } else if (destination.IsFpuRegister()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -0500631 if (source.IsFpuRegister()) {
632 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
633 } else if (source.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000634 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100635 } else {
636 LOG(FATAL) << "Unimplemented";
637 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100638 } else {
Calin Juravled6fb6cf2014-11-11 19:07:44 +0000639 DCHECK(destination.IsDoubleStackSlot()) << destination;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100640 if (source.IsRegisterPair()) {
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000641 // No conflict possible, so just do the moves.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100642 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100643 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100644 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100645 } else if (source.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000646 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000647 } else if (source.IsConstant()) {
648 HConstant* constant = source.GetConstant();
649 int64_t value;
650 if (constant->IsLongConstant()) {
651 value = constant->AsLongConstant()->GetValue();
652 } else {
653 DCHECK(constant->IsDoubleConstant());
Roland Levillainda4d79b2015-03-24 14:36:11 +0000654 value = bit_cast<int64_t, double>(constant->AsDoubleConstant()->GetValue());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000655 }
656 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(Low32Bits(value)));
657 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100658 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +0000659 DCHECK(source.IsDoubleStackSlot()) << source;
Nicolas Geoffray32b2a522014-11-27 14:54:18 +0000660 EmitParallelMoves(
661 Location::StackSlot(source.GetStackIndex()),
662 Location::StackSlot(destination.GetStackIndex()),
663 Location::StackSlot(source.GetHighStackIndex(kX86WordSize)),
664 Location::StackSlot(destination.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100665 }
666 }
667}
668
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100669void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Calin Juravlea21f5982014-11-13 15:53:04 +0000670 LocationSummary* locations = instruction->GetLocations();
671 if (locations != nullptr && locations->Out().Equals(location)) {
672 return;
673 }
674
675 if (locations != nullptr && locations->Out().IsConstant()) {
676 HConstant* const_to_move = locations->Out().GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +0000677 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) {
678 Immediate imm(GetInt32ValueOf(const_to_move));
Calin Juravlea21f5982014-11-13 15:53:04 +0000679 if (location.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000680 __ movl(location.AsRegister<Register>(), imm);
Calin Juravlea21f5982014-11-13 15:53:04 +0000681 } else if (location.IsStackSlot()) {
682 __ movl(Address(ESP, location.GetStackIndex()), imm);
683 } else {
684 DCHECK(location.IsConstant());
685 DCHECK_EQ(location.GetConstant(), const_to_move);
686 }
687 } else if (const_to_move->IsLongConstant()) {
688 int64_t value = const_to_move->AsLongConstant()->GetValue();
689 if (location.IsRegisterPair()) {
690 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
691 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
692 } else if (location.IsDoubleStackSlot()) {
693 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
Roland Levillain199f3362014-11-27 17:15:16 +0000694 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)),
695 Immediate(High32Bits(value)));
Calin Juravlea21f5982014-11-13 15:53:04 +0000696 } else {
697 DCHECK(location.IsConstant());
698 DCHECK_EQ(location.GetConstant(), instruction);
699 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100700 }
Nicolas Geoffrayf43083d2014-11-07 10:48:10 +0000701 } else if (instruction->IsTemporary()) {
702 Location temp_location = GetTemporaryLocation(instruction->AsTemporary());
Calin Juravlef97f9fb2014-11-11 15:38:19 +0000703 if (temp_location.IsStackSlot()) {
704 Move32(location, temp_location);
705 } else {
706 DCHECK(temp_location.IsDoubleStackSlot());
707 Move64(location, temp_location);
708 }
Roland Levillain476df552014-10-09 17:51:36 +0100709 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100710 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100711 switch (instruction->GetType()) {
712 case Primitive::kPrimBoolean:
713 case Primitive::kPrimByte:
714 case Primitive::kPrimChar:
715 case Primitive::kPrimShort:
716 case Primitive::kPrimInt:
717 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100718 case Primitive::kPrimFloat:
719 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100720 break;
721
722 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100723 case Primitive::kPrimDouble:
724 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100725 break;
726
727 default:
728 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
729 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000730 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100731 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100732 switch (instruction->GetType()) {
733 case Primitive::kPrimBoolean:
734 case Primitive::kPrimByte:
735 case Primitive::kPrimChar:
736 case Primitive::kPrimShort:
737 case Primitive::kPrimInt:
738 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100739 case Primitive::kPrimFloat:
Calin Juravlea21f5982014-11-13 15:53:04 +0000740 Move32(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100741 break;
742
743 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100744 case Primitive::kPrimDouble:
Calin Juravlea21f5982014-11-13 15:53:04 +0000745 Move64(location, locations->Out());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100746 break;
747
748 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100749 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100750 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000751 }
752}
753
754void LocationsBuilderX86::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000755 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000756}
757
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000758void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000759 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100760 DCHECK(!successor->IsExitBlock());
761
762 HBasicBlock* block = got->GetBlock();
763 HInstruction* previous = got->GetPrevious();
764
765 HLoopInformation* info = block->GetLoopInformation();
David Brazdil46e2a392015-03-16 17:31:52 +0000766 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100767 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
768 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
769 return;
770 }
771
772 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
773 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
774 }
775 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000776 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000777 }
778}
779
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000780void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000781 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000782}
783
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000784void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700785 UNUSED(exit);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000786}
787
Andreas Gampe0ba62732015-03-24 02:39:46 +0000788void LocationsBuilderX86::VisitIf(HIf* if_instr) {
789 LocationSummary* locations =
790 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
791 HInstruction* cond = if_instr->InputAt(0);
792 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
793 locations->SetInAt(0, Location::Any());
794 }
795}
796
797void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
798 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100799 if (cond->IsIntConstant()) {
800 // Constant condition, statically compared against 1.
801 int32_t cond_value = cond->AsIntConstant()->GetValue();
802 if (cond_value == 1) {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000803 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
804 if_instr->IfTrueSuccessor())) {
805 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100806 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100807 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100808 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100809 DCHECK_EQ(cond_value, 0);
810 }
811 } else {
812 bool materialized =
813 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
814 // Moves do not affect the eflags register, so if the condition is
815 // evaluated just before the if, we don't need to evaluate it
816 // again.
817 bool eflags_set = cond->IsCondition()
Andreas Gampe0ba62732015-03-24 02:39:46 +0000818 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100819 if (materialized) {
820 if (!eflags_set) {
821 // Materialized condition, compare against 0.
Andreas Gampe0ba62732015-03-24 02:39:46 +0000822 Location lhs = if_instr->GetLocations()->InAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100823 if (lhs.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -0500824 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100825 } else {
826 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
827 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000828 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100829 } else {
Andreas Gampe0ba62732015-03-24 02:39:46 +0000830 __ j(X86Condition(cond->AsCondition()->GetCondition()),
831 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100832 }
833 } else {
834 Location lhs = cond->GetLocations()->InAt(0);
835 Location rhs = cond->GetLocations()->InAt(1);
836 // LHS is guaranteed to be in a register (see
837 // LocationsBuilderX86::VisitCondition).
838 if (rhs.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000839 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100840 } else if (rhs.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -0500841 int32_t constant = rhs.GetConstant()->AsIntConstant()->GetValue();
842 if (constant == 0) {
843 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
844 } else {
845 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
846 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100847 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +0000848 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100849 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000850 __ j(X86Condition(cond->AsCondition()->GetCondition()),
851 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700852 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100853 }
Andreas Gampe0ba62732015-03-24 02:39:46 +0000854 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
855 if_instr->IfFalseSuccessor())) {
856 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000857 }
858}
859
860void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000861 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000862}
863
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000864void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
865 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000866}
867
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000868void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100869 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000870}
871
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000872void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100873 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700874 UNUSED(load);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000875}
876
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100877void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100878 LocationSummary* locations =
879 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100880 switch (store->InputAt(1)->GetType()) {
881 case Primitive::kPrimBoolean:
882 case Primitive::kPrimByte:
883 case Primitive::kPrimChar:
884 case Primitive::kPrimShort:
885 case Primitive::kPrimInt:
886 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100887 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100888 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
889 break;
890
891 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100892 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100893 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
894 break;
895
896 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100897 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100898 }
899 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000900}
901
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000902void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700903 UNUSED(store);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000904}
905
Dave Allison20dfc792014-06-16 20:44:29 -0700906void LocationsBuilderX86::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100907 LocationSummary* locations =
908 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100909 locations->SetInAt(0, Location::RequiresRegister());
910 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100911 if (comp->NeedsMaterialization()) {
Mark Mendell5f874182015-03-04 15:42:45 -0500912 // We need a byte register.
913 locations->SetOut(Location::RegisterLocation(ECX));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100914 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000915}
916
Dave Allison20dfc792014-06-16 20:44:29 -0700917void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
918 if (comp->NeedsMaterialization()) {
919 LocationSummary* locations = comp->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +0000920 Register reg = locations->Out().AsRegister<Register>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100921 // Clear register: setcc only sets the low byte.
922 __ xorl(reg, reg);
Mark Mendell09b84632015-02-13 17:48:38 -0500923 Location lhs = locations->InAt(0);
924 Location rhs = locations->InAt(1);
925 if (rhs.IsRegister()) {
926 __ cmpl(lhs.AsRegister<Register>(), rhs.AsRegister<Register>());
927 } else if (rhs.IsConstant()) {
Mingyao Yang8928cab2015-03-03 16:15:23 -0800928 int32_t constant = CodeGenerator::GetInt32ValueOf(rhs.GetConstant());
Mark Mendell09b84632015-02-13 17:48:38 -0500929 if (constant == 0) {
930 __ testl(lhs.AsRegister<Register>(), lhs.AsRegister<Register>());
931 } else {
932 __ cmpl(lhs.AsRegister<Register>(), Immediate(constant));
933 }
Dave Allison20dfc792014-06-16 20:44:29 -0700934 } else {
Mark Mendell09b84632015-02-13 17:48:38 -0500935 __ cmpl(lhs.AsRegister<Register>(), Address(ESP, rhs.GetStackIndex()));
Dave Allison20dfc792014-06-16 20:44:29 -0700936 }
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +0000937 __ setb(X86Condition(comp->GetCondition()), reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100938 }
Dave Allison20dfc792014-06-16 20:44:29 -0700939}
940
941void LocationsBuilderX86::VisitEqual(HEqual* comp) {
942 VisitCondition(comp);
943}
944
945void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
946 VisitCondition(comp);
947}
948
949void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
950 VisitCondition(comp);
951}
952
953void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
954 VisitCondition(comp);
955}
956
957void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
958 VisitCondition(comp);
959}
960
961void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
962 VisitCondition(comp);
963}
964
965void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
966 VisitCondition(comp);
967}
968
969void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
970 VisitCondition(comp);
971}
972
973void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
974 VisitCondition(comp);
975}
976
977void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
978 VisitCondition(comp);
979}
980
981void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
982 VisitCondition(comp);
983}
984
985void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
986 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000987}
988
989void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100990 LocationSummary* locations =
991 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100992 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000993}
994
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000995void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100996 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -0700997 UNUSED(constant);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000998}
999
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00001000void LocationsBuilderX86::VisitNullConstant(HNullConstant* constant) {
1001 LocationSummary* locations =
1002 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1003 locations->SetOut(Location::ConstantLocation(constant));
1004}
1005
1006void InstructionCodeGeneratorX86::VisitNullConstant(HNullConstant* constant) {
1007 // Will be generated at use site.
1008 UNUSED(constant);
1009}
1010
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001011void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001012 LocationSummary* locations =
1013 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001014 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001015}
1016
1017void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
1018 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001019 UNUSED(constant);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001020}
1021
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001022void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
1023 LocationSummary* locations =
1024 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1025 locations->SetOut(Location::ConstantLocation(constant));
1026}
1027
1028void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
1029 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001030 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001031}
1032
1033void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
1034 LocationSummary* locations =
1035 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
1036 locations->SetOut(Location::ConstantLocation(constant));
1037}
1038
1039void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
1040 // Will be generated at use site.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001041 UNUSED(constant);
Nicolas Geoffray102cbed2014-10-15 18:31:05 +01001042}
1043
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001044void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001045 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +00001046}
1047
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001048void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07001049 UNUSED(ret);
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001050 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001051 __ ret();
1052}
1053
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001054void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001055 LocationSummary* locations =
1056 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001057 switch (ret->InputAt(0)->GetType()) {
1058 case Primitive::kPrimBoolean:
1059 case Primitive::kPrimByte:
1060 case Primitive::kPrimChar:
1061 case Primitive::kPrimShort:
1062 case Primitive::kPrimInt:
1063 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001064 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001065 break;
1066
1067 case Primitive::kPrimLong:
1068 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001069 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001070 break;
1071
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001072 case Primitive::kPrimFloat:
1073 case Primitive::kPrimDouble:
1074 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001075 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001076 break;
1077
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001078 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001079 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001080 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001081}
1082
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001083void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001084 if (kIsDebugBuild) {
1085 switch (ret->InputAt(0)->GetType()) {
1086 case Primitive::kPrimBoolean:
1087 case Primitive::kPrimByte:
1088 case Primitive::kPrimChar:
1089 case Primitive::kPrimShort:
1090 case Primitive::kPrimInt:
1091 case Primitive::kPrimNot:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001092 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegister<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001093 break;
1094
1095 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001096 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
1097 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001098 break;
1099
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001100 case Primitive::kPrimFloat:
1101 case Primitive::kPrimDouble:
Roland Levillain271ab9c2014-11-27 15:23:57 +00001102 DCHECK_EQ(ret->GetLocations()->InAt(0).AsFpuRegister<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001103 break;
1104
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001105 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001106 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001107 }
1108 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +00001109 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +00001110 __ ret();
1111}
1112
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001113void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendell09ed1a32015-03-25 08:30:06 -04001114 IntrinsicLocationsBuilderX86 intrinsic(GetGraph()->GetArena());
1115 if (intrinsic.TryDispatch(invoke)) {
1116 return;
1117 }
1118
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001119 HandleInvoke(invoke);
1120}
1121
Mark Mendell09ed1a32015-03-25 08:30:06 -04001122static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorX86* codegen) {
1123 if (invoke->GetLocations()->Intrinsified()) {
1124 IntrinsicCodeGeneratorX86 intrinsic(codegen);
1125 intrinsic.Dispatch(invoke);
1126 return true;
1127 }
1128 return false;
1129}
1130
Nicolas Geoffraye53798a2014-12-01 10:31:54 +00001131void InstructionCodeGeneratorX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) {
Mark Mendell09ed1a32015-03-25 08:30:06 -04001132 if (TryGenerateIntrinsicCode(invoke, codegen_)) {
1133 return;
Nicolas Geoffray1cf95282014-12-12 19:22:03 +00001134 }
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001135
Mark Mendell09ed1a32015-03-25 08:30:06 -04001136 codegen_->GenerateStaticOrDirectCall(
1137 invoke, invoke->GetLocations()->GetTemp(0).AsRegister<Register>());
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001138}
1139
1140void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
1141 HandleInvoke(invoke);
1142}
1143
1144void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001145 LocationSummary* locations =
1146 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001147 locations->AddTemp(Location::RegisterLocation(EAX));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001148
1149 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001150 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +01001151 HInstruction* input = invoke->InputAt(i);
1152 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
1153 }
1154
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001155 switch (invoke->GetType()) {
1156 case Primitive::kPrimBoolean:
1157 case Primitive::kPrimByte:
1158 case Primitive::kPrimChar:
1159 case Primitive::kPrimShort:
1160 case Primitive::kPrimInt:
1161 case Primitive::kPrimNot:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001162 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001163 break;
1164
1165 case Primitive::kPrimLong:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001166 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001167 break;
1168
1169 case Primitive::kPrimVoid:
1170 break;
1171
1172 case Primitive::kPrimDouble:
1173 case Primitive::kPrimFloat:
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001174 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001175 break;
1176 }
1177
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001178 invoke->SetLocations(locations);
1179}
1180
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001181void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001182 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001183 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
1184 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
1185 LocationSummary* locations = invoke->GetLocations();
1186 Location receiver = locations->InAt(0);
1187 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1188 // temp = object->GetClass();
1189 if (receiver.IsStackSlot()) {
1190 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1191 __ movl(temp, Address(temp, class_offset));
1192 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001193 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001194 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001195 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001196 // temp = temp->GetMethodAt(method_offset);
1197 __ movl(temp, Address(temp, method_offset));
1198 // call temp->GetEntryPoint();
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001199 __ call(Address(
1200 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001201
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001202 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001203 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001204}
1205
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001206void LocationsBuilderX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1207 HandleInvoke(invoke);
1208 // Add the hidden argument.
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001209 invoke->GetLocations()->AddTemp(Location::FpuRegisterLocation(XMM7));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001210}
1211
1212void InstructionCodeGeneratorX86::VisitInvokeInterface(HInvokeInterface* invoke) {
1213 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001214 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001215 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() +
1216 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry);
1217 LocationSummary* locations = invoke->GetLocations();
1218 Location receiver = locations->InAt(0);
1219 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1220
1221 // Set the hidden argument.
1222 __ movl(temp, Immediate(invoke->GetDexMethodIndex()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001223 __ movd(invoke->GetLocations()->GetTemp(1).AsFpuRegister<XmmRegister>(), temp);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001224
1225 // temp = object->GetClass();
1226 if (receiver.IsStackSlot()) {
1227 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1228 __ movl(temp, Address(temp, class_offset));
1229 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001230 __ movl(temp, Address(receiver.AsRegister<Register>(), class_offset));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001231 }
Calin Juravle77520bc2015-01-12 18:45:46 +00001232 codegen_->MaybeRecordImplicitNullCheck(invoke);
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001233 // temp = temp->GetImtEntryAt(method_offset);
1234 __ movl(temp, Address(temp, method_offset));
1235 // call temp->GetEntryPoint();
Mathieu Chartier2d721012014-11-10 11:08:06 -08001236 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
Nicolas Geoffray86a8d7a2014-11-19 08:47:18 +00001237 kX86WordSize).Int32Value()));
Nicolas Geoffray52839d12014-11-07 17:47:25 +00001238
1239 DCHECK(!codegen_->IsLeafMethod());
1240 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
1241}
1242
Roland Levillain88cb1752014-10-20 16:36:47 +01001243void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1244 LocationSummary* locations =
1245 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1246 switch (neg->GetResultType()) {
1247 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001248 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001249 locations->SetInAt(0, Location::RequiresRegister());
1250 locations->SetOut(Location::SameAsFirstInput());
1251 break;
1252
Roland Levillain88cb1752014-10-20 16:36:47 +01001253 case Primitive::kPrimFloat:
Roland Levillain5368c212014-11-27 15:03:41 +00001254 locations->SetInAt(0, Location::RequiresFpuRegister());
1255 locations->SetOut(Location::SameAsFirstInput());
1256 locations->AddTemp(Location::RequiresRegister());
1257 locations->AddTemp(Location::RequiresFpuRegister());
1258 break;
1259
Roland Levillain88cb1752014-10-20 16:36:47 +01001260 case Primitive::kPrimDouble:
Roland Levillain3dbcb382014-10-28 17:30:07 +00001261 locations->SetInAt(0, Location::RequiresFpuRegister());
Roland Levillain5368c212014-11-27 15:03:41 +00001262 locations->SetOut(Location::SameAsFirstInput());
1263 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain88cb1752014-10-20 16:36:47 +01001264 break;
1265
1266 default:
1267 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1268 }
1269}
1270
1271void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1272 LocationSummary* locations = neg->GetLocations();
1273 Location out = locations->Out();
1274 Location in = locations->InAt(0);
1275 switch (neg->GetResultType()) {
1276 case Primitive::kPrimInt:
1277 DCHECK(in.IsRegister());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001278 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001279 __ negl(out.AsRegister<Register>());
Roland Levillain88cb1752014-10-20 16:36:47 +01001280 break;
1281
1282 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001283 DCHECK(in.IsRegisterPair());
Roland Levillain3dbcb382014-10-28 17:30:07 +00001284 DCHECK(in.Equals(out));
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001285 __ negl(out.AsRegisterPairLow<Register>());
1286 // Negation is similar to subtraction from zero. The least
1287 // significant byte triggers a borrow when it is different from
1288 // zero; to take it into account, add 1 to the most significant
1289 // byte if the carry flag (CF) is set to 1 after the first NEGL
1290 // operation.
1291 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1292 __ negl(out.AsRegisterPairHigh<Register>());
1293 break;
1294
Roland Levillain5368c212014-11-27 15:03:41 +00001295 case Primitive::kPrimFloat: {
1296 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001297 Register constant = locations->GetTemp(0).AsRegister<Register>();
1298 XmmRegister mask = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001299 // Implement float negation with an exclusive or with value
1300 // 0x80000000 (mask for bit 31, representing the sign of a
1301 // single-precision floating-point number).
1302 __ movl(constant, Immediate(INT32_C(0x80000000)));
1303 __ movd(mask, constant);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001304 __ xorps(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain3dbcb382014-10-28 17:30:07 +00001305 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001306 }
Roland Levillain3dbcb382014-10-28 17:30:07 +00001307
Roland Levillain5368c212014-11-27 15:03:41 +00001308 case Primitive::kPrimDouble: {
1309 DCHECK(in.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001310 XmmRegister mask = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
Roland Levillain5368c212014-11-27 15:03:41 +00001311 // Implement double negation with an exclusive or with value
1312 // 0x8000000000000000 (mask for bit 63, representing the sign of
1313 // a double-precision floating-point number).
1314 __ LoadLongConstant(mask, INT64_C(0x8000000000000000));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001315 __ xorpd(out.AsFpuRegister<XmmRegister>(), mask);
Roland Levillain88cb1752014-10-20 16:36:47 +01001316 break;
Roland Levillain5368c212014-11-27 15:03:41 +00001317 }
Roland Levillain88cb1752014-10-20 16:36:47 +01001318
1319 default:
1320 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1321 }
1322}
1323
Roland Levillaindff1f282014-11-05 14:15:05 +00001324void LocationsBuilderX86::VisitTypeConversion(HTypeConversion* conversion) {
Roland Levillaindff1f282014-11-05 14:15:05 +00001325 Primitive::Type result_type = conversion->GetResultType();
1326 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001327 DCHECK_NE(result_type, input_type);
Roland Levillain624279f2014-12-04 11:54:28 +00001328
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001329 // The float-to-long and double-to-long type conversions rely on a
1330 // call to the runtime.
Roland Levillain624279f2014-12-04 11:54:28 +00001331 LocationSummary::CallKind call_kind =
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001332 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble)
1333 && result_type == Primitive::kPrimLong)
Roland Levillain624279f2014-12-04 11:54:28 +00001334 ? LocationSummary::kCall
1335 : LocationSummary::kNoCall;
1336 LocationSummary* locations =
1337 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind);
1338
David Brazdilb2bd1c52015-03-25 11:17:37 +00001339 // The Java language does not allow treating boolean as an integral type but
1340 // our bit representation makes it safe.
David Brazdil46e2a392015-03-16 17:31:52 +00001341
Roland Levillaindff1f282014-11-05 14:15:05 +00001342 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001343 case Primitive::kPrimByte:
1344 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001345 case Primitive::kPrimBoolean:
1346 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001347 case Primitive::kPrimShort:
1348 case Primitive::kPrimInt:
1349 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001350 // Processing a Dex `int-to-byte' instruction.
Mark Mendell5f874182015-03-04 15:42:45 -05001351 locations->SetInAt(0, Location::ByteRegisterOrConstant(ECX, conversion->InputAt(0)));
1352 // Make the output overlap to please the register allocator. This greatly simplifies
1353 // the validation of the linear scan implementation
1354 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap);
Roland Levillain51d3fc42014-11-13 14:11:42 +00001355 break;
1356
1357 default:
1358 LOG(FATAL) << "Unexpected type conversion from " << input_type
1359 << " to " << result_type;
1360 }
1361 break;
1362
Roland Levillain01a8d712014-11-14 16:27:39 +00001363 case Primitive::kPrimShort:
1364 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001365 case Primitive::kPrimBoolean:
1366 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001367 case Primitive::kPrimByte:
1368 case Primitive::kPrimInt:
1369 case Primitive::kPrimChar:
1370 // Processing a Dex `int-to-short' instruction.
1371 locations->SetInAt(0, Location::Any());
1372 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1373 break;
1374
1375 default:
1376 LOG(FATAL) << "Unexpected type conversion from " << input_type
1377 << " to " << result_type;
1378 }
1379 break;
1380
Roland Levillain946e1432014-11-11 17:35:19 +00001381 case Primitive::kPrimInt:
1382 switch (input_type) {
1383 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001384 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001385 locations->SetInAt(0, Location::Any());
1386 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1387 break;
1388
1389 case Primitive::kPrimFloat:
Roland Levillain3f8f9362014-12-02 17:45:01 +00001390 // Processing a Dex `float-to-int' instruction.
1391 locations->SetInAt(0, Location::RequiresFpuRegister());
1392 locations->SetOut(Location::RequiresRegister());
1393 locations->AddTemp(Location::RequiresFpuRegister());
1394 break;
1395
Roland Levillain946e1432014-11-11 17:35:19 +00001396 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001397 // Processing a Dex `double-to-int' instruction.
1398 locations->SetInAt(0, Location::RequiresFpuRegister());
1399 locations->SetOut(Location::RequiresRegister());
1400 locations->AddTemp(Location::RequiresFpuRegister());
Roland Levillain946e1432014-11-11 17:35:19 +00001401 break;
1402
1403 default:
1404 LOG(FATAL) << "Unexpected type conversion from " << input_type
1405 << " to " << result_type;
1406 }
1407 break;
1408
Roland Levillaindff1f282014-11-05 14:15:05 +00001409 case Primitive::kPrimLong:
1410 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001411 case Primitive::kPrimBoolean:
1412 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001413 case Primitive::kPrimByte:
1414 case Primitive::kPrimShort:
1415 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001416 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001417 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001418 locations->SetInAt(0, Location::RegisterLocation(EAX));
1419 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
1420 break;
1421
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001422 case Primitive::kPrimFloat:
Vladimir Marko949c91f2015-01-27 10:48:44 +00001423 case Primitive::kPrimDouble: {
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001424 // Processing a Dex `float-to-long' or 'double-to-long' instruction.
Vladimir Marko949c91f2015-01-27 10:48:44 +00001425 InvokeRuntimeCallingConvention calling_convention;
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001426 XmmRegister parameter = calling_convention.GetFpuRegisterAt(0);
1427 locations->SetInAt(0, Location::FpuRegisterLocation(parameter));
1428
Vladimir Marko949c91f2015-01-27 10:48:44 +00001429 // The runtime helper puts the result in EAX, EDX.
1430 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Vladimir Marko949c91f2015-01-27 10:48:44 +00001431 }
Mark P Mendell966c3ae2015-01-27 15:45:27 +00001432 break;
Roland Levillaindff1f282014-11-05 14:15:05 +00001433
1434 default:
1435 LOG(FATAL) << "Unexpected type conversion from " << input_type
1436 << " to " << result_type;
1437 }
1438 break;
1439
Roland Levillain981e4542014-11-14 11:47:14 +00001440 case Primitive::kPrimChar:
1441 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001442 case Primitive::kPrimBoolean:
1443 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001444 case Primitive::kPrimByte:
1445 case Primitive::kPrimShort:
1446 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001447 // Processing a Dex `int-to-char' instruction.
1448 locations->SetInAt(0, Location::Any());
1449 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1450 break;
1451
1452 default:
1453 LOG(FATAL) << "Unexpected type conversion from " << input_type
1454 << " to " << result_type;
1455 }
1456 break;
1457
Roland Levillaindff1f282014-11-05 14:15:05 +00001458 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001459 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001460 case Primitive::kPrimBoolean:
1461 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001462 case Primitive::kPrimByte:
1463 case Primitive::kPrimShort:
1464 case Primitive::kPrimInt:
1465 case Primitive::kPrimChar:
1466 // Processing a Dex `int-to-float' instruction.
1467 locations->SetInAt(0, Location::RequiresRegister());
1468 locations->SetOut(Location::RequiresFpuRegister());
1469 break;
1470
1471 case Primitive::kPrimLong:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001472 // Processing a Dex `long-to-float' instruction.
1473 locations->SetInAt(0, Location::RequiresRegister());
1474 locations->SetOut(Location::RequiresFpuRegister());
1475 locations->AddTemp(Location::RequiresFpuRegister());
1476 locations->AddTemp(Location::RequiresFpuRegister());
1477 break;
1478
Roland Levillaincff13742014-11-17 14:32:17 +00001479 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001480 // Processing a Dex `double-to-float' instruction.
1481 locations->SetInAt(0, Location::RequiresFpuRegister());
1482 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001483 break;
1484
1485 default:
1486 LOG(FATAL) << "Unexpected type conversion from " << input_type
1487 << " to " << result_type;
1488 };
1489 break;
1490
Roland Levillaindff1f282014-11-05 14:15:05 +00001491 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001492 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001493 case Primitive::kPrimBoolean:
1494 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001495 case Primitive::kPrimByte:
1496 case Primitive::kPrimShort:
1497 case Primitive::kPrimInt:
1498 case Primitive::kPrimChar:
1499 // Processing a Dex `int-to-double' instruction.
1500 locations->SetInAt(0, Location::RequiresRegister());
1501 locations->SetOut(Location::RequiresFpuRegister());
1502 break;
1503
1504 case Primitive::kPrimLong:
Roland Levillain647b9ed2014-11-27 12:06:00 +00001505 // Processing a Dex `long-to-double' instruction.
1506 locations->SetInAt(0, Location::RequiresRegister());
1507 locations->SetOut(Location::RequiresFpuRegister());
1508 locations->AddTemp(Location::RequiresFpuRegister());
1509 locations->AddTemp(Location::RequiresFpuRegister());
1510 break;
1511
Roland Levillaincff13742014-11-17 14:32:17 +00001512 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001513 // Processing a Dex `float-to-double' instruction.
1514 locations->SetInAt(0, Location::RequiresFpuRegister());
1515 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
Roland Levillaincff13742014-11-17 14:32:17 +00001516 break;
1517
1518 default:
1519 LOG(FATAL) << "Unexpected type conversion from " << input_type
1520 << " to " << result_type;
1521 }
Roland Levillaindff1f282014-11-05 14:15:05 +00001522 break;
1523
1524 default:
1525 LOG(FATAL) << "Unexpected type conversion from " << input_type
1526 << " to " << result_type;
1527 }
1528}
1529
1530void InstructionCodeGeneratorX86::VisitTypeConversion(HTypeConversion* conversion) {
1531 LocationSummary* locations = conversion->GetLocations();
1532 Location out = locations->Out();
1533 Location in = locations->InAt(0);
1534 Primitive::Type result_type = conversion->GetResultType();
1535 Primitive::Type input_type = conversion->GetInputType();
Nicolas Geoffray01fcc9e2014-12-01 14:16:20 +00001536 DCHECK_NE(result_type, input_type);
Roland Levillaindff1f282014-11-05 14:15:05 +00001537 switch (result_type) {
Roland Levillain51d3fc42014-11-13 14:11:42 +00001538 case Primitive::kPrimByte:
1539 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001540 case Primitive::kPrimBoolean:
1541 // Boolean input is a result of code transformations.
Roland Levillain51d3fc42014-11-13 14:11:42 +00001542 case Primitive::kPrimShort:
1543 case Primitive::kPrimInt:
1544 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001545 // Processing a Dex `int-to-byte' instruction.
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001546 if (in.IsRegister()) {
1547 __ movsxb(out.AsRegister<Register>(), in.AsRegister<ByteRegister>());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00001548 } else {
1549 DCHECK(in.GetConstant()->IsIntConstant());
1550 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
1551 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int8_t>(value)));
1552 }
Roland Levillain51d3fc42014-11-13 14:11:42 +00001553 break;
1554
1555 default:
1556 LOG(FATAL) << "Unexpected type conversion from " << input_type
1557 << " to " << result_type;
1558 }
1559 break;
1560
Roland Levillain01a8d712014-11-14 16:27:39 +00001561 case Primitive::kPrimShort:
1562 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001563 case Primitive::kPrimBoolean:
1564 // Boolean input is a result of code transformations.
Roland Levillain01a8d712014-11-14 16:27:39 +00001565 case Primitive::kPrimByte:
1566 case Primitive::kPrimInt:
1567 case Primitive::kPrimChar:
1568 // Processing a Dex `int-to-short' instruction.
1569 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001570 __ movsxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain01a8d712014-11-14 16:27:39 +00001571 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001572 __ movsxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain01a8d712014-11-14 16:27:39 +00001573 } else {
1574 DCHECK(in.GetConstant()->IsIntConstant());
1575 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001576 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int16_t>(value)));
Roland Levillain01a8d712014-11-14 16:27:39 +00001577 }
1578 break;
1579
1580 default:
1581 LOG(FATAL) << "Unexpected type conversion from " << input_type
1582 << " to " << result_type;
1583 }
1584 break;
1585
Roland Levillain946e1432014-11-11 17:35:19 +00001586 case Primitive::kPrimInt:
1587 switch (input_type) {
1588 case Primitive::kPrimLong:
Roland Levillain981e4542014-11-14 11:47:14 +00001589 // Processing a Dex `long-to-int' instruction.
Roland Levillain946e1432014-11-11 17:35:19 +00001590 if (in.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001591 __ movl(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>());
Roland Levillain946e1432014-11-11 17:35:19 +00001592 } else if (in.IsDoubleStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001593 __ movl(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain946e1432014-11-11 17:35:19 +00001594 } else {
1595 DCHECK(in.IsConstant());
1596 DCHECK(in.GetConstant()->IsLongConstant());
1597 int64_t value = in.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001598 __ movl(out.AsRegister<Register>(), Immediate(static_cast<int32_t>(value)));
Roland Levillain946e1432014-11-11 17:35:19 +00001599 }
1600 break;
1601
Roland Levillain3f8f9362014-12-02 17:45:01 +00001602 case Primitive::kPrimFloat: {
1603 // Processing a Dex `float-to-int' instruction.
1604 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1605 Register output = out.AsRegister<Register>();
1606 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1607 Label done, nan;
1608
1609 __ movl(output, Immediate(kPrimIntMax));
1610 // temp = int-to-float(output)
1611 __ cvtsi2ss(temp, output);
1612 // if input >= temp goto done
1613 __ comiss(input, temp);
1614 __ j(kAboveEqual, &done);
1615 // if input == NaN goto nan
1616 __ j(kUnordered, &nan);
1617 // output = float-to-int-truncate(input)
1618 __ cvttss2si(output, input);
1619 __ jmp(&done);
1620 __ Bind(&nan);
1621 // output = 0
1622 __ xorl(output, output);
1623 __ Bind(&done);
1624 break;
1625 }
1626
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001627 case Primitive::kPrimDouble: {
1628 // Processing a Dex `double-to-int' instruction.
1629 XmmRegister input = in.AsFpuRegister<XmmRegister>();
1630 Register output = out.AsRegister<Register>();
1631 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1632 Label done, nan;
1633
1634 __ movl(output, Immediate(kPrimIntMax));
1635 // temp = int-to-double(output)
1636 __ cvtsi2sd(temp, output);
1637 // if input >= temp goto done
1638 __ comisd(input, temp);
1639 __ j(kAboveEqual, &done);
1640 // if input == NaN goto nan
1641 __ j(kUnordered, &nan);
1642 // output = double-to-int-truncate(input)
1643 __ cvttsd2si(output, input);
1644 __ jmp(&done);
1645 __ Bind(&nan);
1646 // output = 0
1647 __ xorl(output, output);
1648 __ Bind(&done);
Roland Levillain946e1432014-11-11 17:35:19 +00001649 break;
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001650 }
Roland Levillain946e1432014-11-11 17:35:19 +00001651
1652 default:
1653 LOG(FATAL) << "Unexpected type conversion from " << input_type
1654 << " to " << result_type;
1655 }
1656 break;
1657
Roland Levillaindff1f282014-11-05 14:15:05 +00001658 case Primitive::kPrimLong:
1659 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001660 case Primitive::kPrimBoolean:
1661 // Boolean input is a result of code transformations.
Roland Levillaindff1f282014-11-05 14:15:05 +00001662 case Primitive::kPrimByte:
1663 case Primitive::kPrimShort:
1664 case Primitive::kPrimInt:
Roland Levillain666c7322014-11-10 13:39:43 +00001665 case Primitive::kPrimChar:
Roland Levillain981e4542014-11-14 11:47:14 +00001666 // Processing a Dex `int-to-long' instruction.
Roland Levillaindff1f282014-11-05 14:15:05 +00001667 DCHECK_EQ(out.AsRegisterPairLow<Register>(), EAX);
1668 DCHECK_EQ(out.AsRegisterPairHigh<Register>(), EDX);
Roland Levillain271ab9c2014-11-27 15:23:57 +00001669 DCHECK_EQ(in.AsRegister<Register>(), EAX);
Roland Levillaindff1f282014-11-05 14:15:05 +00001670 __ cdq();
1671 break;
1672
1673 case Primitive::kPrimFloat:
Roland Levillain624279f2014-12-04 11:54:28 +00001674 // Processing a Dex `float-to-long' instruction.
1675 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pF2l)));
Roland Levillain624279f2014-12-04 11:54:28 +00001676 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
1677 break;
1678
Roland Levillaindff1f282014-11-05 14:15:05 +00001679 case Primitive::kPrimDouble:
Roland Levillain4c0b61f2014-12-05 12:06:01 +00001680 // Processing a Dex `double-to-long' instruction.
1681 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pD2l)));
1682 codegen_->RecordPcInfo(conversion, conversion->GetDexPc());
Roland Levillaindff1f282014-11-05 14:15:05 +00001683 break;
1684
1685 default:
1686 LOG(FATAL) << "Unexpected type conversion from " << input_type
1687 << " to " << result_type;
1688 }
1689 break;
1690
Roland Levillain981e4542014-11-14 11:47:14 +00001691 case Primitive::kPrimChar:
1692 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001693 case Primitive::kPrimBoolean:
1694 // Boolean input is a result of code transformations.
Roland Levillain981e4542014-11-14 11:47:14 +00001695 case Primitive::kPrimByte:
1696 case Primitive::kPrimShort:
1697 case Primitive::kPrimInt:
Roland Levillain981e4542014-11-14 11:47:14 +00001698 // Processing a Dex `Process a Dex `int-to-char'' instruction.
1699 if (in.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001700 __ movzxw(out.AsRegister<Register>(), in.AsRegister<Register>());
Roland Levillain981e4542014-11-14 11:47:14 +00001701 } else if (in.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001702 __ movzxw(out.AsRegister<Register>(), Address(ESP, in.GetStackIndex()));
Roland Levillain981e4542014-11-14 11:47:14 +00001703 } else {
1704 DCHECK(in.GetConstant()->IsIntConstant());
1705 int32_t value = in.GetConstant()->AsIntConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001706 __ movl(out.AsRegister<Register>(), Immediate(static_cast<uint16_t>(value)));
Roland Levillain981e4542014-11-14 11:47:14 +00001707 }
1708 break;
1709
1710 default:
1711 LOG(FATAL) << "Unexpected type conversion from " << input_type
1712 << " to " << result_type;
1713 }
1714 break;
1715
Roland Levillaindff1f282014-11-05 14:15:05 +00001716 case Primitive::kPrimFloat:
Roland Levillaincff13742014-11-17 14:32:17 +00001717 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001718 case Primitive::kPrimBoolean:
1719 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001720 case Primitive::kPrimByte:
1721 case Primitive::kPrimShort:
1722 case Primitive::kPrimInt:
1723 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001724 // Processing a Dex `int-to-float' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001725 __ cvtsi2ss(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001726 break;
1727
Roland Levillain6d0e4832014-11-27 18:31:21 +00001728 case Primitive::kPrimLong: {
1729 // Processing a Dex `long-to-float' instruction.
1730 Register low = in.AsRegisterPairLow<Register>();
1731 Register high = in.AsRegisterPairHigh<Register>();
1732 XmmRegister result = out.AsFpuRegister<XmmRegister>();
1733 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1734 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
1735
1736 // Operations use doubles for precision reasons (each 32-bit
1737 // half of a long fits in the 53-bit mantissa of a double,
1738 // but not in the 24-bit mantissa of a float). This is
1739 // especially important for the low bits. The result is
1740 // eventually converted to float.
1741
1742 // low = low - 2^31 (to prevent bit 31 of `low` to be
1743 // interpreted as a sign bit)
1744 __ subl(low, Immediate(0x80000000));
1745 // temp = int-to-double(high)
1746 __ cvtsi2sd(temp, high);
1747 // temp = temp * 2^32
1748 __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
1749 __ mulsd(temp, constant);
1750 // result = int-to-double(low)
1751 __ cvtsi2sd(result, low);
1752 // result = result + 2^31 (restore the original value of `low`)
1753 __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
1754 __ addsd(result, constant);
1755 // result = result + temp
1756 __ addsd(result, temp);
1757 // result = double-to-float(result)
1758 __ cvtsd2ss(result, result);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001759 // Restore low.
1760 __ addl(low, Immediate(0x80000000));
Roland Levillain6d0e4832014-11-27 18:31:21 +00001761 break;
1762 }
1763
Roland Levillaincff13742014-11-17 14:32:17 +00001764 case Primitive::kPrimDouble:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001765 // Processing a Dex `double-to-float' instruction.
1766 __ cvtsd2ss(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001767 break;
1768
1769 default:
1770 LOG(FATAL) << "Unexpected type conversion from " << input_type
1771 << " to " << result_type;
1772 };
1773 break;
1774
Roland Levillaindff1f282014-11-05 14:15:05 +00001775 case Primitive::kPrimDouble:
Roland Levillaincff13742014-11-17 14:32:17 +00001776 switch (input_type) {
David Brazdil46e2a392015-03-16 17:31:52 +00001777 case Primitive::kPrimBoolean:
1778 // Boolean input is a result of code transformations.
Roland Levillaincff13742014-11-17 14:32:17 +00001779 case Primitive::kPrimByte:
1780 case Primitive::kPrimShort:
1781 case Primitive::kPrimInt:
1782 case Primitive::kPrimChar:
Roland Levillain6d0e4832014-11-27 18:31:21 +00001783 // Processing a Dex `int-to-double' instruction.
Roland Levillain271ab9c2014-11-27 15:23:57 +00001784 __ cvtsi2sd(out.AsFpuRegister<XmmRegister>(), in.AsRegister<Register>());
Roland Levillaincff13742014-11-17 14:32:17 +00001785 break;
1786
Roland Levillain647b9ed2014-11-27 12:06:00 +00001787 case Primitive::kPrimLong: {
1788 // Processing a Dex `long-to-double' instruction.
1789 Register low = in.AsRegisterPairLow<Register>();
1790 Register high = in.AsRegisterPairHigh<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00001791 XmmRegister result = out.AsFpuRegister<XmmRegister>();
1792 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
1793 XmmRegister constant = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
Roland Levillain647b9ed2014-11-27 12:06:00 +00001794
Roland Levillain647b9ed2014-11-27 12:06:00 +00001795 // low = low - 2^31 (to prevent bit 31 of `low` to be
1796 // interpreted as a sign bit)
1797 __ subl(low, Immediate(0x80000000));
1798 // temp = int-to-double(high)
1799 __ cvtsi2sd(temp, high);
1800 // temp = temp * 2^32
Roland Levillain6d0e4832014-11-27 18:31:21 +00001801 __ LoadLongConstant(constant, k2Pow32EncodingForDouble);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001802 __ mulsd(temp, constant);
1803 // result = int-to-double(low)
1804 __ cvtsi2sd(result, low);
1805 // result = result + 2^31 (restore the original value of `low`)
Roland Levillain6d0e4832014-11-27 18:31:21 +00001806 __ LoadLongConstant(constant, k2Pow31EncodingForDouble);
Roland Levillain647b9ed2014-11-27 12:06:00 +00001807 __ addsd(result, constant);
1808 // result = result + temp
1809 __ addsd(result, temp);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001810 // Restore low.
1811 __ addl(low, Immediate(0x80000000));
Roland Levillain647b9ed2014-11-27 12:06:00 +00001812 break;
1813 }
1814
Roland Levillaincff13742014-11-17 14:32:17 +00001815 case Primitive::kPrimFloat:
Roland Levillain8964e2b2014-12-04 12:10:50 +00001816 // Processing a Dex `float-to-double' instruction.
1817 __ cvtss2sd(out.AsFpuRegister<XmmRegister>(), in.AsFpuRegister<XmmRegister>());
Roland Levillaincff13742014-11-17 14:32:17 +00001818 break;
1819
1820 default:
1821 LOG(FATAL) << "Unexpected type conversion from " << input_type
1822 << " to " << result_type;
1823 };
Roland Levillaindff1f282014-11-05 14:15:05 +00001824 break;
1825
1826 default:
1827 LOG(FATAL) << "Unexpected type conversion from " << input_type
1828 << " to " << result_type;
1829 }
1830}
1831
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001832void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001833 LocationSummary* locations =
1834 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001835 switch (add->GetResultType()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001836 case Primitive::kPrimInt: {
1837 locations->SetInAt(0, Location::RequiresRegister());
1838 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)));
1839 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
1840 break;
1841 }
1842
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001843 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001844 locations->SetInAt(0, Location::RequiresRegister());
1845 locations->SetInAt(1, Location::Any());
1846 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001847 break;
1848 }
1849
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001850 case Primitive::kPrimFloat:
1851 case Primitive::kPrimDouble: {
1852 locations->SetInAt(0, Location::RequiresFpuRegister());
Calin Juravle3173c8a2015-02-23 15:53:39 +00001853 locations->SetInAt(1, Location::RequiresFpuRegister());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001854 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001855 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001856 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001857
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001858 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001859 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1860 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001861 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001862}
1863
1864void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
1865 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001866 Location first = locations->InAt(0);
1867 Location second = locations->InAt(1);
Mark Mendell09b84632015-02-13 17:48:38 -05001868 Location out = locations->Out();
1869
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001870 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001871 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001872 if (second.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001873 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1874 __ addl(out.AsRegister<Register>(), second.AsRegister<Register>());
1875 } else {
1876 __ leal(out.AsRegister<Register>(), Address(
1877 first.AsRegister<Register>(), second.AsRegister<Register>(), TIMES_1, 0));
1878 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001879 } else if (second.IsConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05001880 int32_t value = second.GetConstant()->AsIntConstant()->GetValue();
1881 if (out.AsRegister<Register>() == first.AsRegister<Register>()) {
1882 __ addl(out.AsRegister<Register>(), Immediate(value));
1883 } else {
1884 __ leal(out.AsRegister<Register>(), Address(first.AsRegister<Register>(), value));
1885 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001886 } else {
Mark Mendell09b84632015-02-13 17:48:38 -05001887 DCHECK(first.Equals(locations->Out()));
Roland Levillain271ab9c2014-11-27 15:23:57 +00001888 __ addl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001889 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001890 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001891 }
1892
1893 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001894 if (second.IsRegisterPair()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001895 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1896 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001897 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001898 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
1899 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001900 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001901 } else {
1902 DCHECK(second.IsConstant()) << second;
1903 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1904 __ addl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
1905 __ adcl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001906 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001907 break;
1908 }
1909
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001910 case Primitive::kPrimFloat: {
1911 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001912 __ addss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001913 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001914 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001915 }
1916
1917 case Primitive::kPrimDouble: {
1918 if (second.IsFpuRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001919 __ addsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001920 }
1921 break;
1922 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001923
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001924 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001925 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001926 }
1927}
1928
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001929void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001930 LocationSummary* locations =
1931 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001932 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001933 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001934 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001935 locations->SetInAt(0, Location::RequiresRegister());
1936 locations->SetInAt(1, Location::Any());
1937 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001938 break;
1939 }
Calin Juravle11351682014-10-23 15:38:15 +01001940 case Primitive::kPrimFloat:
1941 case Primitive::kPrimDouble: {
1942 locations->SetInAt(0, Location::RequiresFpuRegister());
1943 locations->SetInAt(1, Location::RequiresFpuRegister());
1944 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001945 break;
Calin Juravle11351682014-10-23 15:38:15 +01001946 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001947
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001948 default:
Calin Juravle11351682014-10-23 15:38:15 +01001949 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001950 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001951}
1952
1953void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
1954 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001955 Location first = locations->InAt(0);
1956 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01001957 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001958 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001959 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001960 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001961 __ subl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001962 } else if (second.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00001963 __ subl(first.AsRegister<Register>(),
1964 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001965 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001966 __ subl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001967 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001968 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001969 }
1970
1971 case Primitive::kPrimLong: {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00001972 if (second.IsRegisterPair()) {
Calin Juravle11351682014-10-23 15:38:15 +01001973 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1974 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001975 } else if (second.IsDoubleStackSlot()) {
Calin Juravle11351682014-10-23 15:38:15 +01001976 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001977 __ sbbl(first.AsRegisterPairHigh<Register>(),
1978 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00001979 } else {
1980 DCHECK(second.IsConstant()) << second;
1981 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
1982 __ subl(first.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
1983 __ sbbl(first.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001984 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001985 break;
1986 }
1987
Calin Juravle11351682014-10-23 15:38:15 +01001988 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001989 __ subss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001990 break;
Calin Juravle11351682014-10-23 15:38:15 +01001991 }
1992
1993 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00001994 __ subsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle11351682014-10-23 15:38:15 +01001995 break;
1996 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001997
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001998 default:
Calin Juravle11351682014-10-23 15:38:15 +01001999 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002000 }
2001}
2002
Calin Juravle34bacdf2014-10-07 20:23:36 +01002003void LocationsBuilderX86::VisitMul(HMul* mul) {
2004 LocationSummary* locations =
2005 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
2006 switch (mul->GetResultType()) {
2007 case Primitive::kPrimInt:
2008 locations->SetInAt(0, Location::RequiresRegister());
2009 locations->SetInAt(1, Location::Any());
2010 locations->SetOut(Location::SameAsFirstInput());
2011 break;
2012 case Primitive::kPrimLong: {
2013 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002014 locations->SetInAt(1, Location::Any());
2015 locations->SetOut(Location::SameAsFirstInput());
2016 // Needed for imul on 32bits with 64bits output.
2017 locations->AddTemp(Location::RegisterLocation(EAX));
2018 locations->AddTemp(Location::RegisterLocation(EDX));
2019 break;
2020 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01002021 case Primitive::kPrimFloat:
2022 case Primitive::kPrimDouble: {
2023 locations->SetInAt(0, Location::RequiresFpuRegister());
2024 locations->SetInAt(1, Location::RequiresFpuRegister());
2025 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002026 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002027 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002028
2029 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002030 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002031 }
2032}
2033
2034void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
2035 LocationSummary* locations = mul->GetLocations();
2036 Location first = locations->InAt(0);
2037 Location second = locations->InAt(1);
2038 DCHECK(first.Equals(locations->Out()));
2039
2040 switch (mul->GetResultType()) {
2041 case Primitive::kPrimInt: {
2042 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002043 __ imull(first.AsRegister<Register>(), second.AsRegister<Register>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002044 } else if (second.IsConstant()) {
2045 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002046 __ imull(first.AsRegister<Register>(), imm);
Calin Juravle34bacdf2014-10-07 20:23:36 +01002047 } else {
2048 DCHECK(second.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00002049 __ imull(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Calin Juravle34bacdf2014-10-07 20:23:36 +01002050 }
2051 break;
2052 }
2053
2054 case Primitive::kPrimLong: {
Calin Juravle34bacdf2014-10-07 20:23:36 +01002055 Register in1_hi = first.AsRegisterPairHigh<Register>();
2056 Register in1_lo = first.AsRegisterPairLow<Register>();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002057 Register eax = locations->GetTemp(0).AsRegister<Register>();
2058 Register edx = locations->GetTemp(1).AsRegister<Register>();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002059
2060 DCHECK_EQ(EAX, eax);
2061 DCHECK_EQ(EDX, edx);
2062
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002063 // input: in1 - 64 bits, in2 - 64 bits.
Calin Juravle34bacdf2014-10-07 20:23:36 +01002064 // output: in1
2065 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
2066 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
2067 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002068 if (second.IsConstant()) {
2069 DCHECK(second.GetConstant()->IsLongConstant());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002070
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002071 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
2072 int32_t low_value = Low32Bits(value);
2073 int32_t high_value = High32Bits(value);
2074 Immediate low(low_value);
2075 Immediate high(high_value);
2076
2077 __ movl(eax, high);
2078 // eax <- in1.lo * in2.hi
2079 __ imull(eax, in1_lo);
2080 // in1.hi <- in1.hi * in2.lo
2081 __ imull(in1_hi, low);
2082 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2083 __ addl(in1_hi, eax);
2084 // move in2_lo to eax to prepare for double precision
2085 __ movl(eax, low);
2086 // edx:eax <- in1.lo * in2.lo
2087 __ mull(in1_lo);
2088 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2089 __ addl(in1_hi, edx);
2090 // in1.lo <- (in1.lo * in2.lo)[31:0];
2091 __ movl(in1_lo, eax);
2092 } else if (second.IsRegisterPair()) {
2093 Register in2_hi = second.AsRegisterPairHigh<Register>();
2094 Register in2_lo = second.AsRegisterPairLow<Register>();
2095
2096 __ movl(eax, in2_hi);
2097 // eax <- in1.lo * in2.hi
2098 __ imull(eax, in1_lo);
2099 // in1.hi <- in1.hi * in2.lo
2100 __ imull(in1_hi, in2_lo);
2101 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2102 __ addl(in1_hi, eax);
2103 // move in1_lo to eax to prepare for double precision
2104 __ movl(eax, in1_lo);
2105 // edx:eax <- in1.lo * in2.lo
2106 __ mull(in2_lo);
2107 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2108 __ addl(in1_hi, edx);
2109 // in1.lo <- (in1.lo * in2.lo)[31:0];
2110 __ movl(in1_lo, eax);
2111 } else {
2112 DCHECK(second.IsDoubleStackSlot()) << second;
2113 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
2114 Address in2_lo(ESP, second.GetStackIndex());
2115
2116 __ movl(eax, in2_hi);
2117 // eax <- in1.lo * in2.hi
2118 __ imull(eax, in1_lo);
2119 // in1.hi <- in1.hi * in2.lo
2120 __ imull(in1_hi, in2_lo);
2121 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
2122 __ addl(in1_hi, eax);
2123 // move in1_lo to eax to prepare for double precision
2124 __ movl(eax, in1_lo);
2125 // edx:eax <- in1.lo * in2.lo
2126 __ mull(in2_lo);
2127 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
2128 __ addl(in1_hi, edx);
2129 // in1.lo <- (in1.lo * in2.lo)[31:0];
2130 __ movl(in1_lo, eax);
2131 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002132
2133 break;
2134 }
2135
Calin Juravleb5bfa962014-10-21 18:02:24 +01002136 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002137 __ mulss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01002138 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01002139 }
2140
2141 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002142 __ mulsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravleb5bfa962014-10-21 18:02:24 +01002143 break;
2144 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01002145
2146 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01002147 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01002148 }
2149}
2150
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002151void InstructionCodeGeneratorX86::PushOntoFPStack(Location source, uint32_t temp_offset,
2152 uint32_t stack_adjustment, bool is_float) {
2153 if (source.IsStackSlot()) {
2154 DCHECK(is_float);
2155 __ flds(Address(ESP, source.GetStackIndex() + stack_adjustment));
2156 } else if (source.IsDoubleStackSlot()) {
2157 DCHECK(!is_float);
2158 __ fldl(Address(ESP, source.GetStackIndex() + stack_adjustment));
2159 } else {
2160 // Write the value to the temporary location on the stack and load to FP stack.
2161 if (is_float) {
2162 Location stack_temp = Location::StackSlot(temp_offset);
2163 codegen_->Move32(stack_temp, source);
2164 __ flds(Address(ESP, temp_offset));
2165 } else {
2166 Location stack_temp = Location::DoubleStackSlot(temp_offset);
2167 codegen_->Move64(stack_temp, source);
2168 __ fldl(Address(ESP, temp_offset));
2169 }
2170 }
2171}
2172
2173void InstructionCodeGeneratorX86::GenerateRemFP(HRem *rem) {
2174 Primitive::Type type = rem->GetResultType();
2175 bool is_float = type == Primitive::kPrimFloat;
2176 size_t elem_size = Primitive::ComponentSize(type);
2177 LocationSummary* locations = rem->GetLocations();
2178 Location first = locations->InAt(0);
2179 Location second = locations->InAt(1);
2180 Location out = locations->Out();
2181
2182 // Create stack space for 2 elements.
2183 // TODO: enhance register allocator to ask for stack temporaries.
2184 __ subl(ESP, Immediate(2 * elem_size));
2185
2186 // Load the values to the FP stack in reverse order, using temporaries if needed.
2187 PushOntoFPStack(second, elem_size, 2 * elem_size, is_float);
2188 PushOntoFPStack(first, 0, 2 * elem_size, is_float);
2189
2190 // Loop doing FPREM until we stabilize.
2191 Label retry;
2192 __ Bind(&retry);
2193 __ fprem();
2194
2195 // Move FP status to AX.
2196 __ fstsw();
2197
2198 // And see if the argument reduction is complete. This is signaled by the
2199 // C2 FPU flag bit set to 0.
2200 __ andl(EAX, Immediate(kC2ConditionMask));
2201 __ j(kNotEqual, &retry);
2202
2203 // We have settled on the final value. Retrieve it into an XMM register.
2204 // Store FP top of stack to real stack.
2205 if (is_float) {
2206 __ fsts(Address(ESP, 0));
2207 } else {
2208 __ fstl(Address(ESP, 0));
2209 }
2210
2211 // Pop the 2 items from the FP stack.
2212 __ fucompp();
2213
2214 // Load the value from the stack into an XMM register.
2215 DCHECK(out.IsFpuRegister()) << out;
2216 if (is_float) {
2217 __ movss(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2218 } else {
2219 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(ESP, 0));
2220 }
2221
2222 // And remove the temporary stack space we allocated.
2223 __ addl(ESP, Immediate(2 * elem_size));
2224}
2225
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002226
2227void InstructionCodeGeneratorX86::DivRemOneOrMinusOne(HBinaryOperation* instruction) {
2228 DCHECK(instruction->IsDiv() || instruction->IsRem());
2229
2230 LocationSummary* locations = instruction->GetLocations();
2231 DCHECK(locations->InAt(1).IsConstant());
2232
2233 Register out_register = locations->Out().AsRegister<Register>();
2234 Register input_register = locations->InAt(0).AsRegister<Register>();
2235 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2236
2237 DCHECK(imm == 1 || imm == -1);
2238
2239 if (instruction->IsRem()) {
2240 __ xorl(out_register, out_register);
2241 } else {
2242 __ movl(out_register, input_register);
2243 if (imm == -1) {
2244 __ negl(out_register);
2245 }
2246 }
2247}
2248
2249
2250void InstructionCodeGeneratorX86::DivByPowerOfTwo(HBinaryOperation* instruction) {
2251 DCHECK(instruction->IsDiv());
2252
2253 LocationSummary* locations = instruction->GetLocations();
2254
2255 Register out_register = locations->Out().AsRegister<Register>();
2256 Register input_register = locations->InAt(0).AsRegister<Register>();
2257 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2258
2259 DCHECK(instruction->IsDiv() && IsPowerOfTwo(std::abs(imm)));
2260 Register num = locations->GetTemp(0).AsRegister<Register>();
2261
2262 __ leal(num, Address(input_register, std::abs(imm) - 1));
2263 __ testl(input_register, input_register);
2264 __ cmovl(kGreaterEqual, num, input_register);
2265 int shift = CTZ(imm);
2266 __ sarl(num, Immediate(shift));
2267
2268 if (imm < 0) {
2269 __ negl(num);
2270 }
2271
2272 __ movl(out_register, num);
2273}
2274
2275void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2276 DCHECK(instruction->IsDiv() || instruction->IsRem());
2277
2278 LocationSummary* locations = instruction->GetLocations();
2279 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2280
2281 Register eax = locations->InAt(0).AsRegister<Register>();
2282 Register out = locations->Out().AsRegister<Register>();
2283 Register num;
2284 Register edx;
2285
2286 if (instruction->IsDiv()) {
2287 edx = locations->GetTemp(0).AsRegister<Register>();
2288 num = locations->GetTemp(1).AsRegister<Register>();
2289 } else {
2290 edx = locations->Out().AsRegister<Register>();
2291 num = locations->GetTemp(0).AsRegister<Register>();
2292 }
2293
2294 DCHECK_EQ(EAX, eax);
2295 DCHECK_EQ(EDX, edx);
2296 if (instruction->IsDiv()) {
2297 DCHECK_EQ(EAX, out);
2298 } else {
2299 DCHECK_EQ(EDX, out);
2300 }
2301
2302 int64_t magic;
2303 int shift;
2304 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2305
2306 Label ndiv;
2307 Label end;
2308 // If numerator is 0, the result is 0, no computation needed.
2309 __ testl(eax, eax);
2310 __ j(kNotEqual, &ndiv);
2311
2312 __ xorl(out, out);
2313 __ jmp(&end);
2314
2315 __ Bind(&ndiv);
2316
2317 // Save the numerator.
2318 __ movl(num, eax);
2319
2320 // EAX = magic
2321 __ movl(eax, Immediate(magic));
2322
2323 // EDX:EAX = magic * numerator
2324 __ imull(num);
2325
2326 if (imm > 0 && magic < 0) {
2327 // EDX += num
2328 __ addl(edx, num);
2329 } else if (imm < 0 && magic > 0) {
2330 __ subl(edx, num);
2331 }
2332
2333 // Shift if needed.
2334 if (shift != 0) {
2335 __ sarl(edx, Immediate(shift));
2336 }
2337
2338 // EDX += 1 if EDX < 0
2339 __ movl(eax, edx);
2340 __ shrl(edx, Immediate(31));
2341 __ addl(edx, eax);
2342
2343 if (instruction->IsRem()) {
2344 __ movl(eax, num);
2345 __ imull(edx, Immediate(imm));
2346 __ subl(eax, edx);
2347 __ movl(edx, eax);
2348 } else {
2349 __ movl(eax, edx);
2350 }
2351 __ Bind(&end);
2352}
2353
Calin Juravlebacfec32014-11-14 15:54:36 +00002354void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2355 DCHECK(instruction->IsDiv() || instruction->IsRem());
2356
2357 LocationSummary* locations = instruction->GetLocations();
2358 Location out = locations->Out();
2359 Location first = locations->InAt(0);
2360 Location second = locations->InAt(1);
2361 bool is_div = instruction->IsDiv();
2362
2363 switch (instruction->GetResultType()) {
2364 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002365 DCHECK_EQ(EAX, first.AsRegister<Register>());
2366 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002367
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002368 if (second.IsConstant()) {
2369 int imm = second.GetConstant()->AsIntConstant()->GetValue();
2370
2371 if (imm == 0) {
2372 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
2373 } else if (imm == 1 || imm == -1) {
2374 DivRemOneOrMinusOne(instruction);
2375 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
2376 DivByPowerOfTwo(instruction);
2377 } else {
2378 DCHECK(imm <= -2 || imm >= 2);
2379 GenerateDivRemWithAnyConstant(instruction);
2380 }
2381 } else {
2382 SlowPathCodeX86* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002383 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002384 is_div);
2385 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002386
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002387 Register second_reg = second.AsRegister<Register>();
2388 // 0x80000000/-1 triggers an arithmetic exception!
2389 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2390 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002391
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002392 __ cmpl(second_reg, Immediate(-1));
2393 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002394
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002395 // edx:eax <- sign-extended of eax
2396 __ cdq();
2397 // eax = quotient, edx = remainder
2398 __ idivl(second_reg);
2399 __ Bind(slow_path->GetExitLabel());
2400 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002401 break;
2402 }
2403
2404 case Primitive::kPrimLong: {
2405 InvokeRuntimeCallingConvention calling_convention;
2406 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2407 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2408 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2409 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2410 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2411 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2412
2413 if (is_div) {
2414 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv)));
2415 } else {
2416 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod)));
2417 }
2418 uint32_t dex_pc = is_div
2419 ? instruction->AsDiv()->GetDexPc()
2420 : instruction->AsRem()->GetDexPc();
2421 codegen_->RecordPcInfo(instruction, dex_pc);
2422
2423 break;
2424 }
2425
2426 default:
2427 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
2428 }
2429}
2430
Calin Juravle7c4954d2014-10-28 16:57:40 +00002431void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002432 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002433 ? LocationSummary::kCall
2434 : LocationSummary::kNoCall;
2435 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2436
Calin Juravle7c4954d2014-10-28 16:57:40 +00002437 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002438 case Primitive::kPrimInt: {
2439 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002440 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002441 locations->SetOut(Location::SameAsFirstInput());
2442 // Intel uses edx:eax as the dividend.
2443 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002444 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2445 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
2446 // output and request another temp.
2447 if (div->InputAt(1)->IsConstant()) {
2448 locations->AddTemp(Location::RequiresRegister());
2449 }
Calin Juravled0d48522014-11-04 16:40:20 +00002450 break;
2451 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002452 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002453 InvokeRuntimeCallingConvention calling_convention;
2454 locations->SetInAt(0, Location::RegisterPairLocation(
2455 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2456 locations->SetInAt(1, Location::RegisterPairLocation(
2457 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2458 // Runtime helper puts the result in EAX, EDX.
2459 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002460 break;
2461 }
2462 case Primitive::kPrimFloat:
2463 case Primitive::kPrimDouble: {
2464 locations->SetInAt(0, Location::RequiresFpuRegister());
2465 locations->SetInAt(1, Location::RequiresFpuRegister());
2466 locations->SetOut(Location::SameAsFirstInput());
2467 break;
2468 }
2469
2470 default:
2471 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2472 }
2473}
2474
2475void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
2476 LocationSummary* locations = div->GetLocations();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002477 Location out = locations->Out();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002478 Location first = locations->InAt(0);
2479 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002480
2481 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002482 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00002483 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002484 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002485 break;
2486 }
2487
2488 case Primitive::kPrimFloat: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002489 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002490 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002491 break;
2492 }
2493
2494 case Primitive::kPrimDouble: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002495 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002496 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002497 break;
2498 }
2499
2500 default:
2501 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2502 }
2503}
2504
Calin Juravlebacfec32014-11-14 15:54:36 +00002505void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002506 Primitive::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002507
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002508 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
2509 ? LocationSummary::kCall
2510 : LocationSummary::kNoCall;
2511 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00002512
Calin Juravled2ec87d2014-12-08 14:24:46 +00002513 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002514 case Primitive::kPrimInt: {
2515 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002516 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002517 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002518 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2519 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
2520 // output and request another temp.
2521 if (rem->InputAt(1)->IsConstant()) {
2522 locations->AddTemp(Location::RequiresRegister());
2523 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002524 break;
2525 }
2526 case Primitive::kPrimLong: {
2527 InvokeRuntimeCallingConvention calling_convention;
2528 locations->SetInAt(0, Location::RegisterPairLocation(
2529 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2530 locations->SetInAt(1, Location::RegisterPairLocation(
2531 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2532 // Runtime helper puts the result in EAX, EDX.
2533 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2534 break;
2535 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002536 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002537 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002538 locations->SetInAt(0, Location::Any());
2539 locations->SetInAt(1, Location::Any());
2540 locations->SetOut(Location::RequiresFpuRegister());
2541 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002542 break;
2543 }
2544
2545 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002546 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002547 }
2548}
2549
2550void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
2551 Primitive::Type type = rem->GetResultType();
2552 switch (type) {
2553 case Primitive::kPrimInt:
2554 case Primitive::kPrimLong: {
2555 GenerateDivRemIntegral(rem);
2556 break;
2557 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002558 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00002559 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002560 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00002561 break;
2562 }
2563 default:
2564 LOG(FATAL) << "Unexpected rem type " << type;
2565 }
2566}
2567
Calin Juravled0d48522014-11-04 16:40:20 +00002568void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2569 LocationSummary* locations =
2570 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002571 switch (instruction->GetType()) {
2572 case Primitive::kPrimInt: {
2573 locations->SetInAt(0, Location::Any());
2574 break;
2575 }
2576 case Primitive::kPrimLong: {
2577 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2578 if (!instruction->IsConstant()) {
2579 locations->AddTemp(Location::RequiresRegister());
2580 }
2581 break;
2582 }
2583 default:
2584 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2585 }
Calin Juravled0d48522014-11-04 16:40:20 +00002586 if (instruction->HasUses()) {
2587 locations->SetOut(Location::SameAsFirstInput());
2588 }
2589}
2590
2591void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2592 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
2593 codegen_->AddSlowPath(slow_path);
2594
2595 LocationSummary* locations = instruction->GetLocations();
2596 Location value = locations->InAt(0);
2597
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002598 switch (instruction->GetType()) {
2599 case Primitive::kPrimInt: {
2600 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002601 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002602 __ j(kEqual, slow_path->GetEntryLabel());
2603 } else if (value.IsStackSlot()) {
2604 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
2605 __ j(kEqual, slow_path->GetEntryLabel());
2606 } else {
2607 DCHECK(value.IsConstant()) << value;
2608 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2609 __ jmp(slow_path->GetEntryLabel());
2610 }
2611 }
2612 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002613 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002614 case Primitive::kPrimLong: {
2615 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002616 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002617 __ movl(temp, value.AsRegisterPairLow<Register>());
2618 __ orl(temp, value.AsRegisterPairHigh<Register>());
2619 __ j(kEqual, slow_path->GetEntryLabel());
2620 } else {
2621 DCHECK(value.IsConstant()) << value;
2622 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2623 __ jmp(slow_path->GetEntryLabel());
2624 }
2625 }
2626 break;
2627 }
2628 default:
2629 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002630 }
Calin Juravled0d48522014-11-04 16:40:20 +00002631}
2632
Calin Juravle9aec02f2014-11-18 23:06:35 +00002633void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
2634 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2635
2636 LocationSummary* locations =
2637 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2638
2639 switch (op->GetResultType()) {
2640 case Primitive::kPrimInt: {
2641 locations->SetInAt(0, Location::RequiresRegister());
2642 // The shift count needs to be in CL.
2643 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
2644 locations->SetOut(Location::SameAsFirstInput());
2645 break;
2646 }
2647 case Primitive::kPrimLong: {
2648 locations->SetInAt(0, Location::RequiresRegister());
2649 // The shift count needs to be in CL.
2650 locations->SetInAt(1, Location::RegisterLocation(ECX));
2651 locations->SetOut(Location::SameAsFirstInput());
2652 break;
2653 }
2654 default:
2655 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2656 }
2657}
2658
2659void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
2660 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2661
2662 LocationSummary* locations = op->GetLocations();
2663 Location first = locations->InAt(0);
2664 Location second = locations->InAt(1);
2665 DCHECK(first.Equals(locations->Out()));
2666
2667 switch (op->GetResultType()) {
2668 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002669 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002670 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002671 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002672 DCHECK_EQ(ECX, second_reg);
2673 if (op->IsShl()) {
2674 __ shll(first_reg, second_reg);
2675 } else if (op->IsShr()) {
2676 __ sarl(first_reg, second_reg);
2677 } else {
2678 __ shrl(first_reg, second_reg);
2679 }
2680 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002681 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002682 if (op->IsShl()) {
2683 __ shll(first_reg, imm);
2684 } else if (op->IsShr()) {
2685 __ sarl(first_reg, imm);
2686 } else {
2687 __ shrl(first_reg, imm);
2688 }
2689 }
2690 break;
2691 }
2692 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002693 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002694 DCHECK_EQ(ECX, second_reg);
2695 if (op->IsShl()) {
2696 GenerateShlLong(first, second_reg);
2697 } else if (op->IsShr()) {
2698 GenerateShrLong(first, second_reg);
2699 } else {
2700 GenerateUShrLong(first, second_reg);
2701 }
2702 break;
2703 }
2704 default:
2705 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2706 }
2707}
2708
2709void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
2710 Label done;
2711 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
2712 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
2713 __ testl(shifter, Immediate(32));
2714 __ j(kEqual, &done);
2715 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
2716 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
2717 __ Bind(&done);
2718}
2719
2720void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
2721 Label done;
2722 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2723 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
2724 __ testl(shifter, Immediate(32));
2725 __ j(kEqual, &done);
2726 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2727 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
2728 __ Bind(&done);
2729}
2730
2731void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
2732 Label done;
2733 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2734 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
2735 __ testl(shifter, Immediate(32));
2736 __ j(kEqual, &done);
2737 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2738 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
2739 __ Bind(&done);
2740}
2741
2742void LocationsBuilderX86::VisitShl(HShl* shl) {
2743 HandleShift(shl);
2744}
2745
2746void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
2747 HandleShift(shl);
2748}
2749
2750void LocationsBuilderX86::VisitShr(HShr* shr) {
2751 HandleShift(shr);
2752}
2753
2754void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
2755 HandleShift(shr);
2756}
2757
2758void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
2759 HandleShift(ushr);
2760}
2761
2762void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
2763 HandleShift(ushr);
2764}
2765
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002766void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002767 LocationSummary* locations =
2768 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002769 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002770 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002771 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2772 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002773}
2774
2775void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
2776 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002777 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002778 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002779
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002780 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002781
Nicolas Geoffray39468442014-09-02 15:17:15 +01002782 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002783 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002784}
2785
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002786void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
2787 LocationSummary* locations =
2788 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2789 locations->SetOut(Location::RegisterLocation(EAX));
2790 InvokeRuntimeCallingConvention calling_convention;
2791 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002792 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2793 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002794}
2795
2796void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
2797 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002798 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002799 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
2800
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002801 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002802
2803 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2804 DCHECK(!codegen_->IsLeafMethod());
2805}
2806
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002807void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002808 LocationSummary* locations =
2809 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002810 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2811 if (location.IsStackSlot()) {
2812 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2813 } else if (location.IsDoubleStackSlot()) {
2814 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002815 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002816 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002817}
2818
2819void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002820 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002821}
2822
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002823void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002824 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002825 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002826 locations->SetInAt(0, Location::RequiresRegister());
2827 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002828}
2829
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002830void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
2831 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01002832 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002833 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01002834 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002835 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002836 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002837 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002838 break;
2839
2840 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002841 __ notl(out.AsRegisterPairLow<Register>());
2842 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002843 break;
2844
2845 default:
2846 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2847 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002848}
2849
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002850void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002851 LocationSummary* locations =
2852 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002853 switch (compare->InputAt(0)->GetType()) {
2854 case Primitive::kPrimLong: {
2855 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00002856 locations->SetInAt(1, Location::Any());
2857 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2858 break;
2859 }
2860 case Primitive::kPrimFloat:
2861 case Primitive::kPrimDouble: {
2862 locations->SetInAt(0, Location::RequiresFpuRegister());
2863 locations->SetInAt(1, Location::RequiresFpuRegister());
2864 locations->SetOut(Location::RequiresRegister());
2865 break;
2866 }
2867 default:
2868 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2869 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002870}
2871
2872void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002873 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002874 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002875 Location left = locations->InAt(0);
2876 Location right = locations->InAt(1);
2877
2878 Label less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002879 switch (compare->InputAt(0)->GetType()) {
2880 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002881 Register left_low = left.AsRegisterPairLow<Register>();
2882 Register left_high = left.AsRegisterPairHigh<Register>();
2883 int32_t val_low = 0;
2884 int32_t val_high = 0;
2885 bool right_is_const = false;
2886
2887 if (right.IsConstant()) {
2888 DCHECK(right.GetConstant()->IsLongConstant());
2889 right_is_const = true;
2890 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
2891 val_low = Low32Bits(val);
2892 val_high = High32Bits(val);
2893 }
2894
Calin Juravleddb7df22014-11-25 20:56:51 +00002895 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002896 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002897 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002898 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002899 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002900 DCHECK(right_is_const) << right;
2901 if (val_high == 0) {
2902 __ testl(left_high, left_high);
2903 } else {
2904 __ cmpl(left_high, Immediate(val_high));
2905 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002906 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002907 __ j(kLess, &less); // Signed compare.
2908 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002909 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002910 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002911 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002912 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002913 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002914 DCHECK(right_is_const) << right;
2915 if (val_low == 0) {
2916 __ testl(left_low, left_low);
2917 } else {
2918 __ cmpl(left_low, Immediate(val_low));
2919 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002920 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002921 break;
2922 }
2923 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002924 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002925 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
2926 break;
2927 }
2928 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002929 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002930 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002931 break;
2932 }
2933 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002934 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002935 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002936 __ movl(out, Immediate(0));
2937 __ j(kEqual, &done);
2938 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
2939
2940 __ Bind(&greater);
2941 __ movl(out, Immediate(1));
2942 __ jmp(&done);
2943
2944 __ Bind(&less);
2945 __ movl(out, Immediate(-1));
2946
2947 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002948}
2949
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002950void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002951 LocationSummary* locations =
2952 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002953 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2954 locations->SetInAt(i, Location::Any());
2955 }
2956 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002957}
2958
2959void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002960 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002961 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002962}
2963
Calin Juravle52c48962014-12-16 17:02:57 +00002964void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
2965 /*
2966 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2967 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2968 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2969 */
2970 switch (kind) {
2971 case MemBarrierKind::kAnyAny: {
2972 __ mfence();
2973 break;
2974 }
2975 case MemBarrierKind::kAnyStore:
2976 case MemBarrierKind::kLoadAny:
2977 case MemBarrierKind::kStoreStore: {
2978 // nop
2979 break;
2980 }
2981 default:
2982 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002983 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002984}
2985
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002986
Mark Mendell09ed1a32015-03-25 08:30:06 -04002987void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
2988 Register temp) {
2989 // TODO: Implement all kinds of calls:
2990 // 1) boot -> boot
2991 // 2) app -> boot
2992 // 3) app -> app
2993 //
2994 // Currently we implement the app -> app logic, which looks up in the resolve cache.
2995 // temp = method;
2996 LoadCurrentMethod(temp);
2997 if (!invoke->IsRecursive()) {
2998 // temp = temp->dex_cache_resolved_methods_;
2999 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
3000 // temp = temp[index_in_cache]
3001 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
3002 // (temp + offset_of_quick_compiled_code)()
3003 __ call(Address(
3004 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3005 } else {
3006 __ call(GetFrameEntryLabel());
3007 }
3008
3009 DCHECK(!IsLeafMethod());
3010 RecordPcInfo(invoke, invoke->GetDexPc());
3011}
3012
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003013void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003014 Label is_null;
3015 __ testl(value, value);
3016 __ j(kEqual, &is_null);
3017 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3018 __ movl(temp, object);
3019 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003020 __ movb(Address(temp, card, TIMES_1, 0),
3021 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003022 __ Bind(&is_null);
3023}
3024
Calin Juravle52c48962014-12-16 17:02:57 +00003025void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3026 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003027 LocationSummary* locations =
3028 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003029 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003030
3031 // The output overlaps in case of long: we don't want the low move to overwrite
3032 // the object's location.
3033 locations->SetOut(Location::RequiresRegister(),
3034 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3035 : Location::kNoOutputOverlap);
Calin Juravle52c48962014-12-16 17:02:57 +00003036
3037 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3038 // Long values can be loaded atomically into an XMM using movsd.
3039 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3040 // and then copy the XMM into the output 32bits at a time).
3041 locations->AddTemp(Location::RequiresFpuRegister());
3042 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003043}
3044
Calin Juravle52c48962014-12-16 17:02:57 +00003045void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3046 const FieldInfo& field_info) {
3047 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003048
Calin Juravle52c48962014-12-16 17:02:57 +00003049 LocationSummary* locations = instruction->GetLocations();
3050 Register base = locations->InAt(0).AsRegister<Register>();
3051 Location out = locations->Out();
3052 bool is_volatile = field_info.IsVolatile();
3053 Primitive::Type field_type = field_info.GetFieldType();
3054 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3055
3056 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003057 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003058 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003059 break;
3060 }
3061
3062 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003063 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003064 break;
3065 }
3066
3067 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003068 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003069 break;
3070 }
3071
3072 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003073 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003074 break;
3075 }
3076
3077 case Primitive::kPrimInt:
3078 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003079 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003080 break;
3081 }
3082
3083 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00003084 if (is_volatile) {
3085 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3086 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003087 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003088 __ movd(out.AsRegisterPairLow<Register>(), temp);
3089 __ psrlq(temp, Immediate(32));
3090 __ movd(out.AsRegisterPairHigh<Register>(), temp);
3091 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003092 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003093 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003094 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003095 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
3096 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003097 break;
3098 }
3099
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003100 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003101 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003102 break;
3103 }
3104
3105 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003106 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003107 break;
3108 }
3109
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003110 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003111 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003112 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003113 }
Calin Juravle52c48962014-12-16 17:02:57 +00003114
Calin Juravle77520bc2015-01-12 18:45:46 +00003115 // Longs are handled in the switch.
3116 if (field_type != Primitive::kPrimLong) {
3117 codegen_->MaybeRecordImplicitNullCheck(instruction);
3118 }
3119
Calin Juravle52c48962014-12-16 17:02:57 +00003120 if (is_volatile) {
3121 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3122 }
3123}
3124
3125void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3126 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3127
3128 LocationSummary* locations =
3129 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3130 locations->SetInAt(0, Location::RequiresRegister());
3131 bool is_volatile = field_info.IsVolatile();
3132 Primitive::Type field_type = field_info.GetFieldType();
3133 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
3134 || (field_type == Primitive::kPrimByte);
3135
3136 // The register allocator does not support multiple
3137 // inputs that die at entry with one in a specific register.
3138 if (is_byte_type) {
3139 // Ensure the value is in a byte register.
3140 locations->SetInAt(1, Location::RegisterLocation(EAX));
3141 } else {
3142 locations->SetInAt(1, Location::RequiresRegister());
3143 }
3144 // Temporary registers for the write barrier.
3145 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3146 locations->AddTemp(Location::RequiresRegister());
3147 // Ensure the card is in a byte register.
3148 locations->AddTemp(Location::RegisterLocation(ECX));
3149 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
3150 // 64bits value can be atomically written to an address with movsd and an XMM register.
3151 // We need two XMM registers because there's no easier way to (bit) copy a register pair
3152 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
3153 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
3154 // isolated cases when we need this it isn't worth adding the extra complexity.
3155 locations->AddTemp(Location::RequiresFpuRegister());
3156 locations->AddTemp(Location::RequiresFpuRegister());
3157 }
3158}
3159
3160void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
3161 const FieldInfo& field_info) {
3162 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3163
3164 LocationSummary* locations = instruction->GetLocations();
3165 Register base = locations->InAt(0).AsRegister<Register>();
3166 Location value = locations->InAt(1);
3167 bool is_volatile = field_info.IsVolatile();
3168 Primitive::Type field_type = field_info.GetFieldType();
3169 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3170
3171 if (is_volatile) {
3172 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3173 }
3174
3175 switch (field_type) {
3176 case Primitive::kPrimBoolean:
3177 case Primitive::kPrimByte: {
3178 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
3179 break;
3180 }
3181
3182 case Primitive::kPrimShort:
3183 case Primitive::kPrimChar: {
3184 __ movw(Address(base, offset), value.AsRegister<Register>());
3185 break;
3186 }
3187
3188 case Primitive::kPrimInt:
3189 case Primitive::kPrimNot: {
3190 __ movl(Address(base, offset), value.AsRegister<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003191 break;
3192 }
3193
3194 case Primitive::kPrimLong: {
3195 if (is_volatile) {
3196 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3197 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
3198 __ movd(temp1, value.AsRegisterPairLow<Register>());
3199 __ movd(temp2, value.AsRegisterPairHigh<Register>());
3200 __ punpckldq(temp1, temp2);
3201 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00003202 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003203 } else {
3204 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003205 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003206 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
3207 }
3208 break;
3209 }
3210
3211 case Primitive::kPrimFloat: {
3212 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3213 break;
3214 }
3215
3216 case Primitive::kPrimDouble: {
3217 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3218 break;
3219 }
3220
3221 case Primitive::kPrimVoid:
3222 LOG(FATAL) << "Unreachable type " << field_type;
3223 UNREACHABLE();
3224 }
3225
Calin Juravle77520bc2015-01-12 18:45:46 +00003226 // Longs are handled in the switch.
3227 if (field_type != Primitive::kPrimLong) {
3228 codegen_->MaybeRecordImplicitNullCheck(instruction);
3229 }
3230
3231 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3232 Register temp = locations->GetTemp(0).AsRegister<Register>();
3233 Register card = locations->GetTemp(1).AsRegister<Register>();
3234 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
3235 }
3236
Calin Juravle52c48962014-12-16 17:02:57 +00003237 if (is_volatile) {
3238 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3239 }
3240}
3241
3242void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3243 HandleFieldGet(instruction, instruction->GetFieldInfo());
3244}
3245
3246void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3247 HandleFieldGet(instruction, instruction->GetFieldInfo());
3248}
3249
3250void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3251 HandleFieldSet(instruction, instruction->GetFieldInfo());
3252}
3253
3254void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3255 HandleFieldSet(instruction, instruction->GetFieldInfo());
3256}
3257
3258void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3259 HandleFieldSet(instruction, instruction->GetFieldInfo());
3260}
3261
3262void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3263 HandleFieldSet(instruction, instruction->GetFieldInfo());
3264}
3265
3266void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3267 HandleFieldGet(instruction, instruction->GetFieldInfo());
3268}
3269
3270void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3271 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003272}
3273
3274void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003275 LocationSummary* locations =
3276 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003277 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3278 ? Location::RequiresRegister()
3279 : Location::Any();
3280 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003281 if (instruction->HasUses()) {
3282 locations->SetOut(Location::SameAsFirstInput());
3283 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003284}
3285
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003286void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003287 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3288 return;
3289 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003290 LocationSummary* locations = instruction->GetLocations();
3291 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003292
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003293 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
3294 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3295}
3296
3297void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003298 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003299 codegen_->AddSlowPath(slow_path);
3300
3301 LocationSummary* locations = instruction->GetLocations();
3302 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003303
3304 if (obj.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003305 __ cmpl(obj.AsRegister<Register>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003306 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003307 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003308 } else {
3309 DCHECK(obj.IsConstant()) << obj;
3310 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3311 __ jmp(slow_path->GetEntryLabel());
3312 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003313 }
3314 __ j(kEqual, slow_path->GetEntryLabel());
3315}
3316
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003317void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
3318 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3319 GenerateImplicitNullCheck(instruction);
3320 } else {
3321 GenerateExplicitNullCheck(instruction);
3322 }
3323}
3324
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003325void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003326 LocationSummary* locations =
3327 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003328 locations->SetInAt(0, Location::RequiresRegister());
3329 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003330 // The output overlaps in case of long: we don't want the low move to overwrite
3331 // the array's location.
3332 locations->SetOut(Location::RequiresRegister(),
3333 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3334 : Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003335}
3336
3337void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
3338 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003339 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003340 Location index = locations->InAt(1);
3341
Calin Juravle77520bc2015-01-12 18:45:46 +00003342 Primitive::Type type = instruction->GetType();
3343 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003344 case Primitive::kPrimBoolean: {
3345 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003346 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003347 if (index.IsConstant()) {
3348 __ movzxb(out, Address(obj,
3349 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3350 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003351 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003352 }
3353 break;
3354 }
3355
3356 case Primitive::kPrimByte: {
3357 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003358 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003359 if (index.IsConstant()) {
3360 __ movsxb(out, Address(obj,
3361 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3362 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003363 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003364 }
3365 break;
3366 }
3367
3368 case Primitive::kPrimShort: {
3369 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003370 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003371 if (index.IsConstant()) {
3372 __ movsxw(out, Address(obj,
3373 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3374 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003375 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003376 }
3377 break;
3378 }
3379
3380 case Primitive::kPrimChar: {
3381 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003382 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003383 if (index.IsConstant()) {
3384 __ movzxw(out, Address(obj,
3385 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3386 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003387 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003388 }
3389 break;
3390 }
3391
3392 case Primitive::kPrimInt:
3393 case Primitive::kPrimNot: {
3394 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003395 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003396 if (index.IsConstant()) {
3397 __ movl(out, Address(obj,
3398 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3399 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003400 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003401 }
3402 break;
3403 }
3404
3405 case Primitive::kPrimLong: {
3406 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003407 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003408 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003409 if (index.IsConstant()) {
3410 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003411 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003412 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003413 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003414 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003415 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003416 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003417 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003418 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003419 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003420 }
3421 break;
3422 }
3423
Mark Mendell7c8d0092015-01-26 11:21:33 -05003424 case Primitive::kPrimFloat: {
3425 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3426 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3427 if (index.IsConstant()) {
3428 __ movss(out, Address(obj,
3429 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3430 } else {
3431 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
3432 }
3433 break;
3434 }
3435
3436 case Primitive::kPrimDouble: {
3437 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3438 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3439 if (index.IsConstant()) {
3440 __ movsd(out, Address(obj,
3441 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3442 } else {
3443 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
3444 }
3445 break;
3446 }
3447
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003448 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00003449 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003450 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003451 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003452
3453 if (type != Primitive::kPrimLong) {
3454 codegen_->MaybeRecordImplicitNullCheck(instruction);
3455 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003456}
3457
3458void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05003459 // This location builder might end up asking to up to four registers, which is
3460 // not currently possible for baseline. The situation in which we need four
3461 // registers cannot be met by baseline though, because it has not run any
3462 // optimization.
3463
Nicolas Geoffray39468442014-09-02 15:17:15 +01003464 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003465 bool needs_write_barrier =
3466 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3467
Mark Mendell5f874182015-03-04 15:42:45 -05003468 bool needs_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003469
Nicolas Geoffray39468442014-09-02 15:17:15 +01003470 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3471 instruction,
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003472 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003473
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003474 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003475 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003476 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3477 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3478 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003479 } else {
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003480 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
3481 || (value_type == Primitive::kPrimByte);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003482 // We need the inputs to be different than the output in case of long operation.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003483 // In case of a byte operation, the register allocator does not support multiple
3484 // inputs that die at entry with one in a specific register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003485 locations->SetInAt(0, Location::RequiresRegister());
3486 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003487 if (is_byte_type) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003488 // Ensure the value is in a byte register.
3489 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003490 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003491 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003492 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003493 // Temporary registers for the write barrier.
3494 if (needs_write_barrier) {
3495 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003496 // Ensure the card is in a byte register.
3497 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003498 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003499 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003500}
3501
3502void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
3503 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003504 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003505 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003506 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003507 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003508 bool needs_runtime_call = locations->WillCall();
3509 bool needs_write_barrier =
3510 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003511
3512 switch (value_type) {
3513 case Primitive::kPrimBoolean:
3514 case Primitive::kPrimByte: {
3515 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003516 if (index.IsConstant()) {
3517 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003518 if (value.IsRegister()) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003519 __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003520 } else {
3521 __ movb(Address(obj, offset),
3522 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3523 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003524 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003525 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003526 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003527 value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003528 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003529 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003530 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3531 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003532 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003533 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003534 break;
3535 }
3536
3537 case Primitive::kPrimShort:
3538 case Primitive::kPrimChar: {
3539 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003540 if (index.IsConstant()) {
3541 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003542 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003543 __ movw(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003544 } else {
3545 __ movw(Address(obj, offset),
3546 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3547 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003548 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003549 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003550 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
3551 value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003552 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003553 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003554 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3555 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003556 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003557 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003558 break;
3559 }
3560
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003561 case Primitive::kPrimInt:
3562 case Primitive::kPrimNot: {
3563 if (!needs_runtime_call) {
3564 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3565 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003566 size_t offset =
3567 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003568 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003569 __ movl(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003570 } else {
3571 DCHECK(value.IsConstant()) << value;
3572 __ movl(Address(obj, offset),
3573 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3574 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003575 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003576 DCHECK(index.IsRegister()) << index;
3577 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003578 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3579 value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003580 } else {
3581 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003582 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003583 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3584 }
3585 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003586 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003587
3588 if (needs_write_barrier) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003589 Register temp = locations->GetTemp(0).AsRegister<Register>();
3590 Register card = locations->GetTemp(1).AsRegister<Register>();
3591 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003592 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003593 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003594 DCHECK_EQ(value_type, Primitive::kPrimNot);
3595 DCHECK(!codegen_->IsLeafMethod());
3596 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
3597 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003598 }
3599 break;
3600 }
3601
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003602 case Primitive::kPrimLong: {
3603 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003604 if (index.IsConstant()) {
3605 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003606 if (value.IsRegisterPair()) {
3607 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003608 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003609 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003610 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003611 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003612 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
3613 __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003614 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003615 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
3616 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003617 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003618 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003619 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003620 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003621 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003622 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003623 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003624 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003625 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003626 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003627 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003628 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003629 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003630 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003631 Immediate(High32Bits(val)));
3632 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003633 }
3634 break;
3635 }
3636
Mark Mendell7c8d0092015-01-26 11:21:33 -05003637 case Primitive::kPrimFloat: {
3638 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3639 DCHECK(value.IsFpuRegister());
3640 if (index.IsConstant()) {
3641 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3642 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3643 } else {
3644 __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3645 value.AsFpuRegister<XmmRegister>());
3646 }
3647 break;
3648 }
3649
3650 case Primitive::kPrimDouble: {
3651 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3652 DCHECK(value.IsFpuRegister());
3653 if (index.IsConstant()) {
3654 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3655 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3656 } else {
3657 __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3658 value.AsFpuRegister<XmmRegister>());
3659 }
3660 break;
3661 }
3662
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003663 case Primitive::kPrimVoid:
3664 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003665 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003666 }
3667}
3668
3669void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
3670 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003671 locations->SetInAt(0, Location::RequiresRegister());
3672 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003673 instruction->SetLocations(locations);
3674}
3675
3676void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
3677 LocationSummary* locations = instruction->GetLocations();
3678 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003679 Register obj = locations->InAt(0).AsRegister<Register>();
3680 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003681 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003682 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003683}
3684
3685void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003686 LocationSummary* locations =
3687 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003688 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003689 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003690 if (instruction->HasUses()) {
3691 locations->SetOut(Location::SameAsFirstInput());
3692 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003693}
3694
3695void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
3696 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003697 Location index_loc = locations->InAt(0);
3698 Location length_loc = locations->InAt(1);
3699 SlowPathCodeX86* slow_path =
3700 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003701 codegen_->AddSlowPath(slow_path);
3702
Mark Mendellf60c90b2015-03-04 15:12:59 -05003703 Register length = length_loc.AsRegister<Register>();
3704 if (index_loc.IsConstant()) {
3705 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3706 __ cmpl(length, Immediate(value));
3707 } else {
3708 __ cmpl(length, index_loc.AsRegister<Register>());
3709 }
3710 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003711}
3712
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003713void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
3714 temp->SetLocations(nullptr);
3715}
3716
3717void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
3718 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003719 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003720}
3721
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003722void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003723 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003724 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003725}
3726
3727void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003728 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3729}
3730
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003731void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
3732 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3733}
3734
3735void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003736 HBasicBlock* block = instruction->GetBlock();
3737 if (block->GetLoopInformation() != nullptr) {
3738 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3739 // The back edge will generate the suspend check.
3740 return;
3741 }
3742 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3743 // The goto will generate the suspend check.
3744 return;
3745 }
3746 GenerateSuspendCheck(instruction, nullptr);
3747}
3748
3749void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
3750 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003751 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003752 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003753 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003754 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003755 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003756 if (successor == nullptr) {
3757 __ j(kNotEqual, slow_path->GetEntryLabel());
3758 __ Bind(slow_path->GetReturnLabel());
3759 } else {
3760 __ j(kEqual, codegen_->GetLabelOf(successor));
3761 __ jmp(slow_path->GetEntryLabel());
3762 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003763}
3764
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003765X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
3766 return codegen_->GetAssembler();
3767}
3768
Mark Mendell7c8d0092015-01-26 11:21:33 -05003769void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003770 ScratchRegisterScope ensure_scratch(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003771 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003772 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003773 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
Mark Mendell7c8d0092015-01-26 11:21:33 -05003774 __ movl(temp_reg, Address(ESP, src + stack_offset));
3775 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3776}
3777
3778void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
3779 ScratchRegisterScope ensure_scratch(
3780 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3781 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3782 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3783 __ movl(temp_reg, Address(ESP, src + stack_offset));
3784 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3785 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
3786 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003787}
3788
3789void ParallelMoveResolverX86::EmitMove(size_t index) {
3790 MoveOperands* move = moves_.Get(index);
3791 Location source = move->GetSource();
3792 Location destination = move->GetDestination();
3793
3794 if (source.IsRegister()) {
3795 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003796 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003797 } else {
3798 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003799 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003800 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003801 } else if (source.IsFpuRegister()) {
3802 if (destination.IsFpuRegister()) {
3803 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3804 } else if (destination.IsStackSlot()) {
3805 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3806 } else {
3807 DCHECK(destination.IsDoubleStackSlot());
3808 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3809 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003810 } else if (source.IsStackSlot()) {
3811 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003812 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003813 } else if (destination.IsFpuRegister()) {
3814 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003815 } else {
3816 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003817 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
3818 }
3819 } else if (source.IsDoubleStackSlot()) {
3820 if (destination.IsFpuRegister()) {
3821 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
3822 } else {
3823 DCHECK(destination.IsDoubleStackSlot()) << destination;
3824 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003825 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003826 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003827 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003828 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003829 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05003830 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003831 if (value == 0) {
3832 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
3833 } else {
3834 __ movl(destination.AsRegister<Register>(), Immediate(value));
3835 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003836 } else {
3837 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05003838 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003839 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003840 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003841 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003842 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003843 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05003844 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003845 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3846 if (value == 0) {
3847 // Easy handling of 0.0.
3848 __ xorps(dest, dest);
3849 } else {
3850 ScratchRegisterScope ensure_scratch(
3851 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3852 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
3853 __ movl(temp, Immediate(value));
3854 __ movd(dest, temp);
3855 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003856 } else {
3857 DCHECK(destination.IsStackSlot()) << destination;
3858 __ movl(Address(ESP, destination.GetStackIndex()), imm);
3859 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003860 } else if (constant->IsLongConstant()) {
3861 int64_t value = constant->AsLongConstant()->GetValue();
3862 int32_t low_value = Low32Bits(value);
3863 int32_t high_value = High32Bits(value);
3864 Immediate low(low_value);
3865 Immediate high(high_value);
3866 if (destination.IsDoubleStackSlot()) {
3867 __ movl(Address(ESP, destination.GetStackIndex()), low);
3868 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
3869 } else {
3870 __ movl(destination.AsRegisterPairLow<Register>(), low);
3871 __ movl(destination.AsRegisterPairHigh<Register>(), high);
3872 }
3873 } else {
3874 DCHECK(constant->IsDoubleConstant());
3875 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003876 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003877 int32_t low_value = Low32Bits(value);
3878 int32_t high_value = High32Bits(value);
3879 Immediate low(low_value);
3880 Immediate high(high_value);
3881 if (destination.IsFpuRegister()) {
3882 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3883 if (value == 0) {
3884 // Easy handling of 0.0.
3885 __ xorpd(dest, dest);
3886 } else {
3887 __ pushl(high);
3888 __ pushl(low);
3889 __ movsd(dest, Address(ESP, 0));
3890 __ addl(ESP, Immediate(8));
3891 }
3892 } else {
3893 DCHECK(destination.IsDoubleStackSlot()) << destination;
3894 __ movl(Address(ESP, destination.GetStackIndex()), low);
3895 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
3896 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003897 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003898 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00003899 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003900 }
3901}
3902
3903void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003904 Register suggested_scratch = reg == EAX ? EBX : EAX;
3905 ScratchRegisterScope ensure_scratch(
3906 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3907
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003908 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3909 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
3910 __ movl(Address(ESP, mem + stack_offset), reg);
3911 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
3912}
3913
Mark Mendell7c8d0092015-01-26 11:21:33 -05003914void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
3915 ScratchRegisterScope ensure_scratch(
3916 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3917
3918 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3919 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3920 __ movl(temp_reg, Address(ESP, mem + stack_offset));
3921 __ movss(Address(ESP, mem + stack_offset), reg);
3922 __ movd(reg, temp_reg);
3923}
3924
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003925void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
3926 ScratchRegisterScope ensure_scratch1(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003927 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3928
3929 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003930 ScratchRegisterScope ensure_scratch2(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003931 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3932
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003933 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
3934 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
3935 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
3936 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
3937 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
3938 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
3939}
3940
3941void ParallelMoveResolverX86::EmitSwap(size_t index) {
3942 MoveOperands* move = moves_.Get(index);
3943 Location source = move->GetSource();
3944 Location destination = move->GetDestination();
3945
3946 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003947 __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003948 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003949 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003950 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003951 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003952 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3953 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003954 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
3955 // Use XOR Swap algorithm to avoid a temporary.
3956 DCHECK_NE(source.reg(), destination.reg());
3957 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3958 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3959 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3960 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
3961 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
3962 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
3963 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003964 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
3965 // Take advantage of the 16 bytes in the XMM register.
3966 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
3967 Address stack(ESP, destination.GetStackIndex());
3968 // Load the double into the high doubleword.
3969 __ movhpd(reg, stack);
3970
3971 // Store the low double into the destination.
3972 __ movsd(stack, reg);
3973
3974 // Move the high double to the low double.
3975 __ psrldq(reg, Immediate(8));
3976 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
3977 // Take advantage of the 16 bytes in the XMM register.
3978 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
3979 Address stack(ESP, source.GetStackIndex());
3980 // Load the double into the high doubleword.
3981 __ movhpd(reg, stack);
3982
3983 // Store the low double into the destination.
3984 __ movsd(stack, reg);
3985
3986 // Move the high double to the low double.
3987 __ psrldq(reg, Immediate(8));
3988 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
3989 Exchange(destination.GetStackIndex(), source.GetStackIndex());
3990 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003991 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003992 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003993 }
3994}
3995
3996void ParallelMoveResolverX86::SpillScratch(int reg) {
3997 __ pushl(static_cast<Register>(reg));
3998}
3999
4000void ParallelMoveResolverX86::RestoreScratch(int reg) {
4001 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004002}
4003
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004004void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004005 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4006 ? LocationSummary::kCallOnSlowPath
4007 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004008 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004009 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004010 locations->SetOut(Location::RequiresRegister());
4011}
4012
4013void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004014 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004015 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004016 DCHECK(!cls->CanCallRuntime());
4017 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004018 codegen_->LoadCurrentMethod(out);
4019 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
4020 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004021 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004022 codegen_->LoadCurrentMethod(out);
4023 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
4024 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004025
4026 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
4027 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4028 codegen_->AddSlowPath(slow_path);
4029 __ testl(out, out);
4030 __ j(kEqual, slow_path->GetEntryLabel());
4031 if (cls->MustGenerateClinitCheck()) {
4032 GenerateClassInitializationCheck(slow_path, out);
4033 } else {
4034 __ Bind(slow_path->GetExitLabel());
4035 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004036 }
4037}
4038
4039void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
4040 LocationSummary* locations =
4041 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4042 locations->SetInAt(0, Location::RequiresRegister());
4043 if (check->HasUses()) {
4044 locations->SetOut(Location::SameAsFirstInput());
4045 }
4046}
4047
4048void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004049 // We assume the class to not be null.
4050 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
4051 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004052 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004053 GenerateClassInitializationCheck(slow_path,
4054 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004055}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004056
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004057void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
4058 SlowPathCodeX86* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004059 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4060 Immediate(mirror::Class::kStatusInitialized));
4061 __ j(kLess, slow_path->GetEntryLabel());
4062 __ Bind(slow_path->GetExitLabel());
4063 // No need for memory fence, thanks to the X86 memory model.
4064}
4065
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004066void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
4067 LocationSummary* locations =
4068 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
4069 locations->SetOut(Location::RequiresRegister());
4070}
4071
4072void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
4073 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
4074 codegen_->AddSlowPath(slow_path);
4075
Roland Levillain271ab9c2014-11-27 15:23:57 +00004076 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004077 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08004078 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
4079 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004080 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
4081 __ testl(out, out);
4082 __ j(kEqual, slow_path->GetEntryLabel());
4083 __ Bind(slow_path->GetExitLabel());
4084}
4085
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004086void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
4087 LocationSummary* locations =
4088 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4089 locations->SetOut(Location::RequiresRegister());
4090}
4091
4092void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
4093 Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004094 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004095 __ fs()->movl(address, Immediate(0));
4096}
4097
4098void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
4099 LocationSummary* locations =
4100 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4101 InvokeRuntimeCallingConvention calling_convention;
4102 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4103}
4104
4105void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
4106 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
4107 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4108}
4109
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004110void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004111 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4112 ? LocationSummary::kNoCall
4113 : LocationSummary::kCallOnSlowPath;
4114 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4115 locations->SetInAt(0, Location::RequiresRegister());
4116 locations->SetInAt(1, Location::Any());
4117 locations->SetOut(Location::RequiresRegister());
4118}
4119
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004120void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004121 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004122 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004123 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004124 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004125 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4126 Label done, zero;
4127 SlowPathCodeX86* slow_path = nullptr;
4128
4129 // Return 0 if `obj` is null.
4130 // TODO: avoid this check if we know obj is not null.
4131 __ testl(obj, obj);
4132 __ j(kEqual, &zero);
4133 __ movl(out, Address(obj, class_offset));
4134 // Compare the class of `obj` with `cls`.
4135 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004136 __ cmpl(out, cls.AsRegister<Register>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004137 } else {
4138 DCHECK(cls.IsStackSlot()) << cls;
4139 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
4140 }
4141
4142 if (instruction->IsClassFinal()) {
4143 // Classes must be equal for the instanceof to succeed.
4144 __ j(kNotEqual, &zero);
4145 __ movl(out, Immediate(1));
4146 __ jmp(&done);
4147 } else {
4148 // If the classes are not equal, we go into a slow path.
4149 DCHECK(locations->OnlyCallsOnSlowPath());
4150 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004151 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004152 codegen_->AddSlowPath(slow_path);
4153 __ j(kNotEqual, slow_path->GetEntryLabel());
4154 __ movl(out, Immediate(1));
4155 __ jmp(&done);
4156 }
4157 __ Bind(&zero);
4158 __ movl(out, Immediate(0));
4159 if (slow_path != nullptr) {
4160 __ Bind(slow_path->GetExitLabel());
4161 }
4162 __ Bind(&done);
4163}
4164
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004165void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
4166 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4167 instruction, LocationSummary::kCallOnSlowPath);
4168 locations->SetInAt(0, Location::RequiresRegister());
4169 locations->SetInAt(1, Location::Any());
4170 locations->AddTemp(Location::RequiresRegister());
4171}
4172
4173void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
4174 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004175 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004176 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004177 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004178 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4179 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
4180 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4181 codegen_->AddSlowPath(slow_path);
4182
4183 // TODO: avoid this check if we know obj is not null.
4184 __ testl(obj, obj);
4185 __ j(kEqual, slow_path->GetExitLabel());
4186 __ movl(temp, Address(obj, class_offset));
4187
4188 // Compare the class of `obj` with `cls`.
4189 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004190 __ cmpl(temp, cls.AsRegister<Register>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004191 } else {
4192 DCHECK(cls.IsStackSlot()) << cls;
4193 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
4194 }
4195
4196 __ j(kNotEqual, slow_path->GetEntryLabel());
4197 __ Bind(slow_path->GetExitLabel());
4198}
4199
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004200void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4201 LocationSummary* locations =
4202 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4203 InvokeRuntimeCallingConvention calling_convention;
4204 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4205}
4206
4207void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4208 __ fs()->call(Address::Absolute(instruction->IsEnter()
4209 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject)
4210 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject)));
4211 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4212}
4213
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004214void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4215void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4216void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4217
4218void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4219 LocationSummary* locations =
4220 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4221 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4222 || instruction->GetResultType() == Primitive::kPrimLong);
4223 locations->SetInAt(0, Location::RequiresRegister());
4224 locations->SetInAt(1, Location::Any());
4225 locations->SetOut(Location::SameAsFirstInput());
4226}
4227
4228void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
4229 HandleBitwiseOperation(instruction);
4230}
4231
4232void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
4233 HandleBitwiseOperation(instruction);
4234}
4235
4236void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
4237 HandleBitwiseOperation(instruction);
4238}
4239
4240void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4241 LocationSummary* locations = instruction->GetLocations();
4242 Location first = locations->InAt(0);
4243 Location second = locations->InAt(1);
4244 DCHECK(first.Equals(locations->Out()));
4245
4246 if (instruction->GetResultType() == Primitive::kPrimInt) {
4247 if (second.IsRegister()) {
4248 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004249 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004250 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004251 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004252 } else {
4253 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004254 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004255 }
4256 } else if (second.IsConstant()) {
4257 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004258 __ andl(first.AsRegister<Register>(),
4259 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004260 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004261 __ orl(first.AsRegister<Register>(),
4262 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004263 } else {
4264 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00004265 __ xorl(first.AsRegister<Register>(),
4266 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004267 }
4268 } else {
4269 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004270 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004271 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004272 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004273 } else {
4274 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004275 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004276 }
4277 }
4278 } else {
4279 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4280 if (second.IsRegisterPair()) {
4281 if (instruction->IsAnd()) {
4282 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4283 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4284 } else if (instruction->IsOr()) {
4285 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4286 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4287 } else {
4288 DCHECK(instruction->IsXor());
4289 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4290 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4291 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004292 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004293 if (instruction->IsAnd()) {
4294 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4295 __ andl(first.AsRegisterPairHigh<Register>(),
4296 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4297 } else if (instruction->IsOr()) {
4298 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4299 __ orl(first.AsRegisterPairHigh<Register>(),
4300 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4301 } else {
4302 DCHECK(instruction->IsXor());
4303 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4304 __ xorl(first.AsRegisterPairHigh<Register>(),
4305 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4306 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004307 } else {
4308 DCHECK(second.IsConstant()) << second;
4309 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004310 int32_t low_value = Low32Bits(value);
4311 int32_t high_value = High32Bits(value);
4312 Immediate low(low_value);
4313 Immediate high(high_value);
4314 Register first_low = first.AsRegisterPairLow<Register>();
4315 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004316 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004317 if (low_value == 0) {
4318 __ xorl(first_low, first_low);
4319 } else if (low_value != -1) {
4320 __ andl(first_low, low);
4321 }
4322 if (high_value == 0) {
4323 __ xorl(first_high, first_high);
4324 } else if (high_value != -1) {
4325 __ andl(first_high, high);
4326 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004327 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004328 if (low_value != 0) {
4329 __ orl(first_low, low);
4330 }
4331 if (high_value != 0) {
4332 __ orl(first_high, high);
4333 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004334 } else {
4335 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004336 if (low_value != 0) {
4337 __ xorl(first_low, low);
4338 }
4339 if (high_value != 0) {
4340 __ xorl(first_high, high);
4341 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004342 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004343 }
4344 }
4345}
4346
Calin Juravleb1498f62015-02-16 13:13:29 +00004347void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
4348 // Nothing to do, this should be removed during prepare for register allocator.
4349 UNUSED(instruction);
4350 LOG(FATAL) << "Unreachable";
4351}
4352
4353void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
4354 // Nothing to do, this should be removed during prepare for register allocator.
4355 UNUSED(instruction);
4356 LOG(FATAL) << "Unreachable";
4357}
4358
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004359} // namespace x86
4360} // namespace art