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