code_generator_arm.cc revision c74652867cd9293e86232324e5e057cd73c48e74
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_arm.h" 18 19#include "arch/arm/instruction_set_features_arm.h" 20#include "entrypoints/quick/quick_entrypoints.h" 21#include "gc/accounting/card_table.h" 22#include "intrinsics.h" 23#include "intrinsics_arm.h" 24#include "mirror/array-inl.h" 25#include "mirror/art_method.h" 26#include "mirror/class.h" 27#include "thread.h" 28#include "utils/arm/assembler_arm.h" 29#include "utils/arm/managed_register_arm.h" 30#include "utils/assembler.h" 31#include "utils/stack_checks.h" 32 33namespace art { 34 35namespace arm { 36 37static bool ExpectedPairLayout(Location location) { 38 // We expected this for both core and fpu register pairs. 39 return ((location.low() & 1) == 0) && (location.low() + 1 == location.high()); 40} 41 42static constexpr int kCurrentMethodStackOffset = 0; 43 44// We unconditionally allocate R5 to ensure we can do long operations 45// with baseline. 46static constexpr Register kCoreSavedRegisterForBaseline = R5; 47static constexpr Register kCoreCalleeSaves[] = 48 { R5, R6, R7, R8, R10, R11, PC }; 49static constexpr SRegister kFpuCalleeSaves[] = 50 { S16, S17, S18, S19, S20, S21, S22, S23, S24, S25, S26, S27, S28, S29, S30, S31 }; 51 52// D31 cannot be split into two S registers, and the register allocator only works on 53// S registers. Therefore there is no need to block it. 54static constexpr DRegister DTMP = D31; 55 56#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())-> 57#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value() 58 59class NullCheckSlowPathARM : public SlowPathCodeARM { 60 public: 61 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {} 62 63 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 64 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 65 __ Bind(GetEntryLabel()); 66 arm_codegen->InvokeRuntime( 67 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc(), this); 68 } 69 70 private: 71 HNullCheck* const instruction_; 72 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM); 73}; 74 75class DivZeroCheckSlowPathARM : public SlowPathCodeARM { 76 public: 77 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {} 78 79 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 80 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 81 __ Bind(GetEntryLabel()); 82 arm_codegen->InvokeRuntime( 83 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc(), this); 84 } 85 86 private: 87 HDivZeroCheck* const instruction_; 88 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM); 89}; 90 91class SuspendCheckSlowPathARM : public SlowPathCodeARM { 92 public: 93 SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor) 94 : instruction_(instruction), successor_(successor) {} 95 96 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 97 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 98 __ Bind(GetEntryLabel()); 99 SaveLiveRegisters(codegen, instruction_->GetLocations()); 100 arm_codegen->InvokeRuntime( 101 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc(), this); 102 RestoreLiveRegisters(codegen, instruction_->GetLocations()); 103 if (successor_ == nullptr) { 104 __ b(GetReturnLabel()); 105 } else { 106 __ b(arm_codegen->GetLabelOf(successor_)); 107 } 108 } 109 110 Label* GetReturnLabel() { 111 DCHECK(successor_ == nullptr); 112 return &return_label_; 113 } 114 115 HBasicBlock* GetSuccessor() const { 116 return successor_; 117 } 118 119 private: 120 HSuspendCheck* const instruction_; 121 // If not null, the block to branch to after the suspend check. 122 HBasicBlock* const successor_; 123 124 // If `successor_` is null, the label to branch to after the suspend check. 125 Label return_label_; 126 127 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM); 128}; 129 130class BoundsCheckSlowPathARM : public SlowPathCodeARM { 131 public: 132 BoundsCheckSlowPathARM(HBoundsCheck* instruction, 133 Location index_location, 134 Location length_location) 135 : instruction_(instruction), 136 index_location_(index_location), 137 length_location_(length_location) {} 138 139 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 140 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 141 __ Bind(GetEntryLabel()); 142 // We're moving two locations to locations that could overlap, so we need a parallel 143 // move resolver. 144 InvokeRuntimeCallingConvention calling_convention; 145 codegen->EmitParallelMoves( 146 index_location_, 147 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 148 Primitive::kPrimInt, 149 length_location_, 150 Location::RegisterLocation(calling_convention.GetRegisterAt(1)), 151 Primitive::kPrimInt); 152 arm_codegen->InvokeRuntime( 153 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc(), this); 154 } 155 156 private: 157 HBoundsCheck* const instruction_; 158 const Location index_location_; 159 const Location length_location_; 160 161 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM); 162}; 163 164class LoadClassSlowPathARM : public SlowPathCodeARM { 165 public: 166 LoadClassSlowPathARM(HLoadClass* cls, 167 HInstruction* at, 168 uint32_t dex_pc, 169 bool do_clinit) 170 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { 171 DCHECK(at->IsLoadClass() || at->IsClinitCheck()); 172 } 173 174 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 175 LocationSummary* locations = at_->GetLocations(); 176 177 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 178 __ Bind(GetEntryLabel()); 179 SaveLiveRegisters(codegen, locations); 180 181 InvokeRuntimeCallingConvention calling_convention; 182 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex()); 183 int32_t entry_point_offset = do_clinit_ 184 ? QUICK_ENTRY_POINT(pInitializeStaticStorage) 185 : QUICK_ENTRY_POINT(pInitializeType); 186 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_, this); 187 188 // Move the class to the desired location. 189 Location out = locations->Out(); 190 if (out.IsValid()) { 191 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg())); 192 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); 193 } 194 RestoreLiveRegisters(codegen, locations); 195 __ b(GetExitLabel()); 196 } 197 198 private: 199 // The class this slow path will load. 200 HLoadClass* const cls_; 201 202 // The instruction where this slow path is happening. 203 // (Might be the load class or an initialization check). 204 HInstruction* const at_; 205 206 // The dex PC of `at_`. 207 const uint32_t dex_pc_; 208 209 // Whether to initialize the class. 210 const bool do_clinit_; 211 212 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM); 213}; 214 215class LoadStringSlowPathARM : public SlowPathCodeARM { 216 public: 217 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {} 218 219 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 220 LocationSummary* locations = instruction_->GetLocations(); 221 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 222 223 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 224 __ Bind(GetEntryLabel()); 225 SaveLiveRegisters(codegen, locations); 226 227 InvokeRuntimeCallingConvention calling_convention; 228 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction_->GetStringIndex()); 229 arm_codegen->InvokeRuntime( 230 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc(), this); 231 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); 232 233 RestoreLiveRegisters(codegen, locations); 234 __ b(GetExitLabel()); 235 } 236 237 private: 238 HLoadString* const instruction_; 239 240 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM); 241}; 242 243class TypeCheckSlowPathARM : public SlowPathCodeARM { 244 public: 245 TypeCheckSlowPathARM(HInstruction* instruction, 246 Location class_to_check, 247 Location object_class, 248 uint32_t dex_pc) 249 : instruction_(instruction), 250 class_to_check_(class_to_check), 251 object_class_(object_class), 252 dex_pc_(dex_pc) {} 253 254 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 255 LocationSummary* locations = instruction_->GetLocations(); 256 DCHECK(instruction_->IsCheckCast() 257 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 258 259 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 260 __ Bind(GetEntryLabel()); 261 SaveLiveRegisters(codegen, locations); 262 263 // We're moving two locations to locations that could overlap, so we need a parallel 264 // move resolver. 265 InvokeRuntimeCallingConvention calling_convention; 266 codegen->EmitParallelMoves( 267 class_to_check_, 268 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 269 Primitive::kPrimNot, 270 object_class_, 271 Location::RegisterLocation(calling_convention.GetRegisterAt(1)), 272 Primitive::kPrimNot); 273 274 if (instruction_->IsInstanceOf()) { 275 arm_codegen->InvokeRuntime( 276 QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_, this); 277 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); 278 } else { 279 DCHECK(instruction_->IsCheckCast()); 280 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_, this); 281 } 282 283 RestoreLiveRegisters(codegen, locations); 284 __ b(GetExitLabel()); 285 } 286 287 private: 288 HInstruction* const instruction_; 289 const Location class_to_check_; 290 const Location object_class_; 291 uint32_t dex_pc_; 292 293 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM); 294}; 295 296class DeoptimizationSlowPathARM : public SlowPathCodeARM { 297 public: 298 explicit DeoptimizationSlowPathARM(HInstruction* instruction) 299 : instruction_(instruction) {} 300 301 void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 302 __ Bind(GetEntryLabel()); 303 SaveLiveRegisters(codegen, instruction_->GetLocations()); 304 DCHECK(instruction_->IsDeoptimize()); 305 HDeoptimize* deoptimize = instruction_->AsDeoptimize(); 306 uint32_t dex_pc = deoptimize->GetDexPc(); 307 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 308 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pDeoptimize), instruction_, dex_pc, this); 309 } 310 311 private: 312 HInstruction* const instruction_; 313 DISALLOW_COPY_AND_ASSIGN(DeoptimizationSlowPathARM); 314}; 315 316#undef __ 317 318#undef __ 319#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> 320 321inline Condition ARMCondition(IfCondition cond) { 322 switch (cond) { 323 case kCondEQ: return EQ; 324 case kCondNE: return NE; 325 case kCondLT: return LT; 326 case kCondLE: return LE; 327 case kCondGT: return GT; 328 case kCondGE: return GE; 329 default: 330 LOG(FATAL) << "Unknown if condition"; 331 } 332 return EQ; // Unreachable. 333} 334 335inline Condition ARMOppositeCondition(IfCondition cond) { 336 switch (cond) { 337 case kCondEQ: return NE; 338 case kCondNE: return EQ; 339 case kCondLT: return GE; 340 case kCondLE: return GT; 341 case kCondGT: return LE; 342 case kCondGE: return LT; 343 default: 344 LOG(FATAL) << "Unknown if condition"; 345 } 346 return EQ; // Unreachable. 347} 348 349void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const { 350 stream << Register(reg); 351} 352 353void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 354 stream << SRegister(reg); 355} 356 357size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { 358 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index); 359 return kArmWordSize; 360} 361 362size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) { 363 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index); 364 return kArmWordSize; 365} 366 367size_t CodeGeneratorARM::SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) { 368 __ StoreSToOffset(static_cast<SRegister>(reg_id), SP, stack_index); 369 return kArmWordSize; 370} 371 372size_t CodeGeneratorARM::RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) { 373 __ LoadSFromOffset(static_cast<SRegister>(reg_id), SP, stack_index); 374 return kArmWordSize; 375} 376 377CodeGeneratorARM::CodeGeneratorARM(HGraph* graph, 378 const ArmInstructionSetFeatures& isa_features, 379 const CompilerOptions& compiler_options) 380 : CodeGenerator(graph, 381 kNumberOfCoreRegisters, 382 kNumberOfSRegisters, 383 kNumberOfRegisterPairs, 384 ComputeRegisterMask(reinterpret_cast<const int*>(kCoreCalleeSaves), 385 arraysize(kCoreCalleeSaves)), 386 ComputeRegisterMask(reinterpret_cast<const int*>(kFpuCalleeSaves), 387 arraysize(kFpuCalleeSaves)), 388 compiler_options), 389 block_labels_(graph->GetArena(), 0), 390 location_builder_(graph, this), 391 instruction_visitor_(graph, this), 392 move_resolver_(graph->GetArena(), this), 393 assembler_(true), 394 isa_features_(isa_features) { 395 // Save the PC register to mimic Quick. 396 AddAllocatedRegister(Location::RegisterLocation(PC)); 397} 398 399Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const { 400 switch (type) { 401 case Primitive::kPrimLong: { 402 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs); 403 ArmManagedRegister pair = 404 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg)); 405 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]); 406 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]); 407 408 blocked_core_registers_[pair.AsRegisterPairLow()] = true; 409 blocked_core_registers_[pair.AsRegisterPairHigh()] = true; 410 UpdateBlockedPairRegisters(); 411 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 412 } 413 414 case Primitive::kPrimByte: 415 case Primitive::kPrimBoolean: 416 case Primitive::kPrimChar: 417 case Primitive::kPrimShort: 418 case Primitive::kPrimInt: 419 case Primitive::kPrimNot: { 420 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters); 421 // Block all register pairs that contain `reg`. 422 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 423 ArmManagedRegister current = 424 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 425 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) { 426 blocked_register_pairs_[i] = true; 427 } 428 } 429 return Location::RegisterLocation(reg); 430 } 431 432 case Primitive::kPrimFloat: { 433 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters); 434 return Location::FpuRegisterLocation(reg); 435 } 436 437 case Primitive::kPrimDouble: { 438 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters); 439 DCHECK_EQ(reg % 2, 0); 440 return Location::FpuRegisterPairLocation(reg, reg + 1); 441 } 442 443 case Primitive::kPrimVoid: 444 LOG(FATAL) << "Unreachable type " << type; 445 } 446 447 return Location(); 448} 449 450void CodeGeneratorARM::SetupBlockedRegisters(bool is_baseline) const { 451 // Don't allocate the dalvik style register pair passing. 452 blocked_register_pairs_[R1_R2] = true; 453 454 // Stack register, LR and PC are always reserved. 455 blocked_core_registers_[SP] = true; 456 blocked_core_registers_[LR] = true; 457 blocked_core_registers_[PC] = true; 458 459 // Reserve thread register. 460 blocked_core_registers_[TR] = true; 461 462 // Reserve temp register. 463 blocked_core_registers_[IP] = true; 464 465 if (is_baseline) { 466 for (size_t i = 0; i < arraysize(kCoreCalleeSaves); ++i) { 467 blocked_core_registers_[kCoreCalleeSaves[i]] = true; 468 } 469 470 blocked_core_registers_[kCoreSavedRegisterForBaseline] = false; 471 472 for (size_t i = 0; i < arraysize(kFpuCalleeSaves); ++i) { 473 blocked_fpu_registers_[kFpuCalleeSaves[i]] = true; 474 } 475 } 476 477 UpdateBlockedPairRegisters(); 478} 479 480void CodeGeneratorARM::UpdateBlockedPairRegisters() const { 481 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 482 ArmManagedRegister current = 483 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 484 if (blocked_core_registers_[current.AsRegisterPairLow()] 485 || blocked_core_registers_[current.AsRegisterPairHigh()]) { 486 blocked_register_pairs_[i] = true; 487 } 488 } 489} 490 491InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) 492 : HGraphVisitor(graph), 493 assembler_(codegen->GetAssembler()), 494 codegen_(codegen) {} 495 496static uint32_t LeastSignificantBit(uint32_t mask) { 497 // ffs starts at 1. 498 return ffs(mask) - 1; 499} 500 501void CodeGeneratorARM::ComputeSpillMask() { 502 core_spill_mask_ = allocated_registers_.GetCoreRegisters() & core_callee_save_mask_; 503 // Save one extra register for baseline. Note that on thumb2, there is no easy 504 // instruction to restore just the PC, so this actually helps both baseline 505 // and non-baseline to save and restore at least two registers at entry and exit. 506 core_spill_mask_ |= (1 << kCoreSavedRegisterForBaseline); 507 DCHECK_NE(core_spill_mask_, 0u) << "At least the return address register must be saved"; 508 fpu_spill_mask_ = allocated_registers_.GetFloatingPointRegisters() & fpu_callee_save_mask_; 509 // We use vpush and vpop for saving and restoring floating point registers, which take 510 // a SRegister and the number of registers to save/restore after that SRegister. We 511 // therefore update the `fpu_spill_mask_` to also contain those registers not allocated, 512 // but in the range. 513 if (fpu_spill_mask_ != 0) { 514 uint32_t least_significant_bit = LeastSignificantBit(fpu_spill_mask_); 515 uint32_t most_significant_bit = MostSignificantBit(fpu_spill_mask_); 516 for (uint32_t i = least_significant_bit + 1 ; i < most_significant_bit; ++i) { 517 fpu_spill_mask_ |= (1 << i); 518 } 519 } 520} 521 522static dwarf::Reg DWARFReg(Register reg) { 523 return dwarf::Reg::ArmCore(static_cast<int>(reg)); 524} 525 526static dwarf::Reg DWARFReg(SRegister reg) { 527 return dwarf::Reg::ArmFp(static_cast<int>(reg)); 528} 529 530void CodeGeneratorARM::GenerateFrameEntry() { 531 bool skip_overflow_check = 532 IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm); 533 DCHECK(GetCompilerOptions().GetImplicitStackOverflowChecks()); 534 __ Bind(&frame_entry_label_); 535 536 if (HasEmptyFrame()) { 537 return; 538 } 539 540 if (!skip_overflow_check) { 541 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm))); 542 __ LoadFromOffset(kLoadWord, IP, IP, 0); 543 RecordPcInfo(nullptr, 0); 544 } 545 546 // PC is in the list of callee-save to mimic Quick, but we need to push 547 // LR at entry instead. 548 uint32_t push_mask = (core_spill_mask_ & (~(1 << PC))) | 1 << LR; 549 __ PushList(push_mask); 550 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(push_mask)); 551 __ cfi().RelOffsetForMany(DWARFReg(R0), 0, push_mask, kArmWordSize); 552 if (fpu_spill_mask_ != 0) { 553 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_)); 554 __ vpushs(start_register, POPCOUNT(fpu_spill_mask_)); 555 __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(fpu_spill_mask_)); 556 __ cfi().RelOffsetForMany(DWARFReg(S0), 0, fpu_spill_mask_, kArmWordSize); 557 } 558 int adjust = GetFrameSize() - FrameEntrySpillSize(); 559 __ AddConstant(SP, -adjust); 560 __ cfi().AdjustCFAOffset(adjust); 561 __ StoreToOffset(kStoreWord, R0, SP, 0); 562} 563 564void CodeGeneratorARM::GenerateFrameExit() { 565 if (HasEmptyFrame()) { 566 __ bx(LR); 567 return; 568 } 569 __ cfi().RememberState(); 570 int adjust = GetFrameSize() - FrameEntrySpillSize(); 571 __ AddConstant(SP, adjust); 572 __ cfi().AdjustCFAOffset(-adjust); 573 if (fpu_spill_mask_ != 0) { 574 SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_)); 575 __ vpops(start_register, POPCOUNT(fpu_spill_mask_)); 576 __ cfi().AdjustCFAOffset(-kArmPointerSize * POPCOUNT(fpu_spill_mask_)); 577 __ cfi().RestoreMany(DWARFReg(SRegister(0)), fpu_spill_mask_); 578 } 579 __ PopList(core_spill_mask_); 580 __ cfi().RestoreState(); 581 __ cfi().DefCFAOffset(GetFrameSize()); 582} 583 584void CodeGeneratorARM::Bind(HBasicBlock* block) { 585 __ Bind(GetLabelOf(block)); 586} 587 588Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const { 589 switch (load->GetType()) { 590 case Primitive::kPrimLong: 591 case Primitive::kPrimDouble: 592 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 593 594 case Primitive::kPrimInt: 595 case Primitive::kPrimNot: 596 case Primitive::kPrimFloat: 597 return Location::StackSlot(GetStackSlot(load->GetLocal())); 598 599 case Primitive::kPrimBoolean: 600 case Primitive::kPrimByte: 601 case Primitive::kPrimChar: 602 case Primitive::kPrimShort: 603 case Primitive::kPrimVoid: 604 LOG(FATAL) << "Unexpected type " << load->GetType(); 605 UNREACHABLE(); 606 } 607 608 LOG(FATAL) << "Unreachable"; 609 UNREACHABLE(); 610} 611 612Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type type) { 613 switch (type) { 614 case Primitive::kPrimBoolean: 615 case Primitive::kPrimByte: 616 case Primitive::kPrimChar: 617 case Primitive::kPrimShort: 618 case Primitive::kPrimInt: 619 case Primitive::kPrimNot: { 620 uint32_t index = gp_index_++; 621 uint32_t stack_index = stack_index_++; 622 if (index < calling_convention.GetNumberOfRegisters()) { 623 return Location::RegisterLocation(calling_convention.GetRegisterAt(index)); 624 } else { 625 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index)); 626 } 627 } 628 629 case Primitive::kPrimLong: { 630 uint32_t index = gp_index_; 631 uint32_t stack_index = stack_index_; 632 gp_index_ += 2; 633 stack_index_ += 2; 634 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 635 if (calling_convention.GetRegisterAt(index) == R1) { 636 // Skip R1, and use R2_R3 instead. 637 gp_index_++; 638 index++; 639 } 640 } 641 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 642 DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1, 643 calling_convention.GetRegisterAt(index + 1)); 644 return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index), 645 calling_convention.GetRegisterAt(index + 1)); 646 } else { 647 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index)); 648 } 649 } 650 651 case Primitive::kPrimFloat: { 652 uint32_t stack_index = stack_index_++; 653 if (float_index_ % 2 == 0) { 654 float_index_ = std::max(double_index_, float_index_); 655 } 656 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) { 657 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++)); 658 } else { 659 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index)); 660 } 661 } 662 663 case Primitive::kPrimDouble: { 664 double_index_ = std::max(double_index_, RoundUp(float_index_, 2)); 665 uint32_t stack_index = stack_index_; 666 stack_index_ += 2; 667 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) { 668 uint32_t index = double_index_; 669 double_index_ += 2; 670 Location result = Location::FpuRegisterPairLocation( 671 calling_convention.GetFpuRegisterAt(index), 672 calling_convention.GetFpuRegisterAt(index + 1)); 673 DCHECK(ExpectedPairLayout(result)); 674 return result; 675 } else { 676 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index)); 677 } 678 } 679 680 case Primitive::kPrimVoid: 681 LOG(FATAL) << "Unexpected parameter type " << type; 682 break; 683 } 684 return Location(); 685} 686 687Location InvokeDexCallingConventionVisitorARM::GetReturnLocation(Primitive::Type type) { 688 switch (type) { 689 case Primitive::kPrimBoolean: 690 case Primitive::kPrimByte: 691 case Primitive::kPrimChar: 692 case Primitive::kPrimShort: 693 case Primitive::kPrimInt: 694 case Primitive::kPrimNot: { 695 return Location::RegisterLocation(R0); 696 } 697 698 case Primitive::kPrimFloat: { 699 return Location::FpuRegisterLocation(S0); 700 } 701 702 case Primitive::kPrimLong: { 703 return Location::RegisterPairLocation(R0, R1); 704 } 705 706 case Primitive::kPrimDouble: { 707 return Location::FpuRegisterPairLocation(S0, S1); 708 } 709 710 case Primitive::kPrimVoid: 711 return Location(); 712 } 713 UNREACHABLE(); 714} 715 716void CodeGeneratorARM::Move32(Location destination, Location source) { 717 if (source.Equals(destination)) { 718 return; 719 } 720 if (destination.IsRegister()) { 721 if (source.IsRegister()) { 722 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>()); 723 } else if (source.IsFpuRegister()) { 724 __ vmovrs(destination.AsRegister<Register>(), source.AsFpuRegister<SRegister>()); 725 } else { 726 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex()); 727 } 728 } else if (destination.IsFpuRegister()) { 729 if (source.IsRegister()) { 730 __ vmovsr(destination.AsFpuRegister<SRegister>(), source.AsRegister<Register>()); 731 } else if (source.IsFpuRegister()) { 732 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>()); 733 } else { 734 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex()); 735 } 736 } else { 737 DCHECK(destination.IsStackSlot()) << destination; 738 if (source.IsRegister()) { 739 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex()); 740 } else if (source.IsFpuRegister()) { 741 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex()); 742 } else { 743 DCHECK(source.IsStackSlot()) << source; 744 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 745 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 746 } 747 } 748} 749 750void CodeGeneratorARM::Move64(Location destination, Location source) { 751 if (source.Equals(destination)) { 752 return; 753 } 754 if (destination.IsRegisterPair()) { 755 if (source.IsRegisterPair()) { 756 EmitParallelMoves( 757 Location::RegisterLocation(source.AsRegisterPairHigh<Register>()), 758 Location::RegisterLocation(destination.AsRegisterPairHigh<Register>()), 759 Primitive::kPrimInt, 760 Location::RegisterLocation(source.AsRegisterPairLow<Register>()), 761 Location::RegisterLocation(destination.AsRegisterPairLow<Register>()), 762 Primitive::kPrimInt); 763 } else if (source.IsFpuRegister()) { 764 UNIMPLEMENTED(FATAL); 765 } else { 766 DCHECK(source.IsDoubleStackSlot()); 767 DCHECK(ExpectedPairLayout(destination)); 768 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(), 769 SP, source.GetStackIndex()); 770 } 771 } else if (destination.IsFpuRegisterPair()) { 772 if (source.IsDoubleStackSlot()) { 773 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), 774 SP, 775 source.GetStackIndex()); 776 } else { 777 UNIMPLEMENTED(FATAL); 778 } 779 } else { 780 DCHECK(destination.IsDoubleStackSlot()); 781 if (source.IsRegisterPair()) { 782 // No conflict possible, so just do the moves. 783 if (source.AsRegisterPairLow<Register>() == R1) { 784 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2); 785 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex()); 786 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize)); 787 } else { 788 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(), 789 SP, destination.GetStackIndex()); 790 } 791 } else if (source.IsFpuRegisterPair()) { 792 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()), 793 SP, 794 destination.GetStackIndex()); 795 } else { 796 DCHECK(source.IsDoubleStackSlot()); 797 EmitParallelMoves( 798 Location::StackSlot(source.GetStackIndex()), 799 Location::StackSlot(destination.GetStackIndex()), 800 Primitive::kPrimInt, 801 Location::StackSlot(source.GetHighStackIndex(kArmWordSize)), 802 Location::StackSlot(destination.GetHighStackIndex(kArmWordSize)), 803 Primitive::kPrimInt); 804 } 805 } 806} 807 808void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 809 LocationSummary* locations = instruction->GetLocations(); 810 if (locations != nullptr && locations->Out().Equals(location)) { 811 return; 812 } 813 814 if (locations != nullptr && locations->Out().IsConstant()) { 815 HConstant* const_to_move = locations->Out().GetConstant(); 816 if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) { 817 int32_t value = GetInt32ValueOf(const_to_move); 818 if (location.IsRegister()) { 819 __ LoadImmediate(location.AsRegister<Register>(), value); 820 } else { 821 DCHECK(location.IsStackSlot()); 822 __ LoadImmediate(IP, value); 823 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); 824 } 825 } else { 826 DCHECK(const_to_move->IsLongConstant()) << const_to_move->DebugName(); 827 int64_t value = const_to_move->AsLongConstant()->GetValue(); 828 if (location.IsRegisterPair()) { 829 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value)); 830 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value)); 831 } else { 832 DCHECK(location.IsDoubleStackSlot()); 833 __ LoadImmediate(IP, Low32Bits(value)); 834 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); 835 __ LoadImmediate(IP, High32Bits(value)); 836 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize)); 837 } 838 } 839 } else if (instruction->IsLoadLocal()) { 840 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 841 switch (instruction->GetType()) { 842 case Primitive::kPrimBoolean: 843 case Primitive::kPrimByte: 844 case Primitive::kPrimChar: 845 case Primitive::kPrimShort: 846 case Primitive::kPrimInt: 847 case Primitive::kPrimNot: 848 case Primitive::kPrimFloat: 849 Move32(location, Location::StackSlot(stack_slot)); 850 break; 851 852 case Primitive::kPrimLong: 853 case Primitive::kPrimDouble: 854 Move64(location, Location::DoubleStackSlot(stack_slot)); 855 break; 856 857 default: 858 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 859 } 860 } else if (instruction->IsTemporary()) { 861 Location temp_location = GetTemporaryLocation(instruction->AsTemporary()); 862 if (temp_location.IsStackSlot()) { 863 Move32(location, temp_location); 864 } else { 865 DCHECK(temp_location.IsDoubleStackSlot()); 866 Move64(location, temp_location); 867 } 868 } else { 869 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary()); 870 switch (instruction->GetType()) { 871 case Primitive::kPrimBoolean: 872 case Primitive::kPrimByte: 873 case Primitive::kPrimChar: 874 case Primitive::kPrimShort: 875 case Primitive::kPrimNot: 876 case Primitive::kPrimInt: 877 case Primitive::kPrimFloat: 878 Move32(location, locations->Out()); 879 break; 880 881 case Primitive::kPrimLong: 882 case Primitive::kPrimDouble: 883 Move64(location, locations->Out()); 884 break; 885 886 default: 887 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 888 } 889 } 890} 891 892void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset, 893 HInstruction* instruction, 894 uint32_t dex_pc, 895 SlowPathCode* slow_path) { 896 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset); 897 __ blx(LR); 898 RecordPcInfo(instruction, dex_pc, slow_path); 899 DCHECK(instruction->IsSuspendCheck() 900 || instruction->IsBoundsCheck() 901 || instruction->IsNullCheck() 902 || instruction->IsDivZeroCheck() 903 || instruction->GetLocations()->CanCall() 904 || !IsLeafMethod()); 905} 906 907void LocationsBuilderARM::VisitGoto(HGoto* got) { 908 got->SetLocations(nullptr); 909} 910 911void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { 912 HBasicBlock* successor = got->GetSuccessor(); 913 DCHECK(!successor->IsExitBlock()); 914 915 HBasicBlock* block = got->GetBlock(); 916 HInstruction* previous = got->GetPrevious(); 917 918 HLoopInformation* info = block->GetLoopInformation(); 919 if (info != nullptr && info->IsBackEdge(*block) && info->HasSuspendCheck()) { 920 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); 921 GenerateSuspendCheck(info->GetSuspendCheck(), successor); 922 return; 923 } 924 925 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) { 926 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr); 927 } 928 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 929 __ b(codegen_->GetLabelOf(successor)); 930 } 931} 932 933void LocationsBuilderARM::VisitExit(HExit* exit) { 934 exit->SetLocations(nullptr); 935} 936 937void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { 938 UNUSED(exit); 939} 940 941void InstructionCodeGeneratorARM::GenerateTestAndBranch(HInstruction* instruction, 942 Label* true_target, 943 Label* false_target, 944 Label* always_true_target) { 945 HInstruction* cond = instruction->InputAt(0); 946 if (cond->IsIntConstant()) { 947 // Constant condition, statically compared against 1. 948 int32_t cond_value = cond->AsIntConstant()->GetValue(); 949 if (cond_value == 1) { 950 if (always_true_target != nullptr) { 951 __ b(always_true_target); 952 } 953 return; 954 } else { 955 DCHECK_EQ(cond_value, 0); 956 } 957 } else { 958 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 959 // Condition has been materialized, compare the output to 0 960 DCHECK(instruction->GetLocations()->InAt(0).IsRegister()); 961 __ cmp(instruction->GetLocations()->InAt(0).AsRegister<Register>(), 962 ShifterOperand(0)); 963 __ b(true_target, NE); 964 } else { 965 // Condition has not been materialized, use its inputs as the 966 // comparison and its condition as the branch condition. 967 LocationSummary* locations = cond->GetLocations(); 968 DCHECK(locations->InAt(0).IsRegister()) << locations->InAt(0); 969 Register left = locations->InAt(0).AsRegister<Register>(); 970 if (locations->InAt(1).IsRegister()) { 971 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>())); 972 } else { 973 DCHECK(locations->InAt(1).IsConstant()); 974 HConstant* constant = locations->InAt(1).GetConstant(); 975 int32_t value = CodeGenerator::GetInt32ValueOf(constant); 976 ShifterOperand operand; 977 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) { 978 __ cmp(left, operand); 979 } else { 980 Register temp = IP; 981 __ LoadImmediate(temp, value); 982 __ cmp(left, ShifterOperand(temp)); 983 } 984 } 985 __ b(true_target, ARMCondition(cond->AsCondition()->GetCondition())); 986 } 987 } 988 if (false_target != nullptr) { 989 __ b(false_target); 990 } 991} 992 993void LocationsBuilderARM::VisitIf(HIf* if_instr) { 994 LocationSummary* locations = 995 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); 996 HInstruction* cond = if_instr->InputAt(0); 997 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 998 locations->SetInAt(0, Location::RequiresRegister()); 999 } 1000} 1001 1002void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 1003 Label* true_target = codegen_->GetLabelOf(if_instr->IfTrueSuccessor()); 1004 Label* false_target = codegen_->GetLabelOf(if_instr->IfFalseSuccessor()); 1005 Label* always_true_target = true_target; 1006 if (codegen_->GoesToNextBlock(if_instr->GetBlock(), 1007 if_instr->IfTrueSuccessor())) { 1008 always_true_target = nullptr; 1009 } 1010 if (codegen_->GoesToNextBlock(if_instr->GetBlock(), 1011 if_instr->IfFalseSuccessor())) { 1012 false_target = nullptr; 1013 } 1014 GenerateTestAndBranch(if_instr, true_target, false_target, always_true_target); 1015} 1016 1017void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) { 1018 LocationSummary* locations = new (GetGraph()->GetArena()) 1019 LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath); 1020 HInstruction* cond = deoptimize->InputAt(0); 1021 DCHECK(cond->IsCondition()); 1022 if (cond->AsCondition()->NeedsMaterialization()) { 1023 locations->SetInAt(0, Location::RequiresRegister()); 1024 } 1025} 1026 1027void InstructionCodeGeneratorARM::VisitDeoptimize(HDeoptimize* deoptimize) { 1028 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) 1029 DeoptimizationSlowPathARM(deoptimize); 1030 codegen_->AddSlowPath(slow_path); 1031 Label* slow_path_entry = slow_path->GetEntryLabel(); 1032 GenerateTestAndBranch(deoptimize, slow_path_entry, nullptr, slow_path_entry); 1033} 1034 1035void LocationsBuilderARM::VisitCondition(HCondition* comp) { 1036 LocationSummary* locations = 1037 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); 1038 locations->SetInAt(0, Location::RequiresRegister()); 1039 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1))); 1040 if (comp->NeedsMaterialization()) { 1041 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1042 } 1043} 1044 1045void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) { 1046 if (!comp->NeedsMaterialization()) return; 1047 LocationSummary* locations = comp->GetLocations(); 1048 Register left = locations->InAt(0).AsRegister<Register>(); 1049 1050 if (locations->InAt(1).IsRegister()) { 1051 __ cmp(left, ShifterOperand(locations->InAt(1).AsRegister<Register>())); 1052 } else { 1053 DCHECK(locations->InAt(1).IsConstant()); 1054 int32_t value = CodeGenerator::GetInt32ValueOf(locations->InAt(1).GetConstant()); 1055 ShifterOperand operand; 1056 if (GetAssembler()->ShifterOperandCanHold(R0, left, CMP, value, &operand)) { 1057 __ cmp(left, operand); 1058 } else { 1059 Register temp = IP; 1060 __ LoadImmediate(temp, value); 1061 __ cmp(left, ShifterOperand(temp)); 1062 } 1063 } 1064 __ it(ARMCondition(comp->GetCondition()), kItElse); 1065 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(1), 1066 ARMCondition(comp->GetCondition())); 1067 __ mov(locations->Out().AsRegister<Register>(), ShifterOperand(0), 1068 ARMOppositeCondition(comp->GetCondition())); 1069} 1070 1071void LocationsBuilderARM::VisitEqual(HEqual* comp) { 1072 VisitCondition(comp); 1073} 1074 1075void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) { 1076 VisitCondition(comp); 1077} 1078 1079void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) { 1080 VisitCondition(comp); 1081} 1082 1083void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) { 1084 VisitCondition(comp); 1085} 1086 1087void LocationsBuilderARM::VisitLessThan(HLessThan* comp) { 1088 VisitCondition(comp); 1089} 1090 1091void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) { 1092 VisitCondition(comp); 1093} 1094 1095void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 1096 VisitCondition(comp); 1097} 1098 1099void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 1100 VisitCondition(comp); 1101} 1102 1103void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) { 1104 VisitCondition(comp); 1105} 1106 1107void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) { 1108 VisitCondition(comp); 1109} 1110 1111void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1112 VisitCondition(comp); 1113} 1114 1115void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1116 VisitCondition(comp); 1117} 1118 1119void LocationsBuilderARM::VisitLocal(HLocal* local) { 1120 local->SetLocations(nullptr); 1121} 1122 1123void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 1124 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 1125} 1126 1127void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 1128 load->SetLocations(nullptr); 1129} 1130 1131void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 1132 // Nothing to do, this is driven by the code generator. 1133 UNUSED(load); 1134} 1135 1136void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 1137 LocationSummary* locations = 1138 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall); 1139 switch (store->InputAt(1)->GetType()) { 1140 case Primitive::kPrimBoolean: 1141 case Primitive::kPrimByte: 1142 case Primitive::kPrimChar: 1143 case Primitive::kPrimShort: 1144 case Primitive::kPrimInt: 1145 case Primitive::kPrimNot: 1146 case Primitive::kPrimFloat: 1147 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1148 break; 1149 1150 case Primitive::kPrimLong: 1151 case Primitive::kPrimDouble: 1152 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1153 break; 1154 1155 default: 1156 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType(); 1157 } 1158} 1159 1160void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 1161 UNUSED(store); 1162} 1163 1164void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 1165 LocationSummary* locations = 1166 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1167 locations->SetOut(Location::ConstantLocation(constant)); 1168} 1169 1170void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 1171 // Will be generated at use site. 1172 UNUSED(constant); 1173} 1174 1175void LocationsBuilderARM::VisitNullConstant(HNullConstant* constant) { 1176 LocationSummary* locations = 1177 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1178 locations->SetOut(Location::ConstantLocation(constant)); 1179} 1180 1181void InstructionCodeGeneratorARM::VisitNullConstant(HNullConstant* constant) { 1182 // Will be generated at use site. 1183 UNUSED(constant); 1184} 1185 1186void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { 1187 LocationSummary* locations = 1188 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1189 locations->SetOut(Location::ConstantLocation(constant)); 1190} 1191 1192void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { 1193 // Will be generated at use site. 1194 UNUSED(constant); 1195} 1196 1197void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) { 1198 LocationSummary* locations = 1199 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1200 locations->SetOut(Location::ConstantLocation(constant)); 1201} 1202 1203void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) { 1204 // Will be generated at use site. 1205 UNUSED(constant); 1206} 1207 1208void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) { 1209 LocationSummary* locations = 1210 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1211 locations->SetOut(Location::ConstantLocation(constant)); 1212} 1213 1214void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) { 1215 // Will be generated at use site. 1216 UNUSED(constant); 1217} 1218 1219void LocationsBuilderARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) { 1220 memory_barrier->SetLocations(nullptr); 1221} 1222 1223void InstructionCodeGeneratorARM::VisitMemoryBarrier(HMemoryBarrier* memory_barrier) { 1224 GenerateMemoryBarrier(memory_barrier->GetBarrierKind()); 1225} 1226 1227void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 1228 ret->SetLocations(nullptr); 1229} 1230 1231void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 1232 UNUSED(ret); 1233 codegen_->GenerateFrameExit(); 1234} 1235 1236void LocationsBuilderARM::VisitReturn(HReturn* ret) { 1237 LocationSummary* locations = 1238 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall); 1239 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType())); 1240} 1241 1242void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 1243 UNUSED(ret); 1244 codegen_->GenerateFrameExit(); 1245} 1246 1247void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { 1248 // When we do not run baseline, explicit clinit checks triggered by static 1249 // invokes must have been pruned by art::PrepareForRegisterAllocation. 1250 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); 1251 1252 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(), 1253 codegen_->GetInstructionSetFeatures()); 1254 if (intrinsic.TryDispatch(invoke)) { 1255 return; 1256 } 1257 1258 HandleInvoke(invoke); 1259} 1260 1261void CodeGeneratorARM::LoadCurrentMethod(Register reg) { 1262 DCHECK(RequiresCurrentMethod()); 1263 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset); 1264} 1265 1266static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) { 1267 if (invoke->GetLocations()->Intrinsified()) { 1268 IntrinsicCodeGeneratorARM intrinsic(codegen); 1269 intrinsic.Dispatch(invoke); 1270 return true; 1271 } 1272 return false; 1273} 1274 1275void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { 1276 // When we do not run baseline, explicit clinit checks triggered by static 1277 // invokes must have been pruned by art::PrepareForRegisterAllocation. 1278 DCHECK(codegen_->IsBaseline() || !invoke->IsStaticWithExplicitClinitCheck()); 1279 1280 if (TryGenerateIntrinsicCode(invoke, codegen_)) { 1281 return; 1282 } 1283 1284 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>(); 1285 1286 codegen_->GenerateStaticOrDirectCall(invoke, temp); 1287 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1288} 1289 1290void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { 1291 LocationSummary* locations = 1292 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); 1293 locations->AddTemp(Location::RegisterLocation(R0)); 1294 1295 InvokeDexCallingConventionVisitorARM calling_convention_visitor; 1296 for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { 1297 HInstruction* input = invoke->InputAt(i); 1298 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 1299 } 1300 1301 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType())); 1302} 1303 1304void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1305 IntrinsicLocationsBuilderARM intrinsic(GetGraph()->GetArena(), 1306 codegen_->GetInstructionSetFeatures()); 1307 if (intrinsic.TryDispatch(invoke)) { 1308 return; 1309 } 1310 1311 HandleInvoke(invoke); 1312} 1313 1314void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1315 if (TryGenerateIntrinsicCode(invoke, codegen_)) { 1316 return; 1317 } 1318 1319 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>(); 1320 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() + 1321 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); 1322 LocationSummary* locations = invoke->GetLocations(); 1323 Location receiver = locations->InAt(0); 1324 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1325 // temp = object->GetClass(); 1326 if (receiver.IsStackSlot()) { 1327 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); 1328 __ LoadFromOffset(kLoadWord, temp, temp, class_offset); 1329 } else { 1330 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset); 1331 } 1332 codegen_->MaybeRecordImplicitNullCheck(invoke); 1333 // temp = temp->GetMethodAt(method_offset); 1334 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( 1335 kArmWordSize).Int32Value(); 1336 __ LoadFromOffset(kLoadWord, temp, temp, method_offset); 1337 // LR = temp->GetEntryPoint(); 1338 __ LoadFromOffset(kLoadWord, LR, temp, entry_point); 1339 // LR(); 1340 __ blx(LR); 1341 DCHECK(!codegen_->IsLeafMethod()); 1342 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1343} 1344 1345void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) { 1346 HandleInvoke(invoke); 1347 // Add the hidden argument. 1348 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12)); 1349} 1350 1351void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) { 1352 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. 1353 Register temp = invoke->GetLocations()->GetTemp(0).AsRegister<Register>(); 1354 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + 1355 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); 1356 LocationSummary* locations = invoke->GetLocations(); 1357 Location receiver = locations->InAt(0); 1358 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1359 1360 // Set the hidden argument. 1361 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).AsRegister<Register>(), 1362 invoke->GetDexMethodIndex()); 1363 1364 // temp = object->GetClass(); 1365 if (receiver.IsStackSlot()) { 1366 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); 1367 __ LoadFromOffset(kLoadWord, temp, temp, class_offset); 1368 } else { 1369 __ LoadFromOffset(kLoadWord, temp, receiver.AsRegister<Register>(), class_offset); 1370 } 1371 codegen_->MaybeRecordImplicitNullCheck(invoke); 1372 // temp = temp->GetImtEntryAt(method_offset); 1373 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( 1374 kArmWordSize).Int32Value(); 1375 __ LoadFromOffset(kLoadWord, temp, temp, method_offset); 1376 // LR = temp->GetEntryPoint(); 1377 __ LoadFromOffset(kLoadWord, LR, temp, entry_point); 1378 // LR(); 1379 __ blx(LR); 1380 DCHECK(!codegen_->IsLeafMethod()); 1381 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1382} 1383 1384void LocationsBuilderARM::VisitNeg(HNeg* neg) { 1385 LocationSummary* locations = 1386 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); 1387 switch (neg->GetResultType()) { 1388 case Primitive::kPrimInt: { 1389 locations->SetInAt(0, Location::RequiresRegister()); 1390 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1391 break; 1392 } 1393 case Primitive::kPrimLong: { 1394 locations->SetInAt(0, Location::RequiresRegister()); 1395 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 1396 break; 1397 } 1398 1399 case Primitive::kPrimFloat: 1400 case Primitive::kPrimDouble: 1401 locations->SetInAt(0, Location::RequiresFpuRegister()); 1402 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1403 break; 1404 1405 default: 1406 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1407 } 1408} 1409 1410void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) { 1411 LocationSummary* locations = neg->GetLocations(); 1412 Location out = locations->Out(); 1413 Location in = locations->InAt(0); 1414 switch (neg->GetResultType()) { 1415 case Primitive::kPrimInt: 1416 DCHECK(in.IsRegister()); 1417 __ rsb(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(0)); 1418 break; 1419 1420 case Primitive::kPrimLong: 1421 DCHECK(in.IsRegisterPair()); 1422 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag) 1423 __ rsbs(out.AsRegisterPairLow<Register>(), 1424 in.AsRegisterPairLow<Register>(), 1425 ShifterOperand(0)); 1426 // We cannot emit an RSC (Reverse Subtract with Carry) 1427 // instruction here, as it does not exist in the Thumb-2 1428 // instruction set. We use the following approach 1429 // using SBC and SUB instead. 1430 // 1431 // out.hi = -C 1432 __ sbc(out.AsRegisterPairHigh<Register>(), 1433 out.AsRegisterPairHigh<Register>(), 1434 ShifterOperand(out.AsRegisterPairHigh<Register>())); 1435 // out.hi = out.hi - in.hi 1436 __ sub(out.AsRegisterPairHigh<Register>(), 1437 out.AsRegisterPairHigh<Register>(), 1438 ShifterOperand(in.AsRegisterPairHigh<Register>())); 1439 break; 1440 1441 case Primitive::kPrimFloat: 1442 DCHECK(in.IsFpuRegister()); 1443 __ vnegs(out.AsFpuRegister<SRegister>(), in.AsFpuRegister<SRegister>()); 1444 break; 1445 1446 case Primitive::kPrimDouble: 1447 DCHECK(in.IsFpuRegisterPair()); 1448 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1449 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 1450 break; 1451 1452 default: 1453 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1454 } 1455} 1456 1457void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { 1458 Primitive::Type result_type = conversion->GetResultType(); 1459 Primitive::Type input_type = conversion->GetInputType(); 1460 DCHECK_NE(result_type, input_type); 1461 1462 // The float-to-long and double-to-long type conversions rely on a 1463 // call to the runtime. 1464 LocationSummary::CallKind call_kind = 1465 ((input_type == Primitive::kPrimFloat || input_type == Primitive::kPrimDouble) 1466 && result_type == Primitive::kPrimLong) 1467 ? LocationSummary::kCall 1468 : LocationSummary::kNoCall; 1469 LocationSummary* locations = 1470 new (GetGraph()->GetArena()) LocationSummary(conversion, call_kind); 1471 1472 // The Java language does not allow treating boolean as an integral type but 1473 // our bit representation makes it safe. 1474 1475 switch (result_type) { 1476 case Primitive::kPrimByte: 1477 switch (input_type) { 1478 case Primitive::kPrimBoolean: 1479 // Boolean input is a result of code transformations. 1480 case Primitive::kPrimShort: 1481 case Primitive::kPrimInt: 1482 case Primitive::kPrimChar: 1483 // Processing a Dex `int-to-byte' instruction. 1484 locations->SetInAt(0, Location::RequiresRegister()); 1485 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1486 break; 1487 1488 default: 1489 LOG(FATAL) << "Unexpected type conversion from " << input_type 1490 << " to " << result_type; 1491 } 1492 break; 1493 1494 case Primitive::kPrimShort: 1495 switch (input_type) { 1496 case Primitive::kPrimBoolean: 1497 // Boolean input is a result of code transformations. 1498 case Primitive::kPrimByte: 1499 case Primitive::kPrimInt: 1500 case Primitive::kPrimChar: 1501 // Processing a Dex `int-to-short' instruction. 1502 locations->SetInAt(0, Location::RequiresRegister()); 1503 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1504 break; 1505 1506 default: 1507 LOG(FATAL) << "Unexpected type conversion from " << input_type 1508 << " to " << result_type; 1509 } 1510 break; 1511 1512 case Primitive::kPrimInt: 1513 switch (input_type) { 1514 case Primitive::kPrimLong: 1515 // Processing a Dex `long-to-int' instruction. 1516 locations->SetInAt(0, Location::Any()); 1517 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1518 break; 1519 1520 case Primitive::kPrimFloat: 1521 // Processing a Dex `float-to-int' instruction. 1522 locations->SetInAt(0, Location::RequiresFpuRegister()); 1523 locations->SetOut(Location::RequiresRegister()); 1524 locations->AddTemp(Location::RequiresFpuRegister()); 1525 break; 1526 1527 case Primitive::kPrimDouble: 1528 // Processing a Dex `double-to-int' instruction. 1529 locations->SetInAt(0, Location::RequiresFpuRegister()); 1530 locations->SetOut(Location::RequiresRegister()); 1531 locations->AddTemp(Location::RequiresFpuRegister()); 1532 break; 1533 1534 default: 1535 LOG(FATAL) << "Unexpected type conversion from " << input_type 1536 << " to " << result_type; 1537 } 1538 break; 1539 1540 case Primitive::kPrimLong: 1541 switch (input_type) { 1542 case Primitive::kPrimBoolean: 1543 // Boolean input is a result of code transformations. 1544 case Primitive::kPrimByte: 1545 case Primitive::kPrimShort: 1546 case Primitive::kPrimInt: 1547 case Primitive::kPrimChar: 1548 // Processing a Dex `int-to-long' instruction. 1549 locations->SetInAt(0, Location::RequiresRegister()); 1550 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1551 break; 1552 1553 case Primitive::kPrimFloat: { 1554 // Processing a Dex `float-to-long' instruction. 1555 InvokeRuntimeCallingConvention calling_convention; 1556 locations->SetInAt(0, Location::FpuRegisterLocation( 1557 calling_convention.GetFpuRegisterAt(0))); 1558 locations->SetOut(Location::RegisterPairLocation(R0, R1)); 1559 break; 1560 } 1561 1562 case Primitive::kPrimDouble: { 1563 // Processing a Dex `double-to-long' instruction. 1564 InvokeRuntimeCallingConvention calling_convention; 1565 locations->SetInAt(0, Location::FpuRegisterPairLocation( 1566 calling_convention.GetFpuRegisterAt(0), 1567 calling_convention.GetFpuRegisterAt(1))); 1568 locations->SetOut(Location::RegisterPairLocation(R0, R1)); 1569 break; 1570 } 1571 1572 default: 1573 LOG(FATAL) << "Unexpected type conversion from " << input_type 1574 << " to " << result_type; 1575 } 1576 break; 1577 1578 case Primitive::kPrimChar: 1579 switch (input_type) { 1580 case Primitive::kPrimBoolean: 1581 // Boolean input is a result of code transformations. 1582 case Primitive::kPrimByte: 1583 case Primitive::kPrimShort: 1584 case Primitive::kPrimInt: 1585 // Processing a Dex `int-to-char' instruction. 1586 locations->SetInAt(0, Location::RequiresRegister()); 1587 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1588 break; 1589 1590 default: 1591 LOG(FATAL) << "Unexpected type conversion from " << input_type 1592 << " to " << result_type; 1593 } 1594 break; 1595 1596 case Primitive::kPrimFloat: 1597 switch (input_type) { 1598 case Primitive::kPrimBoolean: 1599 // Boolean input is a result of code transformations. 1600 case Primitive::kPrimByte: 1601 case Primitive::kPrimShort: 1602 case Primitive::kPrimInt: 1603 case Primitive::kPrimChar: 1604 // Processing a Dex `int-to-float' instruction. 1605 locations->SetInAt(0, Location::RequiresRegister()); 1606 locations->SetOut(Location::RequiresFpuRegister()); 1607 break; 1608 1609 case Primitive::kPrimLong: 1610 // Processing a Dex `long-to-float' instruction. 1611 locations->SetInAt(0, Location::RequiresRegister()); 1612 locations->SetOut(Location::RequiresFpuRegister()); 1613 locations->AddTemp(Location::RequiresRegister()); 1614 locations->AddTemp(Location::RequiresRegister()); 1615 locations->AddTemp(Location::RequiresFpuRegister()); 1616 locations->AddTemp(Location::RequiresFpuRegister()); 1617 break; 1618 1619 case Primitive::kPrimDouble: 1620 // Processing a Dex `double-to-float' instruction. 1621 locations->SetInAt(0, Location::RequiresFpuRegister()); 1622 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1623 break; 1624 1625 default: 1626 LOG(FATAL) << "Unexpected type conversion from " << input_type 1627 << " to " << result_type; 1628 }; 1629 break; 1630 1631 case Primitive::kPrimDouble: 1632 switch (input_type) { 1633 case Primitive::kPrimBoolean: 1634 // Boolean input is a result of code transformations. 1635 case Primitive::kPrimByte: 1636 case Primitive::kPrimShort: 1637 case Primitive::kPrimInt: 1638 case Primitive::kPrimChar: 1639 // Processing a Dex `int-to-double' instruction. 1640 locations->SetInAt(0, Location::RequiresRegister()); 1641 locations->SetOut(Location::RequiresFpuRegister()); 1642 break; 1643 1644 case Primitive::kPrimLong: 1645 // Processing a Dex `long-to-double' instruction. 1646 locations->SetInAt(0, Location::RequiresRegister()); 1647 locations->SetOut(Location::RequiresFpuRegister()); 1648 locations->AddTemp(Location::RequiresRegister()); 1649 locations->AddTemp(Location::RequiresRegister()); 1650 locations->AddTemp(Location::RequiresFpuRegister()); 1651 break; 1652 1653 case Primitive::kPrimFloat: 1654 // Processing a Dex `float-to-double' instruction. 1655 locations->SetInAt(0, Location::RequiresFpuRegister()); 1656 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1657 break; 1658 1659 default: 1660 LOG(FATAL) << "Unexpected type conversion from " << input_type 1661 << " to " << result_type; 1662 }; 1663 break; 1664 1665 default: 1666 LOG(FATAL) << "Unexpected type conversion from " << input_type 1667 << " to " << result_type; 1668 } 1669} 1670 1671void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) { 1672 LocationSummary* locations = conversion->GetLocations(); 1673 Location out = locations->Out(); 1674 Location in = locations->InAt(0); 1675 Primitive::Type result_type = conversion->GetResultType(); 1676 Primitive::Type input_type = conversion->GetInputType(); 1677 DCHECK_NE(result_type, input_type); 1678 switch (result_type) { 1679 case Primitive::kPrimByte: 1680 switch (input_type) { 1681 case Primitive::kPrimBoolean: 1682 // Boolean input is a result of code transformations. 1683 case Primitive::kPrimShort: 1684 case Primitive::kPrimInt: 1685 case Primitive::kPrimChar: 1686 // Processing a Dex `int-to-byte' instruction. 1687 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 8); 1688 break; 1689 1690 default: 1691 LOG(FATAL) << "Unexpected type conversion from " << input_type 1692 << " to " << result_type; 1693 } 1694 break; 1695 1696 case Primitive::kPrimShort: 1697 switch (input_type) { 1698 case Primitive::kPrimBoolean: 1699 // Boolean input is a result of code transformations. 1700 case Primitive::kPrimByte: 1701 case Primitive::kPrimInt: 1702 case Primitive::kPrimChar: 1703 // Processing a Dex `int-to-short' instruction. 1704 __ sbfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16); 1705 break; 1706 1707 default: 1708 LOG(FATAL) << "Unexpected type conversion from " << input_type 1709 << " to " << result_type; 1710 } 1711 break; 1712 1713 case Primitive::kPrimInt: 1714 switch (input_type) { 1715 case Primitive::kPrimLong: 1716 // Processing a Dex `long-to-int' instruction. 1717 DCHECK(out.IsRegister()); 1718 if (in.IsRegisterPair()) { 1719 __ Mov(out.AsRegister<Register>(), in.AsRegisterPairLow<Register>()); 1720 } else if (in.IsDoubleStackSlot()) { 1721 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), SP, in.GetStackIndex()); 1722 } else { 1723 DCHECK(in.IsConstant()); 1724 DCHECK(in.GetConstant()->IsLongConstant()); 1725 int64_t value = in.GetConstant()->AsLongConstant()->GetValue(); 1726 __ LoadImmediate(out.AsRegister<Register>(), static_cast<int32_t>(value)); 1727 } 1728 break; 1729 1730 case Primitive::kPrimFloat: { 1731 // Processing a Dex `float-to-int' instruction. 1732 SRegister temp = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>(); 1733 __ vmovs(temp, in.AsFpuRegister<SRegister>()); 1734 __ vcvtis(temp, temp); 1735 __ vmovrs(out.AsRegister<Register>(), temp); 1736 break; 1737 } 1738 1739 case Primitive::kPrimDouble: { 1740 // Processing a Dex `double-to-int' instruction. 1741 SRegister temp_s = locations->GetTemp(0).AsFpuRegisterPairLow<SRegister>(); 1742 DRegister temp_d = FromLowSToD(temp_s); 1743 __ vmovd(temp_d, FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 1744 __ vcvtid(temp_s, temp_d); 1745 __ vmovrs(out.AsRegister<Register>(), temp_s); 1746 break; 1747 } 1748 1749 default: 1750 LOG(FATAL) << "Unexpected type conversion from " << input_type 1751 << " to " << result_type; 1752 } 1753 break; 1754 1755 case Primitive::kPrimLong: 1756 switch (input_type) { 1757 case Primitive::kPrimBoolean: 1758 // Boolean input is a result of code transformations. 1759 case Primitive::kPrimByte: 1760 case Primitive::kPrimShort: 1761 case Primitive::kPrimInt: 1762 case Primitive::kPrimChar: 1763 // Processing a Dex `int-to-long' instruction. 1764 DCHECK(out.IsRegisterPair()); 1765 DCHECK(in.IsRegister()); 1766 __ Mov(out.AsRegisterPairLow<Register>(), in.AsRegister<Register>()); 1767 // Sign extension. 1768 __ Asr(out.AsRegisterPairHigh<Register>(), 1769 out.AsRegisterPairLow<Register>(), 1770 31); 1771 break; 1772 1773 case Primitive::kPrimFloat: 1774 // Processing a Dex `float-to-long' instruction. 1775 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pF2l), 1776 conversion, 1777 conversion->GetDexPc(), 1778 nullptr); 1779 break; 1780 1781 case Primitive::kPrimDouble: 1782 // Processing a Dex `double-to-long' instruction. 1783 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pD2l), 1784 conversion, 1785 conversion->GetDexPc(), 1786 nullptr); 1787 break; 1788 1789 default: 1790 LOG(FATAL) << "Unexpected type conversion from " << input_type 1791 << " to " << result_type; 1792 } 1793 break; 1794 1795 case Primitive::kPrimChar: 1796 switch (input_type) { 1797 case Primitive::kPrimBoolean: 1798 // Boolean input is a result of code transformations. 1799 case Primitive::kPrimByte: 1800 case Primitive::kPrimShort: 1801 case Primitive::kPrimInt: 1802 // Processing a Dex `int-to-char' instruction. 1803 __ ubfx(out.AsRegister<Register>(), in.AsRegister<Register>(), 0, 16); 1804 break; 1805 1806 default: 1807 LOG(FATAL) << "Unexpected type conversion from " << input_type 1808 << " to " << result_type; 1809 } 1810 break; 1811 1812 case Primitive::kPrimFloat: 1813 switch (input_type) { 1814 case Primitive::kPrimBoolean: 1815 // Boolean input is a result of code transformations. 1816 case Primitive::kPrimByte: 1817 case Primitive::kPrimShort: 1818 case Primitive::kPrimInt: 1819 case Primitive::kPrimChar: { 1820 // Processing a Dex `int-to-float' instruction. 1821 __ vmovsr(out.AsFpuRegister<SRegister>(), in.AsRegister<Register>()); 1822 __ vcvtsi(out.AsFpuRegister<SRegister>(), out.AsFpuRegister<SRegister>()); 1823 break; 1824 } 1825 1826 case Primitive::kPrimLong: { 1827 // Processing a Dex `long-to-float' instruction. 1828 Register low = in.AsRegisterPairLow<Register>(); 1829 Register high = in.AsRegisterPairHigh<Register>(); 1830 SRegister output = out.AsFpuRegister<SRegister>(); 1831 Register constant_low = locations->GetTemp(0).AsRegister<Register>(); 1832 Register constant_high = locations->GetTemp(1).AsRegister<Register>(); 1833 SRegister temp1_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>(); 1834 DRegister temp1_d = FromLowSToD(temp1_s); 1835 SRegister temp2_s = locations->GetTemp(3).AsFpuRegisterPairLow<SRegister>(); 1836 DRegister temp2_d = FromLowSToD(temp2_s); 1837 1838 // Operations use doubles for precision reasons (each 32-bit 1839 // half of a long fits in the 53-bit mantissa of a double, 1840 // but not in the 24-bit mantissa of a float). This is 1841 // especially important for the low bits. The result is 1842 // eventually converted to float. 1843 1844 // temp1_d = int-to-double(high) 1845 __ vmovsr(temp1_s, high); 1846 __ vcvtdi(temp1_d, temp1_s); 1847 // Using vmovd to load the `k2Pow32EncodingForDouble` constant 1848 // as an immediate value into `temp2_d` does not work, as 1849 // this instruction only transfers 8 significant bits of its 1850 // immediate operand. Instead, use two 32-bit core 1851 // registers to load `k2Pow32EncodingForDouble` into 1852 // `temp2_d`. 1853 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble)); 1854 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble)); 1855 __ vmovdrr(temp2_d, constant_low, constant_high); 1856 // temp1_d = temp1_d * 2^32 1857 __ vmuld(temp1_d, temp1_d, temp2_d); 1858 // temp2_d = unsigned-to-double(low) 1859 __ vmovsr(temp2_s, low); 1860 __ vcvtdu(temp2_d, temp2_s); 1861 // temp1_d = temp1_d + temp2_d 1862 __ vaddd(temp1_d, temp1_d, temp2_d); 1863 // output = double-to-float(temp1_d); 1864 __ vcvtsd(output, temp1_d); 1865 break; 1866 } 1867 1868 case Primitive::kPrimDouble: 1869 // Processing a Dex `double-to-float' instruction. 1870 __ vcvtsd(out.AsFpuRegister<SRegister>(), 1871 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 1872 break; 1873 1874 default: 1875 LOG(FATAL) << "Unexpected type conversion from " << input_type 1876 << " to " << result_type; 1877 }; 1878 break; 1879 1880 case Primitive::kPrimDouble: 1881 switch (input_type) { 1882 case Primitive::kPrimBoolean: 1883 // Boolean input is a result of code transformations. 1884 case Primitive::kPrimByte: 1885 case Primitive::kPrimShort: 1886 case Primitive::kPrimInt: 1887 case Primitive::kPrimChar: { 1888 // Processing a Dex `int-to-double' instruction. 1889 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.AsRegister<Register>()); 1890 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1891 out.AsFpuRegisterPairLow<SRegister>()); 1892 break; 1893 } 1894 1895 case Primitive::kPrimLong: { 1896 // Processing a Dex `long-to-double' instruction. 1897 Register low = in.AsRegisterPairLow<Register>(); 1898 Register high = in.AsRegisterPairHigh<Register>(); 1899 SRegister out_s = out.AsFpuRegisterPairLow<SRegister>(); 1900 DRegister out_d = FromLowSToD(out_s); 1901 Register constant_low = locations->GetTemp(0).AsRegister<Register>(); 1902 Register constant_high = locations->GetTemp(1).AsRegister<Register>(); 1903 SRegister temp_s = locations->GetTemp(2).AsFpuRegisterPairLow<SRegister>(); 1904 DRegister temp_d = FromLowSToD(temp_s); 1905 1906 // out_d = int-to-double(high) 1907 __ vmovsr(out_s, high); 1908 __ vcvtdi(out_d, out_s); 1909 // Using vmovd to load the `k2Pow32EncodingForDouble` constant 1910 // as an immediate value into `temp_d` does not work, as 1911 // this instruction only transfers 8 significant bits of its 1912 // immediate operand. Instead, use two 32-bit core 1913 // registers to load `k2Pow32EncodingForDouble` into `temp_d`. 1914 __ LoadImmediate(constant_low, Low32Bits(k2Pow32EncodingForDouble)); 1915 __ LoadImmediate(constant_high, High32Bits(k2Pow32EncodingForDouble)); 1916 __ vmovdrr(temp_d, constant_low, constant_high); 1917 // out_d = out_d * 2^32 1918 __ vmuld(out_d, out_d, temp_d); 1919 // temp_d = unsigned-to-double(low) 1920 __ vmovsr(temp_s, low); 1921 __ vcvtdu(temp_d, temp_s); 1922 // out_d = out_d + temp_d 1923 __ vaddd(out_d, out_d, temp_d); 1924 break; 1925 } 1926 1927 case Primitive::kPrimFloat: 1928 // Processing a Dex `float-to-double' instruction. 1929 __ vcvtds(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1930 in.AsFpuRegister<SRegister>()); 1931 break; 1932 1933 default: 1934 LOG(FATAL) << "Unexpected type conversion from " << input_type 1935 << " to " << result_type; 1936 }; 1937 break; 1938 1939 default: 1940 LOG(FATAL) << "Unexpected type conversion from " << input_type 1941 << " to " << result_type; 1942 } 1943} 1944 1945void LocationsBuilderARM::VisitAdd(HAdd* add) { 1946 LocationSummary* locations = 1947 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); 1948 switch (add->GetResultType()) { 1949 case Primitive::kPrimInt: { 1950 locations->SetInAt(0, Location::RequiresRegister()); 1951 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1))); 1952 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1953 break; 1954 } 1955 1956 case Primitive::kPrimLong: { 1957 locations->SetInAt(0, Location::RequiresRegister()); 1958 locations->SetInAt(1, Location::RequiresRegister()); 1959 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1960 break; 1961 } 1962 1963 case Primitive::kPrimFloat: 1964 case Primitive::kPrimDouble: { 1965 locations->SetInAt(0, Location::RequiresFpuRegister()); 1966 locations->SetInAt(1, Location::RequiresFpuRegister()); 1967 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1968 break; 1969 } 1970 1971 default: 1972 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1973 } 1974} 1975 1976void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 1977 LocationSummary* locations = add->GetLocations(); 1978 Location out = locations->Out(); 1979 Location first = locations->InAt(0); 1980 Location second = locations->InAt(1); 1981 switch (add->GetResultType()) { 1982 case Primitive::kPrimInt: 1983 if (second.IsRegister()) { 1984 __ add(out.AsRegister<Register>(), 1985 first.AsRegister<Register>(), 1986 ShifterOperand(second.AsRegister<Register>())); 1987 } else { 1988 __ AddConstant(out.AsRegister<Register>(), 1989 first.AsRegister<Register>(), 1990 second.GetConstant()->AsIntConstant()->GetValue()); 1991 } 1992 break; 1993 1994 case Primitive::kPrimLong: { 1995 DCHECK(second.IsRegisterPair()); 1996 __ adds(out.AsRegisterPairLow<Register>(), 1997 first.AsRegisterPairLow<Register>(), 1998 ShifterOperand(second.AsRegisterPairLow<Register>())); 1999 __ adc(out.AsRegisterPairHigh<Register>(), 2000 first.AsRegisterPairHigh<Register>(), 2001 ShifterOperand(second.AsRegisterPairHigh<Register>())); 2002 break; 2003 } 2004 2005 case Primitive::kPrimFloat: 2006 __ vadds(out.AsFpuRegister<SRegister>(), 2007 first.AsFpuRegister<SRegister>(), 2008 second.AsFpuRegister<SRegister>()); 2009 break; 2010 2011 case Primitive::kPrimDouble: 2012 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 2013 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 2014 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 2015 break; 2016 2017 default: 2018 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 2019 } 2020} 2021 2022void LocationsBuilderARM::VisitSub(HSub* sub) { 2023 LocationSummary* locations = 2024 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall); 2025 switch (sub->GetResultType()) { 2026 case Primitive::kPrimInt: { 2027 locations->SetInAt(0, Location::RequiresRegister()); 2028 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1))); 2029 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2030 break; 2031 } 2032 2033 case Primitive::kPrimLong: { 2034 locations->SetInAt(0, Location::RequiresRegister()); 2035 locations->SetInAt(1, Location::RequiresRegister()); 2036 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2037 break; 2038 } 2039 case Primitive::kPrimFloat: 2040 case Primitive::kPrimDouble: { 2041 locations->SetInAt(0, Location::RequiresFpuRegister()); 2042 locations->SetInAt(1, Location::RequiresFpuRegister()); 2043 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 2044 break; 2045 } 2046 default: 2047 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 2048 } 2049} 2050 2051void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { 2052 LocationSummary* locations = sub->GetLocations(); 2053 Location out = locations->Out(); 2054 Location first = locations->InAt(0); 2055 Location second = locations->InAt(1); 2056 switch (sub->GetResultType()) { 2057 case Primitive::kPrimInt: { 2058 if (second.IsRegister()) { 2059 __ sub(out.AsRegister<Register>(), 2060 first.AsRegister<Register>(), 2061 ShifterOperand(second.AsRegister<Register>())); 2062 } else { 2063 __ AddConstant(out.AsRegister<Register>(), 2064 first.AsRegister<Register>(), 2065 -second.GetConstant()->AsIntConstant()->GetValue()); 2066 } 2067 break; 2068 } 2069 2070 case Primitive::kPrimLong: { 2071 DCHECK(second.IsRegisterPair()); 2072 __ subs(out.AsRegisterPairLow<Register>(), 2073 first.AsRegisterPairLow<Register>(), 2074 ShifterOperand(second.AsRegisterPairLow<Register>())); 2075 __ sbc(out.AsRegisterPairHigh<Register>(), 2076 first.AsRegisterPairHigh<Register>(), 2077 ShifterOperand(second.AsRegisterPairHigh<Register>())); 2078 break; 2079 } 2080 2081 case Primitive::kPrimFloat: { 2082 __ vsubs(out.AsFpuRegister<SRegister>(), 2083 first.AsFpuRegister<SRegister>(), 2084 second.AsFpuRegister<SRegister>()); 2085 break; 2086 } 2087 2088 case Primitive::kPrimDouble: { 2089 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 2090 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 2091 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 2092 break; 2093 } 2094 2095 2096 default: 2097 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 2098 } 2099} 2100 2101void LocationsBuilderARM::VisitMul(HMul* mul) { 2102 LocationSummary* locations = 2103 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall); 2104 switch (mul->GetResultType()) { 2105 case Primitive::kPrimInt: 2106 case Primitive::kPrimLong: { 2107 locations->SetInAt(0, Location::RequiresRegister()); 2108 locations->SetInAt(1, Location::RequiresRegister()); 2109 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2110 break; 2111 } 2112 2113 case Primitive::kPrimFloat: 2114 case Primitive::kPrimDouble: { 2115 locations->SetInAt(0, Location::RequiresFpuRegister()); 2116 locations->SetInAt(1, Location::RequiresFpuRegister()); 2117 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 2118 break; 2119 } 2120 2121 default: 2122 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 2123 } 2124} 2125 2126void InstructionCodeGeneratorARM::VisitMul(HMul* mul) { 2127 LocationSummary* locations = mul->GetLocations(); 2128 Location out = locations->Out(); 2129 Location first = locations->InAt(0); 2130 Location second = locations->InAt(1); 2131 switch (mul->GetResultType()) { 2132 case Primitive::kPrimInt: { 2133 __ mul(out.AsRegister<Register>(), 2134 first.AsRegister<Register>(), 2135 second.AsRegister<Register>()); 2136 break; 2137 } 2138 case Primitive::kPrimLong: { 2139 Register out_hi = out.AsRegisterPairHigh<Register>(); 2140 Register out_lo = out.AsRegisterPairLow<Register>(); 2141 Register in1_hi = first.AsRegisterPairHigh<Register>(); 2142 Register in1_lo = first.AsRegisterPairLow<Register>(); 2143 Register in2_hi = second.AsRegisterPairHigh<Register>(); 2144 Register in2_lo = second.AsRegisterPairLow<Register>(); 2145 2146 // Extra checks to protect caused by the existence of R1_R2. 2147 // The algorithm is wrong if out.hi is either in1.lo or in2.lo: 2148 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2); 2149 DCHECK_NE(out_hi, in1_lo); 2150 DCHECK_NE(out_hi, in2_lo); 2151 2152 // input: in1 - 64 bits, in2 - 64 bits 2153 // output: out 2154 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo 2155 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32] 2156 // parts: out.lo = (in1.lo * in2.lo)[31:0] 2157 2158 // IP <- in1.lo * in2.hi 2159 __ mul(IP, in1_lo, in2_hi); 2160 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo 2161 __ mla(out_hi, in1_hi, in2_lo, IP); 2162 // out.lo <- (in1.lo * in2.lo)[31:0]; 2163 __ umull(out_lo, IP, in1_lo, in2_lo); 2164 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 2165 __ add(out_hi, out_hi, ShifterOperand(IP)); 2166 break; 2167 } 2168 2169 case Primitive::kPrimFloat: { 2170 __ vmuls(out.AsFpuRegister<SRegister>(), 2171 first.AsFpuRegister<SRegister>(), 2172 second.AsFpuRegister<SRegister>()); 2173 break; 2174 } 2175 2176 case Primitive::kPrimDouble: { 2177 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 2178 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 2179 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 2180 break; 2181 } 2182 2183 default: 2184 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 2185 } 2186} 2187 2188void LocationsBuilderARM::VisitDiv(HDiv* div) { 2189 LocationSummary::CallKind call_kind = LocationSummary::kNoCall; 2190 if (div->GetResultType() == Primitive::kPrimLong) { 2191 // pLdiv runtime call. 2192 call_kind = LocationSummary::kCall; 2193 } else if (div->GetResultType() == Primitive::kPrimInt && 2194 !codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { 2195 // pIdivmod runtime call. 2196 call_kind = LocationSummary::kCall; 2197 } 2198 2199 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind); 2200 2201 switch (div->GetResultType()) { 2202 case Primitive::kPrimInt: { 2203 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { 2204 locations->SetInAt(0, Location::RequiresRegister()); 2205 locations->SetInAt(1, Location::RequiresRegister()); 2206 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2207 } else { 2208 InvokeRuntimeCallingConvention calling_convention; 2209 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2210 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2211 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but 2212 // we only need the former. 2213 locations->SetOut(Location::RegisterLocation(R0)); 2214 } 2215 break; 2216 } 2217 case Primitive::kPrimLong: { 2218 InvokeRuntimeCallingConvention calling_convention; 2219 locations->SetInAt(0, Location::RegisterPairLocation( 2220 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 2221 locations->SetInAt(1, Location::RegisterPairLocation( 2222 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 2223 locations->SetOut(Location::RegisterPairLocation(R0, R1)); 2224 break; 2225 } 2226 case Primitive::kPrimFloat: 2227 case Primitive::kPrimDouble: { 2228 locations->SetInAt(0, Location::RequiresFpuRegister()); 2229 locations->SetInAt(1, Location::RequiresFpuRegister()); 2230 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 2231 break; 2232 } 2233 2234 default: 2235 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 2236 } 2237} 2238 2239void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) { 2240 LocationSummary* locations = div->GetLocations(); 2241 Location out = locations->Out(); 2242 Location first = locations->InAt(0); 2243 Location second = locations->InAt(1); 2244 2245 switch (div->GetResultType()) { 2246 case Primitive::kPrimInt: { 2247 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { 2248 __ sdiv(out.AsRegister<Register>(), 2249 first.AsRegister<Register>(), 2250 second.AsRegister<Register>()); 2251 } else { 2252 InvokeRuntimeCallingConvention calling_convention; 2253 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>()); 2254 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>()); 2255 DCHECK_EQ(R0, out.AsRegister<Register>()); 2256 2257 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), div, div->GetDexPc(), nullptr); 2258 } 2259 break; 2260 } 2261 2262 case Primitive::kPrimLong: { 2263 InvokeRuntimeCallingConvention calling_convention; 2264 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); 2265 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); 2266 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); 2267 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); 2268 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>()); 2269 DCHECK_EQ(R1, out.AsRegisterPairHigh<Register>()); 2270 2271 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc(), nullptr); 2272 break; 2273 } 2274 2275 case Primitive::kPrimFloat: { 2276 __ vdivs(out.AsFpuRegister<SRegister>(), 2277 first.AsFpuRegister<SRegister>(), 2278 second.AsFpuRegister<SRegister>()); 2279 break; 2280 } 2281 2282 case Primitive::kPrimDouble: { 2283 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 2284 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 2285 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 2286 break; 2287 } 2288 2289 default: 2290 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 2291 } 2292} 2293 2294void LocationsBuilderARM::VisitRem(HRem* rem) { 2295 Primitive::Type type = rem->GetResultType(); 2296 2297 // Most remainders are implemented in the runtime. 2298 LocationSummary::CallKind call_kind = LocationSummary::kCall; 2299 if (rem->GetResultType() == Primitive::kPrimInt && 2300 codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { 2301 // Have hardware divide instruction for int, do it with three instructions. 2302 call_kind = LocationSummary::kNoCall; 2303 } 2304 2305 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); 2306 2307 switch (type) { 2308 case Primitive::kPrimInt: { 2309 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { 2310 locations->SetInAt(0, Location::RequiresRegister()); 2311 locations->SetInAt(1, Location::RequiresRegister()); 2312 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2313 locations->AddTemp(Location::RequiresRegister()); 2314 } else { 2315 InvokeRuntimeCallingConvention calling_convention; 2316 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2317 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2318 // Note: divrem will compute both the quotient and the remainder as the pair R0 and R1, but 2319 // we only need the latter. 2320 locations->SetOut(Location::RegisterLocation(R1)); 2321 } 2322 break; 2323 } 2324 case Primitive::kPrimLong: { 2325 InvokeRuntimeCallingConvention calling_convention; 2326 locations->SetInAt(0, Location::RegisterPairLocation( 2327 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 2328 locations->SetInAt(1, Location::RegisterPairLocation( 2329 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 2330 // The runtime helper puts the output in R2,R3. 2331 locations->SetOut(Location::RegisterPairLocation(R2, R3)); 2332 break; 2333 } 2334 case Primitive::kPrimFloat: { 2335 InvokeRuntimeCallingConvention calling_convention; 2336 locations->SetInAt(0, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(0))); 2337 locations->SetInAt(1, Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(1))); 2338 locations->SetOut(Location::FpuRegisterLocation(S0)); 2339 break; 2340 } 2341 2342 case Primitive::kPrimDouble: { 2343 InvokeRuntimeCallingConvention calling_convention; 2344 locations->SetInAt(0, Location::FpuRegisterPairLocation( 2345 calling_convention.GetFpuRegisterAt(0), calling_convention.GetFpuRegisterAt(1))); 2346 locations->SetInAt(1, Location::FpuRegisterPairLocation( 2347 calling_convention.GetFpuRegisterAt(2), calling_convention.GetFpuRegisterAt(3))); 2348 locations->SetOut(Location::Location::FpuRegisterPairLocation(S0, S1)); 2349 break; 2350 } 2351 2352 default: 2353 LOG(FATAL) << "Unexpected rem type " << type; 2354 } 2355} 2356 2357void InstructionCodeGeneratorARM::VisitRem(HRem* rem) { 2358 LocationSummary* locations = rem->GetLocations(); 2359 Location out = locations->Out(); 2360 Location first = locations->InAt(0); 2361 Location second = locations->InAt(1); 2362 2363 Primitive::Type type = rem->GetResultType(); 2364 switch (type) { 2365 case Primitive::kPrimInt: { 2366 if (codegen_->GetInstructionSetFeatures().HasDivideInstruction()) { 2367 Register reg1 = first.AsRegister<Register>(); 2368 Register reg2 = second.AsRegister<Register>(); 2369 Register temp = locations->GetTemp(0).AsRegister<Register>(); 2370 2371 // temp = reg1 / reg2 (integer division) 2372 // temp = temp * reg2 2373 // dest = reg1 - temp 2374 __ sdiv(temp, reg1, reg2); 2375 __ mul(temp, temp, reg2); 2376 __ sub(out.AsRegister<Register>(), reg1, ShifterOperand(temp)); 2377 } else { 2378 InvokeRuntimeCallingConvention calling_convention; 2379 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegister<Register>()); 2380 DCHECK_EQ(calling_convention.GetRegisterAt(1), second.AsRegister<Register>()); 2381 DCHECK_EQ(R1, out.AsRegister<Register>()); 2382 2383 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pIdivmod), rem, rem->GetDexPc(), nullptr); 2384 } 2385 break; 2386 } 2387 2388 case Primitive::kPrimLong: { 2389 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc(), nullptr); 2390 break; 2391 } 2392 2393 case Primitive::kPrimFloat: { 2394 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmodf), rem, rem->GetDexPc(), nullptr); 2395 break; 2396 } 2397 2398 case Primitive::kPrimDouble: { 2399 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pFmod), rem, rem->GetDexPc(), nullptr); 2400 break; 2401 } 2402 2403 default: 2404 LOG(FATAL) << "Unexpected rem type " << type; 2405 } 2406} 2407 2408void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { 2409 LocationSummary* locations = 2410 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2411 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); 2412 if (instruction->HasUses()) { 2413 locations->SetOut(Location::SameAsFirstInput()); 2414 } 2415} 2416 2417void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { 2418 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction); 2419 codegen_->AddSlowPath(slow_path); 2420 2421 LocationSummary* locations = instruction->GetLocations(); 2422 Location value = locations->InAt(0); 2423 2424 switch (instruction->GetType()) { 2425 case Primitive::kPrimInt: { 2426 if (value.IsRegister()) { 2427 __ cmp(value.AsRegister<Register>(), ShifterOperand(0)); 2428 __ b(slow_path->GetEntryLabel(), EQ); 2429 } else { 2430 DCHECK(value.IsConstant()) << value; 2431 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) { 2432 __ b(slow_path->GetEntryLabel()); 2433 } 2434 } 2435 break; 2436 } 2437 case Primitive::kPrimLong: { 2438 if (value.IsRegisterPair()) { 2439 __ orrs(IP, 2440 value.AsRegisterPairLow<Register>(), 2441 ShifterOperand(value.AsRegisterPairHigh<Register>())); 2442 __ b(slow_path->GetEntryLabel(), EQ); 2443 } else { 2444 DCHECK(value.IsConstant()) << value; 2445 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) { 2446 __ b(slow_path->GetEntryLabel()); 2447 } 2448 } 2449 break; 2450 default: 2451 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType(); 2452 } 2453 } 2454} 2455 2456void LocationsBuilderARM::HandleShift(HBinaryOperation* op) { 2457 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); 2458 2459 LocationSummary* locations = 2460 new (GetGraph()->GetArena()) LocationSummary(op, LocationSummary::kNoCall); 2461 2462 switch (op->GetResultType()) { 2463 case Primitive::kPrimInt: { 2464 locations->SetInAt(0, Location::RequiresRegister()); 2465 locations->SetInAt(1, Location::RegisterOrConstant(op->InputAt(1))); 2466 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2467 break; 2468 } 2469 case Primitive::kPrimLong: { 2470 locations->SetInAt(0, Location::RequiresRegister()); 2471 locations->SetInAt(1, Location::RequiresRegister()); 2472 locations->AddTemp(Location::RequiresRegister()); 2473 locations->SetOut(Location::RequiresRegister()); 2474 break; 2475 } 2476 default: 2477 LOG(FATAL) << "Unexpected operation type " << op->GetResultType(); 2478 } 2479} 2480 2481void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) { 2482 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); 2483 2484 LocationSummary* locations = op->GetLocations(); 2485 Location out = locations->Out(); 2486 Location first = locations->InAt(0); 2487 Location second = locations->InAt(1); 2488 2489 Primitive::Type type = op->GetResultType(); 2490 switch (type) { 2491 case Primitive::kPrimInt: { 2492 Register out_reg = out.AsRegister<Register>(); 2493 Register first_reg = first.AsRegister<Register>(); 2494 // Arm doesn't mask the shift count so we need to do it ourselves. 2495 if (second.IsRegister()) { 2496 Register second_reg = second.AsRegister<Register>(); 2497 __ and_(second_reg, second_reg, ShifterOperand(kMaxIntShiftValue)); 2498 if (op->IsShl()) { 2499 __ Lsl(out_reg, first_reg, second_reg); 2500 } else if (op->IsShr()) { 2501 __ Asr(out_reg, first_reg, second_reg); 2502 } else { 2503 __ Lsr(out_reg, first_reg, second_reg); 2504 } 2505 } else { 2506 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue(); 2507 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue); 2508 if (shift_value == 0) { // arm does not support shifting with 0 immediate. 2509 __ Mov(out_reg, first_reg); 2510 } else if (op->IsShl()) { 2511 __ Lsl(out_reg, first_reg, shift_value); 2512 } else if (op->IsShr()) { 2513 __ Asr(out_reg, first_reg, shift_value); 2514 } else { 2515 __ Lsr(out_reg, first_reg, shift_value); 2516 } 2517 } 2518 break; 2519 } 2520 case Primitive::kPrimLong: { 2521 Register o_h = out.AsRegisterPairHigh<Register>(); 2522 Register o_l = out.AsRegisterPairLow<Register>(); 2523 2524 Register temp = locations->GetTemp(0).AsRegister<Register>(); 2525 2526 Register high = first.AsRegisterPairHigh<Register>(); 2527 Register low = first.AsRegisterPairLow<Register>(); 2528 2529 Register second_reg = second.AsRegister<Register>(); 2530 2531 if (op->IsShl()) { 2532 // Shift the high part 2533 __ and_(second_reg, second_reg, ShifterOperand(63)); 2534 __ Lsl(o_h, high, second_reg); 2535 // Shift the low part and `or` what overflew on the high part 2536 __ rsb(temp, second_reg, ShifterOperand(32)); 2537 __ Lsr(temp, low, temp); 2538 __ orr(o_h, o_h, ShifterOperand(temp)); 2539 // If the shift is > 32 bits, override the high part 2540 __ subs(temp, second_reg, ShifterOperand(32)); 2541 __ it(PL); 2542 __ Lsl(o_h, low, temp, false, PL); 2543 // Shift the low part 2544 __ Lsl(o_l, low, second_reg); 2545 } else if (op->IsShr()) { 2546 // Shift the low part 2547 __ and_(second_reg, second_reg, ShifterOperand(63)); 2548 __ Lsr(o_l, low, second_reg); 2549 // Shift the high part and `or` what underflew on the low part 2550 __ rsb(temp, second_reg, ShifterOperand(32)); 2551 __ Lsl(temp, high, temp); 2552 __ orr(o_l, o_l, ShifterOperand(temp)); 2553 // If the shift is > 32 bits, override the low part 2554 __ subs(temp, second_reg, ShifterOperand(32)); 2555 __ it(PL); 2556 __ Asr(o_l, high, temp, false, PL); 2557 // Shift the high part 2558 __ Asr(o_h, high, second_reg); 2559 } else { 2560 // same as Shr except we use `Lsr`s and not `Asr`s 2561 __ and_(second_reg, second_reg, ShifterOperand(63)); 2562 __ Lsr(o_l, low, second_reg); 2563 __ rsb(temp, second_reg, ShifterOperand(32)); 2564 __ Lsl(temp, high, temp); 2565 __ orr(o_l, o_l, ShifterOperand(temp)); 2566 __ subs(temp, second_reg, ShifterOperand(32)); 2567 __ it(PL); 2568 __ Lsr(o_l, high, temp, false, PL); 2569 __ Lsr(o_h, high, second_reg); 2570 } 2571 break; 2572 } 2573 default: 2574 LOG(FATAL) << "Unexpected operation type " << type; 2575 } 2576} 2577 2578void LocationsBuilderARM::VisitShl(HShl* shl) { 2579 HandleShift(shl); 2580} 2581 2582void InstructionCodeGeneratorARM::VisitShl(HShl* shl) { 2583 HandleShift(shl); 2584} 2585 2586void LocationsBuilderARM::VisitShr(HShr* shr) { 2587 HandleShift(shr); 2588} 2589 2590void InstructionCodeGeneratorARM::VisitShr(HShr* shr) { 2591 HandleShift(shr); 2592} 2593 2594void LocationsBuilderARM::VisitUShr(HUShr* ushr) { 2595 HandleShift(ushr); 2596} 2597 2598void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) { 2599 HandleShift(ushr); 2600} 2601 2602void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 2603 LocationSummary* locations = 2604 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2605 InvokeRuntimeCallingConvention calling_convention; 2606 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2607 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2608 locations->SetOut(Location::RegisterLocation(R0)); 2609} 2610 2611void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 2612 InvokeRuntimeCallingConvention calling_convention; 2613 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 2614 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 2615 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(), 2616 instruction, 2617 instruction->GetDexPc(), 2618 nullptr); 2619} 2620 2621void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) { 2622 LocationSummary* locations = 2623 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2624 InvokeRuntimeCallingConvention calling_convention; 2625 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2626 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 2627 locations->SetOut(Location::RegisterLocation(R0)); 2628 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2629} 2630 2631void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) { 2632 InvokeRuntimeCallingConvention calling_convention; 2633 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2)); 2634 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 2635 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(), 2636 instruction, 2637 instruction->GetDexPc(), 2638 nullptr); 2639} 2640 2641void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 2642 LocationSummary* locations = 2643 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2644 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 2645 if (location.IsStackSlot()) { 2646 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 2647 } else if (location.IsDoubleStackSlot()) { 2648 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 2649 } 2650 locations->SetOut(location); 2651} 2652 2653void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 2654 // Nothing to do, the parameter is already at its location. 2655 UNUSED(instruction); 2656} 2657 2658void LocationsBuilderARM::VisitNot(HNot* not_) { 2659 LocationSummary* locations = 2660 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall); 2661 locations->SetInAt(0, Location::RequiresRegister()); 2662 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2663} 2664 2665void InstructionCodeGeneratorARM::VisitNot(HNot* not_) { 2666 LocationSummary* locations = not_->GetLocations(); 2667 Location out = locations->Out(); 2668 Location in = locations->InAt(0); 2669 switch (not_->GetResultType()) { 2670 case Primitive::kPrimInt: 2671 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>())); 2672 break; 2673 2674 case Primitive::kPrimLong: 2675 __ mvn(out.AsRegisterPairLow<Register>(), 2676 ShifterOperand(in.AsRegisterPairLow<Register>())); 2677 __ mvn(out.AsRegisterPairHigh<Register>(), 2678 ShifterOperand(in.AsRegisterPairHigh<Register>())); 2679 break; 2680 2681 default: 2682 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType(); 2683 } 2684} 2685 2686void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) { 2687 LocationSummary* locations = 2688 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall); 2689 locations->SetInAt(0, Location::RequiresRegister()); 2690 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2691} 2692 2693void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) { 2694 LocationSummary* locations = bool_not->GetLocations(); 2695 Location out = locations->Out(); 2696 Location in = locations->InAt(0); 2697 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1)); 2698} 2699 2700void LocationsBuilderARM::VisitCompare(HCompare* compare) { 2701 LocationSummary* locations = 2702 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 2703 switch (compare->InputAt(0)->GetType()) { 2704 case Primitive::kPrimLong: { 2705 locations->SetInAt(0, Location::RequiresRegister()); 2706 locations->SetInAt(1, Location::RequiresRegister()); 2707 // Output overlaps because it is written before doing the low comparison. 2708 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 2709 break; 2710 } 2711 case Primitive::kPrimFloat: 2712 case Primitive::kPrimDouble: { 2713 locations->SetInAt(0, Location::RequiresFpuRegister()); 2714 locations->SetInAt(1, Location::RequiresFpuRegister()); 2715 locations->SetOut(Location::RequiresRegister()); 2716 break; 2717 } 2718 default: 2719 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType(); 2720 } 2721} 2722 2723void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { 2724 LocationSummary* locations = compare->GetLocations(); 2725 Register out = locations->Out().AsRegister<Register>(); 2726 Location left = locations->InAt(0); 2727 Location right = locations->InAt(1); 2728 2729 Label less, greater, done; 2730 Primitive::Type type = compare->InputAt(0)->GetType(); 2731 switch (type) { 2732 case Primitive::kPrimLong: { 2733 __ cmp(left.AsRegisterPairHigh<Register>(), 2734 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare. 2735 __ b(&less, LT); 2736 __ b(&greater, GT); 2737 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags. 2738 __ LoadImmediate(out, 0); 2739 __ cmp(left.AsRegisterPairLow<Register>(), 2740 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare. 2741 break; 2742 } 2743 case Primitive::kPrimFloat: 2744 case Primitive::kPrimDouble: { 2745 __ LoadImmediate(out, 0); 2746 if (type == Primitive::kPrimFloat) { 2747 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>()); 2748 } else { 2749 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()), 2750 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>())); 2751 } 2752 __ vmstat(); // transfer FP status register to ARM APSR. 2753 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered. 2754 break; 2755 } 2756 default: 2757 LOG(FATAL) << "Unexpected compare type " << type; 2758 } 2759 __ b(&done, EQ); 2760 __ b(&less, CC); // CC is for both: unsigned compare for longs and 'less than' for floats. 2761 2762 __ Bind(&greater); 2763 __ LoadImmediate(out, 1); 2764 __ b(&done); 2765 2766 __ Bind(&less); 2767 __ LoadImmediate(out, -1); 2768 2769 __ Bind(&done); 2770} 2771 2772void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 2773 LocationSummary* locations = 2774 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2775 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 2776 locations->SetInAt(i, Location::Any()); 2777 } 2778 locations->SetOut(Location::Any()); 2779} 2780 2781void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 2782 UNUSED(instruction); 2783 LOG(FATAL) << "Unreachable"; 2784} 2785 2786void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) { 2787 // TODO (ported from quick): revisit Arm barrier kinds 2788 DmbOptions flavour = DmbOptions::ISH; // quiet c++ warnings 2789 switch (kind) { 2790 case MemBarrierKind::kAnyStore: 2791 case MemBarrierKind::kLoadAny: 2792 case MemBarrierKind::kAnyAny: { 2793 flavour = DmbOptions::ISH; 2794 break; 2795 } 2796 case MemBarrierKind::kStoreStore: { 2797 flavour = DmbOptions::ISHST; 2798 break; 2799 } 2800 default: 2801 LOG(FATAL) << "Unexpected memory barrier " << kind; 2802 } 2803 __ dmb(flavour); 2804} 2805 2806void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr, 2807 uint32_t offset, 2808 Register out_lo, 2809 Register out_hi) { 2810 if (offset != 0) { 2811 __ LoadImmediate(out_lo, offset); 2812 __ add(IP, addr, ShifterOperand(out_lo)); 2813 addr = IP; 2814 } 2815 __ ldrexd(out_lo, out_hi, addr); 2816} 2817 2818void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr, 2819 uint32_t offset, 2820 Register value_lo, 2821 Register value_hi, 2822 Register temp1, 2823 Register temp2, 2824 HInstruction* instruction) { 2825 Label fail; 2826 if (offset != 0) { 2827 __ LoadImmediate(temp1, offset); 2828 __ add(IP, addr, ShifterOperand(temp1)); 2829 addr = IP; 2830 } 2831 __ Bind(&fail); 2832 // We need a load followed by store. (The address used in a STREX instruction must 2833 // be the same as the address in the most recently executed LDREX instruction.) 2834 __ ldrexd(temp1, temp2, addr); 2835 codegen_->MaybeRecordImplicitNullCheck(instruction); 2836 __ strexd(temp1, value_lo, value_hi, addr); 2837 __ cmp(temp1, ShifterOperand(0)); 2838 __ b(&fail, NE); 2839} 2840 2841void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) { 2842 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet()); 2843 2844 LocationSummary* locations = 2845 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2846 locations->SetInAt(0, Location::RequiresRegister()); 2847 2848 Primitive::Type field_type = field_info.GetFieldType(); 2849 if (Primitive::IsFloatingPointType(field_type)) { 2850 locations->SetInAt(1, Location::RequiresFpuRegister()); 2851 } else { 2852 locations->SetInAt(1, Location::RequiresRegister()); 2853 } 2854 2855 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble; 2856 bool generate_volatile = field_info.IsVolatile() 2857 && is_wide 2858 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); 2859 // Temporary registers for the write barrier. 2860 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark. 2861 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { 2862 locations->AddTemp(Location::RequiresRegister()); 2863 locations->AddTemp(Location::RequiresRegister()); 2864 } else if (generate_volatile) { 2865 // Arm encoding have some additional constraints for ldrexd/strexd: 2866 // - registers need to be consecutive 2867 // - the first register should be even but not R14. 2868 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever 2869 // enable Arm encoding. 2870 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet()); 2871 2872 locations->AddTemp(Location::RequiresRegister()); 2873 locations->AddTemp(Location::RequiresRegister()); 2874 if (field_type == Primitive::kPrimDouble) { 2875 // For doubles we need two more registers to copy the value. 2876 locations->AddTemp(Location::RegisterLocation(R2)); 2877 locations->AddTemp(Location::RegisterLocation(R3)); 2878 } 2879 } 2880} 2881 2882void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction, 2883 const FieldInfo& field_info) { 2884 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet()); 2885 2886 LocationSummary* locations = instruction->GetLocations(); 2887 Register base = locations->InAt(0).AsRegister<Register>(); 2888 Location value = locations->InAt(1); 2889 2890 bool is_volatile = field_info.IsVolatile(); 2891 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); 2892 Primitive::Type field_type = field_info.GetFieldType(); 2893 uint32_t offset = field_info.GetFieldOffset().Uint32Value(); 2894 2895 if (is_volatile) { 2896 GenerateMemoryBarrier(MemBarrierKind::kAnyStore); 2897 } 2898 2899 switch (field_type) { 2900 case Primitive::kPrimBoolean: 2901 case Primitive::kPrimByte: { 2902 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset); 2903 break; 2904 } 2905 2906 case Primitive::kPrimShort: 2907 case Primitive::kPrimChar: { 2908 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset); 2909 break; 2910 } 2911 2912 case Primitive::kPrimInt: 2913 case Primitive::kPrimNot: { 2914 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset); 2915 break; 2916 } 2917 2918 case Primitive::kPrimLong: { 2919 if (is_volatile && !atomic_ldrd_strd) { 2920 GenerateWideAtomicStore(base, offset, 2921 value.AsRegisterPairLow<Register>(), 2922 value.AsRegisterPairHigh<Register>(), 2923 locations->GetTemp(0).AsRegister<Register>(), 2924 locations->GetTemp(1).AsRegister<Register>(), 2925 instruction); 2926 } else { 2927 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset); 2928 codegen_->MaybeRecordImplicitNullCheck(instruction); 2929 } 2930 break; 2931 } 2932 2933 case Primitive::kPrimFloat: { 2934 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset); 2935 break; 2936 } 2937 2938 case Primitive::kPrimDouble: { 2939 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()); 2940 if (is_volatile && !atomic_ldrd_strd) { 2941 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>(); 2942 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>(); 2943 2944 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg); 2945 2946 GenerateWideAtomicStore(base, offset, 2947 value_reg_lo, 2948 value_reg_hi, 2949 locations->GetTemp(2).AsRegister<Register>(), 2950 locations->GetTemp(3).AsRegister<Register>(), 2951 instruction); 2952 } else { 2953 __ StoreDToOffset(value_reg, base, offset); 2954 codegen_->MaybeRecordImplicitNullCheck(instruction); 2955 } 2956 break; 2957 } 2958 2959 case Primitive::kPrimVoid: 2960 LOG(FATAL) << "Unreachable type " << field_type; 2961 UNREACHABLE(); 2962 } 2963 2964 // Longs and doubles are handled in the switch. 2965 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) { 2966 codegen_->MaybeRecordImplicitNullCheck(instruction); 2967 } 2968 2969 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { 2970 Register temp = locations->GetTemp(0).AsRegister<Register>(); 2971 Register card = locations->GetTemp(1).AsRegister<Register>(); 2972 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>()); 2973 } 2974 2975 if (is_volatile) { 2976 GenerateMemoryBarrier(MemBarrierKind::kAnyAny); 2977 } 2978} 2979 2980void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) { 2981 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); 2982 LocationSummary* locations = 2983 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2984 locations->SetInAt(0, Location::RequiresRegister()); 2985 2986 bool volatile_for_double = field_info.IsVolatile() 2987 && (field_info.GetFieldType() == Primitive::kPrimDouble) 2988 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); 2989 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong); 2990 2991 if (Primitive::IsFloatingPointType(instruction->GetType())) { 2992 locations->SetOut(Location::RequiresFpuRegister()); 2993 } else { 2994 locations->SetOut(Location::RequiresRegister(), 2995 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap)); 2996 } 2997 if (volatile_for_double) { 2998 // Arm encoding have some additional constraints for ldrexd/strexd: 2999 // - registers need to be consecutive 3000 // - the first register should be even but not R14. 3001 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever 3002 // enable Arm encoding. 3003 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet()); 3004 locations->AddTemp(Location::RequiresRegister()); 3005 locations->AddTemp(Location::RequiresRegister()); 3006 } 3007} 3008 3009void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction, 3010 const FieldInfo& field_info) { 3011 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); 3012 3013 LocationSummary* locations = instruction->GetLocations(); 3014 Register base = locations->InAt(0).AsRegister<Register>(); 3015 Location out = locations->Out(); 3016 bool is_volatile = field_info.IsVolatile(); 3017 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); 3018 Primitive::Type field_type = field_info.GetFieldType(); 3019 uint32_t offset = field_info.GetFieldOffset().Uint32Value(); 3020 3021 switch (field_type) { 3022 case Primitive::kPrimBoolean: { 3023 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset); 3024 break; 3025 } 3026 3027 case Primitive::kPrimByte: { 3028 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset); 3029 break; 3030 } 3031 3032 case Primitive::kPrimShort: { 3033 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset); 3034 break; 3035 } 3036 3037 case Primitive::kPrimChar: { 3038 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset); 3039 break; 3040 } 3041 3042 case Primitive::kPrimInt: 3043 case Primitive::kPrimNot: { 3044 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset); 3045 break; 3046 } 3047 3048 case Primitive::kPrimLong: { 3049 if (is_volatile && !atomic_ldrd_strd) { 3050 GenerateWideAtomicLoad(base, offset, 3051 out.AsRegisterPairLow<Register>(), 3052 out.AsRegisterPairHigh<Register>()); 3053 } else { 3054 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset); 3055 } 3056 break; 3057 } 3058 3059 case Primitive::kPrimFloat: { 3060 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset); 3061 break; 3062 } 3063 3064 case Primitive::kPrimDouble: { 3065 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()); 3066 if (is_volatile && !atomic_ldrd_strd) { 3067 Register lo = locations->GetTemp(0).AsRegister<Register>(); 3068 Register hi = locations->GetTemp(1).AsRegister<Register>(); 3069 GenerateWideAtomicLoad(base, offset, lo, hi); 3070 codegen_->MaybeRecordImplicitNullCheck(instruction); 3071 __ vmovdrr(out_reg, lo, hi); 3072 } else { 3073 __ LoadDFromOffset(out_reg, base, offset); 3074 codegen_->MaybeRecordImplicitNullCheck(instruction); 3075 } 3076 break; 3077 } 3078 3079 case Primitive::kPrimVoid: 3080 LOG(FATAL) << "Unreachable type " << field_type; 3081 UNREACHABLE(); 3082 } 3083 3084 // Doubles are handled in the switch. 3085 if (field_type != Primitive::kPrimDouble) { 3086 codegen_->MaybeRecordImplicitNullCheck(instruction); 3087 } 3088 3089 if (is_volatile) { 3090 GenerateMemoryBarrier(MemBarrierKind::kLoadAny); 3091 } 3092} 3093 3094void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 3095 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3096} 3097 3098void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 3099 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3100} 3101 3102void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 3103 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3104} 3105 3106void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 3107 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3108} 3109 3110void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) { 3111 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3112} 3113 3114void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) { 3115 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3116} 3117 3118void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { 3119 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3120} 3121 3122void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { 3123 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3124} 3125 3126void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { 3127 LocationSummary* locations = 3128 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3129 locations->SetInAt(0, Location::RequiresRegister()); 3130 if (instruction->HasUses()) { 3131 locations->SetOut(Location::SameAsFirstInput()); 3132 } 3133} 3134 3135void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) { 3136 if (codegen_->CanMoveNullCheckToUser(instruction)) { 3137 return; 3138 } 3139 Location obj = instruction->GetLocations()->InAt(0); 3140 3141 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0); 3142 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 3143} 3144 3145void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) { 3146 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); 3147 codegen_->AddSlowPath(slow_path); 3148 3149 LocationSummary* locations = instruction->GetLocations(); 3150 Location obj = locations->InAt(0); 3151 3152 __ cmp(obj.AsRegister<Register>(), ShifterOperand(0)); 3153 __ b(slow_path->GetEntryLabel(), EQ); 3154} 3155 3156void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { 3157 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) { 3158 GenerateImplicitNullCheck(instruction); 3159 } else { 3160 GenerateExplicitNullCheck(instruction); 3161 } 3162} 3163 3164void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { 3165 LocationSummary* locations = 3166 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3167 locations->SetInAt(0, Location::RequiresRegister()); 3168 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 3169 if (Primitive::IsFloatingPointType(instruction->GetType())) { 3170 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 3171 } else { 3172 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3173 } 3174} 3175 3176void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { 3177 LocationSummary* locations = instruction->GetLocations(); 3178 Register obj = locations->InAt(0).AsRegister<Register>(); 3179 Location index = locations->InAt(1); 3180 3181 switch (instruction->GetType()) { 3182 case Primitive::kPrimBoolean: { 3183 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 3184 Register out = locations->Out().AsRegister<Register>(); 3185 if (index.IsConstant()) { 3186 size_t offset = 3187 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 3188 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 3189 } else { 3190 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>())); 3191 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset); 3192 } 3193 break; 3194 } 3195 3196 case Primitive::kPrimByte: { 3197 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 3198 Register out = locations->Out().AsRegister<Register>(); 3199 if (index.IsConstant()) { 3200 size_t offset = 3201 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 3202 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 3203 } else { 3204 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>())); 3205 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset); 3206 } 3207 break; 3208 } 3209 3210 case Primitive::kPrimShort: { 3211 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 3212 Register out = locations->Out().AsRegister<Register>(); 3213 if (index.IsConstant()) { 3214 size_t offset = 3215 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 3216 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 3217 } else { 3218 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2)); 3219 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset); 3220 } 3221 break; 3222 } 3223 3224 case Primitive::kPrimChar: { 3225 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 3226 Register out = locations->Out().AsRegister<Register>(); 3227 if (index.IsConstant()) { 3228 size_t offset = 3229 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 3230 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 3231 } else { 3232 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2)); 3233 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset); 3234 } 3235 break; 3236 } 3237 3238 case Primitive::kPrimInt: 3239 case Primitive::kPrimNot: { 3240 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t)); 3241 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 3242 Register out = locations->Out().AsRegister<Register>(); 3243 if (index.IsConstant()) { 3244 size_t offset = 3245 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3246 __ LoadFromOffset(kLoadWord, out, obj, offset); 3247 } else { 3248 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); 3249 __ LoadFromOffset(kLoadWord, out, IP, data_offset); 3250 } 3251 break; 3252 } 3253 3254 case Primitive::kPrimLong: { 3255 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 3256 Location out = locations->Out(); 3257 if (index.IsConstant()) { 3258 size_t offset = 3259 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3260 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset); 3261 } else { 3262 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); 3263 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset); 3264 } 3265 break; 3266 } 3267 3268 case Primitive::kPrimFloat: { 3269 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); 3270 Location out = locations->Out(); 3271 DCHECK(out.IsFpuRegister()); 3272 if (index.IsConstant()) { 3273 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3274 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset); 3275 } else { 3276 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); 3277 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset); 3278 } 3279 break; 3280 } 3281 3282 case Primitive::kPrimDouble: { 3283 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); 3284 Location out = locations->Out(); 3285 DCHECK(out.IsFpuRegisterPair()); 3286 if (index.IsConstant()) { 3287 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3288 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset); 3289 } else { 3290 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); 3291 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset); 3292 } 3293 break; 3294 } 3295 3296 case Primitive::kPrimVoid: 3297 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 3298 UNREACHABLE(); 3299 } 3300 codegen_->MaybeRecordImplicitNullCheck(instruction); 3301} 3302 3303void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) { 3304 Primitive::Type value_type = instruction->GetComponentType(); 3305 3306 bool needs_write_barrier = 3307 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 3308 bool needs_runtime_call = instruction->NeedsTypeCheck(); 3309 3310 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 3311 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall); 3312 if (needs_runtime_call) { 3313 InvokeRuntimeCallingConvention calling_convention; 3314 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3315 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 3316 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 3317 } else { 3318 locations->SetInAt(0, Location::RequiresRegister()); 3319 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 3320 if (Primitive::IsFloatingPointType(value_type)) { 3321 locations->SetInAt(2, Location::RequiresFpuRegister()); 3322 } else { 3323 locations->SetInAt(2, Location::RequiresRegister()); 3324 } 3325 3326 if (needs_write_barrier) { 3327 // Temporary registers for the write barrier. 3328 locations->AddTemp(Location::RequiresRegister()); 3329 locations->AddTemp(Location::RequiresRegister()); 3330 } 3331 } 3332} 3333 3334void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { 3335 LocationSummary* locations = instruction->GetLocations(); 3336 Register obj = locations->InAt(0).AsRegister<Register>(); 3337 Location index = locations->InAt(1); 3338 Primitive::Type value_type = instruction->GetComponentType(); 3339 bool needs_runtime_call = locations->WillCall(); 3340 bool needs_write_barrier = 3341 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 3342 3343 switch (value_type) { 3344 case Primitive::kPrimBoolean: 3345 case Primitive::kPrimByte: { 3346 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 3347 Register value = locations->InAt(2).AsRegister<Register>(); 3348 if (index.IsConstant()) { 3349 size_t offset = 3350 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 3351 __ StoreToOffset(kStoreByte, value, obj, offset); 3352 } else { 3353 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>())); 3354 __ StoreToOffset(kStoreByte, value, IP, data_offset); 3355 } 3356 break; 3357 } 3358 3359 case Primitive::kPrimShort: 3360 case Primitive::kPrimChar: { 3361 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 3362 Register value = locations->InAt(2).AsRegister<Register>(); 3363 if (index.IsConstant()) { 3364 size_t offset = 3365 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 3366 __ StoreToOffset(kStoreHalfword, value, obj, offset); 3367 } else { 3368 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2)); 3369 __ StoreToOffset(kStoreHalfword, value, IP, data_offset); 3370 } 3371 break; 3372 } 3373 3374 case Primitive::kPrimInt: 3375 case Primitive::kPrimNot: { 3376 if (!needs_runtime_call) { 3377 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 3378 Register value = locations->InAt(2).AsRegister<Register>(); 3379 if (index.IsConstant()) { 3380 size_t offset = 3381 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3382 __ StoreToOffset(kStoreWord, value, obj, offset); 3383 } else { 3384 DCHECK(index.IsRegister()) << index; 3385 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); 3386 __ StoreToOffset(kStoreWord, value, IP, data_offset); 3387 } 3388 codegen_->MaybeRecordImplicitNullCheck(instruction); 3389 if (needs_write_barrier) { 3390 DCHECK_EQ(value_type, Primitive::kPrimNot); 3391 Register temp = locations->GetTemp(0).AsRegister<Register>(); 3392 Register card = locations->GetTemp(1).AsRegister<Register>(); 3393 codegen_->MarkGCCard(temp, card, obj, value); 3394 } 3395 } else { 3396 DCHECK_EQ(value_type, Primitive::kPrimNot); 3397 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), 3398 instruction, 3399 instruction->GetDexPc(), 3400 nullptr); 3401 } 3402 break; 3403 } 3404 3405 case Primitive::kPrimLong: { 3406 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 3407 Location value = locations->InAt(2); 3408 if (index.IsConstant()) { 3409 size_t offset = 3410 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3411 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset); 3412 } else { 3413 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); 3414 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset); 3415 } 3416 break; 3417 } 3418 3419 case Primitive::kPrimFloat: { 3420 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); 3421 Location value = locations->InAt(2); 3422 DCHECK(value.IsFpuRegister()); 3423 if (index.IsConstant()) { 3424 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3425 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset); 3426 } else { 3427 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); 3428 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset); 3429 } 3430 break; 3431 } 3432 3433 case Primitive::kPrimDouble: { 3434 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); 3435 Location value = locations->InAt(2); 3436 DCHECK(value.IsFpuRegisterPair()); 3437 if (index.IsConstant()) { 3438 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3439 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset); 3440 } else { 3441 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); 3442 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset); 3443 } 3444 3445 break; 3446 } 3447 3448 case Primitive::kPrimVoid: 3449 LOG(FATAL) << "Unreachable type " << value_type; 3450 UNREACHABLE(); 3451 } 3452 3453 // Ints and objects are handled in the switch. 3454 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) { 3455 codegen_->MaybeRecordImplicitNullCheck(instruction); 3456 } 3457} 3458 3459void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) { 3460 LocationSummary* locations = 3461 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3462 locations->SetInAt(0, Location::RequiresRegister()); 3463 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3464} 3465 3466void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) { 3467 LocationSummary* locations = instruction->GetLocations(); 3468 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 3469 Register obj = locations->InAt(0).AsRegister<Register>(); 3470 Register out = locations->Out().AsRegister<Register>(); 3471 __ LoadFromOffset(kLoadWord, out, obj, offset); 3472 codegen_->MaybeRecordImplicitNullCheck(instruction); 3473} 3474 3475void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { 3476 LocationSummary* locations = 3477 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3478 locations->SetInAt(0, Location::RequiresRegister()); 3479 locations->SetInAt(1, Location::RequiresRegister()); 3480 if (instruction->HasUses()) { 3481 locations->SetOut(Location::SameAsFirstInput()); 3482 } 3483} 3484 3485void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { 3486 LocationSummary* locations = instruction->GetLocations(); 3487 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM( 3488 instruction, locations->InAt(0), locations->InAt(1)); 3489 codegen_->AddSlowPath(slow_path); 3490 3491 Register index = locations->InAt(0).AsRegister<Register>(); 3492 Register length = locations->InAt(1).AsRegister<Register>(); 3493 3494 __ cmp(index, ShifterOperand(length)); 3495 __ b(slow_path->GetEntryLabel(), CS); 3496} 3497 3498void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) { 3499 Label is_null; 3500 __ CompareAndBranchIfZero(value, &is_null); 3501 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value()); 3502 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift); 3503 __ strb(card, Address(card, temp)); 3504 __ Bind(&is_null); 3505} 3506 3507void LocationsBuilderARM::VisitTemporary(HTemporary* temp) { 3508 temp->SetLocations(nullptr); 3509} 3510 3511void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) { 3512 // Nothing to do, this is driven by the code generator. 3513 UNUSED(temp); 3514} 3515 3516void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) { 3517 UNUSED(instruction); 3518 LOG(FATAL) << "Unreachable"; 3519} 3520 3521void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) { 3522 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 3523} 3524 3525void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) { 3526 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 3527} 3528 3529void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) { 3530 HBasicBlock* block = instruction->GetBlock(); 3531 if (block->GetLoopInformation() != nullptr) { 3532 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 3533 // The back edge will generate the suspend check. 3534 return; 3535 } 3536 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 3537 // The goto will generate the suspend check. 3538 return; 3539 } 3540 GenerateSuspendCheck(instruction, nullptr); 3541} 3542 3543void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction, 3544 HBasicBlock* successor) { 3545 SuspendCheckSlowPathARM* slow_path = 3546 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath()); 3547 if (slow_path == nullptr) { 3548 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor); 3549 instruction->SetSlowPath(slow_path); 3550 codegen_->AddSlowPath(slow_path); 3551 if (successor != nullptr) { 3552 DCHECK(successor->IsLoopHeader()); 3553 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction); 3554 } 3555 } else { 3556 DCHECK_EQ(slow_path->GetSuccessor(), successor); 3557 } 3558 3559 __ LoadFromOffset( 3560 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value()); 3561 __ cmp(IP, ShifterOperand(0)); 3562 // TODO: Figure out the branch offsets and use cbz/cbnz. 3563 if (successor == nullptr) { 3564 __ b(slow_path->GetEntryLabel(), NE); 3565 __ Bind(slow_path->GetReturnLabel()); 3566 } else { 3567 __ b(codegen_->GetLabelOf(successor), EQ); 3568 __ b(slow_path->GetEntryLabel()); 3569 } 3570} 3571 3572ArmAssembler* ParallelMoveResolverARM::GetAssembler() const { 3573 return codegen_->GetAssembler(); 3574} 3575 3576void ParallelMoveResolverARM::EmitMove(size_t index) { 3577 MoveOperands* move = moves_.Get(index); 3578 Location source = move->GetSource(); 3579 Location destination = move->GetDestination(); 3580 3581 if (source.IsRegister()) { 3582 if (destination.IsRegister()) { 3583 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>()); 3584 } else { 3585 DCHECK(destination.IsStackSlot()); 3586 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), 3587 SP, destination.GetStackIndex()); 3588 } 3589 } else if (source.IsStackSlot()) { 3590 if (destination.IsRegister()) { 3591 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), 3592 SP, source.GetStackIndex()); 3593 } else if (destination.IsFpuRegister()) { 3594 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex()); 3595 } else { 3596 DCHECK(destination.IsStackSlot()); 3597 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 3598 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3599 } 3600 } else if (source.IsFpuRegister()) { 3601 if (destination.IsFpuRegister()) { 3602 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>()); 3603 } else { 3604 DCHECK(destination.IsStackSlot()); 3605 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex()); 3606 } 3607 } else if (source.IsDoubleStackSlot()) { 3608 if (destination.IsDoubleStackSlot()) { 3609 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex()); 3610 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex()); 3611 } else if (destination.IsRegisterPair()) { 3612 DCHECK(ExpectedPairLayout(destination)); 3613 __ LoadFromOffset( 3614 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex()); 3615 } else { 3616 DCHECK(destination.IsFpuRegisterPair()) << destination; 3617 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), 3618 SP, 3619 source.GetStackIndex()); 3620 } 3621 } else if (source.IsRegisterPair()) { 3622 if (destination.IsRegisterPair()) { 3623 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>()); 3624 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>()); 3625 } else { 3626 DCHECK(destination.IsDoubleStackSlot()) << destination; 3627 DCHECK(ExpectedPairLayout(source)); 3628 __ StoreToOffset( 3629 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex()); 3630 } 3631 } else if (source.IsFpuRegisterPair()) { 3632 if (destination.IsFpuRegisterPair()) { 3633 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), 3634 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())); 3635 } else { 3636 DCHECK(destination.IsDoubleStackSlot()) << destination; 3637 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()), 3638 SP, 3639 destination.GetStackIndex()); 3640 } 3641 } else { 3642 DCHECK(source.IsConstant()) << source; 3643 HConstant* constant = source.GetConstant(); 3644 if (constant->IsIntConstant() || constant->IsNullConstant()) { 3645 int32_t value = CodeGenerator::GetInt32ValueOf(constant); 3646 if (destination.IsRegister()) { 3647 __ LoadImmediate(destination.AsRegister<Register>(), value); 3648 } else { 3649 DCHECK(destination.IsStackSlot()); 3650 __ LoadImmediate(IP, value); 3651 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3652 } 3653 } else if (constant->IsLongConstant()) { 3654 int64_t value = constant->AsLongConstant()->GetValue(); 3655 if (destination.IsRegisterPair()) { 3656 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value)); 3657 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value)); 3658 } else { 3659 DCHECK(destination.IsDoubleStackSlot()) << destination; 3660 __ LoadImmediate(IP, Low32Bits(value)); 3661 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3662 __ LoadImmediate(IP, High32Bits(value)); 3663 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize)); 3664 } 3665 } else if (constant->IsDoubleConstant()) { 3666 double value = constant->AsDoubleConstant()->GetValue(); 3667 if (destination.IsFpuRegisterPair()) { 3668 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value); 3669 } else { 3670 DCHECK(destination.IsDoubleStackSlot()) << destination; 3671 uint64_t int_value = bit_cast<uint64_t, double>(value); 3672 __ LoadImmediate(IP, Low32Bits(int_value)); 3673 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3674 __ LoadImmediate(IP, High32Bits(int_value)); 3675 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize)); 3676 } 3677 } else { 3678 DCHECK(constant->IsFloatConstant()) << constant->DebugName(); 3679 float value = constant->AsFloatConstant()->GetValue(); 3680 if (destination.IsFpuRegister()) { 3681 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value); 3682 } else { 3683 DCHECK(destination.IsStackSlot()); 3684 __ LoadImmediate(IP, bit_cast<int32_t, float>(value)); 3685 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3686 } 3687 } 3688 } 3689} 3690 3691void ParallelMoveResolverARM::Exchange(Register reg, int mem) { 3692 __ Mov(IP, reg); 3693 __ LoadFromOffset(kLoadWord, reg, SP, mem); 3694 __ StoreToOffset(kStoreWord, IP, SP, mem); 3695} 3696 3697void ParallelMoveResolverARM::Exchange(int mem1, int mem2) { 3698 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters()); 3699 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; 3700 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()), 3701 SP, mem1 + stack_offset); 3702 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset); 3703 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()), 3704 SP, mem2 + stack_offset); 3705 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset); 3706} 3707 3708void ParallelMoveResolverARM::EmitSwap(size_t index) { 3709 MoveOperands* move = moves_.Get(index); 3710 Location source = move->GetSource(); 3711 Location destination = move->GetDestination(); 3712 3713 if (source.IsRegister() && destination.IsRegister()) { 3714 DCHECK_NE(source.AsRegister<Register>(), IP); 3715 DCHECK_NE(destination.AsRegister<Register>(), IP); 3716 __ Mov(IP, source.AsRegister<Register>()); 3717 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>()); 3718 __ Mov(destination.AsRegister<Register>(), IP); 3719 } else if (source.IsRegister() && destination.IsStackSlot()) { 3720 Exchange(source.AsRegister<Register>(), destination.GetStackIndex()); 3721 } else if (source.IsStackSlot() && destination.IsRegister()) { 3722 Exchange(destination.AsRegister<Register>(), source.GetStackIndex()); 3723 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 3724 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 3725 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { 3726 __ vmovrs(IP, source.AsFpuRegister<SRegister>()); 3727 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>()); 3728 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP); 3729 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) { 3730 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>()); 3731 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>()); 3732 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>()); 3733 __ vmovrrd(destination.AsRegisterPairLow<Register>(), 3734 destination.AsRegisterPairHigh<Register>(), 3735 DTMP); 3736 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) { 3737 Register low_reg = source.IsRegisterPair() 3738 ? source.AsRegisterPairLow<Register>() 3739 : destination.AsRegisterPairLow<Register>(); 3740 int mem = source.IsRegisterPair() 3741 ? destination.GetStackIndex() 3742 : source.GetStackIndex(); 3743 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination)); 3744 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1)); 3745 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem); 3746 __ StoreDToOffset(DTMP, SP, mem); 3747 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) { 3748 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()); 3749 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()); 3750 __ vmovd(DTMP, first); 3751 __ vmovd(first, second); 3752 __ vmovd(second, DTMP); 3753 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) { 3754 DRegister reg = source.IsFpuRegisterPair() 3755 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()) 3756 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()); 3757 int mem = source.IsFpuRegisterPair() 3758 ? destination.GetStackIndex() 3759 : source.GetStackIndex(); 3760 __ vmovd(DTMP, reg); 3761 __ LoadDFromOffset(reg, SP, mem); 3762 __ StoreDToOffset(DTMP, SP, mem); 3763 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { 3764 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>() 3765 : destination.AsFpuRegister<SRegister>(); 3766 int mem = source.IsFpuRegister() 3767 ? destination.GetStackIndex() 3768 : source.GetStackIndex(); 3769 3770 __ vmovrs(IP, reg); 3771 __ LoadSFromOffset(reg, SP, mem); 3772 __ StoreToOffset(kStoreWord, IP, SP, mem); 3773 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { 3774 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 3775 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize)); 3776 } else { 3777 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination; 3778 } 3779} 3780 3781void ParallelMoveResolverARM::SpillScratch(int reg) { 3782 __ Push(static_cast<Register>(reg)); 3783} 3784 3785void ParallelMoveResolverARM::RestoreScratch(int reg) { 3786 __ Pop(static_cast<Register>(reg)); 3787} 3788 3789void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) { 3790 LocationSummary::CallKind call_kind = cls->CanCallRuntime() 3791 ? LocationSummary::kCallOnSlowPath 3792 : LocationSummary::kNoCall; 3793 LocationSummary* locations = 3794 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); 3795 locations->SetOut(Location::RequiresRegister()); 3796} 3797 3798void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { 3799 Register out = cls->GetLocations()->Out().AsRegister<Register>(); 3800 if (cls->IsReferrersClass()) { 3801 DCHECK(!cls->CanCallRuntime()); 3802 DCHECK(!cls->MustGenerateClinitCheck()); 3803 codegen_->LoadCurrentMethod(out); 3804 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()); 3805 } else { 3806 DCHECK(cls->CanCallRuntime()); 3807 codegen_->LoadCurrentMethod(out); 3808 __ LoadFromOffset( 3809 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()); 3810 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); 3811 3812 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( 3813 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); 3814 codegen_->AddSlowPath(slow_path); 3815 __ cmp(out, ShifterOperand(0)); 3816 __ b(slow_path->GetEntryLabel(), EQ); 3817 if (cls->MustGenerateClinitCheck()) { 3818 GenerateClassInitializationCheck(slow_path, out); 3819 } else { 3820 __ Bind(slow_path->GetExitLabel()); 3821 } 3822 } 3823} 3824 3825void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) { 3826 LocationSummary* locations = 3827 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath); 3828 locations->SetInAt(0, Location::RequiresRegister()); 3829 if (check->HasUses()) { 3830 locations->SetOut(Location::SameAsFirstInput()); 3831 } 3832} 3833 3834void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) { 3835 // We assume the class is not null. 3836 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( 3837 check->GetLoadClass(), check, check->GetDexPc(), true); 3838 codegen_->AddSlowPath(slow_path); 3839 GenerateClassInitializationCheck(slow_path, 3840 check->GetLocations()->InAt(0).AsRegister<Register>()); 3841} 3842 3843void InstructionCodeGeneratorARM::GenerateClassInitializationCheck( 3844 SlowPathCodeARM* slow_path, Register class_reg) { 3845 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value()); 3846 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized)); 3847 __ b(slow_path->GetEntryLabel(), LT); 3848 // Even if the initialized flag is set, we may be in a situation where caches are not synced 3849 // properly. Therefore, we do a memory fence. 3850 __ dmb(ISH); 3851 __ Bind(slow_path->GetExitLabel()); 3852} 3853 3854void LocationsBuilderARM::VisitLoadString(HLoadString* load) { 3855 LocationSummary* locations = 3856 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath); 3857 locations->SetOut(Location::RequiresRegister()); 3858} 3859 3860void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { 3861 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load); 3862 codegen_->AddSlowPath(slow_path); 3863 3864 Register out = load->GetLocations()->Out().AsRegister<Register>(); 3865 codegen_->LoadCurrentMethod(out); 3866 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()); 3867 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value()); 3868 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex())); 3869 __ cmp(out, ShifterOperand(0)); 3870 __ b(slow_path->GetEntryLabel(), EQ); 3871 __ Bind(slow_path->GetExitLabel()); 3872} 3873 3874void LocationsBuilderARM::VisitLoadException(HLoadException* load) { 3875 LocationSummary* locations = 3876 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall); 3877 locations->SetOut(Location::RequiresRegister()); 3878} 3879 3880void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) { 3881 Register out = load->GetLocations()->Out().AsRegister<Register>(); 3882 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value(); 3883 __ LoadFromOffset(kLoadWord, out, TR, offset); 3884 __ LoadImmediate(IP, 0); 3885 __ StoreToOffset(kStoreWord, IP, TR, offset); 3886} 3887 3888void LocationsBuilderARM::VisitThrow(HThrow* instruction) { 3889 LocationSummary* locations = 3890 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3891 InvokeRuntimeCallingConvention calling_convention; 3892 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3893} 3894 3895void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) { 3896 codegen_->InvokeRuntime( 3897 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr); 3898} 3899 3900void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) { 3901 LocationSummary::CallKind call_kind = instruction->IsClassFinal() 3902 ? LocationSummary::kNoCall 3903 : LocationSummary::kCallOnSlowPath; 3904 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 3905 locations->SetInAt(0, Location::RequiresRegister()); 3906 locations->SetInAt(1, Location::RequiresRegister()); 3907 // The out register is used as a temporary, so it overlaps with the inputs. 3908 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 3909} 3910 3911void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { 3912 LocationSummary* locations = instruction->GetLocations(); 3913 Register obj = locations->InAt(0).AsRegister<Register>(); 3914 Register cls = locations->InAt(1).AsRegister<Register>(); 3915 Register out = locations->Out().AsRegister<Register>(); 3916 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 3917 Label done, zero; 3918 SlowPathCodeARM* slow_path = nullptr; 3919 3920 // Return 0 if `obj` is null. 3921 // avoid null check if we know obj is not null. 3922 if (instruction->MustDoNullCheck()) { 3923 __ cmp(obj, ShifterOperand(0)); 3924 __ b(&zero, EQ); 3925 } 3926 // Compare the class of `obj` with `cls`. 3927 __ LoadFromOffset(kLoadWord, out, obj, class_offset); 3928 __ cmp(out, ShifterOperand(cls)); 3929 if (instruction->IsClassFinal()) { 3930 // Classes must be equal for the instanceof to succeed. 3931 __ b(&zero, NE); 3932 __ LoadImmediate(out, 1); 3933 __ b(&done); 3934 } else { 3935 // If the classes are not equal, we go into a slow path. 3936 DCHECK(locations->OnlyCallsOnSlowPath()); 3937 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( 3938 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc()); 3939 codegen_->AddSlowPath(slow_path); 3940 __ b(slow_path->GetEntryLabel(), NE); 3941 __ LoadImmediate(out, 1); 3942 __ b(&done); 3943 } 3944 3945 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) { 3946 __ Bind(&zero); 3947 __ LoadImmediate(out, 0); 3948 } 3949 3950 if (slow_path != nullptr) { 3951 __ Bind(slow_path->GetExitLabel()); 3952 } 3953 __ Bind(&done); 3954} 3955 3956void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) { 3957 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 3958 instruction, LocationSummary::kCallOnSlowPath); 3959 locations->SetInAt(0, Location::RequiresRegister()); 3960 locations->SetInAt(1, Location::RequiresRegister()); 3961 locations->AddTemp(Location::RequiresRegister()); 3962} 3963 3964void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { 3965 LocationSummary* locations = instruction->GetLocations(); 3966 Register obj = locations->InAt(0).AsRegister<Register>(); 3967 Register cls = locations->InAt(1).AsRegister<Register>(); 3968 Register temp = locations->GetTemp(0).AsRegister<Register>(); 3969 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 3970 3971 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( 3972 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc()); 3973 codegen_->AddSlowPath(slow_path); 3974 3975 // avoid null check if we know obj is not null. 3976 if (instruction->MustDoNullCheck()) { 3977 __ cmp(obj, ShifterOperand(0)); 3978 __ b(slow_path->GetExitLabel(), EQ); 3979 } 3980 // Compare the class of `obj` with `cls`. 3981 __ LoadFromOffset(kLoadWord, temp, obj, class_offset); 3982 __ cmp(temp, ShifterOperand(cls)); 3983 __ b(slow_path->GetEntryLabel(), NE); 3984 __ Bind(slow_path->GetExitLabel()); 3985} 3986 3987void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) { 3988 LocationSummary* locations = 3989 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3990 InvokeRuntimeCallingConvention calling_convention; 3991 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3992} 3993 3994void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) { 3995 codegen_->InvokeRuntime(instruction->IsEnter() 3996 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject), 3997 instruction, 3998 instruction->GetDexPc(), 3999 nullptr); 4000} 4001 4002void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } 4003void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } 4004void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } 4005 4006void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) { 4007 LocationSummary* locations = 4008 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 4009 DCHECK(instruction->GetResultType() == Primitive::kPrimInt 4010 || instruction->GetResultType() == Primitive::kPrimLong); 4011 locations->SetInAt(0, Location::RequiresRegister()); 4012 locations->SetInAt(1, Location::RequiresRegister()); 4013 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 4014} 4015 4016void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) { 4017 HandleBitwiseOperation(instruction); 4018} 4019 4020void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) { 4021 HandleBitwiseOperation(instruction); 4022} 4023 4024void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) { 4025 HandleBitwiseOperation(instruction); 4026} 4027 4028void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) { 4029 LocationSummary* locations = instruction->GetLocations(); 4030 4031 if (instruction->GetResultType() == Primitive::kPrimInt) { 4032 Register first = locations->InAt(0).AsRegister<Register>(); 4033 Register second = locations->InAt(1).AsRegister<Register>(); 4034 Register out = locations->Out().AsRegister<Register>(); 4035 if (instruction->IsAnd()) { 4036 __ and_(out, first, ShifterOperand(second)); 4037 } else if (instruction->IsOr()) { 4038 __ orr(out, first, ShifterOperand(second)); 4039 } else { 4040 DCHECK(instruction->IsXor()); 4041 __ eor(out, first, ShifterOperand(second)); 4042 } 4043 } else { 4044 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); 4045 Location first = locations->InAt(0); 4046 Location second = locations->InAt(1); 4047 Location out = locations->Out(); 4048 if (instruction->IsAnd()) { 4049 __ and_(out.AsRegisterPairLow<Register>(), 4050 first.AsRegisterPairLow<Register>(), 4051 ShifterOperand(second.AsRegisterPairLow<Register>())); 4052 __ and_(out.AsRegisterPairHigh<Register>(), 4053 first.AsRegisterPairHigh<Register>(), 4054 ShifterOperand(second.AsRegisterPairHigh<Register>())); 4055 } else if (instruction->IsOr()) { 4056 __ orr(out.AsRegisterPairLow<Register>(), 4057 first.AsRegisterPairLow<Register>(), 4058 ShifterOperand(second.AsRegisterPairLow<Register>())); 4059 __ orr(out.AsRegisterPairHigh<Register>(), 4060 first.AsRegisterPairHigh<Register>(), 4061 ShifterOperand(second.AsRegisterPairHigh<Register>())); 4062 } else { 4063 DCHECK(instruction->IsXor()); 4064 __ eor(out.AsRegisterPairLow<Register>(), 4065 first.AsRegisterPairLow<Register>(), 4066 ShifterOperand(second.AsRegisterPairLow<Register>())); 4067 __ eor(out.AsRegisterPairHigh<Register>(), 4068 first.AsRegisterPairHigh<Register>(), 4069 ShifterOperand(second.AsRegisterPairHigh<Register>())); 4070 } 4071 } 4072} 4073 4074void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) { 4075 DCHECK_EQ(temp, kArtMethodRegister); 4076 4077 // TODO: Implement all kinds of calls: 4078 // 1) boot -> boot 4079 // 2) app -> boot 4080 // 3) app -> app 4081 // 4082 // Currently we implement the app -> app logic, which looks up in the resolve cache. 4083 4084 if (invoke->IsStringInit()) { 4085 // temp = thread->string_init_entrypoint 4086 __ LoadFromOffset(kLoadWord, temp, TR, invoke->GetStringInitOffset()); 4087 // LR = temp[offset_of_quick_compiled_code] 4088 __ LoadFromOffset(kLoadWord, LR, temp, 4089 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( 4090 kArmWordSize).Int32Value()); 4091 // LR() 4092 __ blx(LR); 4093 } else { 4094 // temp = method; 4095 LoadCurrentMethod(temp); 4096 if (!invoke->IsRecursive()) { 4097 // temp = temp->dex_cache_resolved_methods_; 4098 __ LoadFromOffset( 4099 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); 4100 // temp = temp[index_in_cache] 4101 __ LoadFromOffset( 4102 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())); 4103 // LR = temp[offset_of_quick_compiled_code] 4104 __ LoadFromOffset(kLoadWord, LR, temp, 4105 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset( 4106 kArmWordSize).Int32Value()); 4107 // LR() 4108 __ blx(LR); 4109 } else { 4110 __ bl(GetFrameEntryLabel()); 4111 } 4112 } 4113 4114 DCHECK(!IsLeafMethod()); 4115} 4116 4117void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) { 4118 // Nothing to do, this should be removed during prepare for register allocator. 4119 UNUSED(instruction); 4120 LOG(FATAL) << "Unreachable"; 4121} 4122 4123void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) { 4124 // Nothing to do, this should be removed during prepare for register allocator. 4125 UNUSED(instruction); 4126 LOG(FATAL) << "Unreachable"; 4127} 4128 4129} // namespace arm 4130} // namespace art 4131