code_generator_arm.cc revision cff137481eda0eb8dbdf9d2a303ae2bdac2c7322
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 "entrypoints/quick/quick_entrypoints.h" 20#include "gc/accounting/card_table.h" 21#include "mirror/array-inl.h" 22#include "mirror/art_method.h" 23#include "mirror/class.h" 24#include "thread.h" 25#include "utils/arm/assembler_arm.h" 26#include "utils/arm/managed_register_arm.h" 27#include "utils/assembler.h" 28#include "utils/stack_checks.h" 29 30namespace art { 31 32namespace arm { 33 34static DRegister FromLowSToD(SRegister reg) { 35 DCHECK_EQ(reg % 2, 0); 36 return static_cast<DRegister>(reg / 2); 37} 38 39static constexpr bool kExplicitStackOverflowCheck = false; 40 41static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7 42static constexpr int kCurrentMethodStackOffset = 0; 43 44static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2, R3 }; 45static constexpr size_t kRuntimeParameterCoreRegistersLength = 46 arraysize(kRuntimeParameterCoreRegisters); 47static constexpr SRegister kRuntimeParameterFpuRegisters[] = { }; 48static constexpr size_t kRuntimeParameterFpuRegistersLength = 0; 49 50class InvokeRuntimeCallingConvention : public CallingConvention<Register, SRegister> { 51 public: 52 InvokeRuntimeCallingConvention() 53 : CallingConvention(kRuntimeParameterCoreRegisters, 54 kRuntimeParameterCoreRegistersLength, 55 kRuntimeParameterFpuRegisters, 56 kRuntimeParameterFpuRegistersLength) {} 57 58 private: 59 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 60}; 61 62#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())-> 63#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kArmWordSize, x).Int32Value() 64 65class SlowPathCodeARM : public SlowPathCode { 66 public: 67 SlowPathCodeARM() : entry_label_(), exit_label_() {} 68 69 Label* GetEntryLabel() { return &entry_label_; } 70 Label* GetExitLabel() { return &exit_label_; } 71 72 private: 73 Label entry_label_; 74 Label exit_label_; 75 76 DISALLOW_COPY_AND_ASSIGN(SlowPathCodeARM); 77}; 78 79class NullCheckSlowPathARM : public SlowPathCodeARM { 80 public: 81 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {} 82 83 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 84 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 85 __ Bind(GetEntryLabel()); 86 arm_codegen->InvokeRuntime( 87 QUICK_ENTRY_POINT(pThrowNullPointer), instruction_, instruction_->GetDexPc()); 88 } 89 90 private: 91 HNullCheck* const instruction_; 92 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM); 93}; 94 95class DivZeroCheckSlowPathARM : public SlowPathCodeARM { 96 public: 97 explicit DivZeroCheckSlowPathARM(HDivZeroCheck* instruction) : instruction_(instruction) {} 98 99 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 100 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 101 __ Bind(GetEntryLabel()); 102 arm_codegen->InvokeRuntime( 103 QUICK_ENTRY_POINT(pThrowDivZero), instruction_, instruction_->GetDexPc()); 104 } 105 106 private: 107 HDivZeroCheck* const instruction_; 108 DISALLOW_COPY_AND_ASSIGN(DivZeroCheckSlowPathARM); 109}; 110 111class StackOverflowCheckSlowPathARM : public SlowPathCodeARM { 112 public: 113 StackOverflowCheckSlowPathARM() {} 114 115 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 116 __ Bind(GetEntryLabel()); 117 __ LoadFromOffset(kLoadWord, PC, TR, 118 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value()); 119 } 120 121 private: 122 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM); 123}; 124 125class SuspendCheckSlowPathARM : public SlowPathCodeARM { 126 public: 127 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor) 128 : instruction_(instruction), successor_(successor) {} 129 130 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 131 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 132 __ Bind(GetEntryLabel()); 133 codegen->SaveLiveRegisters(instruction_->GetLocations()); 134 arm_codegen->InvokeRuntime( 135 QUICK_ENTRY_POINT(pTestSuspend), instruction_, instruction_->GetDexPc()); 136 codegen->RestoreLiveRegisters(instruction_->GetLocations()); 137 if (successor_ == nullptr) { 138 __ b(GetReturnLabel()); 139 } else { 140 __ b(arm_codegen->GetLabelOf(successor_)); 141 } 142 } 143 144 Label* GetReturnLabel() { 145 DCHECK(successor_ == nullptr); 146 return &return_label_; 147 } 148 149 private: 150 HSuspendCheck* const instruction_; 151 // If not null, the block to branch to after the suspend check. 152 HBasicBlock* const successor_; 153 154 // If `successor_` is null, the label to branch to after the suspend check. 155 Label return_label_; 156 157 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM); 158}; 159 160class BoundsCheckSlowPathARM : public SlowPathCodeARM { 161 public: 162 BoundsCheckSlowPathARM(HBoundsCheck* instruction, 163 Location index_location, 164 Location length_location) 165 : instruction_(instruction), 166 index_location_(index_location), 167 length_location_(length_location) {} 168 169 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 170 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 171 __ Bind(GetEntryLabel()); 172 // We're moving two locations to locations that could overlap, so we need a parallel 173 // move resolver. 174 InvokeRuntimeCallingConvention calling_convention; 175 codegen->EmitParallelMoves( 176 index_location_, 177 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 178 length_location_, 179 Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 180 arm_codegen->InvokeRuntime( 181 QUICK_ENTRY_POINT(pThrowArrayBounds), instruction_, instruction_->GetDexPc()); 182 } 183 184 private: 185 HBoundsCheck* const instruction_; 186 const Location index_location_; 187 const Location length_location_; 188 189 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM); 190}; 191 192class LoadClassSlowPathARM : public SlowPathCodeARM { 193 public: 194 LoadClassSlowPathARM(HLoadClass* cls, 195 HInstruction* at, 196 uint32_t dex_pc, 197 bool do_clinit) 198 : cls_(cls), at_(at), dex_pc_(dex_pc), do_clinit_(do_clinit) { 199 DCHECK(at->IsLoadClass() || at->IsClinitCheck()); 200 } 201 202 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 203 LocationSummary* locations = at_->GetLocations(); 204 205 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 206 __ Bind(GetEntryLabel()); 207 codegen->SaveLiveRegisters(locations); 208 209 InvokeRuntimeCallingConvention calling_convention; 210 __ LoadImmediate(calling_convention.GetRegisterAt(0), cls_->GetTypeIndex()); 211 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 212 int32_t entry_point_offset = do_clinit_ 213 ? QUICK_ENTRY_POINT(pInitializeStaticStorage) 214 : QUICK_ENTRY_POINT(pInitializeType); 215 arm_codegen->InvokeRuntime(entry_point_offset, at_, dex_pc_); 216 217 // Move the class to the desired location. 218 Location out = locations->Out(); 219 if (out.IsValid()) { 220 DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg())); 221 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); 222 } 223 codegen->RestoreLiveRegisters(locations); 224 __ b(GetExitLabel()); 225 } 226 227 private: 228 // The class this slow path will load. 229 HLoadClass* const cls_; 230 231 // The instruction where this slow path is happening. 232 // (Might be the load class or an initialization check). 233 HInstruction* const at_; 234 235 // The dex PC of `at_`. 236 const uint32_t dex_pc_; 237 238 // Whether to initialize the class. 239 const bool do_clinit_; 240 241 DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM); 242}; 243 244class LoadStringSlowPathARM : public SlowPathCodeARM { 245 public: 246 explicit LoadStringSlowPathARM(HLoadString* instruction) : instruction_(instruction) {} 247 248 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 249 LocationSummary* locations = instruction_->GetLocations(); 250 DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 251 252 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 253 __ Bind(GetEntryLabel()); 254 codegen->SaveLiveRegisters(locations); 255 256 InvokeRuntimeCallingConvention calling_convention; 257 arm_codegen->LoadCurrentMethod(calling_convention.GetRegisterAt(0)); 258 __ LoadImmediate(calling_convention.GetRegisterAt(1), instruction_->GetStringIndex()); 259 arm_codegen->InvokeRuntime( 260 QUICK_ENTRY_POINT(pResolveString), instruction_, instruction_->GetDexPc()); 261 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); 262 263 codegen->RestoreLiveRegisters(locations); 264 __ b(GetExitLabel()); 265 } 266 267 private: 268 HLoadString* const instruction_; 269 270 DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM); 271}; 272 273class TypeCheckSlowPathARM : public SlowPathCodeARM { 274 public: 275 TypeCheckSlowPathARM(HInstruction* instruction, 276 Location class_to_check, 277 Location object_class, 278 uint32_t dex_pc) 279 : instruction_(instruction), 280 class_to_check_(class_to_check), 281 object_class_(object_class), 282 dex_pc_(dex_pc) {} 283 284 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 285 LocationSummary* locations = instruction_->GetLocations(); 286 DCHECK(instruction_->IsCheckCast() 287 || !locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); 288 289 CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); 290 __ Bind(GetEntryLabel()); 291 codegen->SaveLiveRegisters(locations); 292 293 // We're moving two locations to locations that could overlap, so we need a parallel 294 // move resolver. 295 InvokeRuntimeCallingConvention calling_convention; 296 codegen->EmitParallelMoves( 297 class_to_check_, 298 Location::RegisterLocation(calling_convention.GetRegisterAt(0)), 299 object_class_, 300 Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 301 302 if (instruction_->IsInstanceOf()) { 303 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pInstanceofNonTrivial), instruction_, dex_pc_); 304 arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); 305 } else { 306 DCHECK(instruction_->IsCheckCast()); 307 arm_codegen->InvokeRuntime(QUICK_ENTRY_POINT(pCheckCast), instruction_, dex_pc_); 308 } 309 310 codegen->RestoreLiveRegisters(locations); 311 __ b(GetExitLabel()); 312 } 313 314 private: 315 HInstruction* const instruction_; 316 const Location class_to_check_; 317 const Location object_class_; 318 uint32_t dex_pc_; 319 320 DISALLOW_COPY_AND_ASSIGN(TypeCheckSlowPathARM); 321}; 322 323#undef __ 324 325#undef __ 326#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> 327 328inline Condition ARMCondition(IfCondition cond) { 329 switch (cond) { 330 case kCondEQ: return EQ; 331 case kCondNE: return NE; 332 case kCondLT: return LT; 333 case kCondLE: return LE; 334 case kCondGT: return GT; 335 case kCondGE: return GE; 336 default: 337 LOG(FATAL) << "Unknown if condition"; 338 } 339 return EQ; // Unreachable. 340} 341 342inline Condition ARMOppositeCondition(IfCondition cond) { 343 switch (cond) { 344 case kCondEQ: return NE; 345 case kCondNE: return EQ; 346 case kCondLT: return GE; 347 case kCondLE: return GT; 348 case kCondGT: return LE; 349 case kCondGE: return LT; 350 default: 351 LOG(FATAL) << "Unknown if condition"; 352 } 353 return EQ; // Unreachable. 354} 355 356void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const { 357 stream << ArmManagedRegister::FromCoreRegister(Register(reg)); 358} 359 360void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 361 stream << ArmManagedRegister::FromSRegister(SRegister(reg)); 362} 363 364size_t CodeGeneratorARM::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { 365 __ StoreToOffset(kStoreWord, static_cast<Register>(reg_id), SP, stack_index); 366 return kArmWordSize; 367} 368 369size_t CodeGeneratorARM::RestoreCoreRegister(size_t stack_index, uint32_t reg_id) { 370 __ LoadFromOffset(kLoadWord, static_cast<Register>(reg_id), SP, stack_index); 371 return kArmWordSize; 372} 373 374CodeGeneratorARM::CodeGeneratorARM(HGraph* graph) 375 : CodeGenerator(graph, kNumberOfCoreRegisters, kNumberOfSRegisters, kNumberOfRegisterPairs), 376 block_labels_(graph->GetArena(), 0), 377 location_builder_(graph, this), 378 instruction_visitor_(graph, this), 379 move_resolver_(graph->GetArena(), this), 380 assembler_(true) {} 381 382size_t CodeGeneratorARM::FrameEntrySpillSize() const { 383 return kNumberOfPushedRegistersAtEntry * kArmWordSize; 384} 385 386Location CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type) const { 387 switch (type) { 388 case Primitive::kPrimLong: { 389 size_t reg = FindFreeEntry(blocked_register_pairs_, kNumberOfRegisterPairs); 390 ArmManagedRegister pair = 391 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg)); 392 DCHECK(!blocked_core_registers_[pair.AsRegisterPairLow()]); 393 DCHECK(!blocked_core_registers_[pair.AsRegisterPairHigh()]); 394 395 blocked_core_registers_[pair.AsRegisterPairLow()] = true; 396 blocked_core_registers_[pair.AsRegisterPairHigh()] = true; 397 UpdateBlockedPairRegisters(); 398 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 399 } 400 401 case Primitive::kPrimByte: 402 case Primitive::kPrimBoolean: 403 case Primitive::kPrimChar: 404 case Primitive::kPrimShort: 405 case Primitive::kPrimInt: 406 case Primitive::kPrimNot: { 407 int reg = FindFreeEntry(blocked_core_registers_, kNumberOfCoreRegisters); 408 // Block all register pairs that contain `reg`. 409 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 410 ArmManagedRegister current = 411 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 412 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) { 413 blocked_register_pairs_[i] = true; 414 } 415 } 416 return Location::RegisterLocation(reg); 417 } 418 419 case Primitive::kPrimFloat: { 420 int reg = FindFreeEntry(blocked_fpu_registers_, kNumberOfSRegisters); 421 return Location::FpuRegisterLocation(reg); 422 } 423 424 case Primitive::kPrimDouble: { 425 int reg = FindTwoFreeConsecutiveAlignedEntries(blocked_fpu_registers_, kNumberOfSRegisters); 426 DCHECK_EQ(reg % 2, 0); 427 return Location::FpuRegisterPairLocation(reg, reg + 1); 428 } 429 430 case Primitive::kPrimVoid: 431 LOG(FATAL) << "Unreachable type " << type; 432 } 433 434 return Location(); 435} 436 437void CodeGeneratorARM::SetupBlockedRegisters() const { 438 // Don't allocate the dalvik style register pair passing. 439 blocked_register_pairs_[R1_R2] = true; 440 441 // Stack register, LR and PC are always reserved. 442 blocked_core_registers_[SP] = true; 443 blocked_core_registers_[LR] = true; 444 blocked_core_registers_[PC] = true; 445 446 // Reserve thread register. 447 blocked_core_registers_[TR] = true; 448 449 // Reserve temp register. 450 blocked_core_registers_[IP] = true; 451 452 // TODO: We currently don't use Quick's callee saved registers. 453 // We always save and restore R6 and R7 to make sure we can use three 454 // register pairs for long operations. 455 blocked_core_registers_[R4] = true; 456 blocked_core_registers_[R5] = true; 457 blocked_core_registers_[R8] = true; 458 blocked_core_registers_[R10] = true; 459 blocked_core_registers_[R11] = true; 460 461 blocked_fpu_registers_[S16] = true; 462 blocked_fpu_registers_[S17] = true; 463 blocked_fpu_registers_[S18] = true; 464 blocked_fpu_registers_[S19] = true; 465 blocked_fpu_registers_[S20] = true; 466 blocked_fpu_registers_[S21] = true; 467 blocked_fpu_registers_[S22] = true; 468 blocked_fpu_registers_[S23] = true; 469 blocked_fpu_registers_[S24] = true; 470 blocked_fpu_registers_[S25] = true; 471 blocked_fpu_registers_[S26] = true; 472 blocked_fpu_registers_[S27] = true; 473 blocked_fpu_registers_[S28] = true; 474 blocked_fpu_registers_[S29] = true; 475 blocked_fpu_registers_[S30] = true; 476 blocked_fpu_registers_[S31] = true; 477 478 UpdateBlockedPairRegisters(); 479} 480 481void CodeGeneratorARM::UpdateBlockedPairRegisters() const { 482 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 483 ArmManagedRegister current = 484 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 485 if (blocked_core_registers_[current.AsRegisterPairLow()] 486 || blocked_core_registers_[current.AsRegisterPairHigh()]) { 487 blocked_register_pairs_[i] = true; 488 } 489 } 490} 491 492InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) 493 : HGraphVisitor(graph), 494 assembler_(codegen->GetAssembler()), 495 codegen_(codegen) {} 496 497void CodeGeneratorARM::GenerateFrameEntry() { 498 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm); 499 if (!skip_overflow_check) { 500 if (kExplicitStackOverflowCheck) { 501 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM(); 502 AddSlowPath(slow_path); 503 504 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value()); 505 __ cmp(SP, ShifterOperand(IP)); 506 __ b(slow_path->GetEntryLabel(), CC); 507 } else { 508 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm))); 509 __ LoadFromOffset(kLoadWord, IP, IP, 0); 510 RecordPcInfo(nullptr, 0); 511 } 512 } 513 514 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7); 515 __ PushList(1 << LR | 1 << R6 | 1 << R7); 516 517 // The return PC has already been pushed on the stack. 518 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize)); 519 __ StoreToOffset(kStoreWord, R0, SP, 0); 520} 521 522void CodeGeneratorARM::GenerateFrameExit() { 523 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize); 524 __ PopList(1 << PC | 1 << R6 | 1 << R7); 525} 526 527void CodeGeneratorARM::Bind(HBasicBlock* block) { 528 __ Bind(GetLabelOf(block)); 529} 530 531Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const { 532 switch (load->GetType()) { 533 case Primitive::kPrimLong: 534 case Primitive::kPrimDouble: 535 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 536 break; 537 538 case Primitive::kPrimInt: 539 case Primitive::kPrimNot: 540 case Primitive::kPrimFloat: 541 return Location::StackSlot(GetStackSlot(load->GetLocal())); 542 543 case Primitive::kPrimBoolean: 544 case Primitive::kPrimByte: 545 case Primitive::kPrimChar: 546 case Primitive::kPrimShort: 547 case Primitive::kPrimVoid: 548 LOG(FATAL) << "Unexpected type " << load->GetType(); 549 } 550 551 LOG(FATAL) << "Unreachable"; 552 return Location(); 553} 554 555Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { 556 switch (type) { 557 case Primitive::kPrimBoolean: 558 case Primitive::kPrimByte: 559 case Primitive::kPrimChar: 560 case Primitive::kPrimShort: 561 case Primitive::kPrimInt: 562 case Primitive::kPrimNot: { 563 uint32_t index = gp_index_++; 564 uint32_t stack_index = stack_index_++; 565 if (index < calling_convention.GetNumberOfRegisters()) { 566 return Location::RegisterLocation(calling_convention.GetRegisterAt(index)); 567 } else { 568 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index)); 569 } 570 } 571 572 case Primitive::kPrimLong: { 573 uint32_t index = gp_index_; 574 uint32_t stack_index = stack_index_; 575 gp_index_ += 2; 576 stack_index_ += 2; 577 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 578 ArmManagedRegister pair = ArmManagedRegister::FromRegisterPair( 579 calling_convention.GetRegisterPairAt(index)); 580 return Location::RegisterPairLocation(pair.AsRegisterPairLow(), pair.AsRegisterPairHigh()); 581 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { 582 return Location::QuickParameter(index, stack_index); 583 } else { 584 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index)); 585 } 586 } 587 588 case Primitive::kPrimFloat: { 589 uint32_t stack_index = stack_index_++; 590 if (float_index_ % 2 == 0) { 591 float_index_ = std::max(double_index_, float_index_); 592 } 593 if (float_index_ < calling_convention.GetNumberOfFpuRegisters()) { 594 return Location::FpuRegisterLocation(calling_convention.GetFpuRegisterAt(float_index_++)); 595 } else { 596 return Location::StackSlot(calling_convention.GetStackOffsetOf(stack_index)); 597 } 598 } 599 600 case Primitive::kPrimDouble: { 601 double_index_ = std::max(double_index_, RoundUp(float_index_, 2)); 602 uint32_t stack_index = stack_index_; 603 stack_index_ += 2; 604 if (double_index_ + 1 < calling_convention.GetNumberOfFpuRegisters()) { 605 uint32_t index = double_index_; 606 double_index_ += 2; 607 return Location::FpuRegisterPairLocation( 608 calling_convention.GetFpuRegisterAt(index), 609 calling_convention.GetFpuRegisterAt(index + 1)); 610 } else { 611 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(stack_index)); 612 } 613 } 614 615 case Primitive::kPrimVoid: 616 LOG(FATAL) << "Unexpected parameter type " << type; 617 break; 618 } 619 return Location(); 620} 621 622Location InvokeDexCallingConventionVisitor::GetReturnLocation(Primitive::Type type) { 623 switch (type) { 624 case Primitive::kPrimBoolean: 625 case Primitive::kPrimByte: 626 case Primitive::kPrimChar: 627 case Primitive::kPrimShort: 628 case Primitive::kPrimInt: 629 case Primitive::kPrimNot: { 630 return Location::RegisterLocation(R0); 631 } 632 633 case Primitive::kPrimFloat: { 634 return Location::FpuRegisterLocation(S0); 635 } 636 637 case Primitive::kPrimLong: { 638 return Location::RegisterPairLocation(R0, R1); 639 } 640 641 case Primitive::kPrimDouble: { 642 return Location::FpuRegisterPairLocation(S0, S1); 643 } 644 645 case Primitive::kPrimVoid: 646 return Location(); 647 } 648 UNREACHABLE(); 649 return Location(); 650} 651 652void CodeGeneratorARM::Move32(Location destination, Location source) { 653 if (source.Equals(destination)) { 654 return; 655 } 656 if (destination.IsRegister()) { 657 if (source.IsRegister()) { 658 __ Mov(destination.As<Register>(), source.As<Register>()); 659 } else if (source.IsFpuRegister()) { 660 __ vmovrs(destination.As<Register>(), source.As<SRegister>()); 661 } else { 662 __ LoadFromOffset(kLoadWord, destination.As<Register>(), SP, source.GetStackIndex()); 663 } 664 } else if (destination.IsFpuRegister()) { 665 if (source.IsRegister()) { 666 __ vmovsr(destination.As<SRegister>(), source.As<Register>()); 667 } else if (source.IsFpuRegister()) { 668 __ vmovs(destination.As<SRegister>(), source.As<SRegister>()); 669 } else { 670 __ LoadSFromOffset(destination.As<SRegister>(), SP, source.GetStackIndex()); 671 } 672 } else { 673 DCHECK(destination.IsStackSlot()) << destination; 674 if (source.IsRegister()) { 675 __ StoreToOffset(kStoreWord, source.As<Register>(), SP, destination.GetStackIndex()); 676 } else if (source.IsFpuRegister()) { 677 __ StoreSToOffset(source.As<SRegister>(), SP, destination.GetStackIndex()); 678 } else { 679 DCHECK(source.IsStackSlot()) << source; 680 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 681 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 682 } 683 } 684} 685 686void CodeGeneratorARM::Move64(Location destination, Location source) { 687 if (source.Equals(destination)) { 688 return; 689 } 690 if (destination.IsRegisterPair()) { 691 if (source.IsRegisterPair()) { 692 __ Mov(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>()); 693 __ Mov(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>()); 694 } else if (source.IsFpuRegister()) { 695 UNIMPLEMENTED(FATAL); 696 } else if (source.IsQuickParameter()) { 697 uint16_t register_index = source.GetQuickParameterRegisterIndex(); 698 uint16_t stack_index = source.GetQuickParameterStackIndex(); 699 InvokeDexCallingConvention calling_convention; 700 __ Mov(destination.AsRegisterPairLow<Register>(), 701 calling_convention.GetRegisterAt(register_index)); 702 __ LoadFromOffset(kLoadWord, destination.AsRegisterPairHigh<Register>(), 703 SP, calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize()); 704 } else { 705 DCHECK(source.IsDoubleStackSlot()); 706 if (destination.AsRegisterPairLow<Register>() == R1) { 707 DCHECK_EQ(destination.AsRegisterPairHigh<Register>(), R2); 708 __ LoadFromOffset(kLoadWord, R1, SP, source.GetStackIndex()); 709 __ LoadFromOffset(kLoadWord, R2, SP, source.GetHighStackIndex(kArmWordSize)); 710 } else { 711 __ LoadFromOffset(kLoadWordPair, destination.AsRegisterPairLow<Register>(), 712 SP, source.GetStackIndex()); 713 } 714 } 715 } else if (destination.IsFpuRegisterPair()) { 716 if (source.IsDoubleStackSlot()) { 717 __ LoadDFromOffset(FromLowSToD(destination.AsFpuRegisterPairLow<SRegister>()), 718 SP, 719 source.GetStackIndex()); 720 } else { 721 UNIMPLEMENTED(FATAL); 722 } 723 } else if (destination.IsQuickParameter()) { 724 InvokeDexCallingConvention calling_convention; 725 uint16_t register_index = destination.GetQuickParameterRegisterIndex(); 726 uint16_t stack_index = destination.GetQuickParameterStackIndex(); 727 if (source.IsRegisterPair()) { 728 __ Mov(calling_convention.GetRegisterAt(register_index), 729 source.AsRegisterPairLow<Register>()); 730 __ StoreToOffset(kStoreWord, source.AsRegisterPairHigh<Register>(), 731 SP, calling_convention.GetStackOffsetOf(stack_index + 1)); 732 } else if (source.IsFpuRegister()) { 733 UNIMPLEMENTED(FATAL); 734 } else { 735 DCHECK(source.IsDoubleStackSlot()); 736 __ LoadFromOffset( 737 kLoadWord, calling_convention.GetRegisterAt(register_index), SP, source.GetStackIndex()); 738 __ LoadFromOffset(kLoadWord, R0, SP, source.GetHighStackIndex(kArmWordSize)); 739 __ StoreToOffset(kStoreWord, R0, SP, calling_convention.GetStackOffsetOf(stack_index + 1)); 740 } 741 } else { 742 DCHECK(destination.IsDoubleStackSlot()); 743 if (source.IsRegisterPair()) { 744 if (source.AsRegisterPairLow<Register>() == R1) { 745 DCHECK_EQ(source.AsRegisterPairHigh<Register>(), R2); 746 __ StoreToOffset(kStoreWord, R1, SP, destination.GetStackIndex()); 747 __ StoreToOffset(kStoreWord, R2, SP, destination.GetHighStackIndex(kArmWordSize)); 748 } else { 749 __ StoreToOffset(kStoreWordPair, source.AsRegisterPairLow<Register>(), 750 SP, destination.GetStackIndex()); 751 } 752 } else if (source.IsQuickParameter()) { 753 InvokeDexCallingConvention calling_convention; 754 uint16_t register_index = source.GetQuickParameterRegisterIndex(); 755 uint16_t stack_index = source.GetQuickParameterStackIndex(); 756 __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(register_index), 757 SP, destination.GetStackIndex()); 758 __ LoadFromOffset(kLoadWord, R0, 759 SP, calling_convention.GetStackOffsetOf(stack_index + 1) + GetFrameSize()); 760 __ StoreToOffset(kStoreWord, R0, SP, destination.GetHighStackIndex(kArmWordSize)); 761 } else if (source.IsFpuRegisterPair()) { 762 __ StoreDToOffset(FromLowSToD(source.AsFpuRegisterPairLow<SRegister>()), 763 SP, 764 destination.GetStackIndex()); 765 } else { 766 DCHECK(source.IsDoubleStackSlot()); 767 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 768 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 769 __ LoadFromOffset(kLoadWord, IP, SP, source.GetHighStackIndex(kArmWordSize)); 770 __ StoreToOffset(kStoreWord, IP, SP, destination.GetHighStackIndex(kArmWordSize)); 771 } 772 } 773} 774 775void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 776 LocationSummary* locations = instruction->GetLocations(); 777 if (locations != nullptr && locations->Out().Equals(location)) { 778 return; 779 } 780 781 if (locations != nullptr && locations->Out().IsConstant()) { 782 HConstant* const_to_move = locations->Out().GetConstant(); 783 if (const_to_move->IsIntConstant()) { 784 int32_t value = const_to_move->AsIntConstant()->GetValue(); 785 if (location.IsRegister()) { 786 __ LoadImmediate(location.As<Register>(), value); 787 } else { 788 DCHECK(location.IsStackSlot()); 789 __ LoadImmediate(IP, value); 790 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); 791 } 792 } else if (const_to_move->IsLongConstant()) { 793 int64_t value = const_to_move->AsLongConstant()->GetValue(); 794 if (location.IsRegisterPair()) { 795 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value)); 796 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value)); 797 } else { 798 DCHECK(location.IsDoubleStackSlot()); 799 __ LoadImmediate(IP, Low32Bits(value)); 800 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); 801 __ LoadImmediate(IP, High32Bits(value)); 802 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize)); 803 } 804 } 805 } else if (instruction->IsLoadLocal()) { 806 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 807 switch (instruction->GetType()) { 808 case Primitive::kPrimBoolean: 809 case Primitive::kPrimByte: 810 case Primitive::kPrimChar: 811 case Primitive::kPrimShort: 812 case Primitive::kPrimInt: 813 case Primitive::kPrimNot: 814 case Primitive::kPrimFloat: 815 Move32(location, Location::StackSlot(stack_slot)); 816 break; 817 818 case Primitive::kPrimLong: 819 case Primitive::kPrimDouble: 820 Move64(location, Location::DoubleStackSlot(stack_slot)); 821 break; 822 823 default: 824 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 825 } 826 } else if (instruction->IsTemporary()) { 827 Location temp_location = GetTemporaryLocation(instruction->AsTemporary()); 828 if (temp_location.IsStackSlot()) { 829 Move32(location, temp_location); 830 } else { 831 DCHECK(temp_location.IsDoubleStackSlot()); 832 Move64(location, temp_location); 833 } 834 } else { 835 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary()); 836 switch (instruction->GetType()) { 837 case Primitive::kPrimBoolean: 838 case Primitive::kPrimByte: 839 case Primitive::kPrimChar: 840 case Primitive::kPrimShort: 841 case Primitive::kPrimNot: 842 case Primitive::kPrimInt: 843 case Primitive::kPrimFloat: 844 Move32(location, locations->Out()); 845 break; 846 847 case Primitive::kPrimLong: 848 case Primitive::kPrimDouble: 849 Move64(location, locations->Out()); 850 break; 851 852 default: 853 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 854 } 855 } 856} 857 858void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset, 859 HInstruction* instruction, 860 uint32_t dex_pc) { 861 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset); 862 __ blx(LR); 863 RecordPcInfo(instruction, dex_pc); 864 DCHECK(instruction->IsSuspendCheck() 865 || instruction->IsBoundsCheck() 866 || instruction->IsNullCheck() 867 || instruction->IsDivZeroCheck() 868 || !IsLeafMethod()); 869} 870 871void LocationsBuilderARM::VisitGoto(HGoto* got) { 872 got->SetLocations(nullptr); 873} 874 875void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { 876 HBasicBlock* successor = got->GetSuccessor(); 877 DCHECK(!successor->IsExitBlock()); 878 879 HBasicBlock* block = got->GetBlock(); 880 HInstruction* previous = got->GetPrevious(); 881 882 HLoopInformation* info = block->GetLoopInformation(); 883 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) { 884 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); 885 GenerateSuspendCheck(info->GetSuspendCheck(), successor); 886 return; 887 } 888 889 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) { 890 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr); 891 } 892 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 893 __ b(codegen_->GetLabelOf(successor)); 894 } 895} 896 897void LocationsBuilderARM::VisitExit(HExit* exit) { 898 exit->SetLocations(nullptr); 899} 900 901void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { 902 UNUSED(exit); 903 if (kIsDebugBuild) { 904 __ Comment("Unreachable"); 905 __ bkpt(0); 906 } 907} 908 909void LocationsBuilderARM::VisitIf(HIf* if_instr) { 910 LocationSummary* locations = 911 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); 912 HInstruction* cond = if_instr->InputAt(0); 913 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 914 locations->SetInAt(0, Location::RequiresRegister()); 915 } 916} 917 918void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 919 HInstruction* cond = if_instr->InputAt(0); 920 if (cond->IsIntConstant()) { 921 // Constant condition, statically compared against 1. 922 int32_t cond_value = cond->AsIntConstant()->GetValue(); 923 if (cond_value == 1) { 924 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), 925 if_instr->IfTrueSuccessor())) { 926 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 927 } 928 return; 929 } else { 930 DCHECK_EQ(cond_value, 0); 931 } 932 } else { 933 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 934 // Condition has been materialized, compare the output to 0 935 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister()); 936 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(), 937 ShifterOperand(0)); 938 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE); 939 } else { 940 // Condition has not been materialized, use its inputs as the 941 // comparison and its condition as the branch condition. 942 LocationSummary* locations = cond->GetLocations(); 943 if (locations->InAt(1).IsRegister()) { 944 __ cmp(locations->InAt(0).As<Register>(), 945 ShifterOperand(locations->InAt(1).As<Register>())); 946 } else { 947 DCHECK(locations->InAt(1).IsConstant()); 948 int32_t value = 949 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 950 ShifterOperand operand; 951 if (ShifterOperand::CanHoldArm(value, &operand)) { 952 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value)); 953 } else { 954 Register temp = IP; 955 __ LoadImmediate(temp, value); 956 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp)); 957 } 958 } 959 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), 960 ARMCondition(cond->AsCondition()->GetCondition())); 961 } 962 } 963 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), 964 if_instr->IfFalseSuccessor())) { 965 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); 966 } 967} 968 969 970void LocationsBuilderARM::VisitCondition(HCondition* comp) { 971 LocationSummary* locations = 972 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); 973 locations->SetInAt(0, Location::RequiresRegister()); 974 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1))); 975 if (comp->NeedsMaterialization()) { 976 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 977 } 978} 979 980void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) { 981 if (!comp->NeedsMaterialization()) return; 982 983 LocationSummary* locations = comp->GetLocations(); 984 if (locations->InAt(1).IsRegister()) { 985 __ cmp(locations->InAt(0).As<Register>(), 986 ShifterOperand(locations->InAt(1).As<Register>())); 987 } else { 988 DCHECK(locations->InAt(1).IsConstant()); 989 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 990 ShifterOperand operand; 991 if (ShifterOperand::CanHoldArm(value, &operand)) { 992 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value)); 993 } else { 994 Register temp = IP; 995 __ LoadImmediate(temp, value); 996 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp)); 997 } 998 } 999 __ it(ARMCondition(comp->GetCondition()), kItElse); 1000 __ mov(locations->Out().As<Register>(), ShifterOperand(1), 1001 ARMCondition(comp->GetCondition())); 1002 __ mov(locations->Out().As<Register>(), ShifterOperand(0), 1003 ARMOppositeCondition(comp->GetCondition())); 1004} 1005 1006void LocationsBuilderARM::VisitEqual(HEqual* comp) { 1007 VisitCondition(comp); 1008} 1009 1010void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) { 1011 VisitCondition(comp); 1012} 1013 1014void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) { 1015 VisitCondition(comp); 1016} 1017 1018void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) { 1019 VisitCondition(comp); 1020} 1021 1022void LocationsBuilderARM::VisitLessThan(HLessThan* comp) { 1023 VisitCondition(comp); 1024} 1025 1026void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) { 1027 VisitCondition(comp); 1028} 1029 1030void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 1031 VisitCondition(comp); 1032} 1033 1034void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 1035 VisitCondition(comp); 1036} 1037 1038void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) { 1039 VisitCondition(comp); 1040} 1041 1042void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) { 1043 VisitCondition(comp); 1044} 1045 1046void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1047 VisitCondition(comp); 1048} 1049 1050void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1051 VisitCondition(comp); 1052} 1053 1054void LocationsBuilderARM::VisitLocal(HLocal* local) { 1055 local->SetLocations(nullptr); 1056} 1057 1058void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 1059 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 1060} 1061 1062void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 1063 load->SetLocations(nullptr); 1064} 1065 1066void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 1067 // Nothing to do, this is driven by the code generator. 1068 UNUSED(load); 1069} 1070 1071void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 1072 LocationSummary* locations = 1073 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall); 1074 switch (store->InputAt(1)->GetType()) { 1075 case Primitive::kPrimBoolean: 1076 case Primitive::kPrimByte: 1077 case Primitive::kPrimChar: 1078 case Primitive::kPrimShort: 1079 case Primitive::kPrimInt: 1080 case Primitive::kPrimNot: 1081 case Primitive::kPrimFloat: 1082 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1083 break; 1084 1085 case Primitive::kPrimLong: 1086 case Primitive::kPrimDouble: 1087 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1088 break; 1089 1090 default: 1091 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType(); 1092 } 1093} 1094 1095void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 1096 UNUSED(store); 1097} 1098 1099void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 1100 LocationSummary* locations = 1101 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1102 locations->SetOut(Location::ConstantLocation(constant)); 1103} 1104 1105void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 1106 // Will be generated at use site. 1107 UNUSED(constant); 1108} 1109 1110void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { 1111 LocationSummary* locations = 1112 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1113 locations->SetOut(Location::ConstantLocation(constant)); 1114} 1115 1116void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { 1117 // Will be generated at use site. 1118 UNUSED(constant); 1119} 1120 1121void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) { 1122 LocationSummary* locations = 1123 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1124 locations->SetOut(Location::ConstantLocation(constant)); 1125} 1126 1127void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) { 1128 // Will be generated at use site. 1129 UNUSED(constant); 1130} 1131 1132void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) { 1133 LocationSummary* locations = 1134 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1135 locations->SetOut(Location::ConstantLocation(constant)); 1136} 1137 1138void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) { 1139 // Will be generated at use site. 1140 UNUSED(constant); 1141} 1142 1143void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 1144 ret->SetLocations(nullptr); 1145} 1146 1147void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 1148 UNUSED(ret); 1149 codegen_->GenerateFrameExit(); 1150} 1151 1152void LocationsBuilderARM::VisitReturn(HReturn* ret) { 1153 LocationSummary* locations = 1154 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall); 1155 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType())); 1156} 1157 1158void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 1159 UNUSED(ret); 1160 codegen_->GenerateFrameExit(); 1161} 1162 1163void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { 1164 HandleInvoke(invoke); 1165} 1166 1167void CodeGeneratorARM::LoadCurrentMethod(Register reg) { 1168 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset); 1169} 1170 1171void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { 1172 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); 1173 1174 // TODO: Implement all kinds of calls: 1175 // 1) boot -> boot 1176 // 2) app -> boot 1177 // 3) app -> app 1178 // 1179 // Currently we implement the app -> app logic, which looks up in the resolve cache. 1180 1181 // temp = method; 1182 codegen_->LoadCurrentMethod(temp); 1183 // temp = temp->dex_cache_resolved_methods_; 1184 __ LoadFromOffset( 1185 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); 1186 // temp = temp[index_in_cache] 1187 __ LoadFromOffset( 1188 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache())); 1189 // LR = temp[offset_of_quick_compiled_code] 1190 __ LoadFromOffset(kLoadWord, LR, temp, 1191 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()); 1192 // LR() 1193 __ blx(LR); 1194 1195 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1196 DCHECK(!codegen_->IsLeafMethod()); 1197} 1198 1199void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { 1200 LocationSummary* locations = 1201 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); 1202 locations->AddTemp(Location::RegisterLocation(R0)); 1203 1204 InvokeDexCallingConventionVisitor calling_convention_visitor; 1205 for (size_t i = 0; i < invoke->InputCount(); i++) { 1206 HInstruction* input = invoke->InputAt(i); 1207 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 1208 } 1209 1210 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType())); 1211} 1212 1213void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1214 HandleInvoke(invoke); 1215} 1216 1217void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1218 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); 1219 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() + 1220 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); 1221 LocationSummary* locations = invoke->GetLocations(); 1222 Location receiver = locations->InAt(0); 1223 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1224 // temp = object->GetClass(); 1225 if (receiver.IsStackSlot()) { 1226 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); 1227 __ LoadFromOffset(kLoadWord, temp, temp, class_offset); 1228 } else { 1229 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); 1230 } 1231 // temp = temp->GetMethodAt(method_offset); 1232 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); 1233 __ LoadFromOffset(kLoadWord, temp, temp, method_offset); 1234 // LR = temp->GetEntryPoint(); 1235 __ LoadFromOffset(kLoadWord, LR, temp, entry_point); 1236 // LR(); 1237 __ blx(LR); 1238 DCHECK(!codegen_->IsLeafMethod()); 1239 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1240} 1241 1242void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) { 1243 HandleInvoke(invoke); 1244 // Add the hidden argument. 1245 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12)); 1246} 1247 1248void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) { 1249 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. 1250 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); 1251 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + 1252 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); 1253 LocationSummary* locations = invoke->GetLocations(); 1254 Location receiver = locations->InAt(0); 1255 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1256 1257 // Set the hidden argument. 1258 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).As<Register>(), invoke->GetDexMethodIndex()); 1259 1260 // temp = object->GetClass(); 1261 if (receiver.IsStackSlot()) { 1262 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); 1263 __ LoadFromOffset(kLoadWord, temp, temp, class_offset); 1264 } else { 1265 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); 1266 } 1267 // temp = temp->GetImtEntryAt(method_offset); 1268 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); 1269 __ LoadFromOffset(kLoadWord, temp, temp, method_offset); 1270 // LR = temp->GetEntryPoint(); 1271 __ LoadFromOffset(kLoadWord, LR, temp, entry_point); 1272 // LR(); 1273 __ blx(LR); 1274 DCHECK(!codegen_->IsLeafMethod()); 1275 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1276} 1277 1278void LocationsBuilderARM::VisitNeg(HNeg* neg) { 1279 LocationSummary* locations = 1280 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); 1281 switch (neg->GetResultType()) { 1282 case Primitive::kPrimInt: 1283 case Primitive::kPrimLong: { 1284 bool output_overlaps = (neg->GetResultType() == Primitive::kPrimLong); 1285 locations->SetInAt(0, Location::RequiresRegister()); 1286 locations->SetOut(Location::RequiresRegister(), output_overlaps); 1287 break; 1288 } 1289 1290 case Primitive::kPrimFloat: 1291 case Primitive::kPrimDouble: 1292 locations->SetInAt(0, Location::RequiresFpuRegister()); 1293 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1294 break; 1295 1296 default: 1297 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1298 } 1299} 1300 1301void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) { 1302 LocationSummary* locations = neg->GetLocations(); 1303 Location out = locations->Out(); 1304 Location in = locations->InAt(0); 1305 switch (neg->GetResultType()) { 1306 case Primitive::kPrimInt: 1307 DCHECK(in.IsRegister()); 1308 __ rsb(out.As<Register>(), in.As<Register>(), ShifterOperand(0)); 1309 break; 1310 1311 case Primitive::kPrimLong: 1312 DCHECK(in.IsRegisterPair()); 1313 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag) 1314 __ rsbs(out.AsRegisterPairLow<Register>(), 1315 in.AsRegisterPairLow<Register>(), 1316 ShifterOperand(0)); 1317 // We cannot emit an RSC (Reverse Subtract with Carry) 1318 // instruction here, as it does not exist in the Thumb-2 1319 // instruction set. We use the following approach 1320 // using SBC and SUB instead. 1321 // 1322 // out.hi = -C 1323 __ sbc(out.AsRegisterPairHigh<Register>(), 1324 out.AsRegisterPairHigh<Register>(), 1325 ShifterOperand(out.AsRegisterPairHigh<Register>())); 1326 // out.hi = out.hi - in.hi 1327 __ sub(out.AsRegisterPairHigh<Register>(), 1328 out.AsRegisterPairHigh<Register>(), 1329 ShifterOperand(in.AsRegisterPairHigh<Register>())); 1330 break; 1331 1332 case Primitive::kPrimFloat: 1333 DCHECK(in.IsFpuRegister()); 1334 __ vnegs(out.As<SRegister>(), in.As<SRegister>()); 1335 break; 1336 1337 case Primitive::kPrimDouble: 1338 DCHECK(in.IsFpuRegisterPair()); 1339 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1340 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 1341 break; 1342 1343 default: 1344 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1345 } 1346} 1347 1348void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { 1349 LocationSummary* locations = 1350 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall); 1351 Primitive::Type result_type = conversion->GetResultType(); 1352 Primitive::Type input_type = conversion->GetInputType(); 1353 switch (result_type) { 1354 case Primitive::kPrimByte: 1355 switch (input_type) { 1356 case Primitive::kPrimShort: 1357 case Primitive::kPrimInt: 1358 case Primitive::kPrimChar: 1359 // Processing a Dex `int-to-byte' instruction. 1360 locations->SetInAt(0, Location::RequiresRegister()); 1361 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1362 break; 1363 1364 default: 1365 LOG(FATAL) << "Unexpected type conversion from " << input_type 1366 << " to " << result_type; 1367 } 1368 break; 1369 1370 case Primitive::kPrimShort: 1371 switch (input_type) { 1372 case Primitive::kPrimByte: 1373 case Primitive::kPrimInt: 1374 case Primitive::kPrimChar: 1375 // Processing a Dex `int-to-short' instruction. 1376 locations->SetInAt(0, Location::RequiresRegister()); 1377 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1378 break; 1379 1380 default: 1381 LOG(FATAL) << "Unexpected type conversion from " << input_type 1382 << " to " << result_type; 1383 } 1384 break; 1385 1386 case Primitive::kPrimInt: 1387 switch (input_type) { 1388 case Primitive::kPrimLong: 1389 // Processing a Dex `long-to-int' instruction. 1390 locations->SetInAt(0, Location::Any()); 1391 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1392 break; 1393 1394 case Primitive::kPrimFloat: 1395 case Primitive::kPrimDouble: 1396 LOG(FATAL) << "Type conversion from " << input_type 1397 << " to " << result_type << " not yet implemented"; 1398 break; 1399 1400 default: 1401 LOG(FATAL) << "Unexpected type conversion from " << input_type 1402 << " to " << result_type; 1403 } 1404 break; 1405 1406 case Primitive::kPrimLong: 1407 switch (input_type) { 1408 case Primitive::kPrimByte: 1409 case Primitive::kPrimShort: 1410 case Primitive::kPrimInt: 1411 case Primitive::kPrimChar: 1412 // Processing a Dex `int-to-long' instruction. 1413 locations->SetInAt(0, Location::RequiresRegister()); 1414 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1415 break; 1416 1417 case Primitive::kPrimFloat: 1418 case Primitive::kPrimDouble: 1419 LOG(FATAL) << "Type conversion from " << input_type << " to " 1420 << result_type << " not yet implemented"; 1421 break; 1422 1423 default: 1424 LOG(FATAL) << "Unexpected type conversion from " << input_type 1425 << " to " << result_type; 1426 } 1427 break; 1428 1429 case Primitive::kPrimChar: 1430 switch (input_type) { 1431 case Primitive::kPrimByte: 1432 case Primitive::kPrimShort: 1433 case Primitive::kPrimInt: 1434 case Primitive::kPrimChar: 1435 // Processing a Dex `int-to-char' instruction. 1436 locations->SetInAt(0, Location::RequiresRegister()); 1437 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1438 break; 1439 1440 default: 1441 LOG(FATAL) << "Unexpected type conversion from " << input_type 1442 << " to " << result_type; 1443 } 1444 break; 1445 1446 case Primitive::kPrimFloat: 1447 switch (input_type) { 1448 case Primitive::kPrimByte: 1449 case Primitive::kPrimShort: 1450 case Primitive::kPrimInt: 1451 case Primitive::kPrimChar: 1452 // Processing a Dex `int-to-float' instruction. 1453 locations->SetInAt(0, Location::RequiresRegister()); 1454 locations->SetOut(Location::RequiresFpuRegister()); 1455 break; 1456 1457 case Primitive::kPrimLong: 1458 case Primitive::kPrimDouble: 1459 LOG(FATAL) << "Type conversion from " << input_type 1460 << " to " << result_type << " not yet implemented"; 1461 break; 1462 1463 default: 1464 LOG(FATAL) << "Unexpected type conversion from " << input_type 1465 << " to " << result_type; 1466 }; 1467 break; 1468 1469 case Primitive::kPrimDouble: 1470 switch (input_type) { 1471 case Primitive::kPrimByte: 1472 case Primitive::kPrimShort: 1473 case Primitive::kPrimInt: 1474 case Primitive::kPrimChar: 1475 // Processing a Dex `int-to-double' instruction. 1476 locations->SetInAt(0, Location::RequiresRegister()); 1477 locations->SetOut(Location::RequiresFpuRegister()); 1478 break; 1479 1480 case Primitive::kPrimLong: 1481 case Primitive::kPrimFloat: 1482 LOG(FATAL) << "Type conversion from " << input_type 1483 << " to " << result_type << " not yet implemented"; 1484 break; 1485 1486 default: 1487 LOG(FATAL) << "Unexpected type conversion from " << input_type 1488 << " to " << result_type; 1489 }; 1490 break; 1491 1492 default: 1493 LOG(FATAL) << "Unexpected type conversion from " << input_type 1494 << " to " << result_type; 1495 } 1496} 1497 1498void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) { 1499 LocationSummary* locations = conversion->GetLocations(); 1500 Location out = locations->Out(); 1501 Location in = locations->InAt(0); 1502 Primitive::Type result_type = conversion->GetResultType(); 1503 Primitive::Type input_type = conversion->GetInputType(); 1504 switch (result_type) { 1505 case Primitive::kPrimByte: 1506 switch (input_type) { 1507 case Primitive::kPrimShort: 1508 case Primitive::kPrimInt: 1509 case Primitive::kPrimChar: 1510 // Processing a Dex `int-to-byte' instruction. 1511 __ sbfx(out.As<Register>(), in.As<Register>(), 0, 8); 1512 break; 1513 1514 default: 1515 LOG(FATAL) << "Unexpected type conversion from " << input_type 1516 << " to " << result_type; 1517 } 1518 break; 1519 1520 case Primitive::kPrimShort: 1521 switch (input_type) { 1522 case Primitive::kPrimByte: 1523 case Primitive::kPrimInt: 1524 case Primitive::kPrimChar: 1525 // Processing a Dex `int-to-short' instruction. 1526 __ sbfx(out.As<Register>(), in.As<Register>(), 0, 16); 1527 break; 1528 1529 default: 1530 LOG(FATAL) << "Unexpected type conversion from " << input_type 1531 << " to " << result_type; 1532 } 1533 break; 1534 1535 case Primitive::kPrimInt: 1536 switch (input_type) { 1537 case Primitive::kPrimLong: 1538 // Processing a Dex `long-to-int' instruction. 1539 DCHECK(out.IsRegister()); 1540 if (in.IsRegisterPair()) { 1541 __ Mov(out.As<Register>(), in.AsRegisterPairLow<Register>()); 1542 } else if (in.IsDoubleStackSlot()) { 1543 __ LoadFromOffset(kLoadWord, out.As<Register>(), SP, in.GetStackIndex()); 1544 } else { 1545 DCHECK(in.IsConstant()); 1546 DCHECK(in.GetConstant()->IsLongConstant()); 1547 int64_t value = in.GetConstant()->AsLongConstant()->GetValue(); 1548 __ LoadImmediate(out.As<Register>(), static_cast<int32_t>(value)); 1549 } 1550 break; 1551 1552 case Primitive::kPrimFloat: 1553 case Primitive::kPrimDouble: 1554 LOG(FATAL) << "Type conversion from " << input_type 1555 << " to " << result_type << " not yet implemented"; 1556 break; 1557 1558 default: 1559 LOG(FATAL) << "Unexpected type conversion from " << input_type 1560 << " to " << result_type; 1561 } 1562 break; 1563 1564 case Primitive::kPrimLong: 1565 switch (input_type) { 1566 case Primitive::kPrimByte: 1567 case Primitive::kPrimShort: 1568 case Primitive::kPrimInt: 1569 case Primitive::kPrimChar: 1570 // Processing a Dex `int-to-long' instruction. 1571 DCHECK(out.IsRegisterPair()); 1572 DCHECK(in.IsRegister()); 1573 __ Mov(out.AsRegisterPairLow<Register>(), in.As<Register>()); 1574 // Sign extension. 1575 __ Asr(out.AsRegisterPairHigh<Register>(), 1576 out.AsRegisterPairLow<Register>(), 1577 31); 1578 break; 1579 1580 case Primitive::kPrimFloat: 1581 case Primitive::kPrimDouble: 1582 LOG(FATAL) << "Type conversion from " << input_type << " to " 1583 << result_type << " not yet implemented"; 1584 break; 1585 1586 default: 1587 LOG(FATAL) << "Unexpected type conversion from " << input_type 1588 << " to " << result_type; 1589 } 1590 break; 1591 1592 case Primitive::kPrimChar: 1593 switch (input_type) { 1594 case Primitive::kPrimByte: 1595 case Primitive::kPrimShort: 1596 case Primitive::kPrimInt: 1597 case Primitive::kPrimChar: 1598 // Processing a Dex `int-to-char' instruction. 1599 __ ubfx(out.As<Register>(), in.As<Register>(), 0, 16); 1600 break; 1601 1602 default: 1603 LOG(FATAL) << "Unexpected type conversion from " << input_type 1604 << " to " << result_type; 1605 } 1606 break; 1607 1608 case Primitive::kPrimFloat: 1609 switch (input_type) { 1610 case Primitive::kPrimByte: 1611 case Primitive::kPrimShort: 1612 case Primitive::kPrimInt: 1613 case Primitive::kPrimChar: { 1614 // Processing a Dex `int-to-float' instruction. 1615 __ vmovsr(out.As<SRegister>(), in.As<Register>()); 1616 __ vcvtsi(out.As<SRegister>(), out.As<SRegister>()); 1617 break; 1618 } 1619 1620 case Primitive::kPrimLong: 1621 case Primitive::kPrimDouble: 1622 LOG(FATAL) << "Type conversion from " << input_type 1623 << " to " << result_type << " not yet implemented"; 1624 break; 1625 1626 default: 1627 LOG(FATAL) << "Unexpected type conversion from " << input_type 1628 << " to " << result_type; 1629 }; 1630 break; 1631 1632 case Primitive::kPrimDouble: 1633 switch (input_type) { 1634 case Primitive::kPrimByte: 1635 case Primitive::kPrimShort: 1636 case Primitive::kPrimInt: 1637 case Primitive::kPrimChar: { 1638 // Processing a Dex `int-to-double' instruction. 1639 __ vmovsr(out.AsFpuRegisterPairLow<SRegister>(), in.As<Register>()); 1640 __ vcvtdi(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1641 out.AsFpuRegisterPairLow<SRegister>()); 1642 break; 1643 } 1644 1645 case Primitive::kPrimLong: 1646 case Primitive::kPrimFloat: 1647 LOG(FATAL) << "Type conversion from " << input_type 1648 << " to " << result_type << " not yet implemented"; 1649 break; 1650 1651 default: 1652 LOG(FATAL) << "Unexpected type conversion from " << input_type 1653 << " to " << result_type; 1654 }; 1655 break; 1656 1657 default: 1658 LOG(FATAL) << "Unexpected type conversion from " << input_type 1659 << " to " << result_type; 1660 } 1661} 1662 1663void LocationsBuilderARM::VisitAdd(HAdd* add) { 1664 LocationSummary* locations = 1665 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); 1666 switch (add->GetResultType()) { 1667 case Primitive::kPrimInt: 1668 case Primitive::kPrimLong: { 1669 bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong); 1670 locations->SetInAt(0, Location::RequiresRegister()); 1671 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1))); 1672 locations->SetOut(Location::RequiresRegister(), output_overlaps); 1673 break; 1674 } 1675 1676 case Primitive::kPrimFloat: 1677 case Primitive::kPrimDouble: { 1678 locations->SetInAt(0, Location::RequiresFpuRegister()); 1679 locations->SetInAt(1, Location::RequiresFpuRegister()); 1680 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1681 break; 1682 } 1683 1684 default: 1685 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1686 } 1687} 1688 1689void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 1690 LocationSummary* locations = add->GetLocations(); 1691 Location out = locations->Out(); 1692 Location first = locations->InAt(0); 1693 Location second = locations->InAt(1); 1694 switch (add->GetResultType()) { 1695 case Primitive::kPrimInt: 1696 if (second.IsRegister()) { 1697 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>())); 1698 } else { 1699 __ AddConstant(out.As<Register>(), 1700 first.As<Register>(), 1701 second.GetConstant()->AsIntConstant()->GetValue()); 1702 } 1703 break; 1704 1705 case Primitive::kPrimLong: 1706 __ adds(out.AsRegisterPairLow<Register>(), 1707 first.AsRegisterPairLow<Register>(), 1708 ShifterOperand(second.AsRegisterPairLow<Register>())); 1709 __ adc(out.AsRegisterPairHigh<Register>(), 1710 first.AsRegisterPairHigh<Register>(), 1711 ShifterOperand(second.AsRegisterPairHigh<Register>())); 1712 break; 1713 1714 case Primitive::kPrimFloat: 1715 __ vadds(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>()); 1716 break; 1717 1718 case Primitive::kPrimDouble: 1719 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1720 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 1721 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 1722 break; 1723 1724 default: 1725 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1726 } 1727} 1728 1729void LocationsBuilderARM::VisitSub(HSub* sub) { 1730 LocationSummary* locations = 1731 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall); 1732 switch (sub->GetResultType()) { 1733 case Primitive::kPrimInt: 1734 case Primitive::kPrimLong: { 1735 bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong); 1736 locations->SetInAt(0, Location::RequiresRegister()); 1737 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1))); 1738 locations->SetOut(Location::RequiresRegister(), output_overlaps); 1739 break; 1740 } 1741 case Primitive::kPrimFloat: 1742 case Primitive::kPrimDouble: { 1743 locations->SetInAt(0, Location::RequiresFpuRegister()); 1744 locations->SetInAt(1, Location::RequiresFpuRegister()); 1745 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1746 break; 1747 } 1748 default: 1749 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1750 } 1751} 1752 1753void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { 1754 LocationSummary* locations = sub->GetLocations(); 1755 Location out = locations->Out(); 1756 Location first = locations->InAt(0); 1757 Location second = locations->InAt(1); 1758 switch (sub->GetResultType()) { 1759 case Primitive::kPrimInt: { 1760 if (second.IsRegister()) { 1761 __ sub(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>())); 1762 } else { 1763 __ AddConstant(out.As<Register>(), 1764 first.As<Register>(), 1765 -second.GetConstant()->AsIntConstant()->GetValue()); 1766 } 1767 break; 1768 } 1769 1770 case Primitive::kPrimLong: { 1771 __ subs(out.AsRegisterPairLow<Register>(), 1772 first.AsRegisterPairLow<Register>(), 1773 ShifterOperand(second.AsRegisterPairLow<Register>())); 1774 __ sbc(out.AsRegisterPairHigh<Register>(), 1775 first.AsRegisterPairHigh<Register>(), 1776 ShifterOperand(second.AsRegisterPairHigh<Register>())); 1777 break; 1778 } 1779 1780 case Primitive::kPrimFloat: { 1781 __ vsubs(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>()); 1782 break; 1783 } 1784 1785 case Primitive::kPrimDouble: { 1786 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1787 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 1788 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 1789 break; 1790 } 1791 1792 1793 default: 1794 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1795 } 1796} 1797 1798void LocationsBuilderARM::VisitMul(HMul* mul) { 1799 LocationSummary* locations = 1800 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall); 1801 switch (mul->GetResultType()) { 1802 case Primitive::kPrimInt: 1803 case Primitive::kPrimLong: { 1804 locations->SetInAt(0, Location::RequiresRegister()); 1805 locations->SetInAt(1, Location::RequiresRegister()); 1806 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1807 break; 1808 } 1809 1810 case Primitive::kPrimFloat: 1811 case Primitive::kPrimDouble: { 1812 locations->SetInAt(0, Location::RequiresFpuRegister()); 1813 locations->SetInAt(1, Location::RequiresFpuRegister()); 1814 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1815 break; 1816 } 1817 1818 default: 1819 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 1820 } 1821} 1822 1823void InstructionCodeGeneratorARM::VisitMul(HMul* mul) { 1824 LocationSummary* locations = mul->GetLocations(); 1825 Location out = locations->Out(); 1826 Location first = locations->InAt(0); 1827 Location second = locations->InAt(1); 1828 switch (mul->GetResultType()) { 1829 case Primitive::kPrimInt: { 1830 __ mul(out.As<Register>(), first.As<Register>(), second.As<Register>()); 1831 break; 1832 } 1833 case Primitive::kPrimLong: { 1834 Register out_hi = out.AsRegisterPairHigh<Register>(); 1835 Register out_lo = out.AsRegisterPairLow<Register>(); 1836 Register in1_hi = first.AsRegisterPairHigh<Register>(); 1837 Register in1_lo = first.AsRegisterPairLow<Register>(); 1838 Register in2_hi = second.AsRegisterPairHigh<Register>(); 1839 Register in2_lo = second.AsRegisterPairLow<Register>(); 1840 1841 // Extra checks to protect caused by the existence of R1_R2. 1842 // The algorithm is wrong if out.hi is either in1.lo or in2.lo: 1843 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2); 1844 DCHECK_NE(out_hi, in1_lo); 1845 DCHECK_NE(out_hi, in2_lo); 1846 1847 // input: in1 - 64 bits, in2 - 64 bits 1848 // output: out 1849 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo 1850 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32] 1851 // parts: out.lo = (in1.lo * in2.lo)[31:0] 1852 1853 // IP <- in1.lo * in2.hi 1854 __ mul(IP, in1_lo, in2_hi); 1855 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo 1856 __ mla(out_hi, in1_hi, in2_lo, IP); 1857 // out.lo <- (in1.lo * in2.lo)[31:0]; 1858 __ umull(out_lo, IP, in1_lo, in2_lo); 1859 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 1860 __ add(out_hi, out_hi, ShifterOperand(IP)); 1861 break; 1862 } 1863 1864 case Primitive::kPrimFloat: { 1865 __ vmuls(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>()); 1866 break; 1867 } 1868 1869 case Primitive::kPrimDouble: { 1870 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1871 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 1872 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 1873 break; 1874 } 1875 1876 default: 1877 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 1878 } 1879} 1880 1881void LocationsBuilderARM::VisitDiv(HDiv* div) { 1882 LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong 1883 ? LocationSummary::kCall 1884 : LocationSummary::kNoCall; 1885 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind); 1886 1887 switch (div->GetResultType()) { 1888 case Primitive::kPrimInt: { 1889 locations->SetInAt(0, Location::RequiresRegister()); 1890 locations->SetInAt(1, Location::RequiresRegister()); 1891 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1892 break; 1893 } 1894 case Primitive::kPrimLong: { 1895 InvokeRuntimeCallingConvention calling_convention; 1896 locations->SetInAt(0, Location::RegisterPairLocation( 1897 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 1898 locations->SetInAt(1, Location::RegisterPairLocation( 1899 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 1900 // The runtime helper puts the output in R0,R2. 1901 locations->SetOut(Location::RegisterPairLocation(R0, R2)); 1902 break; 1903 } 1904 case Primitive::kPrimFloat: 1905 case Primitive::kPrimDouble: { 1906 locations->SetInAt(0, Location::RequiresFpuRegister()); 1907 locations->SetInAt(1, Location::RequiresFpuRegister()); 1908 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1909 break; 1910 } 1911 1912 default: 1913 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 1914 } 1915} 1916 1917void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) { 1918 LocationSummary* locations = div->GetLocations(); 1919 Location out = locations->Out(); 1920 Location first = locations->InAt(0); 1921 Location second = locations->InAt(1); 1922 1923 switch (div->GetResultType()) { 1924 case Primitive::kPrimInt: { 1925 __ sdiv(out.As<Register>(), first.As<Register>(), second.As<Register>()); 1926 break; 1927 } 1928 1929 case Primitive::kPrimLong: { 1930 InvokeRuntimeCallingConvention calling_convention; 1931 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); 1932 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); 1933 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); 1934 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); 1935 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>()); 1936 DCHECK_EQ(R2, out.AsRegisterPairHigh<Register>()); 1937 1938 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc()); 1939 break; 1940 } 1941 1942 case Primitive::kPrimFloat: { 1943 __ vdivs(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>()); 1944 break; 1945 } 1946 1947 case Primitive::kPrimDouble: { 1948 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1949 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 1950 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 1951 break; 1952 } 1953 1954 default: 1955 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 1956 } 1957} 1958 1959void LocationsBuilderARM::VisitRem(HRem* rem) { 1960 LocationSummary::CallKind call_kind = rem->GetResultType() == Primitive::kPrimLong 1961 ? LocationSummary::kCall 1962 : LocationSummary::kNoCall; 1963 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(rem, call_kind); 1964 1965 switch (rem->GetResultType()) { 1966 case Primitive::kPrimInt: { 1967 locations->SetInAt(0, Location::RequiresRegister()); 1968 locations->SetInAt(1, Location::RequiresRegister()); 1969 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1970 locations->AddTemp(Location::RequiresRegister()); 1971 break; 1972 } 1973 case Primitive::kPrimLong: { 1974 InvokeRuntimeCallingConvention calling_convention; 1975 locations->SetInAt(0, Location::RegisterPairLocation( 1976 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 1977 locations->SetInAt(1, Location::RegisterPairLocation( 1978 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 1979 // The runtime helper puts the output in R2,R3. 1980 locations->SetOut(Location::RegisterPairLocation(R2, R3)); 1981 break; 1982 } 1983 case Primitive::kPrimFloat: 1984 case Primitive::kPrimDouble: { 1985 LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); 1986 break; 1987 } 1988 1989 default: 1990 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); 1991 } 1992} 1993 1994void InstructionCodeGeneratorARM::VisitRem(HRem* rem) { 1995 LocationSummary* locations = rem->GetLocations(); 1996 Location out = locations->Out(); 1997 Location first = locations->InAt(0); 1998 Location second = locations->InAt(1); 1999 2000 switch (rem->GetResultType()) { 2001 case Primitive::kPrimInt: { 2002 Register reg1 = first.As<Register>(); 2003 Register reg2 = second.As<Register>(); 2004 Register temp = locations->GetTemp(0).As<Register>(); 2005 2006 // temp = reg1 / reg2 (integer division) 2007 // temp = temp * reg2 2008 // dest = reg1 - temp 2009 __ sdiv(temp, reg1, reg2); 2010 __ mul(temp, temp, reg2); 2011 __ sub(out.As<Register>(), reg1, ShifterOperand(temp)); 2012 break; 2013 } 2014 2015 case Primitive::kPrimLong: { 2016 InvokeRuntimeCallingConvention calling_convention; 2017 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); 2018 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); 2019 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); 2020 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); 2021 DCHECK_EQ(R2, out.AsRegisterPairLow<Register>()); 2022 DCHECK_EQ(R3, out.AsRegisterPairHigh<Register>()); 2023 2024 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLmod), rem, rem->GetDexPc()); 2025 break; 2026 } 2027 2028 case Primitive::kPrimFloat: 2029 case Primitive::kPrimDouble: { 2030 LOG(FATAL) << "Unimplemented rem type " << rem->GetResultType(); 2031 break; 2032 } 2033 2034 default: 2035 LOG(FATAL) << "Unexpected rem type " << rem->GetResultType(); 2036 } 2037} 2038 2039void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { 2040 LocationSummary* locations = 2041 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2042 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); 2043 if (instruction->HasUses()) { 2044 locations->SetOut(Location::SameAsFirstInput()); 2045 } 2046} 2047 2048void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { 2049 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction); 2050 codegen_->AddSlowPath(slow_path); 2051 2052 LocationSummary* locations = instruction->GetLocations(); 2053 Location value = locations->InAt(0); 2054 2055 switch (instruction->GetType()) { 2056 case Primitive::kPrimInt: { 2057 if (value.IsRegister()) { 2058 __ cmp(value.As<Register>(), ShifterOperand(0)); 2059 __ b(slow_path->GetEntryLabel(), EQ); 2060 } else { 2061 DCHECK(value.IsConstant()) << value; 2062 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) { 2063 __ b(slow_path->GetEntryLabel()); 2064 } 2065 } 2066 break; 2067 } 2068 case Primitive::kPrimLong: { 2069 if (value.IsRegisterPair()) { 2070 __ orrs(IP, 2071 value.AsRegisterPairLow<Register>(), 2072 ShifterOperand(value.AsRegisterPairHigh<Register>())); 2073 __ b(slow_path->GetEntryLabel(), EQ); 2074 } else { 2075 DCHECK(value.IsConstant()) << value; 2076 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) { 2077 __ b(slow_path->GetEntryLabel()); 2078 } 2079 } 2080 break; 2081 default: 2082 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType(); 2083 } 2084 } 2085} 2086 2087void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 2088 LocationSummary* locations = 2089 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2090 InvokeRuntimeCallingConvention calling_convention; 2091 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2092 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2093 locations->SetOut(Location::RegisterLocation(R0)); 2094} 2095 2096void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 2097 InvokeRuntimeCallingConvention calling_convention; 2098 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 2099 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 2100 codegen_->InvokeRuntime( 2101 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc()); 2102} 2103 2104void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) { 2105 LocationSummary* locations = 2106 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2107 InvokeRuntimeCallingConvention calling_convention; 2108 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2109 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2110 locations->SetOut(Location::RegisterLocation(R0)); 2111 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 2112} 2113 2114void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) { 2115 InvokeRuntimeCallingConvention calling_convention; 2116 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 2117 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 2118 codegen_->InvokeRuntime( 2119 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc()); 2120} 2121 2122void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 2123 LocationSummary* locations = 2124 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2125 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 2126 if (location.IsStackSlot()) { 2127 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 2128 } else if (location.IsDoubleStackSlot()) { 2129 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 2130 } 2131 locations->SetOut(location); 2132} 2133 2134void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 2135 // Nothing to do, the parameter is already at its location. 2136 UNUSED(instruction); 2137} 2138 2139void LocationsBuilderARM::VisitNot(HNot* not_) { 2140 LocationSummary* locations = 2141 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall); 2142 locations->SetInAt(0, Location::RequiresRegister()); 2143 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2144} 2145 2146void InstructionCodeGeneratorARM::VisitNot(HNot* not_) { 2147 LocationSummary* locations = not_->GetLocations(); 2148 Location out = locations->Out(); 2149 Location in = locations->InAt(0); 2150 switch (not_->InputAt(0)->GetType()) { 2151 case Primitive::kPrimBoolean: 2152 __ eor(out.As<Register>(), in.As<Register>(), ShifterOperand(1)); 2153 break; 2154 2155 case Primitive::kPrimInt: 2156 __ mvn(out.As<Register>(), ShifterOperand(in.As<Register>())); 2157 break; 2158 2159 case Primitive::kPrimLong: 2160 __ mvn(out.AsRegisterPairLow<Register>(), 2161 ShifterOperand(in.AsRegisterPairLow<Register>())); 2162 __ mvn(out.AsRegisterPairHigh<Register>(), 2163 ShifterOperand(in.AsRegisterPairHigh<Register>())); 2164 break; 2165 2166 default: 2167 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType(); 2168 } 2169} 2170 2171void LocationsBuilderARM::VisitCompare(HCompare* compare) { 2172 LocationSummary* locations = 2173 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 2174 locations->SetInAt(0, Location::RequiresRegister()); 2175 locations->SetInAt(1, Location::RequiresRegister()); 2176 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2177} 2178 2179void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { 2180 LocationSummary* locations = compare->GetLocations(); 2181 switch (compare->InputAt(0)->GetType()) { 2182 case Primitive::kPrimLong: { 2183 Register output = locations->Out().As<Register>(); 2184 Location left = locations->InAt(0); 2185 Location right = locations->InAt(1); 2186 Label less, greater, done; 2187 __ cmp(left.AsRegisterPairHigh<Register>(), 2188 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare. 2189 __ b(&less, LT); 2190 __ b(&greater, GT); 2191 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect 2192 // the status flags. 2193 __ LoadImmediate(output, 0); 2194 __ cmp(left.AsRegisterPairLow<Register>(), 2195 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare. 2196 __ b(&done, EQ); 2197 __ b(&less, CC); 2198 2199 __ Bind(&greater); 2200 __ LoadImmediate(output, 1); 2201 __ b(&done); 2202 2203 __ Bind(&less); 2204 __ LoadImmediate(output, -1); 2205 2206 __ Bind(&done); 2207 break; 2208 } 2209 default: 2210 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType(); 2211 } 2212} 2213 2214void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 2215 LocationSummary* locations = 2216 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2217 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 2218 locations->SetInAt(i, Location::Any()); 2219 } 2220 locations->SetOut(Location::Any()); 2221} 2222 2223void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 2224 UNUSED(instruction); 2225 LOG(FATAL) << "Unreachable"; 2226} 2227 2228void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 2229 LocationSummary* locations = 2230 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2231 bool needs_write_barrier = 2232 CodeGenerator::StoreNeedsWriteBarrier(instruction->GetFieldType(), instruction->GetValue()); 2233 locations->SetInAt(0, Location::RequiresRegister()); 2234 locations->SetInAt(1, Location::RequiresRegister()); 2235 // Temporary registers for the write barrier. 2236 if (needs_write_barrier) { 2237 locations->AddTemp(Location::RequiresRegister()); 2238 locations->AddTemp(Location::RequiresRegister()); 2239 } 2240} 2241 2242void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 2243 LocationSummary* locations = instruction->GetLocations(); 2244 Register obj = locations->InAt(0).As<Register>(); 2245 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 2246 Primitive::Type field_type = instruction->GetFieldType(); 2247 2248 switch (field_type) { 2249 case Primitive::kPrimBoolean: 2250 case Primitive::kPrimByte: { 2251 Register value = locations->InAt(1).As<Register>(); 2252 __ StoreToOffset(kStoreByte, value, obj, offset); 2253 break; 2254 } 2255 2256 case Primitive::kPrimShort: 2257 case Primitive::kPrimChar: { 2258 Register value = locations->InAt(1).As<Register>(); 2259 __ StoreToOffset(kStoreHalfword, value, obj, offset); 2260 break; 2261 } 2262 2263 case Primitive::kPrimInt: 2264 case Primitive::kPrimNot: { 2265 Register value = locations->InAt(1).As<Register>(); 2266 __ StoreToOffset(kStoreWord, value, obj, offset); 2267 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) { 2268 Register temp = locations->GetTemp(0).As<Register>(); 2269 Register card = locations->GetTemp(1).As<Register>(); 2270 codegen_->MarkGCCard(temp, card, obj, value); 2271 } 2272 break; 2273 } 2274 2275 case Primitive::kPrimLong: { 2276 Location value = locations->InAt(1); 2277 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset); 2278 break; 2279 } 2280 2281 case Primitive::kPrimFloat: { 2282 SRegister value = locations->InAt(1).As<SRegister>(); 2283 __ StoreSToOffset(value, obj, offset); 2284 break; 2285 } 2286 2287 case Primitive::kPrimDouble: { 2288 DRegister value = FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>()); 2289 __ StoreDToOffset(value, obj, offset); 2290 break; 2291 } 2292 2293 case Primitive::kPrimVoid: 2294 LOG(FATAL) << "Unreachable type " << field_type; 2295 UNREACHABLE(); 2296 } 2297} 2298 2299void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 2300 LocationSummary* locations = 2301 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2302 locations->SetInAt(0, Location::RequiresRegister()); 2303 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2304} 2305 2306void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 2307 LocationSummary* locations = instruction->GetLocations(); 2308 Register obj = locations->InAt(0).As<Register>(); 2309 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 2310 2311 switch (instruction->GetType()) { 2312 case Primitive::kPrimBoolean: { 2313 Register out = locations->Out().As<Register>(); 2314 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 2315 break; 2316 } 2317 2318 case Primitive::kPrimByte: { 2319 Register out = locations->Out().As<Register>(); 2320 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 2321 break; 2322 } 2323 2324 case Primitive::kPrimShort: { 2325 Register out = locations->Out().As<Register>(); 2326 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 2327 break; 2328 } 2329 2330 case Primitive::kPrimChar: { 2331 Register out = locations->Out().As<Register>(); 2332 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 2333 break; 2334 } 2335 2336 case Primitive::kPrimInt: 2337 case Primitive::kPrimNot: { 2338 Register out = locations->Out().As<Register>(); 2339 __ LoadFromOffset(kLoadWord, out, obj, offset); 2340 break; 2341 } 2342 2343 case Primitive::kPrimLong: { 2344 // TODO: support volatile. 2345 Location out = locations->Out(); 2346 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset); 2347 break; 2348 } 2349 2350 case Primitive::kPrimFloat: { 2351 SRegister out = locations->Out().As<SRegister>(); 2352 __ LoadSFromOffset(out, obj, offset); 2353 break; 2354 } 2355 2356 case Primitive::kPrimDouble: { 2357 DRegister out = FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()); 2358 __ LoadDFromOffset(out, obj, offset); 2359 break; 2360 } 2361 2362 case Primitive::kPrimVoid: 2363 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 2364 UNREACHABLE(); 2365 } 2366} 2367 2368void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { 2369 LocationSummary* locations = 2370 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2371 locations->SetInAt(0, Location::RequiresRegister()); 2372 if (instruction->HasUses()) { 2373 locations->SetOut(Location::SameAsFirstInput()); 2374 } 2375} 2376 2377void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { 2378 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); 2379 codegen_->AddSlowPath(slow_path); 2380 2381 LocationSummary* locations = instruction->GetLocations(); 2382 Location obj = locations->InAt(0); 2383 2384 if (obj.IsRegister()) { 2385 __ cmp(obj.As<Register>(), ShifterOperand(0)); 2386 __ b(slow_path->GetEntryLabel(), EQ); 2387 } else { 2388 DCHECK(obj.IsConstant()) << obj; 2389 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); 2390 __ b(slow_path->GetEntryLabel()); 2391 } 2392} 2393 2394void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { 2395 LocationSummary* locations = 2396 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2397 locations->SetInAt(0, Location::RequiresRegister()); 2398 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 2399 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2400} 2401 2402void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { 2403 LocationSummary* locations = instruction->GetLocations(); 2404 Register obj = locations->InAt(0).As<Register>(); 2405 Location index = locations->InAt(1); 2406 2407 switch (instruction->GetType()) { 2408 case Primitive::kPrimBoolean: { 2409 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 2410 Register out = locations->Out().As<Register>(); 2411 if (index.IsConstant()) { 2412 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 2413 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 2414 } else { 2415 __ add(IP, obj, ShifterOperand(index.As<Register>())); 2416 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset); 2417 } 2418 break; 2419 } 2420 2421 case Primitive::kPrimByte: { 2422 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 2423 Register out = locations->Out().As<Register>(); 2424 if (index.IsConstant()) { 2425 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 2426 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 2427 } else { 2428 __ add(IP, obj, ShifterOperand(index.As<Register>())); 2429 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset); 2430 } 2431 break; 2432 } 2433 2434 case Primitive::kPrimShort: { 2435 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 2436 Register out = locations->Out().As<Register>(); 2437 if (index.IsConstant()) { 2438 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 2439 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 2440 } else { 2441 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 2442 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset); 2443 } 2444 break; 2445 } 2446 2447 case Primitive::kPrimChar: { 2448 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 2449 Register out = locations->Out().As<Register>(); 2450 if (index.IsConstant()) { 2451 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 2452 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 2453 } else { 2454 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 2455 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset); 2456 } 2457 break; 2458 } 2459 2460 case Primitive::kPrimInt: 2461 case Primitive::kPrimNot: { 2462 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t)); 2463 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 2464 Register out = locations->Out().As<Register>(); 2465 if (index.IsConstant()) { 2466 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 2467 __ LoadFromOffset(kLoadWord, out, obj, offset); 2468 } else { 2469 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4)); 2470 __ LoadFromOffset(kLoadWord, out, IP, data_offset); 2471 } 2472 break; 2473 } 2474 2475 case Primitive::kPrimLong: { 2476 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 2477 Location out = locations->Out(); 2478 if (index.IsConstant()) { 2479 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 2480 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset); 2481 } else { 2482 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8)); 2483 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset); 2484 } 2485 break; 2486 } 2487 2488 case Primitive::kPrimFloat: 2489 case Primitive::kPrimDouble: 2490 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 2491 UNREACHABLE(); 2492 case Primitive::kPrimVoid: 2493 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 2494 UNREACHABLE(); 2495 } 2496} 2497 2498void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) { 2499 Primitive::Type value_type = instruction->GetComponentType(); 2500 2501 bool needs_write_barrier = 2502 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 2503 bool needs_runtime_call = instruction->NeedsTypeCheck(); 2504 2505 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 2506 instruction, needs_runtime_call ? LocationSummary::kCall : LocationSummary::kNoCall); 2507 if (needs_runtime_call) { 2508 InvokeRuntimeCallingConvention calling_convention; 2509 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2510 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2511 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 2512 } else { 2513 locations->SetInAt(0, Location::RequiresRegister()); 2514 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 2515 locations->SetInAt(2, Location::RequiresRegister()); 2516 2517 if (needs_write_barrier) { 2518 // Temporary registers for the write barrier. 2519 locations->AddTemp(Location::RequiresRegister()); 2520 locations->AddTemp(Location::RequiresRegister()); 2521 } 2522 } 2523} 2524 2525void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { 2526 LocationSummary* locations = instruction->GetLocations(); 2527 Register obj = locations->InAt(0).As<Register>(); 2528 Location index = locations->InAt(1); 2529 Primitive::Type value_type = instruction->GetComponentType(); 2530 bool needs_runtime_call = locations->WillCall(); 2531 bool needs_write_barrier = 2532 CodeGenerator::StoreNeedsWriteBarrier(value_type, instruction->GetValue()); 2533 2534 switch (value_type) { 2535 case Primitive::kPrimBoolean: 2536 case Primitive::kPrimByte: { 2537 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 2538 Register value = locations->InAt(2).As<Register>(); 2539 if (index.IsConstant()) { 2540 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 2541 __ StoreToOffset(kStoreByte, value, obj, offset); 2542 } else { 2543 __ add(IP, obj, ShifterOperand(index.As<Register>())); 2544 __ StoreToOffset(kStoreByte, value, IP, data_offset); 2545 } 2546 break; 2547 } 2548 2549 case Primitive::kPrimShort: 2550 case Primitive::kPrimChar: { 2551 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 2552 Register value = locations->InAt(2).As<Register>(); 2553 if (index.IsConstant()) { 2554 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 2555 __ StoreToOffset(kStoreHalfword, value, obj, offset); 2556 } else { 2557 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 2558 __ StoreToOffset(kStoreHalfword, value, IP, data_offset); 2559 } 2560 break; 2561 } 2562 2563 case Primitive::kPrimInt: 2564 case Primitive::kPrimNot: { 2565 if (!needs_runtime_call) { 2566 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 2567 Register value = locations->InAt(2).As<Register>(); 2568 if (index.IsConstant()) { 2569 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 2570 __ StoreToOffset(kStoreWord, value, obj, offset); 2571 } else { 2572 DCHECK(index.IsRegister()) << index; 2573 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4)); 2574 __ StoreToOffset(kStoreWord, value, IP, data_offset); 2575 } 2576 if (needs_write_barrier) { 2577 DCHECK_EQ(value_type, Primitive::kPrimNot); 2578 Register temp = locations->GetTemp(0).As<Register>(); 2579 Register card = locations->GetTemp(1).As<Register>(); 2580 codegen_->MarkGCCard(temp, card, obj, value); 2581 } 2582 } else { 2583 DCHECK_EQ(value_type, Primitive::kPrimNot); 2584 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc()); 2585 } 2586 break; 2587 } 2588 2589 case Primitive::kPrimLong: { 2590 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 2591 Location value = locations->InAt(2); 2592 if (index.IsConstant()) { 2593 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 2594 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset); 2595 } else { 2596 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8)); 2597 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset); 2598 } 2599 break; 2600 } 2601 2602 case Primitive::kPrimFloat: 2603 case Primitive::kPrimDouble: 2604 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 2605 UNREACHABLE(); 2606 case Primitive::kPrimVoid: 2607 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 2608 UNREACHABLE(); 2609 } 2610} 2611 2612void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) { 2613 LocationSummary* locations = 2614 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2615 locations->SetInAt(0, Location::RequiresRegister()); 2616 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2617} 2618 2619void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) { 2620 LocationSummary* locations = instruction->GetLocations(); 2621 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 2622 Register obj = locations->InAt(0).As<Register>(); 2623 Register out = locations->Out().As<Register>(); 2624 __ LoadFromOffset(kLoadWord, out, obj, offset); 2625} 2626 2627void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { 2628 LocationSummary* locations = 2629 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2630 locations->SetInAt(0, Location::RequiresRegister()); 2631 locations->SetInAt(1, Location::RequiresRegister()); 2632 if (instruction->HasUses()) { 2633 locations->SetOut(Location::SameAsFirstInput()); 2634 } 2635} 2636 2637void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { 2638 LocationSummary* locations = instruction->GetLocations(); 2639 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM( 2640 instruction, locations->InAt(0), locations->InAt(1)); 2641 codegen_->AddSlowPath(slow_path); 2642 2643 Register index = locations->InAt(0).As<Register>(); 2644 Register length = locations->InAt(1).As<Register>(); 2645 2646 __ cmp(index, ShifterOperand(length)); 2647 __ b(slow_path->GetEntryLabel(), CS); 2648} 2649 2650void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) { 2651 Label is_null; 2652 __ CompareAndBranchIfZero(value, &is_null); 2653 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value()); 2654 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift); 2655 __ strb(card, Address(card, temp)); 2656 __ Bind(&is_null); 2657} 2658 2659void LocationsBuilderARM::VisitTemporary(HTemporary* temp) { 2660 temp->SetLocations(nullptr); 2661} 2662 2663void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) { 2664 // Nothing to do, this is driven by the code generator. 2665 UNUSED(temp); 2666} 2667 2668void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) { 2669 UNUSED(instruction); 2670 LOG(FATAL) << "Unreachable"; 2671} 2672 2673void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) { 2674 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 2675} 2676 2677void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) { 2678 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 2679} 2680 2681void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) { 2682 HBasicBlock* block = instruction->GetBlock(); 2683 if (block->GetLoopInformation() != nullptr) { 2684 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 2685 // The back edge will generate the suspend check. 2686 return; 2687 } 2688 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 2689 // The goto will generate the suspend check. 2690 return; 2691 } 2692 GenerateSuspendCheck(instruction, nullptr); 2693} 2694 2695void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction, 2696 HBasicBlock* successor) { 2697 SuspendCheckSlowPathARM* slow_path = 2698 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor); 2699 codegen_->AddSlowPath(slow_path); 2700 2701 __ LoadFromOffset( 2702 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value()); 2703 __ cmp(IP, ShifterOperand(0)); 2704 // TODO: Figure out the branch offsets and use cbz/cbnz. 2705 if (successor == nullptr) { 2706 __ b(slow_path->GetEntryLabel(), NE); 2707 __ Bind(slow_path->GetReturnLabel()); 2708 } else { 2709 __ b(codegen_->GetLabelOf(successor), EQ); 2710 __ b(slow_path->GetEntryLabel()); 2711 } 2712} 2713 2714ArmAssembler* ParallelMoveResolverARM::GetAssembler() const { 2715 return codegen_->GetAssembler(); 2716} 2717 2718void ParallelMoveResolverARM::EmitMove(size_t index) { 2719 MoveOperands* move = moves_.Get(index); 2720 Location source = move->GetSource(); 2721 Location destination = move->GetDestination(); 2722 2723 if (source.IsRegister()) { 2724 if (destination.IsRegister()) { 2725 __ Mov(destination.As<Register>(), source.As<Register>()); 2726 } else { 2727 DCHECK(destination.IsStackSlot()); 2728 __ StoreToOffset(kStoreWord, source.As<Register>(), 2729 SP, destination.GetStackIndex()); 2730 } 2731 } else if (source.IsStackSlot()) { 2732 if (destination.IsRegister()) { 2733 __ LoadFromOffset(kLoadWord, destination.As<Register>(), 2734 SP, source.GetStackIndex()); 2735 } else { 2736 DCHECK(destination.IsStackSlot()); 2737 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 2738 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 2739 } 2740 } else { 2741 DCHECK(source.IsConstant()); 2742 DCHECK(source.GetConstant()->IsIntConstant()); 2743 int32_t value = source.GetConstant()->AsIntConstant()->GetValue(); 2744 if (destination.IsRegister()) { 2745 __ LoadImmediate(destination.As<Register>(), value); 2746 } else { 2747 DCHECK(destination.IsStackSlot()); 2748 __ LoadImmediate(IP, value); 2749 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 2750 } 2751 } 2752} 2753 2754void ParallelMoveResolverARM::Exchange(Register reg, int mem) { 2755 __ Mov(IP, reg); 2756 __ LoadFromOffset(kLoadWord, reg, SP, mem); 2757 __ StoreToOffset(kStoreWord, IP, SP, mem); 2758} 2759 2760void ParallelMoveResolverARM::Exchange(int mem1, int mem2) { 2761 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters()); 2762 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; 2763 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()), 2764 SP, mem1 + stack_offset); 2765 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset); 2766 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()), 2767 SP, mem2 + stack_offset); 2768 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset); 2769} 2770 2771void ParallelMoveResolverARM::EmitSwap(size_t index) { 2772 MoveOperands* move = moves_.Get(index); 2773 Location source = move->GetSource(); 2774 Location destination = move->GetDestination(); 2775 2776 if (source.IsRegister() && destination.IsRegister()) { 2777 DCHECK_NE(source.As<Register>(), IP); 2778 DCHECK_NE(destination.As<Register>(), IP); 2779 __ Mov(IP, source.As<Register>()); 2780 __ Mov(source.As<Register>(), destination.As<Register>()); 2781 __ Mov(destination.As<Register>(), IP); 2782 } else if (source.IsRegister() && destination.IsStackSlot()) { 2783 Exchange(source.As<Register>(), destination.GetStackIndex()); 2784 } else if (source.IsStackSlot() && destination.IsRegister()) { 2785 Exchange(destination.As<Register>(), source.GetStackIndex()); 2786 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 2787 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 2788 } else { 2789 LOG(FATAL) << "Unimplemented"; 2790 } 2791} 2792 2793void ParallelMoveResolverARM::SpillScratch(int reg) { 2794 __ Push(static_cast<Register>(reg)); 2795} 2796 2797void ParallelMoveResolverARM::RestoreScratch(int reg) { 2798 __ Pop(static_cast<Register>(reg)); 2799} 2800 2801void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) { 2802 LocationSummary::CallKind call_kind = cls->CanCallRuntime() 2803 ? LocationSummary::kCallOnSlowPath 2804 : LocationSummary::kNoCall; 2805 LocationSummary* locations = 2806 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); 2807 locations->SetOut(Location::RequiresRegister()); 2808} 2809 2810void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { 2811 Register out = cls->GetLocations()->Out().As<Register>(); 2812 if (cls->IsReferrersClass()) { 2813 DCHECK(!cls->CanCallRuntime()); 2814 DCHECK(!cls->MustGenerateClinitCheck()); 2815 codegen_->LoadCurrentMethod(out); 2816 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()); 2817 } else { 2818 DCHECK(cls->CanCallRuntime()); 2819 codegen_->LoadCurrentMethod(out); 2820 __ LoadFromOffset( 2821 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()); 2822 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); 2823 2824 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( 2825 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); 2826 codegen_->AddSlowPath(slow_path); 2827 __ cmp(out, ShifterOperand(0)); 2828 __ b(slow_path->GetEntryLabel(), EQ); 2829 if (cls->MustGenerateClinitCheck()) { 2830 GenerateClassInitializationCheck(slow_path, out); 2831 } else { 2832 __ Bind(slow_path->GetExitLabel()); 2833 } 2834 } 2835} 2836 2837void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) { 2838 LocationSummary* locations = 2839 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath); 2840 locations->SetInAt(0, Location::RequiresRegister()); 2841 if (check->HasUses()) { 2842 locations->SetOut(Location::SameAsFirstInput()); 2843 } 2844} 2845 2846void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) { 2847 // We assume the class is not null. 2848 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( 2849 check->GetLoadClass(), check, check->GetDexPc(), true); 2850 codegen_->AddSlowPath(slow_path); 2851 GenerateClassInitializationCheck(slow_path, check->GetLocations()->InAt(0).As<Register>()); 2852} 2853 2854void InstructionCodeGeneratorARM::GenerateClassInitializationCheck( 2855 SlowPathCodeARM* slow_path, Register class_reg) { 2856 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value()); 2857 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized)); 2858 __ b(slow_path->GetEntryLabel(), LT); 2859 // Even if the initialized flag is set, we may be in a situation where caches are not synced 2860 // properly. Therefore, we do a memory fence. 2861 __ dmb(ISH); 2862 __ Bind(slow_path->GetExitLabel()); 2863} 2864 2865void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) { 2866 LocationSummary* locations = 2867 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2868 locations->SetInAt(0, Location::RequiresRegister()); 2869 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2870} 2871 2872void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) { 2873 LocationSummary* locations = instruction->GetLocations(); 2874 Register cls = locations->InAt(0).As<Register>(); 2875 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 2876 2877 switch (instruction->GetType()) { 2878 case Primitive::kPrimBoolean: { 2879 Register out = locations->Out().As<Register>(); 2880 __ LoadFromOffset(kLoadUnsignedByte, out, cls, offset); 2881 break; 2882 } 2883 2884 case Primitive::kPrimByte: { 2885 Register out = locations->Out().As<Register>(); 2886 __ LoadFromOffset(kLoadSignedByte, out, cls, offset); 2887 break; 2888 } 2889 2890 case Primitive::kPrimShort: { 2891 Register out = locations->Out().As<Register>(); 2892 __ LoadFromOffset(kLoadSignedHalfword, out, cls, offset); 2893 break; 2894 } 2895 2896 case Primitive::kPrimChar: { 2897 Register out = locations->Out().As<Register>(); 2898 __ LoadFromOffset(kLoadUnsignedHalfword, out, cls, offset); 2899 break; 2900 } 2901 2902 case Primitive::kPrimInt: 2903 case Primitive::kPrimNot: { 2904 Register out = locations->Out().As<Register>(); 2905 __ LoadFromOffset(kLoadWord, out, cls, offset); 2906 break; 2907 } 2908 2909 case Primitive::kPrimLong: { 2910 // TODO: support volatile. 2911 Location out = locations->Out(); 2912 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), cls, offset); 2913 break; 2914 } 2915 2916 case Primitive::kPrimFloat: { 2917 SRegister out = locations->Out().As<SRegister>(); 2918 __ LoadSFromOffset(out, cls, offset); 2919 break; 2920 } 2921 2922 case Primitive::kPrimDouble: { 2923 DRegister out = FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()); 2924 __ LoadDFromOffset(out, cls, offset); 2925 break; 2926 } 2927 2928 case Primitive::kPrimVoid: 2929 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 2930 UNREACHABLE(); 2931 } 2932} 2933 2934void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { 2935 LocationSummary* locations = 2936 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2937 bool needs_write_barrier = 2938 CodeGenerator::StoreNeedsWriteBarrier(instruction->GetFieldType(), instruction->GetValue()); 2939 locations->SetInAt(0, Location::RequiresRegister()); 2940 locations->SetInAt(1, Location::RequiresRegister()); 2941 // Temporary registers for the write barrier. 2942 if (needs_write_barrier) { 2943 locations->AddTemp(Location::RequiresRegister()); 2944 locations->AddTemp(Location::RequiresRegister()); 2945 } 2946} 2947 2948void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { 2949 LocationSummary* locations = instruction->GetLocations(); 2950 Register cls = locations->InAt(0).As<Register>(); 2951 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 2952 Primitive::Type field_type = instruction->GetFieldType(); 2953 2954 switch (field_type) { 2955 case Primitive::kPrimBoolean: 2956 case Primitive::kPrimByte: { 2957 Register value = locations->InAt(1).As<Register>(); 2958 __ StoreToOffset(kStoreByte, value, cls, offset); 2959 break; 2960 } 2961 2962 case Primitive::kPrimShort: 2963 case Primitive::kPrimChar: { 2964 Register value = locations->InAt(1).As<Register>(); 2965 __ StoreToOffset(kStoreHalfword, value, cls, offset); 2966 break; 2967 } 2968 2969 case Primitive::kPrimInt: 2970 case Primitive::kPrimNot: { 2971 Register value = locations->InAt(1).As<Register>(); 2972 __ StoreToOffset(kStoreWord, value, cls, offset); 2973 if (CodeGenerator::StoreNeedsWriteBarrier(field_type, instruction->GetValue())) { 2974 Register temp = locations->GetTemp(0).As<Register>(); 2975 Register card = locations->GetTemp(1).As<Register>(); 2976 codegen_->MarkGCCard(temp, card, cls, value); 2977 } 2978 break; 2979 } 2980 2981 case Primitive::kPrimLong: { 2982 Location value = locations->InAt(1); 2983 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), cls, offset); 2984 break; 2985 } 2986 2987 case Primitive::kPrimFloat: { 2988 SRegister value = locations->InAt(1).As<SRegister>(); 2989 __ StoreSToOffset(value, cls, offset); 2990 break; 2991 } 2992 2993 case Primitive::kPrimDouble: { 2994 DRegister value = FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>()); 2995 __ StoreDToOffset(value, cls, offset); 2996 break; 2997 } 2998 2999 case Primitive::kPrimVoid: 3000 LOG(FATAL) << "Unreachable type " << field_type; 3001 UNREACHABLE(); 3002 } 3003} 3004 3005void LocationsBuilderARM::VisitLoadString(HLoadString* load) { 3006 LocationSummary* locations = 3007 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath); 3008 locations->SetOut(Location::RequiresRegister()); 3009} 3010 3011void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { 3012 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load); 3013 codegen_->AddSlowPath(slow_path); 3014 3015 Register out = load->GetLocations()->Out().As<Register>(); 3016 codegen_->LoadCurrentMethod(out); 3017 __ LoadFromOffset( 3018 kLoadWord, out, out, mirror::ArtMethod::DexCacheStringsOffset().Int32Value()); 3019 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex())); 3020 __ cmp(out, ShifterOperand(0)); 3021 __ b(slow_path->GetEntryLabel(), EQ); 3022 __ Bind(slow_path->GetExitLabel()); 3023} 3024 3025void LocationsBuilderARM::VisitLoadException(HLoadException* load) { 3026 LocationSummary* locations = 3027 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall); 3028 locations->SetOut(Location::RequiresRegister()); 3029} 3030 3031void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) { 3032 Register out = load->GetLocations()->Out().As<Register>(); 3033 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value(); 3034 __ LoadFromOffset(kLoadWord, out, TR, offset); 3035 __ LoadImmediate(IP, 0); 3036 __ StoreToOffset(kStoreWord, IP, TR, offset); 3037} 3038 3039void LocationsBuilderARM::VisitThrow(HThrow* instruction) { 3040 LocationSummary* locations = 3041 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3042 InvokeRuntimeCallingConvention calling_convention; 3043 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3044} 3045 3046void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) { 3047 codegen_->InvokeRuntime( 3048 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc()); 3049} 3050 3051void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) { 3052 LocationSummary::CallKind call_kind = instruction->IsClassFinal() 3053 ? LocationSummary::kNoCall 3054 : LocationSummary::kCallOnSlowPath; 3055 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 3056 locations->SetInAt(0, Location::RequiresRegister()); 3057 locations->SetInAt(1, Location::RequiresRegister()); 3058 locations->SetOut(Location::RequiresRegister()); 3059} 3060 3061void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { 3062 LocationSummary* locations = instruction->GetLocations(); 3063 Register obj = locations->InAt(0).As<Register>(); 3064 Register cls = locations->InAt(1).As<Register>(); 3065 Register out = locations->Out().As<Register>(); 3066 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 3067 Label done, zero; 3068 SlowPathCodeARM* slow_path = nullptr; 3069 3070 // Return 0 if `obj` is null. 3071 // TODO: avoid this check if we know obj is not null. 3072 __ cmp(obj, ShifterOperand(0)); 3073 __ b(&zero, EQ); 3074 // Compare the class of `obj` with `cls`. 3075 __ LoadFromOffset(kLoadWord, out, obj, class_offset); 3076 __ cmp(out, ShifterOperand(cls)); 3077 if (instruction->IsClassFinal()) { 3078 // Classes must be equal for the instanceof to succeed. 3079 __ b(&zero, NE); 3080 __ LoadImmediate(out, 1); 3081 __ b(&done); 3082 } else { 3083 // If the classes are not equal, we go into a slow path. 3084 DCHECK(locations->OnlyCallsOnSlowPath()); 3085 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( 3086 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc()); 3087 codegen_->AddSlowPath(slow_path); 3088 __ b(slow_path->GetEntryLabel(), NE); 3089 __ LoadImmediate(out, 1); 3090 __ b(&done); 3091 } 3092 __ Bind(&zero); 3093 __ LoadImmediate(out, 0); 3094 if (slow_path != nullptr) { 3095 __ Bind(slow_path->GetExitLabel()); 3096 } 3097 __ Bind(&done); 3098} 3099 3100void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) { 3101 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 3102 instruction, LocationSummary::kCallOnSlowPath); 3103 locations->SetInAt(0, Location::RequiresRegister()); 3104 locations->SetInAt(1, Location::RequiresRegister()); 3105 locations->AddTemp(Location::RequiresRegister()); 3106} 3107 3108void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { 3109 LocationSummary* locations = instruction->GetLocations(); 3110 Register obj = locations->InAt(0).As<Register>(); 3111 Register cls = locations->InAt(1).As<Register>(); 3112 Register temp = locations->GetTemp(0).As<Register>(); 3113 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 3114 3115 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( 3116 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc()); 3117 codegen_->AddSlowPath(slow_path); 3118 3119 // TODO: avoid this check if we know obj is not null. 3120 __ cmp(obj, ShifterOperand(0)); 3121 __ b(slow_path->GetExitLabel(), EQ); 3122 // Compare the class of `obj` with `cls`. 3123 __ LoadFromOffset(kLoadWord, temp, obj, class_offset); 3124 __ cmp(temp, ShifterOperand(cls)); 3125 __ b(slow_path->GetEntryLabel(), NE); 3126 __ Bind(slow_path->GetExitLabel()); 3127} 3128 3129void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) { 3130 LocationSummary* locations = 3131 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 3132 InvokeRuntimeCallingConvention calling_convention; 3133 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 3134} 3135 3136void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) { 3137 codegen_->InvokeRuntime(instruction->IsEnter() 3138 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject), 3139 instruction, 3140 instruction->GetDexPc()); 3141} 3142 3143void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } 3144void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } 3145void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } 3146 3147void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) { 3148 LocationSummary* locations = 3149 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 3150 DCHECK(instruction->GetResultType() == Primitive::kPrimInt 3151 || instruction->GetResultType() == Primitive::kPrimLong); 3152 locations->SetInAt(0, Location::RequiresRegister()); 3153 locations->SetInAt(1, Location::RequiresRegister()); 3154 bool output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong); 3155 locations->SetOut(Location::RequiresRegister(), output_overlaps); 3156} 3157 3158void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) { 3159 HandleBitwiseOperation(instruction); 3160} 3161 3162void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) { 3163 HandleBitwiseOperation(instruction); 3164} 3165 3166void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) { 3167 HandleBitwiseOperation(instruction); 3168} 3169 3170void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) { 3171 LocationSummary* locations = instruction->GetLocations(); 3172 3173 if (instruction->GetResultType() == Primitive::kPrimInt) { 3174 Register first = locations->InAt(0).As<Register>(); 3175 Register second = locations->InAt(1).As<Register>(); 3176 Register out = locations->Out().As<Register>(); 3177 if (instruction->IsAnd()) { 3178 __ and_(out, first, ShifterOperand(second)); 3179 } else if (instruction->IsOr()) { 3180 __ orr(out, first, ShifterOperand(second)); 3181 } else { 3182 DCHECK(instruction->IsXor()); 3183 __ eor(out, first, ShifterOperand(second)); 3184 } 3185 } else { 3186 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); 3187 Location first = locations->InAt(0); 3188 Location second = locations->InAt(1); 3189 Location out = locations->Out(); 3190 if (instruction->IsAnd()) { 3191 __ and_(out.AsRegisterPairLow<Register>(), 3192 first.AsRegisterPairLow<Register>(), 3193 ShifterOperand(second.AsRegisterPairLow<Register>())); 3194 __ and_(out.AsRegisterPairHigh<Register>(), 3195 first.AsRegisterPairHigh<Register>(), 3196 ShifterOperand(second.AsRegisterPairHigh<Register>())); 3197 } else if (instruction->IsOr()) { 3198 __ orr(out.AsRegisterPairLow<Register>(), 3199 first.AsRegisterPairLow<Register>(), 3200 ShifterOperand(second.AsRegisterPairLow<Register>())); 3201 __ orr(out.AsRegisterPairHigh<Register>(), 3202 first.AsRegisterPairHigh<Register>(), 3203 ShifterOperand(second.AsRegisterPairHigh<Register>())); 3204 } else { 3205 DCHECK(instruction->IsXor()); 3206 __ eor(out.AsRegisterPairLow<Register>(), 3207 first.AsRegisterPairLow<Register>(), 3208 ShifterOperand(second.AsRegisterPairLow<Register>())); 3209 __ eor(out.AsRegisterPairHigh<Register>(), 3210 first.AsRegisterPairHigh<Register>(), 3211 ShifterOperand(second.AsRegisterPairHigh<Register>())); 3212 } 3213 } 3214} 3215 3216} // namespace arm 3217} // namespace art 3218