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