blob: 007e25ab4a54d5fdb9307c64e272c2a5d5d1b43c [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());
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002232 DCHECK(locations->InAt(1).GetConstant()->IsIntConstant());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002233
2234 Register out_register = locations->Out().AsRegister<Register>();
2235 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002236 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002237
2238 DCHECK(imm == 1 || imm == -1);
2239
2240 if (instruction->IsRem()) {
2241 __ xorl(out_register, out_register);
2242 } else {
2243 __ movl(out_register, input_register);
2244 if (imm == -1) {
2245 __ negl(out_register);
2246 }
2247 }
2248}
2249
2250
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002251void InstructionCodeGeneratorX86::DivByPowerOfTwo(HDiv* instruction) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002252 LocationSummary* locations = instruction->GetLocations();
2253
2254 Register out_register = locations->Out().AsRegister<Register>();
2255 Register input_register = locations->InAt(0).AsRegister<Register>();
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002256 int32_t imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002257
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002258 DCHECK(IsPowerOfTwo(std::abs(imm)));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002259 Register num = locations->GetTemp(0).AsRegister<Register>();
2260
2261 __ leal(num, Address(input_register, std::abs(imm) - 1));
2262 __ testl(input_register, input_register);
2263 __ cmovl(kGreaterEqual, num, input_register);
2264 int shift = CTZ(imm);
2265 __ sarl(num, Immediate(shift));
2266
2267 if (imm < 0) {
2268 __ negl(num);
2269 }
2270
2271 __ movl(out_register, num);
2272}
2273
2274void InstructionCodeGeneratorX86::GenerateDivRemWithAnyConstant(HBinaryOperation* instruction) {
2275 DCHECK(instruction->IsDiv() || instruction->IsRem());
2276
2277 LocationSummary* locations = instruction->GetLocations();
2278 int imm = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
2279
2280 Register eax = locations->InAt(0).AsRegister<Register>();
2281 Register out = locations->Out().AsRegister<Register>();
2282 Register num;
2283 Register edx;
2284
2285 if (instruction->IsDiv()) {
2286 edx = locations->GetTemp(0).AsRegister<Register>();
2287 num = locations->GetTemp(1).AsRegister<Register>();
2288 } else {
2289 edx = locations->Out().AsRegister<Register>();
2290 num = locations->GetTemp(0).AsRegister<Register>();
2291 }
2292
2293 DCHECK_EQ(EAX, eax);
2294 DCHECK_EQ(EDX, edx);
2295 if (instruction->IsDiv()) {
2296 DCHECK_EQ(EAX, out);
2297 } else {
2298 DCHECK_EQ(EDX, out);
2299 }
2300
2301 int64_t magic;
2302 int shift;
2303 CalculateMagicAndShiftForDivRem(imm, false /* is_long */, &magic, &shift);
2304
2305 Label ndiv;
2306 Label end;
2307 // If numerator is 0, the result is 0, no computation needed.
2308 __ testl(eax, eax);
2309 __ j(kNotEqual, &ndiv);
2310
2311 __ xorl(out, out);
2312 __ jmp(&end);
2313
2314 __ Bind(&ndiv);
2315
2316 // Save the numerator.
2317 __ movl(num, eax);
2318
2319 // EAX = magic
2320 __ movl(eax, Immediate(magic));
2321
2322 // EDX:EAX = magic * numerator
2323 __ imull(num);
2324
2325 if (imm > 0 && magic < 0) {
2326 // EDX += num
2327 __ addl(edx, num);
2328 } else if (imm < 0 && magic > 0) {
2329 __ subl(edx, num);
2330 }
2331
2332 // Shift if needed.
2333 if (shift != 0) {
2334 __ sarl(edx, Immediate(shift));
2335 }
2336
2337 // EDX += 1 if EDX < 0
2338 __ movl(eax, edx);
2339 __ shrl(edx, Immediate(31));
2340 __ addl(edx, eax);
2341
2342 if (instruction->IsRem()) {
2343 __ movl(eax, num);
2344 __ imull(edx, Immediate(imm));
2345 __ subl(eax, edx);
2346 __ movl(edx, eax);
2347 } else {
2348 __ movl(eax, edx);
2349 }
2350 __ Bind(&end);
2351}
2352
Calin Juravlebacfec32014-11-14 15:54:36 +00002353void InstructionCodeGeneratorX86::GenerateDivRemIntegral(HBinaryOperation* instruction) {
2354 DCHECK(instruction->IsDiv() || instruction->IsRem());
2355
2356 LocationSummary* locations = instruction->GetLocations();
2357 Location out = locations->Out();
2358 Location first = locations->InAt(0);
2359 Location second = locations->InAt(1);
2360 bool is_div = instruction->IsDiv();
2361
2362 switch (instruction->GetResultType()) {
2363 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002364 DCHECK_EQ(EAX, first.AsRegister<Register>());
2365 DCHECK_EQ(is_div ? EAX : EDX, out.AsRegister<Register>());
Calin Juravlebacfec32014-11-14 15:54:36 +00002366
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002367 if (instruction->InputAt(1)->IsIntConstant()) {
2368 int32_t imm = second.GetConstant()->AsIntConstant()->GetValue();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002369
2370 if (imm == 0) {
2371 // Do not generate anything for 0. DivZeroCheck would forbid any generated code.
2372 } else if (imm == 1 || imm == -1) {
2373 DivRemOneOrMinusOne(instruction);
2374 } else if (is_div && IsPowerOfTwo(std::abs(imm))) {
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002375 DivByPowerOfTwo(instruction->AsDiv());
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002376 } else {
2377 DCHECK(imm <= -2 || imm >= 2);
2378 GenerateDivRemWithAnyConstant(instruction);
2379 }
2380 } else {
2381 SlowPathCodeX86* slow_path =
Roland Levillain199f3362014-11-27 17:15:16 +00002382 new (GetGraph()->GetArena()) DivRemMinusOneSlowPathX86(out.AsRegister<Register>(),
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002383 is_div);
2384 codegen_->AddSlowPath(slow_path);
Calin Juravlebacfec32014-11-14 15:54:36 +00002385
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002386 Register second_reg = second.AsRegister<Register>();
2387 // 0x80000000/-1 triggers an arithmetic exception!
2388 // Dividing by -1 is actually negation and -0x800000000 = 0x80000000 so
2389 // it's safe to just use negl instead of more complex comparisons.
Calin Juravlebacfec32014-11-14 15:54:36 +00002390
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002391 __ cmpl(second_reg, Immediate(-1));
2392 __ j(kEqual, slow_path->GetEntryLabel());
Calin Juravlebacfec32014-11-14 15:54:36 +00002393
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002394 // edx:eax <- sign-extended of eax
2395 __ cdq();
2396 // eax = quotient, edx = remainder
2397 __ idivl(second_reg);
2398 __ Bind(slow_path->GetExitLabel());
2399 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002400 break;
2401 }
2402
2403 case Primitive::kPrimLong: {
2404 InvokeRuntimeCallingConvention calling_convention;
2405 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>());
2406 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>());
2407 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>());
2408 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>());
2409 DCHECK_EQ(EAX, out.AsRegisterPairLow<Register>());
2410 DCHECK_EQ(EDX, out.AsRegisterPairHigh<Register>());
2411
2412 if (is_div) {
2413 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLdiv)));
2414 } else {
2415 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLmod)));
2416 }
2417 uint32_t dex_pc = is_div
2418 ? instruction->AsDiv()->GetDexPc()
2419 : instruction->AsRem()->GetDexPc();
2420 codegen_->RecordPcInfo(instruction, dex_pc);
2421
2422 break;
2423 }
2424
2425 default:
2426 LOG(FATAL) << "Unexpected type for GenerateDivRemIntegral " << instruction->GetResultType();
2427 }
2428}
2429
Calin Juravle7c4954d2014-10-28 16:57:40 +00002430void LocationsBuilderX86::VisitDiv(HDiv* div) {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002431 LocationSummary::CallKind call_kind = (div->GetResultType() == Primitive::kPrimLong)
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002432 ? LocationSummary::kCall
2433 : LocationSummary::kNoCall;
2434 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind);
2435
Calin Juravle7c4954d2014-10-28 16:57:40 +00002436 switch (div->GetResultType()) {
Calin Juravled0d48522014-11-04 16:40:20 +00002437 case Primitive::kPrimInt: {
2438 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002439 locations->SetInAt(1, Location::RegisterOrConstant(div->InputAt(1)));
Calin Juravled0d48522014-11-04 16:40:20 +00002440 locations->SetOut(Location::SameAsFirstInput());
2441 // Intel uses edx:eax as the dividend.
2442 locations->AddTemp(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002443 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2444 // which enforces results to be in EAX and EDX, things are simpler if we use EAX also as
2445 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002446 if (div->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002447 locations->AddTemp(Location::RequiresRegister());
2448 }
Calin Juravled0d48522014-11-04 16:40:20 +00002449 break;
2450 }
Calin Juravle7c4954d2014-10-28 16:57:40 +00002451 case Primitive::kPrimLong: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002452 InvokeRuntimeCallingConvention calling_convention;
2453 locations->SetInAt(0, Location::RegisterPairLocation(
2454 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2455 locations->SetInAt(1, Location::RegisterPairLocation(
2456 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2457 // Runtime helper puts the result in EAX, EDX.
2458 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Calin Juravle7c4954d2014-10-28 16:57:40 +00002459 break;
2460 }
2461 case Primitive::kPrimFloat:
2462 case Primitive::kPrimDouble: {
2463 locations->SetInAt(0, Location::RequiresFpuRegister());
2464 locations->SetInAt(1, Location::RequiresFpuRegister());
2465 locations->SetOut(Location::SameAsFirstInput());
2466 break;
2467 }
2468
2469 default:
2470 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2471 }
2472}
2473
2474void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
2475 LocationSummary* locations = div->GetLocations();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002476 Location out = locations->Out();
Calin Juravle7c4954d2014-10-28 16:57:40 +00002477 Location first = locations->InAt(0);
2478 Location second = locations->InAt(1);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002479
2480 switch (div->GetResultType()) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002481 case Primitive::kPrimInt:
Calin Juravle7c4954d2014-10-28 16:57:40 +00002482 case Primitive::kPrimLong: {
Calin Juravlebacfec32014-11-14 15:54:36 +00002483 GenerateDivRemIntegral(div);
Calin Juravle7c4954d2014-10-28 16:57:40 +00002484 break;
2485 }
2486
2487 case Primitive::kPrimFloat: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002488 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002489 __ divss(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002490 break;
2491 }
2492
2493 case Primitive::kPrimDouble: {
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002494 DCHECK(first.Equals(out));
Roland Levillain271ab9c2014-11-27 15:23:57 +00002495 __ divsd(first.AsFpuRegister<XmmRegister>(), second.AsFpuRegister<XmmRegister>());
Calin Juravle7c4954d2014-10-28 16:57:40 +00002496 break;
2497 }
2498
2499 default:
2500 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
2501 }
2502}
2503
Calin Juravlebacfec32014-11-14 15:54:36 +00002504void LocationsBuilderX86::VisitRem(HRem* rem) {
Calin Juravled2ec87d2014-12-08 14:24:46 +00002505 Primitive::Type type = rem->GetResultType();
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002506
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002507 LocationSummary::CallKind call_kind = (rem->GetResultType() == Primitive::kPrimLong)
2508 ? LocationSummary::kCall
2509 : LocationSummary::kNoCall;
2510 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind);
Calin Juravlebacfec32014-11-14 15:54:36 +00002511
Calin Juravled2ec87d2014-12-08 14:24:46 +00002512 switch (type) {
Calin Juravlebacfec32014-11-14 15:54:36 +00002513 case Primitive::kPrimInt: {
2514 locations->SetInAt(0, Location::RegisterLocation(EAX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002515 locations->SetInAt(1, Location::RegisterOrConstant(rem->InputAt(1)));
Calin Juravlebacfec32014-11-14 15:54:36 +00002516 locations->SetOut(Location::RegisterLocation(EDX));
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002517 // We need to save the numerator while we tweak eax and edx. As we are using imul in a way
2518 // which enforces results to be in EAX and EDX, things are simpler if we use EDX also as
2519 // output and request another temp.
Guillaume Sanchezb19930c2015-04-09 21:12:15 +01002520 if (rem->InputAt(1)->IsIntConstant()) {
Guillaume Sanchez0f88e872015-03-30 17:55:45 +01002521 locations->AddTemp(Location::RequiresRegister());
2522 }
Calin Juravlebacfec32014-11-14 15:54:36 +00002523 break;
2524 }
2525 case Primitive::kPrimLong: {
2526 InvokeRuntimeCallingConvention calling_convention;
2527 locations->SetInAt(0, Location::RegisterPairLocation(
2528 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1)));
2529 locations->SetInAt(1, Location::RegisterPairLocation(
2530 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3)));
2531 // Runtime helper puts the result in EAX, EDX.
2532 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
2533 break;
2534 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002535 case Primitive::kPrimDouble:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002536 case Primitive::kPrimFloat: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002537 locations->SetInAt(0, Location::Any());
2538 locations->SetInAt(1, Location::Any());
2539 locations->SetOut(Location::RequiresFpuRegister());
2540 locations->AddTemp(Location::RegisterLocation(EAX));
Calin Juravlebacfec32014-11-14 15:54:36 +00002541 break;
2542 }
2543
2544 default:
Calin Juravled2ec87d2014-12-08 14:24:46 +00002545 LOG(FATAL) << "Unexpected rem type " << type;
Calin Juravlebacfec32014-11-14 15:54:36 +00002546 }
2547}
2548
2549void InstructionCodeGeneratorX86::VisitRem(HRem* rem) {
2550 Primitive::Type type = rem->GetResultType();
2551 switch (type) {
2552 case Primitive::kPrimInt:
2553 case Primitive::kPrimLong: {
2554 GenerateDivRemIntegral(rem);
2555 break;
2556 }
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002557 case Primitive::kPrimFloat:
Calin Juravlebacfec32014-11-14 15:54:36 +00002558 case Primitive::kPrimDouble: {
Mark Mendell24f2dfa2015-01-14 19:51:45 -05002559 GenerateRemFP(rem);
Calin Juravlebacfec32014-11-14 15:54:36 +00002560 break;
2561 }
2562 default:
2563 LOG(FATAL) << "Unexpected rem type " << type;
2564 }
2565}
2566
Calin Juravled0d48522014-11-04 16:40:20 +00002567void LocationsBuilderX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2568 LocationSummary* locations =
2569 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002570 switch (instruction->GetType()) {
2571 case Primitive::kPrimInt: {
2572 locations->SetInAt(0, Location::Any());
2573 break;
2574 }
2575 case Primitive::kPrimLong: {
2576 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
2577 if (!instruction->IsConstant()) {
2578 locations->AddTemp(Location::RequiresRegister());
2579 }
2580 break;
2581 }
2582 default:
2583 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType();
2584 }
Calin Juravled0d48522014-11-04 16:40:20 +00002585 if (instruction->HasUses()) {
2586 locations->SetOut(Location::SameAsFirstInput());
2587 }
2588}
2589
2590void InstructionCodeGeneratorX86::VisitDivZeroCheck(HDivZeroCheck* instruction) {
2591 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathX86(instruction);
2592 codegen_->AddSlowPath(slow_path);
2593
2594 LocationSummary* locations = instruction->GetLocations();
2595 Location value = locations->InAt(0);
2596
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002597 switch (instruction->GetType()) {
2598 case Primitive::kPrimInt: {
2599 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002600 __ testl(value.AsRegister<Register>(), value.AsRegister<Register>());
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002601 __ j(kEqual, slow_path->GetEntryLabel());
2602 } else if (value.IsStackSlot()) {
2603 __ cmpl(Address(ESP, value.GetStackIndex()), Immediate(0));
2604 __ j(kEqual, slow_path->GetEntryLabel());
2605 } else {
2606 DCHECK(value.IsConstant()) << value;
2607 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) {
2608 __ jmp(slow_path->GetEntryLabel());
2609 }
2610 }
2611 break;
Calin Juravled0d48522014-11-04 16:40:20 +00002612 }
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002613 case Primitive::kPrimLong: {
2614 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002615 Register temp = locations->GetTemp(0).AsRegister<Register>();
Calin Juravled6fb6cf2014-11-11 19:07:44 +00002616 __ movl(temp, value.AsRegisterPairLow<Register>());
2617 __ orl(temp, value.AsRegisterPairHigh<Register>());
2618 __ j(kEqual, slow_path->GetEntryLabel());
2619 } else {
2620 DCHECK(value.IsConstant()) << value;
2621 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) {
2622 __ jmp(slow_path->GetEntryLabel());
2623 }
2624 }
2625 break;
2626 }
2627 default:
2628 LOG(FATAL) << "Unexpected type for HDivZeroCheck" << instruction->GetType();
Calin Juravled0d48522014-11-04 16:40:20 +00002629 }
Calin Juravled0d48522014-11-04 16:40:20 +00002630}
2631
Calin Juravle9aec02f2014-11-18 23:06:35 +00002632void LocationsBuilderX86::HandleShift(HBinaryOperation* op) {
2633 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2634
2635 LocationSummary* locations =
2636 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall);
2637
2638 switch (op->GetResultType()) {
2639 case Primitive::kPrimInt: {
2640 locations->SetInAt(0, Location::RequiresRegister());
2641 // The shift count needs to be in CL.
2642 locations->SetInAt(1, Location::ByteRegisterOrConstant(ECX, op->InputAt(1)));
2643 locations->SetOut(Location::SameAsFirstInput());
2644 break;
2645 }
2646 case Primitive::kPrimLong: {
2647 locations->SetInAt(0, Location::RequiresRegister());
2648 // The shift count needs to be in CL.
2649 locations->SetInAt(1, Location::RegisterLocation(ECX));
2650 locations->SetOut(Location::SameAsFirstInput());
2651 break;
2652 }
2653 default:
2654 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2655 }
2656}
2657
2658void InstructionCodeGeneratorX86::HandleShift(HBinaryOperation* op) {
2659 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr());
2660
2661 LocationSummary* locations = op->GetLocations();
2662 Location first = locations->InAt(0);
2663 Location second = locations->InAt(1);
2664 DCHECK(first.Equals(locations->Out()));
2665
2666 switch (op->GetResultType()) {
2667 case Primitive::kPrimInt: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002668 Register first_reg = first.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002669 if (second.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002670 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002671 DCHECK_EQ(ECX, second_reg);
2672 if (op->IsShl()) {
2673 __ shll(first_reg, second_reg);
2674 } else if (op->IsShr()) {
2675 __ sarl(first_reg, second_reg);
2676 } else {
2677 __ shrl(first_reg, second_reg);
2678 }
2679 } else {
Nicolas Geoffray486cc192014-12-08 18:00:55 +00002680 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue() & kMaxIntShiftValue);
Calin Juravle9aec02f2014-11-18 23:06:35 +00002681 if (op->IsShl()) {
2682 __ shll(first_reg, imm);
2683 } else if (op->IsShr()) {
2684 __ sarl(first_reg, imm);
2685 } else {
2686 __ shrl(first_reg, imm);
2687 }
2688 }
2689 break;
2690 }
2691 case Primitive::kPrimLong: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002692 Register second_reg = second.AsRegister<Register>();
Calin Juravle9aec02f2014-11-18 23:06:35 +00002693 DCHECK_EQ(ECX, second_reg);
2694 if (op->IsShl()) {
2695 GenerateShlLong(first, second_reg);
2696 } else if (op->IsShr()) {
2697 GenerateShrLong(first, second_reg);
2698 } else {
2699 GenerateUShrLong(first, second_reg);
2700 }
2701 break;
2702 }
2703 default:
2704 LOG(FATAL) << "Unexpected op type " << op->GetResultType();
2705 }
2706}
2707
2708void InstructionCodeGeneratorX86::GenerateShlLong(const Location& loc, Register shifter) {
2709 Label done;
2710 __ shld(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>(), shifter);
2711 __ shll(loc.AsRegisterPairLow<Register>(), shifter);
2712 __ testl(shifter, Immediate(32));
2713 __ j(kEqual, &done);
2714 __ movl(loc.AsRegisterPairHigh<Register>(), loc.AsRegisterPairLow<Register>());
2715 __ movl(loc.AsRegisterPairLow<Register>(), Immediate(0));
2716 __ Bind(&done);
2717}
2718
2719void InstructionCodeGeneratorX86::GenerateShrLong(const Location& loc, Register shifter) {
2720 Label done;
2721 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2722 __ sarl(loc.AsRegisterPairHigh<Register>(), shifter);
2723 __ testl(shifter, Immediate(32));
2724 __ j(kEqual, &done);
2725 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2726 __ sarl(loc.AsRegisterPairHigh<Register>(), Immediate(31));
2727 __ Bind(&done);
2728}
2729
2730void InstructionCodeGeneratorX86::GenerateUShrLong(const Location& loc, Register shifter) {
2731 Label done;
2732 __ shrd(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>(), shifter);
2733 __ shrl(loc.AsRegisterPairHigh<Register>(), shifter);
2734 __ testl(shifter, Immediate(32));
2735 __ j(kEqual, &done);
2736 __ movl(loc.AsRegisterPairLow<Register>(), loc.AsRegisterPairHigh<Register>());
2737 __ movl(loc.AsRegisterPairHigh<Register>(), Immediate(0));
2738 __ Bind(&done);
2739}
2740
2741void LocationsBuilderX86::VisitShl(HShl* shl) {
2742 HandleShift(shl);
2743}
2744
2745void InstructionCodeGeneratorX86::VisitShl(HShl* shl) {
2746 HandleShift(shl);
2747}
2748
2749void LocationsBuilderX86::VisitShr(HShr* shr) {
2750 HandleShift(shr);
2751}
2752
2753void InstructionCodeGeneratorX86::VisitShr(HShr* shr) {
2754 HandleShift(shr);
2755}
2756
2757void LocationsBuilderX86::VisitUShr(HUShr* ushr) {
2758 HandleShift(ushr);
2759}
2760
2761void InstructionCodeGeneratorX86::VisitUShr(HUShr* ushr) {
2762 HandleShift(ushr);
2763}
2764
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002765void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002766 LocationSummary* locations =
2767 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002768 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002769 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002770 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
2771 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002772}
2773
2774void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
2775 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002776 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002777 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002778
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002779 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002780
Nicolas Geoffray39468442014-09-02 15:17:15 +01002781 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01002782 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01002783}
2784
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002785void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
2786 LocationSummary* locations =
2787 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
2788 locations->SetOut(Location::RegisterLocation(EAX));
2789 InvokeRuntimeCallingConvention calling_convention;
2790 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002791 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
2792 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002793}
2794
2795void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
2796 InvokeRuntimeCallingConvention calling_convention;
Andreas Gampe1cc7dba2014-12-17 18:43:01 -08002797 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002798 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
2799
Nicolas Geoffraycb1b00a2015-01-28 14:50:01 +00002800 __ fs()->call(Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01002801
2802 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
2803 DCHECK(!codegen_->IsLeafMethod());
2804}
2805
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002806void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002807 LocationSummary* locations =
2808 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002809 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
2810 if (location.IsStackSlot()) {
2811 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
2812 } else if (location.IsDoubleStackSlot()) {
2813 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002814 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01002815 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002816}
2817
2818void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002819 UNUSED(instruction);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01002820}
2821
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002822void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002823 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002824 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002825 locations->SetInAt(0, Location::RequiresRegister());
2826 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002827}
2828
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002829void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
2830 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01002831 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01002832 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01002833 DCHECK(in.Equals(out));
Nicolas Geoffrayd8ef2e92015-02-24 16:02:06 +00002834 switch (not_->GetResultType()) {
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002835 case Primitive::kPrimInt:
Roland Levillain271ab9c2014-11-27 15:23:57 +00002836 __ notl(out.AsRegister<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002837 break;
2838
2839 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01002840 __ notl(out.AsRegisterPairLow<Register>());
2841 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01002842 break;
2843
2844 default:
2845 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
2846 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01002847}
2848
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002849void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002850 LocationSummary* locations =
2851 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Calin Juravleddb7df22014-11-25 20:56:51 +00002852 switch (compare->InputAt(0)->GetType()) {
2853 case Primitive::kPrimLong: {
2854 locations->SetInAt(0, Location::RequiresRegister());
Calin Juravleddb7df22014-11-25 20:56:51 +00002855 locations->SetInAt(1, Location::Any());
2856 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2857 break;
2858 }
2859 case Primitive::kPrimFloat:
2860 case Primitive::kPrimDouble: {
2861 locations->SetInAt(0, Location::RequiresFpuRegister());
2862 locations->SetInAt(1, Location::RequiresFpuRegister());
2863 locations->SetOut(Location::RequiresRegister());
2864 break;
2865 }
2866 default:
2867 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
2868 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002869}
2870
2871void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002872 LocationSummary* locations = compare->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00002873 Register out = locations->Out().AsRegister<Register>();
Calin Juravleddb7df22014-11-25 20:56:51 +00002874 Location left = locations->InAt(0);
2875 Location right = locations->InAt(1);
2876
2877 Label less, greater, done;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002878 switch (compare->InputAt(0)->GetType()) {
2879 case Primitive::kPrimLong: {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002880 Register left_low = left.AsRegisterPairLow<Register>();
2881 Register left_high = left.AsRegisterPairHigh<Register>();
2882 int32_t val_low = 0;
2883 int32_t val_high = 0;
2884 bool right_is_const = false;
2885
2886 if (right.IsConstant()) {
2887 DCHECK(right.GetConstant()->IsLongConstant());
2888 right_is_const = true;
2889 int64_t val = right.GetConstant()->AsLongConstant()->GetValue();
2890 val_low = Low32Bits(val);
2891 val_high = High32Bits(val);
2892 }
2893
Calin Juravleddb7df22014-11-25 20:56:51 +00002894 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002895 __ cmpl(left_high, right.AsRegisterPairHigh<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002896 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002897 __ cmpl(left_high, Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002898 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002899 DCHECK(right_is_const) << right;
2900 if (val_high == 0) {
2901 __ testl(left_high, left_high);
2902 } else {
2903 __ cmpl(left_high, Immediate(val_high));
2904 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002905 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002906 __ j(kLess, &less); // Signed compare.
2907 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002908 if (right.IsRegisterPair()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002909 __ cmpl(left_low, right.AsRegisterPairLow<Register>());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002910 } else if (right.IsDoubleStackSlot()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002911 __ cmpl(left_low, Address(ESP, right.GetStackIndex()));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00002912 } else {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04002913 DCHECK(right_is_const) << right;
2914 if (val_low == 0) {
2915 __ testl(left_low, left_low);
2916 } else {
2917 __ cmpl(left_low, Immediate(val_low));
2918 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002919 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002920 break;
2921 }
2922 case Primitive::kPrimFloat: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002923 __ ucomiss(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002924 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
2925 break;
2926 }
2927 case Primitive::kPrimDouble: {
Roland Levillain271ab9c2014-11-27 15:23:57 +00002928 __ ucomisd(left.AsFpuRegister<XmmRegister>(), right.AsFpuRegister<XmmRegister>());
Calin Juravleddb7df22014-11-25 20:56:51 +00002929 __ j(kUnordered, compare->IsGtBias() ? &greater : &less);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002930 break;
2931 }
2932 default:
Calin Juravleddb7df22014-11-25 20:56:51 +00002933 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType();
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002934 }
Calin Juravleddb7df22014-11-25 20:56:51 +00002935 __ movl(out, Immediate(0));
2936 __ j(kEqual, &done);
2937 __ j(kBelow, &less); // kBelow is for CF (unsigned & floats).
2938
2939 __ Bind(&greater);
2940 __ movl(out, Immediate(1));
2941 __ jmp(&done);
2942
2943 __ Bind(&less);
2944 __ movl(out, Immediate(-1));
2945
2946 __ Bind(&done);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01002947}
2948
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002949void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01002950 LocationSummary* locations =
2951 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01002952 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
2953 locations->SetInAt(i, Location::Any());
2954 }
2955 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002956}
2957
2958void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07002959 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002960 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01002961}
2962
Calin Juravle52c48962014-12-16 17:02:57 +00002963void InstructionCodeGeneratorX86::GenerateMemoryBarrier(MemBarrierKind kind) {
2964 /*
2965 * According to the JSR-133 Cookbook, for x86 only StoreLoad/AnyAny barriers need memory fence.
2966 * All other barriers (LoadAny, AnyStore, StoreStore) are nops due to the x86 memory model.
2967 * For those cases, all we need to ensure is that there is a scheduling barrier in place.
2968 */
2969 switch (kind) {
2970 case MemBarrierKind::kAnyAny: {
2971 __ mfence();
2972 break;
2973 }
2974 case MemBarrierKind::kAnyStore:
2975 case MemBarrierKind::kLoadAny:
2976 case MemBarrierKind::kStoreStore: {
2977 // nop
2978 break;
2979 }
2980 default:
2981 LOG(FATAL) << "Unexpected memory barrier " << kind;
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01002982 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002983}
2984
Nicolas Geoffraye5038322014-07-04 09:41:32 +01002985
Mark Mendell09ed1a32015-03-25 08:30:06 -04002986void CodeGeneratorX86::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke,
2987 Register temp) {
2988 // TODO: Implement all kinds of calls:
2989 // 1) boot -> boot
2990 // 2) app -> boot
2991 // 3) app -> app
2992 //
2993 // Currently we implement the app -> app logic, which looks up in the resolve cache.
2994 // temp = method;
2995 LoadCurrentMethod(temp);
2996 if (!invoke->IsRecursive()) {
2997 // temp = temp->dex_cache_resolved_methods_;
2998 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
2999 // temp = temp[index_in_cache]
3000 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())));
3001 // (temp + offset_of_quick_compiled_code)()
3002 __ call(Address(
3003 temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kX86WordSize).Int32Value()));
3004 } else {
3005 __ call(GetFrameEntryLabel());
3006 }
3007
3008 DCHECK(!IsLeafMethod());
3009 RecordPcInfo(invoke, invoke->GetDexPc());
3010}
3011
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003012void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003013 Label is_null;
3014 __ testl(value, value);
3015 __ j(kEqual, &is_null);
3016 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
3017 __ movl(temp, object);
3018 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003019 __ movb(Address(temp, card, TIMES_1, 0),
3020 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003021 __ Bind(&is_null);
3022}
3023
Calin Juravle52c48962014-12-16 17:02:57 +00003024void LocationsBuilderX86::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) {
3025 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffray39468442014-09-02 15:17:15 +01003026 LocationSummary* locations =
3027 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003028 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003029
3030 // The output overlaps in case of long: we don't want the low move to overwrite
3031 // the object's location.
3032 locations->SetOut(Location::RequiresRegister(),
3033 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3034 : Location::kNoOutputOverlap);
Calin Juravle52c48962014-12-16 17:02:57 +00003035
3036 if (field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong)) {
3037 // Long values can be loaded atomically into an XMM using movsd.
3038 // So we use an XMM register as a temp to achieve atomicity (first load the temp into the XMM
3039 // and then copy the XMM into the output 32bits at a time).
3040 locations->AddTemp(Location::RequiresFpuRegister());
3041 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003042}
3043
Calin Juravle52c48962014-12-16 17:02:57 +00003044void InstructionCodeGeneratorX86::HandleFieldGet(HInstruction* instruction,
3045 const FieldInfo& field_info) {
3046 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003047
Calin Juravle52c48962014-12-16 17:02:57 +00003048 LocationSummary* locations = instruction->GetLocations();
3049 Register base = locations->InAt(0).AsRegister<Register>();
3050 Location out = locations->Out();
3051 bool is_volatile = field_info.IsVolatile();
3052 Primitive::Type field_type = field_info.GetFieldType();
3053 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3054
3055 switch (field_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003056 case Primitive::kPrimBoolean: {
Calin Juravle52c48962014-12-16 17:02:57 +00003057 __ movzxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003058 break;
3059 }
3060
3061 case Primitive::kPrimByte: {
Calin Juravle52c48962014-12-16 17:02:57 +00003062 __ movsxb(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003063 break;
3064 }
3065
3066 case Primitive::kPrimShort: {
Calin Juravle52c48962014-12-16 17:02:57 +00003067 __ movsxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003068 break;
3069 }
3070
3071 case Primitive::kPrimChar: {
Calin Juravle52c48962014-12-16 17:02:57 +00003072 __ movzxw(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003073 break;
3074 }
3075
3076 case Primitive::kPrimInt:
3077 case Primitive::kPrimNot: {
Calin Juravle52c48962014-12-16 17:02:57 +00003078 __ movl(out.AsRegister<Register>(), Address(base, offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003079 break;
3080 }
3081
3082 case Primitive::kPrimLong: {
Calin Juravle52c48962014-12-16 17:02:57 +00003083 if (is_volatile) {
3084 XmmRegister temp = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3085 __ movsd(temp, Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003086 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003087 __ movd(out.AsRegisterPairLow<Register>(), temp);
3088 __ psrlq(temp, Immediate(32));
3089 __ movd(out.AsRegisterPairHigh<Register>(), temp);
3090 } else {
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003091 DCHECK_NE(base, out.AsRegisterPairLow<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003092 __ movl(out.AsRegisterPairLow<Register>(), Address(base, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003093 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003094 __ movl(out.AsRegisterPairHigh<Register>(), Address(base, kX86WordSize + offset));
3095 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003096 break;
3097 }
3098
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003099 case Primitive::kPrimFloat: {
Calin Juravle52c48962014-12-16 17:02:57 +00003100 __ movss(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003101 break;
3102 }
3103
3104 case Primitive::kPrimDouble: {
Calin Juravle52c48962014-12-16 17:02:57 +00003105 __ movsd(out.AsFpuRegister<XmmRegister>(), Address(base, offset));
Nicolas Geoffray52e832b2014-11-06 15:15:31 +00003106 break;
3107 }
3108
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003109 case Primitive::kPrimVoid:
Calin Juravle52c48962014-12-16 17:02:57 +00003110 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003111 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003112 }
Calin Juravle52c48962014-12-16 17:02:57 +00003113
Calin Juravle77520bc2015-01-12 18:45:46 +00003114 // Longs are handled in the switch.
3115 if (field_type != Primitive::kPrimLong) {
3116 codegen_->MaybeRecordImplicitNullCheck(instruction);
3117 }
3118
Calin Juravle52c48962014-12-16 17:02:57 +00003119 if (is_volatile) {
3120 GenerateMemoryBarrier(MemBarrierKind::kLoadAny);
3121 }
3122}
3123
3124void LocationsBuilderX86::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) {
3125 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3126
3127 LocationSummary* locations =
3128 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
3129 locations->SetInAt(0, Location::RequiresRegister());
3130 bool is_volatile = field_info.IsVolatile();
3131 Primitive::Type field_type = field_info.GetFieldType();
3132 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
3133 || (field_type == Primitive::kPrimByte);
3134
3135 // The register allocator does not support multiple
3136 // inputs that die at entry with one in a specific register.
3137 if (is_byte_type) {
3138 // Ensure the value is in a byte register.
3139 locations->SetInAt(1, Location::RegisterLocation(EAX));
3140 } else {
3141 locations->SetInAt(1, Location::RequiresRegister());
3142 }
3143 // Temporary registers for the write barrier.
3144 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3145 locations->AddTemp(Location::RequiresRegister());
3146 // Ensure the card is in a byte register.
3147 locations->AddTemp(Location::RegisterLocation(ECX));
3148 } else if (is_volatile && (field_type == Primitive::kPrimLong)) {
3149 // 64bits value can be atomically written to an address with movsd and an XMM register.
3150 // We need two XMM registers because there's no easier way to (bit) copy a register pair
3151 // into a single XMM register (we copy each pair part into the XMMs and then interleave them).
3152 // NB: We could make the register allocator understand fp_reg <-> core_reg moves but given the
3153 // isolated cases when we need this it isn't worth adding the extra complexity.
3154 locations->AddTemp(Location::RequiresFpuRegister());
3155 locations->AddTemp(Location::RequiresFpuRegister());
3156 }
3157}
3158
3159void InstructionCodeGeneratorX86::HandleFieldSet(HInstruction* instruction,
3160 const FieldInfo& field_info) {
3161 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet());
3162
3163 LocationSummary* locations = instruction->GetLocations();
3164 Register base = locations->InAt(0).AsRegister<Register>();
3165 Location value = locations->InAt(1);
3166 bool is_volatile = field_info.IsVolatile();
3167 Primitive::Type field_type = field_info.GetFieldType();
3168 uint32_t offset = field_info.GetFieldOffset().Uint32Value();
3169
3170 if (is_volatile) {
3171 GenerateMemoryBarrier(MemBarrierKind::kAnyStore);
3172 }
3173
3174 switch (field_type) {
3175 case Primitive::kPrimBoolean:
3176 case Primitive::kPrimByte: {
3177 __ movb(Address(base, offset), value.AsRegister<ByteRegister>());
3178 break;
3179 }
3180
3181 case Primitive::kPrimShort:
3182 case Primitive::kPrimChar: {
3183 __ movw(Address(base, offset), value.AsRegister<Register>());
3184 break;
3185 }
3186
3187 case Primitive::kPrimInt:
3188 case Primitive::kPrimNot: {
3189 __ movl(Address(base, offset), value.AsRegister<Register>());
Calin Juravle52c48962014-12-16 17:02:57 +00003190 break;
3191 }
3192
3193 case Primitive::kPrimLong: {
3194 if (is_volatile) {
3195 XmmRegister temp1 = locations->GetTemp(0).AsFpuRegister<XmmRegister>();
3196 XmmRegister temp2 = locations->GetTemp(1).AsFpuRegister<XmmRegister>();
3197 __ movd(temp1, value.AsRegisterPairLow<Register>());
3198 __ movd(temp2, value.AsRegisterPairHigh<Register>());
3199 __ punpckldq(temp1, temp2);
3200 __ movsd(Address(base, offset), temp1);
Calin Juravle77520bc2015-01-12 18:45:46 +00003201 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003202 } else {
3203 __ movl(Address(base, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003204 codegen_->MaybeRecordImplicitNullCheck(instruction);
Calin Juravle52c48962014-12-16 17:02:57 +00003205 __ movl(Address(base, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
3206 }
3207 break;
3208 }
3209
3210 case Primitive::kPrimFloat: {
3211 __ movss(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3212 break;
3213 }
3214
3215 case Primitive::kPrimDouble: {
3216 __ movsd(Address(base, offset), value.AsFpuRegister<XmmRegister>());
3217 break;
3218 }
3219
3220 case Primitive::kPrimVoid:
3221 LOG(FATAL) << "Unreachable type " << field_type;
3222 UNREACHABLE();
3223 }
3224
Calin Juravle77520bc2015-01-12 18:45:46 +00003225 // Longs are handled in the switch.
3226 if (field_type != Primitive::kPrimLong) {
3227 codegen_->MaybeRecordImplicitNullCheck(instruction);
3228 }
3229
3230 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) {
3231 Register temp = locations->GetTemp(0).AsRegister<Register>();
3232 Register card = locations->GetTemp(1).AsRegister<Register>();
3233 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>());
3234 }
3235
Calin Juravle52c48962014-12-16 17:02:57 +00003236 if (is_volatile) {
3237 GenerateMemoryBarrier(MemBarrierKind::kAnyAny);
3238 }
3239}
3240
3241void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3242 HandleFieldGet(instruction, instruction->GetFieldInfo());
3243}
3244
3245void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
3246 HandleFieldGet(instruction, instruction->GetFieldInfo());
3247}
3248
3249void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3250 HandleFieldSet(instruction, instruction->GetFieldInfo());
3251}
3252
3253void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
3254 HandleFieldSet(instruction, instruction->GetFieldInfo());
3255}
3256
3257void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3258 HandleFieldSet(instruction, instruction->GetFieldInfo());
3259}
3260
3261void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
3262 HandleFieldSet(instruction, instruction->GetFieldInfo());
3263}
3264
3265void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3266 HandleFieldGet(instruction, instruction->GetFieldInfo());
3267}
3268
3269void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
3270 HandleFieldGet(instruction, instruction->GetFieldInfo());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003271}
3272
3273void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003274 LocationSummary* locations =
3275 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003276 Location loc = codegen_->GetCompilerOptions().GetImplicitNullChecks()
3277 ? Location::RequiresRegister()
3278 : Location::Any();
3279 locations->SetInAt(0, loc);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003280 if (instruction->HasUses()) {
3281 locations->SetOut(Location::SameAsFirstInput());
3282 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003283}
3284
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003285void InstructionCodeGeneratorX86::GenerateImplicitNullCheck(HNullCheck* instruction) {
Calin Juravle77520bc2015-01-12 18:45:46 +00003286 if (codegen_->CanMoveNullCheckToUser(instruction)) {
3287 return;
3288 }
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003289 LocationSummary* locations = instruction->GetLocations();
3290 Location obj = locations->InAt(0);
Calin Juravle77520bc2015-01-12 18:45:46 +00003291
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003292 __ testl(EAX, Address(obj.AsRegister<Register>(), 0));
3293 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
3294}
3295
3296void InstructionCodeGeneratorX86::GenerateExplicitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01003297 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003298 codegen_->AddSlowPath(slow_path);
3299
3300 LocationSummary* locations = instruction->GetLocations();
3301 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003302
3303 if (obj.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003304 __ cmpl(obj.AsRegister<Register>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003305 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003306 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003307 } else {
3308 DCHECK(obj.IsConstant()) << obj;
3309 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
3310 __ jmp(slow_path->GetEntryLabel());
3311 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003312 }
3313 __ j(kEqual, slow_path->GetEntryLabel());
3314}
3315
Calin Juravlecd6dffe2015-01-08 17:35:35 +00003316void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
3317 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
3318 GenerateImplicitNullCheck(instruction);
3319 } else {
3320 GenerateExplicitNullCheck(instruction);
3321 }
3322}
3323
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003324void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003325 LocationSummary* locations =
3326 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003327 locations->SetInAt(0, Location::RequiresRegister());
3328 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003329 // The output overlaps in case of long: we don't want the low move to overwrite
3330 // the array's location.
3331 locations->SetOut(Location::RequiresRegister(),
3332 (instruction->GetType() == Primitive::kPrimLong) ? Location::kOutputOverlap
3333 : Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003334}
3335
3336void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
3337 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003338 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003339 Location index = locations->InAt(1);
3340
Calin Juravle77520bc2015-01-12 18:45:46 +00003341 Primitive::Type type = instruction->GetType();
3342 switch (type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003343 case Primitive::kPrimBoolean: {
3344 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003345 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003346 if (index.IsConstant()) {
3347 __ movzxb(out, Address(obj,
3348 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3349 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003350 __ movzxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003351 }
3352 break;
3353 }
3354
3355 case Primitive::kPrimByte: {
3356 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003357 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003358 if (index.IsConstant()) {
3359 __ movsxb(out, Address(obj,
3360 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
3361 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003362 __ movsxb(out, Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003363 }
3364 break;
3365 }
3366
3367 case Primitive::kPrimShort: {
3368 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003369 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003370 if (index.IsConstant()) {
3371 __ movsxw(out, Address(obj,
3372 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3373 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003374 __ movsxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003375 }
3376 break;
3377 }
3378
3379 case Primitive::kPrimChar: {
3380 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003381 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003382 if (index.IsConstant()) {
3383 __ movzxw(out, Address(obj,
3384 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
3385 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003386 __ movzxw(out, Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003387 }
3388 break;
3389 }
3390
3391 case Primitive::kPrimInt:
3392 case Primitive::kPrimNot: {
3393 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003394 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003395 if (index.IsConstant()) {
3396 __ movl(out, Address(obj,
3397 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3398 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003399 __ movl(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003400 }
3401 break;
3402 }
3403
3404 case Primitive::kPrimLong: {
3405 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003406 Location out = locations->Out();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003407 DCHECK_NE(obj, out.AsRegisterPairLow<Register>());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003408 if (index.IsConstant()) {
3409 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003410 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003411 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003412 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003413 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003414 __ movl(out.AsRegisterPairLow<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003415 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003416 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003417 __ movl(out.AsRegisterPairHigh<Register>(),
Roland Levillain271ab9c2014-11-27 15:23:57 +00003418 Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003419 }
3420 break;
3421 }
3422
Mark Mendell7c8d0092015-01-26 11:21:33 -05003423 case Primitive::kPrimFloat: {
3424 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3425 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3426 if (index.IsConstant()) {
3427 __ movss(out, Address(obj,
3428 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
3429 } else {
3430 __ movss(out, Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset));
3431 }
3432 break;
3433 }
3434
3435 case Primitive::kPrimDouble: {
3436 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3437 XmmRegister out = locations->Out().AsFpuRegister<XmmRegister>();
3438 if (index.IsConstant()) {
3439 __ movsd(out, Address(obj,
3440 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
3441 } else {
3442 __ movsd(out, Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset));
3443 }
3444 break;
3445 }
3446
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003447 case Primitive::kPrimVoid:
Calin Juravle77520bc2015-01-12 18:45:46 +00003448 LOG(FATAL) << "Unreachable type " << type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07003449 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003450 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003451
3452 if (type != Primitive::kPrimLong) {
3453 codegen_->MaybeRecordImplicitNullCheck(instruction);
3454 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003455}
3456
3457void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Mark Mendell5f874182015-03-04 15:42:45 -05003458 // This location builder might end up asking to up to four registers, which is
3459 // not currently possible for baseline. The situation in which we need four
3460 // registers cannot be met by baseline though, because it has not run any
3461 // optimization.
3462
Nicolas Geoffray39468442014-09-02 15:17:15 +01003463 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003464 bool needs_write_barrier =
3465 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
3466
Mark Mendell5f874182015-03-04 15:42:45 -05003467 bool needs_runtime_call = instruction->NeedsTypeCheck();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003468
Nicolas Geoffray39468442014-09-02 15:17:15 +01003469 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
3470 instruction,
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003471 needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003472
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003473 if (needs_runtime_call) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003474 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003475 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
3476 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
3477 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003478 } else {
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003479 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
3480 || (value_type == Primitive::kPrimByte);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01003481 // We need the inputs to be different than the output in case of long operation.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003482 // In case of a byte operation, the register allocator does not support multiple
3483 // inputs that die at entry with one in a specific register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003484 locations->SetInAt(0, Location::RequiresRegister());
3485 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01003486 if (is_byte_type) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003487 // Ensure the value is in a byte register.
3488 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003489 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003490 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003491 }
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003492 // Temporary registers for the write barrier.
3493 if (needs_write_barrier) {
3494 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003495 // Ensure the card is in a byte register.
3496 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003497 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003498 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003499}
3500
3501void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
3502 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003503 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003504 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003505 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01003506 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003507 bool needs_runtime_call = locations->WillCall();
3508 bool needs_write_barrier =
3509 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003510
3511 switch (value_type) {
3512 case Primitive::kPrimBoolean:
3513 case Primitive::kPrimByte: {
3514 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003515 if (index.IsConstant()) {
3516 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003517 if (value.IsRegister()) {
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003518 __ movb(Address(obj, offset), value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003519 } else {
3520 __ movb(Address(obj, offset),
3521 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3522 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003523 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003524 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003525 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray5b4b8982014-12-18 17:45:56 +00003526 value.AsRegister<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003527 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003528 __ movb(Address(obj, index.AsRegister<Register>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003529 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3530 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003531 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003532 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003533 break;
3534 }
3535
3536 case Primitive::kPrimShort:
3537 case Primitive::kPrimChar: {
3538 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003539 if (index.IsConstant()) {
3540 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003541 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003542 __ movw(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003543 } else {
3544 __ movw(Address(obj, offset),
3545 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3546 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003547 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003548 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003549 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
3550 value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003551 } else {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003552 __ movw(Address(obj, index.AsRegister<Register>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003553 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3554 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003555 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003556 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003557 break;
3558 }
3559
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003560 case Primitive::kPrimInt:
3561 case Primitive::kPrimNot: {
3562 if (!needs_runtime_call) {
3563 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
3564 if (index.IsConstant()) {
Roland Levillain199f3362014-11-27 17:15:16 +00003565 size_t offset =
3566 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003567 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003568 __ movl(Address(obj, offset), value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003569 } else {
3570 DCHECK(value.IsConstant()) << value;
3571 __ movl(Address(obj, offset),
3572 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3573 }
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003574 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003575 DCHECK(index.IsRegister()) << index;
3576 if (value.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003577 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3578 value.AsRegister<Register>());
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003579 } else {
3580 DCHECK(value.IsConstant()) << value;
Roland Levillain271ab9c2014-11-27 15:23:57 +00003581 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003582 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
3583 }
3584 }
Calin Juravle77520bc2015-01-12 18:45:46 +00003585 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003586
3587 if (needs_write_barrier) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003588 Register temp = locations->GetTemp(0).AsRegister<Register>();
3589 Register card = locations->GetTemp(1).AsRegister<Register>();
3590 codegen_->MarkGCCard(temp, card, obj, value.AsRegister<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003591 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003592 } else {
Nicolas Geoffrayaf07bc12014-11-12 18:08:09 +00003593 DCHECK_EQ(value_type, Primitive::kPrimNot);
3594 DCHECK(!codegen_->IsLeafMethod());
3595 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
3596 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003597 }
3598 break;
3599 }
3600
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003601 case Primitive::kPrimLong: {
3602 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003603 if (index.IsConstant()) {
3604 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003605 if (value.IsRegisterPair()) {
3606 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003607 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003608 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003609 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003610 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003611 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
3612 __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003613 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003614 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
3615 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003616 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003617 if (value.IsRegisterPair()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003618 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003619 value.AsRegisterPairLow<Register>());
Calin Juravle77520bc2015-01-12 18:45:46 +00003620 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003621 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003622 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003623 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01003624 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003625 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003626 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003627 Immediate(Low32Bits(val)));
Calin Juravle77520bc2015-01-12 18:45:46 +00003628 codegen_->MaybeRecordImplicitNullCheck(instruction);
Roland Levillain271ab9c2014-11-27 15:23:57 +00003629 __ movl(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003630 Immediate(High32Bits(val)));
3631 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003632 }
3633 break;
3634 }
3635
Mark Mendell7c8d0092015-01-26 11:21:33 -05003636 case Primitive::kPrimFloat: {
3637 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value();
3638 DCHECK(value.IsFpuRegister());
3639 if (index.IsConstant()) {
3640 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
3641 __ movss(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3642 } else {
3643 __ movss(Address(obj, index.AsRegister<Register>(), TIMES_4, data_offset),
3644 value.AsFpuRegister<XmmRegister>());
3645 }
3646 break;
3647 }
3648
3649 case Primitive::kPrimDouble: {
3650 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value();
3651 DCHECK(value.IsFpuRegister());
3652 if (index.IsConstant()) {
3653 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
3654 __ movsd(Address(obj, offset), value.AsFpuRegister<XmmRegister>());
3655 } else {
3656 __ movsd(Address(obj, index.AsRegister<Register>(), TIMES_8, data_offset),
3657 value.AsFpuRegister<XmmRegister>());
3658 }
3659 break;
3660 }
3661
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003662 case Primitive::kPrimVoid:
3663 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07003664 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003665 }
3666}
3667
3668void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
3669 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01003670 locations->SetInAt(0, Location::RequiresRegister());
3671 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003672 instruction->SetLocations(locations);
3673}
3674
3675void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
3676 LocationSummary* locations = instruction->GetLocations();
3677 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Roland Levillain271ab9c2014-11-27 15:23:57 +00003678 Register obj = locations->InAt(0).AsRegister<Register>();
3679 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003680 __ movl(out, Address(obj, offset));
Calin Juravle77520bc2015-01-12 18:45:46 +00003681 codegen_->MaybeRecordImplicitNullCheck(instruction);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003682}
3683
3684void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01003685 LocationSummary* locations =
3686 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Mark Mendellf60c90b2015-03-04 15:12:59 -05003687 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003688 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01003689 if (instruction->HasUses()) {
3690 locations->SetOut(Location::SameAsFirstInput());
3691 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003692}
3693
3694void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
3695 LocationSummary* locations = instruction->GetLocations();
Mark Mendellf60c90b2015-03-04 15:12:59 -05003696 Location index_loc = locations->InAt(0);
3697 Location length_loc = locations->InAt(1);
3698 SlowPathCodeX86* slow_path =
3699 new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(instruction, index_loc, length_loc);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003700 codegen_->AddSlowPath(slow_path);
3701
Mark Mendellf60c90b2015-03-04 15:12:59 -05003702 Register length = length_loc.AsRegister<Register>();
3703 if (index_loc.IsConstant()) {
3704 int32_t value = CodeGenerator::GetInt32ValueOf(index_loc.GetConstant());
3705 __ cmpl(length, Immediate(value));
3706 } else {
3707 __ cmpl(length, index_loc.AsRegister<Register>());
3708 }
3709 __ j(kBelowEqual, slow_path->GetEntryLabel());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01003710}
3711
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003712void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
3713 temp->SetLocations(nullptr);
3714}
3715
3716void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
3717 // Nothing to do, this is driven by the code generator.
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003718 UNUSED(temp);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01003719}
3720
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003721void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Ian Rogers6a3c1fc2014-10-31 00:33:20 -07003722 UNUSED(instruction);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003723 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01003724}
3725
3726void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003727 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
3728}
3729
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003730void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
3731 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
3732}
3733
3734void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003735 HBasicBlock* block = instruction->GetBlock();
3736 if (block->GetLoopInformation() != nullptr) {
3737 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
3738 // The back edge will generate the suspend check.
3739 return;
3740 }
3741 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
3742 // The goto will generate the suspend check.
3743 return;
3744 }
3745 GenerateSuspendCheck(instruction, nullptr);
3746}
3747
3748void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
3749 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003750 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003751 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003752 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003753 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003754 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01003755 if (successor == nullptr) {
3756 __ j(kNotEqual, slow_path->GetEntryLabel());
3757 __ Bind(slow_path->GetReturnLabel());
3758 } else {
3759 __ j(kEqual, codegen_->GetLabelOf(successor));
3760 __ jmp(slow_path->GetEntryLabel());
3761 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00003762}
3763
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003764X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
3765 return codegen_->GetAssembler();
3766}
3767
Mark Mendell7c8d0092015-01-26 11:21:33 -05003768void ParallelMoveResolverX86::MoveMemoryToMemory32(int dst, int src) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003769 ScratchRegisterScope ensure_scratch(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003770 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003771 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003772 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
Mark Mendell7c8d0092015-01-26 11:21:33 -05003773 __ movl(temp_reg, Address(ESP, src + stack_offset));
3774 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3775}
3776
3777void ParallelMoveResolverX86::MoveMemoryToMemory64(int dst, int src) {
3778 ScratchRegisterScope ensure_scratch(
3779 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3780 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3781 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3782 __ movl(temp_reg, Address(ESP, src + stack_offset));
3783 __ movl(Address(ESP, dst + stack_offset), temp_reg);
3784 __ movl(temp_reg, Address(ESP, src + stack_offset + kX86WordSize));
3785 __ movl(Address(ESP, dst + stack_offset + kX86WordSize), temp_reg);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003786}
3787
3788void ParallelMoveResolverX86::EmitMove(size_t index) {
3789 MoveOperands* move = moves_.Get(index);
3790 Location source = move->GetSource();
3791 Location destination = move->GetDestination();
3792
3793 if (source.IsRegister()) {
3794 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003795 __ movl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003796 } else {
3797 DCHECK(destination.IsStackSlot());
Roland Levillain271ab9c2014-11-27 15:23:57 +00003798 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003799 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003800 } else if (source.IsFpuRegister()) {
3801 if (destination.IsFpuRegister()) {
3802 __ movaps(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3803 } else if (destination.IsStackSlot()) {
3804 __ movss(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3805 } else {
3806 DCHECK(destination.IsDoubleStackSlot());
3807 __ movsd(Address(ESP, destination.GetStackIndex()), source.AsFpuRegister<XmmRegister>());
3808 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003809 } else if (source.IsStackSlot()) {
3810 if (destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003811 __ movl(destination.AsRegister<Register>(), Address(ESP, source.GetStackIndex()));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003812 } else if (destination.IsFpuRegister()) {
3813 __ movss(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003814 } else {
3815 DCHECK(destination.IsStackSlot());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003816 MoveMemoryToMemory32(destination.GetStackIndex(), source.GetStackIndex());
3817 }
3818 } else if (source.IsDoubleStackSlot()) {
3819 if (destination.IsFpuRegister()) {
3820 __ movsd(destination.AsFpuRegister<XmmRegister>(), Address(ESP, source.GetStackIndex()));
3821 } else {
3822 DCHECK(destination.IsDoubleStackSlot()) << destination;
3823 MoveMemoryToMemory64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003824 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003825 } else if (source.IsConstant()) {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003826 HConstant* constant = source.GetConstant();
Nicolas Geoffrayd6138ef2015-02-18 14:48:53 +00003827 if (constant->IsIntConstant() || constant->IsNullConstant()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003828 int32_t value = CodeGenerator::GetInt32ValueOf(constant);
Mark Mendell7c8d0092015-01-26 11:21:33 -05003829 if (destination.IsRegister()) {
Mark Mendell09b84632015-02-13 17:48:38 -05003830 if (value == 0) {
3831 __ xorl(destination.AsRegister<Register>(), destination.AsRegister<Register>());
3832 } else {
3833 __ movl(destination.AsRegister<Register>(), Immediate(value));
3834 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003835 } else {
3836 DCHECK(destination.IsStackSlot()) << destination;
Mark Mendell09b84632015-02-13 17:48:38 -05003837 __ movl(Address(ESP, destination.GetStackIndex()), Immediate(value));
Mark Mendell7c8d0092015-01-26 11:21:33 -05003838 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003839 } else if (constant->IsFloatConstant()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003840 float fp_value = constant->AsFloatConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003841 int32_t value = bit_cast<int32_t, float>(fp_value);
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003842 Immediate imm(value);
Mark Mendell7c8d0092015-01-26 11:21:33 -05003843 if (destination.IsFpuRegister()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04003844 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3845 if (value == 0) {
3846 // Easy handling of 0.0.
3847 __ xorps(dest, dest);
3848 } else {
3849 ScratchRegisterScope ensure_scratch(
3850 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3851 Register temp = static_cast<Register>(ensure_scratch.GetRegister());
3852 __ movl(temp, Immediate(value));
3853 __ movd(dest, temp);
3854 }
Mark Mendell7c8d0092015-01-26 11:21:33 -05003855 } else {
3856 DCHECK(destination.IsStackSlot()) << destination;
3857 __ movl(Address(ESP, destination.GetStackIndex()), imm);
3858 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003859 } else if (constant->IsLongConstant()) {
3860 int64_t value = constant->AsLongConstant()->GetValue();
3861 int32_t low_value = Low32Bits(value);
3862 int32_t high_value = High32Bits(value);
3863 Immediate low(low_value);
3864 Immediate high(high_value);
3865 if (destination.IsDoubleStackSlot()) {
3866 __ movl(Address(ESP, destination.GetStackIndex()), low);
3867 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
3868 } else {
3869 __ movl(destination.AsRegisterPairLow<Register>(), low);
3870 __ movl(destination.AsRegisterPairHigh<Register>(), high);
3871 }
3872 } else {
3873 DCHECK(constant->IsDoubleConstant());
3874 double dbl_value = constant->AsDoubleConstant()->GetValue();
Roland Levillainda4d79b2015-03-24 14:36:11 +00003875 int64_t value = bit_cast<int64_t, double>(dbl_value);
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003876 int32_t low_value = Low32Bits(value);
3877 int32_t high_value = High32Bits(value);
3878 Immediate low(low_value);
3879 Immediate high(high_value);
3880 if (destination.IsFpuRegister()) {
3881 XmmRegister dest = destination.AsFpuRegister<XmmRegister>();
3882 if (value == 0) {
3883 // Easy handling of 0.0.
3884 __ xorpd(dest, dest);
3885 } else {
3886 __ pushl(high);
3887 __ pushl(low);
3888 __ movsd(dest, Address(ESP, 0));
3889 __ addl(ESP, Immediate(8));
3890 }
3891 } else {
3892 DCHECK(destination.IsDoubleStackSlot()) << destination;
3893 __ movl(Address(ESP, destination.GetStackIndex()), low);
3894 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), high);
3895 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01003896 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003897 } else {
Nicolas Geoffray42d1f5f2015-01-16 09:14:18 +00003898 LOG(FATAL) << "Unimplemented move: " << destination << " <- " << source;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003899 }
3900}
3901
3902void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003903 Register suggested_scratch = reg == EAX ? EBX : EAX;
3904 ScratchRegisterScope ensure_scratch(
3905 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3906
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003907 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3908 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
3909 __ movl(Address(ESP, mem + stack_offset), reg);
3910 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
3911}
3912
Mark Mendell7c8d0092015-01-26 11:21:33 -05003913void ParallelMoveResolverX86::Exchange32(XmmRegister reg, int mem) {
3914 ScratchRegisterScope ensure_scratch(
3915 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3916
3917 Register temp_reg = static_cast<Register>(ensure_scratch.GetRegister());
3918 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
3919 __ movl(temp_reg, Address(ESP, mem + stack_offset));
3920 __ movss(Address(ESP, mem + stack_offset), reg);
3921 __ movd(reg, temp_reg);
3922}
3923
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003924void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
3925 ScratchRegisterScope ensure_scratch1(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003926 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
3927
3928 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003929 ScratchRegisterScope ensure_scratch2(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01003930 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
3931
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003932 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
3933 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
3934 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
3935 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
3936 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
3937 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
3938}
3939
3940void ParallelMoveResolverX86::EmitSwap(size_t index) {
3941 MoveOperands* move = moves_.Get(index);
3942 Location source = move->GetSource();
3943 Location destination = move->GetDestination();
3944
3945 if (source.IsRegister() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003946 __ xchgl(destination.AsRegister<Register>(), source.AsRegister<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003947 } else if (source.IsRegister() && destination.IsStackSlot()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003948 Exchange(source.AsRegister<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003949 } else if (source.IsStackSlot() && destination.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00003950 Exchange(destination.AsRegister<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003951 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
3952 Exchange(destination.GetStackIndex(), source.GetStackIndex());
Mark Mendell7c8d0092015-01-26 11:21:33 -05003953 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) {
3954 // Use XOR Swap algorithm to avoid a temporary.
3955 DCHECK_NE(source.reg(), destination.reg());
3956 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3957 __ xorpd(source.AsFpuRegister<XmmRegister>(), destination.AsFpuRegister<XmmRegister>());
3958 __ xorpd(destination.AsFpuRegister<XmmRegister>(), source.AsFpuRegister<XmmRegister>());
3959 } else if (source.IsFpuRegister() && destination.IsStackSlot()) {
3960 Exchange32(source.AsFpuRegister<XmmRegister>(), destination.GetStackIndex());
3961 } else if (destination.IsFpuRegister() && source.IsStackSlot()) {
3962 Exchange32(destination.AsFpuRegister<XmmRegister>(), source.GetStackIndex());
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00003963 } else if (source.IsFpuRegister() && destination.IsDoubleStackSlot()) {
3964 // Take advantage of the 16 bytes in the XMM register.
3965 XmmRegister reg = source.AsFpuRegister<XmmRegister>();
3966 Address stack(ESP, destination.GetStackIndex());
3967 // Load the double into the high doubleword.
3968 __ movhpd(reg, stack);
3969
3970 // Store the low double into the destination.
3971 __ movsd(stack, reg);
3972
3973 // Move the high double to the low double.
3974 __ psrldq(reg, Immediate(8));
3975 } else if (destination.IsFpuRegister() && source.IsDoubleStackSlot()) {
3976 // Take advantage of the 16 bytes in the XMM register.
3977 XmmRegister reg = destination.AsFpuRegister<XmmRegister>();
3978 Address stack(ESP, source.GetStackIndex());
3979 // Load the double into the high doubleword.
3980 __ movhpd(reg, stack);
3981
3982 // Store the low double into the destination.
3983 __ movsd(stack, reg);
3984
3985 // Move the high double to the low double.
3986 __ psrldq(reg, Immediate(8));
3987 } else if (destination.IsDoubleStackSlot() && source.IsDoubleStackSlot()) {
3988 Exchange(destination.GetStackIndex(), source.GetStackIndex());
3989 Exchange(destination.GetHighStackIndex(kX86WordSize), source.GetHighStackIndex(kX86WordSize));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003990 } else {
Mark Mendell7c8d0092015-01-26 11:21:33 -05003991 LOG(FATAL) << "Unimplemented: source: " << source << ", destination: " << destination;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01003992 }
3993}
3994
3995void ParallelMoveResolverX86::SpillScratch(int reg) {
3996 __ pushl(static_cast<Register>(reg));
3997}
3998
3999void ParallelMoveResolverX86::RestoreScratch(int reg) {
4000 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01004001}
4002
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004003void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004004 LocationSummary::CallKind call_kind = cls->CanCallRuntime()
4005 ? LocationSummary::kCallOnSlowPath
4006 : LocationSummary::kNoCall;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004007 LocationSummary* locations =
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004008 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004009 locations->SetOut(Location::RequiresRegister());
4010}
4011
4012void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004013 Register out = cls->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004014 if (cls->IsReferrersClass()) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004015 DCHECK(!cls->CanCallRuntime());
4016 DCHECK(!cls->MustGenerateClinitCheck());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004017 codegen_->LoadCurrentMethod(out);
4018 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
4019 } else {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004020 DCHECK(cls->CanCallRuntime());
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004021 codegen_->LoadCurrentMethod(out);
4022 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
4023 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004024
4025 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
4026 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
4027 codegen_->AddSlowPath(slow_path);
4028 __ testl(out, out);
4029 __ j(kEqual, slow_path->GetEntryLabel());
4030 if (cls->MustGenerateClinitCheck()) {
4031 GenerateClassInitializationCheck(slow_path, out);
4032 } else {
4033 __ Bind(slow_path->GetExitLabel());
4034 }
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004035 }
4036}
4037
4038void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
4039 LocationSummary* locations =
4040 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
4041 locations->SetInAt(0, Location::RequiresRegister());
4042 if (check->HasUses()) {
4043 locations->SetOut(Location::SameAsFirstInput());
4044 }
4045}
4046
4047void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004048 // We assume the class to not be null.
4049 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86(
4050 check->GetLoadClass(), check, check->GetDexPc(), true);
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004051 codegen_->AddSlowPath(slow_path);
Roland Levillain199f3362014-11-27 17:15:16 +00004052 GenerateClassInitializationCheck(slow_path,
4053 check->GetLocations()->InAt(0).AsRegister<Register>());
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004054}
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004055
Nicolas Geoffray424f6762014-11-03 14:51:25 +00004056void InstructionCodeGeneratorX86::GenerateClassInitializationCheck(
4057 SlowPathCodeX86* slow_path, Register class_reg) {
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01004058 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
4059 Immediate(mirror::Class::kStatusInitialized));
4060 __ j(kLess, slow_path->GetEntryLabel());
4061 __ Bind(slow_path->GetExitLabel());
4062 // No need for memory fence, thanks to the X86 memory model.
4063}
4064
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004065void LocationsBuilderX86::VisitLoadString(HLoadString* load) {
4066 LocationSummary* locations =
4067 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
4068 locations->SetOut(Location::RequiresRegister());
4069}
4070
4071void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) {
4072 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86(load);
4073 codegen_->AddSlowPath(slow_path);
4074
Roland Levillain271ab9c2014-11-27 15:23:57 +00004075 Register out = load->GetLocations()->Out().AsRegister<Register>();
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004076 codegen_->LoadCurrentMethod(out);
Mathieu Chartiereace4582014-11-24 18:29:54 -08004077 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
4078 __ movl(out, Address(out, mirror::Class::DexCacheStringsOffset().Int32Value()));
Nicolas Geoffrayb5f62b32014-10-30 10:58:41 +00004079 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(load->GetStringIndex())));
4080 __ testl(out, out);
4081 __ j(kEqual, slow_path->GetEntryLabel());
4082 __ Bind(slow_path->GetExitLabel());
4083}
4084
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004085void LocationsBuilderX86::VisitLoadException(HLoadException* load) {
4086 LocationSummary* locations =
4087 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall);
4088 locations->SetOut(Location::RequiresRegister());
4089}
4090
4091void InstructionCodeGeneratorX86::VisitLoadException(HLoadException* load) {
4092 Address address = Address::Absolute(Thread::ExceptionOffset<kX86WordSize>().Int32Value());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004093 __ fs()->movl(load->GetLocations()->Out().AsRegister<Register>(), address);
Nicolas Geoffrayde58ab22014-11-05 12:46:03 +00004094 __ fs()->movl(address, Immediate(0));
4095}
4096
4097void LocationsBuilderX86::VisitThrow(HThrow* instruction) {
4098 LocationSummary* locations =
4099 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4100 InvokeRuntimeCallingConvention calling_convention;
4101 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4102}
4103
4104void InstructionCodeGeneratorX86::VisitThrow(HThrow* instruction) {
4105 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pDeliverException)));
4106 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4107}
4108
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004109void LocationsBuilderX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004110 LocationSummary::CallKind call_kind = instruction->IsClassFinal()
4111 ? LocationSummary::kNoCall
4112 : LocationSummary::kCallOnSlowPath;
4113 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
4114 locations->SetInAt(0, Location::RequiresRegister());
4115 locations->SetInAt(1, Location::Any());
4116 locations->SetOut(Location::RequiresRegister());
4117}
4118
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004119void InstructionCodeGeneratorX86::VisitInstanceOf(HInstanceOf* instruction) {
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004120 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004121 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004122 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004123 Register out = locations->Out().AsRegister<Register>();
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004124 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4125 Label done, zero;
4126 SlowPathCodeX86* slow_path = nullptr;
4127
4128 // Return 0 if `obj` is null.
4129 // TODO: avoid this check if we know obj is not null.
4130 __ testl(obj, obj);
4131 __ j(kEqual, &zero);
4132 __ movl(out, Address(obj, class_offset));
4133 // Compare the class of `obj` with `cls`.
4134 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004135 __ cmpl(out, cls.AsRegister<Register>());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004136 } else {
4137 DCHECK(cls.IsStackSlot()) << cls;
4138 __ cmpl(out, Address(ESP, cls.GetStackIndex()));
4139 }
4140
4141 if (instruction->IsClassFinal()) {
4142 // Classes must be equal for the instanceof to succeed.
4143 __ j(kNotEqual, &zero);
4144 __ movl(out, Immediate(1));
4145 __ jmp(&done);
4146 } else {
4147 // If the classes are not equal, we go into a slow path.
4148 DCHECK(locations->OnlyCallsOnSlowPath());
4149 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004150 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc());
Nicolas Geoffray6f5c41f2014-11-06 08:59:20 +00004151 codegen_->AddSlowPath(slow_path);
4152 __ j(kNotEqual, slow_path->GetEntryLabel());
4153 __ movl(out, Immediate(1));
4154 __ jmp(&done);
4155 }
4156 __ Bind(&zero);
4157 __ movl(out, Immediate(0));
4158 if (slow_path != nullptr) {
4159 __ Bind(slow_path->GetExitLabel());
4160 }
4161 __ Bind(&done);
4162}
4163
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004164void LocationsBuilderX86::VisitCheckCast(HCheckCast* instruction) {
4165 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
4166 instruction, LocationSummary::kCallOnSlowPath);
4167 locations->SetInAt(0, Location::RequiresRegister());
4168 locations->SetInAt(1, Location::Any());
4169 locations->AddTemp(Location::RequiresRegister());
4170}
4171
4172void InstructionCodeGeneratorX86::VisitCheckCast(HCheckCast* instruction) {
4173 LocationSummary* locations = instruction->GetLocations();
Roland Levillain271ab9c2014-11-27 15:23:57 +00004174 Register obj = locations->InAt(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004175 Location cls = locations->InAt(1);
Roland Levillain271ab9c2014-11-27 15:23:57 +00004176 Register temp = locations->GetTemp(0).AsRegister<Register>();
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004177 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
4178 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathX86(
4179 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc());
4180 codegen_->AddSlowPath(slow_path);
4181
4182 // TODO: avoid this check if we know obj is not null.
4183 __ testl(obj, obj);
4184 __ j(kEqual, slow_path->GetExitLabel());
4185 __ movl(temp, Address(obj, class_offset));
4186
4187 // Compare the class of `obj` with `cls`.
4188 if (cls.IsRegister()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004189 __ cmpl(temp, cls.AsRegister<Register>());
Nicolas Geoffray57a88d42014-11-10 15:09:21 +00004190 } else {
4191 DCHECK(cls.IsStackSlot()) << cls;
4192 __ cmpl(temp, Address(ESP, cls.GetStackIndex()));
4193 }
4194
4195 __ j(kNotEqual, slow_path->GetEntryLabel());
4196 __ Bind(slow_path->GetExitLabel());
4197}
4198
Nicolas Geoffrayb7baf5c2014-11-11 16:29:44 +00004199void LocationsBuilderX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4200 LocationSummary* locations =
4201 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
4202 InvokeRuntimeCallingConvention calling_convention;
4203 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
4204}
4205
4206void InstructionCodeGeneratorX86::VisitMonitorOperation(HMonitorOperation* instruction) {
4207 __ fs()->call(Address::Absolute(instruction->IsEnter()
4208 ? QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pLockObject)
4209 : QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pUnlockObject)));
4210 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
4211}
4212
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004213void LocationsBuilderX86::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); }
4214void LocationsBuilderX86::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); }
4215void LocationsBuilderX86::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); }
4216
4217void LocationsBuilderX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4218 LocationSummary* locations =
4219 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
4220 DCHECK(instruction->GetResultType() == Primitive::kPrimInt
4221 || instruction->GetResultType() == Primitive::kPrimLong);
4222 locations->SetInAt(0, Location::RequiresRegister());
4223 locations->SetInAt(1, Location::Any());
4224 locations->SetOut(Location::SameAsFirstInput());
4225}
4226
4227void InstructionCodeGeneratorX86::VisitAnd(HAnd* instruction) {
4228 HandleBitwiseOperation(instruction);
4229}
4230
4231void InstructionCodeGeneratorX86::VisitOr(HOr* instruction) {
4232 HandleBitwiseOperation(instruction);
4233}
4234
4235void InstructionCodeGeneratorX86::VisitXor(HXor* instruction) {
4236 HandleBitwiseOperation(instruction);
4237}
4238
4239void InstructionCodeGeneratorX86::HandleBitwiseOperation(HBinaryOperation* instruction) {
4240 LocationSummary* locations = instruction->GetLocations();
4241 Location first = locations->InAt(0);
4242 Location second = locations->InAt(1);
4243 DCHECK(first.Equals(locations->Out()));
4244
4245 if (instruction->GetResultType() == Primitive::kPrimInt) {
4246 if (second.IsRegister()) {
4247 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004248 __ andl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004249 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004250 __ orl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004251 } else {
4252 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004253 __ xorl(first.AsRegister<Register>(), second.AsRegister<Register>());
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004254 }
4255 } else if (second.IsConstant()) {
4256 if (instruction->IsAnd()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004257 __ andl(first.AsRegister<Register>(),
4258 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004259 } else if (instruction->IsOr()) {
Roland Levillain199f3362014-11-27 17:15:16 +00004260 __ orl(first.AsRegister<Register>(),
4261 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004262 } else {
4263 DCHECK(instruction->IsXor());
Roland Levillain199f3362014-11-27 17:15:16 +00004264 __ xorl(first.AsRegister<Register>(),
4265 Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004266 }
4267 } else {
4268 if (instruction->IsAnd()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004269 __ andl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004270 } else if (instruction->IsOr()) {
Roland Levillain271ab9c2014-11-27 15:23:57 +00004271 __ orl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004272 } else {
4273 DCHECK(instruction->IsXor());
Roland Levillain271ab9c2014-11-27 15:23:57 +00004274 __ xorl(first.AsRegister<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004275 }
4276 }
4277 } else {
4278 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong);
4279 if (second.IsRegisterPair()) {
4280 if (instruction->IsAnd()) {
4281 __ andl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4282 __ andl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4283 } else if (instruction->IsOr()) {
4284 __ orl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4285 __ orl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4286 } else {
4287 DCHECK(instruction->IsXor());
4288 __ xorl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
4289 __ xorl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
4290 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004291 } else if (second.IsDoubleStackSlot()) {
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004292 if (instruction->IsAnd()) {
4293 __ andl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4294 __ andl(first.AsRegisterPairHigh<Register>(),
4295 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4296 } else if (instruction->IsOr()) {
4297 __ orl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4298 __ orl(first.AsRegisterPairHigh<Register>(),
4299 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4300 } else {
4301 DCHECK(instruction->IsXor());
4302 __ xorl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
4303 __ xorl(first.AsRegisterPairHigh<Register>(),
4304 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
4305 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004306 } else {
4307 DCHECK(second.IsConstant()) << second;
4308 int64_t value = second.GetConstant()->AsLongConstant()->GetValue();
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004309 int32_t low_value = Low32Bits(value);
4310 int32_t high_value = High32Bits(value);
4311 Immediate low(low_value);
4312 Immediate high(high_value);
4313 Register first_low = first.AsRegisterPairLow<Register>();
4314 Register first_high = first.AsRegisterPairHigh<Register>();
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004315 if (instruction->IsAnd()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004316 if (low_value == 0) {
4317 __ xorl(first_low, first_low);
4318 } else if (low_value != -1) {
4319 __ andl(first_low, low);
4320 }
4321 if (high_value == 0) {
4322 __ xorl(first_high, first_high);
4323 } else if (high_value != -1) {
4324 __ andl(first_high, high);
4325 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004326 } else if (instruction->IsOr()) {
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004327 if (low_value != 0) {
4328 __ orl(first_low, low);
4329 }
4330 if (high_value != 0) {
4331 __ orl(first_high, high);
4332 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004333 } else {
4334 DCHECK(instruction->IsXor());
Mark Mendell3f6c7f62015-03-13 13:47:53 -04004335 if (low_value != 0) {
4336 __ xorl(first_low, low);
4337 }
4338 if (high_value != 0) {
4339 __ xorl(first_high, high);
4340 }
Nicolas Geoffray234d69d2015-03-09 10:28:50 +00004341 }
Nicolas Geoffray9574c4b2014-11-12 13:19:37 +00004342 }
4343 }
4344}
4345
Calin Juravleb1498f62015-02-16 13:13:29 +00004346void LocationsBuilderX86::VisitBoundType(HBoundType* instruction) {
4347 // Nothing to do, this should be removed during prepare for register allocator.
4348 UNUSED(instruction);
4349 LOG(FATAL) << "Unreachable";
4350}
4351
4352void InstructionCodeGeneratorX86::VisitBoundType(HBoundType* instruction) {
4353 // Nothing to do, this should be removed during prepare for register allocator.
4354 UNUSED(instruction);
4355 LOG(FATAL) << "Unreachable";
4356}
4357
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00004358} // namespace x86
4359} // namespace art