blob: 8bfd8d67c4befa86ce695f2ab738ce95bb40a344 [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"
18#include "utils/assembler.h"
19#include "utils/x86/assembler_x86.h"
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010020#include "utils/x86/managed_register_x86.h"
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000021
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070022#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000023#include "mirror/array.h"
24#include "mirror/art_method.h"
Ian Rogersb0fa5dc2014-04-28 16:47:08 -070025#include "thread.h"
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +000026
Nicolas Geoffray787c3072014-03-17 10:20:19 +000027#define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000028
29namespace art {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +010030
31x86::X86ManagedRegister Location::AsX86() const {
32 return reg().AsX86();
33}
34
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +000035namespace x86 {
36
Nicolas Geoffray4a34a422014-04-03 10:38:37 +010037static constexpr int kNumberOfPushedRegistersAtEntry = 1;
38static constexpr int kCurrentMethodStackOffset = 0;
39
Nicolas Geoffraya7062e02014-05-22 12:50:17 +010040void CodeGeneratorX86::DumpCoreRegister(std::ostream& stream, int reg) const {
41 stream << X86ManagedRegister::FromCpuRegister(Register(reg));
42}
43
44void CodeGeneratorX86::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
45 stream << X86ManagedRegister::FromXmmRegister(XmmRegister(reg));
46}
47
Nicolas Geoffraya7aca372014-04-28 17:47:12 +010048CodeGeneratorX86::CodeGeneratorX86(HGraph* graph)
49 : CodeGenerator(graph, kNumberOfRegIds),
50 location_builder_(graph, this),
51 instruction_visitor_(graph, this) {}
52
53static bool* GetBlockedRegisterPairs(bool* blocked_registers) {
54 return blocked_registers + kNumberOfAllocIds;
55}
56
57ManagedRegister CodeGeneratorX86::AllocateFreeRegister(Primitive::Type type,
58 bool* blocked_registers) const {
59 switch (type) {
60 case Primitive::kPrimLong: {
61 size_t reg = AllocateFreeRegisterInternal(
62 GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs);
63 X86ManagedRegister pair =
64 X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg));
65 blocked_registers[pair.AsRegisterPairLow()] = true;
66 blocked_registers[pair.AsRegisterPairHigh()] = true;
67 return pair;
68 }
69
70 case Primitive::kPrimByte:
71 case Primitive::kPrimBoolean:
72 case Primitive::kPrimChar:
73 case Primitive::kPrimShort:
74 case Primitive::kPrimInt:
75 case Primitive::kPrimNot: {
76 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
77 return X86ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
78 }
79
80 case Primitive::kPrimFloat:
81 case Primitive::kPrimDouble:
82 LOG(FATAL) << "Unimplemented register type " << type;
83
84 case Primitive::kPrimVoid:
85 LOG(FATAL) << "Unreachable type " << type;
86 }
87
88 return ManagedRegister::NoRegister();
89}
90
91void CodeGeneratorX86::SetupBlockedRegisters(bool* blocked_registers) const {
92 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers);
93
94 // Don't allocate the dalvik style register pair passing.
95 blocked_register_pairs[ECX_EDX] = true;
96
97 // Stack register is always reserved.
98 blocked_registers[ESP] = true;
99
100 // TODO: We currently don't use Quick's callee saved registers.
101 blocked_registers[EBP] = true;
102 blocked_registers[ESI] = true;
103 blocked_registers[EDI] = true;
104 blocked_register_pairs[EAX_EDI] = true;
105 blocked_register_pairs[EDX_EDI] = true;
106 blocked_register_pairs[ECX_EDI] = true;
107 blocked_register_pairs[EBX_EDI] = true;
108}
109
110size_t CodeGeneratorX86::GetNumberOfRegisters() const {
111 return kNumberOfRegIds;
112}
113
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100114static Location X86CpuLocation(Register reg) {
115 return Location::RegisterLocation(X86ManagedRegister::FromCpuRegister(reg));
116}
117
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100118InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen)
119 : HGraphVisitor(graph),
120 assembler_(codegen->GetAssembler()),
121 codegen_(codegen) {}
122
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000123void CodeGeneratorX86::GenerateFrameEntry() {
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000124 // Create a fake register to mimic Quick.
125 static const int kFakeReturnRegister = 8;
126 core_spill_mask_ |= (1 << kFakeReturnRegister);
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000127
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100128 SetFrameSize(RoundUp(
129 (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize
130 + kVRegSize // filler
131 + kX86WordSize // Art method
132 + kNumberOfPushedRegistersAtEntry * kX86WordSize,
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100133 kStackAlignment));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100134
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100135 // The return PC has already been pushed on the stack.
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100136 __ subl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100137 __ movl(Address(ESP, kCurrentMethodStackOffset), EAX);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000138}
139
140void CodeGeneratorX86::GenerateFrameExit() {
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100141 __ addl(ESP, Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86WordSize));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000142}
143
144void CodeGeneratorX86::Bind(Label* label) {
145 __ Bind(label);
146}
147
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000148void InstructionCodeGeneratorX86::LoadCurrentMethod(Register reg) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100149 __ movl(reg, Address(ESP, kCurrentMethodStackOffset));
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000150}
151
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100152int32_t CodeGeneratorX86::GetStackSlot(HLocal* local) const {
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100153 uint16_t reg_number = local->GetRegNumber();
154 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs();
155 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs();
156 if (reg_number >= number_of_vregs - number_of_in_vregs) {
157 // Local is a parameter of the method. It is stored in the caller's frame.
158 return GetFrameSize() + kX86WordSize // ART method
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100159 + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize;
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100160 } else {
161 // Local is a temporary in this method. It is stored in this method's frame.
162 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kX86WordSize)
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100163 - kVRegSize // filler.
164 - (number_of_vregs * kVRegSize)
165 + (reg_number * kVRegSize);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100166 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100167}
168
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100169
170Location CodeGeneratorX86::GetStackLocation(HLoadLocal* load) const {
171 switch (load->GetType()) {
172 case Primitive::kPrimLong:
173 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
174 break;
175
176 case Primitive::kPrimInt:
177 case Primitive::kPrimNot:
178 return Location::StackSlot(GetStackSlot(load->GetLocal()));
179
180 case Primitive::kPrimFloat:
181 case Primitive::kPrimDouble:
182 LOG(FATAL) << "Unimplemented type " << load->GetType();
183
184 case Primitive::kPrimBoolean:
185 case Primitive::kPrimByte:
186 case Primitive::kPrimChar:
187 case Primitive::kPrimShort:
188 case Primitive::kPrimVoid:
189 LOG(FATAL) << "Unexpected type " << load->GetType();
190 }
191
192 LOG(FATAL) << "Unreachable";
193 return Location();
194}
195
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100196static constexpr Register kRuntimeParameterCoreRegisters[] = { EAX, ECX, EDX };
197static constexpr size_t kRuntimeParameterCoreRegistersLength =
198 arraysize(kRuntimeParameterCoreRegisters);
199
200class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
201 public:
202 InvokeRuntimeCallingConvention()
203 : CallingConvention(kRuntimeParameterCoreRegisters,
204 kRuntimeParameterCoreRegistersLength) {}
205
206 private:
207 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
208};
209
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100210Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
211 switch (type) {
212 case Primitive::kPrimBoolean:
213 case Primitive::kPrimByte:
214 case Primitive::kPrimChar:
215 case Primitive::kPrimShort:
216 case Primitive::kPrimInt:
217 case Primitive::kPrimNot: {
218 uint32_t index = gp_index_++;
219 if (index < calling_convention.GetNumberOfRegisters()) {
220 return X86CpuLocation(calling_convention.GetRegisterAt(index));
221 } else {
222 return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kX86WordSize));
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100223 }
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100224 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100225
226 case Primitive::kPrimLong: {
227 uint32_t index = gp_index_;
228 gp_index_ += 2;
229 if (index + 1 < calling_convention.GetNumberOfRegisters()) {
230 return Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(
231 calling_convention.GetRegisterPairAt(index)));
232 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) {
233 return Location::QuickParameter(index);
234 } else {
235 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kX86WordSize));
236 }
237 }
238
239 case Primitive::kPrimDouble:
240 case Primitive::kPrimFloat:
241 LOG(FATAL) << "Unimplemented parameter type " << type;
242 break;
243
244 case Primitive::kPrimVoid:
245 LOG(FATAL) << "Unexpected parameter type " << type;
246 break;
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100247 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100248 return Location();
249}
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100250
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100251void CodeGeneratorX86::Move32(Location destination, Location source) {
252 if (source.Equals(destination)) {
253 return;
254 }
255 if (destination.IsRegister()) {
256 if (source.IsRegister()) {
257 __ movl(destination.AsX86().AsCpuRegister(), source.AsX86().AsCpuRegister());
258 } else {
259 DCHECK(source.IsStackSlot());
260 __ movl(destination.AsX86().AsCpuRegister(), Address(ESP, source.GetStackIndex()));
261 }
262 } else {
263 if (source.IsRegister()) {
264 __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsCpuRegister());
265 } else {
266 DCHECK(source.IsStackSlot());
267 __ movl(EAX, Address(ESP, source.GetStackIndex()));
268 __ movl(Address(ESP, destination.GetStackIndex()), EAX);
269 }
270 }
271}
272
273void CodeGeneratorX86::Move64(Location destination, Location source) {
274 if (source.Equals(destination)) {
275 return;
276 }
277 if (destination.IsRegister()) {
278 if (source.IsRegister()) {
279 __ movl(destination.AsX86().AsRegisterPairLow(), source.AsX86().AsRegisterPairLow());
280 __ movl(destination.AsX86().AsRegisterPairHigh(), source.AsX86().AsRegisterPairHigh());
281 } else if (source.IsQuickParameter()) {
282 uint32_t argument_index = source.GetQuickParameterIndex();
283 InvokeDexCallingConvention calling_convention;
284 __ movl(destination.AsX86().AsRegisterPairLow(),
285 calling_convention.GetRegisterAt(argument_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100286 __ movl(destination.AsX86().AsRegisterPairHigh(), Address(ESP,
287 calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100288 } else {
289 DCHECK(source.IsDoubleStackSlot());
290 __ movl(destination.AsX86().AsRegisterPairLow(), Address(ESP, source.GetStackIndex()));
291 __ movl(destination.AsX86().AsRegisterPairHigh(),
292 Address(ESP, source.GetHighStackIndex(kX86WordSize)));
293 }
294 } else if (destination.IsQuickParameter()) {
295 InvokeDexCallingConvention calling_convention;
296 uint32_t argument_index = destination.GetQuickParameterIndex();
297 if (source.IsRegister()) {
298 __ movl(calling_convention.GetRegisterAt(argument_index), source.AsX86().AsRegisterPairLow());
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100299 __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize)),
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100300 source.AsX86().AsRegisterPairHigh());
301 } else {
302 DCHECK(source.IsDoubleStackSlot());
303 __ movl(calling_convention.GetRegisterAt(argument_index),
304 Address(ESP, source.GetStackIndex()));
305 __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize)));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100306 __ movl(Address(ESP, calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize)), EAX);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100307 }
308 } else {
309 if (source.IsRegister()) {
310 __ movl(Address(ESP, destination.GetStackIndex()), source.AsX86().AsRegisterPairLow());
311 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)),
312 source.AsX86().AsRegisterPairHigh());
313 } else if (source.IsQuickParameter()) {
314 InvokeDexCallingConvention calling_convention;
315 uint32_t argument_index = source.GetQuickParameterIndex();
316 __ movl(Address(ESP, destination.GetStackIndex()),
317 calling_convention.GetRegisterAt(argument_index));
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100318 __ movl(EAX, Address(ESP,
319 calling_convention.GetStackOffsetOf(argument_index + 1, kX86WordSize) + GetFrameSize()));
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100320 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX);
321 } else {
322 DCHECK(source.IsDoubleStackSlot());
323 __ movl(EAX, Address(ESP, source.GetStackIndex()));
324 __ movl(Address(ESP, destination.GetStackIndex()), EAX);
325 __ movl(EAX, Address(ESP, source.GetHighStackIndex(kX86WordSize)));
326 __ movl(Address(ESP, destination.GetHighStackIndex(kX86WordSize)), EAX);
327 }
328 }
329}
330
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100331void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) {
332 if (instruction->AsIntConstant() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100333 Immediate imm(instruction->AsIntConstant()->GetValue());
334 if (location.IsRegister()) {
335 __ movl(location.AsX86().AsCpuRegister(), imm);
336 } else {
337 __ movl(Address(ESP, location.GetStackIndex()), imm);
338 }
339 } else if (instruction->AsLongConstant() != nullptr) {
340 int64_t value = instruction->AsLongConstant()->GetValue();
341 if (location.IsRegister()) {
342 __ movl(location.AsX86().AsRegisterPairLow(), Immediate(Low32Bits(value)));
343 __ movl(location.AsX86().AsRegisterPairHigh(), Immediate(High32Bits(value)));
344 } else {
345 __ movl(Address(ESP, location.GetStackIndex()), Immediate(Low32Bits(value)));
346 __ movl(Address(ESP, location.GetHighStackIndex(kX86WordSize)), Immediate(High32Bits(value)));
347 }
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100348 } else if (instruction->AsLoadLocal() != nullptr) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100349 switch (instruction->GetType()) {
350 case Primitive::kPrimBoolean:
351 case Primitive::kPrimByte:
352 case Primitive::kPrimChar:
353 case Primitive::kPrimShort:
354 case Primitive::kPrimInt:
355 case Primitive::kPrimNot:
356 Move32(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
357 break;
358
359 case Primitive::kPrimLong:
360 Move64(location, Location::DoubleStackSlot(
361 GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
362 break;
363
364 default:
365 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
366 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000367 } else {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100368 // This can currently only happen when the instruction that requests the move
369 // is the next to be compiled.
370 DCHECK_EQ(instruction->GetNext(), move_for);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100371 switch (instruction->GetType()) {
372 case Primitive::kPrimBoolean:
373 case Primitive::kPrimByte:
374 case Primitive::kPrimChar:
375 case Primitive::kPrimShort:
376 case Primitive::kPrimInt:
377 case Primitive::kPrimNot:
378 Move32(location, instruction->GetLocations()->Out());
379 break;
380
381 case Primitive::kPrimLong:
382 Move64(location, instruction->GetLocations()->Out());
383 break;
384
385 default:
386 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
387 }
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000388 }
389}
390
391void LocationsBuilderX86::VisitGoto(HGoto* got) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000392 got->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000393}
394
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000395void InstructionCodeGeneratorX86::VisitGoto(HGoto* got) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000396 HBasicBlock* successor = got->GetSuccessor();
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000397 if (GetGraph()->GetExitBlock() == successor) {
398 codegen_->GenerateFrameExit();
399 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
400 __ jmp(codegen_->GetLabelOf(successor));
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000401 }
402}
403
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000404void LocationsBuilderX86::VisitExit(HExit* exit) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000405 exit->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000406}
407
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000408void InstructionCodeGeneratorX86::VisitExit(HExit* exit) {
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000409 if (kIsDebugBuild) {
410 __ Comment("Unreachable");
411 __ int3();
412 }
413}
414
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000415void LocationsBuilderX86::VisitIf(HIf* if_instr) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000416 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100417 locations->SetInAt(0, Location::Any());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000418 if_instr->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000419}
420
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000421void InstructionCodeGeneratorX86::VisitIf(HIf* if_instr) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000422 // TODO: Generate the input as a condition, instead of materializing in a register.
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100423 Location location = if_instr->GetLocations()->InAt(0);
424 if (location.IsRegister()) {
425 __ cmpl(location.AsX86().AsCpuRegister(), Immediate(0));
426 } else {
427 __ cmpl(Address(ESP, location.GetStackIndex()), Immediate(0));
428 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000429 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
430 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) {
431 __ jmp(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000432 }
433}
434
435void LocationsBuilderX86::VisitLocal(HLocal* local) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000436 local->SetLocations(nullptr);
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000437}
438
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000439void InstructionCodeGeneratorX86::VisitLocal(HLocal* local) {
440 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000441}
442
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000443void LocationsBuilderX86::VisitLoadLocal(HLoadLocal* local) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100444 local->SetLocations(nullptr);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000445}
446
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000447void InstructionCodeGeneratorX86::VisitLoadLocal(HLoadLocal* load) {
Nicolas Geoffray4a34a422014-04-03 10:38:37 +0100448 // Nothing to do, this is driven by the code generator.
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000449}
450
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100451void LocationsBuilderX86::VisitStoreLocal(HStoreLocal* store) {
452 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
453 switch (store->InputAt(1)->GetType()) {
454 case Primitive::kPrimBoolean:
455 case Primitive::kPrimByte:
456 case Primitive::kPrimChar:
457 case Primitive::kPrimShort:
458 case Primitive::kPrimInt:
459 case Primitive::kPrimNot:
460 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
461 break;
462
463 case Primitive::kPrimLong:
464 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
465 break;
466
467 default:
468 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
469 }
470 store->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000471}
472
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000473void InstructionCodeGeneratorX86::VisitStoreLocal(HStoreLocal* store) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000474}
475
476void LocationsBuilderX86::VisitEqual(HEqual* equal) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000477 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100478 locations->SetInAt(0, Location::RequiresRegister());
479 locations->SetInAt(1, Location::Any());
480 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000481 equal->SetLocations(locations);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000482}
483
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000484void InstructionCodeGeneratorX86::VisitEqual(HEqual* equal) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100485 LocationSummary* locations = equal->GetLocations();
486 if (locations->InAt(1).IsRegister()) {
487 __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
488 locations->InAt(1).AsX86().AsCpuRegister());
489 } else {
490 __ cmpl(locations->InAt(0).AsX86().AsCpuRegister(),
491 Address(ESP, locations->InAt(1).GetStackIndex()));
492 }
493 __ setb(kEqual, locations->Out().AsX86().AsCpuRegister());
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000494}
495
496void LocationsBuilderX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000497 constant->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000498}
499
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000500void InstructionCodeGeneratorX86::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000501 // Will be generated at use site.
502}
503
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100504void LocationsBuilderX86::VisitLongConstant(HLongConstant* constant) {
505 constant->SetLocations(nullptr);
506}
507
508void InstructionCodeGeneratorX86::VisitLongConstant(HLongConstant* constant) {
509 // Will be generated at use site.
510}
511
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000512void LocationsBuilderX86::VisitReturnVoid(HReturnVoid* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000513 ret->SetLocations(nullptr);
Nicolas Geoffray3ff386a2014-03-04 14:46:47 +0000514}
515
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000516void InstructionCodeGeneratorX86::VisitReturnVoid(HReturnVoid* ret) {
517 codegen_->GenerateFrameExit();
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000518 __ ret();
519}
520
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000521void LocationsBuilderX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000522 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100523 switch (ret->InputAt(0)->GetType()) {
524 case Primitive::kPrimBoolean:
525 case Primitive::kPrimByte:
526 case Primitive::kPrimChar:
527 case Primitive::kPrimShort:
528 case Primitive::kPrimInt:
529 case Primitive::kPrimNot:
530 locations->SetInAt(0, X86CpuLocation(EAX));
531 break;
532
533 case Primitive::kPrimLong:
534 locations->SetInAt(
535 0, Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
536 break;
537
538 default:
539 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
540 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000541 ret->SetLocations(locations);
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000542}
543
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000544void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100545 if (kIsDebugBuild) {
546 switch (ret->InputAt(0)->GetType()) {
547 case Primitive::kPrimBoolean:
548 case Primitive::kPrimByte:
549 case Primitive::kPrimChar:
550 case Primitive::kPrimShort:
551 case Primitive::kPrimInt:
552 case Primitive::kPrimNot:
553 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsCpuRegister(), EAX);
554 break;
555
556 case Primitive::kPrimLong:
557 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86().AsRegisterPair(), EAX_EDX);
558 break;
559
560 default:
561 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
562 }
563 }
Nicolas Geoffray787c3072014-03-17 10:20:19 +0000564 codegen_->GenerateFrameExit();
Nicolas Geoffraybab4ed72014-03-11 17:53:17 +0000565 __ ret();
566}
567
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000568void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
569 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100570 locations->AddTemp(Location::RequiresRegister());
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100571
572 InvokeDexCallingConventionVisitor calling_convention_visitor;
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100573 for (size_t i = 0; i < invoke->InputCount(); i++) {
Nicolas Geoffraydb928fc2014-04-16 17:38:32 +0100574 HInstruction* input = invoke->InputAt(i);
575 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
576 }
577
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100578 switch (invoke->GetType()) {
579 case Primitive::kPrimBoolean:
580 case Primitive::kPrimByte:
581 case Primitive::kPrimChar:
582 case Primitive::kPrimShort:
583 case Primitive::kPrimInt:
584 case Primitive::kPrimNot:
585 locations->SetOut(X86CpuLocation(EAX));
586 break;
587
588 case Primitive::kPrimLong:
589 locations->SetOut(Location::RegisterLocation(X86ManagedRegister::FromRegisterPair(EAX_EDX)));
590 break;
591
592 case Primitive::kPrimVoid:
593 break;
594
595 case Primitive::kPrimDouble:
596 case Primitive::kPrimFloat:
597 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
598 break;
599 }
600
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000601 invoke->SetLocations(locations);
602}
603
604void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100605 Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister();
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000606 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100607 invoke->GetIndexInDexCache() * kX86WordSize;
Nicolas Geoffray8ccc3f52014-03-19 10:34:11 +0000608
609 // TODO: Implement all kinds of calls:
610 // 1) boot -> boot
611 // 2) app -> boot
612 // 3) app -> app
613 //
614 // Currently we implement the app -> app logic, which looks up in the resolve cache.
615
616 // temp = method;
617 LoadCurrentMethod(temp);
618 // temp = temp->dex_cache_resolved_methods_;
619 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
620 // temp = temp[index_in_cache]
621 __ movl(temp, Address(temp, index_in_cache));
622 // (temp + offset_of_quick_compiled_code)()
623 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
624
625 codegen_->RecordPcInfo(invoke->GetDexPc());
626}
627
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000628void LocationsBuilderX86::VisitAdd(HAdd* add) {
629 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
630 switch (add->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100631 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100632 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100633 locations->SetInAt(0, Location::RequiresRegister());
634 locations->SetInAt(1, Location::Any());
635 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100636 break;
637 }
638
639 case Primitive::kPrimBoolean:
640 case Primitive::kPrimByte:
641 case Primitive::kPrimChar:
642 case Primitive::kPrimShort:
643 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
644 break;
645
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000646 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100647 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000648 }
649 add->SetLocations(locations);
650}
651
652void InstructionCodeGeneratorX86::VisitAdd(HAdd* add) {
653 LocationSummary* locations = add->GetLocations();
654 switch (add->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100655 case Primitive::kPrimInt: {
656 DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(),
657 locations->Out().AsX86().AsCpuRegister());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100658 if (locations->InAt(1).IsRegister()) {
659 __ addl(locations->InAt(0).AsX86().AsCpuRegister(),
660 locations->InAt(1).AsX86().AsCpuRegister());
661 } else {
662 __ addl(locations->InAt(0).AsX86().AsCpuRegister(),
663 Address(ESP, locations->InAt(1).GetStackIndex()));
664 }
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000665 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100666 }
667
668 case Primitive::kPrimLong: {
669 DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
670 locations->Out().AsX86().AsRegisterPair());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100671 if (locations->InAt(1).IsRegister()) {
672 __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(),
673 locations->InAt(1).AsX86().AsRegisterPairLow());
674 __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
675 locations->InAt(1).AsX86().AsRegisterPairHigh());
676 } else {
677 __ addl(locations->InAt(0).AsX86().AsRegisterPairLow(),
678 Address(ESP, locations->InAt(1).GetStackIndex()));
679 __ adcl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
680 Address(ESP, locations->InAt(1).GetHighStackIndex(kX86WordSize)));
681 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100682 break;
683 }
684
685 case Primitive::kPrimBoolean:
686 case Primitive::kPrimByte:
687 case Primitive::kPrimChar:
688 case Primitive::kPrimShort:
689 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
690 break;
691
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000692 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100693 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
Nicolas Geoffrayd8ee7372014-03-28 15:43:40 +0000694 }
695}
696
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100697void LocationsBuilderX86::VisitSub(HSub* sub) {
698 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
699 switch (sub->GetResultType()) {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100700 case Primitive::kPrimInt:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100701 case Primitive::kPrimLong: {
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100702 locations->SetInAt(0, Location::RequiresRegister());
703 locations->SetInAt(1, Location::Any());
704 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100705 break;
706 }
707
708 case Primitive::kPrimBoolean:
709 case Primitive::kPrimByte:
710 case Primitive::kPrimChar:
711 case Primitive::kPrimShort:
712 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
713 break;
714
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100715 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100716 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100717 }
718 sub->SetLocations(locations);
719}
720
721void InstructionCodeGeneratorX86::VisitSub(HSub* sub) {
722 LocationSummary* locations = sub->GetLocations();
723 switch (sub->GetResultType()) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100724 case Primitive::kPrimInt: {
725 DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(),
726 locations->Out().AsX86().AsCpuRegister());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100727 if (locations->InAt(1).IsRegister()) {
728 __ subl(locations->InAt(0).AsX86().AsCpuRegister(),
729 locations->InAt(1).AsX86().AsCpuRegister());
730 } else {
731 __ subl(locations->InAt(0).AsX86().AsCpuRegister(),
732 Address(ESP, locations->InAt(1).GetStackIndex()));
733 }
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100734 break;
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100735 }
736
737 case Primitive::kPrimLong: {
738 DCHECK_EQ(locations->InAt(0).AsX86().AsRegisterPair(),
739 locations->Out().AsX86().AsRegisterPair());
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100740 if (locations->InAt(1).IsRegister()) {
741 __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(),
742 locations->InAt(1).AsX86().AsRegisterPairLow());
743 __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
744 locations->InAt(1).AsX86().AsRegisterPairHigh());
745 } else {
746 __ subl(locations->InAt(0).AsX86().AsRegisterPairLow(),
747 Address(ESP, locations->InAt(1).GetStackIndex()));
748 __ sbbl(locations->InAt(0).AsX86().AsRegisterPairHigh(),
749 Address(ESP, locations->InAt(1).GetHighStackIndex(kX86WordSize)));
750 }
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100751 break;
752 }
753
754 case Primitive::kPrimBoolean:
755 case Primitive::kPrimByte:
756 case Primitive::kPrimChar:
757 case Primitive::kPrimShort:
758 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
759 break;
760
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100761 default:
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100762 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100763 }
764}
765
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100766void LocationsBuilderX86::VisitNewInstance(HNewInstance* instruction) {
767 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100768 locations->SetOut(X86CpuLocation(EAX));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100769 InvokeRuntimeCallingConvention calling_convention;
770 locations->AddTemp(X86CpuLocation(calling_convention.GetRegisterAt(0)));
771 locations->AddTemp(X86CpuLocation(calling_convention.GetRegisterAt(1)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100772 instruction->SetLocations(locations);
773}
774
775void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) {
776 InvokeRuntimeCallingConvention calling_convention;
777 LoadCurrentMethod(calling_convention.GetRegisterAt(1));
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100778 __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex()));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100779
Nicolas Geoffray707c8092014-04-04 10:50:14 +0100780 __ fs()->call(
781 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pAllocObjectWithAccessCheck)));
Nicolas Geoffray2e7038a2014-04-03 18:49:58 +0100782
783 codegen_->RecordPcInfo(instruction->GetDexPc());
784}
785
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100786void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) {
787 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100788 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
789 if (location.IsStackSlot()) {
790 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
791 } else if (location.IsDoubleStackSlot()) {
792 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100793 }
Nicolas Geoffraya747a392014-04-17 14:56:23 +0100794 locations->SetOut(location);
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100795 instruction->SetLocations(locations);
796}
797
798void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) {
Nicolas Geoffray01bc96d2014-04-11 17:43:50 +0100799 // Nothing to do, the parameter is already at its location.
Nicolas Geoffrayf583e592014-04-07 13:20:42 +0100800}
801
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100802void LocationsBuilderX86::VisitNot(HNot* instruction) {
803 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100804 locations->SetInAt(0, Location::RequiresRegister());
805 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100806 instruction->SetLocations(locations);
807}
808
809void InstructionCodeGeneratorX86::VisitNot(HNot* instruction) {
810 LocationSummary* locations = instruction->GetLocations();
Nicolas Geoffraya7aca372014-04-28 17:47:12 +0100811 Location out = locations->Out();
812 DCHECK_EQ(locations->InAt(0).AsX86().AsCpuRegister(), out.AsX86().AsCpuRegister());
813 __ xorl(out.AsX86().AsCpuRegister(), Immediate(1));
Nicolas Geoffrayb55f8352014-04-07 15:26:35 +0100814}
815
Nicolas Geoffrayc32e7702014-04-24 12:43:16 +0100816void LocationsBuilderX86::VisitPhi(HPhi* instruction) {
817 LOG(FATAL) << "Unimplemented";
818}
819
820void InstructionCodeGeneratorX86::VisitPhi(HPhi* instruction) {
821 LOG(FATAL) << "Unimplemented";
822}
823
Nicolas Geoffray4e3d23a2014-05-22 18:32:45 +0100824void LocationsBuilderX86::VisitParallelMove(HParallelMove* instruction) {
825 LOG(FATAL) << "Unimplemented";
826}
827
828void InstructionCodeGeneratorX86::VisitParallelMove(HParallelMove* instruction) {
829 LOG(FATAL) << "Unimplemented";
830}
831
Nicolas Geoffrayd4dd2552014-02-28 10:23:58 +0000832} // namespace x86
833} // namespace art