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