code_generator_arm64.cc revision 4a962e5373bc0992d6e9ba6a43bb65845e7a8783
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_arm64.h" 18 19#include "entrypoints/quick/quick_entrypoints.h" 20#include "gc/accounting/card_table.h" 21#include "mirror/array-inl.h" 22#include "mirror/art_method.h" 23#include "mirror/class.h" 24#include "thread.h" 25#include "utils/arm64/assembler_arm64.h" 26#include "utils/assembler.h" 27#include "utils/stack_checks.h" 28 29 30using namespace vixl; // NOLINT(build/namespaces) 31 32#ifdef __ 33#error "ARM64 Codegen VIXL macro-assembler macro already defined." 34#endif 35 36 37namespace art { 38 39namespace arm64 { 40 41// TODO: clean-up some of the constant definitions. 42static constexpr size_t kHeapRefSize = sizeof(mirror::HeapReference<mirror::Object>); 43static constexpr int kCurrentMethodStackOffset = 0; 44 45namespace { 46 47bool IsFPType(Primitive::Type type) { 48 return type == Primitive::kPrimFloat || type == Primitive::kPrimDouble; 49} 50 51bool IsIntegralType(Primitive::Type type) { 52 switch (type) { 53 case Primitive::kPrimByte: 54 case Primitive::kPrimChar: 55 case Primitive::kPrimShort: 56 case Primitive::kPrimInt: 57 case Primitive::kPrimLong: 58 return true; 59 default: 60 return false; 61 } 62} 63 64bool Is64BitType(Primitive::Type type) { 65 return type == Primitive::kPrimLong || type == Primitive::kPrimDouble; 66} 67 68// Convenience helpers to ease conversion to and from VIXL operands. 69static_assert((SP == 31) && (WSP == 31) && (XZR == 32) && (WZR == 32), 70 "Unexpected values for register codes."); 71 72int VIXLRegCodeFromART(int code) { 73 if (code == SP) { 74 return vixl::kSPRegInternalCode; 75 } 76 if (code == XZR) { 77 return vixl::kZeroRegCode; 78 } 79 return code; 80} 81 82int ARTRegCodeFromVIXL(int code) { 83 if (code == vixl::kSPRegInternalCode) { 84 return SP; 85 } 86 if (code == vixl::kZeroRegCode) { 87 return XZR; 88 } 89 return code; 90} 91 92Register XRegisterFrom(Location location) { 93 return Register::XRegFromCode(VIXLRegCodeFromART(location.reg())); 94} 95 96Register WRegisterFrom(Location location) { 97 return Register::WRegFromCode(VIXLRegCodeFromART(location.reg())); 98} 99 100Register RegisterFrom(Location location, Primitive::Type type) { 101 DCHECK(type != Primitive::kPrimVoid && !IsFPType(type)); 102 return type == Primitive::kPrimLong ? XRegisterFrom(location) : WRegisterFrom(location); 103} 104 105Register OutputRegister(HInstruction* instr) { 106 return RegisterFrom(instr->GetLocations()->Out(), instr->GetType()); 107} 108 109Register InputRegisterAt(HInstruction* instr, int input_index) { 110 return RegisterFrom(instr->GetLocations()->InAt(input_index), 111 instr->InputAt(input_index)->GetType()); 112} 113 114FPRegister DRegisterFrom(Location location) { 115 return FPRegister::DRegFromCode(location.reg()); 116} 117 118FPRegister SRegisterFrom(Location location) { 119 return FPRegister::SRegFromCode(location.reg()); 120} 121 122FPRegister FPRegisterFrom(Location location, Primitive::Type type) { 123 DCHECK(IsFPType(type)); 124 return type == Primitive::kPrimDouble ? DRegisterFrom(location) : SRegisterFrom(location); 125} 126 127FPRegister OutputFPRegister(HInstruction* instr) { 128 return FPRegisterFrom(instr->GetLocations()->Out(), instr->GetType()); 129} 130 131FPRegister InputFPRegisterAt(HInstruction* instr, int input_index) { 132 return FPRegisterFrom(instr->GetLocations()->InAt(input_index), 133 instr->InputAt(input_index)->GetType()); 134} 135 136CPURegister OutputCPURegister(HInstruction* instr) { 137 return IsFPType(instr->GetType()) ? static_cast<CPURegister>(OutputFPRegister(instr)) 138 : static_cast<CPURegister>(OutputRegister(instr)); 139} 140 141CPURegister InputCPURegisterAt(HInstruction* instr, int index) { 142 return IsFPType(instr->InputAt(index)->GetType()) 143 ? static_cast<CPURegister>(InputFPRegisterAt(instr, index)) 144 : static_cast<CPURegister>(InputRegisterAt(instr, index)); 145} 146 147int64_t Int64ConstantFrom(Location location) { 148 HConstant* instr = location.GetConstant(); 149 return instr->IsIntConstant() ? instr->AsIntConstant()->GetValue() 150 : instr->AsLongConstant()->GetValue(); 151} 152 153Operand OperandFrom(Location location, Primitive::Type type) { 154 if (location.IsRegister()) { 155 return Operand(RegisterFrom(location, type)); 156 } else { 157 return Operand(Int64ConstantFrom(location)); 158 } 159} 160 161Operand InputOperandAt(HInstruction* instr, int input_index) { 162 return OperandFrom(instr->GetLocations()->InAt(input_index), 163 instr->InputAt(input_index)->GetType()); 164} 165 166MemOperand StackOperandFrom(Location location) { 167 return MemOperand(sp, location.GetStackIndex()); 168} 169 170MemOperand HeapOperand(const Register& base, size_t offset) { 171 // A heap reference must be 32bit, so fit in a W register. 172 DCHECK(base.IsW()); 173 return MemOperand(base.X(), offset); 174} 175 176MemOperand HeapOperand(const Register& base, Offset offset) { 177 return HeapOperand(base, offset.SizeValue()); 178} 179 180MemOperand HeapOperandFrom(Location location, Offset offset) { 181 return HeapOperand(RegisterFrom(location, Primitive::kPrimNot), offset); 182} 183 184Location LocationFrom(const Register& reg) { 185 return Location::RegisterLocation(ARTRegCodeFromVIXL(reg.code())); 186} 187 188Location LocationFrom(const FPRegister& fpreg) { 189 return Location::FpuRegisterLocation(fpreg.code()); 190} 191 192} // namespace 193 194inline Condition ARM64Condition(IfCondition cond) { 195 switch (cond) { 196 case kCondEQ: return eq; 197 case kCondNE: return ne; 198 case kCondLT: return lt; 199 case kCondLE: return le; 200 case kCondGT: return gt; 201 case kCondGE: return ge; 202 default: 203 LOG(FATAL) << "Unknown if condition"; 204 } 205 return nv; // Unreachable. 206} 207 208Location ARM64ReturnLocation(Primitive::Type return_type) { 209 DCHECK_NE(return_type, Primitive::kPrimVoid); 210 // Note that in practice, `LocationFrom(x0)` and `LocationFrom(w0)` create the 211 // same Location object, and so do `LocationFrom(d0)` and `LocationFrom(s0)`, 212 // but we use the exact registers for clarity. 213 if (return_type == Primitive::kPrimFloat) { 214 return LocationFrom(s0); 215 } else if (return_type == Primitive::kPrimDouble) { 216 return LocationFrom(d0); 217 } else if (return_type == Primitive::kPrimLong) { 218 return LocationFrom(x0); 219 } else { 220 return LocationFrom(w0); 221 } 222} 223 224static const Register kRuntimeParameterCoreRegisters[] = { x0, x1, x2, x3, x4, x5, x6, x7 }; 225static constexpr size_t kRuntimeParameterCoreRegistersLength = 226 arraysize(kRuntimeParameterCoreRegisters); 227static const FPRegister kRuntimeParameterFpuRegisters[] = { }; 228static constexpr size_t kRuntimeParameterFpuRegistersLength = 0; 229 230class InvokeRuntimeCallingConvention : public CallingConvention<Register, FPRegister> { 231 public: 232 static constexpr size_t kParameterCoreRegistersLength = arraysize(kParameterCoreRegisters); 233 234 InvokeRuntimeCallingConvention() 235 : CallingConvention(kRuntimeParameterCoreRegisters, 236 kRuntimeParameterCoreRegistersLength, 237 kRuntimeParameterFpuRegisters, 238 kRuntimeParameterFpuRegistersLength) {} 239 240 Location GetReturnLocation(Primitive::Type return_type); 241 242 private: 243 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 244}; 245 246Location InvokeRuntimeCallingConvention::GetReturnLocation(Primitive::Type return_type) { 247 return ARM64ReturnLocation(return_type); 248} 249 250#define __ down_cast<CodeGeneratorARM64*>(codegen)->GetVIXLAssembler()-> 251#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArm64WordSize, x).Int32Value() 252 253class SlowPathCodeARM64 : public SlowPathCode { 254 public: 255 SlowPathCodeARM64() : entry_label_(), exit_label_() {} 256 257 vixl::Label* GetEntryLabel() { return &entry_label_; } 258 vixl::Label* GetExitLabel() { return &exit_label_; } 259 260 private: 261 vixl::Label entry_label_; 262 vixl::Label exit_label_; 263 264 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM64); 265}; 266 267class BoundsCheckSlowPathARM64 : public SlowPathCodeARM64 { 268 public: 269 BoundsCheckSlowPathARM64() {} 270 271 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 272 __ Bind(GetEntryLabel()); 273 __ Brk(__LINE__); // TODO: Unimplemented BoundsCheckSlowPathARM64. 274 } 275 276 private: 277 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM64); 278}; 279 280class DivZeroCheckSlowPathARM64 : public SlowPathCodeARM64 { 281 public: 282 explicit DivZeroCheckSlowPathARM64(HDivZeroCheck* instruction) : instruction_(instruction) {} 283 284 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 285 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); 286 __ Bind(GetEntryLabel()); 287 arm64_codegen->InvokeRuntime( 288 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc()); 289 } 290 291 private: 292 HDivZeroCheck* const instruction_; 293 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM64); 294}; 295 296class LoadClassSlowPathARM64 : public SlowPathCodeARM64 { 297 public: 298 LoadClassSlowPathARM64(HLoadClass* cls, 299 HInstruction* at, 300 uint32_t dex_pc, 301 bool do_clinit) 302 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { 303 DCHECK(at->IsLoadClass() || at->IsClinitCheck()); 304 } 305 306 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 307 LocationSummary* locations = at_->GetLocations(); 308 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); 309 310 __ Bind(GetEntryLabel()); 311 codegen->SaveLiveRegisters(locations); 312 313 InvokeRuntimeCallingConvention calling_convention; 314 __ Mov(calling_convention.GetRegisterAt(0).W(), cls_->GetTypeIndex()); 315 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1).W()); 316 int32_t entry_point_offset = do_clinit_ ? QUICK_ENTRY_POINT(pInitializeStaticStorage) 317 : QUICK_ENTRY_POINT(pInitializeType); 318 arm64_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_); 319 320 // Move the class to the desired location. 321 Location out = locations->Out(); 322 if (out.IsValid()) { 323 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg())); 324 Primitive::Type type = at_->GetType(); 325 arm64_codegen->MoveHelper(out, calling_convention.GetReturnLocation(type), type); 326 } 327 328 codegen->RestoreLiveRegisters(locations); 329 __ B(GetExitLabel()); 330 } 331 332 private: 333 // The class this slow path will load. 334 HLoadClass* const cls_; 335 336 // The instruction where this slow path is happening. 337 // (Might be the load class or an initialization check). 338 HInstruction* const at_; 339 340 // The dex PC of `at_`. 341 const uint32_t dex_pc_; 342 343 // Whether to initialize the class. 344 const bool do_clinit_; 345 346 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64); 347}; 348 349class LoadStringSlowPathARM64 : public SlowPathCodeARM64 { 350 public: 351 explicit LoadStringSlowPathARM64(HLoadString* instruction) : instruction_(instruction) {} 352 353 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 354 LocationSummary* locations = instruction_->GetLocations(); 355 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 356 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); 357 358 __ Bind(GetEntryLabel()); 359 codegen->SaveLiveRegisters(locations); 360 361 InvokeRuntimeCallingConvention calling_convention; 362 arm64_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0).W()); 363 __ Mov(calling_convention.GetRegisterAt(1).W(), instruction_->GetStringIndex()); 364 arm64_codegen->InvokeRuntime( 365 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc()); 366 Primitive::Type type = instruction_->GetType(); 367 arm64_codegen->MoveHelper(locations->Out(), calling_convention.GetReturnLocation(type), type); 368 369 codegen->RestoreLiveRegisters(locations); 370 __ B(GetExitLabel()); 371 } 372 373 private: 374 HLoadString* const instruction_; 375 376 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64); 377}; 378 379class NullCheckSlowPathARM64 : public SlowPathCodeARM64 { 380 public: 381 explicit NullCheckSlowPathARM64(HNullCheck* instr) : instruction_(instr) {} 382 383 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 384 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); 385 __ Bind(GetEntryLabel()); 386 arm64_codegen->InvokeRuntime( 387 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc()); 388 } 389 390 private: 391 HNullCheck* const instruction_; 392 393 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM64); 394}; 395 396class SuspendCheckSlowPathARM64 : public SlowPathCodeARM64 { 397 public: 398 explicit SuspendCheckSlowPathARM64(HSuspendCheck* instruction, 399 HBasicBlock* successor) 400 : instruction_(instruction), successor_(successor) {} 401 402 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 403 CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); 404 __ Bind(GetEntryLabel()); 405 codegen->SaveLiveRegisters(instruction_->GetLocations()); 406 arm64_codegen->InvokeRuntime( 407 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc()); 408 codegen->RestoreLiveRegisters(instruction_->GetLocations()); 409 if (successor_ == nullptr) { 410 __ B(GetReturnLabel()); 411 } else { 412 __ B(arm64_codegen->GetLabelOf(successor_)); 413 } 414 } 415 416 vixl::Label* GetReturnLabel() { 417 DCHECK(successor_ == nullptr); 418 return &return_label_; 419 } 420 421 422 private: 423 HSuspendCheck* const instruction_; 424 // If not null, the block to branch to after the suspend check. 425 HBasicBlock* const successor_; 426 427 // If `successor_` is null, the label to branch to after the suspend check. 428 vixl::Label return_label_; 429 430 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM64); 431}; 432 433class TypeCheckSlowPathARM64 : public SlowPathCodeARM64 { 434 public: 435 TypeCheckSlowPathARM64() {} 436 437 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 438 __ Bind(GetEntryLabel()); 439 __ Brk(__LINE__); // TODO: Unimplemented TypeCheckSlowPathARM64. 440 __ b(GetExitLabel()); 441 } 442 443 private: 444 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM64); 445}; 446 447#undef __ 448 449Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { 450 Location next_location; 451 if (type == Primitive::kPrimVoid) { 452 LOG(FATAL) << "Unreachable type " << type; 453 } 454 455 if (IsFPType(type) && (fp_index_ < calling_convention.GetNumberOfFpuRegisters())) { 456 next_location = LocationFrom(calling_convention.GetFpuRegisterAt(fp_index_++)); 457 } else if (!IsFPType(type) && (gp_index_ < calling_convention.GetNumberOfRegisters())) { 458 next_location = LocationFrom(calling_convention.GetRegisterAt(gp_index_++)); 459 } else { 460 size_t stack_offset = calling_convention.GetStackOffsetOf(stack_index_); 461 next_location = Is64BitType(type) ? Location::DoubleStackSlot(stack_offset) 462 : Location::StackSlot(stack_offset); 463 } 464 465 // Space on the stack is reserved for all arguments. 466 stack_index_ += Is64BitType(type) ? 2 : 1; 467 return next_location; 468} 469 470CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph) 471 : CodeGenerator(graph, 472 kNumberOfAllocatableRegisters, 473 kNumberOfAllocatableFPRegisters, 474 kNumberOfAllocatableRegisterPairs), 475 block_labels_(nullptr), 476 location_builder_(graph, this), 477 instruction_visitor_(graph, this) {} 478 479#undef __ 480#define __ GetVIXLAssembler()-> 481 482void CodeGeneratorARM64::GenerateFrameEntry() { 483 // TODO: Add proper support for the stack overflow check. 484 UseScratchRegisterScope temps(GetVIXLAssembler()); 485 Register temp = temps.AcquireX(); 486 __ Add(temp, sp, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm64))); 487 __ Ldr(temp, MemOperand(temp, 0)); 488 RecordPcInfo(nullptr, 0); 489 490 CPURegList preserved_regs = GetFramePreservedRegisters(); 491 int frame_size = GetFrameSize(); 492 core_spill_mask_ |= preserved_regs.list(); 493 494 __ Str(w0, MemOperand(sp, -frame_size, PreIndex)); 495 __ PokeCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes()); 496 497 // Stack layout: 498 // sp[frame_size - 8] : lr. 499 // ... : other preserved registers. 500 // sp[frame_size - regs_size]: first preserved register. 501 // ... : reserved frame space. 502 // sp[0] : current method. 503} 504 505void CodeGeneratorARM64::GenerateFrameExit() { 506 int frame_size = GetFrameSize(); 507 CPURegList preserved_regs = GetFramePreservedRegisters(); 508 __ PeekCPURegList(preserved_regs, frame_size - preserved_regs.TotalSizeInBytes()); 509 __ Drop(frame_size); 510} 511 512void CodeGeneratorARM64::Bind(HBasicBlock* block) { 513 __ Bind(GetLabelOf(block)); 514} 515 516void CodeGeneratorARM64::Move(HInstruction* instruction, 517 Location location, 518 HInstruction* move_for) { 519 LocationSummary* locations = instruction->GetLocations(); 520 if (locations != nullptr && locations->Out().Equals(location)) { 521 return; 522 } 523 524 Primitive::Type type = instruction->GetType(); 525 DCHECK_NE(type, Primitive::kPrimVoid); 526 527 if (instruction->IsIntConstant() || instruction->IsLongConstant()) { 528 int64_t value = instruction->IsIntConstant() ? instruction->AsIntConstant()->GetValue() 529 : instruction->AsLongConstant()->GetValue(); 530 if (location.IsRegister()) { 531 Register dst = RegisterFrom(location, type); 532 DCHECK((instruction->IsIntConstant() && dst.Is32Bits()) || 533 (instruction->IsLongConstant() && dst.Is64Bits())); 534 __ Mov(dst, value); 535 } else { 536 DCHECK(location.IsStackSlot() || location.IsDoubleStackSlot()); 537 UseScratchRegisterScope temps(GetVIXLAssembler()); 538 Register temp = instruction->IsIntConstant() ? temps.AcquireW() : temps.AcquireX(); 539 __ Mov(temp, value); 540 __ Str(temp, StackOperandFrom(location)); 541 } 542 } else if (instruction->IsTemporary()) { 543 Location temp_location = GetTemporaryLocation(instruction->AsTemporary()); 544 MoveHelper(location, temp_location, type); 545 } else if (instruction->IsLoadLocal()) { 546 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 547 if (Is64BitType(type)) { 548 MoveHelper(location, Location::DoubleStackSlot(stack_slot), type); 549 } else { 550 MoveHelper(location, Location::StackSlot(stack_slot), type); 551 } 552 553 } else { 554 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary()); 555 MoveHelper(location, locations->Out(), type); 556 } 557} 558 559size_t CodeGeneratorARM64::FrameEntrySpillSize() const { 560 return GetFramePreservedRegistersSize(); 561} 562 563Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const { 564 Primitive::Type type = load->GetType(); 565 566 switch (type) { 567 case Primitive::kPrimNot: 568 case Primitive::kPrimInt: 569 case Primitive::kPrimFloat: 570 return Location::StackSlot(GetStackSlot(load->GetLocal())); 571 572 case Primitive::kPrimLong: 573 case Primitive::kPrimDouble: 574 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 575 576 case Primitive::kPrimBoolean: 577 case Primitive::kPrimByte: 578 case Primitive::kPrimChar: 579 case Primitive::kPrimShort: 580 case Primitive::kPrimVoid: 581 LOG(FATAL) << "Unexpected type " << type; 582 } 583 584 LOG(FATAL) << "Unreachable"; 585 return Location::NoLocation(); 586} 587 588void CodeGeneratorARM64::MarkGCCard(Register object, Register value) { 589 UseScratchRegisterScope temps(GetVIXLAssembler()); 590 Register card = temps.AcquireX(); 591 Register temp = temps.AcquireX(); 592 vixl::Label done; 593 __ Cbz(value, &done); 594 __ Ldr(card, MemOperand(tr, Thread::CardTableOffset<kArm64WordSize>().Int32Value())); 595 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift); 596 __ Strb(card, MemOperand(card, temp)); 597 __ Bind(&done); 598} 599 600void CodeGeneratorARM64::SetupBlockedRegisters() const { 601 // Block reserved registers: 602 // ip0 (VIXL temporary) 603 // ip1 (VIXL temporary) 604 // xSuspend (Suspend counter) 605 // lr 606 // sp is not part of the allocatable registers, so we don't need to block it. 607 // TODO: Avoid blocking callee-saved registers, and instead preserve them 608 // where necessary. 609 CPURegList reserved_core_registers = vixl_reserved_core_registers; 610 reserved_core_registers.Combine(runtime_reserved_core_registers); 611 reserved_core_registers.Combine(quick_callee_saved_registers); 612 while (!reserved_core_registers.IsEmpty()) { 613 blocked_core_registers_[reserved_core_registers.PopLowestIndex().code()] = true; 614 } 615 CPURegList reserved_fp_registers = vixl_reserved_fp_registers; 616 reserved_fp_registers.Combine(CPURegList::GetCalleeSavedFP()); 617 while (!reserved_core_registers.IsEmpty()) { 618 blocked_fpu_registers_[reserved_fp_registers.PopLowestIndex().code()] = true; 619 } 620} 621 622Location CodeGeneratorARM64::AllocateFreeRegister(Primitive::Type type) const { 623 if (type == Primitive::kPrimVoid) { 624 LOG(FATAL) << "Unreachable type " << type; 625 } 626 627 if (IsFPType(type)) { 628 ssize_t reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfAllocatableFPRegisters); 629 DCHECK_NE(reg, -1); 630 return Location::FpuRegisterLocation(reg); 631 } else { 632 ssize_t reg = FindFreeEntry(blocked_core_registers_, kNumberOfAllocatableRegisters); 633 DCHECK_NE(reg, -1); 634 return Location::RegisterLocation(reg); 635 } 636} 637 638void CodeGeneratorARM64::DumpCoreRegister(std::ostream& stream, int reg) const { 639 stream << Arm64ManagedRegister::FromXRegister(XRegister(reg)); 640} 641 642void CodeGeneratorARM64::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 643 stream << Arm64ManagedRegister::FromDRegister(DRegister(reg)); 644} 645 646void CodeGeneratorARM64::MoveConstant(CPURegister destination, HConstant* constant) { 647 if (constant->IsIntConstant() || constant->IsLongConstant()) { 648 __ Mov(Register(destination), 649 constant->IsIntConstant() ? constant->AsIntConstant()->GetValue() 650 : constant->AsLongConstant()->GetValue()); 651 } else if (constant->IsFloatConstant()) { 652 __ Fmov(FPRegister(destination), constant->AsFloatConstant()->GetValue()); 653 } else { 654 DCHECK(constant->IsDoubleConstant()); 655 __ Fmov(FPRegister(destination), constant->AsDoubleConstant()->GetValue()); 656 } 657} 658 659void CodeGeneratorARM64::MoveHelper(Location destination, 660 Location source, 661 Primitive::Type type) { 662 if (source.Equals(destination)) { 663 return; 664 } 665 if (destination.IsRegister()) { 666 Register dst = RegisterFrom(destination, type); 667 if (source.IsStackSlot() || source.IsDoubleStackSlot()) { 668 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot()); 669 __ Ldr(dst, StackOperandFrom(source)); 670 } else { 671 __ Mov(dst, OperandFrom(source, type)); 672 } 673 } else if (destination.IsFpuRegister()) { 674 FPRegister dst = FPRegisterFrom(destination, type); 675 if (source.IsStackSlot() || source.IsDoubleStackSlot()) { 676 DCHECK(dst.Is64Bits() == source.IsDoubleStackSlot()); 677 __ Ldr(dst, StackOperandFrom(source)); 678 } else if (source.IsFpuRegister()) { 679 __ Fmov(dst, FPRegisterFrom(source, type)); 680 } else { 681 MoveConstant(dst, source.GetConstant()); 682 } 683 } else { 684 DCHECK(destination.IsStackSlot() || destination.IsDoubleStackSlot()); 685 if (source.IsRegister()) { 686 __ Str(RegisterFrom(source, type), StackOperandFrom(destination)); 687 } else if (source.IsFpuRegister()) { 688 __ Str(FPRegisterFrom(source, type), StackOperandFrom(destination)); 689 } else if (source.IsConstant()) { 690 UseScratchRegisterScope temps(GetVIXLAssembler()); 691 HConstant* cst = source.GetConstant(); 692 CPURegister temp; 693 if (cst->IsIntConstant() || cst->IsLongConstant()) { 694 temp = cst->IsIntConstant() ? temps.AcquireW() : temps.AcquireX(); 695 } else { 696 DCHECK(cst->IsFloatConstant() || cst->IsDoubleConstant()); 697 temp = cst->IsFloatConstant() ? temps.AcquireS() : temps.AcquireD(); 698 } 699 MoveConstant(temp, cst); 700 __ Str(temp, StackOperandFrom(destination)); 701 } else { 702 DCHECK(source.IsStackSlot() || source.IsDoubleStackSlot()); 703 UseScratchRegisterScope temps(GetVIXLAssembler()); 704 Register temp = destination.IsDoubleStackSlot() ? temps.AcquireX() : temps.AcquireW(); 705 __ Ldr(temp, StackOperandFrom(source)); 706 __ Str(temp, StackOperandFrom(destination)); 707 } 708 } 709} 710 711void CodeGeneratorARM64::Load(Primitive::Type type, 712 vixl::CPURegister dst, 713 const vixl::MemOperand& src) { 714 switch (type) { 715 case Primitive::kPrimBoolean: 716 __ Ldrb(Register(dst), src); 717 break; 718 case Primitive::kPrimByte: 719 __ Ldrsb(Register(dst), src); 720 break; 721 case Primitive::kPrimShort: 722 __ Ldrsh(Register(dst), src); 723 break; 724 case Primitive::kPrimChar: 725 __ Ldrh(Register(dst), src); 726 break; 727 case Primitive::kPrimInt: 728 case Primitive::kPrimNot: 729 case Primitive::kPrimLong: 730 case Primitive::kPrimFloat: 731 case Primitive::kPrimDouble: 732 DCHECK(dst.Is64Bits() == Is64BitType(type)); 733 __ Ldr(dst, src); 734 break; 735 case Primitive::kPrimVoid: 736 LOG(FATAL) << "Unreachable type " << type; 737 } 738} 739 740void CodeGeneratorARM64::Store(Primitive::Type type, 741 vixl::CPURegister rt, 742 const vixl::MemOperand& dst) { 743 switch (type) { 744 case Primitive::kPrimBoolean: 745 case Primitive::kPrimByte: 746 __ Strb(Register(rt), dst); 747 break; 748 case Primitive::kPrimChar: 749 case Primitive::kPrimShort: 750 __ Strh(Register(rt), dst); 751 break; 752 case Primitive::kPrimInt: 753 case Primitive::kPrimNot: 754 case Primitive::kPrimLong: 755 case Primitive::kPrimFloat: 756 case Primitive::kPrimDouble: 757 DCHECK(rt.Is64Bits() == Is64BitType(type)); 758 __ Str(rt, dst); 759 break; 760 case Primitive::kPrimVoid: 761 LOG(FATAL) << "Unreachable type " << type; 762 } 763} 764 765void CodeGeneratorARM64::LoadCurrentMethod(vixl::Register current_method) { 766 DCHECK(current_method.IsW()); 767 __ Ldr(current_method, MemOperand(sp, kCurrentMethodStackOffset)); 768} 769 770void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset, 771 HInstruction* instruction, 772 uint32_t dex_pc) { 773 __ Ldr(lr, MemOperand(tr, entry_point_offset)); 774 __ Blr(lr); 775 RecordPcInfo(instruction, dex_pc); 776 DCHECK(instruction->IsSuspendCheck() 777 || instruction->IsBoundsCheck() 778 || instruction->IsNullCheck() 779 || instruction->IsDivZeroCheck() 780 || !IsLeafMethod()); 781} 782 783void InstructionCodeGeneratorARM64::GenerateClassInitializationCheck(SlowPathCodeARM64* slow_path, 784 vixl::Register class_reg) { 785 UseScratchRegisterScope temps(GetVIXLAssembler()); 786 Register temp = temps.AcquireW(); 787 __ Ldr(temp, HeapOperand(class_reg, mirror::Class::StatusOffset())); 788 __ Cmp(temp, mirror::Class::kStatusInitialized); 789 __ B(lt, slow_path->GetEntryLabel()); 790 // Even if the initialized flag is set, we may be in a situation where caches are not synced 791 // properly. Therefore, we do a memory fence. 792 __ Dmb(InnerShareable, BarrierAll); 793 __ Bind(slow_path->GetExitLabel()); 794} 795 796InstructionCodeGeneratorARM64::InstructionCodeGeneratorARM64(HGraph* graph, 797 CodeGeneratorARM64* codegen) 798 : HGraphVisitor(graph), 799 assembler_(codegen->GetAssembler()), 800 codegen_(codegen) {} 801 802#define FOR_EACH_UNIMPLEMENTED_INSTRUCTION(M) \ 803 M(ParallelMove) \ 804 M(Rem) 805 806#define UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name) name##UnimplementedInstructionBreakCode 807 808enum UnimplementedInstructionBreakCode { 809 // Using a base helps identify when we hit such breakpoints. 810 UnimplementedInstructionBreakCodeBaseCode = 0x900, 811#define ENUM_UNIMPLEMENTED_INSTRUCTION(name) UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name), 812 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(ENUM_UNIMPLEMENTED_INSTRUCTION) 813#undef ENUM_UNIMPLEMENTED_INSTRUCTION 814}; 815 816#define DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS(name) \ 817 void InstructionCodeGeneratorARM64::Visit##name(H##name* instr) { \ 818 UNUSED(instr); \ 819 __ Brk(UNIMPLEMENTED_INSTRUCTION_BREAK_CODE(name)); \ 820 } \ 821 void LocationsBuilderARM64::Visit##name(H##name* instr) { \ 822 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); \ 823 locations->SetOut(Location::Any()); \ 824 } 825 FOR_EACH_UNIMPLEMENTED_INSTRUCTION(DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS) 826#undef DEFINE_UNIMPLEMENTED_INSTRUCTION_VISITORS 827 828#undef UNIMPLEMENTED_INSTRUCTION_BREAK_CODE 829#undef FOR_EACH_UNIMPLEMENTED_INSTRUCTION 830 831void LocationsBuilderARM64::HandleBinaryOp(HBinaryOperation* instr) { 832 DCHECK_EQ(instr->InputCount(), 2U); 833 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instr); 834 Primitive::Type type = instr->GetResultType(); 835 switch (type) { 836 case Primitive::kPrimInt: 837 case Primitive::kPrimLong: 838 locations->SetInAt(0, Location::RequiresRegister()); 839 locations->SetInAt(1, Location::RegisterOrConstant(instr->InputAt(1))); 840 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 841 break; 842 843 case Primitive::kPrimFloat: 844 case Primitive::kPrimDouble: 845 locations->SetInAt(0, Location::RequiresFpuRegister()); 846 locations->SetInAt(1, Location::RequiresFpuRegister()); 847 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 848 break; 849 850 default: 851 LOG(FATAL) << "Unexpected " << instr->DebugName() << " type " << type; 852 } 853} 854 855void InstructionCodeGeneratorARM64::HandleBinaryOp(HBinaryOperation* instr) { 856 Primitive::Type type = instr->GetType(); 857 858 switch (type) { 859 case Primitive::kPrimInt: 860 case Primitive::kPrimLong: { 861 Register dst = OutputRegister(instr); 862 Register lhs = InputRegisterAt(instr, 0); 863 Operand rhs = InputOperandAt(instr, 1); 864 if (instr->IsAdd()) { 865 __ Add(dst, lhs, rhs); 866 } else if (instr->IsAnd()) { 867 __ And(dst, lhs, rhs); 868 } else if (instr->IsOr()) { 869 __ Orr(dst, lhs, rhs); 870 } else if (instr->IsSub()) { 871 __ Sub(dst, lhs, rhs); 872 } else { 873 DCHECK(instr->IsXor()); 874 __ Eor(dst, lhs, rhs); 875 } 876 break; 877 } 878 case Primitive::kPrimFloat: 879 case Primitive::kPrimDouble: { 880 FPRegister dst = OutputFPRegister(instr); 881 FPRegister lhs = InputFPRegisterAt(instr, 0); 882 FPRegister rhs = InputFPRegisterAt(instr, 1); 883 if (instr->IsAdd()) { 884 __ Fadd(dst, lhs, rhs); 885 } else if (instr->IsSub()) { 886 __ Fsub(dst, lhs, rhs); 887 } else { 888 LOG(FATAL) << "Unexpected floating-point binary operation"; 889 } 890 break; 891 } 892 default: 893 LOG(FATAL) << "Unexpected binary operation type " << type; 894 } 895} 896 897void LocationsBuilderARM64::VisitAdd(HAdd* instruction) { 898 HandleBinaryOp(instruction); 899} 900 901void InstructionCodeGeneratorARM64::VisitAdd(HAdd* instruction) { 902 HandleBinaryOp(instruction); 903} 904 905void LocationsBuilderARM64::VisitAnd(HAnd* instruction) { 906 HandleBinaryOp(instruction); 907} 908 909void InstructionCodeGeneratorARM64::VisitAnd(HAnd* instruction) { 910 HandleBinaryOp(instruction); 911} 912 913void LocationsBuilderARM64::VisitArrayGet(HArrayGet* instruction) { 914 LocationSummary* locations = 915 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 916 locations->SetInAt(0, Location::RequiresRegister()); 917 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 918 locations->SetOut(Location::RequiresRegister()); 919} 920 921void InstructionCodeGeneratorARM64::VisitArrayGet(HArrayGet* instruction) { 922 LocationSummary* locations = instruction->GetLocations(); 923 Primitive::Type type = instruction->GetType(); 924 Register obj = InputRegisterAt(instruction, 0); 925 Location index = locations->InAt(1); 926 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(type)).Uint32Value(); 927 MemOperand source(obj); 928 UseScratchRegisterScope temps(GetVIXLAssembler()); 929 930 if (index.IsConstant()) { 931 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(type); 932 source = MemOperand(obj, offset); 933 } else { 934 Register temp = temps.AcquireSameSizeAs(obj); 935 Register index_reg = RegisterFrom(index, Primitive::kPrimInt); 936 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(type))); 937 source = MemOperand(temp, offset); 938 } 939 940 codegen_->Load(type, OutputCPURegister(instruction), source); 941} 942 943void LocationsBuilderARM64::VisitArrayLength(HArrayLength* instruction) { 944 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 945 locations->SetInAt(0, Location::RequiresRegister()); 946 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 947} 948 949void InstructionCodeGeneratorARM64::VisitArrayLength(HArrayLength* instruction) { 950 __ Ldr(OutputRegister(instruction), 951 HeapOperand(InputRegisterAt(instruction, 0), mirror::Array::LengthOffset())); 952} 953 954void LocationsBuilderARM64::VisitArraySet(HArraySet* instruction) { 955 Primitive::Type value_type = instruction->GetComponentType(); 956 bool is_object = value_type == Primitive::kPrimNot; 957 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 958 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall); 959 if (is_object) { 960 InvokeRuntimeCallingConvention calling_convention; 961 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); 962 locations->SetInAt(1, LocationFrom(calling_convention.GetRegisterAt(1))); 963 locations->SetInAt(2, LocationFrom(calling_convention.GetRegisterAt(2))); 964 } else { 965 locations->SetInAt(0, Location::RequiresRegister()); 966 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 967 locations->SetInAt(2, Location::RequiresRegister()); 968 } 969} 970 971void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) { 972 Primitive::Type value_type = instruction->GetComponentType(); 973 if (value_type == Primitive::kPrimNot) { 974 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc()); 975 976 } else { 977 LocationSummary* locations = instruction->GetLocations(); 978 Register obj = InputRegisterAt(instruction, 0); 979 CPURegister value = InputCPURegisterAt(instruction, 2); 980 Location index = locations->InAt(1); 981 size_t offset = mirror::Array::DataOffset(Primitive::ComponentSize(value_type)).Uint32Value(); 982 MemOperand destination(obj); 983 UseScratchRegisterScope temps(GetVIXLAssembler()); 984 985 if (index.IsConstant()) { 986 offset += Int64ConstantFrom(index) << Primitive::ComponentSizeShift(value_type); 987 destination = MemOperand(obj, offset); 988 } else { 989 Register temp = temps.AcquireSameSizeAs(obj); 990 Register index_reg = InputRegisterAt(instruction, 1); 991 __ Add(temp, obj, Operand(index_reg, LSL, Primitive::ComponentSizeShift(value_type))); 992 destination = MemOperand(temp, offset); 993 } 994 995 codegen_->Store(value_type, value, destination); 996 } 997} 998 999void LocationsBuilderARM64::VisitBoundsCheck(HBoundsCheck* instruction) { 1000 LocationSummary* locations = 1001 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1002 locations->SetInAt(0, Location::RequiresRegister()); 1003 locations->SetInAt(1, Location::RequiresRegister()); 1004 if (instruction->HasUses()) { 1005 locations->SetOut(Location::SameAsFirstInput()); 1006 } 1007} 1008 1009void InstructionCodeGeneratorARM64::VisitBoundsCheck(HBoundsCheck* instruction) { 1010 BoundsCheckSlowPathARM64* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM64(); 1011 codegen_->AddSlowPath(slow_path); 1012 1013 __ Cmp(InputRegisterAt(instruction, 0), InputOperandAt(instruction, 1)); 1014 __ B(slow_path->GetEntryLabel(), hs); 1015} 1016 1017void LocationsBuilderARM64::VisitCheckCast(HCheckCast* instruction) { 1018 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 1019 instruction, LocationSummary::kCallOnSlowPath); 1020 locations->SetInAt(0, Location::RequiresRegister()); 1021 locations->SetInAt(1, Location::RequiresRegister()); 1022} 1023 1024void InstructionCodeGeneratorARM64::VisitCheckCast(HCheckCast* instruction) { 1025 UseScratchRegisterScope temps(GetVIXLAssembler()); 1026 Register obj = InputRegisterAt(instruction, 0);; 1027 Register cls = InputRegisterAt(instruction, 1);; 1028 Register temp = temps.AcquireW(); 1029 1030 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(); 1031 codegen_->AddSlowPath(slow_path); 1032 1033 // TODO: avoid this check if we know obj is not null. 1034 __ Cbz(obj, slow_path->GetExitLabel()); 1035 // Compare the class of `obj` with `cls`. 1036 __ Ldr(temp, HeapOperand(obj, mirror::Object::ClassOffset())); 1037 __ Cmp(temp, cls); 1038 __ B(ne, slow_path->GetEntryLabel()); 1039 __ Bind(slow_path->GetExitLabel()); 1040} 1041 1042void LocationsBuilderARM64::VisitClinitCheck(HClinitCheck* check) { 1043 LocationSummary* locations = 1044 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath); 1045 locations->SetInAt(0, Location::RequiresRegister()); 1046 if (check->HasUses()) { 1047 locations->SetOut(Location::SameAsFirstInput()); 1048 } 1049} 1050 1051void InstructionCodeGeneratorARM64::VisitClinitCheck(HClinitCheck* check) { 1052 // We assume the class is not null. 1053 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64( 1054 check->GetLoadClass(), check, check->GetDexPc(), true); 1055 codegen_->AddSlowPath(slow_path); 1056 GenerateClassInitializationCheck(slow_path, InputRegisterAt(check, 0)); 1057} 1058 1059void LocationsBuilderARM64::VisitCompare(HCompare* instruction) { 1060 LocationSummary* locations = 1061 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1062 locations->SetInAt(0, Location::RequiresRegister()); 1063 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 1064 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1065} 1066 1067void InstructionCodeGeneratorARM64::VisitCompare(HCompare* instruction) { 1068 Primitive::Type in_type = instruction->InputAt(0)->GetType(); 1069 1070 DCHECK_EQ(in_type, Primitive::kPrimLong); 1071 switch (in_type) { 1072 case Primitive::kPrimLong: { 1073 vixl::Label done; 1074 Register result = OutputRegister(instruction); 1075 Register left = InputRegisterAt(instruction, 0); 1076 Operand right = InputOperandAt(instruction, 1); 1077 __ Subs(result.X(), left, right); 1078 __ B(eq, &done); 1079 __ Mov(result, 1); 1080 __ Cneg(result, result, le); 1081 __ Bind(&done); 1082 break; 1083 } 1084 default: 1085 LOG(FATAL) << "Unimplemented compare type " << in_type; 1086 } 1087} 1088 1089void LocationsBuilderARM64::VisitCondition(HCondition* instruction) { 1090 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 1091 locations->SetInAt(0, Location::RequiresRegister()); 1092 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 1093 if (instruction->NeedsMaterialization()) { 1094 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1095 } 1096} 1097 1098void InstructionCodeGeneratorARM64::VisitCondition(HCondition* instruction) { 1099 if (!instruction->NeedsMaterialization()) { 1100 return; 1101 } 1102 1103 LocationSummary* locations = instruction->GetLocations(); 1104 Register lhs = InputRegisterAt(instruction, 0); 1105 Operand rhs = InputOperandAt(instruction, 1); 1106 Register res = RegisterFrom(locations->Out(), instruction->GetType()); 1107 Condition cond = ARM64Condition(instruction->GetCondition()); 1108 1109 __ Cmp(lhs, rhs); 1110 __ Csel(res, vixl::Assembler::AppropriateZeroRegFor(res), Operand(1), InvertCondition(cond)); 1111} 1112 1113#define FOR_EACH_CONDITION_INSTRUCTION(M) \ 1114 M(Equal) \ 1115 M(NotEqual) \ 1116 M(LessThan) \ 1117 M(LessThanOrEqual) \ 1118 M(GreaterThan) \ 1119 M(GreaterThanOrEqual) 1120#define DEFINE_CONDITION_VISITORS(Name) \ 1121void LocationsBuilderARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } \ 1122void InstructionCodeGeneratorARM64::Visit##Name(H##Name* comp) { VisitCondition(comp); } 1123FOR_EACH_CONDITION_INSTRUCTION(DEFINE_CONDITION_VISITORS) 1124#undef DEFINE_CONDITION_VISITORS 1125#undef FOR_EACH_CONDITION_INSTRUCTION 1126 1127void LocationsBuilderARM64::VisitDiv(HDiv* div) { 1128 LocationSummary* locations = 1129 new (GetGraph()->GetArena()) LocationSummary(div, LocationSummary::kNoCall); 1130 switch (div->GetResultType()) { 1131 case Primitive::kPrimInt: 1132 case Primitive::kPrimLong: 1133 locations->SetInAt(0, Location::RequiresRegister()); 1134 locations->SetInAt(1, Location::RequiresRegister()); 1135 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1136 break; 1137 1138 case Primitive::kPrimFloat: 1139 case Primitive::kPrimDouble: 1140 locations->SetInAt(0, Location::RequiresFpuRegister()); 1141 locations->SetInAt(1, Location::RequiresFpuRegister()); 1142 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1143 break; 1144 1145 default: 1146 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 1147 } 1148} 1149 1150void InstructionCodeGeneratorARM64::VisitDiv(HDiv* div) { 1151 Primitive::Type type = div->GetResultType(); 1152 switch (type) { 1153 case Primitive::kPrimInt: 1154 case Primitive::kPrimLong: 1155 __ Sdiv(OutputRegister(div), InputRegisterAt(div, 0), InputRegisterAt(div, 1)); 1156 break; 1157 1158 case Primitive::kPrimFloat: 1159 case Primitive::kPrimDouble: 1160 __ Fdiv(OutputFPRegister(div), InputFPRegisterAt(div, 0), InputFPRegisterAt(div, 1)); 1161 break; 1162 1163 default: 1164 LOG(FATAL) << "Unexpected div type " << type; 1165 } 1166} 1167 1168void LocationsBuilderARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) { 1169 LocationSummary* locations = 1170 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1171 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); 1172 if (instruction->HasUses()) { 1173 locations->SetOut(Location::SameAsFirstInput()); 1174 } 1175} 1176 1177void InstructionCodeGeneratorARM64::VisitDivZeroCheck(HDivZeroCheck* instruction) { 1178 SlowPathCodeARM64* slow_path = 1179 new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM64(instruction); 1180 codegen_->AddSlowPath(slow_path); 1181 Location value = instruction->GetLocations()->InAt(0); 1182 1183 if (value.IsConstant()) { 1184 int64_t divisor = Int64ConstantFrom(value); 1185 if (divisor == 0) { 1186 __ B(slow_path->GetEntryLabel()); 1187 } else { 1188 LOG(FATAL) << "Divisions by non-null constants should have been optimized away."; 1189 } 1190 } else { 1191 __ Cbz(InputRegisterAt(instruction, 0), slow_path->GetEntryLabel()); 1192 } 1193} 1194 1195void LocationsBuilderARM64::VisitDoubleConstant(HDoubleConstant* constant) { 1196 LocationSummary* locations = 1197 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1198 locations->SetOut(Location::ConstantLocation(constant)); 1199} 1200 1201void InstructionCodeGeneratorARM64::VisitDoubleConstant(HDoubleConstant* constant) { 1202 UNUSED(constant); 1203 // Will be generated at use site. 1204} 1205 1206void LocationsBuilderARM64::VisitExit(HExit* exit) { 1207 exit->SetLocations(nullptr); 1208} 1209 1210void InstructionCodeGeneratorARM64::VisitExit(HExit* exit) { 1211 UNUSED(exit); 1212 if (kIsDebugBuild) { 1213 down_cast<Arm64Assembler*>(GetAssembler())->Comment("Unreachable"); 1214 __ Brk(__LINE__); // TODO: Introduce special markers for such code locations. 1215 } 1216} 1217 1218void LocationsBuilderARM64::VisitFloatConstant(HFloatConstant* constant) { 1219 LocationSummary* locations = 1220 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1221 locations->SetOut(Location::ConstantLocation(constant)); 1222} 1223 1224void InstructionCodeGeneratorARM64::VisitFloatConstant(HFloatConstant* constant) { 1225 UNUSED(constant); 1226 // Will be generated at use site. 1227} 1228 1229void LocationsBuilderARM64::VisitGoto(HGoto* got) { 1230 got->SetLocations(nullptr); 1231} 1232 1233void InstructionCodeGeneratorARM64::VisitGoto(HGoto* got) { 1234 HBasicBlock* successor = got->GetSuccessor(); 1235 // TODO: Support for suspend checks emission. 1236 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 1237 __ B(codegen_->GetLabelOf(successor)); 1238 } 1239} 1240 1241void LocationsBuilderARM64::VisitIf(HIf* if_instr) { 1242 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); 1243 HInstruction* cond = if_instr->InputAt(0); 1244 DCHECK(cond->IsCondition()); 1245 if (cond->AsCondition()->NeedsMaterialization()) { 1246 locations->SetInAt(0, Location::RequiresRegister()); 1247 } 1248} 1249 1250void InstructionCodeGeneratorARM64::VisitIf(HIf* if_instr) { 1251 HInstruction* cond = if_instr->InputAt(0); 1252 DCHECK(cond->IsCondition()); 1253 HCondition* condition = cond->AsCondition(); 1254 vixl::Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor()); 1255 vixl::Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor()); 1256 1257 // TODO: Support constant condition input in VisitIf. 1258 1259 if (condition->NeedsMaterialization()) { 1260 // The condition instruction has been materialized, compare the output to 0. 1261 Location cond_val = if_instr->GetLocations()->InAt(0); 1262 DCHECK(cond_val.IsRegister()); 1263 __ Cbnz(InputRegisterAt(if_instr, 0), true_target); 1264 1265 } else { 1266 // The condition instruction has not been materialized, use its inputs as 1267 // the comparison and its condition as the branch condition. 1268 Register lhs = InputRegisterAt(condition, 0); 1269 Operand rhs = InputOperandAt(condition, 1); 1270 Condition arm64_cond = ARM64Condition(condition->GetCondition()); 1271 if ((arm64_cond == eq || arm64_cond == ne) && rhs.IsImmediate() && (rhs.immediate() == 0)) { 1272 if (arm64_cond == eq) { 1273 __ Cbz(lhs, true_target); 1274 } else { 1275 __ Cbnz(lhs, true_target); 1276 } 1277 } else { 1278 __ Cmp(lhs, rhs); 1279 __ B(arm64_cond, true_target); 1280 } 1281 } 1282 1283 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) { 1284 __ B(false_target); 1285 } 1286} 1287 1288void LocationsBuilderARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 1289 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 1290 locations->SetInAt(0, Location::RequiresRegister()); 1291 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1292} 1293 1294void InstructionCodeGeneratorARM64::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 1295 MemOperand field = MemOperand(InputRegisterAt(instruction, 0), 1296 instruction->GetFieldOffset().Uint32Value()); 1297 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), field); 1298} 1299 1300void LocationsBuilderARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1301 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 1302 locations->SetInAt(0, Location::RequiresRegister()); 1303 locations->SetInAt(1, Location::RequiresRegister()); 1304} 1305 1306void InstructionCodeGeneratorARM64::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1307 Primitive::Type field_type = instruction->GetFieldType(); 1308 CPURegister value = InputCPURegisterAt(instruction, 1); 1309 Register obj = InputRegisterAt(instruction, 0); 1310 codegen_->Store(field_type, value, MemOperand(obj, instruction->GetFieldOffset().Uint32Value())); 1311 if (field_type == Primitive::kPrimNot) { 1312 codegen_->MarkGCCard(obj, Register(value)); 1313 } 1314} 1315 1316void LocationsBuilderARM64::VisitInstanceOf(HInstanceOf* instruction) { 1317 LocationSummary::CallKind call_kind = 1318 instruction->IsClassFinal() ? LocationSummary::kNoCall : LocationSummary::kCallOnSlowPath; 1319 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 1320 locations->SetInAt(0, Location::RequiresRegister()); 1321 locations->SetInAt(1, Location::RequiresRegister()); 1322 locations->SetOut(Location::RequiresRegister(), true); // The output does overlap inputs. 1323} 1324 1325void InstructionCodeGeneratorARM64::VisitInstanceOf(HInstanceOf* instruction) { 1326 LocationSummary* locations = instruction->GetLocations(); 1327 Register obj = InputRegisterAt(instruction, 0);; 1328 Register cls = InputRegisterAt(instruction, 1);; 1329 Register out = OutputRegister(instruction); 1330 1331 vixl::Label done; 1332 1333 // Return 0 if `obj` is null. 1334 // TODO: Avoid this check if we know `obj` is not null. 1335 __ Mov(out, 0); 1336 __ Cbz(obj, &done); 1337 1338 // Compare the class of `obj` with `cls`. 1339 __ Ldr(out, MemOperand(obj, mirror::Object::ClassOffset().Int32Value())); 1340 __ Cmp(out, cls); 1341 if (instruction->IsClassFinal()) { 1342 // Classes must be equal for the instanceof to succeed. 1343 __ Cset(out, eq); 1344 } else { 1345 // If the classes are not equal, we go into a slow path. 1346 DCHECK(locations->OnlyCallsOnSlowPath()); 1347 SlowPathCodeARM64* slow_path = 1348 new (GetGraph()->GetArena()) TypeCheckSlowPathARM64(); 1349 codegen_->AddSlowPath(slow_path); 1350 __ B(ne, slow_path->GetEntryLabel()); 1351 __ Mov(out, 1); 1352 __ Bind(slow_path->GetExitLabel()); 1353 } 1354 1355 __ Bind(&done); 1356} 1357 1358void LocationsBuilderARM64::VisitIntConstant(HIntConstant* constant) { 1359 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant); 1360 locations->SetOut(Location::ConstantLocation(constant)); 1361} 1362 1363void InstructionCodeGeneratorARM64::VisitIntConstant(HIntConstant* constant) { 1364 // Will be generated at use site. 1365 UNUSED(constant); 1366} 1367 1368void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) { 1369 LocationSummary* locations = 1370 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); 1371 locations->AddTemp(LocationFrom(x0)); 1372 1373 InvokeDexCallingConventionVisitor calling_convention_visitor; 1374 for (size_t i = 0; i < invoke->InputCount(); i++) { 1375 HInstruction* input = invoke->InputAt(i); 1376 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 1377 } 1378 1379 Primitive::Type return_type = invoke->GetType(); 1380 if (return_type != Primitive::kPrimVoid) { 1381 locations->SetOut(calling_convention_visitor.GetReturnLocation(return_type)); 1382 } 1383} 1384 1385void LocationsBuilderARM64::VisitInvokeInterface(HInvokeInterface* invoke) { 1386 HandleInvoke(invoke); 1387} 1388 1389void InstructionCodeGeneratorARM64::VisitInvokeInterface(HInvokeInterface* invoke) { 1390 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. 1391 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0)); 1392 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + 1393 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); 1394 Location receiver = invoke->GetLocations()->InAt(0); 1395 Offset class_offset = mirror::Object::ClassOffset(); 1396 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64PointerSize); 1397 1398 // The register ip1 is required to be used for the hidden argument in 1399 // art_quick_imt_conflict_trampoline, so prevent VIXL from using it. 1400 UseScratchRegisterScope scratch_scope(GetVIXLAssembler()); 1401 scratch_scope.Exclude(ip1); 1402 __ Mov(ip1, invoke->GetDexMethodIndex()); 1403 1404 // temp = object->GetClass(); 1405 if (receiver.IsStackSlot()) { 1406 __ Ldr(temp, StackOperandFrom(receiver)); 1407 __ Ldr(temp, HeapOperand(temp, class_offset)); 1408 } else { 1409 __ Ldr(temp, HeapOperandFrom(receiver, class_offset)); 1410 } 1411 // temp = temp->GetImtEntryAt(method_offset); 1412 __ Ldr(temp, HeapOperand(temp, method_offset)); 1413 // lr = temp->GetEntryPoint(); 1414 __ Ldr(lr, HeapOperand(temp, entry_point)); 1415 // lr(); 1416 __ Blr(lr); 1417 DCHECK(!codegen_->IsLeafMethod()); 1418 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1419} 1420 1421void LocationsBuilderARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1422 HandleInvoke(invoke); 1423} 1424 1425void LocationsBuilderARM64::VisitInvokeStatic(HInvokeStatic* invoke) { 1426 HandleInvoke(invoke); 1427} 1428 1429void InstructionCodeGeneratorARM64::VisitInvokeStatic(HInvokeStatic* invoke) { 1430 Register temp = WRegisterFrom(invoke->GetLocations()->GetTemp(0)); 1431 // Make sure that ArtMethod* is passed in W0 as per the calling convention 1432 DCHECK(temp.Is(w0)); 1433 size_t index_in_cache = mirror::Array::DataOffset(kHeapRefSize).SizeValue() + 1434 invoke->GetIndexInDexCache() * kHeapRefSize; 1435 1436 // TODO: Implement all kinds of calls: 1437 // 1) boot -> boot 1438 // 2) app -> boot 1439 // 3) app -> app 1440 // 1441 // Currently we implement the app -> app logic, which looks up in the resolve cache. 1442 1443 // temp = method; 1444 codegen_->LoadCurrentMethod(temp); 1445 // temp = temp->dex_cache_resolved_methods_; 1446 __ Ldr(temp, MemOperand(temp.X(), 1447 mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue())); 1448 // temp = temp[index_in_cache]; 1449 __ Ldr(temp, MemOperand(temp.X(), index_in_cache)); 1450 // lr = temp->entry_point_from_quick_compiled_code_; 1451 __ Ldr(lr, MemOperand(temp.X(), 1452 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( 1453 kArm64PointerSize).SizeValue())); 1454 // lr(); 1455 __ Blr(lr); 1456 1457 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1458 DCHECK(!codegen_->IsLeafMethod()); 1459} 1460 1461void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1462 LocationSummary* locations = invoke->GetLocations(); 1463 Location receiver = locations->InAt(0); 1464 Register temp = XRegisterFrom(invoke->GetLocations()->GetTemp(0)); 1465 size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() + 1466 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); 1467 Offset class_offset = mirror::Object::ClassOffset(); 1468 Offset entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset(kArm64PointerSize); 1469 1470 // temp = object->GetClass(); 1471 if (receiver.IsStackSlot()) { 1472 __ Ldr(temp.W(), MemOperand(sp, receiver.GetStackIndex())); 1473 __ Ldr(temp.W(), MemOperand(temp, class_offset.SizeValue())); 1474 } else { 1475 DCHECK(receiver.IsRegister()); 1476 __ Ldr(temp.W(), HeapOperandFrom(receiver, class_offset)); 1477 } 1478 // temp = temp->GetMethodAt(method_offset); 1479 __ Ldr(temp.W(), MemOperand(temp, method_offset)); 1480 // lr = temp->GetEntryPoint(); 1481 __ Ldr(lr, MemOperand(temp, entry_point.SizeValue())); 1482 // lr(); 1483 __ Blr(lr); 1484 DCHECK(!codegen_->IsLeafMethod()); 1485 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1486} 1487 1488void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) { 1489 LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath 1490 : LocationSummary::kNoCall; 1491 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); 1492 locations->SetOut(Location::RequiresRegister()); 1493} 1494 1495void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { 1496 Register out = OutputRegister(cls); 1497 if (cls->IsReferrersClass()) { 1498 DCHECK(!cls->CanCallRuntime()); 1499 DCHECK(!cls->MustGenerateClinitCheck()); 1500 codegen_->LoadCurrentMethod(out); 1501 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset())); 1502 } else { 1503 DCHECK(cls->CanCallRuntime()); 1504 codegen_->LoadCurrentMethod(out); 1505 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset())); 1506 __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); 1507 1508 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64( 1509 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); 1510 codegen_->AddSlowPath(slow_path); 1511 __ Cbz(out, slow_path->GetEntryLabel()); 1512 if (cls->MustGenerateClinitCheck()) { 1513 GenerateClassInitializationCheck(slow_path, out); 1514 } else { 1515 __ Bind(slow_path->GetExitLabel()); 1516 } 1517 } 1518} 1519 1520void LocationsBuilderARM64::VisitLoadException(HLoadException* load) { 1521 LocationSummary* locations = 1522 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall); 1523 locations->SetOut(Location::RequiresRegister()); 1524} 1525 1526void InstructionCodeGeneratorARM64::VisitLoadException(HLoadException* instruction) { 1527 MemOperand exception = MemOperand(tr, Thread::ExceptionOffset<kArm64WordSize>().Int32Value()); 1528 __ Ldr(OutputRegister(instruction), exception); 1529 __ Str(wzr, exception); 1530} 1531 1532void LocationsBuilderARM64::VisitLoadLocal(HLoadLocal* load) { 1533 load->SetLocations(nullptr); 1534} 1535 1536void InstructionCodeGeneratorARM64::VisitLoadLocal(HLoadLocal* load) { 1537 // Nothing to do, this is driven by the code generator. 1538 UNUSED(load); 1539} 1540 1541void LocationsBuilderARM64::VisitLoadString(HLoadString* load) { 1542 LocationSummary* locations = 1543 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath); 1544 locations->SetOut(Location::RequiresRegister()); 1545} 1546 1547void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) { 1548 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load); 1549 codegen_->AddSlowPath(slow_path); 1550 1551 Register out = OutputRegister(load); 1552 codegen_->LoadCurrentMethod(out); 1553 __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheStringsOffset())); 1554 __ Ldr(out, MemOperand(out.X(), CodeGenerator::GetCacheOffset(load->GetStringIndex()))); 1555 __ Cbz(out, slow_path->GetEntryLabel()); 1556 __ Bind(slow_path->GetExitLabel()); 1557} 1558 1559void LocationsBuilderARM64::VisitLocal(HLocal* local) { 1560 local->SetLocations(nullptr); 1561} 1562 1563void InstructionCodeGeneratorARM64::VisitLocal(HLocal* local) { 1564 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 1565} 1566 1567void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) { 1568 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant); 1569 locations->SetOut(Location::ConstantLocation(constant)); 1570} 1571 1572void InstructionCodeGeneratorARM64::VisitLongConstant(HLongConstant* constant) { 1573 // Will be generated at use site. 1574 UNUSED(constant); 1575} 1576 1577void LocationsBuilderARM64::VisitMonitorOperation(HMonitorOperation* instruction) { 1578 LocationSummary* locations = 1579 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1580 InvokeRuntimeCallingConvention calling_convention; 1581 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); 1582} 1583 1584void InstructionCodeGeneratorARM64::VisitMonitorOperation(HMonitorOperation* instruction) { 1585 codegen_->InvokeRuntime(instruction->IsEnter() 1586 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject), 1587 instruction, 1588 instruction->GetDexPc()); 1589} 1590 1591void LocationsBuilderARM64::VisitMul(HMul* mul) { 1592 LocationSummary* locations = 1593 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall); 1594 switch (mul->GetResultType()) { 1595 case Primitive::kPrimInt: 1596 case Primitive::kPrimLong: 1597 locations->SetInAt(0, Location::RequiresRegister()); 1598 locations->SetInAt(1, Location::RequiresRegister()); 1599 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1600 break; 1601 1602 case Primitive::kPrimFloat: 1603 case Primitive::kPrimDouble: 1604 locations->SetInAt(0, Location::RequiresFpuRegister()); 1605 locations->SetInAt(1, Location::RequiresFpuRegister()); 1606 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1607 break; 1608 1609 default: 1610 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 1611 } 1612} 1613 1614void InstructionCodeGeneratorARM64::VisitMul(HMul* mul) { 1615 switch (mul->GetResultType()) { 1616 case Primitive::kPrimInt: 1617 case Primitive::kPrimLong: 1618 __ Mul(OutputRegister(mul), InputRegisterAt(mul, 0), InputRegisterAt(mul, 1)); 1619 break; 1620 1621 case Primitive::kPrimFloat: 1622 case Primitive::kPrimDouble: 1623 __ Fmul(OutputFPRegister(mul), InputFPRegisterAt(mul, 0), InputFPRegisterAt(mul, 1)); 1624 break; 1625 1626 default: 1627 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 1628 } 1629} 1630 1631void LocationsBuilderARM64::VisitNeg(HNeg* neg) { 1632 LocationSummary* locations = 1633 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); 1634 switch (neg->GetResultType()) { 1635 case Primitive::kPrimInt: 1636 case Primitive::kPrimLong: 1637 locations->SetInAt(0, Location::RegisterOrConstant(neg->InputAt(0))); 1638 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1639 break; 1640 1641 case Primitive::kPrimFloat: 1642 case Primitive::kPrimDouble: 1643 locations->SetInAt(0, Location::RequiresFpuRegister()); 1644 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1645 break; 1646 1647 default: 1648 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1649 } 1650} 1651 1652void InstructionCodeGeneratorARM64::VisitNeg(HNeg* neg) { 1653 switch (neg->GetResultType()) { 1654 case Primitive::kPrimInt: 1655 case Primitive::kPrimLong: 1656 __ Neg(OutputRegister(neg), InputOperandAt(neg, 0)); 1657 break; 1658 1659 case Primitive::kPrimFloat: 1660 case Primitive::kPrimDouble: 1661 __ Fneg(OutputFPRegister(neg), InputFPRegisterAt(neg, 0)); 1662 break; 1663 1664 default: 1665 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1666 } 1667} 1668 1669void LocationsBuilderARM64::VisitNewArray(HNewArray* instruction) { 1670 LocationSummary* locations = 1671 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1672 InvokeRuntimeCallingConvention calling_convention; 1673 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0))); 1674 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1))); 1675 locations->SetOut(LocationFrom(x0)); 1676 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(2))); 1677} 1678 1679void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) { 1680 LocationSummary* locations = instruction->GetLocations(); 1681 InvokeRuntimeCallingConvention calling_convention; 1682 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt); 1683 DCHECK(type_index.Is(w0)); 1684 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot); 1685 DCHECK(current_method.Is(w1)); 1686 codegen_->LoadCurrentMethod(current_method); 1687 __ Mov(type_index, instruction->GetTypeIndex()); 1688 codegen_->InvokeRuntime( 1689 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc()); 1690} 1691 1692void LocationsBuilderARM64::VisitNewInstance(HNewInstance* instruction) { 1693 LocationSummary* locations = 1694 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1695 InvokeRuntimeCallingConvention calling_convention; 1696 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(0))); 1697 locations->AddTemp(LocationFrom(calling_convention.GetRegisterAt(1))); 1698 locations->SetOut(calling_convention.GetReturnLocation(Primitive::kPrimNot)); 1699} 1700 1701void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) { 1702 LocationSummary* locations = instruction->GetLocations(); 1703 Register type_index = RegisterFrom(locations->GetTemp(0), Primitive::kPrimInt); 1704 DCHECK(type_index.Is(w0)); 1705 Register current_method = RegisterFrom(locations->GetTemp(1), Primitive::kPrimNot); 1706 DCHECK(current_method.Is(w1)); 1707 codegen_->LoadCurrentMethod(current_method); 1708 __ Mov(type_index, instruction->GetTypeIndex()); 1709 codegen_->InvokeRuntime( 1710 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc()); 1711} 1712 1713void LocationsBuilderARM64::VisitNot(HNot* instruction) { 1714 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 1715 locations->SetInAt(0, Location::RequiresRegister()); 1716 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1717} 1718 1719void InstructionCodeGeneratorARM64::VisitNot(HNot* instruction) { 1720 switch (instruction->InputAt(0)->GetType()) { 1721 case Primitive::kPrimBoolean: 1722 __ Eor(OutputRegister(instruction), InputRegisterAt(instruction, 0), Operand(1)); 1723 break; 1724 1725 case Primitive::kPrimInt: 1726 case Primitive::kPrimLong: 1727 __ Mvn(OutputRegister(instruction), InputOperandAt(instruction, 0)); 1728 break; 1729 1730 default: 1731 LOG(FATAL) << "Unexpected type for not operation " << instruction->GetResultType(); 1732 } 1733} 1734 1735void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) { 1736 LocationSummary* locations = 1737 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1738 locations->SetInAt(0, Location::RequiresRegister()); 1739 if (instruction->HasUses()) { 1740 locations->SetOut(Location::SameAsFirstInput()); 1741 } 1742} 1743 1744void InstructionCodeGeneratorARM64::VisitNullCheck(HNullCheck* instruction) { 1745 SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM64(instruction); 1746 codegen_->AddSlowPath(slow_path); 1747 1748 LocationSummary* locations = instruction->GetLocations(); 1749 Location obj = locations->InAt(0); 1750 if (obj.IsRegister()) { 1751 __ Cbz(RegisterFrom(obj, instruction->InputAt(0)->GetType()), slow_path->GetEntryLabel()); 1752 } else { 1753 DCHECK(obj.IsConstant()) << obj; 1754 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); 1755 __ B(slow_path->GetEntryLabel()); 1756 } 1757} 1758 1759void LocationsBuilderARM64::VisitOr(HOr* instruction) { 1760 HandleBinaryOp(instruction); 1761} 1762 1763void InstructionCodeGeneratorARM64::VisitOr(HOr* instruction) { 1764 HandleBinaryOp(instruction); 1765} 1766 1767void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) { 1768 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 1769 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 1770 if (location.IsStackSlot()) { 1771 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1772 } else if (location.IsDoubleStackSlot()) { 1773 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1774 } 1775 locations->SetOut(location); 1776} 1777 1778void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) { 1779 // Nothing to do, the parameter is already at its location. 1780 UNUSED(instruction); 1781} 1782 1783void LocationsBuilderARM64::VisitPhi(HPhi* instruction) { 1784 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 1785 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 1786 locations->SetInAt(i, Location::Any()); 1787 } 1788 locations->SetOut(Location::Any()); 1789} 1790 1791void InstructionCodeGeneratorARM64::VisitPhi(HPhi* instruction) { 1792 UNUSED(instruction); 1793 LOG(FATAL) << "Unreachable"; 1794} 1795 1796void LocationsBuilderARM64::VisitReturn(HReturn* instruction) { 1797 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 1798 Primitive::Type return_type = instruction->InputAt(0)->GetType(); 1799 locations->SetInAt(0, ARM64ReturnLocation(return_type)); 1800} 1801 1802void InstructionCodeGeneratorARM64::VisitReturn(HReturn* instruction) { 1803 UNUSED(instruction); 1804 codegen_->GenerateFrameExit(); 1805 __ Br(lr); 1806} 1807 1808void LocationsBuilderARM64::VisitReturnVoid(HReturnVoid* instruction) { 1809 instruction->SetLocations(nullptr); 1810} 1811 1812void InstructionCodeGeneratorARM64::VisitReturnVoid(HReturnVoid* instruction) { 1813 UNUSED(instruction); 1814 codegen_->GenerateFrameExit(); 1815 __ Br(lr); 1816} 1817 1818void LocationsBuilderARM64::VisitStoreLocal(HStoreLocal* store) { 1819 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store); 1820 Primitive::Type field_type = store->InputAt(1)->GetType(); 1821 switch (field_type) { 1822 case Primitive::kPrimNot: 1823 case Primitive::kPrimBoolean: 1824 case Primitive::kPrimByte: 1825 case Primitive::kPrimChar: 1826 case Primitive::kPrimShort: 1827 case Primitive::kPrimInt: 1828 case Primitive::kPrimFloat: 1829 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1830 break; 1831 1832 case Primitive::kPrimLong: 1833 case Primitive::kPrimDouble: 1834 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1835 break; 1836 1837 default: 1838 LOG(FATAL) << "Unimplemented local type " << field_type; 1839 } 1840} 1841 1842void InstructionCodeGeneratorARM64::VisitStoreLocal(HStoreLocal* store) { 1843 UNUSED(store); 1844} 1845 1846void LocationsBuilderARM64::VisitSub(HSub* instruction) { 1847 HandleBinaryOp(instruction); 1848} 1849 1850void InstructionCodeGeneratorARM64::VisitSub(HSub* instruction) { 1851 HandleBinaryOp(instruction); 1852} 1853 1854void LocationsBuilderARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) { 1855 LocationSummary* locations = 1856 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1857 locations->SetInAt(0, Location::RequiresRegister()); 1858 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1859} 1860 1861void InstructionCodeGeneratorARM64::VisitStaticFieldGet(HStaticFieldGet* instruction) { 1862 Register cls = InputRegisterAt(instruction, 0); 1863 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1864 codegen_->Load(instruction->GetType(), OutputCPURegister(instruction), MemOperand(cls, offset)); 1865} 1866 1867void LocationsBuilderARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) { 1868 LocationSummary* locations = 1869 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1870 locations->SetInAt(0, Location::RequiresRegister()); 1871 locations->SetInAt(1, Location::RequiresRegister()); 1872} 1873 1874void InstructionCodeGeneratorARM64::VisitStaticFieldSet(HStaticFieldSet* instruction) { 1875 CPURegister value = InputCPURegisterAt(instruction, 1); 1876 Register cls = InputRegisterAt(instruction, 0); 1877 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1878 Primitive::Type field_type = instruction->GetFieldType(); 1879 1880 codegen_->Store(field_type, value, MemOperand(cls, offset)); 1881 if (field_type == Primitive::kPrimNot) { 1882 codegen_->MarkGCCard(cls, Register(value)); 1883 } 1884} 1885 1886void LocationsBuilderARM64::VisitSuspendCheck(HSuspendCheck* instruction) { 1887 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 1888} 1889 1890void InstructionCodeGeneratorARM64::VisitSuspendCheck(HSuspendCheck* instruction) { 1891 // TODO: Improve support for suspend checks. 1892 SuspendCheckSlowPathARM64* slow_path = 1893 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM64(instruction, nullptr); 1894 codegen_->AddSlowPath(slow_path); 1895 1896 __ Subs(wSuspend, wSuspend, 1); 1897 __ B(slow_path->GetEntryLabel(), le); 1898 __ Bind(slow_path->GetReturnLabel()); 1899} 1900 1901void LocationsBuilderARM64::VisitTemporary(HTemporary* temp) { 1902 temp->SetLocations(nullptr); 1903} 1904 1905void InstructionCodeGeneratorARM64::VisitTemporary(HTemporary* temp) { 1906 // Nothing to do, this is driven by the code generator. 1907 UNUSED(temp); 1908} 1909 1910void LocationsBuilderARM64::VisitThrow(HThrow* instruction) { 1911 LocationSummary* locations = 1912 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1913 InvokeRuntimeCallingConvention calling_convention; 1914 locations->SetInAt(0, LocationFrom(calling_convention.GetRegisterAt(0))); 1915} 1916 1917void InstructionCodeGeneratorARM64::VisitThrow(HThrow* instruction) { 1918 codegen_->InvokeRuntime( 1919 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc()); 1920} 1921 1922void LocationsBuilderARM64::VisitTypeConversion(HTypeConversion* conversion) { 1923 LocationSummary* locations = 1924 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall); 1925 Primitive::Type input_type = conversion->GetInputType(); 1926 Primitive::Type result_type = conversion->GetResultType(); 1927 if ((input_type == Primitive::kPrimNot) || (input_type == Primitive::kPrimVoid) || 1928 (result_type == Primitive::kPrimNot) || (result_type == Primitive::kPrimVoid)) { 1929 LOG(FATAL) << "Unexpected type conversion from " << input_type << " to " << result_type; 1930 } 1931 1932 if (IsFPType(input_type)) { 1933 locations->SetInAt(0, Location::RequiresFpuRegister()); 1934 } else { 1935 locations->SetInAt(0, Location::RequiresRegister()); 1936 } 1937 1938 if (IsFPType(result_type)) { 1939 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1940 } else { 1941 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1942 } 1943} 1944 1945void InstructionCodeGeneratorARM64::VisitTypeConversion(HTypeConversion* conversion) { 1946 Primitive::Type result_type = conversion->GetResultType(); 1947 Primitive::Type input_type = conversion->GetInputType(); 1948 1949 DCHECK_NE(input_type, result_type); 1950 1951 if (IsIntegralType(result_type) && IsIntegralType(input_type)) { 1952 int result_size = Primitive::ComponentSize(result_type); 1953 int input_size = Primitive::ComponentSize(input_type); 1954 int min_size = kBitsPerByte * std::min(result_size, input_size); 1955 if ((result_type == Primitive::kPrimChar) || 1956 ((input_type == Primitive::kPrimChar) && (result_size > input_size))) { 1957 __ Ubfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size); 1958 } else { 1959 __ Sbfx(OutputRegister(conversion), InputRegisterAt(conversion, 0), 0, min_size); 1960 } 1961 return; 1962 } 1963 1964 LOG(FATAL) << "Unexpected or unimplemented type conversion from " << input_type 1965 << " to " << result_type; 1966} 1967 1968void LocationsBuilderARM64::VisitXor(HXor* instruction) { 1969 HandleBinaryOp(instruction); 1970} 1971 1972void InstructionCodeGeneratorARM64::VisitXor(HXor* instruction) { 1973 HandleBinaryOp(instruction); 1974} 1975 1976#undef __ 1977#undef QUICK_ENTRY_POINT 1978 1979} // namespace arm64 1980} // namespace art 1981