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