blob: d20dff0556b11afe2268b149fd502994f38a074a [file] [log] [blame]
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001/*
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_64.h"
18
19#include "entrypoints/quick/quick_entrypoints.h"
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +010020#include "gc/accounting/card_table.h"
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010021#include "mirror/array.h"
22#include "mirror/art_method.h"
23#include "mirror/object_reference.h"
24#include "thread.h"
25#include "utils/assembler.h"
26#include "utils/x86_64/assembler_x86_64.h"
27#include "utils/x86_64/managed_register_x86_64.h"
28
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010029namespace art {
30
31x86_64::X86_64ManagedRegister Location::AsX86_64() const {
32 return reg().AsX86_64();
33}
34
35namespace x86_64 {
36
Nicolas Geoffraye5038322014-07-04 09:41:32 +010037#define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
38
39class NullCheckSlowPathX86_64 : public SlowPathCode {
40 public:
41 explicit NullCheckSlowPathX86_64(uint32_t dex_pc) : dex_pc_(dex_pc) {}
42
43 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
44 __ Bind(GetEntryLabel());
45 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
46 codegen->RecordPcInfo(dex_pc_);
47 }
48
49 private:
50 const uint32_t dex_pc_;
51 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
52};
53
54#undef __
55#define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
56
Dave Allison20dfc792014-06-16 20:44:29 -070057inline Condition X86_64Condition(IfCondition cond) {
58 switch (cond) {
59 case kCondEQ: return kEqual;
60 case kCondNE: return kNotEqual;
61 case kCondLT: return kLess;
62 case kCondLE: return kLessEqual;
63 case kCondGT: return kGreater;
64 case kCondGE: return kGreaterEqual;
65 default:
66 LOG(FATAL) << "Unknown if condition";
67 }
68 return kEqual;
69}
70
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +000071// Some x86_64 instructions require a register to be available as temp.
72static constexpr Register TMP = R11;
73
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010074static constexpr int kNumberOfPushedRegistersAtEntry = 1;
75static constexpr int kCurrentMethodStackOffset = 0;
76
77void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
78 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
79}
80
81void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
82 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
83}
84
85static Location X86_64CpuLocation(Register reg) {
86 return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
87}
88
89CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
90 : CodeGenerator(graph, kNumberOfRegIds),
91 location_builder_(graph, this),
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +000092 instruction_visitor_(graph, this),
93 move_resolver_(graph->GetArena(), this) {}
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010094
Nicolas Geoffrayab032bc2014-07-15 12:55:21 +010095size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
96 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
97}
98
Nicolas Geoffray9cf35522014-06-09 18:40:10 +010099InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph, CodeGeneratorX86_64* codegen)
100 : HGraphVisitor(graph),
101 assembler_(codegen->GetAssembler()),
102 codegen_(codegen) {}
103
104ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
105 bool* blocked_registers) const {
106 switch (type) {
107 case Primitive::kPrimLong:
108 case Primitive::kPrimByte:
109 case Primitive::kPrimBoolean:
110 case Primitive::kPrimChar:
111 case Primitive::kPrimShort:
112 case Primitive::kPrimInt:
113 case Primitive::kPrimNot: {
114 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
115 return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
116 }
117
118 case Primitive::kPrimFloat:
119 case Primitive::kPrimDouble:
120 LOG(FATAL) << "Unimplemented register type " << type;
121
122 case Primitive::kPrimVoid:
123 LOG(FATAL) << "Unreachable type " << type;
124 }
125
126 return ManagedRegister::NoRegister();
127}
128
129void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
130 // Stack register is always reserved.
131 blocked_registers[RSP] = true;
132
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000133 // Block the register used as TMP.
134 blocked_registers[TMP] = true;
135
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100136 // TODO: We currently don't use Quick's callee saved registers.
137 blocked_registers[RBX] = true;
138 blocked_registers[RBP] = true;
139 blocked_registers[R12] = true;
140 blocked_registers[R13] = true;
141 blocked_registers[R14] = true;
142 blocked_registers[R15] = true;
143}
144
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100145void CodeGeneratorX86_64::GenerateFrameEntry() {
146 // Create a fake register to mimic Quick.
147 static const int kFakeReturnRegister = 16;
148 core_spill_mask_ |= (1 << kFakeReturnRegister);
149
150 // The return PC has already been pushed on the stack.
151 __ subq(CpuRegister(RSP), Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
152 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
153}
154
155void CodeGeneratorX86_64::GenerateFrameExit() {
156 __ addq(CpuRegister(RSP),
157 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
158}
159
160void CodeGeneratorX86_64::Bind(Label* label) {
161 __ Bind(label);
162}
163
164void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
165 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
166}
167
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100168Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
169 switch (load->GetType()) {
170 case Primitive::kPrimLong:
171 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
172 break;
173
174 case Primitive::kPrimInt:
175 case Primitive::kPrimNot:
176 return Location::StackSlot(GetStackSlot(load->GetLocal()));
177
178 case Primitive::kPrimFloat:
179 case Primitive::kPrimDouble:
180 LOG(FATAL) << "Unimplemented type " << load->GetType();
181
182 case Primitive::kPrimBoolean:
183 case Primitive::kPrimByte:
184 case Primitive::kPrimChar:
185 case Primitive::kPrimShort:
186 case Primitive::kPrimVoid:
187 LOG(FATAL) << "Unexpected type " << load->GetType();
188 }
189
190 LOG(FATAL) << "Unreachable";
191 return Location();
192}
193
194void CodeGeneratorX86_64::Move(Location destination, Location source) {
195 if (source.Equals(destination)) {
196 return;
197 }
198 if (destination.IsRegister()) {
199 if (source.IsRegister()) {
200 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
201 } else if (source.IsStackSlot()) {
202 __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
203 } else {
204 DCHECK(source.IsDoubleStackSlot());
205 __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
206 }
207 } else if (destination.IsStackSlot()) {
208 if (source.IsRegister()) {
209 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
210 } else {
211 DCHECK(source.IsStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000212 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
213 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100214 }
215 } else {
216 DCHECK(destination.IsDoubleStackSlot());
217 if (source.IsRegister()) {
218 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
219 } else {
220 DCHECK(source.IsDoubleStackSlot());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000221 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
222 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100223 }
224 }
225}
226
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100227void CodeGeneratorX86_64::Move(HInstruction* instruction,
228 Location location,
229 HInstruction* move_for) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100230 if (instruction->AsIntConstant() != nullptr) {
231 Immediate imm(instruction->AsIntConstant()->GetValue());
232 if (location.IsRegister()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000233 __ movl(location.AsX86_64().AsCpuRegister(), imm);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100234 } else {
235 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
236 }
237 } else if (instruction->AsLongConstant() != nullptr) {
238 int64_t value = instruction->AsLongConstant()->GetValue();
239 if (location.IsRegister()) {
240 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
241 } else {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000242 __ movq(CpuRegister(TMP), Immediate(value));
243 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100244 }
245 } else if (instruction->AsLoadLocal() != nullptr) {
246 switch (instruction->GetType()) {
247 case Primitive::kPrimBoolean:
248 case Primitive::kPrimByte:
249 case Primitive::kPrimChar:
250 case Primitive::kPrimShort:
251 case Primitive::kPrimInt:
252 case Primitive::kPrimNot:
253 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
254 break;
255
256 case Primitive::kPrimLong:
257 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
258 break;
259
260 default:
261 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
262 }
263 } else {
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100264 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100265 switch (instruction->GetType()) {
266 case Primitive::kPrimBoolean:
267 case Primitive::kPrimByte:
268 case Primitive::kPrimChar:
269 case Primitive::kPrimShort:
270 case Primitive::kPrimInt:
271 case Primitive::kPrimNot:
272 case Primitive::kPrimLong:
273 Move(location, instruction->GetLocations()->Out());
274 break;
275
276 default:
277 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
278 }
279 }
280}
281
282void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
283 got->SetLocations(nullptr);
284}
285
286void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
287 HBasicBlock* successor = got->GetSuccessor();
288 if (GetGraph()->GetExitBlock() == successor) {
289 codegen_->GenerateFrameExit();
290 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
291 __ jmp(codegen_->GetLabelOf(successor));
292 }
293}
294
295void LocationsBuilderX86_64::VisitExit(HExit* exit) {
296 exit->SetLocations(nullptr);
297}
298
299void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
300 if (kIsDebugBuild) {
301 __ Comment("Unreachable");
302 __ int3();
303 }
304}
305
306void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
307 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100308 HInstruction* cond = if_instr->InputAt(0);
309 DCHECK(cond->IsCondition());
310 HCondition* condition = cond->AsCondition();
311 if (condition->NeedsMaterialization()) {
312 locations->SetInAt(0, Location::Any());
313 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100314 if_instr->SetLocations(locations);
315}
316
317void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
Dave Allison20dfc792014-06-16 20:44:29 -0700318 HInstruction* cond = if_instr->InputAt(0);
319 DCHECK(cond->IsCondition());
320 HCondition* condition = cond->AsCondition();
321 if (condition->NeedsMaterialization()) {
322 // Materialized condition, compare against 0.
323 Location lhs = if_instr->GetLocations()->InAt(0);
324 if (lhs.IsRegister()) {
325 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
326 } else {
327 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
328 }
329 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
330 } else {
331 Location lhs = condition->GetLocations()->InAt(0);
332 Location rhs = condition->GetLocations()->InAt(1);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100333 if (rhs.IsRegister()) {
334 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
335 } else if (rhs.IsConstant()) {
336 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
337 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
338 } else {
339 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
340 }
Dave Allison20dfc792014-06-16 20:44:29 -0700341 __ j(X86_64Condition(condition->GetCondition()),
342 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
343 }
344 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
345 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100346 }
347}
348
349void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
350 local->SetLocations(nullptr);
351}
352
353void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
354 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
355}
356
357void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
358 local->SetLocations(nullptr);
359}
360
361void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
362 // Nothing to do, this is driven by the code generator.
363}
364
365void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
366 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
367 switch (store->InputAt(1)->GetType()) {
368 case Primitive::kPrimBoolean:
369 case Primitive::kPrimByte:
370 case Primitive::kPrimChar:
371 case Primitive::kPrimShort:
372 case Primitive::kPrimInt:
373 case Primitive::kPrimNot:
374 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
375 break;
376
377 case Primitive::kPrimLong:
378 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
379 break;
380
381 default:
382 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
383 }
384 store->SetLocations(locations);
385}
386
387void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
388}
389
Dave Allison20dfc792014-06-16 20:44:29 -0700390void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
391 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000392 locations->SetInAt(0, Location::RequiresRegister());
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100393 locations->SetInAt(1, Location::Any());
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100394 if (comp->NeedsMaterialization()) {
395 locations->SetOut(Location::RequiresRegister());
396 }
Dave Allison20dfc792014-06-16 20:44:29 -0700397 comp->SetLocations(locations);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100398}
399
Dave Allison20dfc792014-06-16 20:44:29 -0700400void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
401 if (comp->NeedsMaterialization()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100402 LocationSummary* locations = comp->GetLocations();
403 if (locations->InAt(1).IsRegister()) {
404 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
405 locations->InAt(1).AsX86_64().AsCpuRegister());
406 } else if (locations->InAt(1).IsConstant()) {
407 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
408 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
409 } else {
410 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
411 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
412 }
Dave Allison20dfc792014-06-16 20:44:29 -0700413 __ setcc(X86_64Condition(comp->GetCondition()),
414 comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
415 }
416}
417
418void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
419 VisitCondition(comp);
420}
421
422void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
423 VisitCondition(comp);
424}
425
426void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
427 VisitCondition(comp);
428}
429
430void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
431 VisitCondition(comp);
432}
433
434void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
435 VisitCondition(comp);
436}
437
438void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
439 VisitCondition(comp);
440}
441
442void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
443 VisitCondition(comp);
444}
445
446void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
447 VisitCondition(comp);
448}
449
450void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
451 VisitCondition(comp);
452}
453
454void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
455 VisitCondition(comp);
456}
457
458void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
459 VisitCondition(comp);
460}
461
462void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
463 VisitCondition(comp);
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100464}
465
Nicolas Geoffray412f10c2014-06-19 10:00:34 +0100466void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
467 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
468 locations->SetInAt(0, Location::RequiresRegister());
469 locations->SetInAt(1, Location::RequiresRegister());
470 locations->SetOut(Location::RequiresRegister());
471 compare->SetLocations(locations);
472}
473
474void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
475 Label greater, done;
476 LocationSummary* locations = compare->GetLocations();
477 switch (compare->InputAt(0)->GetType()) {
478 case Primitive::kPrimLong:
479 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
480 locations->InAt(1).AsX86_64().AsCpuRegister());
481 break;
482 default:
483 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
484 }
485
486 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
487 __ j(kEqual, &done);
488 __ j(kGreater, &greater);
489
490 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
491 __ jmp(&done);
492
493 __ Bind(&greater);
494 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
495
496 __ Bind(&done);
497}
498
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100499void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100500 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100501 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100502 constant->SetLocations(locations);
503}
504
505void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100506}
507
508void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100509 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100510 locations->SetOut(Location::ConstantLocation(constant));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100511 constant->SetLocations(locations);
512}
513
514void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100515}
516
517void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
518 ret->SetLocations(nullptr);
519}
520
521void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
522 codegen_->GenerateFrameExit();
523 __ ret();
524}
525
526void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
527 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
528 switch (ret->InputAt(0)->GetType()) {
529 case Primitive::kPrimBoolean:
530 case Primitive::kPrimByte:
531 case Primitive::kPrimChar:
532 case Primitive::kPrimShort:
533 case Primitive::kPrimInt:
534 case Primitive::kPrimNot:
535 case Primitive::kPrimLong:
536 locations->SetInAt(0, X86_64CpuLocation(RAX));
537 break;
538
539 default:
540 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
541 }
542 ret->SetLocations(locations);
543}
544
545void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
546 if (kIsDebugBuild) {
547 switch (ret->InputAt(0)->GetType()) {
548 case Primitive::kPrimBoolean:
549 case Primitive::kPrimByte:
550 case Primitive::kPrimChar:
551 case Primitive::kPrimShort:
552 case Primitive::kPrimInt:
553 case Primitive::kPrimNot:
554 case Primitive::kPrimLong:
555 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
556 break;
557
558 default:
559 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
560 }
561 }
562 codegen_->GenerateFrameExit();
563 __ ret();
564}
565
566static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
567static constexpr size_t kRuntimeParameterCoreRegistersLength =
568 arraysize(kRuntimeParameterCoreRegisters);
569
570class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
571 public:
572 InvokeRuntimeCallingConvention()
573 : CallingConvention(kRuntimeParameterCoreRegisters,
574 kRuntimeParameterCoreRegistersLength) {}
575
576 private:
577 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
578};
579
580Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
581 switch (type) {
582 case Primitive::kPrimBoolean:
583 case Primitive::kPrimByte:
584 case Primitive::kPrimChar:
585 case Primitive::kPrimShort:
586 case Primitive::kPrimInt:
587 case Primitive::kPrimNot: {
588 uint32_t index = gp_index_++;
589 stack_index_++;
590 if (index < calling_convention.GetNumberOfRegisters()) {
591 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
592 } else {
593 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
594 }
595 }
596
597 case Primitive::kPrimLong: {
598 uint32_t index = gp_index_;
599 stack_index_ += 2;
600 if (index < calling_convention.GetNumberOfRegisters()) {
601 gp_index_ += 1;
602 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
603 } else {
604 gp_index_ += 2;
605 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
606 }
607 }
608
609 case Primitive::kPrimDouble:
610 case Primitive::kPrimFloat:
611 LOG(FATAL) << "Unimplemented parameter type " << type;
612 break;
613
614 case Primitive::kPrimVoid:
615 LOG(FATAL) << "Unexpected parameter type " << type;
616 break;
617 }
618 return Location();
619}
620
621void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
622 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
623 locations->AddTemp(X86_64CpuLocation(RDI));
624
625 InvokeDexCallingConventionVisitor calling_convention_visitor;
626 for (size_t i = 0; i < invoke->InputCount(); ++i) {
627 HInstruction* input = invoke->InputAt(i);
628 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
629 }
630
631 switch (invoke->GetType()) {
632 case Primitive::kPrimBoolean:
633 case Primitive::kPrimByte:
634 case Primitive::kPrimChar:
635 case Primitive::kPrimShort:
636 case Primitive::kPrimInt:
637 case Primitive::kPrimNot:
638 case Primitive::kPrimLong:
639 locations->SetOut(X86_64CpuLocation(RAX));
640 break;
641
642 case Primitive::kPrimVoid:
643 break;
644
645 case Primitive::kPrimDouble:
646 case Primitive::kPrimFloat:
647 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
648 break;
649 }
650
651 invoke->SetLocations(locations);
652}
653
654void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
655 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
656 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
657 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
658 invoke->GetIndexInDexCache() * heap_reference_size;
659
660 // TODO: Implement all kinds of calls:
661 // 1) boot -> boot
662 // 2) app -> boot
663 // 3) app -> app
664 //
665 // Currently we implement the app -> app logic, which looks up in the resolve cache.
666
667 // temp = method;
668 LoadCurrentMethod(temp);
669 // temp = temp->dex_cache_resolved_methods_;
670 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
671 // temp = temp[index_in_cache]
672 __ movl(temp, Address(temp, index_in_cache));
673 // (temp + offset_of_quick_compiled_code)()
674 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
675
676 codegen_->RecordPcInfo(invoke->GetDexPc());
677}
678
679void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
680 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
681 switch (add->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100682 case Primitive::kPrimInt: {
683 locations->SetInAt(0, Location::RequiresRegister());
684 locations->SetInAt(1, Location::Any());
685 locations->SetOut(Location::SameAsFirstInput());
686 break;
687 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100688 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000689 locations->SetInAt(0, Location::RequiresRegister());
690 locations->SetInAt(1, Location::RequiresRegister());
691 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100692 break;
693 }
694
695 case Primitive::kPrimBoolean:
696 case Primitive::kPrimByte:
697 case Primitive::kPrimChar:
698 case Primitive::kPrimShort:
699 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
700 break;
701
702 default:
703 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
704 }
705 add->SetLocations(locations);
706}
707
708void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
709 LocationSummary* locations = add->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000710 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
711 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100712 switch (add->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000713 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100714 if (locations->InAt(1).IsRegister()) {
715 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
716 locations->InAt(1).AsX86_64().AsCpuRegister());
717 } else if (locations->InAt(1).IsConstant()) {
718 HConstant* instruction = locations->InAt(1).GetConstant();
719 Immediate imm(instruction->AsIntConstant()->GetValue());
720 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
721 } else {
722 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
723 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
724 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000725 break;
726 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100727 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100728 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
729 locations->InAt(1).AsX86_64().AsCpuRegister());
730 break;
731 }
732
733 case Primitive::kPrimBoolean:
734 case Primitive::kPrimByte:
735 case Primitive::kPrimChar:
736 case Primitive::kPrimShort:
737 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
738 break;
739
740 default:
741 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
742 }
743}
744
745void LocationsBuilderX86_64::VisitSub(HSub* sub) {
746 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
747 switch (sub->GetResultType()) {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100748 case Primitive::kPrimInt: {
749 locations->SetInAt(0, Location::RequiresRegister());
750 locations->SetInAt(1, Location::Any());
751 locations->SetOut(Location::SameAsFirstInput());
752 break;
753 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100754 case Primitive::kPrimLong: {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000755 locations->SetInAt(0, Location::RequiresRegister());
756 locations->SetInAt(1, Location::RequiresRegister());
757 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100758 break;
759 }
760
761 case Primitive::kPrimBoolean:
762 case Primitive::kPrimByte:
763 case Primitive::kPrimChar:
764 case Primitive::kPrimShort:
765 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
766 break;
767
768 default:
769 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
770 }
771 sub->SetLocations(locations);
772}
773
774void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
775 LocationSummary* locations = sub->GetLocations();
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000776 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
777 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100778 switch (sub->GetResultType()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000779 case Primitive::kPrimInt: {
Nicolas Geoffray96f89a22014-07-11 10:57:49 +0100780 if (locations->InAt(1).IsRegister()) {
781 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
782 locations->InAt(1).AsX86_64().AsCpuRegister());
783 } else if (locations->InAt(1).IsConstant()) {
784 HConstant* instruction = locations->InAt(1).GetConstant();
785 Immediate imm(instruction->AsIntConstant()->GetValue());
786 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
787 } else {
788 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
789 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
790 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000791 break;
792 }
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100793 case Primitive::kPrimLong: {
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100794 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
795 locations->InAt(1).AsX86_64().AsCpuRegister());
796 break;
797 }
798
799 case Primitive::kPrimBoolean:
800 case Primitive::kPrimByte:
801 case Primitive::kPrimChar:
802 case Primitive::kPrimShort:
803 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
804 break;
805
806 default:
807 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
808 }
809}
810
811void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
812 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
813 locations->SetOut(X86_64CpuLocation(RAX));
814 instruction->SetLocations(locations);
815}
816
817void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
818 InvokeRuntimeCallingConvention calling_convention;
819 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
820 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
821
822 __ gs()->call(Address::Absolute(
823 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
824
825 codegen_->RecordPcInfo(instruction->GetDexPc());
826}
827
828void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
829 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
830 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
831 if (location.IsStackSlot()) {
832 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
833 } else if (location.IsDoubleStackSlot()) {
834 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
835 }
836 locations->SetOut(location);
837 instruction->SetLocations(locations);
838}
839
840void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
841 // Nothing to do, the parameter is already at its location.
842}
843
844void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
845 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +0000846 locations->SetInAt(0, Location::RequiresRegister());
847 locations->SetOut(Location::SameAsFirstInput());
Nicolas Geoffray9cf35522014-06-09 18:40:10 +0100848 instruction->SetLocations(locations);
849}
850
851void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
852 LocationSummary* locations = instruction->GetLocations();
853 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
854 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
855 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
856}
857
858void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
859 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
860 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
861 locations->SetInAt(i, Location::Any());
862 }
863 locations->SetOut(Location::Any());
864 instruction->SetLocations(locations);
865}
866
867void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
868 LOG(FATAL) << "Unimplemented";
869}
870
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100871void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
872 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
873 locations->SetInAt(0, Location::RequiresRegister());
874 locations->SetInAt(1, Location::RequiresRegister());
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100875 // Temporary registers for the write barrier.
876 if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
877 locations->AddTemp(Location::RequiresRegister());
878 locations->AddTemp(Location::RequiresRegister());
879 }
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100880 instruction->SetLocations(locations);
881}
882
883void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
884 LocationSummary* locations = instruction->GetLocations();
885 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
886 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
887 size_t offset = instruction->GetFieldOffset().SizeValue();
888 Primitive::Type field_type = instruction->InputAt(1)->GetType();
889
890 switch (field_type) {
891 case Primitive::kPrimBoolean:
892 case Primitive::kPrimByte: {
893 __ movb(Address(obj, offset), value);
894 break;
895 }
896
897 case Primitive::kPrimShort:
898 case Primitive::kPrimChar: {
899 __ movw(Address(obj, offset), value);
900 break;
901 }
902
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100903 case Primitive::kPrimInt: {
904 __ movl(Address(obj, offset), value);
905 break;
906 }
907
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100908 case Primitive::kPrimNot: {
909 __ movl(Address(obj, offset), value);
Nicolas Geoffray1a43dd72014-07-17 15:15:34 +0100910 Label is_null;
911 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
912 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
913 __ testl(value, value);
914 __ j(kEqual, &is_null);
915 __ gs()->movq(card, Address::Absolute(
916 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
917 __ movq(temp, obj);
918 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
919 __ movb(Address(temp, card, TIMES_1, 0), card);
920 __ Bind(&is_null);
Nicolas Geoffraye5038322014-07-04 09:41:32 +0100921 break;
922 }
923
924 case Primitive::kPrimLong: {
925 __ movq(Address(obj, offset), value);
926 break;
927 }
928
929 case Primitive::kPrimFloat:
930 case Primitive::kPrimDouble:
931 LOG(FATAL) << "Unimplemented register type " << field_type;
932
933 case Primitive::kPrimVoid:
934 LOG(FATAL) << "Unreachable type " << field_type;
935 }
936}
937
938void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
939 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
940 locations->SetInAt(0, Location::RequiresRegister());
941 locations->SetOut(Location::RequiresRegister());
942 instruction->SetLocations(locations);
943}
944
945void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
946 LocationSummary* locations = instruction->GetLocations();
947 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
948 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
949 size_t offset = instruction->GetFieldOffset().SizeValue();
950
951 switch (instruction->GetType()) {
952 case Primitive::kPrimBoolean: {
953 __ movzxb(out, Address(obj, offset));
954 break;
955 }
956
957 case Primitive::kPrimByte: {
958 __ movsxb(out, Address(obj, offset));
959 break;
960 }
961
962 case Primitive::kPrimShort: {
963 __ movsxw(out, Address(obj, offset));
964 break;
965 }
966
967 case Primitive::kPrimChar: {
968 __ movzxw(out, Address(obj, offset));
969 break;
970 }
971
972 case Primitive::kPrimInt:
973 case Primitive::kPrimNot: {
974 __ movl(out, Address(obj, offset));
975 break;
976 }
977
978 case Primitive::kPrimLong: {
979 __ movq(out, Address(obj, offset));
980 break;
981 }
982
983 case Primitive::kPrimFloat:
984 case Primitive::kPrimDouble:
985 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
986
987 case Primitive::kPrimVoid:
988 LOG(FATAL) << "Unreachable type " << instruction->GetType();
989 }
990}
991
992void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
993 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
994 locations->SetInAt(0, Location::Any());
995 // TODO: Have a normalization phase that makes this instruction never used.
996 locations->SetOut(Location::SameAsFirstInput());
997 instruction->SetLocations(locations);
998}
999
1000void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
1001 SlowPathCode* slow_path =
1002 new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction->GetDexPc());
1003 codegen_->AddSlowPath(slow_path);
1004
1005 LocationSummary* locations = instruction->GetLocations();
1006 Location obj = locations->InAt(0);
1007 DCHECK(obj.Equals(locations->Out()));
1008
1009 if (obj.IsRegister()) {
1010 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1011 } else {
1012 DCHECK(locations->InAt(0).IsStackSlot());
1013 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1014 }
1015 __ j(kEqual, slow_path->GetEntryLabel());
1016}
1017
1018void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1019 temp->SetLocations(nullptr);
1020}
1021
1022void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1023 // Nothing to do, this is driven by the code generator.
1024}
1025
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001026void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1027 LOG(FATAL) << "Unimplemented";
1028}
1029
1030void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001031 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1032}
1033
1034X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1035 return codegen_->GetAssembler();
1036}
1037
1038void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1039 MoveOperands* move = moves_.Get(index);
1040 Location source = move->GetSource();
1041 Location destination = move->GetDestination();
1042
1043 if (source.IsRegister()) {
1044 if (destination.IsRegister()) {
1045 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001046 } else if (destination.IsStackSlot()) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001047 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1048 source.AsX86_64().AsCpuRegister());
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001049 } else {
1050 DCHECK(destination.IsDoubleStackSlot());
1051 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1052 source.AsX86_64().AsCpuRegister());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001053 }
1054 } else if (source.IsStackSlot()) {
1055 if (destination.IsRegister()) {
1056 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1057 Address(CpuRegister(RSP), source.GetStackIndex()));
1058 } else {
1059 DCHECK(destination.IsStackSlot());
1060 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1061 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1062 }
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001063 } else if (source.IsDoubleStackSlot()) {
1064 if (destination.IsRegister()) {
1065 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1066 Address(CpuRegister(RSP), source.GetStackIndex()));
1067 } else {
1068 DCHECK(destination.IsDoubleStackSlot());
1069 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1070 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1071 }
Nicolas Geoffray96f89a22014-07-11 10:57:49 +01001072 } else if (source.IsConstant()) {
1073 HConstant* constant = source.GetConstant();
1074 if (constant->IsIntConstant()) {
1075 Immediate imm(constant->AsIntConstant()->GetValue());
1076 if (destination.IsRegister()) {
1077 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1078 } else {
1079 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1080 }
1081 } else if (constant->IsLongConstant()) {
1082 int64_t value = constant->AsLongConstant()->GetValue();
1083 if (destination.IsRegister()) {
1084 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1085 } else {
1086 __ movq(CpuRegister(TMP), Immediate(value));
1087 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1088 }
1089 } else {
1090 LOG(FATAL) << "Unimplemented constant type";
1091 }
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001092 } else {
1093 LOG(FATAL) << "Unimplemented";
1094 }
1095}
1096
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001097void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001098 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001099 __ movl(Address(CpuRegister(RSP), mem), reg);
1100 __ movl(reg, CpuRegister(TMP));
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001101}
1102
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001103void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001104 ScratchRegisterScope ensure_scratch(
1105 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1106
1107 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1108 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1109 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1110 Address(CpuRegister(RSP), mem2 + stack_offset));
1111 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1112 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1113 CpuRegister(ensure_scratch.GetRegister()));
1114}
1115
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001116void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1117 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1118 __ movq(Address(CpuRegister(RSP), mem), reg);
1119 __ movq(reg, CpuRegister(TMP));
1120}
1121
1122void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1123 ScratchRegisterScope ensure_scratch(
1124 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1125
1126 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1127 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1128 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1129 Address(CpuRegister(RSP), mem2 + stack_offset));
1130 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1131 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1132 CpuRegister(ensure_scratch.GetRegister()));
1133}
1134
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001135void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1136 MoveOperands* move = moves_.Get(index);
1137 Location source = move->GetSource();
1138 Location destination = move->GetDestination();
1139
1140 if (source.IsRegister() && destination.IsRegister()) {
1141 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1142 } else if (source.IsRegister() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001143 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001144 } else if (source.IsStackSlot() && destination.IsRegister()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001145 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001146 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
Nicolas Geoffray412f10c2014-06-19 10:00:34 +01001147 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1148 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1149 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1150 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1151 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1152 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1153 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
Nicolas Geoffrayecb2f9b2014-06-13 08:59:59 +00001154 } else {
1155 LOG(FATAL) << "Unimplemented";
1156 }
1157}
1158
1159
1160void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1161 __ pushq(CpuRegister(reg));
1162}
1163
1164
1165void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1166 __ popq(CpuRegister(reg));
Nicolas Geoffray9cf35522014-06-09 18:40:10 +01001167}
1168
1169} // namespace x86_64
1170} // namespace art