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 32 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 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: 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: 68 explicit NullCheckSlowPathX86_64(uint32_t dex_pc) : dex_pc_(dex_pc) {} 69 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: 84 StackOverflowCheckSlowPathX86_64() {} 85 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: 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 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 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 141 void CodeGeneratorX86_64::DumpCoreRegister(std::ostream& stream, int reg) const { 142 stream << X86_64ManagedRegister::FromCpuRegister(Register(reg)); 143 } 144 145 void CodeGeneratorX86_64::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 146 stream << X86_64ManagedRegister::FromXmmRegister(FloatRegister(reg)); 147 } 148 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 155 size_t CodeGeneratorX86_64::FrameEntrySpillSize() const { 156 return kNumberOfPushedRegistersAtEntry * kX86_64WordSize; 157 } 158 159 InstructionCodeGeneratorX86_64::InstructionCodeGeneratorX86_64(HGraph* graph, 160 CodeGeneratorX86_64* codegen) 161 : HGraphVisitor(graph), 162 assembler_(codegen->GetAssembler()), 163 codegen_(codegen) {} 164 165 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 190 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 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 235 void CodeGeneratorX86_64::GenerateFrameExit() { 236 __ addq(CpuRegister(RSP), 237 Immediate(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kX86_64WordSize)); 238 } 239 240 void CodeGeneratorX86_64::Bind(Label* label) { 241 __ Bind(label); 242 } 243 244 void InstructionCodeGeneratorX86_64::LoadCurrentMethod(CpuRegister reg) { 245 __ movl(reg, Address(CpuRegister(RSP), kCurrentMethodStackOffset)); 246 } 247 248 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 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 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 362 void LocationsBuilderX86_64::VisitGoto(HGoto* got) { 363 got->SetLocations(nullptr); 364 } 365 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 375 void LocationsBuilderX86_64::VisitExit(HExit* exit) { 376 exit->SetLocations(nullptr); 377 } 378 379 void InstructionCodeGeneratorX86_64::VisitExit(HExit* exit) { 380 if (kIsDebugBuild) { 381 __ Comment("Unreachable"); 382 __ int3(); 383 } 384 } 385 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 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 429 void LocationsBuilderX86_64::VisitLocal(HLocal* local) { 430 local->SetLocations(nullptr); 431 } 432 433 void InstructionCodeGeneratorX86_64::VisitLocal(HLocal* local) { 434 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 435 } 436 437 void LocationsBuilderX86_64::VisitLoadLocal(HLoadLocal* local) { 438 local->SetLocations(nullptr); 439 } 440 441 void InstructionCodeGeneratorX86_64::VisitLoadLocal(HLoadLocal* load) { 442 // Nothing to do, this is driven by the code generator. 443 } 444 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 467 void InstructionCodeGeneratorX86_64::VisitStoreLocal(HStoreLocal* store) { 468 } 469 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 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 498 void LocationsBuilderX86_64::VisitEqual(HEqual* comp) { 499 VisitCondition(comp); 500 } 501 502 void InstructionCodeGeneratorX86_64::VisitEqual(HEqual* comp) { 503 VisitCondition(comp); 504 } 505 506 void LocationsBuilderX86_64::VisitNotEqual(HNotEqual* comp) { 507 VisitCondition(comp); 508 } 509 510 void InstructionCodeGeneratorX86_64::VisitNotEqual(HNotEqual* comp) { 511 VisitCondition(comp); 512 } 513 514 void LocationsBuilderX86_64::VisitLessThan(HLessThan* comp) { 515 VisitCondition(comp); 516 } 517 518 void InstructionCodeGeneratorX86_64::VisitLessThan(HLessThan* comp) { 519 VisitCondition(comp); 520 } 521 522 void LocationsBuilderX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 523 VisitCondition(comp); 524 } 525 526 void InstructionCodeGeneratorX86_64::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 527 VisitCondition(comp); 528 } 529 530 void LocationsBuilderX86_64::VisitGreaterThan(HGreaterThan* comp) { 531 VisitCondition(comp); 532 } 533 534 void InstructionCodeGeneratorX86_64::VisitGreaterThan(HGreaterThan* comp) { 535 VisitCondition(comp); 536 } 537 538 void LocationsBuilderX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 539 VisitCondition(comp); 540 } 541 542 void InstructionCodeGeneratorX86_64::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 543 VisitCondition(comp); 544 } 545 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 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 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 585 void InstructionCodeGeneratorX86_64::VisitIntConstant(HIntConstant* constant) { 586 } 587 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 594 void InstructionCodeGeneratorX86_64::VisitLongConstant(HLongConstant* constant) { 595 } 596 597 void LocationsBuilderX86_64::VisitReturnVoid(HReturnVoid* ret) { 598 ret->SetLocations(nullptr); 599 } 600 601 void InstructionCodeGeneratorX86_64::VisitReturnVoid(HReturnVoid* ret) { 602 codegen_->GenerateFrameExit(); 603 __ ret(); 604 } 605 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 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 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 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 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 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 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 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 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 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 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 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 911 void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) { 912 // Nothing to do, the parameter is already at its location. 913 } 914 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 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 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 938 void InstructionCodeGeneratorX86_64::VisitPhi(HPhi* instruction) { 939 LOG(FATAL) << "Unimplemented"; 940 } 941 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 1318 void LocationsBuilderX86_64::VisitTemporary(HTemporary* temp) { 1319 temp->SetLocations(nullptr); 1320 } 1321 1322 void InstructionCodeGeneratorX86_64::VisitTemporary(HTemporary* temp) { 1323 // Nothing to do, this is driven by the code generator. 1324 } 1325 1326 void LocationsBuilderX86_64::VisitParallelMove(HParallelMove* instruction) { 1327 LOG(FATAL) << "Unimplemented"; 1328 } 1329 1330 void InstructionCodeGeneratorX86_64::VisitParallelMove(HParallelMove* instruction) { 1331 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 1332 } 1333 1334 X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const { 1335 return codegen_->GetAssembler(); 1336 } 1337 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 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 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 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 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 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 1460 void ParallelMoveResolverX86_64::SpillScratch(int reg) { 1461 __ pushq(CpuRegister(reg)); 1462 } 1463 1464 1465 void ParallelMoveResolverX86_64::RestoreScratch(int reg) { 1466 __ popq(CpuRegister(reg)); 1467 } 1468 1469 } // namespace x86_64 1470 } // namespace art 1471