blob: 2d6d14fbc420a4bd7cd0d93d17d4a942f426edd7 [file] [log] [blame]
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00001/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include "code_generator_x86.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010018
19#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Ian Rogers7e70b002014-10-08 11:47:24 -070021#include "mirror/array-inl.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010022#include "mirror/art_method.h"
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +010023#include "mirror/class.h"
Nicolas Geoffrayf6e206c2014-08-07 20:25:41 +010024#include "thread.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000025#include "utils/assembler.h"
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010026#include "utils/stack_checks.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000027#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010028#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000029
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000030namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010031
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000032namespace x86 {
33
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010034static constexpr bool kExplicitStackOverflowCheck = false;
35
36static constexpr int kNumberOfPushedRegistersAtEntry = 1;
37static constexpr int kCurrentMethodStackOffset = 0;
38
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010039static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX };
40static constexpr size_t kRuntimeParameterCoreRegistersLength =
41 arraysize(kRuntimeParameterCoreRegisters);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010042static constexpr XmmRegister kRuntimeParameterFpuRegisters[] = { };
43static constexpr size_t kRuntimeParameterFpuRegistersLength = 0;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010044
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010045class InvokeRuntimeCallingConvention : public CallingConvention<Register, XmmRegister> {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010046 public:
47 InvokeRuntimeCallingConvention()
48 : CallingConvention(kRuntimeParameterCoreRegisters,
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +010049 kRuntimeParameterCoreRegistersLength,
50 kRuntimeParameterFpuRegisters,
51 kRuntimeParameterFpuRegistersLength) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +010052
53 private:
54 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
55};
56
Nicolas Geoffraye5038322014-07-04 09:41:32 +010057#define __ reinterpret_cast<X86Assembler*>(codegen->GetAssembler())->
58
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010059class SlowPathCodeX86 : public SlowPathCode {
60 public:
61 SlowPathCodeX86() : entry_label_(), exit_label_() {}
62
63 Label* GetEntryLabel() { return &entry_label_; }
64 Label* GetExitLabel() { return &exit_label_; }
65
66 private:
67 Label entry_label_;
68 Label exit_label_;
69
70 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeX86);
71};
72
73class NullCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffraye5038322014-07-04 09:41:32 +010074 public:
Nicolas Geoffray39468442014-09-02 15:17:15 +010075 explicit NullCheckSlowPathX86(HNullCheck* instruction) : instruction_(instruction) {}
Nicolas Geoffraye5038322014-07-04 09:41:32 +010076
77 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
78 __ Bind(GetEntryLabel());
79 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowNullPointer)));
Nicolas Geoffray39468442014-09-02 15:17:15 +010080 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffraye5038322014-07-04 09:41:32 +010081 }
82
83 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +010084 HNullCheck* const instruction_;
Nicolas Geoffraye5038322014-07-04 09:41:32 +010085 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86);
86};
87
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +010088class StackOverflowCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +010089 public:
90 StackOverflowCheckSlowPathX86() {}
91
92 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
93 __ Bind(GetEntryLabel());
94 __ addl(ESP,
95 Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
96 __ fs()->jmp(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowStackOverflow)));
97 }
98
99 private:
100 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86);
101};
102
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100103class BoundsCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100104 public:
Roland Levillain5799fc02014-09-25 12:15:20 +0100105 BoundsCheckSlowPathX86(HBoundsCheck* instruction,
106 Location index_location,
107 Location length_location)
Nicolas Geoffray39468442014-09-02 15:17:15 +0100108 : instruction_(instruction), index_location_(index_location), length_location_(length_location) {}
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100109
110 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100111 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100112 __ Bind(GetEntryLabel());
113 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100114 x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), index_location_);
115 x86_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(1)), length_location_);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100116 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pThrowArrayBounds)));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100117 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100118 }
119
120 private:
Nicolas Geoffray39468442014-09-02 15:17:15 +0100121 HBoundsCheck* const instruction_;
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +0100122 const Location index_location_;
123 const Location length_location_;
124
125 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
126};
127
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100128class SuspendCheckSlowPathX86 : public SlowPathCodeX86 {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000129 public:
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100130 explicit SuspendCheckSlowPathX86(HSuspendCheck* instruction, HBasicBlock* successor)
131 : instruction_(instruction), successor_(successor) {}
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000132
133 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100134 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000135 __ Bind(GetEntryLabel());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100136 codegen->SaveLiveRegisters(instruction_->GetLocations());
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000137 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
138 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100139 codegen->RestoreLiveRegisters(instruction_->GetLocations());
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100140 if (successor_ == nullptr) {
141 __ jmp(GetReturnLabel());
142 } else {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100143 __ jmp(x86_codegen->GetLabelOf(successor_));
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100144 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000145 }
146
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100147 Label* GetReturnLabel() {
148 DCHECK(successor_ == nullptr);
149 return &return_label_;
150 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000151
152 private:
153 HSuspendCheck* const instruction_;
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100154 HBasicBlock* const successor_;
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +0000155 Label return_label_;
156
157 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
158};
159
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100160class ClinitCheckSlowPathX86 : public SlowPathCodeX86 {
161 public:
162 explicit ClinitCheckSlowPathX86(HClinitCheck* instruction) : instruction_(instruction) {}
163
164 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
165 CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
166 __ Bind(GetEntryLabel());
167 codegen->SaveLiveRegisters(instruction_->GetLocations());
168
169 HLoadClass* cls = instruction_->GetLoadClass();
170 InvokeRuntimeCallingConvention calling_convention;
171 __ movl(calling_convention.GetRegisterAt(0), Immediate(cls->GetTypeIndex()));
172 x86_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
173 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pInitializeStaticStorage)));
174 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
175 x86_codegen->Move32(instruction_->GetLocations()->InAt(0), Location::RegisterLocation(EAX));
176 codegen->RestoreLiveRegisters(instruction_->GetLocations());
177 __ jmp(GetExitLabel());
178 }
179
180 private:
181 HClinitCheck* const instruction_;
182
183 DISALLOW_COPY_AND_ASSIGN(ClinitCheckSlowPathX86);
184};
185
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100186#undef __
187#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
188
Dave Allison20dfc792014-06-16 20:44:29 -0700189inline Condition X86Condition(IfCondition cond) {
190 switch (cond) {
191 case kCondEQ: return kEqual;
192 case kCondNE: return kNotEqual;
193 case kCondLT: return kLess;
194 case kCondLE: return kLessEqual;
195 case kCondGT: return kGreater;
196 case kCondGE: return kGreaterEqual;
197 default:
198 LOG(FATAL) << "Unknown if condition";
199 }
200 return kEqual;
201}
202
Nicolas Geoffraya7062e02014-05-22 12:50:17 +0100203void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
204 stream << X86ManagedRegister::FromCpuRegister(Register(reg));
205}
206
207void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
208 stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
209}
210
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100211size_t CodeGeneratorX86::SaveCoreRegister(size_t stack_index, uint32_t reg_id) {
212 __ movl(Address(ESP, stack_index), static_cast<Register>(reg_id));
213 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100214}
215
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100216size_t CodeGeneratorX86::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) {
217 __ movl(static_cast<Register>(reg_id), Address(ESP, stack_index));
218 return kX86WordSize;
Nicolas Geoffray3bca0df2014-09-19 11:01:00 +0100219}
220
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100221CodeGeneratorX86::CodeGeneratorX86(HGraph* graph)
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100222 : CodeGenerator(graph, kNumberOfCpuRegisters, kNumberOfXmmRegisters, kNumberOfRegisterPairs),
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100223 block_labels_(graph->GetArena(), 0),
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100224 location_builder_(graph, this),
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100225 instruction_visitor_(graph, this),
226 move_resolver_(graph->GetArena(), this) {}
227
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +0100228size_t CodeGeneratorX86::FrameEntrySpillSize() const {
229 return kNumberOfPushedRegistersAtEntry * kX86WordSize;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100230}
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100231
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100232Location CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type) const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100233 switch (type) {
234 case Primitive::kPrimLong: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100235 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100236 X86ManagedRegister pair =
237 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
Calin Juravle34bacdf2014-10-07 20:23:36 +0100238 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]);
239 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]);
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100240 blocked_core_registers_[pair.AsRegisterPairLow()] = true;
241 blocked_core_registers_[pair.AsRegisterPairHigh()] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100242 UpdateBlockedPairRegisters();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100243 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100244 }
245
246 case Primitive::kPrimByte:
247 case Primitive::kPrimBoolean:
248 case Primitive::kPrimChar:
249 case Primitive::kPrimShort:
250 case Primitive::kPrimInt:
251 case Primitive::kPrimNot: {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100252 Register reg = static_cast<Register>(
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100253 FindFreeEntry(blocked_core_registers_, kNumberOfCpuRegisters));
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100254 // Block all register pairs that contain `reg`.
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100255 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
256 X86ManagedRegister current =
257 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
258 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100259 blocked_register_pairs_[i] = true;
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100260 }
261 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100262 return Location::RegisterLocation(reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100263 }
264
265 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100266 case Primitive::kPrimDouble: {
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100267 return Location::FpuRegisterLocation(
268 FindFreeEntry(blocked_fpu_registers_, kNumberOfXmmRegisters));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100269 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100270
271 case Primitive::kPrimVoid:
272 LOG(FATAL) << "Unreachable type " << type;
273 }
274
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100275 return Location();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100276}
277
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100278void CodeGeneratorX86::SetupBlockedRegisters() const {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100279 // Don't allocate the dalvik style register pair passing.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100280 blocked_register_pairs_[ECX_EDX] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100281
282 // Stack register is always reserved.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100283 blocked_core_registers_[ESP] = true;
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100284
285 // TODO: We currently don't use Quick's callee saved registers.
Nicolas Geoffray71175b72014-10-09 22:13:55 +0100286 blocked_core_registers_[EBP] = true;
287 blocked_core_registers_[ESI] = true;
288 blocked_core_registers_[EDI] = true;
Calin Juravle34bacdf2014-10-07 20:23:36 +0100289
290 UpdateBlockedPairRegisters();
291}
292
293void CodeGeneratorX86::UpdateBlockedPairRegisters() const {
294 for (int i = 0; i < kNumberOfRegisterPairs; i++) {
295 X86ManagedRegister current =
296 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i));
297 if (blocked_core_registers_[current.AsRegisterPairLow()]
298 || blocked_core_registers_[current.AsRegisterPairHigh()]) {
299 blocked_register_pairs_[i] = true;
300 }
301 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100302}
303
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100304InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
305 : HGraphVisitor(graph),
306 assembler_(codegen->GetAssembler()),
307 codegen_(codegen) {}
308
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000309void CodeGeneratorX86::GenerateFrameEntry() {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000310 // Create a fake register to mimic Quick.
311 static const int kFakeReturnRegister = 8;
312 core_spill_mask_ |= (1 << kFakeReturnRegister);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000313
Dave Allison648d7112014-07-25 16:15:27 -0700314 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100315 if (!skip_overflow_check && !kExplicitStackOverflowCheck) {
316 __ testl(EAX, Address(ESP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86))));
Nicolas Geoffray39468442014-09-02 15:17:15 +0100317 RecordPcInfo(nullptr, 0);
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100318 }
319
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100320 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100321 __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100322
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100323 if (!skip_overflow_check && kExplicitStackOverflowCheck) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100324 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86();
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100325 AddSlowPath(slow_path);
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100326
Nicolas Geoffray397f2e42014-07-23 12:57:19 +0100327 __ fs()->cmpl(ESP, Address::Absolute(Thread::StackEndOffset<kX86WordSize>()));
328 __ j(kLess, slow_path->GetEntryLabel());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +0100329 }
330
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100331 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000332}
333
334void CodeGeneratorX86::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100335 __ addl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000336}
337
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +0100338void CodeGeneratorX86::Bind(HBasicBlock* block) {
339 __ Bind(GetLabelOf(block));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000340}
341
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100342void CodeGeneratorX86::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100343 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000344}
345
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100346Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
347 switch (load->GetType()) {
348 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100349 case Primitive::kPrimDouble:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100350 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
351 break;
352
353 case Primitive::kPrimInt:
354 case Primitive::kPrimNot:
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100355 case Primitive::kPrimFloat:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100356 return Location::StackSlot(GetStackSlot(load->GetLocal()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100357
358 case Primitive::kPrimBoolean:
359 case Primitive::kPrimByte:
360 case Primitive::kPrimChar:
361 case Primitive::kPrimShort:
362 case Primitive::kPrimVoid:
363 LOG(FATAL) << "Unexpected type " << load->GetType();
364 }
365
366 LOG(FATAL) << "Unreachable";
367 return Location();
368}
369
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100370Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
371 switch (type) {
372 case Primitive::kPrimBoolean:
373 case Primitive::kPrimByte:
374 case Primitive::kPrimChar:
375 case Primitive::kPrimShort:
376 case Primitive::kPrimInt:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100377 case Primitive::kPrimFloat:
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100378 case Primitive::kPrimNot: {
379 uint32_t index = gp_index_++;
380 if (index < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100381 return Location::RegisterLocation(calling_convention.GetRegisterAt(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100382 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100383 return Location::StackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100384 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100385 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100386
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100387 case Primitive::kPrimLong:
388 case Primitive::kPrimDouble: {
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100389 uint32_t index = gp_index_;
390 gp_index_ += 2;
391 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100392 X86ManagedRegister pair = X86ManagedRegister::FromRegisterPair(
393 calling_convention.GetRegisterPairAt(index));
394 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100395 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000396 // On X86, the register index and stack index of a quick parameter is the same, since
397 // we are passing floating pointer values in core registers.
398 return Location::QuickParameter(index, index);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100399 } else {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100400 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100401 }
402 }
403
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100404 case Primitive::kPrimVoid:
405 LOG(FATAL) << "Unexpected parameter type " << type;
406 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100407 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100408 return Location();
409}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100410
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100411void CodeGeneratorX86::Move32(Location destination, Location source) {
412 if (source.Equals(destination)) {
413 return;
414 }
415 if (destination.IsRegister()) {
416 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100417 __ movl(destination.As<Register>(), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100418 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100419 __ movd(destination.As<Register>(), source.As<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100420 } else {
421 DCHECK(source.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100422 __ movl(destination.As<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100423 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100424 } else if (destination.IsFpuRegister()) {
425 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100426 __ movd(destination.As<XmmRegister>(), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100427 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100428 __ movaps(destination.As<XmmRegister>(), source.As<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100429 } else {
430 DCHECK(source.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100431 __ movss(destination.As<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100432 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100433 } else {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100434 DCHECK(destination.IsStackSlot());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100435 if (source.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100436 __ movl(Address(ESP, destination.GetStackIndex()), source.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100437 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100438 __ movss(Address(ESP, destination.GetStackIndex()), source.As<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100439 } else {
440 DCHECK(source.IsStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100441 __ pushl(Address(ESP, source.GetStackIndex()));
442 __ popl(Address(ESP, destination.GetStackIndex()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100443 }
444 }
445}
446
447void CodeGeneratorX86::Move64(Location destination, Location source) {
448 if (source.Equals(destination)) {
449 return;
450 }
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100451 if (destination.IsRegisterPair()) {
452 if (source.IsRegisterPair()) {
453 __ movl(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
454 __ movl(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100455 } else if (source.IsFpuRegister()) {
456 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100457 } else if (source.IsQuickParameter()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000458 uint16_t register_index = source.GetQuickParameterRegisterIndex();
459 uint16_t stack_index = source.GetQuickParameterStackIndex();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100460 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100461 __ movl(destination.AsRegisterPairLow<Register>(),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000462 calling_convention.GetRegisterAt(register_index));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100463 __ movl(destination.AsRegisterPairHigh<Register>(), Address(ESP,
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000464 calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100465 } else {
466 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100467 __ movl(destination.AsRegisterPairLow<Register>(), Address(ESP, source.GetStackIndex()));
468 __ movl(destination.AsRegisterPairHigh<Register>(),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100469 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
470 }
471 } else if (destination.IsQuickParameter()) {
472 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000473 uint16_t register_index = destination.GetQuickParameterRegisterIndex();
474 uint16_t stack_index = destination.GetQuickParameterStackIndex();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100475 if (source.IsRegister()) {
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000476 __ movl(calling_convention.GetRegisterAt(register_index), source.AsRegisterPairLow<Register>());
477 __ movl(Address(ESP, calling_convention.GetStackOffsetOf(stack_index + 1)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100478 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100479 } else if (source.IsFpuRegister()) {
480 LOG(FATAL) << "Unimplemented";
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100481 } else {
482 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000483 __ movl(calling_convention.GetRegisterAt(register_index),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100484 Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100485 __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000486 __ popl(Address(ESP, calling_convention.GetStackOffsetOf(stack_index + 1)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100487 }
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100488 } else if (destination.IsFpuRegister()) {
489 if (source.IsDoubleStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100490 __ movsd(destination.As<XmmRegister>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100491 } else {
492 LOG(FATAL) << "Unimplemented";
493 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100494 } else {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100495 DCHECK(destination.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100496 if (source.IsRegisterPair()) {
497 __ movl(Address(ESP, destination.GetStackIndex()), source.AsRegisterPairLow<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100498 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100499 source.AsRegisterPairHigh<Register>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100500 } else if (source.IsQuickParameter()) {
501 InvokeDexCallingConvention calling_convention;
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000502 uint16_t register_index = source.GetQuickParameterRegisterIndex();
503 uint16_t stack_index = source.GetQuickParameterStackIndex();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100504 __ movl(Address(ESP, destination.GetStackIndex()),
Nicolas Geoffray0a6c4592014-10-30 16:37:57 +0000505 calling_convention.GetRegisterAt(register_index));
506 DCHECK_EQ(calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100507 static_cast<size_t>(destination.GetHighStackIndex(kX86WordSize)));
508 } else if (source.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100509 __ movsd(Address(ESP, destination.GetStackIndex()), source.As<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100510 } else {
511 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +0100512 __ pushl(Address(ESP, source.GetStackIndex()));
513 __ popl(Address(ESP, destination.GetStackIndex()));
514 __ pushl(Address(ESP, source.GetHighStackIndex(kX86WordSize)));
515 __ popl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100516 }
517 }
518}
519
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100520void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
Roland Levillain476df552014-10-09 17:51:36 +0100521 if (instruction->IsIntConstant()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100522 Immediate imm(instruction->AsIntConstant()->GetValue());
523 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100524 __ movl(location.As<Register>(), imm);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +0100525 } else if (location.IsStackSlot()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100526 __ movl(Address(ESP, location.GetStackIndex()), imm);
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +0100527 } else {
528 DCHECK(location.IsConstant());
529 DCHECK_EQ(location.GetConstant(), instruction);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100530 }
Roland Levillain476df552014-10-09 17:51:36 +0100531 } else if (instruction->IsLongConstant()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100532 int64_t value = instruction->AsLongConstant()->GetValue();
533 if (location.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100534 __ movl(location.AsRegisterPairLow<Register>(), Immediate(Low32Bits(value)));
535 __ movl(location.AsRegisterPairHigh<Register>(), Immediate(High32Bits(value)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +0100536 } else if (location.IsDoubleStackSlot()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100537 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
538 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +0100539 } else {
540 DCHECK(location.IsConstant());
541 DCHECK_EQ(location.GetConstant(), instruction);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100542 }
Roland Levillain476df552014-10-09 17:51:36 +0100543 } else if (instruction->IsLoadLocal()) {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100544 int slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100545 switch (instruction->GetType()) {
546 case Primitive::kPrimBoolean:
547 case Primitive::kPrimByte:
548 case Primitive::kPrimChar:
549 case Primitive::kPrimShort:
550 case Primitive::kPrimInt:
551 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100552 case Primitive::kPrimFloat:
553 Move32(location, Location::StackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100554 break;
555
556 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100557 case Primitive::kPrimDouble:
558 Move64(location, Location::DoubleStackSlot(slot));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100559 break;
560
561 default:
562 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
563 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000564 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100565 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100566 switch (instruction->GetType()) {
567 case Primitive::kPrimBoolean:
568 case Primitive::kPrimByte:
569 case Primitive::kPrimChar:
570 case Primitive::kPrimShort:
571 case Primitive::kPrimInt:
572 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100573 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100574 Move32(location, instruction->GetLocations()->Out());
575 break;
576
577 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100578 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100579 Move64(location, instruction->GetLocations()->Out());
580 break;
581
582 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100583 LOG(FATAL) << "Unexpected type " << instruction->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100584 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000585 }
586}
587
588void LocationsBuilderX86::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000589 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000590}
591
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000592void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000593 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray3c049742014-09-24 18:10:46 +0100594 DCHECK(!successor->IsExitBlock());
595
596 HBasicBlock* block = got->GetBlock();
597 HInstruction* previous = got->GetPrevious();
598
599 HLoopInformation* info = block->GetLoopInformation();
600 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) {
601 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck());
602 GenerateSuspendCheck(info->GetSuspendCheck(), successor);
603 return;
604 }
605
606 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) {
607 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr);
608 }
609 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000610 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000611 }
612}
613
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000614void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000615 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000616}
617
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000618void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000619 if (kIsDebugBuild) {
620 __ Comment("Unreachable");
621 __ int3();
622 }
623}
624
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000625void LocationsBuilderX86::VisitIf(HIf* if_instr) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100626 LocationSummary* locations =
627 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100628 HInstruction* cond = if_instr->InputAt(0);
Nicolas Geoffray01ef3452014-10-01 11:32:17 +0100629 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100630 locations->SetInAt(0, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100631 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000632}
633
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000634void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700635 HInstruction* cond = if_instr->InputAt(0);
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100636 if (cond->IsIntConstant()) {
637 // Constant condition, statically compared against 1.
638 int32_t cond_value = cond->AsIntConstant()->GetValue();
639 if (cond_value == 1) {
640 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
641 if_instr->IfTrueSuccessor())) {
642 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100643 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100644 return;
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100645 } else {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100646 DCHECK_EQ(cond_value, 0);
647 }
648 } else {
649 bool materialized =
650 !cond->IsCondition() || cond->AsCondition()->NeedsMaterialization();
651 // Moves do not affect the eflags register, so if the condition is
652 // evaluated just before the if, we don't need to evaluate it
653 // again.
654 bool eflags_set = cond->IsCondition()
655 && cond->AsCondition()->IsBeforeWhenDisregardMoves(if_instr);
656 if (materialized) {
657 if (!eflags_set) {
658 // Materialized condition, compare against 0.
659 Location lhs = if_instr->GetLocations()->InAt(0);
660 if (lhs.IsRegister()) {
661 __ cmpl(lhs.As<Register>(), Immediate(0));
662 } else {
663 __ cmpl(Address(ESP, lhs.GetStackIndex()), Immediate(0));
664 }
665 __ j(kNotEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
666 } else {
667 __ j(X86Condition(cond->AsCondition()->GetCondition()),
668 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
669 }
670 } else {
671 Location lhs = cond->GetLocations()->InAt(0);
672 Location rhs = cond->GetLocations()->InAt(1);
673 // LHS is guaranteed to be in a register (see
674 // LocationsBuilderX86::VisitCondition).
675 if (rhs.IsRegister()) {
676 __ cmpl(lhs.As<Register>(), rhs.As<Register>());
677 } else if (rhs.IsConstant()) {
678 HIntConstant* instruction = rhs.GetConstant()->AsIntConstant();
679 Immediate imm(instruction->AsIntConstant()->GetValue());
680 __ cmpl(lhs.As<Register>(), imm);
681 } else {
682 __ cmpl(lhs.As<Register>(), Address(ESP, rhs.GetStackIndex()));
683 }
Nicolas Geoffray360231a2014-10-08 21:07:48 +0100684 __ j(X86Condition(cond->AsCondition()->GetCondition()),
685 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Dave Allison20dfc792014-06-16 20:44:29 -0700686 }
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100687 }
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100688 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(),
689 if_instr->IfFalseSuccessor())) {
Dave Allison20dfc792014-06-16 20:44:29 -0700690 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000691 }
692}
693
694void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000695 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000696}
697
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000698void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
699 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000700}
701
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000702void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100703 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000704}
705
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000706void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100707 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000708}
709
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100710void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100711 LocationSummary* locations =
712 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100713 switch (store->InputAt(1)->GetType()) {
714 case Primitive::kPrimBoolean:
715 case Primitive::kPrimByte:
716 case Primitive::kPrimChar:
717 case Primitive::kPrimShort:
718 case Primitive::kPrimInt:
719 case Primitive::kPrimNot:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100720 case Primitive::kPrimFloat:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100721 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
722 break;
723
724 case Primitive::kPrimLong:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100725 case Primitive::kPrimDouble:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100726 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
727 break;
728
729 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100730 LOG(FATAL) << "Unknown local type " << store->InputAt(1)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100731 }
732 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000733}
734
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000735void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000736}
737
Dave Allison20dfc792014-06-16 20:44:29 -0700738void LocationsBuilderX86::VisitCondition(HCondition* comp) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100739 LocationSummary* locations =
740 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +0100741 locations->SetInAt(0, Location::RequiresRegister());
742 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100743 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100744 locations->SetOut(Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100745 }
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000746}
747
Dave Allison20dfc792014-06-16 20:44:29 -0700748void InstructionCodeGeneratorX86::VisitCondition(HCondition* comp) {
749 if (comp->NeedsMaterialization()) {
750 LocationSummary* locations = comp->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100751 Register reg = locations->Out().As<Register>();
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100752 // Clear register: setcc only sets the low byte.
753 __ xorl(reg, reg);
Dave Allison20dfc792014-06-16 20:44:29 -0700754 if (locations->InAt(1).IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100755 __ cmpl(locations->InAt(0).As<Register>(),
756 locations->InAt(1).As<Register>());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100757 } else if (locations->InAt(1).IsConstant()) {
758 HConstant* instruction = locations->InAt(1).GetConstant();
759 Immediate imm(instruction->AsIntConstant()->GetValue());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100760 __ cmpl(locations->InAt(0).As<Register>(), imm);
Dave Allison20dfc792014-06-16 20:44:29 -0700761 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100762 __ cmpl(locations->InAt(0).As<Register>(),
Dave Allison20dfc792014-06-16 20:44:29 -0700763 Address(ESP, locations->InAt(1).GetStackIndex()));
764 }
Nicolas Geoffray18efde52014-09-22 15:51:11 +0100765 __ setb(X86Condition(comp->GetCondition()), reg);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100766 }
Dave Allison20dfc792014-06-16 20:44:29 -0700767}
768
769void LocationsBuilderX86::VisitEqual(HEqual* comp) {
770 VisitCondition(comp);
771}
772
773void InstructionCodeGeneratorX86::VisitEqual(HEqual* comp) {
774 VisitCondition(comp);
775}
776
777void LocationsBuilderX86::VisitNotEqual(HNotEqual* comp) {
778 VisitCondition(comp);
779}
780
781void InstructionCodeGeneratorX86::VisitNotEqual(HNotEqual* comp) {
782 VisitCondition(comp);
783}
784
785void LocationsBuilderX86::VisitLessThan(HLessThan* comp) {
786 VisitCondition(comp);
787}
788
789void InstructionCodeGeneratorX86::VisitLessThan(HLessThan* comp) {
790 VisitCondition(comp);
791}
792
793void LocationsBuilderX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
794 VisitCondition(comp);
795}
796
797void InstructionCodeGeneratorX86::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
798 VisitCondition(comp);
799}
800
801void LocationsBuilderX86::VisitGreaterThan(HGreaterThan* comp) {
802 VisitCondition(comp);
803}
804
805void InstructionCodeGeneratorX86::VisitGreaterThan(HGreaterThan* comp) {
806 VisitCondition(comp);
807}
808
809void LocationsBuilderX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
810 VisitCondition(comp);
811}
812
813void InstructionCodeGeneratorX86::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
814 VisitCondition(comp);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000815}
816
817void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100818 LocationSummary* locations =
819 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100820 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000821}
822
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000823void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Roland Levillain3a3fd0f2014-10-10 13:56:31 +0100824 // Will be generated at use site.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000825}
826
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100827void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100828 LocationSummary* locations =
829 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100830 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100831}
832
833void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
834 // Will be generated at use site.
835}
836
Nicolas Geoffray102cbed2014-10-15 18:31:05 +0100837void LocationsBuilderX86::VisitFloatConstant(HFloatConstant* constant) {
838 LocationSummary* locations =
839 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
840 locations->SetOut(Location::ConstantLocation(constant));
841}
842
843void InstructionCodeGeneratorX86::VisitFloatConstant(HFloatConstant* constant) {
844 // Will be generated at use site.
845}
846
847void LocationsBuilderX86::VisitDoubleConstant(HDoubleConstant* constant) {
848 LocationSummary* locations =
849 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall);
850 locations->SetOut(Location::ConstantLocation(constant));
851}
852
853void InstructionCodeGeneratorX86::VisitDoubleConstant(HDoubleConstant* constant) {
854 // Will be generated at use site.
855}
856
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000857void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000858 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000859}
860
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000861void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
862 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000863 __ ret();
864}
865
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000866void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100867 LocationSummary* locations =
868 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100869 switch (ret->InputAt(0)->GetType()) {
870 case Primitive::kPrimBoolean:
871 case Primitive::kPrimByte:
872 case Primitive::kPrimChar:
873 case Primitive::kPrimShort:
874 case Primitive::kPrimInt:
875 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100876 locations->SetInAt(0, Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100877 break;
878
879 case Primitive::kPrimLong:
880 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100881 0, Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100882 break;
883
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100884 case Primitive::kPrimFloat:
885 case Primitive::kPrimDouble:
886 locations->SetInAt(
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100887 0, Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100888 break;
889
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100890 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100891 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100892 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000893}
894
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000895void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100896 if (kIsDebugBuild) {
897 switch (ret->InputAt(0)->GetType()) {
898 case Primitive::kPrimBoolean:
899 case Primitive::kPrimByte:
900 case Primitive::kPrimChar:
901 case Primitive::kPrimShort:
902 case Primitive::kPrimInt:
903 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100904 DCHECK_EQ(ret->GetLocations()->InAt(0).As<Register>(), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100905 break;
906
907 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100908 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairLow<Register>(), EAX);
909 DCHECK_EQ(ret->GetLocations()->InAt(0).AsRegisterPairHigh<Register>(), EDX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100910 break;
911
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100912 case Primitive::kPrimFloat:
913 case Primitive::kPrimDouble:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100914 DCHECK_EQ(ret->GetLocations()->InAt(0).As<XmmRegister>(), XMM0);
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100915 break;
916
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100917 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +0100918 LOG(FATAL) << "Unknown return type " << ret->InputAt(0)->GetType();
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100919 }
920 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000921 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000922 __ ret();
923}
924
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000925void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100926 HandleInvoke(invoke);
927}
928
929void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100930 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100931
932 // TODO: Implement all kinds of calls:
933 // 1) boot -> boot
934 // 2) app -> boot
935 // 3) app -> app
936 //
937 // Currently we implement the app -> app logic, which looks up in the resolve cache.
938
939 // temp = method;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100940 codegen_->LoadCurrentMethod(temp);
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100941 // temp = temp->dex_cache_resolved_methods_;
942 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
943 // temp = temp[index_in_cache]
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +0100944 __ movl(temp, Address(temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache())));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100945 // (temp + offset_of_quick_compiled_code)()
946 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
947
948 DCHECK(!codegen_->IsLeafMethod());
949 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
950}
951
952void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
953 HandleInvoke(invoke);
954}
955
956void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
Nicolas Geoffray39468442014-09-02 15:17:15 +0100957 LocationSummary* locations =
958 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100959 locations->AddTemp(Location::RegisterLocation(EAX));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100960
961 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100962 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100963 HInstruction* input = invoke->InputAt(i);
964 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
965 }
966
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100967 switch (invoke->GetType()) {
968 case Primitive::kPrimBoolean:
969 case Primitive::kPrimByte:
970 case Primitive::kPrimChar:
971 case Primitive::kPrimShort:
972 case Primitive::kPrimInt:
973 case Primitive::kPrimNot:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100974 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100975 break;
976
977 case Primitive::kPrimLong:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100978 locations->SetOut(Location::RegisterPairLocation(EAX, EDX));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100979 break;
980
981 case Primitive::kPrimVoid:
982 break;
983
984 case Primitive::kPrimDouble:
985 case Primitive::kPrimFloat:
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100986 locations->SetOut(Location::FpuRegisterLocation(XMM0));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100987 break;
988 }
989
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000990 invoke->SetLocations(locations);
991}
992
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100993void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +0100994 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>();
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +0100995 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
996 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
997 LocationSummary* locations = invoke->GetLocations();
998 Location receiver = locations->InAt(0);
999 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
1000 // temp = object->GetClass();
1001 if (receiver.IsStackSlot()) {
1002 __ movl(temp, Address(ESP, receiver.GetStackIndex()));
1003 __ movl(temp, Address(temp, class_offset));
1004 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001005 __ movl(temp, Address(receiver.As<Register>(), class_offset));
Nicolas Geoffraye982f0b2014-08-13 02:11:24 +01001006 }
1007 // temp = temp->GetMethodAt(method_offset);
1008 __ movl(temp, Address(temp, method_offset));
1009 // call temp->GetEntryPoint();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001010 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
1011
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001012 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001013 codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +00001014}
1015
Roland Levillain88cb1752014-10-20 16:36:47 +01001016void LocationsBuilderX86::VisitNeg(HNeg* neg) {
1017 LocationSummary* locations =
1018 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall);
1019 switch (neg->GetResultType()) {
1020 case Primitive::kPrimInt:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001021 case Primitive::kPrimLong:
Roland Levillain88cb1752014-10-20 16:36:47 +01001022 locations->SetInAt(0, Location::RequiresRegister());
1023 locations->SetOut(Location::SameAsFirstInput());
1024 break;
1025
Roland Levillain88cb1752014-10-20 16:36:47 +01001026 case Primitive::kPrimFloat:
1027 case Primitive::kPrimDouble:
1028 LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
1029 break;
1030
1031 default:
1032 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1033 }
1034}
1035
1036void InstructionCodeGeneratorX86::VisitNeg(HNeg* neg) {
1037 LocationSummary* locations = neg->GetLocations();
1038 Location out = locations->Out();
1039 Location in = locations->InAt(0);
1040 switch (neg->GetResultType()) {
1041 case Primitive::kPrimInt:
1042 DCHECK(in.IsRegister());
1043 __ negl(out.As<Register>());
1044 break;
1045
1046 case Primitive::kPrimLong:
Roland Levillain2e07b4f2014-10-23 18:12:09 +01001047 DCHECK(in.IsRegisterPair());
1048 __ negl(out.AsRegisterPairLow<Register>());
1049 // Negation is similar to subtraction from zero. The least
1050 // significant byte triggers a borrow when it is different from
1051 // zero; to take it into account, add 1 to the most significant
1052 // byte if the carry flag (CF) is set to 1 after the first NEGL
1053 // operation.
1054 __ adcl(out.AsRegisterPairHigh<Register>(), Immediate(0));
1055 __ negl(out.AsRegisterPairHigh<Register>());
1056 break;
1057
Roland Levillain88cb1752014-10-20 16:36:47 +01001058 case Primitive::kPrimFloat:
1059 case Primitive::kPrimDouble:
1060 LOG(FATAL) << "Not yet implemented neg type " << neg->GetResultType();
1061 break;
1062
1063 default:
1064 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType();
1065 }
1066}
1067
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001068void LocationsBuilderX86::VisitAdd(HAdd* add) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001069 LocationSummary* locations =
1070 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall);
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001071 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001072 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001073 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001074 locations->SetInAt(0, Location::RequiresRegister());
1075 locations->SetInAt(1, Location::Any());
1076 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001077 break;
1078 }
1079
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001080 case Primitive::kPrimFloat:
1081 case Primitive::kPrimDouble: {
1082 locations->SetInAt(0, Location::RequiresFpuRegister());
1083 locations->SetInAt(1, Location::Any());
1084 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001085 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001086 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001087
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001088 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001089 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
1090 break;
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001091 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001092}
1093
1094void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
1095 LocationSummary* locations = add->GetLocations();
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001096 Location first = locations->InAt(0);
1097 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01001098 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001099 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001100 case Primitive::kPrimInt: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001101 if (second.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001102 __ addl(first.As<Register>(), second.As<Register>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001103 } else if (second.IsConstant()) {
Calin Juravle11351682014-10-23 15:38:15 +01001104 __ addl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001105 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001106 __ addl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001107 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001108 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001109 }
1110
1111 case Primitive::kPrimLong: {
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001112 if (second.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001113 __ addl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1114 __ adcl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001115 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001116 __ addl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
1117 __ adcl(first.AsRegisterPairHigh<Register>(),
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001118 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001119 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001120 break;
1121 }
1122
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001123 case Primitive::kPrimFloat: {
1124 if (second.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001125 __ addss(first.As<XmmRegister>(), second.As<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001126 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001127 __ addss(first.As<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001128 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001129 break;
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001130 }
1131
1132 case Primitive::kPrimDouble: {
1133 if (second.IsFpuRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001134 __ addsd(first.As<XmmRegister>(), second.As<XmmRegister>());
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001135 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001136 __ addsd(first.As<XmmRegister>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001137 }
1138 break;
1139 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001140
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001141 default:
Nicolas Geoffray7fb49da2014-10-06 09:12:41 +01001142 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +00001143 }
1144}
1145
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001146void LocationsBuilderX86::VisitSub(HSub* sub) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001147 LocationSummary* locations =
1148 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001149 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001150 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001151 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001152 locations->SetInAt(0, Location::RequiresRegister());
1153 locations->SetInAt(1, Location::Any());
1154 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001155 break;
1156 }
Calin Juravle11351682014-10-23 15:38:15 +01001157 case Primitive::kPrimFloat:
1158 case Primitive::kPrimDouble: {
1159 locations->SetInAt(0, Location::RequiresFpuRegister());
1160 locations->SetInAt(1, Location::RequiresFpuRegister());
1161 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001162 break;
Calin Juravle11351682014-10-23 15:38:15 +01001163 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001164
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001165 default:
Calin Juravle11351682014-10-23 15:38:15 +01001166 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001167 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001168}
1169
1170void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
1171 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001172 Location first = locations->InAt(0);
1173 Location second = locations->InAt(1);
Calin Juravle11351682014-10-23 15:38:15 +01001174 DCHECK(first.Equals(locations->Out()));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001175 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001176 case Primitive::kPrimInt: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001177 if (second.IsRegister()) {
Calin Juravle11351682014-10-23 15:38:15 +01001178 __ subl(first.As<Register>(), second.As<Register>());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001179 } else if (second.IsConstant()) {
Calin Juravle11351682014-10-23 15:38:15 +01001180 __ subl(first.As<Register>(), Immediate(second.GetConstant()->AsIntConstant()->GetValue()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001181 } else {
Calin Juravle11351682014-10-23 15:38:15 +01001182 __ subl(first.As<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001183 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001184 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001185 }
1186
1187 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001188 if (second.IsRegister()) {
Calin Juravle11351682014-10-23 15:38:15 +01001189 __ subl(first.AsRegisterPairLow<Register>(), second.AsRegisterPairLow<Register>());
1190 __ sbbl(first.AsRegisterPairHigh<Register>(), second.AsRegisterPairHigh<Register>());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001191 } else {
Calin Juravle11351682014-10-23 15:38:15 +01001192 __ subl(first.AsRegisterPairLow<Register>(), Address(ESP, second.GetStackIndex()));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001193 __ sbbl(first.AsRegisterPairHigh<Register>(),
1194 Address(ESP, second.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001195 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001196 break;
1197 }
1198
Calin Juravle11351682014-10-23 15:38:15 +01001199 case Primitive::kPrimFloat: {
1200 __ subss(first.As<XmmRegister>(), second.As<XmmRegister>());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001201 break;
Calin Juravle11351682014-10-23 15:38:15 +01001202 }
1203
1204 case Primitive::kPrimDouble: {
1205 __ subsd(first.As<XmmRegister>(), second.As<XmmRegister>());
1206 break;
1207 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +01001208
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001209 default:
Calin Juravle11351682014-10-23 15:38:15 +01001210 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001211 }
1212}
1213
Calin Juravle34bacdf2014-10-07 20:23:36 +01001214void LocationsBuilderX86::VisitMul(HMul* mul) {
1215 LocationSummary* locations =
1216 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall);
1217 switch (mul->GetResultType()) {
1218 case Primitive::kPrimInt:
1219 locations->SetInAt(0, Location::RequiresRegister());
1220 locations->SetInAt(1, Location::Any());
1221 locations->SetOut(Location::SameAsFirstInput());
1222 break;
1223 case Primitive::kPrimLong: {
1224 locations->SetInAt(0, Location::RequiresRegister());
1225 // TODO: Currently this handles only stack operands:
1226 // - we don't have enough registers because we currently use Quick ABI.
1227 // - by the time we have a working register allocator we will probably change the ABI
1228 // and fix the above.
1229 // - we don't have a way yet to request operands on stack but the base line compiler
1230 // will leave the operands on the stack with Any().
1231 locations->SetInAt(1, Location::Any());
1232 locations->SetOut(Location::SameAsFirstInput());
1233 // Needed for imul on 32bits with 64bits output.
1234 locations->AddTemp(Location::RegisterLocation(EAX));
1235 locations->AddTemp(Location::RegisterLocation(EDX));
1236 break;
1237 }
Calin Juravleb5bfa962014-10-21 18:02:24 +01001238 case Primitive::kPrimFloat:
1239 case Primitive::kPrimDouble: {
1240 locations->SetInAt(0, Location::RequiresFpuRegister());
1241 locations->SetInAt(1, Location::RequiresFpuRegister());
1242 locations->SetOut(Location::SameAsFirstInput());
Calin Juravle34bacdf2014-10-07 20:23:36 +01001243 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001244 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001245
1246 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001247 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001248 }
1249}
1250
1251void InstructionCodeGeneratorX86::VisitMul(HMul* mul) {
1252 LocationSummary* locations = mul->GetLocations();
1253 Location first = locations->InAt(0);
1254 Location second = locations->InAt(1);
1255 DCHECK(first.Equals(locations->Out()));
1256
1257 switch (mul->GetResultType()) {
1258 case Primitive::kPrimInt: {
1259 if (second.IsRegister()) {
1260 __ imull(first.As<Register>(), second.As<Register>());
1261 } else if (second.IsConstant()) {
1262 Immediate imm(second.GetConstant()->AsIntConstant()->GetValue());
1263 __ imull(first.As<Register>(), imm);
1264 } else {
1265 DCHECK(second.IsStackSlot());
1266 __ imull(first.As<Register>(), Address(ESP, second.GetStackIndex()));
1267 }
1268 break;
1269 }
1270
1271 case Primitive::kPrimLong: {
1272 DCHECK(second.IsDoubleStackSlot());
1273
1274 Register in1_hi = first.AsRegisterPairHigh<Register>();
1275 Register in1_lo = first.AsRegisterPairLow<Register>();
1276 Address in2_hi(ESP, second.GetHighStackIndex(kX86WordSize));
1277 Address in2_lo(ESP, second.GetStackIndex());
1278 Register eax = locations->GetTemp(0).As<Register>();
1279 Register edx = locations->GetTemp(1).As<Register>();
1280
1281 DCHECK_EQ(EAX, eax);
1282 DCHECK_EQ(EDX, edx);
1283
1284 // input: in1 - 64 bits, in2 - 64 bits
1285 // output: in1
1286 // formula: in1.hi : in1.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo
1287 // parts: in1.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32]
1288 // parts: in1.lo = (in1.lo * in2.lo)[31:0]
1289
1290 __ movl(eax, in2_hi);
1291 // eax <- in1.lo * in2.hi
1292 __ imull(eax, in1_lo);
1293 // in1.hi <- in1.hi * in2.lo
1294 __ imull(in1_hi, in2_lo);
1295 // in1.hi <- in1.lo * in2.hi + in1.hi * in2.lo
1296 __ addl(in1_hi, eax);
1297 // move in1_lo to eax to prepare for double precision
1298 __ movl(eax, in1_lo);
1299 // edx:eax <- in1.lo * in2.lo
1300 __ mull(in2_lo);
1301 // in1.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32]
1302 __ addl(in1_hi, edx);
1303 // in1.lo <- (in1.lo * in2.lo)[31:0];
1304 __ movl(in1_lo, eax);
1305
1306 break;
1307 }
1308
Calin Juravleb5bfa962014-10-21 18:02:24 +01001309 case Primitive::kPrimFloat: {
1310 __ mulss(first.As<XmmRegister>(), second.As<XmmRegister>());
Calin Juravle34bacdf2014-10-07 20:23:36 +01001311 break;
Calin Juravleb5bfa962014-10-21 18:02:24 +01001312 }
1313
1314 case Primitive::kPrimDouble: {
1315 __ mulsd(first.As<XmmRegister>(), second.As<XmmRegister>());
1316 break;
1317 }
Calin Juravle34bacdf2014-10-07 20:23:36 +01001318
1319 default:
Calin Juravleb5bfa962014-10-21 18:02:24 +01001320 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType();
Calin Juravle34bacdf2014-10-07 20:23:36 +01001321 }
1322}
1323
Calin Juravle7c4954d2014-10-28 16:57:40 +00001324void LocationsBuilderX86::VisitDiv(HDiv* div) {
1325 LocationSummary* locations =
1326 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall);
1327 switch (div->GetResultType()) {
1328 case Primitive::kPrimInt:
1329 case Primitive::kPrimLong: {
1330 LOG(FATAL) << "Not implemented div type" << div->GetResultType();
1331 break;
1332 }
1333 case Primitive::kPrimFloat:
1334 case Primitive::kPrimDouble: {
1335 locations->SetInAt(0, Location::RequiresFpuRegister());
1336 locations->SetInAt(1, Location::RequiresFpuRegister());
1337 locations->SetOut(Location::SameAsFirstInput());
1338 break;
1339 }
1340
1341 default:
1342 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1343 }
1344}
1345
1346void InstructionCodeGeneratorX86::VisitDiv(HDiv* div) {
1347 LocationSummary* locations = div->GetLocations();
1348 Location first = locations->InAt(0);
1349 Location second = locations->InAt(1);
1350 DCHECK(first.Equals(locations->Out()));
1351
1352 switch (div->GetResultType()) {
1353 case Primitive::kPrimInt:
1354 case Primitive::kPrimLong: {
1355 LOG(FATAL) << "Not implemented div type" << div->GetResultType();
1356 break;
1357 }
1358
1359 case Primitive::kPrimFloat: {
1360 __ divss(first.As<XmmRegister>(), second.As<XmmRegister>());
1361 break;
1362 }
1363
1364 case Primitive::kPrimDouble: {
1365 __ divsd(first.As<XmmRegister>(), second.As<XmmRegister>());
1366 break;
1367 }
1368
1369 default:
1370 LOG(FATAL) << "Unexpected div type " << div->GetResultType();
1371 }
1372}
1373
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001374void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001375 LocationSummary* locations =
1376 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001377 locations->SetOut(Location::RegisterLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001378 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001379 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1380 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001381}
1382
1383void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
1384 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001385 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001386 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001387
Nicolas Geoffray707c8092014-04-04 10:50:14 +01001388 __ fs()->call(
1389 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocObjectWithAccessCheck)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001390
Nicolas Geoffray39468442014-09-02 15:17:15 +01001391 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffrayf12feb82014-07-17 18:32:41 +01001392 DCHECK(!codegen_->IsLeafMethod());
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +01001393}
1394
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001395void LocationsBuilderX86::VisitNewArray(HNewArray* instruction) {
1396 LocationSummary* locations =
1397 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall);
1398 locations->SetOut(Location::RegisterLocation(EAX));
1399 InvokeRuntimeCallingConvention calling_convention;
1400 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1401 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1402 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
1403}
1404
1405void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) {
1406 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01001407 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya3d05a42014-10-20 17:41:32 +01001408 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
1409
1410 __ fs()->call(
1411 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocArrayWithAccessCheck)));
1412
1413 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
1414 DCHECK(!codegen_->IsLeafMethod());
1415}
1416
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001417void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001418 LocationSummary* locations =
1419 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001420 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
1421 if (location.IsStackSlot()) {
1422 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
1423 } else if (location.IsDoubleStackSlot()) {
1424 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001425 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +01001426 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001427}
1428
1429void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +01001430}
1431
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001432void LocationsBuilderX86::VisitNot(HNot* not_) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001433 LocationSummary* locations =
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001434 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001435 locations->SetInAt(0, Location::RequiresRegister());
1436 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001437}
1438
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001439void InstructionCodeGeneratorX86::VisitNot(HNot* not_) {
1440 LocationSummary* locations = not_->GetLocations();
Roland Levillain70566432014-10-24 16:20:17 +01001441 Location in = locations->InAt(0);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +01001442 Location out = locations->Out();
Roland Levillain70566432014-10-24 16:20:17 +01001443 DCHECK(in.Equals(out));
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001444 switch (not_->InputAt(0)->GetType()) {
1445 case Primitive::kPrimBoolean:
1446 __ xorl(out.As<Register>(), Immediate(1));
1447 break;
1448
1449 case Primitive::kPrimInt:
1450 __ notl(out.As<Register>());
1451 break;
1452
1453 case Primitive::kPrimLong:
Roland Levillain70566432014-10-24 16:20:17 +01001454 __ notl(out.AsRegisterPairLow<Register>());
1455 __ notl(out.AsRegisterPairHigh<Register>());
Roland Levillain1cc5f2512014-10-22 18:06:21 +01001456 break;
1457
1458 default:
1459 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType();
1460 }
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +01001461}
1462
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001463void LocationsBuilderX86::VisitCompare(HCompare* compare) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001464 LocationSummary* locations =
1465 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001466 locations->SetInAt(0, Location::RequiresRegister());
1467 locations->SetInAt(1, Location::Any());
1468 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001469}
1470
1471void InstructionCodeGeneratorX86::VisitCompare(HCompare* compare) {
1472 Label greater, done;
1473 LocationSummary* locations = compare->GetLocations();
1474 switch (compare->InputAt(0)->GetType()) {
1475 case Primitive::kPrimLong: {
1476 Label less, greater, done;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001477 Register output = locations->Out().As<Register>();
1478 Location left = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001479 Location right = locations->InAt(1);
1480 if (right.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001481 __ cmpl(left.AsRegisterPairHigh<Register>(), right.AsRegisterPairHigh<Register>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001482 } else {
1483 DCHECK(right.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001484 __ cmpl(left.AsRegisterPairHigh<Register>(),
1485 Address(ESP, right.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001486 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001487 __ j(kLess, &less); // Signed compare.
1488 __ j(kGreater, &greater); // Signed compare.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001489 if (right.IsRegisterPair()) {
1490 __ cmpl(left.AsRegisterPairLow<Register>(), right.AsRegisterPairLow<Register>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001491 } else {
1492 DCHECK(right.IsDoubleStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001493 __ cmpl(left.AsRegisterPairLow<Register>(), Address(ESP, right.GetStackIndex()));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001494 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001495 __ movl(output, Immediate(0));
1496 __ j(kEqual, &done);
1497 __ j(kBelow, &less); // Unsigned compare.
1498
1499 __ Bind(&greater);
1500 __ movl(output, Immediate(1));
1501 __ jmp(&done);
1502
1503 __ Bind(&less);
1504 __ movl(output, Immediate(-1));
1505
1506 __ Bind(&done);
1507 break;
1508 }
1509 default:
1510 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
1511 }
1512}
1513
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001514void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001515 LocationSummary* locations =
1516 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray31d76b42014-06-09 15:02:22 +01001517 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
1518 locations->SetInAt(i, Location::Any());
1519 }
1520 locations->SetOut(Location::Any());
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001521}
1522
1523void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01001524 LOG(FATAL) << "Unreachable";
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +01001525}
1526
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001527void LocationsBuilderX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001528 LocationSummary* locations =
1529 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001530 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray39468442014-09-02 15:17:15 +01001531 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001532 bool is_object_type = field_type == Primitive::kPrimNot;
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01001533 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
1534 || (field_type == Primitive::kPrimByte);
1535 // The register allocator does not support multiple
1536 // inputs that die at entry with one in a specific register.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01001537 if (is_byte_type) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001538 // Ensure the value is in a byte register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001539 locations->SetInAt(1, Location::RegisterLocation(EAX));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001540 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001541 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001542 }
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001543 // Temporary registers for the write barrier.
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001544 if (is_object_type) {
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001545 locations->AddTemp(Location::RequiresRegister());
1546 // Ensure the card is in a byte register.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001547 locations->AddTemp(Location::RegisterLocation(ECX));
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +01001548 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001549}
1550
1551void InstructionCodeGeneratorX86::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
1552 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001553 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001554 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
Nicolas Geoffray39468442014-09-02 15:17:15 +01001555 Primitive::Type field_type = instruction->GetFieldType();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001556
1557 switch (field_type) {
1558 case Primitive::kPrimBoolean:
1559 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001560 ByteRegister value = locations->InAt(1).As<ByteRegister>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001561 __ movb(Address(obj, offset), value);
1562 break;
1563 }
1564
1565 case Primitive::kPrimShort:
1566 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001567 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001568 __ movw(Address(obj, offset), value);
1569 break;
1570 }
1571
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001572 case Primitive::kPrimInt:
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001573 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001574 Register value = locations->InAt(1).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001575 __ movl(Address(obj, offset), value);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001576
1577 if (field_type == Primitive::kPrimNot) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001578 Register temp = locations->GetTemp(0).As<Register>();
1579 Register card = locations->GetTemp(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001580 codegen_->MarkGCCard(temp, card, obj, value);
1581 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001582 break;
1583 }
1584
1585 case Primitive::kPrimLong: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001586 Location value = locations->InAt(1);
1587 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
1588 __ movl(Address(obj, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001589 break;
1590 }
1591
1592 case Primitive::kPrimFloat:
1593 case Primitive::kPrimDouble:
1594 LOG(FATAL) << "Unimplemented register type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001595 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001596 case Primitive::kPrimVoid:
1597 LOG(FATAL) << "Unreachable type " << field_type;
Ian Rogersfc787ec2014-10-09 21:56:44 -07001598 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001599 }
1600}
1601
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001602void CodeGeneratorX86::MarkGCCard(Register temp, Register card, Register object, Register value) {
1603 Label is_null;
1604 __ testl(value, value);
1605 __ j(kEqual, &is_null);
1606 __ fs()->movl(card, Address::Absolute(Thread::CardTableOffset<kX86WordSize>().Int32Value()));
1607 __ movl(temp, object);
1608 __ shrl(temp, Immediate(gc::accounting::CardTable::kCardShift));
1609 __ movb(Address(temp, card, TIMES_1, 0),
1610 X86ManagedRegister::FromCpuRegister(card).AsByteRegister());
1611 __ Bind(&is_null);
1612}
1613
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001614void LocationsBuilderX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001615 LocationSummary* locations =
1616 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001617 locations->SetInAt(0, Location::RequiresRegister());
1618 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001619}
1620
1621void InstructionCodeGeneratorX86::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1622 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001623 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001624 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
1625
1626 switch (instruction->GetType()) {
1627 case Primitive::kPrimBoolean: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001628 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001629 __ movzxb(out, Address(obj, offset));
1630 break;
1631 }
1632
1633 case Primitive::kPrimByte: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001634 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001635 __ movsxb(out, Address(obj, offset));
1636 break;
1637 }
1638
1639 case Primitive::kPrimShort: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001640 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001641 __ movsxw(out, Address(obj, offset));
1642 break;
1643 }
1644
1645 case Primitive::kPrimChar: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001646 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001647 __ movzxw(out, Address(obj, offset));
1648 break;
1649 }
1650
1651 case Primitive::kPrimInt:
1652 case Primitive::kPrimNot: {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001653 Register out = locations->Out().As<Register>();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001654 __ movl(out, Address(obj, offset));
1655 break;
1656 }
1657
1658 case Primitive::kPrimLong: {
1659 // TODO: support volatile.
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001660 __ movl(locations->Out().AsRegisterPairLow<Register>(), Address(obj, offset));
1661 __ movl(locations->Out().AsRegisterPairHigh<Register>(), Address(obj, kX86WordSize + offset));
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001662 break;
1663 }
1664
1665 case Primitive::kPrimFloat:
1666 case Primitive::kPrimDouble:
1667 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001668 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001669 case Primitive::kPrimVoid:
1670 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001671 UNREACHABLE();
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001672 }
1673}
1674
1675void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001676 LocationSummary* locations =
1677 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001678 locations->SetInAt(0, Location::Any());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001679 if (instruction->HasUses()) {
1680 locations->SetOut(Location::SameAsFirstInput());
1681 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001682}
1683
1684void InstructionCodeGeneratorX86::VisitNullCheck(HNullCheck* instruction) {
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001685 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathX86(instruction);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001686 codegen_->AddSlowPath(slow_path);
1687
1688 LocationSummary* locations = instruction->GetLocations();
1689 Location obj = locations->InAt(0);
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001690
1691 if (obj.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001692 __ cmpl(obj.As<Register>(), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001693 } else if (obj.IsStackSlot()) {
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001694 __ cmpl(Address(ESP, obj.GetStackIndex()), Immediate(0));
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001695 } else {
1696 DCHECK(obj.IsConstant()) << obj;
1697 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0);
1698 __ jmp(slow_path->GetEntryLabel());
1699 return;
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001700 }
1701 __ j(kEqual, slow_path->GetEntryLabel());
1702}
1703
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001704void LocationsBuilderX86::VisitArrayGet(HArrayGet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001705 LocationSummary* locations =
1706 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001707 locations->SetInAt(0, Location::RequiresRegister());
1708 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1709 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001710}
1711
1712void InstructionCodeGeneratorX86::VisitArrayGet(HArrayGet* instruction) {
1713 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001714 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001715 Location index = locations->InAt(1);
1716
1717 switch (instruction->GetType()) {
1718 case Primitive::kPrimBoolean: {
1719 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001720 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001721 if (index.IsConstant()) {
1722 __ movzxb(out, Address(obj,
1723 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1724 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001725 __ movzxb(out, Address(obj, index.As<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001726 }
1727 break;
1728 }
1729
1730 case Primitive::kPrimByte: {
1731 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001732 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001733 if (index.IsConstant()) {
1734 __ movsxb(out, Address(obj,
1735 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1736 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001737 __ movsxb(out, Address(obj, index.As<Register>(), TIMES_1, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001738 }
1739 break;
1740 }
1741
1742 case Primitive::kPrimShort: {
1743 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001744 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001745 if (index.IsConstant()) {
1746 __ movsxw(out, Address(obj,
1747 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1748 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001749 __ movsxw(out, Address(obj, index.As<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001750 }
1751 break;
1752 }
1753
1754 case Primitive::kPrimChar: {
1755 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001756 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001757 if (index.IsConstant()) {
1758 __ movzxw(out, Address(obj,
1759 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1760 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001761 __ movzxw(out, Address(obj, index.As<Register>(), TIMES_2, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001762 }
1763 break;
1764 }
1765
1766 case Primitive::kPrimInt:
1767 case Primitive::kPrimNot: {
1768 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001769 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001770 if (index.IsConstant()) {
1771 __ movl(out, Address(obj,
1772 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1773 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001774 __ movl(out, Address(obj, index.As<Register>(), TIMES_4, data_offset));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001775 }
1776 break;
1777 }
1778
1779 case Primitive::kPrimLong: {
1780 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001781 Location out = locations->Out();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001782 if (index.IsConstant()) {
1783 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001784 __ movl(out.AsRegisterPairLow<Register>(), Address(obj, offset));
1785 __ movl(out.AsRegisterPairHigh<Register>(), Address(obj, offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001786 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001787 __ movl(out.AsRegisterPairLow<Register>(),
1788 Address(obj, index.As<Register>(), TIMES_8, data_offset));
1789 __ movl(out.AsRegisterPairHigh<Register>(),
1790 Address(obj, index.As<Register>(), TIMES_8, data_offset + kX86WordSize));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001791 }
1792 break;
1793 }
1794
1795 case Primitive::kPrimFloat:
1796 case Primitive::kPrimDouble:
1797 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001798 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001799 case Primitive::kPrimVoid:
1800 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001801 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001802 }
1803}
1804
1805void LocationsBuilderX86::VisitArraySet(HArraySet* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001806 Primitive::Type value_type = instruction->GetComponentType();
1807 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(
1808 instruction,
1809 value_type == Primitive::kPrimNot ? LocationSummary::kCall : LocationSummary::kNoCall);
1810
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001811 if (value_type == Primitive::kPrimNot) {
1812 InvokeRuntimeCallingConvention calling_convention;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001813 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
1814 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1)));
1815 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001816 } else {
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01001817 bool is_byte_type = (value_type == Primitive::kPrimBoolean)
1818 || (value_type == Primitive::kPrimByte);
Nicolas Geoffray9ae0daa2014-09-30 22:40:23 +01001819 // We need the inputs to be different than the output in case of long operation.
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01001820 // In case of a byte operation, the register allocator does not support multiple
1821 // inputs that die at entry with one in a specific register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001822 locations->SetInAt(0, Location::RequiresRegister());
1823 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
Nicolas Geoffray7adfcc82014-10-07 12:24:52 +01001824 if (is_byte_type) {
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001825 // Ensure the value is in a byte register.
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001826 locations->SetInAt(2, Location::ByteRegisterOrConstant(EAX, instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001827 } else {
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001828 locations->SetInAt(2, Location::RegisterOrConstant(instruction->InputAt(2)));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001829 }
1830 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001831}
1832
1833void InstructionCodeGeneratorX86::VisitArraySet(HArraySet* instruction) {
1834 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001835 Register obj = locations->InAt(0).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001836 Location index = locations->InAt(1);
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001837 Location value = locations->InAt(2);
Nicolas Geoffray39468442014-09-02 15:17:15 +01001838 Primitive::Type value_type = instruction->GetComponentType();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001839
1840 switch (value_type) {
1841 case Primitive::kPrimBoolean:
1842 case Primitive::kPrimByte: {
1843 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001844 if (index.IsConstant()) {
1845 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001846 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001847 __ movb(Address(obj, offset), value.As<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001848 } else {
1849 __ movb(Address(obj, offset),
1850 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1851 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001852 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001853 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001854 __ movb(Address(obj, index.As<Register>(), TIMES_1, data_offset),
1855 value.As<ByteRegister>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001856 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001857 __ movb(Address(obj, index.As<Register>(), TIMES_1, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001858 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1859 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001860 }
1861 break;
1862 }
1863
1864 case Primitive::kPrimShort:
1865 case Primitive::kPrimChar: {
1866 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001867 if (index.IsConstant()) {
1868 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001869 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001870 __ movw(Address(obj, offset), value.As<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001871 } else {
1872 __ movw(Address(obj, offset),
1873 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1874 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001875 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001876 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001877 __ movw(Address(obj, index.As<Register>(), TIMES_2, data_offset),
1878 value.As<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001879 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001880 __ movw(Address(obj, index.As<Register>(), TIMES_2, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001881 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1882 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001883 }
1884 break;
1885 }
1886
1887 case Primitive::kPrimInt: {
1888 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001889 if (index.IsConstant()) {
1890 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001891 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001892 __ movl(Address(obj, offset), value.As<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001893 } else {
1894 __ movl(Address(obj, offset), Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1895 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001896 } else {
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001897 if (value.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001898 __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
1899 value.As<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001900 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001901 __ movl(Address(obj, index.As<Register>(), TIMES_4, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001902 Immediate(value.GetConstant()->AsIntConstant()->GetValue()));
1903 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001904 }
1905 break;
1906 }
1907
1908 case Primitive::kPrimNot: {
1909 DCHECK(!codegen_->IsLeafMethod());
1910 __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAputObject)));
Nicolas Geoffray39468442014-09-02 15:17:15 +01001911 codegen_->RecordPcInfo(instruction, instruction->GetDexPc());
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001912 break;
1913 }
1914
1915 case Primitive::kPrimLong: {
1916 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001917 if (index.IsConstant()) {
1918 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001919 if (value.IsRegisterPair()) {
1920 __ movl(Address(obj, offset), value.AsRegisterPairLow<Register>());
1921 __ movl(Address(obj, offset + kX86WordSize), value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001922 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001923 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001924 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
1925 __ movl(Address(obj, offset), Immediate(Low32Bits(val)));
1926 __ movl(Address(obj, offset + kX86WordSize), Immediate(High32Bits(val)));
1927 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001928 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001929 if (value.IsRegisterPair()) {
1930 __ movl(Address(obj, index.As<Register>(), TIMES_8, data_offset),
1931 value.AsRegisterPairLow<Register>());
1932 __ movl(Address(obj, index.As<Register>(), TIMES_8, data_offset + kX86WordSize),
1933 value.AsRegisterPairHigh<Register>());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001934 } else {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001935 DCHECK(value.IsConstant());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001936 int64_t val = value.GetConstant()->AsLongConstant()->GetValue();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001937 __ movl(Address(obj, index.As<Register>(), TIMES_8, data_offset),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001938 Immediate(Low32Bits(val)));
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001939 __ movl(Address(obj, index.As<Register>(), TIMES_8, data_offset + kX86WordSize),
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001940 Immediate(High32Bits(val)));
1941 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001942 }
1943 break;
1944 }
1945
1946 case Primitive::kPrimFloat:
1947 case Primitive::kPrimDouble:
1948 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001949 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001950 case Primitive::kPrimVoid:
1951 LOG(FATAL) << "Unreachable type " << instruction->GetType();
Ian Rogersfc787ec2014-10-09 21:56:44 -07001952 UNREACHABLE();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001953 }
1954}
1955
1956void LocationsBuilderX86::VisitArrayLength(HArrayLength* instruction) {
1957 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray8e3964b2014-10-17 11:06:38 +01001958 locations->SetInAt(0, Location::RequiresRegister());
1959 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001960 instruction->SetLocations(locations);
1961}
1962
1963void InstructionCodeGeneratorX86::VisitArrayLength(HArrayLength* instruction) {
1964 LocationSummary* locations = instruction->GetLocations();
1965 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001966 Register obj = locations->InAt(0).As<Register>();
1967 Register out = locations->Out().As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001968 __ movl(out, Address(obj, offset));
1969}
1970
1971void LocationsBuilderX86::VisitBoundsCheck(HBoundsCheck* instruction) {
Nicolas Geoffray39468442014-09-02 15:17:15 +01001972 LocationSummary* locations =
1973 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001974 locations->SetInAt(0, Location::RequiresRegister());
1975 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray26a25ef2014-09-30 13:54:09 +01001976 if (instruction->HasUses()) {
1977 locations->SetOut(Location::SameAsFirstInput());
1978 }
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001979}
1980
1981void InstructionCodeGeneratorX86::VisitBoundsCheck(HBoundsCheck* instruction) {
1982 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffray92a73ae2014-10-16 11:12:52 +01001983 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86(
Nicolas Geoffray39468442014-09-02 15:17:15 +01001984 instruction, locations->InAt(0), locations->InAt(1));
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001985 codegen_->AddSlowPath(slow_path);
1986
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01001987 Register index = locations->InAt(0).As<Register>();
1988 Register length = locations->InAt(1).As<Register>();
Nicolas Geoffray3c7bb982014-07-23 16:04:16 +01001989
1990 __ cmpl(index, length);
1991 __ j(kAboveEqual, slow_path->GetEntryLabel());
1992}
1993
Nicolas Geoffraye5038322014-07-04 09:41:32 +01001994void LocationsBuilderX86::VisitTemporary(HTemporary* temp) {
1995 temp->SetLocations(nullptr);
1996}
1997
1998void InstructionCodeGeneratorX86::VisitTemporary(HTemporary* temp) {
1999 // Nothing to do, this is driven by the code generator.
2000}
2001
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002002void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002003 LOG(FATAL) << "Unreachable";
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002004}
2005
2006void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002007 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
2008}
2009
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002010void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
2011 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
2012}
2013
2014void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002015 HBasicBlock* block = instruction->GetBlock();
2016 if (block->GetLoopInformation() != nullptr) {
2017 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction);
2018 // The back edge will generate the suspend check.
2019 return;
2020 }
2021 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) {
2022 // The goto will generate the suspend check.
2023 return;
2024 }
2025 GenerateSuspendCheck(instruction, nullptr);
2026}
2027
2028void InstructionCodeGeneratorX86::GenerateSuspendCheck(HSuspendCheck* instruction,
2029 HBasicBlock* successor) {
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002030 SuspendCheckSlowPathX86* slow_path =
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002031 new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction, successor);
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002032 codegen_->AddSlowPath(slow_path);
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002033 __ fs()->cmpw(Address::Absolute(
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002034 Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
Nicolas Geoffray3c049742014-09-24 18:10:46 +01002035 if (successor == nullptr) {
2036 __ j(kNotEqual, slow_path->GetEntryLabel());
2037 __ Bind(slow_path->GetReturnLabel());
2038 } else {
2039 __ j(kEqual, codegen_->GetLabelOf(successor));
2040 __ jmp(slow_path->GetEntryLabel());
2041 }
Nicolas Geoffrayfbc695f2014-09-15 15:33:30 +00002042}
2043
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002044X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
2045 return codegen_->GetAssembler();
2046}
2047
2048void ParallelMoveResolverX86::MoveMemoryToMemory(int dst, int src) {
2049 ScratchRegisterScope ensure_scratch(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002050 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002051 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
2052 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, src + stack_offset));
2053 __ movl(Address(ESP, dst + stack_offset), static_cast<Register>(ensure_scratch.GetRegister()));
2054}
2055
2056void ParallelMoveResolverX86::EmitMove(size_t index) {
2057 MoveOperands* move = moves_.Get(index);
2058 Location source = move->GetSource();
2059 Location destination = move->GetDestination();
2060
2061 if (source.IsRegister()) {
2062 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002063 __ movl(destination.As<Register>(), source.As<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002064 } else {
2065 DCHECK(destination.IsStackSlot());
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002066 __ movl(Address(ESP, destination.GetStackIndex()), source.As<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002067 }
2068 } else if (source.IsStackSlot()) {
2069 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002070 __ movl(destination.As<Register>(), Address(ESP, source.GetStackIndex()));
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002071 } else {
2072 DCHECK(destination.IsStackSlot());
2073 MoveMemoryToMemory(destination.GetStackIndex(),
2074 source.GetStackIndex());
2075 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002076 } else if (source.IsConstant()) {
2077 HIntConstant* instruction = source.GetConstant()->AsIntConstant();
2078 Immediate imm(instruction->AsIntConstant()->GetValue());
2079 if (destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002080 __ movl(destination.As<Register>(), imm);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01002081 } else {
2082 __ movl(Address(ESP, destination.GetStackIndex()), imm);
2083 }
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002084 } else {
2085 LOG(FATAL) << "Unimplemented";
2086 }
2087}
2088
2089void ParallelMoveResolverX86::Exchange(Register reg, int mem) {
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002090 Register suggested_scratch = reg == EAX ? EBX : EAX;
2091 ScratchRegisterScope ensure_scratch(
2092 this, reg, suggested_scratch, codegen_->GetNumberOfCoreRegisters());
2093
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002094 int stack_offset = ensure_scratch.IsSpilled() ? kX86WordSize : 0;
2095 __ movl(static_cast<Register>(ensure_scratch.GetRegister()), Address(ESP, mem + stack_offset));
2096 __ movl(Address(ESP, mem + stack_offset), reg);
2097 __ movl(reg, static_cast<Register>(ensure_scratch.GetRegister()));
2098}
2099
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002100void ParallelMoveResolverX86::Exchange(int mem1, int mem2) {
2101 ScratchRegisterScope ensure_scratch1(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002102 this, kNoRegister, EAX, codegen_->GetNumberOfCoreRegisters());
2103
2104 Register suggested_scratch = ensure_scratch1.GetRegister() == EAX ? EBX : EAX;
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002105 ScratchRegisterScope ensure_scratch2(
Nicolas Geoffraye27f31a2014-06-12 17:53:14 +01002106 this, ensure_scratch1.GetRegister(), suggested_scratch, codegen_->GetNumberOfCoreRegisters());
2107
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002108 int stack_offset = ensure_scratch1.IsSpilled() ? kX86WordSize : 0;
2109 stack_offset += ensure_scratch2.IsSpilled() ? kX86WordSize : 0;
2110 __ movl(static_cast<Register>(ensure_scratch1.GetRegister()), Address(ESP, mem1 + stack_offset));
2111 __ movl(static_cast<Register>(ensure_scratch2.GetRegister()), Address(ESP, mem2 + stack_offset));
2112 __ movl(Address(ESP, mem2 + stack_offset), static_cast<Register>(ensure_scratch1.GetRegister()));
2113 __ movl(Address(ESP, mem1 + stack_offset), static_cast<Register>(ensure_scratch2.GetRegister()));
2114}
2115
2116void ParallelMoveResolverX86::EmitSwap(size_t index) {
2117 MoveOperands* move = moves_.Get(index);
2118 Location source = move->GetSource();
2119 Location destination = move->GetDestination();
2120
2121 if (source.IsRegister() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002122 __ xchgl(destination.As<Register>(), source.As<Register>());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002123 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002124 Exchange(source.As<Register>(), destination.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002125 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray56b9ee62014-10-09 11:47:51 +01002126 Exchange(destination.As<Register>(), source.GetStackIndex());
Nicolas Geoffray86dbb9a2014-06-04 11:12:39 +01002127 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
2128 Exchange(destination.GetStackIndex(), source.GetStackIndex());
2129 } else {
2130 LOG(FATAL) << "Unimplemented";
2131 }
2132}
2133
2134void ParallelMoveResolverX86::SpillScratch(int reg) {
2135 __ pushl(static_cast<Register>(reg));
2136}
2137
2138void ParallelMoveResolverX86::RestoreScratch(int reg) {
2139 __ popl(static_cast<Register>(reg));
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +01002140}
2141
Nicolas Geoffray19a19cf2014-10-22 16:07:05 +01002142void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) {
2143 LocationSummary* locations =
2144 new (GetGraph()->GetArena()) LocationSummary(cls, LocationSummary::kNoCall);
2145 locations->SetOut(Location::RequiresRegister());
2146}
2147
2148void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) {
2149 Register out = cls->GetLocations()->Out().As<Register>();
2150 if (cls->IsReferrersClass()) {
2151 codegen_->LoadCurrentMethod(out);
2152 __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()));
2153 } else {
2154 codegen_->LoadCurrentMethod(out);
2155 __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()));
2156 __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
2157 }
2158}
2159
2160void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
2161 LocationSummary* locations =
2162 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
2163 locations->SetInAt(0, Location::RequiresRegister());
2164 if (check->HasUses()) {
2165 locations->SetOut(Location::SameAsFirstInput());
2166 }
2167}
2168
2169void InstructionCodeGeneratorX86::VisitClinitCheck(HClinitCheck* check) {
2170 SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) ClinitCheckSlowPathX86(check);
2171 codegen_->AddSlowPath(slow_path);
2172
2173 LocationSummary* locations = check->GetLocations();
2174 // We remove the class as a live register, we know it's null or unused in the slow path.
2175 RegisterSet* register_set = locations->GetLiveRegisters();
2176 register_set->Remove(locations->InAt(0));
2177
2178 Register class_reg = locations->InAt(0).As<Register>();
2179 __ testl(class_reg, class_reg);
2180 __ j(kEqual, slow_path->GetEntryLabel());
2181 __ cmpl(Address(class_reg, mirror::Class::StatusOffset().Int32Value()),
2182 Immediate(mirror::Class::kStatusInitialized));
2183 __ j(kLess, slow_path->GetEntryLabel());
2184 __ Bind(slow_path->GetExitLabel());
2185 // No need for memory fence, thanks to the X86 memory model.
2186}
2187
2188void LocationsBuilderX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2189 LocationSummary* locations =
2190 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2191 locations->SetInAt(0, Location::RequiresRegister());
2192 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap);
2193}
2194
2195void InstructionCodeGeneratorX86::VisitStaticFieldGet(HStaticFieldGet* instruction) {
2196 LocationSummary* locations = instruction->GetLocations();
2197 Register cls = locations->InAt(0).As<Register>();
2198 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
2199
2200 switch (instruction->GetType()) {
2201 case Primitive::kPrimBoolean: {
2202 Register out = locations->Out().As<Register>();
2203 __ movzxb(out, Address(cls, offset));
2204 break;
2205 }
2206
2207 case Primitive::kPrimByte: {
2208 Register out = locations->Out().As<Register>();
2209 __ movsxb(out, Address(cls, offset));
2210 break;
2211 }
2212
2213 case Primitive::kPrimShort: {
2214 Register out = locations->Out().As<Register>();
2215 __ movsxw(out, Address(cls, offset));
2216 break;
2217 }
2218
2219 case Primitive::kPrimChar: {
2220 Register out = locations->Out().As<Register>();
2221 __ movzxw(out, Address(cls, offset));
2222 break;
2223 }
2224
2225 case Primitive::kPrimInt:
2226 case Primitive::kPrimNot: {
2227 Register out = locations->Out().As<Register>();
2228 __ movl(out, Address(cls, offset));
2229 break;
2230 }
2231
2232 case Primitive::kPrimLong: {
2233 // TODO: support volatile.
2234 __ movl(locations->Out().AsRegisterPairLow<Register>(), Address(cls, offset));
2235 __ movl(locations->Out().AsRegisterPairHigh<Register>(), Address(cls, kX86WordSize + offset));
2236 break;
2237 }
2238
2239 case Primitive::kPrimFloat:
2240 case Primitive::kPrimDouble:
2241 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
2242 UNREACHABLE();
2243 case Primitive::kPrimVoid:
2244 LOG(FATAL) << "Unreachable type " << instruction->GetType();
2245 UNREACHABLE();
2246 }
2247}
2248
2249void LocationsBuilderX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2250 LocationSummary* locations =
2251 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall);
2252 locations->SetInAt(0, Location::RequiresRegister());
2253 Primitive::Type field_type = instruction->GetFieldType();
2254 bool is_object_type = field_type == Primitive::kPrimNot;
2255 bool is_byte_type = (field_type == Primitive::kPrimBoolean)
2256 || (field_type == Primitive::kPrimByte);
2257 // The register allocator does not support multiple
2258 // inputs that die at entry with one in a specific register.
2259 if (is_byte_type) {
2260 // Ensure the value is in a byte register.
2261 locations->SetInAt(1, Location::RegisterLocation(EAX));
2262 } else {
2263 locations->SetInAt(1, Location::RequiresRegister());
2264 }
2265 // Temporary registers for the write barrier.
2266 if (is_object_type) {
2267 locations->AddTemp(Location::RequiresRegister());
2268 // Ensure the card is in a byte register.
2269 locations->AddTemp(Location::RegisterLocation(ECX));
2270 }
2271}
2272
2273void InstructionCodeGeneratorX86::VisitStaticFieldSet(HStaticFieldSet* instruction) {
2274 LocationSummary* locations = instruction->GetLocations();
2275 Register cls = locations->InAt(0).As<Register>();
2276 uint32_t offset = instruction->GetFieldOffset().Uint32Value();
2277 Primitive::Type field_type = instruction->GetFieldType();
2278
2279 switch (field_type) {
2280 case Primitive::kPrimBoolean:
2281 case Primitive::kPrimByte: {
2282 ByteRegister value = locations->InAt(1).As<ByteRegister>();
2283 __ movb(Address(cls, offset), value);
2284 break;
2285 }
2286
2287 case Primitive::kPrimShort:
2288 case Primitive::kPrimChar: {
2289 Register value = locations->InAt(1).As<Register>();
2290 __ movw(Address(cls, offset), value);
2291 break;
2292 }
2293
2294 case Primitive::kPrimInt:
2295 case Primitive::kPrimNot: {
2296 Register value = locations->InAt(1).As<Register>();
2297 __ movl(Address(cls, offset), value);
2298
2299 if (field_type == Primitive::kPrimNot) {
2300 Register temp = locations->GetTemp(0).As<Register>();
2301 Register card = locations->GetTemp(1).As<Register>();
2302 codegen_->MarkGCCard(temp, card, cls, value);
2303 }
2304 break;
2305 }
2306
2307 case Primitive::kPrimLong: {
2308 Location value = locations->InAt(1);
2309 __ movl(Address(cls, offset), value.AsRegisterPairLow<Register>());
2310 __ movl(Address(cls, kX86WordSize + offset), value.AsRegisterPairHigh<Register>());
2311 break;
2312 }
2313
2314 case Primitive::kPrimFloat:
2315 case Primitive::kPrimDouble:
2316 LOG(FATAL) << "Unimplemented register type " << field_type;
2317 UNREACHABLE();
2318 case Primitive::kPrimVoid:
2319 LOG(FATAL) << "Unreachable type " << field_type;
2320 UNREACHABLE();
2321 }
2322}
2323
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +00002324} // namespace x86
2325} // namespace art