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