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