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