blob: ab53b17636d2294a592e3bb35b1d1c611c5720ab [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_x86.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010018
19#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010021#include "mirror/array.h"
22#include "mirror/art_method.h"
23#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000024#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010025#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000026#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010027#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000028
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010030
31x86::X86ManagedRegister Location::AsX86() const {
32 return reg().AsX86();
33}
34
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace x86 {
36
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010037static constexpr bool kExplicitStackOverflowCheck = false;
38
39static constexpr int kNumberOfPushedRegistersAtEntry = 1;
40static constexpr int kCurrentMethodStackOffset = 0;
41
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010042static Location X86CpuLocation(Register reg) {
43 return Location::RegisterLocation(X86ManagedRegister::FromCpuRegister(reg));
44}
45
46static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX };
47static constexpr size_t kRuntimeParameterCoreRegistersLength =
48 arraysize(kRuntimeParameterCoreRegisters);
49
50class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
51 public:
52 InvokeRuntimeCallingConvention()
53 : CallingConvention(kRuntimeParameterCoreRegisters,
54 kRuntimeParameterCoreRegistersLength) {}
55
56 private:
57 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
58};
59
Nicolas Geoffraye5038322014-07-04 09:41:32 +010060#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
61
62class NullCheckSlowPathX86 : public SlowPathCode {
63 public:
64 explicit NullCheckSlowPathX86(uint32_t dex_pc) : dex_pc_(dex_pc) {}
65
66 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
67 __ Bind(GetEntryLabel());
68 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
69 codegen->RecordPcInfo(dex_pc_);
70 }
71
72 private:
73 const uint32_t dex_pc_;
74 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
75};
76
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010077class StackOverflowCheckSlowPathX86 : public SlowPathCode {
78 public:
79 StackOverflowCheckSlowPathX86() {}
80
81 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
82 __ Bind(GetEntryLabel());
83 __ addl(ESP,
84 Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
85 __ fs()->jmp(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowStackOverflow)));
86 }
87
88 private:
89 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86);
90};
91
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010092class BoundsCheckSlowPathX86 : public SlowPathCode {
93 public:
94 explicit BoundsCheckSlowPathX86(uint32_t dex_pc,
95 Location index_location,
96 Location length_location)
97 : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
98
99 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
100 CodeGeneratorX86* x86_codegen = reinterpret_cast<CodeGeneratorX86*>(codegen);
101 __ Bind(GetEntryLabel());
102 InvokeRuntimeCallingConvention calling_convention;
103 x86_codegen->Move32(X86CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
104 x86_codegen->Move32(X86CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
105 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
106 codegen->RecordPcInfo(dex_pc_);
107 }
108
109 private:
110 const uint32_t dex_pc_;
111 const Location index_location_;
112 const Location length_location_;
113
114 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
115};
116
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100117#undef __
118#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
119
Dave Allison20dfc792014-06-16 20:44:29 -0700120inline Condition X86Condition(IfCondition cond) {
121 switch (cond) {
122 case kCondEQ: return kEqual;
123 case kCondNE: return kNotEqual;
124 case kCondLT: return kLess;
125 case kCondLE: return kLessEqual;
126 case kCondGT: return kGreater;
127 case kCondGE: return kGreaterEqual;
128 default:
129 LOG(FATAL) << "Unknown if condition";
130 }
131 return kEqual;
132}
133
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100134void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
135 stream << X86ManagedRegister::FromCpuRegister(Register(reg));
136}
137
138void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
139 stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
140}
141
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100142CodeGeneratorX86::CodeGeneratorX86(HGraph* graph)
143 : CodeGenerator(graph, kNumberOfRegIds),
144 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100145 instruction_visitor_(graph, this),
146 move_resolver_(graph->GetArena(), this) {}
147
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100148size_t CodeGeneratorX86::FrameEntrySpillSize() const {
149 return kNumberOfPushedRegistersAtEntry * kX86WordSize;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100150}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100151
152static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
153 return blocked_registers + kNumberOfAllocIds;
154}
155
156ManagedRegister CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type,
157 bool* blocked_registers) const {
158 switch (type) {
159 case Primitive::kPrimLong: {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100160 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
161 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100162 X86ManagedRegister pair =
163 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
164 blocked_registers[pair.AsRegisterPairLow()] = true;
165 blocked_registers[pair.AsRegisterPairHigh()] = true;
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100166 // Block all other register pairs that share a register with `pair`.
167 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
168 X86ManagedRegister current =
169 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
170 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow()
171 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh()
172 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow()
173 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) {
174 blocked_register_pairs[i] = true;
175 }
176 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100177 return pair;
178 }
179
180 case Primitive::kPrimByte:
181 case Primitive::kPrimBoolean:
182 case Primitive::kPrimChar:
183 case Primitive::kPrimShort:
184 case Primitive::kPrimInt:
185 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100186 Register reg = static_cast<Register>(
187 AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters));
188 // Block all register pairs that contain `reg`.
189 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
190 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
191 X86ManagedRegister current =
192 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
193 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
194 blocked_register_pairs[i] = true;
195 }
196 }
197 return X86ManagedRegister::FromCpuRegister(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100198 }
199
200 case Primitive::kPrimFloat:
201 case Primitive::kPrimDouble:
202 LOG(FATAL) << "Unimplemented register type " << type;
203
204 case Primitive::kPrimVoid:
205 LOG(FATAL) << "Unreachable type " << type;
206 }
207
208 return ManagedRegister::NoRegister();
209}
210
211void CodeGeneratorX86::SetupBlockedRegisters(bool* blocked_registers) const {
212 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
213
214 // Don't allocate the dalvik style register pair passing.
215 blocked_register_pairs[ECX_EDX] = true;
216
217 // Stack register is always reserved.
218 blocked_registers[ESP] = true;
219
220 // TODO: We currently don't use Quick's callee saved registers.
221 blocked_registers[EBP] = true;
222 blocked_registers[ESI] = true;
223 blocked_registers[EDI] = true;
224 blocked_register_pairs[EAX_EDI] = true;
225 blocked_register_pairs[EDX_EDI] = true;
226 blocked_register_pairs[ECX_EDI] = true;
227 blocked_register_pairs[EBX_EDI] = true;
228}
229
230size_t CodeGeneratorX86::GetNumberOfRegisters() const {
231 return kNumberOfRegIds;
232}
233
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100234InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
235 : HGraphVisitor(graph),
236 assembler_(codegen->GetAssembler()),
237 codegen_(codegen) {}
238
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000239void CodeGeneratorX86::GenerateFrameEntry() {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000240 // Create a fake register to mimic Quick.
241 static const int kFakeReturnRegister = 8;
242 core_spill_mask_ |= (1 << kFakeReturnRegister);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000243
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100244 bool skip_overflow_check = IsLeafMethod() && !IsLargeFrame(GetFrameSize(), InstructionSet::kX86);
245 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
246 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
247 RecordPcInfo(0);
248 }
249
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100250 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100251 __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100252
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100253 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
254 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86();
255 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100256
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100257 __ fs()->cmpl(ESP, Address::Absolute(Thread::StackEndOffset<kX86WordSize>()));
258 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100259 }
260
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100261 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000262}
263
264void CodeGeneratorX86::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100265 __ addl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000266}
267
268void CodeGeneratorX86::Bind(Label* label) {
269 __ Bind(label);
270}
271
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000272void InstructionCodeGeneratorX86::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100273 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000274}
275
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100276Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
277 switch (load->GetType()) {
278 case Primitive::kPrimLong:
279 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
280 break;
281
282 case Primitive::kPrimInt:
283 case Primitive::kPrimNot:
284 return Location::StackSlot(GetStackSlot(load->GetLocal()));
285
286 case Primitive::kPrimFloat:
287 case Primitive::kPrimDouble:
288 LOG(FATAL) << "Unimplemented type " << load->GetType();
289
290 case Primitive::kPrimBoolean:
291 case Primitive::kPrimByte:
292 case Primitive::kPrimChar:
293 case Primitive::kPrimShort:
294 case Primitive::kPrimVoid:
295 LOG(FATAL) << "Unexpected type " << load->GetType();
296 }
297
298 LOG(FATAL) << "Unreachable";
299 return Location();
300}
301
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100302Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
303 switch (type) {
304 case Primitive::kPrimBoolean:
305 case Primitive::kPrimByte:
306 case Primitive::kPrimChar:
307 case Primitive::kPrimShort:
308 case Primitive::kPrimInt:
309 case Primitive::kPrimNot: {
310 uint32_t index = gp_index_++;
311 if (index < calling_convention.GetNumberOfRegisters()) {
312 return X86CpuLocation(calling_convention.GetRegisterAt(index));
313 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100314 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100315 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100316 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100317
318 case Primitive::kPrimLong: {
319 uint32_t index = gp_index_;
320 gp_index_ += 2;
321 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
322 return Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(
323 calling_convention.GetRegisterPairAt(index)));
324 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
325 return Location::QuickParameter(index);
326 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100327 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100328 }
329 }
330
331 case Primitive::kPrimDouble:
332 case Primitive::kPrimFloat:
333 LOG(FATAL) << "Unimplemented parameter type " << type;
334 break;
335
336 case Primitive::kPrimVoid:
337 LOG(FATAL) << "Unexpected parameter type " << type;
338 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100339 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100340 return Location();
341}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100342
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100343void CodeGeneratorX86::Move32(Location destination, Location source) {
344 if (source.Equals(destination)) {
345 return;
346 }
347 if (destination.IsRegister()) {
348 if (source.IsRegister()) {
349 __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
350 } else {
351 DCHECK(source.IsStackSlot());
352 __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex()));
353 }
354 } else {
355 if (source.IsRegister()) {
356 __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
357 } else {
358 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100359 __ pushl(Address(ESP, source.GetStackIndex()));
360 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100361 }
362 }
363}
364
365void CodeGeneratorX86::Move64(Location destination, Location source) {
366 if (source.Equals(destination)) {
367 return;
368 }
369 if (destination.IsRegister()) {
370 if (source.IsRegister()) {
371 __ movl(destination.AsX86().AsRegisterPairLow(), source.AsX86().AsRegisterPairLow());
372 __ movl(destination.AsX86().AsRegisterPairHigh(), source.AsX86().AsRegisterPairHigh());
373 } else if (source.IsQuickParameter()) {
374 uint32_t argument_index = source.GetQuickParameterIndex();
375 InvokeDexCallingConvention calling_convention;
376 __ movl(destination.AsX86().AsRegisterPairLow(),
377 calling_convention.GetRegisterAt(argument_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100378 __ movl(destination.AsX86().AsRegisterPairHigh(), Address(ESP,
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100379 calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100380 } else {
381 DCHECK(source.IsDoubleStackSlot());
382 __ movl(destination.AsX86().AsRegisterPairLow(), Address(ESP, source.GetStackIndex()));
383 __ movl(destination.AsX86().AsRegisterPairHigh(),
384 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
385 }
386 } else if (destination.IsQuickParameter()) {
387 InvokeDexCallingConvention calling_convention;
388 uint32_t argument_index = destination.GetQuickParameterIndex();
389 if (source.IsRegister()) {
390 __ movl(calling_convention.GetRegisterAt(argument_index), source.AsX86().AsRegisterPairLow());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100391 __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100392 source.AsX86().AsRegisterPairHigh());
393 } else {
394 DCHECK(source.IsDoubleStackSlot());
395 __ movl(calling_convention.GetRegisterAt(argument_index),
396 Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100397 __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100398 __ popl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100399 }
400 } else {
401 if (source.IsRegister()) {
402 __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsRegisterPairLow());
403 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
404 source.AsX86().AsRegisterPairHigh());
405 } else if (source.IsQuickParameter()) {
406 InvokeDexCallingConvention calling_convention;
407 uint32_t argument_index = source.GetQuickParameterIndex();
408 __ movl(Address(ESP, destination.GetStackIndex()),
409 calling_convention.GetRegisterAt(argument_index));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100410 __ pushl(Address(ESP,
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100411 calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100412 __ popl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100413 } else {
414 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100415 __ pushl(Address(ESP, source.GetStackIndex()));
416 __ popl(Address(ESP, destination.GetStackIndex()));
417 __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize)));
418 __ popl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100419 }
420 }
421}
422
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100423void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
424 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100425 Immediate imm(instruction->AsIntConstant()->GetValue());
426 if (location.IsRegister()) {
427 __ movl(location.AsX86().AsCpuRegister(), imm);
428 } else {
429 __ movl(Address(ESP, location.GetStackIndex()), imm);
430 }
431 } else if (instruction->AsLongConstant() != nullptr) {
432 int64_t value = instruction->AsLongConstant()->GetValue();
433 if (location.IsRegister()) {
434 __ movl(location.AsX86().AsRegisterPairLow(), Immediate(Low32Bits(value)));
435 __ movl(location.AsX86().AsRegisterPairHigh(), Immediate(High32Bits(value)));
436 } else {
437 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
438 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
439 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100440 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100441 switch (instruction->GetType()) {
442 case Primitive::kPrimBoolean:
443 case Primitive::kPrimByte:
444 case Primitive::kPrimChar:
445 case Primitive::kPrimShort:
446 case Primitive::kPrimInt:
447 case Primitive::kPrimNot:
448 Move32(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
449 break;
450
451 case Primitive::kPrimLong:
452 Move64(location, Location::DoubleStackSlot(
453 GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
454 break;
455
456 default:
457 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
458 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000459 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100460 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100461 switch (instruction->GetType()) {
462 case Primitive::kPrimBoolean:
463 case Primitive::kPrimByte:
464 case Primitive::kPrimChar:
465 case Primitive::kPrimShort:
466 case Primitive::kPrimInt:
467 case Primitive::kPrimNot:
468 Move32(location, instruction->GetLocations()->Out());
469 break;
470
471 case Primitive::kPrimLong:
472 Move64(location, instruction->GetLocations()->Out());
473 break;
474
475 default:
476 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
477 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000478 }
479}
480
481void LocationsBuilderX86::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000482 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000483}
484
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000485void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000486 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000487 if (GetGraph()->GetExitBlock() == successor) {
488 codegen_->GenerateFrameExit();
489 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
490 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000491 }
492}
493
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000494void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000495 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000496}
497
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000498void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000499 if (kIsDebugBuild) {
500 __ Comment("Unreachable");
501 __ int3();
502 }
503}
504
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000505void LocationsBuilderX86::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000506 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100507 HInstruction* cond = if_instr->InputAt(0);
508 DCHECK(cond->IsCondition());
509 HCondition* condition = cond->AsCondition();
510 if (condition->NeedsMaterialization()) {
511 locations->SetInAt(0, Location::Any());
512 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000513 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000514}
515
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000516void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700517 HInstruction* cond = if_instr->InputAt(0);
518 DCHECK(cond->IsCondition());
519 HCondition* condition = cond->AsCondition();
520 if (condition->NeedsMaterialization()) {
521 // Materialized condition, compare against 0
522 Location lhs = if_instr->GetLocations()->InAt(0);
523 if (lhs.IsRegister()) {
524 __ cmpl(lhs.AsX86().AsCpuRegister(), Immediate(0));
525 } else {
526 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
527 }
528 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100529 } else {
Dave Allison20dfc792014-06-16 20:44:29 -0700530 Location lhs = condition->GetLocations()->InAt(0);
531 Location rhs = condition->GetLocations()->InAt(1);
532 // LHS is guaranteed to be in a register (see LocationsBuilderX86::VisitCondition).
533 if (rhs.IsRegister()) {
534 __ cmpl(lhs.AsX86().AsCpuRegister(), rhs.AsX86().AsCpuRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100535 } else if (rhs.IsConstant()) {
536 HIntConstant* instruction = rhs.GetConstant()->AsIntConstant();
537 Immediate imm(instruction->AsIntConstant()->GetValue());
538 __ cmpl(lhs.AsX86().AsCpuRegister(), imm);
Dave Allison20dfc792014-06-16 20:44:29 -0700539 } else {
540 __ cmpl(lhs.AsX86().AsCpuRegister(), Address(ESP, rhs.GetStackIndex()));
541 }
542 __ j(X86Condition(condition->GetCondition()),
543 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100544 }
Dave Allison20dfc792014-06-16 20:44:29 -0700545 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
546 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000547 }
548}
549
550void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000551 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000552}
553
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000554void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
555 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000556}
557
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000558void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100559 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000560}
561
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000562void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100563 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000564}
565
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100566void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
567 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
568 switch (store->InputAt(1)->GetType()) {
569 case Primitive::kPrimBoolean:
570 case Primitive::kPrimByte:
571 case Primitive::kPrimChar:
572 case Primitive::kPrimShort:
573 case Primitive::kPrimInt:
574 case Primitive::kPrimNot:
575 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
576 break;
577
578 case Primitive::kPrimLong:
579 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
580 break;
581
582 default:
583 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
584 }
585 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000586}
587
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000588void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000589}
590
Dave Allison20dfc792014-06-16 20:44:29 -0700591void LocationsBuilderX86::VisitCondition(HCondition* comp) {
592 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100593 locations->SetInAt(0, Location::RequiresRegister());
594 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100595 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100596 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100597 }
Dave Allison20dfc792014-06-16 20:44:29 -0700598 comp->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000599}
600
Dave Allison20dfc792014-06-16 20:44:29 -0700601void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
602 if (comp->NeedsMaterialization()) {
603 LocationSummary* locations = comp->GetLocations();
604 if (locations->InAt(1).IsRegister()) {
605 __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
606 locations->InAt(1).AsX86().AsCpuRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100607 } else if (locations->InAt(1).IsConstant()) {
608 HConstant* instruction = locations->InAt(1).GetConstant();
609 Immediate imm(instruction->AsIntConstant()->GetValue());
610 __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(), imm);
Dave Allison20dfc792014-06-16 20:44:29 -0700611 } else {
612 __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
613 Address(ESP, locations->InAt(1).GetStackIndex()));
614 }
615 __ setb(X86Condition(comp->GetCondition()), locations->Out().AsX86().AsCpuRegister());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100616 }
Dave Allison20dfc792014-06-16 20:44:29 -0700617}
618
619void LocationsBuilderX86::VisitEqual(HEqual* comp) {
620 VisitCondition(comp);
621}
622
623void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
624 VisitCondition(comp);
625}
626
627void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
628 VisitCondition(comp);
629}
630
631void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
632 VisitCondition(comp);
633}
634
635void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
636 VisitCondition(comp);
637}
638
639void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
640 VisitCondition(comp);
641}
642
643void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
644 VisitCondition(comp);
645}
646
647void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
648 VisitCondition(comp);
649}
650
651void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
652 VisitCondition(comp);
653}
654
655void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
656 VisitCondition(comp);
657}
658
659void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
660 VisitCondition(comp);
661}
662
663void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
664 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000665}
666
667void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100668 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100669 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100670 constant->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000671}
672
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000673void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000674}
675
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100676void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100677 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100678 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray31d76b42014-06-09 15:02:22 +0100679 constant->SetLocations(locations);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100680}
681
682void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
683 // Will be generated at use site.
684}
685
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000686void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000687 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000688}
689
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000690void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
691 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000692 __ ret();
693}
694
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000695void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000696 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100697 switch (ret->InputAt(0)->GetType()) {
698 case Primitive::kPrimBoolean:
699 case Primitive::kPrimByte:
700 case Primitive::kPrimChar:
701 case Primitive::kPrimShort:
702 case Primitive::kPrimInt:
703 case Primitive::kPrimNot:
704 locations->SetInAt(0, X86CpuLocation(EAX));
705 break;
706
707 case Primitive::kPrimLong:
708 locations->SetInAt(
709 0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
710 break;
711
712 default:
713 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
714 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000715 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000716}
717
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000718void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100719 if (kIsDebugBuild) {
720 switch (ret->InputAt(0)->GetType()) {
721 case Primitive::kPrimBoolean:
722 case Primitive::kPrimByte:
723 case Primitive::kPrimChar:
724 case Primitive::kPrimShort:
725 case Primitive::kPrimInt:
726 case Primitive::kPrimNot:
727 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsCpuRegister(), EAX);
728 break;
729
730 case Primitive::kPrimLong:
731 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsRegisterPair(), EAX_EDX);
732 break;
733
734 default:
735 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
736 }
737 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000738 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000739 __ ret();
740}
741
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000742void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100743 codegen_->MarkNotLeaf();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000744 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100745 locations->AddTemp(X86CpuLocation(EAX));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100746
747 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100748 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100749 HInstruction* input = invoke->InputAt(i);
750 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
751 }
752
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100753 switch (invoke->GetType()) {
754 case Primitive::kPrimBoolean:
755 case Primitive::kPrimByte:
756 case Primitive::kPrimChar:
757 case Primitive::kPrimShort:
758 case Primitive::kPrimInt:
759 case Primitive::kPrimNot:
760 locations->SetOut(X86CpuLocation(EAX));
761 break;
762
763 case Primitive::kPrimLong:
764 locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
765 break;
766
767 case Primitive::kPrimVoid:
768 break;
769
770 case Primitive::kPrimDouble:
771 case Primitive::kPrimFloat:
772 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
773 break;
774 }
775
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000776 invoke->SetLocations(locations);
777}
778
779void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100780 Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister();
Nicolas Geoffrayf61b5372014-06-25 14:35:34 +0100781 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
782 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100783 invoke->GetIndexInDexCache() * kX86WordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000784
785 // TODO: Implement all kinds of calls:
786 // 1) boot -> boot
787 // 2) app -> boot
788 // 3) app -> app
789 //
790 // Currently we implement the app -> app logic, which looks up in the resolve cache.
791
792 // temp = method;
793 LoadCurrentMethod(temp);
794 // temp = temp->dex_cache_resolved_methods_;
795 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
796 // temp = temp[index_in_cache]
797 __ movl(temp, Address(temp, index_in_cache));
798 // (temp + offset_of_quick_compiled_code)()
799 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
800
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100801 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000802 codegen_->RecordPcInfo(invoke->GetDexPc());
803}
804
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000805void LocationsBuilderX86::VisitAdd(HAdd* add) {
806 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
807 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100808 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100809 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100810 locations->SetInAt(0, Location::RequiresRegister());
811 locations->SetInAt(1, Location::Any());
812 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100813 break;
814 }
815
816 case Primitive::kPrimBoolean:
817 case Primitive::kPrimByte:
818 case Primitive::kPrimChar:
819 case Primitive::kPrimShort:
820 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
821 break;
822
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000823 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100824 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000825 }
826 add->SetLocations(locations);
827}
828
829void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
830 LocationSummary* locations = add->GetLocations();
831 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100832 case Primitive::kPrimInt: {
833 DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(),
834 locations->Out().AsX86().AsCpuRegister());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100835 if (locations->InAt(1).IsRegister()) {
836 __ addl(locations->InAt(0).AsX86().AsCpuRegister(),
837 locations->InAt(1).AsX86().AsCpuRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100838 } else if (locations->InAt(1).IsConstant()) {
839 HConstant* instruction = locations->InAt(1).GetConstant();
840 Immediate imm(instruction->AsIntConstant()->GetValue());
841 __ addl(locations->InAt(0).AsX86().AsCpuRegister(), imm);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100842 } else {
843 __ addl(locations->InAt(0).AsX86().AsCpuRegister(),
844 Address(ESP, locations->InAt(1).GetStackIndex()));
845 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000846 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100847 }
848
849 case Primitive::kPrimLong: {
850 DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
851 locations->Out().AsX86().AsRegisterPair());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100852 if (locations->InAt(1).IsRegister()) {
853 __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(),
854 locations->InAt(1).AsX86().AsRegisterPairLow());
855 __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
856 locations->InAt(1).AsX86().AsRegisterPairHigh());
857 } else {
858 __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(),
859 Address(ESP, locations->InAt(1).GetStackIndex()));
860 __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
861 Address(ESP, locations->InAt(1).GetHighStackIndex(kX86WordSize)));
862 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100863 break;
864 }
865
866 case Primitive::kPrimBoolean:
867 case Primitive::kPrimByte:
868 case Primitive::kPrimChar:
869 case Primitive::kPrimShort:
870 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
871 break;
872
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000873 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100874 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000875 }
876}
877
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100878void LocationsBuilderX86::VisitSub(HSub* sub) {
879 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
880 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100881 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100882 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100883 locations->SetInAt(0, Location::RequiresRegister());
884 locations->SetInAt(1, Location::Any());
885 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100886 break;
887 }
888
889 case Primitive::kPrimBoolean:
890 case Primitive::kPrimByte:
891 case Primitive::kPrimChar:
892 case Primitive::kPrimShort:
893 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
894 break;
895
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100896 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100897 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100898 }
899 sub->SetLocations(locations);
900}
901
902void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
903 LocationSummary* locations = sub->GetLocations();
904 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100905 case Primitive::kPrimInt: {
906 DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(),
907 locations->Out().AsX86().AsCpuRegister());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100908 if (locations->InAt(1).IsRegister()) {
909 __ subl(locations->InAt(0).AsX86().AsCpuRegister(),
910 locations->InAt(1).AsX86().AsCpuRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100911 } else if (locations->InAt(1).IsConstant()) {
912 HConstant* instruction = locations->InAt(1).GetConstant();
913 Immediate imm(instruction->AsIntConstant()->GetValue());
914 __ subl(locations->InAt(0).AsX86().AsCpuRegister(), imm);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100915 } else {
916 __ subl(locations->InAt(0).AsX86().AsCpuRegister(),
917 Address(ESP, locations->InAt(1).GetStackIndex()));
918 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100919 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100920 }
921
922 case Primitive::kPrimLong: {
923 DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
924 locations->Out().AsX86().AsRegisterPair());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100925 if (locations->InAt(1).IsRegister()) {
926 __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(),
927 locations->InAt(1).AsX86().AsRegisterPairLow());
928 __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
929 locations->InAt(1).AsX86().AsRegisterPairHigh());
930 } else {
931 __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(),
932 Address(ESP, locations->InAt(1).GetStackIndex()));
933 __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
934 Address(ESP, locations->InAt(1).GetHighStackIndex(kX86WordSize)));
935 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100936 break;
937 }
938
939 case Primitive::kPrimBoolean:
940 case Primitive::kPrimByte:
941 case Primitive::kPrimChar:
942 case Primitive::kPrimShort:
943 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
944 break;
945
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100946 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100947 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100948 }
949}
950
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100951void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100952 codegen_->MarkNotLeaf();
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100953 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100954 locations->SetOut(X86CpuLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100955 InvokeRuntimeCallingConvention calling_convention;
956 locations->AddTemp(X86CpuLocation(calling_convention.GetRegisterAt(0)));
957 locations->AddTemp(X86CpuLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100958 instruction->SetLocations(locations);
959}
960
961void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
962 InvokeRuntimeCallingConvention calling_convention;
963 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100964 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100965
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100966 __ fs()->call(
967 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocObjectWithAccessCheck)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100968
969 codegen_->RecordPcInfo(instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100970 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100971}
972
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100973void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
974 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100975 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
976 if (location.IsStackSlot()) {
977 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
978 } else if (location.IsDoubleStackSlot()) {
979 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100980 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100981 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100982 instruction->SetLocations(locations);
983}
984
985void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100986}
987
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100988void LocationsBuilderX86::VisitNot(HNot* instruction) {
989 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100990 locations->SetInAt(0, Location::RequiresRegister());
991 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100992 instruction->SetLocations(locations);
993}
994
995void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
996 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100997 Location out = locations->Out();
998 DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(), out.AsX86().AsCpuRegister());
999 __ xorl(out.AsX86().AsCpuRegister(), Immediate(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001000}
1001
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001002void LocationsBuilderX86::VisitCompare(HCompare* compare) {
1003 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
1004 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001005 locations->SetInAt(1, Location::Any());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001006 locations->SetOut(Location::RequiresRegister());
1007 compare->SetLocations(locations);
1008}
1009
1010void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
1011 Label greater, done;
1012 LocationSummary* locations = compare->GetLocations();
1013 switch (compare->InputAt(0)->GetType()) {
1014 case Primitive::kPrimLong: {
1015 Label less, greater, done;
1016 Register output = locations->Out().AsX86().AsCpuRegister();
1017 X86ManagedRegister left = locations->InAt(0).AsX86();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001018 Location right = locations->InAt(1);
1019 if (right.IsRegister()) {
1020 __ cmpl(left.AsRegisterPairHigh(), right.AsX86().AsRegisterPairHigh());
1021 } else {
1022 DCHECK(right.IsDoubleStackSlot());
1023 __ cmpl(left.AsRegisterPairHigh(), Address(ESP, right.GetHighStackIndex(kX86WordSize)));
1024 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001025 __ j(kLess, &less); // Signed compare.
1026 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001027 if (right.IsRegister()) {
1028 __ cmpl(left.AsRegisterPairLow(), right.AsX86().AsRegisterPairLow());
1029 } else {
1030 DCHECK(right.IsDoubleStackSlot());
1031 __ cmpl(left.AsRegisterPairLow(), Address(ESP, right.GetStackIndex()));
1032 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001033 __ movl(output, Immediate(0));
1034 __ j(kEqual, &done);
1035 __ j(kBelow, &less); // Unsigned compare.
1036
1037 __ Bind(&greater);
1038 __ movl(output, Immediate(1));
1039 __ jmp(&done);
1040
1041 __ Bind(&less);
1042 __ movl(output, Immediate(-1));
1043
1044 __ Bind(&done);
1045 break;
1046 }
1047 default:
1048 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1049 }
1050}
1051
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001052void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001053 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1054 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1055 locations->SetInAt(i, Location::Any());
1056 }
1057 locations->SetOut(Location::Any());
1058 instruction->SetLocations(locations);
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001059}
1060
1061void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001062 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001063}
1064
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001065void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1066 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1067 locations->SetInAt(0, Location::RequiresRegister());
1068 Primitive::Type field_type = instruction->InputAt(1)->GetType();
1069 if (field_type == Primitive::kPrimBoolean || field_type == Primitive::kPrimByte) {
1070 // Ensure the value is in a byte register.
1071 locations->SetInAt(1, X86CpuLocation(EAX));
1072 } else {
1073 locations->SetInAt(1, Location::RequiresRegister());
1074 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001075 // Temporary registers for the write barrier.
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001076 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001077 locations->AddTemp(Location::RequiresRegister());
1078 // Ensure the card is in a byte register.
1079 locations->AddTemp(X86CpuLocation(ECX));
1080 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001081 instruction->SetLocations(locations);
1082}
1083
1084void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1085 LocationSummary* locations = instruction->GetLocations();
1086 Register obj = locations->InAt(0).AsX86().AsCpuRegister();
1087 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1088 Primitive::Type field_type = instruction->InputAt(1)->GetType();
1089
1090 switch (field_type) {
1091 case Primitive::kPrimBoolean:
1092 case Primitive::kPrimByte: {
1093 ByteRegister value = locations->InAt(1).AsX86().AsByteRegister();
1094 __ movb(Address(obj, offset), value);
1095 break;
1096 }
1097
1098 case Primitive::kPrimShort:
1099 case Primitive::kPrimChar: {
1100 Register value = locations->InAt(1).AsX86().AsCpuRegister();
1101 __ movw(Address(obj, offset), value);
1102 break;
1103 }
1104
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001105 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001106 case Primitive::kPrimNot: {
1107 Register value = locations->InAt(1).AsX86().AsCpuRegister();
1108 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001109
1110 if (field_type == Primitive::kPrimNot) {
1111 Register temp = locations->GetTemp(0).AsX86().AsCpuRegister();
1112 Register card = locations->GetTemp(1).AsX86().AsCpuRegister();
1113 codegen_->MarkGCCard(temp, card, obj, value);
1114 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001115 break;
1116 }
1117
1118 case Primitive::kPrimLong: {
1119 X86ManagedRegister value = locations->InAt(1).AsX86();
1120 __ movl(Address(obj, offset), value.AsRegisterPairLow());
1121 __ movl(Address(obj, kX86WordSize + offset), value.AsRegisterPairHigh());
1122 break;
1123 }
1124
1125 case Primitive::kPrimFloat:
1126 case Primitive::kPrimDouble:
1127 LOG(FATAL) << "Unimplemented register type " << field_type;
1128
1129 case Primitive::kPrimVoid:
1130 LOG(FATAL) << "Unreachable type " << field_type;
1131 }
1132}
1133
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001134void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
1135 Label is_null;
1136 __ testl(value, value);
1137 __ j(kEqual, &is_null);
1138 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
1139 __ movl(temp, object);
1140 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
1141 __ movb(Address(temp, card, TIMES_1, 0),
1142 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
1143 __ Bind(&is_null);
1144}
1145
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001146void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1147 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1148 locations->SetInAt(0, Location::RequiresRegister());
1149 locations->SetOut(Location::RequiresRegister());
1150 instruction->SetLocations(locations);
1151}
1152
1153void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1154 LocationSummary* locations = instruction->GetLocations();
1155 Register obj = locations->InAt(0).AsX86().AsCpuRegister();
1156 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1157
1158 switch (instruction->GetType()) {
1159 case Primitive::kPrimBoolean: {
1160 Register out = locations->Out().AsX86().AsCpuRegister();
1161 __ movzxb(out, Address(obj, offset));
1162 break;
1163 }
1164
1165 case Primitive::kPrimByte: {
1166 Register out = locations->Out().AsX86().AsCpuRegister();
1167 __ movsxb(out, Address(obj, offset));
1168 break;
1169 }
1170
1171 case Primitive::kPrimShort: {
1172 Register out = locations->Out().AsX86().AsCpuRegister();
1173 __ movsxw(out, Address(obj, offset));
1174 break;
1175 }
1176
1177 case Primitive::kPrimChar: {
1178 Register out = locations->Out().AsX86().AsCpuRegister();
1179 __ movzxw(out, Address(obj, offset));
1180 break;
1181 }
1182
1183 case Primitive::kPrimInt:
1184 case Primitive::kPrimNot: {
1185 Register out = locations->Out().AsX86().AsCpuRegister();
1186 __ movl(out, Address(obj, offset));
1187 break;
1188 }
1189
1190 case Primitive::kPrimLong: {
1191 // TODO: support volatile.
1192 X86ManagedRegister out = locations->Out().AsX86();
1193 __ movl(out.AsRegisterPairLow(), Address(obj, offset));
1194 __ movl(out.AsRegisterPairHigh(), Address(obj, kX86WordSize + offset));
1195 break;
1196 }
1197
1198 case Primitive::kPrimFloat:
1199 case Primitive::kPrimDouble:
1200 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1201
1202 case Primitive::kPrimVoid:
1203 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1204 }
1205}
1206
1207void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
1208 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1209 locations->SetInAt(0, Location::Any());
1210 // TODO: Have a normalization phase that makes this instruction never used.
1211 locations->SetOut(Location::SameAsFirstInput());
1212 instruction->SetLocations(locations);
1213}
1214
1215void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
1216 SlowPathCode* slow_path =
1217 new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction->GetDexPc());
1218 codegen_->AddSlowPath(slow_path);
1219
1220 LocationSummary* locations = instruction->GetLocations();
1221 Location obj = locations->InAt(0);
1222 DCHECK(obj.Equals(locations->Out()));
1223
1224 if (obj.IsRegister()) {
1225 __ cmpl(obj.AsX86().AsCpuRegister(), Immediate(0));
1226 } else {
1227 DCHECK(locations->InAt(0).IsStackSlot());
1228 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
1229 }
1230 __ j(kEqual, slow_path->GetEntryLabel());
1231}
1232
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001233void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
1234 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1235 locations->SetInAt(0, Location::RequiresRegister());
1236 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1237 locations->SetOut(Location::RequiresRegister());
1238 instruction->SetLocations(locations);
1239}
1240
1241void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
1242 LocationSummary* locations = instruction->GetLocations();
1243 Register obj = locations->InAt(0).AsX86().AsCpuRegister();
1244 Location index = locations->InAt(1);
1245
1246 switch (instruction->GetType()) {
1247 case Primitive::kPrimBoolean: {
1248 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1249 Register out = locations->Out().AsX86().AsCpuRegister();
1250 if (index.IsConstant()) {
1251 __ movzxb(out, Address(obj,
1252 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1253 } else {
1254 __ movzxb(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset));
1255 }
1256 break;
1257 }
1258
1259 case Primitive::kPrimByte: {
1260 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1261 Register out = locations->Out().AsX86().AsCpuRegister();
1262 if (index.IsConstant()) {
1263 __ movsxb(out, Address(obj,
1264 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1265 } else {
1266 __ movsxb(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset));
1267 }
1268 break;
1269 }
1270
1271 case Primitive::kPrimShort: {
1272 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1273 Register out = locations->Out().AsX86().AsCpuRegister();
1274 if (index.IsConstant()) {
1275 __ movsxw(out, Address(obj,
1276 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1277 } else {
1278 __ movsxw(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset));
1279 }
1280 break;
1281 }
1282
1283 case Primitive::kPrimChar: {
1284 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1285 Register out = locations->Out().AsX86().AsCpuRegister();
1286 if (index.IsConstant()) {
1287 __ movzxw(out, Address(obj,
1288 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1289 } else {
1290 __ movzxw(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset));
1291 }
1292 break;
1293 }
1294
1295 case Primitive::kPrimInt:
1296 case Primitive::kPrimNot: {
1297 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1298 Register out = locations->Out().AsX86().AsCpuRegister();
1299 if (index.IsConstant()) {
1300 __ movl(out, Address(obj,
1301 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1302 } else {
1303 __ movl(out, Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset));
1304 }
1305 break;
1306 }
1307
1308 case Primitive::kPrimLong: {
1309 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1310 X86ManagedRegister out = locations->Out().AsX86();
1311 if (index.IsConstant()) {
1312 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1313 __ movl(out.AsRegisterPairLow(), Address(obj, offset));
1314 __ movl(out.AsRegisterPairHigh(), Address(obj, offset + kX86WordSize));
1315 } else {
1316 __ movl(out.AsRegisterPairLow(),
1317 Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset));
1318 __ movl(out.AsRegisterPairHigh(),
1319 Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize));
1320 }
1321 break;
1322 }
1323
1324 case Primitive::kPrimFloat:
1325 case Primitive::kPrimDouble:
1326 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1327
1328 case Primitive::kPrimVoid:
1329 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1330 }
1331}
1332
1333void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
1334 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1335 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1336 if (value_type == Primitive::kPrimNot) {
1337 InvokeRuntimeCallingConvention calling_convention;
1338 locations->SetInAt(0, X86CpuLocation(calling_convention.GetRegisterAt(0)));
1339 locations->SetInAt(1, X86CpuLocation(calling_convention.GetRegisterAt(1)));
1340 locations->SetInAt(2, X86CpuLocation(calling_convention.GetRegisterAt(2)));
1341 codegen_->MarkNotLeaf();
1342 } else {
1343 locations->SetInAt(0, Location::RequiresRegister());
1344 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1345 if (value_type == Primitive::kPrimBoolean || value_type == Primitive::kPrimByte) {
1346 // Ensure the value is in a byte register.
1347 locations->SetInAt(2, X86CpuLocation(EAX));
1348 } else {
1349 locations->SetInAt(2, Location::RequiresRegister());
1350 }
1351 }
1352
1353 instruction->SetLocations(locations);
1354}
1355
1356void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
1357 LocationSummary* locations = instruction->GetLocations();
1358 Register obj = locations->InAt(0).AsX86().AsCpuRegister();
1359 Location index = locations->InAt(1);
1360 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1361
1362 switch (value_type) {
1363 case Primitive::kPrimBoolean:
1364 case Primitive::kPrimByte: {
1365 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1366 ByteRegister value = locations->InAt(2).AsX86().AsByteRegister();
1367 if (index.IsConstant()) {
1368 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1369 __ movb(Address(obj, offset), value);
1370 } else {
1371 __ movb(Address(obj, index.AsX86().AsCpuRegister(), TIMES_1, data_offset), value);
1372 }
1373 break;
1374 }
1375
1376 case Primitive::kPrimShort:
1377 case Primitive::kPrimChar: {
1378 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1379 Register value = locations->InAt(2).AsX86().AsCpuRegister();
1380 if (index.IsConstant()) {
1381 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1382 __ movw(Address(obj, offset), value);
1383 } else {
1384 __ movw(Address(obj, index.AsX86().AsCpuRegister(), TIMES_2, data_offset), value);
1385 }
1386 break;
1387 }
1388
1389 case Primitive::kPrimInt: {
1390 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1391 Register value = locations->InAt(2).AsX86().AsCpuRegister();
1392 if (index.IsConstant()) {
1393 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1394 __ movl(Address(obj, offset), value);
1395 } else {
1396 __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_4, data_offset), value);
1397 }
1398 break;
1399 }
1400
1401 case Primitive::kPrimNot: {
1402 DCHECK(!codegen_->IsLeafMethod());
1403 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
1404 codegen_->RecordPcInfo(instruction->GetDexPc());
1405 break;
1406 }
1407
1408 case Primitive::kPrimLong: {
1409 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1410 X86ManagedRegister value = locations->InAt(2).AsX86();
1411 if (index.IsConstant()) {
1412 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1413 __ movl(Address(obj, offset), value.AsRegisterPairLow());
1414 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh());
1415 } else {
1416 __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset),
1417 value.AsRegisterPairLow());
1418 __ movl(Address(obj, index.AsX86().AsCpuRegister(), TIMES_8, data_offset + kX86WordSize),
1419 value.AsRegisterPairHigh());
1420 }
1421 break;
1422 }
1423
1424 case Primitive::kPrimFloat:
1425 case Primitive::kPrimDouble:
1426 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1427
1428 case Primitive::kPrimVoid:
1429 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1430 }
1431}
1432
1433void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
1434 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1435 locations->SetInAt(0, Location::RequiresRegister());
1436 locations->SetOut(Location::RequiresRegister());
1437 instruction->SetLocations(locations);
1438}
1439
1440void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
1441 LocationSummary* locations = instruction->GetLocations();
1442 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1443 Register obj = locations->InAt(0).AsX86().AsCpuRegister();
1444 Register out = locations->Out().AsX86().AsCpuRegister();
1445 __ movl(out, Address(obj, offset));
1446}
1447
1448void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
1449 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1450 locations->SetInAt(0, Location::RequiresRegister());
1451 locations->SetInAt(1, Location::RequiresRegister());
1452 // TODO: Have a normalization phase that makes this instruction never used.
1453 locations->SetOut(Location::SameAsFirstInput());
1454 instruction->SetLocations(locations);
1455}
1456
1457void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
1458 LocationSummary* locations = instruction->GetLocations();
1459 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(
1460 instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
1461 codegen_->AddSlowPath(slow_path);
1462
1463 Register index = locations->InAt(0).AsX86().AsCpuRegister();
1464 Register length = locations->InAt(1).AsX86().AsCpuRegister();
1465
1466 __ cmpl(index, length);
1467 __ j(kAboveEqual, slow_path->GetEntryLabel());
1468}
1469
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001470void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
1471 temp->SetLocations(nullptr);
1472}
1473
1474void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
1475 // Nothing to do, this is driven by the code generator.
1476}
1477
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001478void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001479 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001480}
1481
1482void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001483 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1484}
1485
1486X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
1487 return codegen_->GetAssembler();
1488}
1489
1490void ParallelMoveResolverX86::MoveMemoryToMemory(int dst, int src) {
1491 ScratchRegisterScope ensure_scratch(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001492 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001493 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
1494 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, src + stack_offset));
1495 __ movl(Address(ESP, dst + stack_offset), static_cast<Register>(ensure_scratch.GetRegister()));
1496}
1497
1498void ParallelMoveResolverX86::EmitMove(size_t index) {
1499 MoveOperands* move = moves_.Get(index);
1500 Location source = move->GetSource();
1501 Location destination = move->GetDestination();
1502
1503 if (source.IsRegister()) {
1504 if (destination.IsRegister()) {
1505 __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
1506 } else {
1507 DCHECK(destination.IsStackSlot());
1508 __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
1509 }
1510 } else if (source.IsStackSlot()) {
1511 if (destination.IsRegister()) {
1512 __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex()));
1513 } else {
1514 DCHECK(destination.IsStackSlot());
1515 MoveMemoryToMemory(destination.GetStackIndex(),
1516 source.GetStackIndex());
1517 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001518 } else if (source.IsConstant()) {
1519 HIntConstant* instruction = source.GetConstant()->AsIntConstant();
1520 Immediate imm(instruction->AsIntConstant()->GetValue());
1521 if (destination.IsRegister()) {
1522 __ movl(destination.AsX86().AsCpuRegister(), imm);
1523 } else {
1524 __ movl(Address(ESP, destination.GetStackIndex()), imm);
1525 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001526 } else {
1527 LOG(FATAL) << "Unimplemented";
1528 }
1529}
1530
1531void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001532 Register suggested_scratch = reg == EAX ? EBX : EAX;
1533 ScratchRegisterScope ensure_scratch(
1534 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
1535
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001536 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
1537 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
1538 __ movl(Address(ESP, mem + stack_offset), reg);
1539 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
1540}
1541
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001542void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
1543 ScratchRegisterScope ensure_scratch1(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001544 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
1545
1546 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001547 ScratchRegisterScope ensure_scratch2(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01001548 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
1549
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001550 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
1551 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
1552 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
1553 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
1554 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
1555 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
1556}
1557
1558void ParallelMoveResolverX86::EmitSwap(size_t index) {
1559 MoveOperands* move = moves_.Get(index);
1560 Location source = move->GetSource();
1561 Location destination = move->GetDestination();
1562
1563 if (source.IsRegister() && destination.IsRegister()) {
1564 __ xchgl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
1565 } else if (source.IsRegister() && destination.IsStackSlot()) {
1566 Exchange(source.AsX86().AsCpuRegister(), destination.GetStackIndex());
1567 } else if (source.IsStackSlot() && destination.IsRegister()) {
1568 Exchange(destination.AsX86().AsCpuRegister(), source.GetStackIndex());
1569 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1570 Exchange(destination.GetStackIndex(), source.GetStackIndex());
1571 } else {
1572 LOG(FATAL) << "Unimplemented";
1573 }
1574}
1575
1576void ParallelMoveResolverX86::SpillScratch(int reg) {
1577 __ pushl(static_cast<Register>(reg));
1578}
1579
1580void ParallelMoveResolverX86::RestoreScratch(int reg) {
1581 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01001582}
1583
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001584} // namespace x86
1585} // namespace art