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