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 "art_method.h" 21#include "entrypoints/quick/quick_entrypoints.h" 22#include "gc/accounting/card_table.h" 23#include "intrinsics.h" 24#include "intrinsics_arm.h" 25#include "mirror/array-inl.h" 26#include "mirror/class-inl.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::EmbeddedVTableEntryOffset( 1316 invoke->GetVTableIndex(), kArmPointerSize).Uint32Value(); 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 = 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::EmbeddedImTableEntryOffset( 1350 invoke->GetImtIndex() % mirror::Class::kImtSize, kArmPointerSize).Uint32Value(); 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 = 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 // Make the output overlap, as it will be used to hold the masked 2462 // second input. 2463 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 2464 break; 2465 } 2466 case Primitive::kPrimLong: { 2467 locations->SetInAt(0, Location::RequiresRegister()); 2468 locations->SetInAt(1, Location::RequiresRegister()); 2469 locations->AddTemp(Location::RequiresRegister()); 2470 locations->SetOut(Location::RequiresRegister()); 2471 break; 2472 } 2473 default: 2474 LOG(FATAL) << "Unexpected operation type " << op->GetResultType(); 2475 } 2476} 2477 2478void InstructionCodeGeneratorARM::HandleShift(HBinaryOperation* op) { 2479 DCHECK(op->IsShl() || op->IsShr() || op->IsUShr()); 2480 2481 LocationSummary* locations = op->GetLocations(); 2482 Location out = locations->Out(); 2483 Location first = locations->InAt(0); 2484 Location second = locations->InAt(1); 2485 2486 Primitive::Type type = op->GetResultType(); 2487 switch (type) { 2488 case Primitive::kPrimInt: { 2489 Register out_reg = out.AsRegister<Register>(); 2490 Register first_reg = first.AsRegister<Register>(); 2491 // Arm doesn't mask the shift count so we need to do it ourselves. 2492 if (second.IsRegister()) { 2493 Register second_reg = second.AsRegister<Register>(); 2494 __ and_(out_reg, second_reg, ShifterOperand(kMaxIntShiftValue)); 2495 if (op->IsShl()) { 2496 __ Lsl(out_reg, first_reg, out_reg); 2497 } else if (op->IsShr()) { 2498 __ Asr(out_reg, first_reg, out_reg); 2499 } else { 2500 __ Lsr(out_reg, first_reg, out_reg); 2501 } 2502 } else { 2503 int32_t cst = second.GetConstant()->AsIntConstant()->GetValue(); 2504 uint32_t shift_value = static_cast<uint32_t>(cst & kMaxIntShiftValue); 2505 if (shift_value == 0) { // arm does not support shifting with 0 immediate. 2506 __ Mov(out_reg, first_reg); 2507 } else if (op->IsShl()) { 2508 __ Lsl(out_reg, first_reg, shift_value); 2509 } else if (op->IsShr()) { 2510 __ Asr(out_reg, first_reg, shift_value); 2511 } else { 2512 __ Lsr(out_reg, first_reg, shift_value); 2513 } 2514 } 2515 break; 2516 } 2517 case Primitive::kPrimLong: { 2518 Register o_h = out.AsRegisterPairHigh<Register>(); 2519 Register o_l = out.AsRegisterPairLow<Register>(); 2520 2521 Register temp = locations->GetTemp(0).AsRegister<Register>(); 2522 2523 Register high = first.AsRegisterPairHigh<Register>(); 2524 Register low = first.AsRegisterPairLow<Register>(); 2525 2526 Register second_reg = second.AsRegister<Register>(); 2527 2528 if (op->IsShl()) { 2529 __ and_(o_l, second_reg, ShifterOperand(kMaxLongShiftValue)); 2530 // Shift the high part 2531 __ Lsl(o_h, high, o_l); 2532 // Shift the low part and `or` what overflew on the high part 2533 __ rsb(temp, o_l, ShifterOperand(kArmBitsPerWord)); 2534 __ Lsr(temp, low, temp); 2535 __ orr(o_h, o_h, ShifterOperand(temp)); 2536 // If the shift is > 32 bits, override the high part 2537 __ subs(temp, o_l, ShifterOperand(kArmBitsPerWord)); 2538 __ it(PL); 2539 __ Lsl(o_h, low, temp, false, PL); 2540 // Shift the low part 2541 __ Lsl(o_l, low, o_l); 2542 } else if (op->IsShr()) { 2543 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue)); 2544 // Shift the low part 2545 __ Lsr(o_l, low, o_h); 2546 // Shift the high part and `or` what underflew on the low part 2547 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord)); 2548 __ Lsl(temp, high, temp); 2549 __ orr(o_l, o_l, ShifterOperand(temp)); 2550 // If the shift is > 32 bits, override the low part 2551 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord)); 2552 __ it(PL); 2553 __ Asr(o_l, high, temp, false, PL); 2554 // Shift the high part 2555 __ Asr(o_h, high, o_h); 2556 } else { 2557 __ and_(o_h, second_reg, ShifterOperand(kMaxLongShiftValue)); 2558 // same as Shr except we use `Lsr`s and not `Asr`s 2559 __ Lsr(o_l, low, o_h); 2560 __ rsb(temp, o_h, ShifterOperand(kArmBitsPerWord)); 2561 __ Lsl(temp, high, temp); 2562 __ orr(o_l, o_l, ShifterOperand(temp)); 2563 __ subs(temp, o_h, ShifterOperand(kArmBitsPerWord)); 2564 __ it(PL); 2565 __ Lsr(o_l, high, temp, false, PL); 2566 __ Lsr(o_h, high, o_h); 2567 } 2568 break; 2569 } 2570 default: 2571 LOG(FATAL) << "Unexpected operation type " << type; 2572 } 2573} 2574 2575void LocationsBuilderARM::VisitShl(HShl* shl) { 2576 HandleShift(shl); 2577} 2578 2579void InstructionCodeGeneratorARM::VisitShl(HShl* shl) { 2580 HandleShift(shl); 2581} 2582 2583void LocationsBuilderARM::VisitShr(HShr* shr) { 2584 HandleShift(shr); 2585} 2586 2587void InstructionCodeGeneratorARM::VisitShr(HShr* shr) { 2588 HandleShift(shr); 2589} 2590 2591void LocationsBuilderARM::VisitUShr(HUShr* ushr) { 2592 HandleShift(ushr); 2593} 2594 2595void InstructionCodeGeneratorARM::VisitUShr(HUShr* ushr) { 2596 HandleShift(ushr); 2597} 2598 2599void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 2600 LocationSummary* locations = 2601 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2602 InvokeRuntimeCallingConvention calling_convention; 2603 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2604 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2605 locations->SetOut(Location::RegisterLocation(R0)); 2606} 2607 2608void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 2609 InvokeRuntimeCallingConvention calling_convention; 2610 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 2611 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 2612 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(), 2613 instruction, 2614 instruction->GetDexPc(), 2615 nullptr); 2616} 2617 2618void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) { 2619 LocationSummary* locations = 2620 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2621 InvokeRuntimeCallingConvention calling_convention; 2622 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2623 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 2624 locations->SetOut(Location::RegisterLocation(R0)); 2625 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2626} 2627 2628void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) { 2629 InvokeRuntimeCallingConvention calling_convention; 2630 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(2)); 2631 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 2632 codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(), 2633 instruction, 2634 instruction->GetDexPc(), 2635 nullptr); 2636} 2637 2638void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 2639 LocationSummary* locations = 2640 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2641 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 2642 if (location.IsStackSlot()) { 2643 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 2644 } else if (location.IsDoubleStackSlot()) { 2645 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 2646 } 2647 locations->SetOut(location); 2648} 2649 2650void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 2651 // Nothing to do, the parameter is already at its location. 2652 UNUSED(instruction); 2653} 2654 2655void LocationsBuilderARM::VisitNot(HNot* not_) { 2656 LocationSummary* locations = 2657 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall); 2658 locations->SetInAt(0, Location::RequiresRegister()); 2659 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2660} 2661 2662void InstructionCodeGeneratorARM::VisitNot(HNot* not_) { 2663 LocationSummary* locations = not_->GetLocations(); 2664 Location out = locations->Out(); 2665 Location in = locations->InAt(0); 2666 switch (not_->GetResultType()) { 2667 case Primitive::kPrimInt: 2668 __ mvn(out.AsRegister<Register>(), ShifterOperand(in.AsRegister<Register>())); 2669 break; 2670 2671 case Primitive::kPrimLong: 2672 __ mvn(out.AsRegisterPairLow<Register>(), 2673 ShifterOperand(in.AsRegisterPairLow<Register>())); 2674 __ mvn(out.AsRegisterPairHigh<Register>(), 2675 ShifterOperand(in.AsRegisterPairHigh<Register>())); 2676 break; 2677 2678 default: 2679 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType(); 2680 } 2681} 2682 2683void LocationsBuilderARM::VisitBooleanNot(HBooleanNot* bool_not) { 2684 LocationSummary* locations = 2685 new (GetGraph()->GetArena()) LocationSummary(bool_not, LocationSummary::kNoCall); 2686 locations->SetInAt(0, Location::RequiresRegister()); 2687 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2688} 2689 2690void InstructionCodeGeneratorARM::VisitBooleanNot(HBooleanNot* bool_not) { 2691 LocationSummary* locations = bool_not->GetLocations(); 2692 Location out = locations->Out(); 2693 Location in = locations->InAt(0); 2694 __ eor(out.AsRegister<Register>(), in.AsRegister<Register>(), ShifterOperand(1)); 2695} 2696 2697void LocationsBuilderARM::VisitCompare(HCompare* compare) { 2698 LocationSummary* locations = 2699 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 2700 switch (compare->InputAt(0)->GetType()) { 2701 case Primitive::kPrimLong: { 2702 locations->SetInAt(0, Location::RequiresRegister()); 2703 locations->SetInAt(1, Location::RequiresRegister()); 2704 // Output overlaps because it is written before doing the low comparison. 2705 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 2706 break; 2707 } 2708 case Primitive::kPrimFloat: 2709 case Primitive::kPrimDouble: { 2710 locations->SetInAt(0, Location::RequiresFpuRegister()); 2711 locations->SetInAt(1, Location::RequiresFpuRegister()); 2712 locations->SetOut(Location::RequiresRegister()); 2713 break; 2714 } 2715 default: 2716 LOG(FATAL) << "Unexpected type for compare operation " << compare->InputAt(0)->GetType(); 2717 } 2718} 2719 2720void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { 2721 LocationSummary* locations = compare->GetLocations(); 2722 Register out = locations->Out().AsRegister<Register>(); 2723 Location left = locations->InAt(0); 2724 Location right = locations->InAt(1); 2725 2726 Label less, greater, done; 2727 Primitive::Type type = compare->InputAt(0)->GetType(); 2728 switch (type) { 2729 case Primitive::kPrimLong: { 2730 __ cmp(left.AsRegisterPairHigh<Register>(), 2731 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare. 2732 __ b(&less, LT); 2733 __ b(&greater, GT); 2734 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect the status flags. 2735 __ LoadImmediate(out, 0); 2736 __ cmp(left.AsRegisterPairLow<Register>(), 2737 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare. 2738 break; 2739 } 2740 case Primitive::kPrimFloat: 2741 case Primitive::kPrimDouble: { 2742 __ LoadImmediate(out, 0); 2743 if (type == Primitive::kPrimFloat) { 2744 __ vcmps(left.AsFpuRegister<SRegister>(), right.AsFpuRegister<SRegister>()); 2745 } else { 2746 __ vcmpd(FromLowSToD(left.AsFpuRegisterPairLow<SRegister>()), 2747 FromLowSToD(right.AsFpuRegisterPairLow<SRegister>())); 2748 } 2749 __ vmstat(); // transfer FP status register to ARM APSR. 2750 __ b(compare->IsGtBias() ? &greater : &less, VS); // VS for unordered. 2751 break; 2752 } 2753 default: 2754 LOG(FATAL) << "Unexpected compare type " << type; 2755 } 2756 __ b(&done, EQ); 2757 __ b(&less, CC); // CC is for both: unsigned compare for longs and 'less than' for floats. 2758 2759 __ Bind(&greater); 2760 __ LoadImmediate(out, 1); 2761 __ b(&done); 2762 2763 __ Bind(&less); 2764 __ LoadImmediate(out, -1); 2765 2766 __ Bind(&done); 2767} 2768 2769void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 2770 LocationSummary* locations = 2771 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2772 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 2773 locations->SetInAt(i, Location::Any()); 2774 } 2775 locations->SetOut(Location::Any()); 2776} 2777 2778void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 2779 UNUSED(instruction); 2780 LOG(FATAL) << "Unreachable"; 2781} 2782 2783void InstructionCodeGeneratorARM::GenerateMemoryBarrier(MemBarrierKind kind) { 2784 // TODO (ported from quick): revisit Arm barrier kinds 2785 DmbOptions flavour = DmbOptions::ISH; // quiet c++ warnings 2786 switch (kind) { 2787 case MemBarrierKind::kAnyStore: 2788 case MemBarrierKind::kLoadAny: 2789 case MemBarrierKind::kAnyAny: { 2790 flavour = DmbOptions::ISH; 2791 break; 2792 } 2793 case MemBarrierKind::kStoreStore: { 2794 flavour = DmbOptions::ISHST; 2795 break; 2796 } 2797 default: 2798 LOG(FATAL) << "Unexpected memory barrier " << kind; 2799 } 2800 __ dmb(flavour); 2801} 2802 2803void InstructionCodeGeneratorARM::GenerateWideAtomicLoad(Register addr, 2804 uint32_t offset, 2805 Register out_lo, 2806 Register out_hi) { 2807 if (offset != 0) { 2808 __ LoadImmediate(out_lo, offset); 2809 __ add(IP, addr, ShifterOperand(out_lo)); 2810 addr = IP; 2811 } 2812 __ ldrexd(out_lo, out_hi, addr); 2813} 2814 2815void InstructionCodeGeneratorARM::GenerateWideAtomicStore(Register addr, 2816 uint32_t offset, 2817 Register value_lo, 2818 Register value_hi, 2819 Register temp1, 2820 Register temp2, 2821 HInstruction* instruction) { 2822 Label fail; 2823 if (offset != 0) { 2824 __ LoadImmediate(temp1, offset); 2825 __ add(IP, addr, ShifterOperand(temp1)); 2826 addr = IP; 2827 } 2828 __ Bind(&fail); 2829 // We need a load followed by store. (The address used in a STREX instruction must 2830 // be the same as the address in the most recently executed LDREX instruction.) 2831 __ ldrexd(temp1, temp2, addr); 2832 codegen_->MaybeRecordImplicitNullCheck(instruction); 2833 __ strexd(temp1, value_lo, value_hi, addr); 2834 __ cmp(temp1, ShifterOperand(0)); 2835 __ b(&fail, NE); 2836} 2837 2838void LocationsBuilderARM::HandleFieldSet(HInstruction* instruction, const FieldInfo& field_info) { 2839 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet()); 2840 2841 LocationSummary* locations = 2842 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2843 locations->SetInAt(0, Location::RequiresRegister()); 2844 2845 Primitive::Type field_type = field_info.GetFieldType(); 2846 if (Primitive::IsFloatingPointType(field_type)) { 2847 locations->SetInAt(1, Location::RequiresFpuRegister()); 2848 } else { 2849 locations->SetInAt(1, Location::RequiresRegister()); 2850 } 2851 2852 bool is_wide = field_type == Primitive::kPrimLong || field_type == Primitive::kPrimDouble; 2853 bool generate_volatile = field_info.IsVolatile() 2854 && is_wide 2855 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); 2856 // Temporary registers for the write barrier. 2857 // TODO: consider renaming StoreNeedsWriteBarrier to StoreNeedsGCMark. 2858 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { 2859 locations->AddTemp(Location::RequiresRegister()); 2860 locations->AddTemp(Location::RequiresRegister()); 2861 } else if (generate_volatile) { 2862 // Arm encoding have some additional constraints for ldrexd/strexd: 2863 // - registers need to be consecutive 2864 // - the first register should be even but not R14. 2865 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever 2866 // enable Arm encoding. 2867 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet()); 2868 2869 locations->AddTemp(Location::RequiresRegister()); 2870 locations->AddTemp(Location::RequiresRegister()); 2871 if (field_type == Primitive::kPrimDouble) { 2872 // For doubles we need two more registers to copy the value. 2873 locations->AddTemp(Location::RegisterLocation(R2)); 2874 locations->AddTemp(Location::RegisterLocation(R3)); 2875 } 2876 } 2877} 2878 2879void InstructionCodeGeneratorARM::HandleFieldSet(HInstruction* instruction, 2880 const FieldInfo& field_info) { 2881 DCHECK(instruction->IsInstanceFieldSet() || instruction->IsStaticFieldSet()); 2882 2883 LocationSummary* locations = instruction->GetLocations(); 2884 Register base = locations->InAt(0).AsRegister<Register>(); 2885 Location value = locations->InAt(1); 2886 2887 bool is_volatile = field_info.IsVolatile(); 2888 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); 2889 Primitive::Type field_type = field_info.GetFieldType(); 2890 uint32_t offset = field_info.GetFieldOffset().Uint32Value(); 2891 2892 if (is_volatile) { 2893 GenerateMemoryBarrier(MemBarrierKind::kAnyStore); 2894 } 2895 2896 switch (field_type) { 2897 case Primitive::kPrimBoolean: 2898 case Primitive::kPrimByte: { 2899 __ StoreToOffset(kStoreByte, value.AsRegister<Register>(), base, offset); 2900 break; 2901 } 2902 2903 case Primitive::kPrimShort: 2904 case Primitive::kPrimChar: { 2905 __ StoreToOffset(kStoreHalfword, value.AsRegister<Register>(), base, offset); 2906 break; 2907 } 2908 2909 case Primitive::kPrimInt: 2910 case Primitive::kPrimNot: { 2911 __ StoreToOffset(kStoreWord, value.AsRegister<Register>(), base, offset); 2912 break; 2913 } 2914 2915 case Primitive::kPrimLong: { 2916 if (is_volatile && !atomic_ldrd_strd) { 2917 GenerateWideAtomicStore(base, offset, 2918 value.AsRegisterPairLow<Register>(), 2919 value.AsRegisterPairHigh<Register>(), 2920 locations->GetTemp(0).AsRegister<Register>(), 2921 locations->GetTemp(1).AsRegister<Register>(), 2922 instruction); 2923 } else { 2924 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), base, offset); 2925 codegen_->MaybeRecordImplicitNullCheck(instruction); 2926 } 2927 break; 2928 } 2929 2930 case Primitive::kPrimFloat: { 2931 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), base, offset); 2932 break; 2933 } 2934 2935 case Primitive::kPrimDouble: { 2936 DRegister value_reg = FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()); 2937 if (is_volatile && !atomic_ldrd_strd) { 2938 Register value_reg_lo = locations->GetTemp(0).AsRegister<Register>(); 2939 Register value_reg_hi = locations->GetTemp(1).AsRegister<Register>(); 2940 2941 __ vmovrrd(value_reg_lo, value_reg_hi, value_reg); 2942 2943 GenerateWideAtomicStore(base, offset, 2944 value_reg_lo, 2945 value_reg_hi, 2946 locations->GetTemp(2).AsRegister<Register>(), 2947 locations->GetTemp(3).AsRegister<Register>(), 2948 instruction); 2949 } else { 2950 __ StoreDToOffset(value_reg, base, offset); 2951 codegen_->MaybeRecordImplicitNullCheck(instruction); 2952 } 2953 break; 2954 } 2955 2956 case Primitive::kPrimVoid: 2957 LOG(FATAL) << "Unreachable type " << field_type; 2958 UNREACHABLE(); 2959 } 2960 2961 // Longs and doubles are handled in the switch. 2962 if (field_type != Primitive::kPrimLong && field_type != Primitive::kPrimDouble) { 2963 codegen_->MaybeRecordImplicitNullCheck(instruction); 2964 } 2965 2966 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->InputAt(1))) { 2967 Register temp = locations->GetTemp(0).AsRegister<Register>(); 2968 Register card = locations->GetTemp(1).AsRegister<Register>(); 2969 codegen_->MarkGCCard(temp, card, base, value.AsRegister<Register>()); 2970 } 2971 2972 if (is_volatile) { 2973 GenerateMemoryBarrier(MemBarrierKind::kAnyAny); 2974 } 2975} 2976 2977void LocationsBuilderARM::HandleFieldGet(HInstruction* instruction, const FieldInfo& field_info) { 2978 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); 2979 LocationSummary* locations = 2980 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2981 locations->SetInAt(0, Location::RequiresRegister()); 2982 2983 bool volatile_for_double = field_info.IsVolatile() 2984 && (field_info.GetFieldType() == Primitive::kPrimDouble) 2985 && !codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); 2986 bool overlap = field_info.IsVolatile() && (field_info.GetFieldType() == Primitive::kPrimLong); 2987 2988 if (Primitive::IsFloatingPointType(instruction->GetType())) { 2989 locations->SetOut(Location::RequiresFpuRegister()); 2990 } else { 2991 locations->SetOut(Location::RequiresRegister(), 2992 (overlap ? Location::kOutputOverlap : Location::kNoOutputOverlap)); 2993 } 2994 if (volatile_for_double) { 2995 // Arm encoding have some additional constraints for ldrexd/strexd: 2996 // - registers need to be consecutive 2997 // - the first register should be even but not R14. 2998 // We don't test for Arm yet, and the assertion makes sure that we revisit this if we ever 2999 // enable Arm encoding. 3000 DCHECK_EQ(InstructionSet::kThumb2, codegen_->GetInstructionSet()); 3001 locations->AddTemp(Location::RequiresRegister()); 3002 locations->AddTemp(Location::RequiresRegister()); 3003 } 3004} 3005 3006void InstructionCodeGeneratorARM::HandleFieldGet(HInstruction* instruction, 3007 const FieldInfo& field_info) { 3008 DCHECK(instruction->IsInstanceFieldGet() || instruction->IsStaticFieldGet()); 3009 3010 LocationSummary* locations = instruction->GetLocations(); 3011 Register base = locations->InAt(0).AsRegister<Register>(); 3012 Location out = locations->Out(); 3013 bool is_volatile = field_info.IsVolatile(); 3014 bool atomic_ldrd_strd = codegen_->GetInstructionSetFeatures().HasAtomicLdrdAndStrd(); 3015 Primitive::Type field_type = field_info.GetFieldType(); 3016 uint32_t offset = field_info.GetFieldOffset().Uint32Value(); 3017 3018 switch (field_type) { 3019 case Primitive::kPrimBoolean: { 3020 __ LoadFromOffset(kLoadUnsignedByte, out.AsRegister<Register>(), base, offset); 3021 break; 3022 } 3023 3024 case Primitive::kPrimByte: { 3025 __ LoadFromOffset(kLoadSignedByte, out.AsRegister<Register>(), base, offset); 3026 break; 3027 } 3028 3029 case Primitive::kPrimShort: { 3030 __ LoadFromOffset(kLoadSignedHalfword, out.AsRegister<Register>(), base, offset); 3031 break; 3032 } 3033 3034 case Primitive::kPrimChar: { 3035 __ LoadFromOffset(kLoadUnsignedHalfword, out.AsRegister<Register>(), base, offset); 3036 break; 3037 } 3038 3039 case Primitive::kPrimInt: 3040 case Primitive::kPrimNot: { 3041 __ LoadFromOffset(kLoadWord, out.AsRegister<Register>(), base, offset); 3042 break; 3043 } 3044 3045 case Primitive::kPrimLong: { 3046 if (is_volatile && !atomic_ldrd_strd) { 3047 GenerateWideAtomicLoad(base, offset, 3048 out.AsRegisterPairLow<Register>(), 3049 out.AsRegisterPairHigh<Register>()); 3050 } else { 3051 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), base, offset); 3052 } 3053 break; 3054 } 3055 3056 case Primitive::kPrimFloat: { 3057 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), base, offset); 3058 break; 3059 } 3060 3061 case Primitive::kPrimDouble: { 3062 DRegister out_reg = FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()); 3063 if (is_volatile && !atomic_ldrd_strd) { 3064 Register lo = locations->GetTemp(0).AsRegister<Register>(); 3065 Register hi = locations->GetTemp(1).AsRegister<Register>(); 3066 GenerateWideAtomicLoad(base, offset, lo, hi); 3067 codegen_->MaybeRecordImplicitNullCheck(instruction); 3068 __ vmovdrr(out_reg, lo, hi); 3069 } else { 3070 __ LoadDFromOffset(out_reg, base, offset); 3071 codegen_->MaybeRecordImplicitNullCheck(instruction); 3072 } 3073 break; 3074 } 3075 3076 case Primitive::kPrimVoid: 3077 LOG(FATAL) << "Unreachable type " << field_type; 3078 UNREACHABLE(); 3079 } 3080 3081 // Doubles are handled in the switch. 3082 if (field_type != Primitive::kPrimDouble) { 3083 codegen_->MaybeRecordImplicitNullCheck(instruction); 3084 } 3085 3086 if (is_volatile) { 3087 GenerateMemoryBarrier(MemBarrierKind::kLoadAny); 3088 } 3089} 3090 3091void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 3092 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3093} 3094 3095void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 3096 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3097} 3098 3099void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 3100 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3101} 3102 3103void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 3104 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3105} 3106 3107void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) { 3108 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3109} 3110 3111void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) { 3112 HandleFieldGet(instruction, instruction->GetFieldInfo()); 3113} 3114 3115void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { 3116 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3117} 3118 3119void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { 3120 HandleFieldSet(instruction, instruction->GetFieldInfo()); 3121} 3122 3123void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { 3124 LocationSummary* locations = 3125 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3126 locations->SetInAt(0, Location::RequiresRegister()); 3127 if (instruction->HasUses()) { 3128 locations->SetOut(Location::SameAsFirstInput()); 3129 } 3130} 3131 3132void InstructionCodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) { 3133 if (codegen_->CanMoveNullCheckToUser(instruction)) { 3134 return; 3135 } 3136 Location obj = instruction->GetLocations()->InAt(0); 3137 3138 __ LoadFromOffset(kLoadWord, IP, obj.AsRegister<Register>(), 0); 3139 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 3140} 3141 3142void InstructionCodeGeneratorARM::GenerateExplicitNullCheck(HNullCheck* instruction) { 3143 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); 3144 codegen_->AddSlowPath(slow_path); 3145 3146 LocationSummary* locations = instruction->GetLocations(); 3147 Location obj = locations->InAt(0); 3148 3149 __ cmp(obj.AsRegister<Register>(), ShifterOperand(0)); 3150 __ b(slow_path->GetEntryLabel(), EQ); 3151} 3152 3153void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { 3154 if (codegen_->GetCompilerOptions().GetImplicitNullChecks()) { 3155 GenerateImplicitNullCheck(instruction); 3156 } else { 3157 GenerateExplicitNullCheck(instruction); 3158 } 3159} 3160 3161void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { 3162 LocationSummary* locations = 3163 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3164 locations->SetInAt(0, Location::RequiresRegister()); 3165 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 3166 if (Primitive::IsFloatingPointType(instruction->GetType())) { 3167 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 3168 } else { 3169 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3170 } 3171} 3172 3173void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { 3174 LocationSummary* locations = instruction->GetLocations(); 3175 Register obj = locations->InAt(0).AsRegister<Register>(); 3176 Location index = locations->InAt(1); 3177 3178 switch (instruction->GetType()) { 3179 case Primitive::kPrimBoolean: { 3180 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 3181 Register out = locations->Out().AsRegister<Register>(); 3182 if (index.IsConstant()) { 3183 size_t offset = 3184 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 3185 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 3186 } else { 3187 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>())); 3188 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset); 3189 } 3190 break; 3191 } 3192 3193 case Primitive::kPrimByte: { 3194 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 3195 Register out = locations->Out().AsRegister<Register>(); 3196 if (index.IsConstant()) { 3197 size_t offset = 3198 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 3199 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 3200 } else { 3201 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>())); 3202 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset); 3203 } 3204 break; 3205 } 3206 3207 case Primitive::kPrimShort: { 3208 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 3209 Register out = locations->Out().AsRegister<Register>(); 3210 if (index.IsConstant()) { 3211 size_t offset = 3212 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 3213 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 3214 } else { 3215 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2)); 3216 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset); 3217 } 3218 break; 3219 } 3220 3221 case Primitive::kPrimChar: { 3222 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 3223 Register out = locations->Out().AsRegister<Register>(); 3224 if (index.IsConstant()) { 3225 size_t offset = 3226 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 3227 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 3228 } else { 3229 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2)); 3230 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset); 3231 } 3232 break; 3233 } 3234 3235 case Primitive::kPrimInt: 3236 case Primitive::kPrimNot: { 3237 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t)); 3238 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 3239 Register out = locations->Out().AsRegister<Register>(); 3240 if (index.IsConstant()) { 3241 size_t offset = 3242 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3243 __ LoadFromOffset(kLoadWord, out, obj, offset); 3244 } else { 3245 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); 3246 __ LoadFromOffset(kLoadWord, out, IP, data_offset); 3247 } 3248 break; 3249 } 3250 3251 case Primitive::kPrimLong: { 3252 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 3253 Location out = locations->Out(); 3254 if (index.IsConstant()) { 3255 size_t offset = 3256 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3257 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset); 3258 } else { 3259 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); 3260 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset); 3261 } 3262 break; 3263 } 3264 3265 case Primitive::kPrimFloat: { 3266 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); 3267 Location out = locations->Out(); 3268 DCHECK(out.IsFpuRegister()); 3269 if (index.IsConstant()) { 3270 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3271 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), obj, offset); 3272 } else { 3273 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); 3274 __ LoadSFromOffset(out.AsFpuRegister<SRegister>(), IP, data_offset); 3275 } 3276 break; 3277 } 3278 3279 case Primitive::kPrimDouble: { 3280 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); 3281 Location out = locations->Out(); 3282 DCHECK(out.IsFpuRegisterPair()); 3283 if (index.IsConstant()) { 3284 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3285 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), obj, offset); 3286 } else { 3287 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); 3288 __ LoadDFromOffset(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), IP, data_offset); 3289 } 3290 break; 3291 } 3292 3293 case Primitive::kPrimVoid: 3294 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 3295 UNREACHABLE(); 3296 } 3297 codegen_->MaybeRecordImplicitNullCheck(instruction); 3298} 3299 3300void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) { 3301 Primitive::Type value_type = instruction->GetComponentType(); 3302 3303 bool needs_write_barrier = 3304 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 3305 bool needs_runtime_call = instruction->NeedsTypeCheck(); 3306 3307 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 3308 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall); 3309 if (needs_runtime_call) { 3310 InvokeRuntimeCallingConvention calling_convention; 3311 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3312 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 3313 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 3314 } else { 3315 locations->SetInAt(0, Location::RequiresRegister()); 3316 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 3317 if (Primitive::IsFloatingPointType(value_type)) { 3318 locations->SetInAt(2, Location::RequiresFpuRegister()); 3319 } else { 3320 locations->SetInAt(2, Location::RequiresRegister()); 3321 } 3322 3323 if (needs_write_barrier) { 3324 // Temporary registers for the write barrier. 3325 locations->AddTemp(Location::RequiresRegister()); 3326 locations->AddTemp(Location::RequiresRegister()); 3327 } 3328 } 3329} 3330 3331void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { 3332 LocationSummary* locations = instruction->GetLocations(); 3333 Register obj = locations->InAt(0).AsRegister<Register>(); 3334 Location index = locations->InAt(1); 3335 Primitive::Type value_type = instruction->GetComponentType(); 3336 bool needs_runtime_call = locations->WillCall(); 3337 bool needs_write_barrier = 3338 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 3339 3340 switch (value_type) { 3341 case Primitive::kPrimBoolean: 3342 case Primitive::kPrimByte: { 3343 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 3344 Register value = locations->InAt(2).AsRegister<Register>(); 3345 if (index.IsConstant()) { 3346 size_t offset = 3347 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 3348 __ StoreToOffset(kStoreByte, value, obj, offset); 3349 } else { 3350 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>())); 3351 __ StoreToOffset(kStoreByte, value, IP, data_offset); 3352 } 3353 break; 3354 } 3355 3356 case Primitive::kPrimShort: 3357 case Primitive::kPrimChar: { 3358 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 3359 Register value = locations->InAt(2).AsRegister<Register>(); 3360 if (index.IsConstant()) { 3361 size_t offset = 3362 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 3363 __ StoreToOffset(kStoreHalfword, value, obj, offset); 3364 } else { 3365 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_2)); 3366 __ StoreToOffset(kStoreHalfword, value, IP, data_offset); 3367 } 3368 break; 3369 } 3370 3371 case Primitive::kPrimInt: 3372 case Primitive::kPrimNot: { 3373 if (!needs_runtime_call) { 3374 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 3375 Register value = locations->InAt(2).AsRegister<Register>(); 3376 if (index.IsConstant()) { 3377 size_t offset = 3378 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3379 __ StoreToOffset(kStoreWord, value, obj, offset); 3380 } else { 3381 DCHECK(index.IsRegister()) << index; 3382 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); 3383 __ StoreToOffset(kStoreWord, value, IP, data_offset); 3384 } 3385 codegen_->MaybeRecordImplicitNullCheck(instruction); 3386 if (needs_write_barrier) { 3387 DCHECK_EQ(value_type, Primitive::kPrimNot); 3388 Register temp = locations->GetTemp(0).AsRegister<Register>(); 3389 Register card = locations->GetTemp(1).AsRegister<Register>(); 3390 codegen_->MarkGCCard(temp, card, obj, value); 3391 } 3392 } else { 3393 DCHECK_EQ(value_type, Primitive::kPrimNot); 3394 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), 3395 instruction, 3396 instruction->GetDexPc(), 3397 nullptr); 3398 } 3399 break; 3400 } 3401 3402 case Primitive::kPrimLong: { 3403 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 3404 Location value = locations->InAt(2); 3405 if (index.IsConstant()) { 3406 size_t offset = 3407 (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3408 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset); 3409 } else { 3410 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); 3411 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset); 3412 } 3413 break; 3414 } 3415 3416 case Primitive::kPrimFloat: { 3417 uint32_t data_offset = mirror::Array::DataOffset(sizeof(float)).Uint32Value(); 3418 Location value = locations->InAt(2); 3419 DCHECK(value.IsFpuRegister()); 3420 if (index.IsConstant()) { 3421 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 3422 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), obj, offset); 3423 } else { 3424 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_4)); 3425 __ StoreSToOffset(value.AsFpuRegister<SRegister>(), IP, data_offset); 3426 } 3427 break; 3428 } 3429 3430 case Primitive::kPrimDouble: { 3431 uint32_t data_offset = mirror::Array::DataOffset(sizeof(double)).Uint32Value(); 3432 Location value = locations->InAt(2); 3433 DCHECK(value.IsFpuRegisterPair()); 3434 if (index.IsConstant()) { 3435 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 3436 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), obj, offset); 3437 } else { 3438 __ add(IP, obj, ShifterOperand(index.AsRegister<Register>(), LSL, TIMES_8)); 3439 __ StoreDToOffset(FromLowSToD(value.AsFpuRegisterPairLow<SRegister>()), IP, data_offset); 3440 } 3441 3442 break; 3443 } 3444 3445 case Primitive::kPrimVoid: 3446 LOG(FATAL) << "Unreachable type " << value_type; 3447 UNREACHABLE(); 3448 } 3449 3450 // Ints and objects are handled in the switch. 3451 if (value_type != Primitive::kPrimInt && value_type != Primitive::kPrimNot) { 3452 codegen_->MaybeRecordImplicitNullCheck(instruction); 3453 } 3454} 3455 3456void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) { 3457 LocationSummary* locations = 3458 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3459 locations->SetInAt(0, Location::RequiresRegister()); 3460 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 3461} 3462 3463void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) { 3464 LocationSummary* locations = instruction->GetLocations(); 3465 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 3466 Register obj = locations->InAt(0).AsRegister<Register>(); 3467 Register out = locations->Out().AsRegister<Register>(); 3468 __ LoadFromOffset(kLoadWord, out, obj, offset); 3469 codegen_->MaybeRecordImplicitNullCheck(instruction); 3470} 3471 3472void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { 3473 LocationSummary* locations = 3474 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3475 locations->SetInAt(0, Location::RequiresRegister()); 3476 locations->SetInAt(1, Location::RequiresRegister()); 3477 if (instruction->HasUses()) { 3478 locations->SetOut(Location::SameAsFirstInput()); 3479 } 3480} 3481 3482void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { 3483 LocationSummary* locations = instruction->GetLocations(); 3484 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM( 3485 instruction, locations->InAt(0), locations->InAt(1)); 3486 codegen_->AddSlowPath(slow_path); 3487 3488 Register index = locations->InAt(0).AsRegister<Register>(); 3489 Register length = locations->InAt(1).AsRegister<Register>(); 3490 3491 __ cmp(index, ShifterOperand(length)); 3492 __ b(slow_path->GetEntryLabel(), CS); 3493} 3494 3495void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) { 3496 Label is_null; 3497 __ CompareAndBranchIfZero(value, &is_null); 3498 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value()); 3499 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift); 3500 __ strb(card, Address(card, temp)); 3501 __ Bind(&is_null); 3502} 3503 3504void LocationsBuilderARM::VisitTemporary(HTemporary* temp) { 3505 temp->SetLocations(nullptr); 3506} 3507 3508void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) { 3509 // Nothing to do, this is driven by the code generator. 3510 UNUSED(temp); 3511} 3512 3513void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) { 3514 UNUSED(instruction); 3515 LOG(FATAL) << "Unreachable"; 3516} 3517 3518void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) { 3519 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 3520} 3521 3522void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) { 3523 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 3524} 3525 3526void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) { 3527 HBasicBlock* block = instruction->GetBlock(); 3528 if (block->GetLoopInformation() != nullptr) { 3529 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 3530 // The back edge will generate the suspend check. 3531 return; 3532 } 3533 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 3534 // The goto will generate the suspend check. 3535 return; 3536 } 3537 GenerateSuspendCheck(instruction, nullptr); 3538} 3539 3540void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction, 3541 HBasicBlock* successor) { 3542 SuspendCheckSlowPathARM* slow_path = 3543 down_cast<SuspendCheckSlowPathARM*>(instruction->GetSlowPath()); 3544 if (slow_path == nullptr) { 3545 slow_path = new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor); 3546 instruction->SetSlowPath(slow_path); 3547 codegen_->AddSlowPath(slow_path); 3548 if (successor != nullptr) { 3549 DCHECK(successor->IsLoopHeader()); 3550 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(instruction); 3551 } 3552 } else { 3553 DCHECK_EQ(slow_path->GetSuccessor(), successor); 3554 } 3555 3556 __ LoadFromOffset( 3557 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value()); 3558 __ cmp(IP, ShifterOperand(0)); 3559 // TODO: Figure out the branch offsets and use cbz/cbnz. 3560 if (successor == nullptr) { 3561 __ b(slow_path->GetEntryLabel(), NE); 3562 __ Bind(slow_path->GetReturnLabel()); 3563 } else { 3564 __ b(codegen_->GetLabelOf(successor), EQ); 3565 __ b(slow_path->GetEntryLabel()); 3566 } 3567} 3568 3569ArmAssembler* ParallelMoveResolverARM::GetAssembler() const { 3570 return codegen_->GetAssembler(); 3571} 3572 3573void ParallelMoveResolverARM::EmitMove(size_t index) { 3574 MoveOperands* move = moves_.Get(index); 3575 Location source = move->GetSource(); 3576 Location destination = move->GetDestination(); 3577 3578 if (source.IsRegister()) { 3579 if (destination.IsRegister()) { 3580 __ Mov(destination.AsRegister<Register>(), source.AsRegister<Register>()); 3581 } else { 3582 DCHECK(destination.IsStackSlot()); 3583 __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), 3584 SP, destination.GetStackIndex()); 3585 } 3586 } else if (source.IsStackSlot()) { 3587 if (destination.IsRegister()) { 3588 __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), 3589 SP, source.GetStackIndex()); 3590 } else if (destination.IsFpuRegister()) { 3591 __ LoadSFromOffset(destination.AsFpuRegister<SRegister>(), SP, source.GetStackIndex()); 3592 } else { 3593 DCHECK(destination.IsStackSlot()); 3594 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 3595 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3596 } 3597 } else if (source.IsFpuRegister()) { 3598 if (destination.IsFpuRegister()) { 3599 __ vmovs(destination.AsFpuRegister<SRegister>(), source.AsFpuRegister<SRegister>()); 3600 } else { 3601 DCHECK(destination.IsStackSlot()); 3602 __ StoreSToOffset(source.AsFpuRegister<SRegister>(), SP, destination.GetStackIndex()); 3603 } 3604 } else if (source.IsDoubleStackSlot()) { 3605 if (destination.IsDoubleStackSlot()) { 3606 __ LoadDFromOffset(DTMP, SP, source.GetStackIndex()); 3607 __ StoreDToOffset(DTMP, SP, destination.GetStackIndex()); 3608 } else if (destination.IsRegisterPair()) { 3609 DCHECK(ExpectedPairLayout(destination)); 3610 __ LoadFromOffset( 3611 kLoadWordPair, destination.AsRegisterPairLow<Register>(), SP, source.GetStackIndex()); 3612 } else { 3613 DCHECK(destination.IsFpuRegisterPair()) << destination; 3614 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), 3615 SP, 3616 source.GetStackIndex()); 3617 } 3618 } else if (source.IsRegisterPair()) { 3619 if (destination.IsRegisterPair()) { 3620 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>()); 3621 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>()); 3622 } else { 3623 DCHECK(destination.IsDoubleStackSlot()) << destination; 3624 DCHECK(ExpectedPairLayout(source)); 3625 __ StoreToOffset( 3626 kStoreWordPair, source.AsRegisterPairLow<Register>(), SP, destination.GetStackIndex()); 3627 } 3628 } else if (source.IsFpuRegisterPair()) { 3629 if (destination.IsFpuRegisterPair()) { 3630 __ vmovd(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), 3631 FromLowSToD(source.AsFpuRegisterPairLow<SRegister>())); 3632 } else { 3633 DCHECK(destination.IsDoubleStackSlot()) << destination; 3634 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()), 3635 SP, 3636 destination.GetStackIndex()); 3637 } 3638 } else { 3639 DCHECK(source.IsConstant()) << source; 3640 HConstant* constant = source.GetConstant(); 3641 if (constant->IsIntConstant() || constant->IsNullConstant()) { 3642 int32_t value = CodeGenerator::GetInt32ValueOf(constant); 3643 if (destination.IsRegister()) { 3644 __ LoadImmediate(destination.AsRegister<Register>(), value); 3645 } else { 3646 DCHECK(destination.IsStackSlot()); 3647 __ LoadImmediate(IP, value); 3648 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3649 } 3650 } else if (constant->IsLongConstant()) { 3651 int64_t value = constant->AsLongConstant()->GetValue(); 3652 if (destination.IsRegisterPair()) { 3653 __ LoadImmediate(destination.AsRegisterPairLow<Register>(), Low32Bits(value)); 3654 __ LoadImmediate(destination.AsRegisterPairHigh<Register>(), High32Bits(value)); 3655 } else { 3656 DCHECK(destination.IsDoubleStackSlot()) << destination; 3657 __ LoadImmediate(IP, Low32Bits(value)); 3658 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3659 __ LoadImmediate(IP, High32Bits(value)); 3660 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize)); 3661 } 3662 } else if (constant->IsDoubleConstant()) { 3663 double value = constant->AsDoubleConstant()->GetValue(); 3664 if (destination.IsFpuRegisterPair()) { 3665 __ LoadDImmediate(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), value); 3666 } else { 3667 DCHECK(destination.IsDoubleStackSlot()) << destination; 3668 uint64_t int_value = bit_cast<uint64_t, double>(value); 3669 __ LoadImmediate(IP, Low32Bits(int_value)); 3670 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3671 __ LoadImmediate(IP, High32Bits(int_value)); 3672 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize)); 3673 } 3674 } else { 3675 DCHECK(constant->IsFloatConstant()) << constant->DebugName(); 3676 float value = constant->AsFloatConstant()->GetValue(); 3677 if (destination.IsFpuRegister()) { 3678 __ LoadSImmediate(destination.AsFpuRegister<SRegister>(), value); 3679 } else { 3680 DCHECK(destination.IsStackSlot()); 3681 __ LoadImmediate(IP, bit_cast<int32_t, float>(value)); 3682 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 3683 } 3684 } 3685 } 3686} 3687 3688void ParallelMoveResolverARM::Exchange(Register reg, int mem) { 3689 __ Mov(IP, reg); 3690 __ LoadFromOffset(kLoadWord, reg, SP, mem); 3691 __ StoreToOffset(kStoreWord, IP, SP, mem); 3692} 3693 3694void ParallelMoveResolverARM::Exchange(int mem1, int mem2) { 3695 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters()); 3696 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; 3697 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()), 3698 SP, mem1 + stack_offset); 3699 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset); 3700 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()), 3701 SP, mem2 + stack_offset); 3702 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset); 3703} 3704 3705void ParallelMoveResolverARM::EmitSwap(size_t index) { 3706 MoveOperands* move = moves_.Get(index); 3707 Location source = move->GetSource(); 3708 Location destination = move->GetDestination(); 3709 3710 if (source.IsRegister() && destination.IsRegister()) { 3711 DCHECK_NE(source.AsRegister<Register>(), IP); 3712 DCHECK_NE(destination.AsRegister<Register>(), IP); 3713 __ Mov(IP, source.AsRegister<Register>()); 3714 __ Mov(source.AsRegister<Register>(), destination.AsRegister<Register>()); 3715 __ Mov(destination.AsRegister<Register>(), IP); 3716 } else if (source.IsRegister() && destination.IsStackSlot()) { 3717 Exchange(source.AsRegister<Register>(), destination.GetStackIndex()); 3718 } else if (source.IsStackSlot() && destination.IsRegister()) { 3719 Exchange(destination.AsRegister<Register>(), source.GetStackIndex()); 3720 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 3721 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 3722 } else if (source.IsFpuRegister() && destination.IsFpuRegister()) { 3723 __ vmovrs(IP, source.AsFpuRegister<SRegister>()); 3724 __ vmovs(source.AsFpuRegister<SRegister>(), destination.AsFpuRegister<SRegister>()); 3725 __ vmovsr(destination.AsFpuRegister<SRegister>(), IP); 3726 } else if (source.IsRegisterPair() && destination.IsRegisterPair()) { 3727 __ vmovdrr(DTMP, source.AsRegisterPairLow<Register>(), source.AsRegisterPairHigh<Register>()); 3728 __ Mov(source.AsRegisterPairLow<Register>(), destination.AsRegisterPairLow<Register>()); 3729 __ Mov(source.AsRegisterPairHigh<Register>(), destination.AsRegisterPairHigh<Register>()); 3730 __ vmovrrd(destination.AsRegisterPairLow<Register>(), 3731 destination.AsRegisterPairHigh<Register>(), 3732 DTMP); 3733 } else if (source.IsRegisterPair() || destination.IsRegisterPair()) { 3734 Register low_reg = source.IsRegisterPair() 3735 ? source.AsRegisterPairLow<Register>() 3736 : destination.AsRegisterPairLow<Register>(); 3737 int mem = source.IsRegisterPair() 3738 ? destination.GetStackIndex() 3739 : source.GetStackIndex(); 3740 DCHECK(ExpectedPairLayout(source.IsRegisterPair() ? source : destination)); 3741 __ vmovdrr(DTMP, low_reg, static_cast<Register>(low_reg + 1)); 3742 __ LoadFromOffset(kLoadWordPair, low_reg, SP, mem); 3743 __ StoreDToOffset(DTMP, SP, mem); 3744 } else if (source.IsFpuRegisterPair() && destination.IsFpuRegisterPair()) { 3745 DRegister first = FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()); 3746 DRegister second = FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()); 3747 __ vmovd(DTMP, first); 3748 __ vmovd(first, second); 3749 __ vmovd(second, DTMP); 3750 } else if (source.IsFpuRegisterPair() || destination.IsFpuRegisterPair()) { 3751 DRegister reg = source.IsFpuRegisterPair() 3752 ? FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()) 3753 : FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()); 3754 int mem = source.IsFpuRegisterPair() 3755 ? destination.GetStackIndex() 3756 : source.GetStackIndex(); 3757 __ vmovd(DTMP, reg); 3758 __ LoadDFromOffset(reg, SP, mem); 3759 __ StoreDToOffset(DTMP, SP, mem); 3760 } else if (source.IsFpuRegister() || destination.IsFpuRegister()) { 3761 SRegister reg = source.IsFpuRegister() ? source.AsFpuRegister<SRegister>() 3762 : destination.AsFpuRegister<SRegister>(); 3763 int mem = source.IsFpuRegister() 3764 ? destination.GetStackIndex() 3765 : source.GetStackIndex(); 3766 3767 __ vmovrs(IP, reg); 3768 __ LoadSFromOffset(reg, SP, mem); 3769 __ StoreToOffset(kStoreWord, IP, SP, mem); 3770 } else if (source.IsDoubleStackSlot() && destination.IsDoubleStackSlot()) { 3771 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 3772 Exchange(source.GetHighStackIndex(kArmWordSize), destination.GetHighStackIndex(kArmWordSize)); 3773 } else { 3774 LOG(FATAL) << "Unimplemented" << source << " <-> " << destination; 3775 } 3776} 3777 3778void ParallelMoveResolverARM::SpillScratch(int reg) { 3779 __ Push(static_cast<Register>(reg)); 3780} 3781 3782void ParallelMoveResolverARM::RestoreScratch(int reg) { 3783 __ Pop(static_cast<Register>(reg)); 3784} 3785 3786void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) { 3787 LocationSummary::CallKind call_kind = cls->CanCallRuntime() 3788 ? LocationSummary::kCallOnSlowPath 3789 : LocationSummary::kNoCall; 3790 LocationSummary* locations = 3791 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); 3792 locations->SetOut(Location::RequiresRegister()); 3793} 3794 3795void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { 3796 Register out = cls->GetLocations()->Out().AsRegister<Register>(); 3797 if (cls->IsReferrersClass()) { 3798 DCHECK(!cls->CanCallRuntime()); 3799 DCHECK(!cls->MustGenerateClinitCheck()); 3800 codegen_->LoadCurrentMethod(out); 3801 __ LoadFromOffset(kLoadWord, out, out, ArtMethod::DeclaringClassOffset().Int32Value()); 3802 } else { 3803 DCHECK(cls->CanCallRuntime()); 3804 codegen_->LoadCurrentMethod(out); 3805 __ LoadFromOffset( 3806 kLoadWord, out, out, ArtMethod::DexCacheResolvedTypesOffset().Int32Value()); 3807 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); 3808 3809 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( 3810 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); 3811 codegen_->AddSlowPath(slow_path); 3812 __ cmp(out, ShifterOperand(0)); 3813 __ b(slow_path->GetEntryLabel(), EQ); 3814 if (cls->MustGenerateClinitCheck()) { 3815 GenerateClassInitializationCheck(slow_path, out); 3816 } else { 3817 __ Bind(slow_path->GetExitLabel()); 3818 } 3819 } 3820} 3821 3822void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) { 3823 LocationSummary* locations = 3824 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath); 3825 locations->SetInAt(0, Location::RequiresRegister()); 3826 if (check->HasUses()) { 3827 locations->SetOut(Location::SameAsFirstInput()); 3828 } 3829} 3830 3831void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) { 3832 // We assume the class is not null. 3833 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( 3834 check->GetLoadClass(), check, check->GetDexPc(), true); 3835 codegen_->AddSlowPath(slow_path); 3836 GenerateClassInitializationCheck(slow_path, 3837 check->GetLocations()->InAt(0).AsRegister<Register>()); 3838} 3839 3840void InstructionCodeGeneratorARM::GenerateClassInitializationCheck( 3841 SlowPathCodeARM* slow_path, Register class_reg) { 3842 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value()); 3843 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized)); 3844 __ b(slow_path->GetEntryLabel(), LT); 3845 // Even if the initialized flag is set, we may be in a situation where caches are not synced 3846 // properly. Therefore, we do a memory fence. 3847 __ dmb(ISH); 3848 __ Bind(slow_path->GetExitLabel()); 3849} 3850 3851void LocationsBuilderARM::VisitLoadString(HLoadString* load) { 3852 LocationSummary* locations = 3853 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath); 3854 locations->SetOut(Location::RequiresRegister()); 3855} 3856 3857void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { 3858 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load); 3859 codegen_->AddSlowPath(slow_path); 3860 3861 Register out = load->GetLocations()->Out().AsRegister<Register>(); 3862 codegen_->LoadCurrentMethod(out); 3863 __ LoadFromOffset(kLoadWord, out, out, ArtMethod::DeclaringClassOffset().Int32Value()); 3864 __ LoadFromOffset(kLoadWord, out, out, mirror::Class::DexCacheStringsOffset().Int32Value()); 3865 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex())); 3866 __ cmp(out, ShifterOperand(0)); 3867 __ b(slow_path->GetEntryLabel(), EQ); 3868 __ Bind(slow_path->GetExitLabel()); 3869} 3870 3871void LocationsBuilderARM::VisitLoadException(HLoadException* load) { 3872 LocationSummary* locations = 3873 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall); 3874 locations->SetOut(Location::RequiresRegister()); 3875} 3876 3877void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) { 3878 Register out = load->GetLocations()->Out().AsRegister<Register>(); 3879 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value(); 3880 __ LoadFromOffset(kLoadWord, out, TR, offset); 3881 __ LoadImmediate(IP, 0); 3882 __ StoreToOffset(kStoreWord, IP, TR, offset); 3883} 3884 3885void LocationsBuilderARM::VisitThrow(HThrow* instruction) { 3886 LocationSummary* locations = 3887 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3888 InvokeRuntimeCallingConvention calling_convention; 3889 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3890} 3891 3892void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) { 3893 codegen_->InvokeRuntime( 3894 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc(), nullptr); 3895} 3896 3897void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) { 3898 LocationSummary::CallKind call_kind = instruction->IsClassFinal() 3899 ? LocationSummary::kNoCall 3900 : LocationSummary::kCallOnSlowPath; 3901 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 3902 locations->SetInAt(0, Location::RequiresRegister()); 3903 locations->SetInAt(1, Location::RequiresRegister()); 3904 // The out register is used as a temporary, so it overlaps with the inputs. 3905 locations->SetOut(Location::RequiresRegister(), Location::kOutputOverlap); 3906} 3907 3908void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { 3909 LocationSummary* locations = instruction->GetLocations(); 3910 Register obj = locations->InAt(0).AsRegister<Register>(); 3911 Register cls = locations->InAt(1).AsRegister<Register>(); 3912 Register out = locations->Out().AsRegister<Register>(); 3913 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 3914 Label done, zero; 3915 SlowPathCodeARM* slow_path = nullptr; 3916 3917 // Return 0 if `obj` is null. 3918 // avoid null check if we know obj is not null. 3919 if (instruction->MustDoNullCheck()) { 3920 __ cmp(obj, ShifterOperand(0)); 3921 __ b(&zero, EQ); 3922 } 3923 // Compare the class of `obj` with `cls`. 3924 __ LoadFromOffset(kLoadWord, out, obj, class_offset); 3925 __ cmp(out, ShifterOperand(cls)); 3926 if (instruction->IsClassFinal()) { 3927 // Classes must be equal for the instanceof to succeed. 3928 __ b(&zero, NE); 3929 __ LoadImmediate(out, 1); 3930 __ b(&done); 3931 } else { 3932 // If the classes are not equal, we go into a slow path. 3933 DCHECK(locations->OnlyCallsOnSlowPath()); 3934 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( 3935 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc()); 3936 codegen_->AddSlowPath(slow_path); 3937 __ b(slow_path->GetEntryLabel(), NE); 3938 __ LoadImmediate(out, 1); 3939 __ b(&done); 3940 } 3941 3942 if (instruction->MustDoNullCheck() || instruction->IsClassFinal()) { 3943 __ Bind(&zero); 3944 __ LoadImmediate(out, 0); 3945 } 3946 3947 if (slow_path != nullptr) { 3948 __ Bind(slow_path->GetExitLabel()); 3949 } 3950 __ Bind(&done); 3951} 3952 3953void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) { 3954 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 3955 instruction, LocationSummary::kCallOnSlowPath); 3956 locations->SetInAt(0, Location::RequiresRegister()); 3957 locations->SetInAt(1, Location::RequiresRegister()); 3958 locations->AddTemp(Location::RequiresRegister()); 3959} 3960 3961void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { 3962 LocationSummary* locations = instruction->GetLocations(); 3963 Register obj = locations->InAt(0).AsRegister<Register>(); 3964 Register cls = locations->InAt(1).AsRegister<Register>(); 3965 Register temp = locations->GetTemp(0).AsRegister<Register>(); 3966 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 3967 3968 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( 3969 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc()); 3970 codegen_->AddSlowPath(slow_path); 3971 3972 // avoid null check if we know obj is not null. 3973 if (instruction->MustDoNullCheck()) { 3974 __ cmp(obj, ShifterOperand(0)); 3975 __ b(slow_path->GetExitLabel(), EQ); 3976 } 3977 // Compare the class of `obj` with `cls`. 3978 __ LoadFromOffset(kLoadWord, temp, obj, class_offset); 3979 __ cmp(temp, ShifterOperand(cls)); 3980 __ b(slow_path->GetEntryLabel(), NE); 3981 __ Bind(slow_path->GetExitLabel()); 3982} 3983 3984void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) { 3985 LocationSummary* locations = 3986 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3987 InvokeRuntimeCallingConvention calling_convention; 3988 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3989} 3990 3991void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) { 3992 codegen_->InvokeRuntime(instruction->IsEnter() 3993 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject), 3994 instruction, 3995 instruction->GetDexPc(), 3996 nullptr); 3997} 3998 3999void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } 4000void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } 4001void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } 4002 4003void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) { 4004 LocationSummary* locations = 4005 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 4006 DCHECK(instruction->GetResultType() == Primitive::kPrimInt 4007 || instruction->GetResultType() == Primitive::kPrimLong); 4008 locations->SetInAt(0, Location::RequiresRegister()); 4009 locations->SetInAt(1, Location::RequiresRegister()); 4010 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 4011} 4012 4013void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) { 4014 HandleBitwiseOperation(instruction); 4015} 4016 4017void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) { 4018 HandleBitwiseOperation(instruction); 4019} 4020 4021void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) { 4022 HandleBitwiseOperation(instruction); 4023} 4024 4025void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) { 4026 LocationSummary* locations = instruction->GetLocations(); 4027 4028 if (instruction->GetResultType() == Primitive::kPrimInt) { 4029 Register first = locations->InAt(0).AsRegister<Register>(); 4030 Register second = locations->InAt(1).AsRegister<Register>(); 4031 Register out = locations->Out().AsRegister<Register>(); 4032 if (instruction->IsAnd()) { 4033 __ and_(out, first, ShifterOperand(second)); 4034 } else if (instruction->IsOr()) { 4035 __ orr(out, first, ShifterOperand(second)); 4036 } else { 4037 DCHECK(instruction->IsXor()); 4038 __ eor(out, first, ShifterOperand(second)); 4039 } 4040 } else { 4041 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); 4042 Location first = locations->InAt(0); 4043 Location second = locations->InAt(1); 4044 Location out = locations->Out(); 4045 if (instruction->IsAnd()) { 4046 __ and_(out.AsRegisterPairLow<Register>(), 4047 first.AsRegisterPairLow<Register>(), 4048 ShifterOperand(second.AsRegisterPairLow<Register>())); 4049 __ and_(out.AsRegisterPairHigh<Register>(), 4050 first.AsRegisterPairHigh<Register>(), 4051 ShifterOperand(second.AsRegisterPairHigh<Register>())); 4052 } else if (instruction->IsOr()) { 4053 __ orr(out.AsRegisterPairLow<Register>(), 4054 first.AsRegisterPairLow<Register>(), 4055 ShifterOperand(second.AsRegisterPairLow<Register>())); 4056 __ orr(out.AsRegisterPairHigh<Register>(), 4057 first.AsRegisterPairHigh<Register>(), 4058 ShifterOperand(second.AsRegisterPairHigh<Register>())); 4059 } else { 4060 DCHECK(instruction->IsXor()); 4061 __ eor(out.AsRegisterPairLow<Register>(), 4062 first.AsRegisterPairLow<Register>(), 4063 ShifterOperand(second.AsRegisterPairLow<Register>())); 4064 __ eor(out.AsRegisterPairHigh<Register>(), 4065 first.AsRegisterPairHigh<Register>(), 4066 ShifterOperand(second.AsRegisterPairHigh<Register>())); 4067 } 4068 } 4069} 4070 4071void CodeGeneratorARM::GenerateStaticOrDirectCall(HInvokeStaticOrDirect* invoke, Register temp) { 4072 DCHECK_EQ(temp, kArtMethodRegister); 4073 4074 // TODO: Implement all kinds of calls: 4075 // 1) boot -> boot 4076 // 2) app -> boot 4077 // 3) app -> app 4078 // 4079 // Currently we implement the app -> app logic, which looks up in the resolve cache. 4080 4081 if (invoke->IsStringInit()) { 4082 // temp = thread->string_init_entrypoint 4083 __ LoadFromOffset(kLoadWord, temp, TR, invoke->GetStringInitOffset()); 4084 // LR = temp[offset_of_quick_compiled_code] 4085 __ LoadFromOffset(kLoadWord, LR, temp, 4086 ArtMethod::EntryPointFromQuickCompiledCodeOffset( 4087 kArmWordSize).Int32Value()); 4088 // LR() 4089 __ blx(LR); 4090 } else { 4091 // temp = method; 4092 LoadCurrentMethod(temp); 4093 if (!invoke->IsRecursive()) { 4094 // temp = temp->dex_cache_resolved_methods_; 4095 __ LoadFromOffset( 4096 kLoadWord, temp, temp, ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); 4097 // temp = temp[index_in_cache] 4098 __ LoadFromOffset( 4099 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetDexMethodIndex())); 4100 // LR = temp[offset_of_quick_compiled_code] 4101 __ LoadFromOffset(kLoadWord, LR, temp, ArtMethod::EntryPointFromQuickCompiledCodeOffset( 4102 kArmWordSize).Int32Value()); 4103 // LR() 4104 __ blx(LR); 4105 } else { 4106 __ bl(GetFrameEntryLabel()); 4107 } 4108 } 4109 4110 DCHECK(!IsLeafMethod()); 4111} 4112 4113void LocationsBuilderARM::VisitBoundType(HBoundType* instruction) { 4114 // Nothing to do, this should be removed during prepare for register allocator. 4115 UNUSED(instruction); 4116 LOG(FATAL) << "Unreachable"; 4117} 4118 4119void InstructionCodeGeneratorARM::VisitBoundType(HBoundType* instruction) { 4120 // Nothing to do, this should be removed during prepare for register allocator. 4121 UNUSED(instruction); 4122 LOG(FATAL) << "Unreachable"; 4123} 4124 4125} // namespace arm 4126} // namespace art 4127