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