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