1 /*
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"
20 #include "gc/accounting/card_table.h"
21 #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/stack_checks.h"
27 #include "utils/x86_64/assembler_x86_64.h"
28 #include "utils/x86_64/managed_register_x86_64.h"
29
30 namespace art {
31
AsX86_64() const32 x86_64::X86_64ManagedRegister Location::AsX86_64() const {
33 return reg().AsX86_64();
34 }
35
36 namespace x86_64 {
37
38 static constexpr bool kExplicitStackOverflowCheck = true;
39
40 // Some x86_64 instructions require a register to be available as temp.
41 static constexpr Register TMP = R11;
42
43 static constexpr int kNumberOfPushedRegistersAtEntry = 1;
44 static constexpr int kCurrentMethodStackOffset = 0;
45
X86_64CpuLocation(Register reg)46 static Location X86_64CpuLocation(Register reg) {
47 return Location::RegisterLocation(X86_64ManagedRegister::FromCpuRegister(reg));
48 }
49
50 static constexpr Register kRuntimeParameterCoreRegisters[] = { RDI, RSI, RDX };
51 static constexpr size_t kRuntimeParameterCoreRegistersLength =
52 arraysize(kRuntimeParameterCoreRegisters);
53
54 class InvokeRuntimeCallingConvention : public CallingConvention<Register> {
55 public:
InvokeRuntimeCallingConvention()56 InvokeRuntimeCallingConvention()
57 : CallingConvention(kRuntimeParameterCoreRegisters,
58 kRuntimeParameterCoreRegistersLength) {}
59
60 private:
61 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention);
62 };
63
64 #define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())->
65
66 class NullCheckSlowPathX86_64 : public SlowPathCode {
67 public:
NullCheckSlowPathX86_64(uint32_t dex_pc)68 explicit NullCheckSlowPathX86_64(uint32_t dex_pc) : dex_pc_(dex_pc) {}
69
EmitNativeCode(CodeGenerator * codegen)70 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
71 __ Bind(GetEntryLabel());
72 __ gs()->call(
73 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowNullPointer), true));
74 codegen->RecordPcInfo(dex_pc_);
75 }
76
77 private:
78 const uint32_t dex_pc_;
79 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathX86_64);
80 };
81
82 class StackOverflowCheckSlowPathX86_64 : public SlowPathCode {
83 public:
StackOverflowCheckSlowPathX86_64()84 StackOverflowCheckSlowPathX86_64() {}
85
EmitNativeCode(CodeGenerator * codegen)86 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
87 __ Bind(GetEntryLabel());
88 __ addq(CpuRegister(RSP),
89 Immediate(codegen->GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
90 __ gs()->jmp(
91 Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowStackOverflow), true));
92 }
93
94 private:
95 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
96 };
97
98 class BoundsCheckSlowPathX86_64 : public SlowPathCode {
99 public:
BoundsCheckSlowPathX86_64(uint32_t dex_pc,Location index_location,Location length_location)100 explicit BoundsCheckSlowPathX86_64(uint32_t dex_pc,
101 Location index_location,
102 Location length_location)
103 : dex_pc_(dex_pc), index_location_(index_location), length_location_(length_location) {}
104
EmitNativeCode(CodeGenerator * codegen)105 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
106 CodeGeneratorX86_64* x64_codegen = reinterpret_cast<CodeGeneratorX86_64*>(codegen);
107 __ Bind(GetEntryLabel());
108 InvokeRuntimeCallingConvention calling_convention;
109 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(0)), index_location_);
110 x64_codegen->Move(X86_64CpuLocation(calling_convention.GetRegisterAt(1)), length_location_);
111 __ gs()->call(Address::Absolute(
112 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pThrowArrayBounds), true));
113 codegen->RecordPcInfo(dex_pc_);
114 }
115
116 private:
117 const uint32_t dex_pc_;
118 const Location index_location_;
119 const Location length_location_;
120
121 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
122 };
123
124 #undef __
125 #define __ reinterpret_cast<X86_64Assembler*>(GetAssembler())->
126
X86_64Condition(IfCondition cond)127 inline Condition X86_64Condition(IfCondition cond) {
128 switch (cond) {
129 case kCondEQ: return kEqual;
130 case kCondNE: return kNotEqual;
131 case kCondLT: return kLess;
132 case kCondLE: return kLessEqual;
133 case kCondGT: return kGreater;
134 case kCondGE: return kGreaterEqual;
135 default:
136 LOG(FATAL) << "Unknown if condition";
137 }
138 return kEqual;
139 }
140
DumpCoreRegister(std::ostream & stream,int reg) const141 void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const {
142 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg));
143 }
144
DumpFloatingPointRegister(std::ostream & stream,int reg) const145 void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const {
146 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg));
147 }
148
CodeGeneratorX86_64(HGraph * graph)149 CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph)
150 : CodeGenerator(graph, kNumberOfRegIds),
151 location_builder_(graph, this),
152 instruction_visitor_(graph, this),
153 move_resolver_(graph->GetArena(), this) {}
154
FrameEntrySpillSize() const155 size_t CodeGeneratorX86_64::FrameEntrySpillSize() const {
156 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize;
157 }
158
InstructionCodeGeneratorX86_64(HGraph * graph,CodeGeneratorX86_64 * codegen)159 InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph,
160 CodeGeneratorX86_64* codegen)
161 : HGraphVisitor(graph),
162 assembler_(codegen->GetAssembler()),
163 codegen_(codegen) {}
164
AllocateFreeRegister(Primitive::Type type,bool * blocked_registers) const165 ManagedRegister CodeGeneratorX86_64::AllocateFreeRegister(Primitive::Type type,
166 bool* blocked_registers) const {
167 switch (type) {
168 case Primitive::kPrimLong:
169 case Primitive::kPrimByte:
170 case Primitive::kPrimBoolean:
171 case Primitive::kPrimChar:
172 case Primitive::kPrimShort:
173 case Primitive::kPrimInt:
174 case Primitive::kPrimNot: {
175 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCpuRegisters);
176 return X86_64ManagedRegister::FromCpuRegister(static_cast<Register>(reg));
177 }
178
179 case Primitive::kPrimFloat:
180 case Primitive::kPrimDouble:
181 LOG(FATAL) << "Unimplemented register type " << type;
182
183 case Primitive::kPrimVoid:
184 LOG(FATAL) << "Unreachable type " << type;
185 }
186
187 return ManagedRegister::NoRegister();
188 }
189
SetupBlockedRegisters(bool * blocked_registers) const190 void CodeGeneratorX86_64::SetupBlockedRegisters(bool* blocked_registers) const {
191 // Stack register is always reserved.
192 blocked_registers[RSP] = true;
193
194 // Block the register used as TMP.
195 blocked_registers[TMP] = true;
196
197 // TODO: We currently don't use Quick's callee saved registers.
198 blocked_registers[RBX] = true;
199 blocked_registers[RBP] = true;
200 blocked_registers[R12] = true;
201 blocked_registers[R13] = true;
202 blocked_registers[R14] = true;
203 blocked_registers[R15] = true;
204 }
205
GenerateFrameEntry()206 void CodeGeneratorX86_64::GenerateFrameEntry() {
207 // Create a fake register to mimic Quick.
208 static const int kFakeReturnRegister = 16;
209 core_spill_mask_ |= (1 << kFakeReturnRegister);
210
211 // The return PC has already been pushed on the stack.
212 __ subq(CpuRegister(RSP),
213 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
214
215 bool skip_overflow_check = IsLeafMethod()
216 && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kX86_64);
217
218 if (!skip_overflow_check) {
219 if (kExplicitStackOverflowCheck) {
220 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathX86_64();
221 AddSlowPath(slow_path);
222
223 __ gs()->cmpq(CpuRegister(RSP),
224 Address::Absolute(Thread::StackEndOffset<kX86_64WordSize>(), true));
225 __ j(kLess, slow_path->GetEntryLabel());
226 } else {
227 __ testq(CpuRegister(RAX), Address(
228 CpuRegister(RSP), -static_cast<int32_t>(GetStackOverflowReservedBytes(kX86_64))));
229 }
230 }
231
232 __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI));
233 }
234
GenerateFrameExit()235 void CodeGeneratorX86_64::GenerateFrameExit() {
236 __ addq(CpuRegister(RSP),
237 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize));
238 }
239
Bind(Label * label)240 void CodeGeneratorX86_64::Bind(Label* label) {
241 __ Bind(label);
242 }
243
LoadCurrentMethod(CpuRegister reg)244 void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) {
245 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset));
246 }
247
GetStackLocation(HLoadLocal * load) const248 Location CodeGeneratorX86_64::GetStackLocation(HLoadLocal* load) const {
249 switch (load->GetType()) {
250 case Primitive::kPrimLong:
251 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal()));
252 break;
253
254 case Primitive::kPrimInt:
255 case Primitive::kPrimNot:
256 return Location::StackSlot(GetStackSlot(load->GetLocal()));
257
258 case Primitive::kPrimFloat:
259 case Primitive::kPrimDouble:
260 LOG(FATAL) << "Unimplemented type " << load->GetType();
261
262 case Primitive::kPrimBoolean:
263 case Primitive::kPrimByte:
264 case Primitive::kPrimChar:
265 case Primitive::kPrimShort:
266 case Primitive::kPrimVoid:
267 LOG(FATAL) << "Unexpected type " << load->GetType();
268 }
269
270 LOG(FATAL) << "Unreachable";
271 return Location();
272 }
273
Move(Location destination,Location source)274 void CodeGeneratorX86_64::Move(Location destination, Location source) {
275 if (source.Equals(destination)) {
276 return;
277 }
278 if (destination.IsRegister()) {
279 if (source.IsRegister()) {
280 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
281 } else if (source.IsStackSlot()) {
282 __ movl(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
283 } else {
284 DCHECK(source.IsDoubleStackSlot());
285 __ movq(destination.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), source.GetStackIndex()));
286 }
287 } else if (destination.IsStackSlot()) {
288 if (source.IsRegister()) {
289 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
290 } else {
291 DCHECK(source.IsStackSlot());
292 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
293 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
294 }
295 } else {
296 DCHECK(destination.IsDoubleStackSlot());
297 if (source.IsRegister()) {
298 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), source.AsX86_64().AsCpuRegister());
299 } else {
300 DCHECK(source.IsDoubleStackSlot());
301 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
302 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
303 }
304 }
305 }
306
Move(HInstruction * instruction,Location location,HInstruction * move_for)307 void CodeGeneratorX86_64::Move(HInstruction* instruction,
308 Location location,
309 HInstruction* move_for) {
310 if (instruction->AsIntConstant() != nullptr) {
311 Immediate imm(instruction->AsIntConstant()->GetValue());
312 if (location.IsRegister()) {
313 __ movl(location.AsX86_64().AsCpuRegister(), imm);
314 } else {
315 __ movl(Address(CpuRegister(RSP), location.GetStackIndex()), imm);
316 }
317 } else if (instruction->AsLongConstant() != nullptr) {
318 int64_t value = instruction->AsLongConstant()->GetValue();
319 if (location.IsRegister()) {
320 __ movq(location.AsX86_64().AsCpuRegister(), Immediate(value));
321 } else {
322 __ movq(CpuRegister(TMP), Immediate(value));
323 __ movq(Address(CpuRegister(RSP), location.GetStackIndex()), CpuRegister(TMP));
324 }
325 } else if (instruction->AsLoadLocal() != nullptr) {
326 switch (instruction->GetType()) {
327 case Primitive::kPrimBoolean:
328 case Primitive::kPrimByte:
329 case Primitive::kPrimChar:
330 case Primitive::kPrimShort:
331 case Primitive::kPrimInt:
332 case Primitive::kPrimNot:
333 Move(location, Location::StackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
334 break;
335
336 case Primitive::kPrimLong:
337 Move(location, Location::DoubleStackSlot(GetStackSlot(instruction->AsLoadLocal()->GetLocal())));
338 break;
339
340 default:
341 LOG(FATAL) << "Unimplemented local type " << instruction->GetType();
342 }
343 } else {
344 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary());
345 switch (instruction->GetType()) {
346 case Primitive::kPrimBoolean:
347 case Primitive::kPrimByte:
348 case Primitive::kPrimChar:
349 case Primitive::kPrimShort:
350 case Primitive::kPrimInt:
351 case Primitive::kPrimNot:
352 case Primitive::kPrimLong:
353 Move(location, instruction->GetLocations()->Out());
354 break;
355
356 default:
357 LOG(FATAL) << "Unimplemented type " << instruction->GetType();
358 }
359 }
360 }
361
VisitGoto(HGoto * got)362 void LocationsBuilderX86_64::VisitGoto(HGoto* got) {
363 got->SetLocations(nullptr);
364 }
365
VisitGoto(HGoto * got)366 void InstructionCodeGeneratorX86_64::VisitGoto(HGoto* got) {
367 HBasicBlock* successor = got->GetSuccessor();
368 if (GetGraph()->GetExitBlock() == successor) {
369 codegen_->GenerateFrameExit();
370 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) {
371 __ jmp(codegen_->GetLabelOf(successor));
372 }
373 }
374
VisitExit(HExit * exit)375 void LocationsBuilderX86_64::VisitExit(HExit* exit) {
376 exit->SetLocations(nullptr);
377 }
378
VisitExit(HExit * exit)379 void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) {
380 if (kIsDebugBuild) {
381 __ Comment("Unreachable");
382 __ int3();
383 }
384 }
385
VisitIf(HIf * if_instr)386 void LocationsBuilderX86_64::VisitIf(HIf* if_instr) {
387 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr);
388 HInstruction* cond = if_instr->InputAt(0);
389 DCHECK(cond->IsCondition());
390 HCondition* condition = cond->AsCondition();
391 if (condition->NeedsMaterialization()) {
392 locations->SetInAt(0, Location::Any());
393 }
394 if_instr->SetLocations(locations);
395 }
396
VisitIf(HIf * if_instr)397 void InstructionCodeGeneratorX86_64::VisitIf(HIf* if_instr) {
398 HInstruction* cond = if_instr->InputAt(0);
399 DCHECK(cond->IsCondition());
400 HCondition* condition = cond->AsCondition();
401 if (condition->NeedsMaterialization()) {
402 // Materialized condition, compare against 0.
403 Location lhs = if_instr->GetLocations()->InAt(0);
404 if (lhs.IsRegister()) {
405 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Immediate(0));
406 } else {
407 __ cmpl(Address(CpuRegister(RSP), lhs.GetStackIndex()), Immediate(0));
408 }
409 __ j(kEqual, codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
410 } else {
411 Location lhs = condition->GetLocations()->InAt(0);
412 Location rhs = condition->GetLocations()->InAt(1);
413 if (rhs.IsRegister()) {
414 __ cmpl(lhs.AsX86_64().AsCpuRegister(), rhs.AsX86_64().AsCpuRegister());
415 } else if (rhs.IsConstant()) {
416 __ cmpl(lhs.AsX86_64().AsCpuRegister(),
417 Immediate(rhs.GetConstant()->AsIntConstant()->GetValue()));
418 } else {
419 __ cmpl(lhs.AsX86_64().AsCpuRegister(), Address(CpuRegister(RSP), rhs.GetStackIndex()));
420 }
421 __ j(X86_64Condition(condition->GetCondition()),
422 codegen_->GetLabelOf(if_instr->IfTrueSuccessor()));
423 }
424 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) {
425 __ jmp(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()));
426 }
427 }
428
VisitLocal(HLocal * local)429 void LocationsBuilderX86_64::VisitLocal(HLocal* local) {
430 local->SetLocations(nullptr);
431 }
432
VisitLocal(HLocal * local)433 void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) {
434 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock());
435 }
436
VisitLoadLocal(HLoadLocal * local)437 void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) {
438 local->SetLocations(nullptr);
439 }
440
VisitLoadLocal(HLoadLocal * load)441 void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) {
442 // Nothing to do, this is driven by the code generator.
443 }
444
VisitStoreLocal(HStoreLocal * store)445 void LocationsBuilderX86_64::VisitStoreLocal(HStoreLocal* store) {
446 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store);
447 switch (store->InputAt(1)->GetType()) {
448 case Primitive::kPrimBoolean:
449 case Primitive::kPrimByte:
450 case Primitive::kPrimChar:
451 case Primitive::kPrimShort:
452 case Primitive::kPrimInt:
453 case Primitive::kPrimNot:
454 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal())));
455 break;
456
457 case Primitive::kPrimLong:
458 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal())));
459 break;
460
461 default:
462 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType();
463 }
464 store->SetLocations(locations);
465 }
466
VisitStoreLocal(HStoreLocal * store)467 void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) {
468 }
469
VisitCondition(HCondition * comp)470 void LocationsBuilderX86_64::VisitCondition(HCondition* comp) {
471 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp);
472 locations->SetInAt(0, Location::RequiresRegister());
473 locations->SetInAt(1, Location::Any());
474 if (comp->NeedsMaterialization()) {
475 locations->SetOut(Location::RequiresRegister());
476 }
477 comp->SetLocations(locations);
478 }
479
VisitCondition(HCondition * comp)480 void InstructionCodeGeneratorX86_64::VisitCondition(HCondition* comp) {
481 if (comp->NeedsMaterialization()) {
482 LocationSummary* locations = comp->GetLocations();
483 if (locations->InAt(1).IsRegister()) {
484 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
485 locations->InAt(1).AsX86_64().AsCpuRegister());
486 } else if (locations->InAt(1).IsConstant()) {
487 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
488 Immediate(locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()));
489 } else {
490 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
491 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
492 }
493 __ setcc(X86_64Condition(comp->GetCondition()),
494 comp->GetLocations()->Out().AsX86_64().AsCpuRegister());
495 }
496 }
497
VisitEqual(HEqual * comp)498 void LocationsBuilderX86_64::VisitEqual(HEqual* comp) {
499 VisitCondition(comp);
500 }
501
VisitEqual(HEqual * comp)502 void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) {
503 VisitCondition(comp);
504 }
505
VisitNotEqual(HNotEqual * comp)506 void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) {
507 VisitCondition(comp);
508 }
509
VisitNotEqual(HNotEqual * comp)510 void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) {
511 VisitCondition(comp);
512 }
513
VisitLessThan(HLessThan * comp)514 void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) {
515 VisitCondition(comp);
516 }
517
VisitLessThan(HLessThan * comp)518 void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) {
519 VisitCondition(comp);
520 }
521
VisitLessThanOrEqual(HLessThanOrEqual * comp)522 void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
523 VisitCondition(comp);
524 }
525
VisitLessThanOrEqual(HLessThanOrEqual * comp)526 void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) {
527 VisitCondition(comp);
528 }
529
VisitGreaterThan(HGreaterThan * comp)530 void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) {
531 VisitCondition(comp);
532 }
533
VisitGreaterThan(HGreaterThan * comp)534 void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) {
535 VisitCondition(comp);
536 }
537
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)538 void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
539 VisitCondition(comp);
540 }
541
VisitGreaterThanOrEqual(HGreaterThanOrEqual * comp)542 void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) {
543 VisitCondition(comp);
544 }
545
VisitCompare(HCompare * compare)546 void LocationsBuilderX86_64::VisitCompare(HCompare* compare) {
547 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(compare);
548 locations->SetInAt(0, Location::RequiresRegister());
549 locations->SetInAt(1, Location::RequiresRegister());
550 locations->SetOut(Location::RequiresRegister());
551 compare->SetLocations(locations);
552 }
553
VisitCompare(HCompare * compare)554 void InstructionCodeGeneratorX86_64::VisitCompare(HCompare* compare) {
555 Label greater, done;
556 LocationSummary* locations = compare->GetLocations();
557 switch (compare->InputAt(0)->GetType()) {
558 case Primitive::kPrimLong:
559 __ cmpq(locations->InAt(0).AsX86_64().AsCpuRegister(),
560 locations->InAt(1).AsX86_64().AsCpuRegister());
561 break;
562 default:
563 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType();
564 }
565
566 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(0));
567 __ j(kEqual, &done);
568 __ j(kGreater, &greater);
569
570 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(-1));
571 __ jmp(&done);
572
573 __ Bind(&greater);
574 __ movl(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
575
576 __ Bind(&done);
577 }
578
VisitIntConstant(HIntConstant * constant)579 void LocationsBuilderX86_64::VisitIntConstant(HIntConstant* constant) {
580 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
581 locations->SetOut(Location::ConstantLocation(constant));
582 constant->SetLocations(locations);
583 }
584
VisitIntConstant(HIntConstant * constant)585 void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) {
586 }
587
VisitLongConstant(HLongConstant * constant)588 void LocationsBuilderX86_64::VisitLongConstant(HLongConstant* constant) {
589 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant);
590 locations->SetOut(Location::ConstantLocation(constant));
591 constant->SetLocations(locations);
592 }
593
VisitLongConstant(HLongConstant * constant)594 void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) {
595 }
596
VisitReturnVoid(HReturnVoid * ret)597 void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) {
598 ret->SetLocations(nullptr);
599 }
600
VisitReturnVoid(HReturnVoid * ret)601 void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) {
602 codegen_->GenerateFrameExit();
603 __ ret();
604 }
605
VisitReturn(HReturn * ret)606 void LocationsBuilderX86_64::VisitReturn(HReturn* ret) {
607 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret);
608 switch (ret->InputAt(0)->GetType()) {
609 case Primitive::kPrimBoolean:
610 case Primitive::kPrimByte:
611 case Primitive::kPrimChar:
612 case Primitive::kPrimShort:
613 case Primitive::kPrimInt:
614 case Primitive::kPrimNot:
615 case Primitive::kPrimLong:
616 locations->SetInAt(0, X86_64CpuLocation(RAX));
617 break;
618
619 default:
620 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
621 }
622 ret->SetLocations(locations);
623 }
624
VisitReturn(HReturn * ret)625 void InstructionCodeGeneratorX86_64::VisitReturn(HReturn* ret) {
626 if (kIsDebugBuild) {
627 switch (ret->InputAt(0)->GetType()) {
628 case Primitive::kPrimBoolean:
629 case Primitive::kPrimByte:
630 case Primitive::kPrimChar:
631 case Primitive::kPrimShort:
632 case Primitive::kPrimInt:
633 case Primitive::kPrimNot:
634 case Primitive::kPrimLong:
635 DCHECK_EQ(ret->GetLocations()->InAt(0).AsX86_64().AsCpuRegister().AsRegister(), RAX);
636 break;
637
638 default:
639 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType();
640 }
641 }
642 codegen_->GenerateFrameExit();
643 __ ret();
644 }
645
GetNextLocation(Primitive::Type type)646 Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) {
647 switch (type) {
648 case Primitive::kPrimBoolean:
649 case Primitive::kPrimByte:
650 case Primitive::kPrimChar:
651 case Primitive::kPrimShort:
652 case Primitive::kPrimInt:
653 case Primitive::kPrimNot: {
654 uint32_t index = gp_index_++;
655 stack_index_++;
656 if (index < calling_convention.GetNumberOfRegisters()) {
657 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
658 } else {
659 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 1));
660 }
661 }
662
663 case Primitive::kPrimLong: {
664 uint32_t index = gp_index_;
665 stack_index_ += 2;
666 if (index < calling_convention.GetNumberOfRegisters()) {
667 gp_index_ += 1;
668 return X86_64CpuLocation(calling_convention.GetRegisterAt(index));
669 } else {
670 gp_index_ += 2;
671 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index_ - 2));
672 }
673 }
674
675 case Primitive::kPrimDouble:
676 case Primitive::kPrimFloat:
677 LOG(FATAL) << "Unimplemented parameter type " << type;
678 break;
679
680 case Primitive::kPrimVoid:
681 LOG(FATAL) << "Unexpected parameter type " << type;
682 break;
683 }
684 return Location();
685 }
686
VisitInvokeStatic(HInvokeStatic * invoke)687 void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
688 codegen_->MarkNotLeaf();
689 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke);
690 locations->AddTemp(X86_64CpuLocation(RDI));
691
692 InvokeDexCallingConventionVisitor calling_convention_visitor;
693 for (size_t i = 0; i < invoke->InputCount(); ++i) {
694 HInstruction* input = invoke->InputAt(i);
695 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
696 }
697
698 switch (invoke->GetType()) {
699 case Primitive::kPrimBoolean:
700 case Primitive::kPrimByte:
701 case Primitive::kPrimChar:
702 case Primitive::kPrimShort:
703 case Primitive::kPrimInt:
704 case Primitive::kPrimNot:
705 case Primitive::kPrimLong:
706 locations->SetOut(X86_64CpuLocation(RAX));
707 break;
708
709 case Primitive::kPrimVoid:
710 break;
711
712 case Primitive::kPrimDouble:
713 case Primitive::kPrimFloat:
714 LOG(FATAL) << "Unimplemented return type " << invoke->GetType();
715 break;
716 }
717
718 invoke->SetLocations(locations);
719 }
720
VisitInvokeStatic(HInvokeStatic * invoke)721 void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
722 CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
723 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
724 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
725 invoke->GetIndexInDexCache() * heap_reference_size;
726
727 // TODO: Implement all kinds of calls:
728 // 1) boot -> boot
729 // 2) app -> boot
730 // 3) app -> app
731 //
732 // Currently we implement the app -> app logic, which looks up in the resolve cache.
733
734 // temp = method;
735 LoadCurrentMethod(temp);
736 // temp = temp->dex_cache_resolved_methods_;
737 __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
738 // temp = temp[index_in_cache]
739 __ movl(temp, Address(temp, index_in_cache));
740 // (temp + offset_of_quick_compiled_code)()
741 __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(
742 kX86_64PointerSize).SizeValue()));
743
744 DCHECK(!codegen_->IsLeafMethod());
745 codegen_->RecordPcInfo(invoke->GetDexPc());
746 }
747
VisitAdd(HAdd * add)748 void LocationsBuilderX86_64::VisitAdd(HAdd* add) {
749 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add);
750 switch (add->GetResultType()) {
751 case Primitive::kPrimInt: {
752 locations->SetInAt(0, Location::RequiresRegister());
753 locations->SetInAt(1, Location::Any());
754 locations->SetOut(Location::SameAsFirstInput());
755 break;
756 }
757 case Primitive::kPrimLong: {
758 locations->SetInAt(0, Location::RequiresRegister());
759 locations->SetInAt(1, Location::RequiresRegister());
760 locations->SetOut(Location::SameAsFirstInput());
761 break;
762 }
763
764 case Primitive::kPrimBoolean:
765 case Primitive::kPrimByte:
766 case Primitive::kPrimChar:
767 case Primitive::kPrimShort:
768 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
769 break;
770
771 default:
772 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
773 }
774 add->SetLocations(locations);
775 }
776
VisitAdd(HAdd * add)777 void InstructionCodeGeneratorX86_64::VisitAdd(HAdd* add) {
778 LocationSummary* locations = add->GetLocations();
779 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
780 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
781 switch (add->GetResultType()) {
782 case Primitive::kPrimInt: {
783 if (locations->InAt(1).IsRegister()) {
784 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
785 locations->InAt(1).AsX86_64().AsCpuRegister());
786 } else if (locations->InAt(1).IsConstant()) {
787 HConstant* instruction = locations->InAt(1).GetConstant();
788 Immediate imm(instruction->AsIntConstant()->GetValue());
789 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
790 } else {
791 __ addl(locations->InAt(0).AsX86_64().AsCpuRegister(),
792 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
793 }
794 break;
795 }
796 case Primitive::kPrimLong: {
797 __ addq(locations->InAt(0).AsX86_64().AsCpuRegister(),
798 locations->InAt(1).AsX86_64().AsCpuRegister());
799 break;
800 }
801
802 case Primitive::kPrimBoolean:
803 case Primitive::kPrimByte:
804 case Primitive::kPrimChar:
805 case Primitive::kPrimShort:
806 LOG(FATAL) << "Unexpected add type " << add->GetResultType();
807 break;
808
809 default:
810 LOG(FATAL) << "Unimplemented add type " << add->GetResultType();
811 }
812 }
813
VisitSub(HSub * sub)814 void LocationsBuilderX86_64::VisitSub(HSub* sub) {
815 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub);
816 switch (sub->GetResultType()) {
817 case Primitive::kPrimInt: {
818 locations->SetInAt(0, Location::RequiresRegister());
819 locations->SetInAt(1, Location::Any());
820 locations->SetOut(Location::SameAsFirstInput());
821 break;
822 }
823 case Primitive::kPrimLong: {
824 locations->SetInAt(0, Location::RequiresRegister());
825 locations->SetInAt(1, Location::RequiresRegister());
826 locations->SetOut(Location::SameAsFirstInput());
827 break;
828 }
829
830 case Primitive::kPrimBoolean:
831 case Primitive::kPrimByte:
832 case Primitive::kPrimChar:
833 case Primitive::kPrimShort:
834 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
835 break;
836
837 default:
838 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
839 }
840 sub->SetLocations(locations);
841 }
842
VisitSub(HSub * sub)843 void InstructionCodeGeneratorX86_64::VisitSub(HSub* sub) {
844 LocationSummary* locations = sub->GetLocations();
845 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
846 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
847 switch (sub->GetResultType()) {
848 case Primitive::kPrimInt: {
849 if (locations->InAt(1).IsRegister()) {
850 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
851 locations->InAt(1).AsX86_64().AsCpuRegister());
852 } else if (locations->InAt(1).IsConstant()) {
853 HConstant* instruction = locations->InAt(1).GetConstant();
854 Immediate imm(instruction->AsIntConstant()->GetValue());
855 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(), imm);
856 } else {
857 __ subl(locations->InAt(0).AsX86_64().AsCpuRegister(),
858 Address(CpuRegister(RSP), locations->InAt(1).GetStackIndex()));
859 }
860 break;
861 }
862 case Primitive::kPrimLong: {
863 __ subq(locations->InAt(0).AsX86_64().AsCpuRegister(),
864 locations->InAt(1).AsX86_64().AsCpuRegister());
865 break;
866 }
867
868 case Primitive::kPrimBoolean:
869 case Primitive::kPrimByte:
870 case Primitive::kPrimChar:
871 case Primitive::kPrimShort:
872 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType();
873 break;
874
875 default:
876 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType();
877 }
878 }
879
VisitNewInstance(HNewInstance * instruction)880 void LocationsBuilderX86_64::VisitNewInstance(HNewInstance* instruction) {
881 codegen_->MarkNotLeaf();
882 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
883 locations->SetOut(X86_64CpuLocation(RAX));
884 instruction->SetLocations(locations);
885 }
886
VisitNewInstance(HNewInstance * instruction)887 void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) {
888 InvokeRuntimeCallingConvention calling_convention;
889 LoadCurrentMethod(CpuRegister(calling_convention.GetRegisterAt(1)));
890 __ movq(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(instruction->GetTypeIndex()));
891
892 __ gs()->call(Address::Absolute(
893 QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAllocObjectWithAccessCheck), true));
894
895 DCHECK(!codegen_->IsLeafMethod());
896 codegen_->RecordPcInfo(instruction->GetDexPc());
897 }
898
VisitParameterValue(HParameterValue * instruction)899 void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) {
900 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
901 Location location = parameter_visitor_.GetNextLocation(instruction->GetType());
902 if (location.IsStackSlot()) {
903 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
904 } else if (location.IsDoubleStackSlot()) {
905 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize());
906 }
907 locations->SetOut(location);
908 instruction->SetLocations(locations);
909 }
910
VisitParameterValue(HParameterValue * instruction)911 void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) {
912 // Nothing to do, the parameter is already at its location.
913 }
914
VisitNot(HNot * instruction)915 void LocationsBuilderX86_64::VisitNot(HNot* instruction) {
916 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
917 locations->SetInAt(0, Location::RequiresRegister());
918 locations->SetOut(Location::SameAsFirstInput());
919 instruction->SetLocations(locations);
920 }
921
VisitNot(HNot * instruction)922 void InstructionCodeGeneratorX86_64::VisitNot(HNot* instruction) {
923 LocationSummary* locations = instruction->GetLocations();
924 DCHECK_EQ(locations->InAt(0).AsX86_64().AsCpuRegister().AsRegister(),
925 locations->Out().AsX86_64().AsCpuRegister().AsRegister());
926 __ xorq(locations->Out().AsX86_64().AsCpuRegister(), Immediate(1));
927 }
928
VisitPhi(HPhi * instruction)929 void LocationsBuilderX86_64::VisitPhi(HPhi* instruction) {
930 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
931 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) {
932 locations->SetInAt(i, Location::Any());
933 }
934 locations->SetOut(Location::Any());
935 instruction->SetLocations(locations);
936 }
937
VisitPhi(HPhi * instruction)938 void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) {
939 LOG(FATAL) << "Unimplemented";
940 }
941
VisitInstanceFieldSet(HInstanceFieldSet * instruction)942 void LocationsBuilderX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
943 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
944 locations->SetInAt(0, Location::RequiresRegister());
945 locations->SetInAt(1, Location::RequiresRegister());
946 // Temporary registers for the write barrier.
947 if (instruction->InputAt(1)->GetType() == Primitive::kPrimNot) {
948 locations->AddTemp(Location::RequiresRegister());
949 locations->AddTemp(Location::RequiresRegister());
950 }
951 instruction->SetLocations(locations);
952 }
953
VisitInstanceFieldSet(HInstanceFieldSet * instruction)954 void InstructionCodeGeneratorX86_64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) {
955 LocationSummary* locations = instruction->GetLocations();
956 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
957 CpuRegister value = locations->InAt(1).AsX86_64().AsCpuRegister();
958 size_t offset = instruction->GetFieldOffset().SizeValue();
959 Primitive::Type field_type = instruction->InputAt(1)->GetType();
960
961 switch (field_type) {
962 case Primitive::kPrimBoolean:
963 case Primitive::kPrimByte: {
964 __ movb(Address(obj, offset), value);
965 break;
966 }
967
968 case Primitive::kPrimShort:
969 case Primitive::kPrimChar: {
970 __ movw(Address(obj, offset), value);
971 break;
972 }
973
974 case Primitive::kPrimInt:
975 case Primitive::kPrimNot: {
976 __ movl(Address(obj, offset), value);
977 if (field_type == Primitive::kPrimNot) {
978 CpuRegister temp = locations->GetTemp(0).AsX86_64().AsCpuRegister();
979 CpuRegister card = locations->GetTemp(1).AsX86_64().AsCpuRegister();
980 codegen_->MarkGCCard(temp, card, obj, value);
981 }
982 break;
983 }
984
985 case Primitive::kPrimLong: {
986 __ movq(Address(obj, offset), value);
987 break;
988 }
989
990 case Primitive::kPrimFloat:
991 case Primitive::kPrimDouble:
992 LOG(FATAL) << "Unimplemented register type " << field_type;
993
994 case Primitive::kPrimVoid:
995 LOG(FATAL) << "Unreachable type " << field_type;
996 }
997 }
998
VisitInstanceFieldGet(HInstanceFieldGet * instruction)999 void LocationsBuilderX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1000 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1001 locations->SetInAt(0, Location::RequiresRegister());
1002 locations->SetOut(Location::RequiresRegister());
1003 instruction->SetLocations(locations);
1004 }
1005
VisitInstanceFieldGet(HInstanceFieldGet * instruction)1006 void InstructionCodeGeneratorX86_64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) {
1007 LocationSummary* locations = instruction->GetLocations();
1008 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1009 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1010 size_t offset = instruction->GetFieldOffset().SizeValue();
1011
1012 switch (instruction->GetType()) {
1013 case Primitive::kPrimBoolean: {
1014 __ movzxb(out, Address(obj, offset));
1015 break;
1016 }
1017
1018 case Primitive::kPrimByte: {
1019 __ movsxb(out, Address(obj, offset));
1020 break;
1021 }
1022
1023 case Primitive::kPrimShort: {
1024 __ movsxw(out, Address(obj, offset));
1025 break;
1026 }
1027
1028 case Primitive::kPrimChar: {
1029 __ movzxw(out, Address(obj, offset));
1030 break;
1031 }
1032
1033 case Primitive::kPrimInt:
1034 case Primitive::kPrimNot: {
1035 __ movl(out, Address(obj, offset));
1036 break;
1037 }
1038
1039 case Primitive::kPrimLong: {
1040 __ movq(out, Address(obj, offset));
1041 break;
1042 }
1043
1044 case Primitive::kPrimFloat:
1045 case Primitive::kPrimDouble:
1046 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1047
1048 case Primitive::kPrimVoid:
1049 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1050 }
1051 }
1052
VisitNullCheck(HNullCheck * instruction)1053 void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
1054 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1055 locations->SetInAt(0, Location::Any());
1056 // TODO: Have a normalization phase that makes this instruction never used.
1057 locations->SetOut(Location::SameAsFirstInput());
1058 instruction->SetLocations(locations);
1059 }
1060
VisitNullCheck(HNullCheck * instruction)1061 void InstructionCodeGeneratorX86_64::VisitNullCheck(HNullCheck* instruction) {
1062 SlowPathCode* slow_path =
1063 new (GetGraph()->GetArena()) NullCheckSlowPathX86_64(instruction->GetDexPc());
1064 codegen_->AddSlowPath(slow_path);
1065
1066 LocationSummary* locations = instruction->GetLocations();
1067 Location obj = locations->InAt(0);
1068 DCHECK(obj.Equals(locations->Out()));
1069
1070 if (obj.IsRegister()) {
1071 __ cmpl(obj.AsX86_64().AsCpuRegister(), Immediate(0));
1072 } else {
1073 DCHECK(locations->InAt(0).IsStackSlot());
1074 __ cmpl(Address(CpuRegister(RSP), obj.GetStackIndex()), Immediate(0));
1075 }
1076 __ j(kEqual, slow_path->GetEntryLabel());
1077 }
1078
VisitArrayGet(HArrayGet * instruction)1079 void LocationsBuilderX86_64::VisitArrayGet(HArrayGet* instruction) {
1080 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1081 locations->SetInAt(0, Location::RequiresRegister());
1082 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1083 locations->SetOut(Location::RequiresRegister());
1084 instruction->SetLocations(locations);
1085 }
1086
VisitArrayGet(HArrayGet * instruction)1087 void InstructionCodeGeneratorX86_64::VisitArrayGet(HArrayGet* instruction) {
1088 LocationSummary* locations = instruction->GetLocations();
1089 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1090 Location index = locations->InAt(1);
1091
1092 switch (instruction->GetType()) {
1093 case Primitive::kPrimBoolean: {
1094 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1095 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1096 if (index.IsConstant()) {
1097 __ movzxb(out, Address(obj,
1098 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1099 } else {
1100 __ movzxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1101 }
1102 break;
1103 }
1104
1105 case Primitive::kPrimByte: {
1106 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value();
1107 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1108 if (index.IsConstant()) {
1109 __ movsxb(out, Address(obj,
1110 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset));
1111 } else {
1112 __ movsxb(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset));
1113 }
1114 break;
1115 }
1116
1117 case Primitive::kPrimShort: {
1118 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value();
1119 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1120 if (index.IsConstant()) {
1121 __ movsxw(out, Address(obj,
1122 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1123 } else {
1124 __ movsxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1125 }
1126 break;
1127 }
1128
1129 case Primitive::kPrimChar: {
1130 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1131 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1132 if (index.IsConstant()) {
1133 __ movzxw(out, Address(obj,
1134 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset));
1135 } else {
1136 __ movzxw(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset));
1137 }
1138 break;
1139 }
1140
1141 case Primitive::kPrimInt:
1142 case Primitive::kPrimNot: {
1143 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t));
1144 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1145 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1146 if (index.IsConstant()) {
1147 __ movl(out, Address(obj,
1148 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset));
1149 } else {
1150 __ movl(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset));
1151 }
1152 break;
1153 }
1154
1155 case Primitive::kPrimLong: {
1156 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1157 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1158 if (index.IsConstant()) {
1159 __ movq(out, Address(obj,
1160 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset));
1161 } else {
1162 __ movq(out, Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset));
1163 }
1164 break;
1165 }
1166
1167 case Primitive::kPrimFloat:
1168 case Primitive::kPrimDouble:
1169 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1170
1171 case Primitive::kPrimVoid:
1172 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1173 }
1174 }
1175
VisitArraySet(HArraySet * instruction)1176 void LocationsBuilderX86_64::VisitArraySet(HArraySet* instruction) {
1177 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1178 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1179 if (value_type == Primitive::kPrimNot) {
1180 InvokeRuntimeCallingConvention calling_convention;
1181 locations->SetInAt(0, X86_64CpuLocation(calling_convention.GetRegisterAt(0)));
1182 locations->SetInAt(1, X86_64CpuLocation(calling_convention.GetRegisterAt(1)));
1183 locations->SetInAt(2, X86_64CpuLocation(calling_convention.GetRegisterAt(2)));
1184 codegen_->MarkNotLeaf();
1185 } else {
1186 locations->SetInAt(0, Location::RequiresRegister());
1187 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
1188 locations->SetInAt(2, Location::RequiresRegister());
1189 }
1190 instruction->SetLocations(locations);
1191 }
1192
VisitArraySet(HArraySet * instruction)1193 void InstructionCodeGeneratorX86_64::VisitArraySet(HArraySet* instruction) {
1194 LocationSummary* locations = instruction->GetLocations();
1195 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1196 Location index = locations->InAt(1);
1197 Primitive::Type value_type = instruction->InputAt(2)->GetType();
1198
1199 switch (value_type) {
1200 case Primitive::kPrimBoolean:
1201 case Primitive::kPrimByte: {
1202 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value();
1203 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1204 if (index.IsConstant()) {
1205 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset;
1206 __ movb(Address(obj, offset), value);
1207 } else {
1208 __ movb(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_1, data_offset), value);
1209 }
1210 break;
1211 }
1212
1213 case Primitive::kPrimShort:
1214 case Primitive::kPrimChar: {
1215 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value();
1216 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1217 if (index.IsConstant()) {
1218 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset;
1219 __ movw(Address(obj, offset), value);
1220 } else {
1221 __ movw(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_2, data_offset), value);
1222 }
1223 break;
1224 }
1225
1226 case Primitive::kPrimInt: {
1227 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value();
1228 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1229 if (index.IsConstant()) {
1230 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset;
1231 __ movl(Address(obj, offset), value);
1232 } else {
1233 __ movl(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_4, data_offset), value);
1234 }
1235 break;
1236 }
1237
1238 case Primitive::kPrimNot: {
1239 __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pAputObject), true));
1240 DCHECK(!codegen_->IsLeafMethod());
1241 codegen_->RecordPcInfo(instruction->GetDexPc());
1242 break;
1243 }
1244
1245 case Primitive::kPrimLong: {
1246 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value();
1247 CpuRegister value = locations->InAt(2).AsX86_64().AsCpuRegister();
1248 if (index.IsConstant()) {
1249 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset;
1250 __ movq(Address(obj, offset), value);
1251 } else {
1252 __ movq(Address(obj, index.AsX86_64().AsCpuRegister(), TIMES_8, data_offset), value);
1253 }
1254 break;
1255 }
1256
1257 case Primitive::kPrimFloat:
1258 case Primitive::kPrimDouble:
1259 LOG(FATAL) << "Unimplemented register type " << instruction->GetType();
1260
1261 case Primitive::kPrimVoid:
1262 LOG(FATAL) << "Unreachable type " << instruction->GetType();
1263 }
1264 }
1265
VisitArrayLength(HArrayLength * instruction)1266 void LocationsBuilderX86_64::VisitArrayLength(HArrayLength* instruction) {
1267 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1268 locations->SetInAt(0, Location::RequiresRegister());
1269 locations->SetOut(Location::RequiresRegister());
1270 instruction->SetLocations(locations);
1271 }
1272
VisitArrayLength(HArrayLength * instruction)1273 void InstructionCodeGeneratorX86_64::VisitArrayLength(HArrayLength* instruction) {
1274 LocationSummary* locations = instruction->GetLocations();
1275 uint32_t offset = mirror::Array::LengthOffset().Uint32Value();
1276 CpuRegister obj = locations->InAt(0).AsX86_64().AsCpuRegister();
1277 CpuRegister out = locations->Out().AsX86_64().AsCpuRegister();
1278 __ movl(out, Address(obj, offset));
1279 }
1280
VisitBoundsCheck(HBoundsCheck * instruction)1281 void LocationsBuilderX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1282 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
1283 locations->SetInAt(0, Location::RequiresRegister());
1284 locations->SetInAt(1, Location::RequiresRegister());
1285 // TODO: Have a normalization phase that makes this instruction never used.
1286 locations->SetOut(Location::SameAsFirstInput());
1287 instruction->SetLocations(locations);
1288 }
1289
VisitBoundsCheck(HBoundsCheck * instruction)1290 void InstructionCodeGeneratorX86_64::VisitBoundsCheck(HBoundsCheck* instruction) {
1291 LocationSummary* locations = instruction->GetLocations();
1292 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathX86_64(
1293 instruction->GetDexPc(), locations->InAt(0), locations->InAt(1));
1294 codegen_->AddSlowPath(slow_path);
1295
1296 CpuRegister index = locations->InAt(0).AsX86_64().AsCpuRegister();
1297 CpuRegister length = locations->InAt(1).AsX86_64().AsCpuRegister();
1298
1299 __ cmpl(index, length);
1300 __ j(kAboveEqual, slow_path->GetEntryLabel());
1301 }
1302
MarkGCCard(CpuRegister temp,CpuRegister card,CpuRegister object,CpuRegister value)1303 void CodeGeneratorX86_64::MarkGCCard(CpuRegister temp,
1304 CpuRegister card,
1305 CpuRegister object,
1306 CpuRegister value) {
1307 Label is_null;
1308 __ testl(value, value);
1309 __ j(kEqual, &is_null);
1310 __ gs()->movq(card, Address::Absolute(
1311 Thread::CardTableOffset<kX86_64WordSize>().Int32Value(), true));
1312 __ movq(temp, object);
1313 __ shrq(temp, Immediate(gc::accounting::CardTable::kCardShift));
1314 __ movb(Address(temp, card, TIMES_1, 0), card);
1315 __ Bind(&is_null);
1316 }
1317
VisitTemporary(HTemporary * temp)1318 void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) {
1319 temp->SetLocations(nullptr);
1320 }
1321
VisitTemporary(HTemporary * temp)1322 void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) {
1323 // Nothing to do, this is driven by the code generator.
1324 }
1325
VisitParallelMove(HParallelMove * instruction)1326 void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) {
1327 LOG(FATAL) << "Unimplemented";
1328 }
1329
VisitParallelMove(HParallelMove * instruction)1330 void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) {
1331 codegen_->GetMoveResolver()->EmitNativeCode(instruction);
1332 }
1333
GetAssembler() const1334 X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
1335 return codegen_->GetAssembler();
1336 }
1337
EmitMove(size_t index)1338 void ParallelMoveResolverX86_64::EmitMove(size_t index) {
1339 MoveOperands* move = moves_.Get(index);
1340 Location source = move->GetSource();
1341 Location destination = move->GetDestination();
1342
1343 if (source.IsRegister()) {
1344 if (destination.IsRegister()) {
1345 __ movq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1346 } else if (destination.IsStackSlot()) {
1347 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()),
1348 source.AsX86_64().AsCpuRegister());
1349 } else {
1350 DCHECK(destination.IsDoubleStackSlot());
1351 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()),
1352 source.AsX86_64().AsCpuRegister());
1353 }
1354 } else if (source.IsStackSlot()) {
1355 if (destination.IsRegister()) {
1356 __ movl(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1357 Address(CpuRegister(RSP), source.GetStackIndex()));
1358 } else {
1359 DCHECK(destination.IsStackSlot());
1360 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1361 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1362 }
1363 } else if (source.IsDoubleStackSlot()) {
1364 if (destination.IsRegister()) {
1365 __ movq(destination.AsX86_64().AsX86_64().AsCpuRegister(),
1366 Address(CpuRegister(RSP), source.GetStackIndex()));
1367 } else {
1368 DCHECK(destination.IsDoubleStackSlot());
1369 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), source.GetStackIndex()));
1370 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1371 }
1372 } else if (source.IsConstant()) {
1373 HConstant* constant = source.GetConstant();
1374 if (constant->IsIntConstant()) {
1375 Immediate imm(constant->AsIntConstant()->GetValue());
1376 if (destination.IsRegister()) {
1377 __ movl(destination.AsX86_64().AsCpuRegister(), imm);
1378 } else {
1379 __ movl(Address(CpuRegister(RSP), destination.GetStackIndex()), imm);
1380 }
1381 } else if (constant->IsLongConstant()) {
1382 int64_t value = constant->AsLongConstant()->GetValue();
1383 if (destination.IsRegister()) {
1384 __ movq(destination.AsX86_64().AsCpuRegister(), Immediate(value));
1385 } else {
1386 __ movq(CpuRegister(TMP), Immediate(value));
1387 __ movq(Address(CpuRegister(RSP), destination.GetStackIndex()), CpuRegister(TMP));
1388 }
1389 } else {
1390 LOG(FATAL) << "Unimplemented constant type";
1391 }
1392 } else {
1393 LOG(FATAL) << "Unimplemented";
1394 }
1395 }
1396
Exchange32(CpuRegister reg,int mem)1397 void ParallelMoveResolverX86_64::Exchange32(CpuRegister reg, int mem) {
1398 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1399 __ movl(Address(CpuRegister(RSP), mem), reg);
1400 __ movl(reg, CpuRegister(TMP));
1401 }
1402
Exchange32(int mem1,int mem2)1403 void ParallelMoveResolverX86_64::Exchange32(int mem1, int mem2) {
1404 ScratchRegisterScope ensure_scratch(
1405 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1406
1407 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1408 __ movl(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1409 __ movl(CpuRegister(ensure_scratch.GetRegister()),
1410 Address(CpuRegister(RSP), mem2 + stack_offset));
1411 __ movl(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1412 __ movl(Address(CpuRegister(RSP), mem1 + stack_offset),
1413 CpuRegister(ensure_scratch.GetRegister()));
1414 }
1415
Exchange64(CpuRegister reg,int mem)1416 void ParallelMoveResolverX86_64::Exchange64(CpuRegister reg, int mem) {
1417 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem));
1418 __ movq(Address(CpuRegister(RSP), mem), reg);
1419 __ movq(reg, CpuRegister(TMP));
1420 }
1421
Exchange64(int mem1,int mem2)1422 void ParallelMoveResolverX86_64::Exchange64(int mem1, int mem2) {
1423 ScratchRegisterScope ensure_scratch(
1424 this, TMP, RAX, codegen_->GetNumberOfCoreRegisters());
1425
1426 int stack_offset = ensure_scratch.IsSpilled() ? kX86_64WordSize : 0;
1427 __ movq(CpuRegister(TMP), Address(CpuRegister(RSP), mem1 + stack_offset));
1428 __ movq(CpuRegister(ensure_scratch.GetRegister()),
1429 Address(CpuRegister(RSP), mem2 + stack_offset));
1430 __ movq(Address(CpuRegister(RSP), mem2 + stack_offset), CpuRegister(TMP));
1431 __ movq(Address(CpuRegister(RSP), mem1 + stack_offset),
1432 CpuRegister(ensure_scratch.GetRegister()));
1433 }
1434
EmitSwap(size_t index)1435 void ParallelMoveResolverX86_64::EmitSwap(size_t index) {
1436 MoveOperands* move = moves_.Get(index);
1437 Location source = move->GetSource();
1438 Location destination = move->GetDestination();
1439
1440 if (source.IsRegister() && destination.IsRegister()) {
1441 __ xchgq(destination.AsX86_64().AsCpuRegister(), source.AsX86_64().AsCpuRegister());
1442 } else if (source.IsRegister() && destination.IsStackSlot()) {
1443 Exchange32(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1444 } else if (source.IsStackSlot() && destination.IsRegister()) {
1445 Exchange32(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1446 } else if (source.IsStackSlot() && destination.IsStackSlot()) {
1447 Exchange32(destination.GetStackIndex(), source.GetStackIndex());
1448 } else if (source.IsRegister() && destination.IsDoubleStackSlot()) {
1449 Exchange64(source.AsX86_64().AsCpuRegister(), destination.GetStackIndex());
1450 } else if (source.IsDoubleStackSlot() && destination.IsRegister()) {
1451 Exchange64(destination.AsX86_64().AsCpuRegister(), source.GetStackIndex());
1452 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) {
1453 Exchange64(destination.GetStackIndex(), source.GetStackIndex());
1454 } else {
1455 LOG(FATAL) << "Unimplemented";
1456 }
1457 }
1458
1459
SpillScratch(int reg)1460 void ParallelMoveResolverX86_64::SpillScratch(int reg) {
1461 __ pushq(CpuRegister(reg));
1462 }
1463
1464
RestoreScratch(int reg)1465 void ParallelMoveResolverX86_64::RestoreScratch(int reg) {
1466 __ popq(CpuRegister(reg));
1467 }
1468
1469 } // namespace x86_64
1470 } // namespace art
1471