code_generator_arm.cc revision a21f598fd4dfdb95dc8597d3156120cc20d94c02
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()) << destination; 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()) << source; 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 (locations != nullptr && locations->Out().IsConstant()) { 784 HConstant* const_to_move = locations->Out().GetConstant(); 785 if (const_to_move->IsIntConstant()) { 786 int32_t value = const_to_move->AsIntConstant()->GetValue(); 787 if (location.IsRegister()) { 788 __ LoadImmediate(location.As<Register>(), value); 789 } else { 790 DCHECK(location.IsStackSlot()); 791 __ LoadImmediate(IP, value); 792 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); 793 } 794 } else if (const_to_move->IsLongConstant()) { 795 int64_t value = const_to_move->AsLongConstant()->GetValue(); 796 if (location.IsRegisterPair()) { 797 __ LoadImmediate(location.AsRegisterPairLow<Register>(), Low32Bits(value)); 798 __ LoadImmediate(location.AsRegisterPairHigh<Register>(), High32Bits(value)); 799 } else { 800 DCHECK(location.IsDoubleStackSlot()); 801 __ LoadImmediate(IP, Low32Bits(value)); 802 __ StoreToOffset(kStoreWord, IP, SP, location.GetStackIndex()); 803 __ LoadImmediate(IP, High32Bits(value)); 804 __ StoreToOffset(kStoreWord, IP, SP, location.GetHighStackIndex(kArmWordSize)); 805 } 806 } 807 } else if (instruction->IsLoadLocal()) { 808 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 809 switch (instruction->GetType()) { 810 case Primitive::kPrimBoolean: 811 case Primitive::kPrimByte: 812 case Primitive::kPrimChar: 813 case Primitive::kPrimShort: 814 case Primitive::kPrimInt: 815 case Primitive::kPrimNot: 816 case Primitive::kPrimFloat: 817 Move32(location, Location::StackSlot(stack_slot)); 818 break; 819 820 case Primitive::kPrimLong: 821 case Primitive::kPrimDouble: 822 Move64(location, Location::DoubleStackSlot(stack_slot)); 823 break; 824 825 default: 826 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 827 } 828 } else if (instruction->IsTemporary()) { 829 Location temp_location = GetTemporaryLocation(instruction->AsTemporary()); 830 if (temp_location.IsStackSlot()) { 831 Move32(location, temp_location); 832 } else { 833 DCHECK(temp_location.IsDoubleStackSlot()); 834 Move64(location, temp_location); 835 } 836 } else { 837 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary()); 838 switch (instruction->GetType()) { 839 case Primitive::kPrimBoolean: 840 case Primitive::kPrimByte: 841 case Primitive::kPrimChar: 842 case Primitive::kPrimShort: 843 case Primitive::kPrimNot: 844 case Primitive::kPrimInt: 845 case Primitive::kPrimFloat: 846 Move32(location, locations->Out()); 847 break; 848 849 case Primitive::kPrimLong: 850 case Primitive::kPrimDouble: 851 Move64(location, locations->Out()); 852 break; 853 854 default: 855 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 856 } 857 } 858} 859 860void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset, 861 HInstruction* instruction, 862 uint32_t dex_pc) { 863 __ LoadFromOffset(kLoadWord, LR, TR, entry_point_offset); 864 __ blx(LR); 865 RecordPcInfo(instruction, dex_pc); 866 DCHECK(instruction->IsSuspendCheck() 867 || instruction->IsBoundsCheck() 868 || instruction->IsNullCheck() 869 || instruction->IsDivZeroCheck() 870 || !IsLeafMethod()); 871} 872 873void LocationsBuilderARM::VisitGoto(HGoto* got) { 874 got->SetLocations(nullptr); 875} 876 877void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { 878 HBasicBlock* successor = got->GetSuccessor(); 879 DCHECK(!successor->IsExitBlock()); 880 881 HBasicBlock* block = got->GetBlock(); 882 HInstruction* previous = got->GetPrevious(); 883 884 HLoopInformation* info = block->GetLoopInformation(); 885 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) { 886 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); 887 GenerateSuspendCheck(info->GetSuspendCheck(), successor); 888 return; 889 } 890 891 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) { 892 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr); 893 } 894 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 895 __ b(codegen_->GetLabelOf(successor)); 896 } 897} 898 899void LocationsBuilderARM::VisitExit(HExit* exit) { 900 exit->SetLocations(nullptr); 901} 902 903void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { 904 UNUSED(exit); 905 if (kIsDebugBuild) { 906 __ Comment("Unreachable"); 907 __ bkpt(0); 908 } 909} 910 911void LocationsBuilderARM::VisitIf(HIf* if_instr) { 912 LocationSummary* locations = 913 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); 914 HInstruction* cond = if_instr->InputAt(0); 915 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 916 locations->SetInAt(0, Location::RequiresRegister()); 917 } 918} 919 920void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 921 HInstruction* cond = if_instr->InputAt(0); 922 if (cond->IsIntConstant()) { 923 // Constant condition, statically compared against 1. 924 int32_t cond_value = cond->AsIntConstant()->GetValue(); 925 if (cond_value == 1) { 926 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), 927 if_instr->IfTrueSuccessor())) { 928 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 929 } 930 return; 931 } else { 932 DCHECK_EQ(cond_value, 0); 933 } 934 } else { 935 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 936 // Condition has been materialized, compare the output to 0 937 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister()); 938 __ cmp(if_instr->GetLocations()->InAt(0).As<Register>(), 939 ShifterOperand(0)); 940 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE); 941 } else { 942 // Condition has not been materialized, use its inputs as the 943 // comparison and its condition as the branch condition. 944 LocationSummary* locations = cond->GetLocations(); 945 if (locations->InAt(1).IsRegister()) { 946 __ cmp(locations->InAt(0).As<Register>(), 947 ShifterOperand(locations->InAt(1).As<Register>())); 948 } else { 949 DCHECK(locations->InAt(1).IsConstant()); 950 int32_t value = 951 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 952 ShifterOperand operand; 953 if (ShifterOperand::CanHoldArm(value, &operand)) { 954 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value)); 955 } else { 956 Register temp = IP; 957 __ LoadImmediate(temp, value); 958 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp)); 959 } 960 } 961 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), 962 ARMCondition(cond->AsCondition()->GetCondition())); 963 } 964 } 965 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), 966 if_instr->IfFalseSuccessor())) { 967 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); 968 } 969} 970 971 972void LocationsBuilderARM::VisitCondition(HCondition* comp) { 973 LocationSummary* locations = 974 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); 975 locations->SetInAt(0, Location::RequiresRegister()); 976 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1))); 977 if (comp->NeedsMaterialization()) { 978 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 979 } 980} 981 982void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) { 983 if (!comp->NeedsMaterialization()) return; 984 985 LocationSummary* locations = comp->GetLocations(); 986 if (locations->InAt(1).IsRegister()) { 987 __ cmp(locations->InAt(0).As<Register>(), 988 ShifterOperand(locations->InAt(1).As<Register>())); 989 } else { 990 DCHECK(locations->InAt(1).IsConstant()); 991 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 992 ShifterOperand operand; 993 if (ShifterOperand::CanHoldArm(value, &operand)) { 994 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(value)); 995 } else { 996 Register temp = IP; 997 __ LoadImmediate(temp, value); 998 __ cmp(locations->InAt(0).As<Register>(), ShifterOperand(temp)); 999 } 1000 } 1001 __ it(ARMCondition(comp->GetCondition()), kItElse); 1002 __ mov(locations->Out().As<Register>(), ShifterOperand(1), 1003 ARMCondition(comp->GetCondition())); 1004 __ mov(locations->Out().As<Register>(), ShifterOperand(0), 1005 ARMOppositeCondition(comp->GetCondition())); 1006} 1007 1008void LocationsBuilderARM::VisitEqual(HEqual* comp) { 1009 VisitCondition(comp); 1010} 1011 1012void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) { 1013 VisitCondition(comp); 1014} 1015 1016void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) { 1017 VisitCondition(comp); 1018} 1019 1020void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) { 1021 VisitCondition(comp); 1022} 1023 1024void LocationsBuilderARM::VisitLessThan(HLessThan* comp) { 1025 VisitCondition(comp); 1026} 1027 1028void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) { 1029 VisitCondition(comp); 1030} 1031 1032void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 1033 VisitCondition(comp); 1034} 1035 1036void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 1037 VisitCondition(comp); 1038} 1039 1040void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) { 1041 VisitCondition(comp); 1042} 1043 1044void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) { 1045 VisitCondition(comp); 1046} 1047 1048void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1049 VisitCondition(comp); 1050} 1051 1052void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 1053 VisitCondition(comp); 1054} 1055 1056void LocationsBuilderARM::VisitLocal(HLocal* local) { 1057 local->SetLocations(nullptr); 1058} 1059 1060void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 1061 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 1062} 1063 1064void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 1065 load->SetLocations(nullptr); 1066} 1067 1068void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 1069 // Nothing to do, this is driven by the code generator. 1070 UNUSED(load); 1071} 1072 1073void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 1074 LocationSummary* locations = 1075 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall); 1076 switch (store->InputAt(1)->GetType()) { 1077 case Primitive::kPrimBoolean: 1078 case Primitive::kPrimByte: 1079 case Primitive::kPrimChar: 1080 case Primitive::kPrimShort: 1081 case Primitive::kPrimInt: 1082 case Primitive::kPrimNot: 1083 case Primitive::kPrimFloat: 1084 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1085 break; 1086 1087 case Primitive::kPrimLong: 1088 case Primitive::kPrimDouble: 1089 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 1090 break; 1091 1092 default: 1093 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType(); 1094 } 1095} 1096 1097void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 1098 UNUSED(store); 1099} 1100 1101void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 1102 LocationSummary* locations = 1103 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1104 locations->SetOut(Location::ConstantLocation(constant)); 1105} 1106 1107void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 1108 // Will be generated at use site. 1109 UNUSED(constant); 1110} 1111 1112void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { 1113 LocationSummary* locations = 1114 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1115 locations->SetOut(Location::ConstantLocation(constant)); 1116} 1117 1118void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { 1119 // Will be generated at use site. 1120 UNUSED(constant); 1121} 1122 1123void LocationsBuilderARM::VisitFloatConstant(HFloatConstant* constant) { 1124 LocationSummary* locations = 1125 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1126 locations->SetOut(Location::ConstantLocation(constant)); 1127} 1128 1129void InstructionCodeGeneratorARM::VisitFloatConstant(HFloatConstant* constant) { 1130 // Will be generated at use site. 1131 UNUSED(constant); 1132} 1133 1134void LocationsBuilderARM::VisitDoubleConstant(HDoubleConstant* constant) { 1135 LocationSummary* locations = 1136 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 1137 locations->SetOut(Location::ConstantLocation(constant)); 1138} 1139 1140void InstructionCodeGeneratorARM::VisitDoubleConstant(HDoubleConstant* constant) { 1141 // Will be generated at use site. 1142 UNUSED(constant); 1143} 1144 1145void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 1146 ret->SetLocations(nullptr); 1147} 1148 1149void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 1150 UNUSED(ret); 1151 codegen_->GenerateFrameExit(); 1152} 1153 1154void LocationsBuilderARM::VisitReturn(HReturn* ret) { 1155 LocationSummary* locations = 1156 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall); 1157 locations->SetInAt(0, parameter_visitor_.GetReturnLocation(ret->InputAt(0)->GetType())); 1158} 1159 1160void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 1161 UNUSED(ret); 1162 codegen_->GenerateFrameExit(); 1163} 1164 1165void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { 1166 HandleInvoke(invoke); 1167} 1168 1169void CodeGeneratorARM::LoadCurrentMethod(Register reg) { 1170 __ LoadFromOffset(kLoadWord, reg, SP, kCurrentMethodStackOffset); 1171} 1172 1173void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { 1174 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); 1175 1176 // TODO: Implement all kinds of calls: 1177 // 1) boot -> boot 1178 // 2) app -> boot 1179 // 3) app -> app 1180 // 1181 // Currently we implement the app -> app logic, which looks up in the resolve cache. 1182 1183 // temp = method; 1184 codegen_->LoadCurrentMethod(temp); 1185 // temp = temp->dex_cache_resolved_methods_; 1186 __ LoadFromOffset( 1187 kLoadWord, temp, temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()); 1188 // temp = temp[index_in_cache] 1189 __ LoadFromOffset( 1190 kLoadWord, temp, temp, CodeGenerator::GetCacheOffset(invoke->GetIndexInDexCache())); 1191 // LR = temp[offset_of_quick_compiled_code] 1192 __ LoadFromOffset(kLoadWord, LR, temp, 1193 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()); 1194 // LR() 1195 __ blx(LR); 1196 1197 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1198 DCHECK(!codegen_->IsLeafMethod()); 1199} 1200 1201void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { 1202 LocationSummary* locations = 1203 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); 1204 locations->AddTemp(Location::RegisterLocation(R0)); 1205 1206 InvokeDexCallingConventionVisitor calling_convention_visitor; 1207 for (size_t i = 0; i < invoke->InputCount(); i++) { 1208 HInstruction* input = invoke->InputAt(i); 1209 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 1210 } 1211 1212 locations->SetOut(calling_convention_visitor.GetReturnLocation(invoke->GetType())); 1213} 1214 1215void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1216 HandleInvoke(invoke); 1217} 1218 1219void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 1220 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); 1221 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() + 1222 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); 1223 LocationSummary* locations = invoke->GetLocations(); 1224 Location receiver = locations->InAt(0); 1225 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1226 // temp = object->GetClass(); 1227 if (receiver.IsStackSlot()) { 1228 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); 1229 __ LoadFromOffset(kLoadWord, temp, temp, class_offset); 1230 } else { 1231 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); 1232 } 1233 // temp = temp->GetMethodAt(method_offset); 1234 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); 1235 __ LoadFromOffset(kLoadWord, temp, temp, method_offset); 1236 // LR = temp->GetEntryPoint(); 1237 __ LoadFromOffset(kLoadWord, LR, temp, entry_point); 1238 // LR(); 1239 __ blx(LR); 1240 DCHECK(!codegen_->IsLeafMethod()); 1241 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1242} 1243 1244void LocationsBuilderARM::VisitInvokeInterface(HInvokeInterface* invoke) { 1245 HandleInvoke(invoke); 1246 // Add the hidden argument. 1247 invoke->GetLocations()->AddTemp(Location::RegisterLocation(R12)); 1248} 1249 1250void InstructionCodeGeneratorARM::VisitInvokeInterface(HInvokeInterface* invoke) { 1251 // TODO: b/18116999, our IMTs can miss an IncompatibleClassChangeError. 1252 Register temp = invoke->GetLocations()->GetTemp(0).As<Register>(); 1253 uint32_t method_offset = mirror::Class::EmbeddedImTableOffset().Uint32Value() + 1254 (invoke->GetImtIndex() % mirror::Class::kImtSize) * sizeof(mirror::Class::ImTableEntry); 1255 LocationSummary* locations = invoke->GetLocations(); 1256 Location receiver = locations->InAt(0); 1257 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 1258 1259 // Set the hidden argument. 1260 __ LoadImmediate(invoke->GetLocations()->GetTemp(1).As<Register>(), invoke->GetDexMethodIndex()); 1261 1262 // temp = object->GetClass(); 1263 if (receiver.IsStackSlot()) { 1264 __ LoadFromOffset(kLoadWord, temp, SP, receiver.GetStackIndex()); 1265 __ LoadFromOffset(kLoadWord, temp, temp, class_offset); 1266 } else { 1267 __ LoadFromOffset(kLoadWord, temp, receiver.As<Register>(), class_offset); 1268 } 1269 // temp = temp->GetImtEntryAt(method_offset); 1270 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); 1271 __ LoadFromOffset(kLoadWord, temp, temp, method_offset); 1272 // LR = temp->GetEntryPoint(); 1273 __ LoadFromOffset(kLoadWord, LR, temp, entry_point); 1274 // LR(); 1275 __ blx(LR); 1276 DCHECK(!codegen_->IsLeafMethod()); 1277 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1278} 1279 1280void LocationsBuilderARM::VisitNeg(HNeg* neg) { 1281 LocationSummary* locations = 1282 new (GetGraph()->GetArena()) LocationSummary(neg, LocationSummary::kNoCall); 1283 switch (neg->GetResultType()) { 1284 case Primitive::kPrimInt: 1285 case Primitive::kPrimLong: { 1286 bool output_overlaps = (neg->GetResultType() == Primitive::kPrimLong); 1287 locations->SetInAt(0, Location::RequiresRegister()); 1288 locations->SetOut(Location::RequiresRegister(), output_overlaps); 1289 break; 1290 } 1291 1292 case Primitive::kPrimFloat: 1293 case Primitive::kPrimDouble: 1294 locations->SetInAt(0, Location::RequiresFpuRegister()); 1295 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1296 break; 1297 1298 default: 1299 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1300 } 1301} 1302 1303void InstructionCodeGeneratorARM::VisitNeg(HNeg* neg) { 1304 LocationSummary* locations = neg->GetLocations(); 1305 Location out = locations->Out(); 1306 Location in = locations->InAt(0); 1307 switch (neg->GetResultType()) { 1308 case Primitive::kPrimInt: 1309 DCHECK(in.IsRegister()); 1310 __ rsb(out.As<Register>(), in.As<Register>(), ShifterOperand(0)); 1311 break; 1312 1313 case Primitive::kPrimLong: 1314 DCHECK(in.IsRegisterPair()); 1315 // out.lo = 0 - in.lo (and update the carry/borrow (C) flag) 1316 __ rsbs(out.AsRegisterPairLow<Register>(), 1317 in.AsRegisterPairLow<Register>(), 1318 ShifterOperand(0)); 1319 // We cannot emit an RSC (Reverse Subtract with Carry) 1320 // instruction here, as it does not exist in the Thumb-2 1321 // instruction set. We use the following approach 1322 // using SBC and SUB instead. 1323 // 1324 // out.hi = -C 1325 __ sbc(out.AsRegisterPairHigh<Register>(), 1326 out.AsRegisterPairHigh<Register>(), 1327 ShifterOperand(out.AsRegisterPairHigh<Register>())); 1328 // out.hi = out.hi - in.hi 1329 __ sub(out.AsRegisterPairHigh<Register>(), 1330 out.AsRegisterPairHigh<Register>(), 1331 ShifterOperand(in.AsRegisterPairHigh<Register>())); 1332 break; 1333 1334 case Primitive::kPrimFloat: 1335 DCHECK(in.IsFpuRegister()); 1336 __ vnegs(out.As<SRegister>(), in.As<SRegister>()); 1337 break; 1338 1339 case Primitive::kPrimDouble: 1340 DCHECK(in.IsFpuRegisterPair()); 1341 __ vnegd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1342 FromLowSToD(in.AsFpuRegisterPairLow<SRegister>())); 1343 break; 1344 1345 default: 1346 LOG(FATAL) << "Unexpected neg type " << neg->GetResultType(); 1347 } 1348} 1349 1350void LocationsBuilderARM::VisitTypeConversion(HTypeConversion* conversion) { 1351 LocationSummary* locations = 1352 new (GetGraph()->GetArena()) LocationSummary(conversion, LocationSummary::kNoCall); 1353 Primitive::Type result_type = conversion->GetResultType(); 1354 Primitive::Type input_type = conversion->GetInputType(); 1355 switch (result_type) { 1356 case Primitive::kPrimInt: 1357 switch (input_type) { 1358 case Primitive::kPrimLong: 1359 // long-to-int conversion. 1360 locations->SetInAt(0, Location::Any()); 1361 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1362 break; 1363 1364 case Primitive::kPrimFloat: 1365 case Primitive::kPrimDouble: 1366 LOG(FATAL) << "Type conversion from " << input_type 1367 << " to " << result_type << " not yet implemented"; 1368 break; 1369 1370 default: 1371 LOG(FATAL) << "Unexpected type conversion from " << input_type 1372 << " to " << result_type; 1373 } 1374 break; 1375 1376 case Primitive::kPrimLong: 1377 switch (input_type) { 1378 case Primitive::kPrimByte: 1379 case Primitive::kPrimShort: 1380 case Primitive::kPrimInt: 1381 case Primitive::kPrimChar: 1382 // int-to-long conversion. 1383 locations->SetInAt(0, Location::RequiresRegister()); 1384 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1385 break; 1386 1387 case Primitive::kPrimFloat: 1388 case Primitive::kPrimDouble: 1389 LOG(FATAL) << "Type conversion from " << input_type << " to " 1390 << result_type << " not yet implemented"; 1391 break; 1392 1393 default: 1394 LOG(FATAL) << "Unexpected type conversion from " << input_type 1395 << " to " << result_type; 1396 } 1397 break; 1398 1399 case Primitive::kPrimFloat: 1400 case Primitive::kPrimDouble: 1401 LOG(FATAL) << "Type conversion from " << input_type 1402 << " to " << result_type << " not yet implemented"; 1403 break; 1404 1405 default: 1406 LOG(FATAL) << "Unexpected type conversion from " << input_type 1407 << " to " << result_type; 1408 } 1409} 1410 1411void InstructionCodeGeneratorARM::VisitTypeConversion(HTypeConversion* conversion) { 1412 LocationSummary* locations = conversion->GetLocations(); 1413 Location out = locations->Out(); 1414 Location in = locations->InAt(0); 1415 Primitive::Type result_type = conversion->GetResultType(); 1416 Primitive::Type input_type = conversion->GetInputType(); 1417 switch (result_type) { 1418 case Primitive::kPrimInt: 1419 switch (input_type) { 1420 case Primitive::kPrimLong: 1421 // long-to-int conversion. 1422 DCHECK(out.IsRegister()); 1423 if (in.IsRegisterPair()) { 1424 __ Mov(out.As<Register>(), in.AsRegisterPairLow<Register>()); 1425 } else if (in.IsDoubleStackSlot()) { 1426 __ LoadFromOffset(kLoadWord, out.As<Register>(), SP, in.GetStackIndex()); 1427 } else { 1428 DCHECK(in.IsConstant()); 1429 DCHECK(in.GetConstant()->IsLongConstant()); 1430 int64_t value = in.GetConstant()->AsLongConstant()->GetValue(); 1431 __ LoadImmediate(out.As<Register>(), static_cast<int32_t>(value)); 1432 } 1433 break; 1434 1435 case Primitive::kPrimFloat: 1436 case Primitive::kPrimDouble: 1437 LOG(FATAL) << "Type conversion from " << input_type 1438 << " to " << result_type << " not yet implemented"; 1439 break; 1440 1441 default: 1442 LOG(FATAL) << "Unexpected type conversion from " << input_type 1443 << " to " << result_type; 1444 } 1445 break; 1446 1447 case Primitive::kPrimLong: 1448 switch (input_type) { 1449 case Primitive::kPrimByte: 1450 case Primitive::kPrimShort: 1451 case Primitive::kPrimInt: 1452 case Primitive::kPrimChar: 1453 // int-to-long conversion. 1454 DCHECK(out.IsRegisterPair()); 1455 DCHECK(in.IsRegister()); 1456 __ Mov(out.AsRegisterPairLow<Register>(), in.As<Register>()); 1457 // Sign extension. 1458 __ Asr(out.AsRegisterPairHigh<Register>(), 1459 out.AsRegisterPairLow<Register>(), 1460 31); 1461 break; 1462 1463 case Primitive::kPrimFloat: 1464 case Primitive::kPrimDouble: 1465 LOG(FATAL) << "Type conversion from " << input_type << " to " 1466 << result_type << " not yet implemented"; 1467 break; 1468 1469 default: 1470 LOG(FATAL) << "Unexpected type conversion from " << input_type 1471 << " to " << result_type; 1472 } 1473 break; 1474 1475 case Primitive::kPrimFloat: 1476 case Primitive::kPrimDouble: 1477 LOG(FATAL) << "Type conversion from " << input_type 1478 << " to " << result_type << " not yet implemented"; 1479 break; 1480 1481 default: 1482 LOG(FATAL) << "Unexpected type conversion from " << input_type 1483 << " to " << result_type; 1484 } 1485} 1486 1487void LocationsBuilderARM::VisitAdd(HAdd* add) { 1488 LocationSummary* locations = 1489 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); 1490 switch (add->GetResultType()) { 1491 case Primitive::kPrimInt: 1492 case Primitive::kPrimLong: { 1493 bool output_overlaps = (add->GetResultType() == Primitive::kPrimLong); 1494 locations->SetInAt(0, Location::RequiresRegister()); 1495 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1))); 1496 locations->SetOut(Location::RequiresRegister(), output_overlaps); 1497 break; 1498 } 1499 1500 case Primitive::kPrimFloat: 1501 case Primitive::kPrimDouble: { 1502 locations->SetInAt(0, Location::RequiresFpuRegister()); 1503 locations->SetInAt(1, Location::RequiresFpuRegister()); 1504 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1505 break; 1506 } 1507 1508 default: 1509 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1510 } 1511} 1512 1513void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 1514 LocationSummary* locations = add->GetLocations(); 1515 Location out = locations->Out(); 1516 Location first = locations->InAt(0); 1517 Location second = locations->InAt(1); 1518 switch (add->GetResultType()) { 1519 case Primitive::kPrimInt: 1520 if (second.IsRegister()) { 1521 __ add(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>())); 1522 } else { 1523 __ AddConstant(out.As<Register>(), 1524 first.As<Register>(), 1525 second.GetConstant()->AsIntConstant()->GetValue()); 1526 } 1527 break; 1528 1529 case Primitive::kPrimLong: 1530 __ adds(out.AsRegisterPairLow<Register>(), 1531 first.AsRegisterPairLow<Register>(), 1532 ShifterOperand(second.AsRegisterPairLow<Register>())); 1533 __ adc(out.AsRegisterPairHigh<Register>(), 1534 first.AsRegisterPairHigh<Register>(), 1535 ShifterOperand(second.AsRegisterPairHigh<Register>())); 1536 break; 1537 1538 case Primitive::kPrimFloat: 1539 __ vadds(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>()); 1540 break; 1541 1542 case Primitive::kPrimDouble: 1543 __ vaddd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1544 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 1545 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 1546 break; 1547 1548 default: 1549 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1550 } 1551} 1552 1553void LocationsBuilderARM::VisitSub(HSub* sub) { 1554 LocationSummary* locations = 1555 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall); 1556 switch (sub->GetResultType()) { 1557 case Primitive::kPrimInt: 1558 case Primitive::kPrimLong: { 1559 bool output_overlaps = (sub->GetResultType() == Primitive::kPrimLong); 1560 locations->SetInAt(0, Location::RequiresRegister()); 1561 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1))); 1562 locations->SetOut(Location::RequiresRegister(), output_overlaps); 1563 break; 1564 } 1565 case Primitive::kPrimFloat: 1566 case Primitive::kPrimDouble: { 1567 locations->SetInAt(0, Location::RequiresFpuRegister()); 1568 locations->SetInAt(1, Location::RequiresFpuRegister()); 1569 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1570 break; 1571 } 1572 default: 1573 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1574 } 1575} 1576 1577void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { 1578 LocationSummary* locations = sub->GetLocations(); 1579 Location out = locations->Out(); 1580 Location first = locations->InAt(0); 1581 Location second = locations->InAt(1); 1582 switch (sub->GetResultType()) { 1583 case Primitive::kPrimInt: { 1584 if (second.IsRegister()) { 1585 __ sub(out.As<Register>(), first.As<Register>(), ShifterOperand(second.As<Register>())); 1586 } else { 1587 __ AddConstant(out.As<Register>(), 1588 first.As<Register>(), 1589 -second.GetConstant()->AsIntConstant()->GetValue()); 1590 } 1591 break; 1592 } 1593 1594 case Primitive::kPrimLong: { 1595 __ subs(out.AsRegisterPairLow<Register>(), 1596 first.AsRegisterPairLow<Register>(), 1597 ShifterOperand(second.AsRegisterPairLow<Register>())); 1598 __ sbc(out.AsRegisterPairHigh<Register>(), 1599 first.AsRegisterPairHigh<Register>(), 1600 ShifterOperand(second.AsRegisterPairHigh<Register>())); 1601 break; 1602 } 1603 1604 case Primitive::kPrimFloat: { 1605 __ vsubs(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>()); 1606 break; 1607 } 1608 1609 case Primitive::kPrimDouble: { 1610 __ vsubd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1611 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 1612 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 1613 break; 1614 } 1615 1616 1617 default: 1618 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1619 } 1620} 1621 1622void LocationsBuilderARM::VisitMul(HMul* mul) { 1623 LocationSummary* locations = 1624 new (GetGraph()->GetArena()) LocationSummary(mul, LocationSummary::kNoCall); 1625 switch (mul->GetResultType()) { 1626 case Primitive::kPrimInt: 1627 case Primitive::kPrimLong: { 1628 locations->SetInAt(0, Location::RequiresRegister()); 1629 locations->SetInAt(1, Location::RequiresRegister()); 1630 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1631 break; 1632 } 1633 1634 case Primitive::kPrimFloat: 1635 case Primitive::kPrimDouble: { 1636 locations->SetInAt(0, Location::RequiresFpuRegister()); 1637 locations->SetInAt(1, Location::RequiresFpuRegister()); 1638 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1639 break; 1640 } 1641 1642 default: 1643 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 1644 } 1645} 1646 1647void InstructionCodeGeneratorARM::VisitMul(HMul* mul) { 1648 LocationSummary* locations = mul->GetLocations(); 1649 Location out = locations->Out(); 1650 Location first = locations->InAt(0); 1651 Location second = locations->InAt(1); 1652 switch (mul->GetResultType()) { 1653 case Primitive::kPrimInt: { 1654 __ mul(out.As<Register>(), first.As<Register>(), second.As<Register>()); 1655 break; 1656 } 1657 case Primitive::kPrimLong: { 1658 Register out_hi = out.AsRegisterPairHigh<Register>(); 1659 Register out_lo = out.AsRegisterPairLow<Register>(); 1660 Register in1_hi = first.AsRegisterPairHigh<Register>(); 1661 Register in1_lo = first.AsRegisterPairLow<Register>(); 1662 Register in2_hi = second.AsRegisterPairHigh<Register>(); 1663 Register in2_lo = second.AsRegisterPairLow<Register>(); 1664 1665 // Extra checks to protect caused by the existence of R1_R2. 1666 // The algorithm is wrong if out.hi is either in1.lo or in2.lo: 1667 // (e.g. in1=r0_r1, in2=r2_r3 and out=r1_r2); 1668 DCHECK_NE(out_hi, in1_lo); 1669 DCHECK_NE(out_hi, in2_lo); 1670 1671 // input: in1 - 64 bits, in2 - 64 bits 1672 // output: out 1673 // formula: out.hi : out.lo = (in1.lo * in2.hi + in1.hi * in2.lo)* 2^32 + in1.lo * in2.lo 1674 // parts: out.hi = in1.lo * in2.hi + in1.hi * in2.lo + (in1.lo * in2.lo)[63:32] 1675 // parts: out.lo = (in1.lo * in2.lo)[31:0] 1676 1677 // IP <- in1.lo * in2.hi 1678 __ mul(IP, in1_lo, in2_hi); 1679 // out.hi <- in1.lo * in2.hi + in1.hi * in2.lo 1680 __ mla(out_hi, in1_hi, in2_lo, IP); 1681 // out.lo <- (in1.lo * in2.lo)[31:0]; 1682 __ umull(out_lo, IP, in1_lo, in2_lo); 1683 // out.hi <- in2.hi * in1.lo + in2.lo * in1.hi + (in1.lo * in2.lo)[63:32] 1684 __ add(out_hi, out_hi, ShifterOperand(IP)); 1685 break; 1686 } 1687 1688 case Primitive::kPrimFloat: { 1689 __ vmuls(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>()); 1690 break; 1691 } 1692 1693 case Primitive::kPrimDouble: { 1694 __ vmuld(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1695 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 1696 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 1697 break; 1698 } 1699 1700 default: 1701 LOG(FATAL) << "Unexpected mul type " << mul->GetResultType(); 1702 } 1703} 1704 1705void LocationsBuilderARM::VisitDiv(HDiv* div) { 1706 LocationSummary::CallKind call_kind = div->GetResultType() == Primitive::kPrimLong 1707 ? LocationSummary::kCall 1708 : LocationSummary::kNoCall; 1709 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(div, call_kind); 1710 1711 switch (div->GetResultType()) { 1712 case Primitive::kPrimInt: { 1713 locations->SetInAt(0, Location::RequiresRegister()); 1714 locations->SetInAt(1, Location::RequiresRegister()); 1715 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1716 break; 1717 } 1718 case Primitive::kPrimLong: { 1719 InvokeRuntimeCallingConvention calling_convention; 1720 locations->SetInAt(0, Location::RegisterPairLocation( 1721 calling_convention.GetRegisterAt(0), calling_convention.GetRegisterAt(1))); 1722 locations->SetInAt(1, Location::RegisterPairLocation( 1723 calling_convention.GetRegisterAt(2), calling_convention.GetRegisterAt(3))); 1724 // The runtime helper puts the output in R0,R2. 1725 locations->SetOut(Location::RegisterPairLocation(R0, R2)); 1726 break; 1727 } 1728 case Primitive::kPrimFloat: 1729 case Primitive::kPrimDouble: { 1730 locations->SetInAt(0, Location::RequiresFpuRegister()); 1731 locations->SetInAt(1, Location::RequiresFpuRegister()); 1732 locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap); 1733 break; 1734 } 1735 1736 default: 1737 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 1738 } 1739} 1740 1741void InstructionCodeGeneratorARM::VisitDiv(HDiv* div) { 1742 LocationSummary* locations = div->GetLocations(); 1743 Location out = locations->Out(); 1744 Location first = locations->InAt(0); 1745 Location second = locations->InAt(1); 1746 1747 switch (div->GetResultType()) { 1748 case Primitive::kPrimInt: { 1749 __ sdiv(out.As<Register>(), first.As<Register>(), second.As<Register>()); 1750 break; 1751 } 1752 1753 case Primitive::kPrimLong: { 1754 InvokeRuntimeCallingConvention calling_convention; 1755 DCHECK_EQ(calling_convention.GetRegisterAt(0), first.AsRegisterPairLow<Register>()); 1756 DCHECK_EQ(calling_convention.GetRegisterAt(1), first.AsRegisterPairHigh<Register>()); 1757 DCHECK_EQ(calling_convention.GetRegisterAt(2), second.AsRegisterPairLow<Register>()); 1758 DCHECK_EQ(calling_convention.GetRegisterAt(3), second.AsRegisterPairHigh<Register>()); 1759 DCHECK_EQ(R0, out.AsRegisterPairLow<Register>()); 1760 DCHECK_EQ(R2, out.AsRegisterPairHigh<Register>()); 1761 1762 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pLdiv), div, div->GetDexPc()); 1763 break; 1764 } 1765 1766 case Primitive::kPrimFloat: { 1767 __ vdivs(out.As<SRegister>(), first.As<SRegister>(), second.As<SRegister>()); 1768 break; 1769 } 1770 1771 case Primitive::kPrimDouble: { 1772 __ vdivd(FromLowSToD(out.AsFpuRegisterPairLow<SRegister>()), 1773 FromLowSToD(first.AsFpuRegisterPairLow<SRegister>()), 1774 FromLowSToD(second.AsFpuRegisterPairLow<SRegister>())); 1775 break; 1776 } 1777 1778 default: 1779 LOG(FATAL) << "Unexpected div type " << div->GetResultType(); 1780 } 1781} 1782 1783void LocationsBuilderARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { 1784 LocationSummary* locations = 1785 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1786 locations->SetInAt(0, Location::RegisterOrConstant(instruction->InputAt(0))); 1787 if (instruction->HasUses()) { 1788 locations->SetOut(Location::SameAsFirstInput()); 1789 } 1790} 1791 1792void InstructionCodeGeneratorARM::VisitDivZeroCheck(HDivZeroCheck* instruction) { 1793 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) DivZeroCheckSlowPathARM(instruction); 1794 codegen_->AddSlowPath(slow_path); 1795 1796 LocationSummary* locations = instruction->GetLocations(); 1797 Location value = locations->InAt(0); 1798 1799 switch (instruction->GetType()) { 1800 case Primitive::kPrimInt: { 1801 if (value.IsRegister()) { 1802 __ cmp(value.As<Register>(), ShifterOperand(0)); 1803 __ b(slow_path->GetEntryLabel(), EQ); 1804 } else { 1805 DCHECK(value.IsConstant()) << value; 1806 if (value.GetConstant()->AsIntConstant()->GetValue() == 0) { 1807 __ b(slow_path->GetEntryLabel()); 1808 } 1809 } 1810 break; 1811 } 1812 case Primitive::kPrimLong: { 1813 if (value.IsRegisterPair()) { 1814 __ orrs(IP, 1815 value.AsRegisterPairLow<Register>(), 1816 ShifterOperand(value.AsRegisterPairHigh<Register>())); 1817 __ b(slow_path->GetEntryLabel(), EQ); 1818 } else { 1819 DCHECK(value.IsConstant()) << value; 1820 if (value.GetConstant()->AsLongConstant()->GetValue() == 0) { 1821 __ b(slow_path->GetEntryLabel()); 1822 } 1823 } 1824 break; 1825 default: 1826 LOG(FATAL) << "Unexpected type for HDivZeroCheck " << instruction->GetType(); 1827 } 1828 } 1829} 1830 1831void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 1832 LocationSummary* locations = 1833 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1834 InvokeRuntimeCallingConvention calling_convention; 1835 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1836 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1837 locations->SetOut(Location::RegisterLocation(R0)); 1838} 1839 1840void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 1841 InvokeRuntimeCallingConvention calling_convention; 1842 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 1843 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 1844 codegen_->InvokeRuntime( 1845 QUICK_ENTRY_POINT(pAllocObjectWithAccessCheck), instruction, instruction->GetDexPc()); 1846} 1847 1848void LocationsBuilderARM::VisitNewArray(HNewArray* instruction) { 1849 LocationSummary* locations = 1850 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1851 InvokeRuntimeCallingConvention calling_convention; 1852 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 1853 locations->AddTemp(Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 1854 locations->SetOut(Location::RegisterLocation(R0)); 1855 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 1856} 1857 1858void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) { 1859 InvokeRuntimeCallingConvention calling_convention; 1860 codegen_->LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 1861 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 1862 codegen_->InvokeRuntime( 1863 QUICK_ENTRY_POINT(pAllocArrayWithAccessCheck), instruction, instruction->GetDexPc()); 1864} 1865 1866void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 1867 LocationSummary* locations = 1868 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1869 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 1870 if (location.IsStackSlot()) { 1871 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1872 } else if (location.IsDoubleStackSlot()) { 1873 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1874 } 1875 locations->SetOut(location); 1876} 1877 1878void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 1879 // Nothing to do, the parameter is already at its location. 1880 UNUSED(instruction); 1881} 1882 1883void LocationsBuilderARM::VisitNot(HNot* not_) { 1884 LocationSummary* locations = 1885 new (GetGraph()->GetArena()) LocationSummary(not_, LocationSummary::kNoCall); 1886 locations->SetInAt(0, Location::RequiresRegister()); 1887 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1888} 1889 1890void InstructionCodeGeneratorARM::VisitNot(HNot* not_) { 1891 LocationSummary* locations = not_->GetLocations(); 1892 Location out = locations->Out(); 1893 Location in = locations->InAt(0); 1894 switch (not_->InputAt(0)->GetType()) { 1895 case Primitive::kPrimBoolean: 1896 __ eor(out.As<Register>(), in.As<Register>(), ShifterOperand(1)); 1897 break; 1898 1899 case Primitive::kPrimInt: 1900 __ mvn(out.As<Register>(), ShifterOperand(in.As<Register>())); 1901 break; 1902 1903 case Primitive::kPrimLong: 1904 __ mvn(out.AsRegisterPairLow<Register>(), 1905 ShifterOperand(in.AsRegisterPairLow<Register>())); 1906 __ mvn(out.AsRegisterPairHigh<Register>(), 1907 ShifterOperand(in.AsRegisterPairHigh<Register>())); 1908 break; 1909 1910 default: 1911 LOG(FATAL) << "Unimplemented type for not operation " << not_->GetResultType(); 1912 } 1913} 1914 1915void LocationsBuilderARM::VisitCompare(HCompare* compare) { 1916 LocationSummary* locations = 1917 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 1918 locations->SetInAt(0, Location::RequiresRegister()); 1919 locations->SetInAt(1, Location::RequiresRegister()); 1920 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 1921} 1922 1923void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { 1924 LocationSummary* locations = compare->GetLocations(); 1925 switch (compare->InputAt(0)->GetType()) { 1926 case Primitive::kPrimLong: { 1927 Register output = locations->Out().As<Register>(); 1928 Location left = locations->InAt(0); 1929 Location right = locations->InAt(1); 1930 Label less, greater, done; 1931 __ cmp(left.AsRegisterPairHigh<Register>(), 1932 ShifterOperand(right.AsRegisterPairHigh<Register>())); // Signed compare. 1933 __ b(&less, LT); 1934 __ b(&greater, GT); 1935 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect 1936 // the status flags. 1937 __ LoadImmediate(output, 0); 1938 __ cmp(left.AsRegisterPairLow<Register>(), 1939 ShifterOperand(right.AsRegisterPairLow<Register>())); // Unsigned compare. 1940 __ b(&done, EQ); 1941 __ b(&less, CC); 1942 1943 __ Bind(&greater); 1944 __ LoadImmediate(output, 1); 1945 __ b(&done); 1946 1947 __ Bind(&less); 1948 __ LoadImmediate(output, -1); 1949 1950 __ Bind(&done); 1951 break; 1952 } 1953 default: 1954 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType(); 1955 } 1956} 1957 1958void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 1959 LocationSummary* locations = 1960 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1961 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 1962 locations->SetInAt(i, Location::Any()); 1963 } 1964 locations->SetOut(Location::Any()); 1965} 1966 1967void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 1968 UNUSED(instruction); 1969 LOG(FATAL) << "Unreachable"; 1970} 1971 1972void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1973 LocationSummary* locations = 1974 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1975 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot; 1976 locations->SetInAt(0, Location::RequiresRegister()); 1977 locations->SetInAt(1, Location::RequiresRegister()); 1978 // Temporary registers for the write barrier. 1979 if (is_object_type) { 1980 locations->AddTemp(Location::RequiresRegister()); 1981 locations->AddTemp(Location::RequiresRegister()); 1982 } 1983} 1984 1985void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1986 LocationSummary* locations = instruction->GetLocations(); 1987 Register obj = locations->InAt(0).As<Register>(); 1988 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1989 Primitive::Type field_type = instruction->GetFieldType(); 1990 1991 switch (field_type) { 1992 case Primitive::kPrimBoolean: 1993 case Primitive::kPrimByte: { 1994 Register value = locations->InAt(1).As<Register>(); 1995 __ StoreToOffset(kStoreByte, value, obj, offset); 1996 break; 1997 } 1998 1999 case Primitive::kPrimShort: 2000 case Primitive::kPrimChar: { 2001 Register value = locations->InAt(1).As<Register>(); 2002 __ StoreToOffset(kStoreHalfword, value, obj, offset); 2003 break; 2004 } 2005 2006 case Primitive::kPrimInt: 2007 case Primitive::kPrimNot: { 2008 Register value = locations->InAt(1).As<Register>(); 2009 __ StoreToOffset(kStoreWord, value, obj, offset); 2010 if (field_type == Primitive::kPrimNot) { 2011 Register temp = locations->GetTemp(0).As<Register>(); 2012 Register card = locations->GetTemp(1).As<Register>(); 2013 codegen_->MarkGCCard(temp, card, obj, value); 2014 } 2015 break; 2016 } 2017 2018 case Primitive::kPrimLong: { 2019 Location value = locations->InAt(1); 2020 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset); 2021 break; 2022 } 2023 2024 case Primitive::kPrimFloat: { 2025 SRegister value = locations->InAt(1).As<SRegister>(); 2026 __ StoreSToOffset(value, obj, offset); 2027 break; 2028 } 2029 2030 case Primitive::kPrimDouble: { 2031 DRegister value = FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>()); 2032 __ StoreDToOffset(value, obj, offset); 2033 break; 2034 } 2035 2036 case Primitive::kPrimVoid: 2037 LOG(FATAL) << "Unreachable type " << field_type; 2038 UNREACHABLE(); 2039 } 2040} 2041 2042void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 2043 LocationSummary* locations = 2044 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2045 locations->SetInAt(0, Location::RequiresRegister()); 2046 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2047} 2048 2049void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 2050 LocationSummary* locations = instruction->GetLocations(); 2051 Register obj = locations->InAt(0).As<Register>(); 2052 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 2053 2054 switch (instruction->GetType()) { 2055 case Primitive::kPrimBoolean: { 2056 Register out = locations->Out().As<Register>(); 2057 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 2058 break; 2059 } 2060 2061 case Primitive::kPrimByte: { 2062 Register out = locations->Out().As<Register>(); 2063 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 2064 break; 2065 } 2066 2067 case Primitive::kPrimShort: { 2068 Register out = locations->Out().As<Register>(); 2069 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 2070 break; 2071 } 2072 2073 case Primitive::kPrimChar: { 2074 Register out = locations->Out().As<Register>(); 2075 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 2076 break; 2077 } 2078 2079 case Primitive::kPrimInt: 2080 case Primitive::kPrimNot: { 2081 Register out = locations->Out().As<Register>(); 2082 __ LoadFromOffset(kLoadWord, out, obj, offset); 2083 break; 2084 } 2085 2086 case Primitive::kPrimLong: { 2087 // TODO: support volatile. 2088 Location out = locations->Out(); 2089 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset); 2090 break; 2091 } 2092 2093 case Primitive::kPrimFloat: { 2094 SRegister out = locations->Out().As<SRegister>(); 2095 __ LoadSFromOffset(out, obj, offset); 2096 break; 2097 } 2098 2099 case Primitive::kPrimDouble: { 2100 DRegister out = FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()); 2101 __ LoadDFromOffset(out, obj, offset); 2102 break; 2103 } 2104 2105 case Primitive::kPrimVoid: 2106 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 2107 UNREACHABLE(); 2108 } 2109} 2110 2111void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { 2112 LocationSummary* locations = 2113 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2114 locations->SetInAt(0, Location::RequiresRegister()); 2115 if (instruction->HasUses()) { 2116 locations->SetOut(Location::SameAsFirstInput()); 2117 } 2118} 2119 2120void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { 2121 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); 2122 codegen_->AddSlowPath(slow_path); 2123 2124 LocationSummary* locations = instruction->GetLocations(); 2125 Location obj = locations->InAt(0); 2126 2127 if (obj.IsRegister()) { 2128 __ cmp(obj.As<Register>(), ShifterOperand(0)); 2129 __ b(slow_path->GetEntryLabel(), EQ); 2130 } else { 2131 DCHECK(obj.IsConstant()) << obj; 2132 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); 2133 __ b(slow_path->GetEntryLabel()); 2134 } 2135} 2136 2137void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { 2138 LocationSummary* locations = 2139 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2140 locations->SetInAt(0, Location::RequiresRegister()); 2141 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 2142 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2143} 2144 2145void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { 2146 LocationSummary* locations = instruction->GetLocations(); 2147 Register obj = locations->InAt(0).As<Register>(); 2148 Location index = locations->InAt(1); 2149 2150 switch (instruction->GetType()) { 2151 case Primitive::kPrimBoolean: { 2152 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 2153 Register out = locations->Out().As<Register>(); 2154 if (index.IsConstant()) { 2155 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 2156 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 2157 } else { 2158 __ add(IP, obj, ShifterOperand(index.As<Register>())); 2159 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset); 2160 } 2161 break; 2162 } 2163 2164 case Primitive::kPrimByte: { 2165 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 2166 Register out = locations->Out().As<Register>(); 2167 if (index.IsConstant()) { 2168 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 2169 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 2170 } else { 2171 __ add(IP, obj, ShifterOperand(index.As<Register>())); 2172 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset); 2173 } 2174 break; 2175 } 2176 2177 case Primitive::kPrimShort: { 2178 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 2179 Register out = locations->Out().As<Register>(); 2180 if (index.IsConstant()) { 2181 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 2182 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 2183 } else { 2184 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 2185 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset); 2186 } 2187 break; 2188 } 2189 2190 case Primitive::kPrimChar: { 2191 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 2192 Register out = locations->Out().As<Register>(); 2193 if (index.IsConstant()) { 2194 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 2195 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 2196 } else { 2197 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 2198 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset); 2199 } 2200 break; 2201 } 2202 2203 case Primitive::kPrimInt: 2204 case Primitive::kPrimNot: { 2205 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t)); 2206 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 2207 Register out = locations->Out().As<Register>(); 2208 if (index.IsConstant()) { 2209 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 2210 __ LoadFromOffset(kLoadWord, out, obj, offset); 2211 } else { 2212 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4)); 2213 __ LoadFromOffset(kLoadWord, out, IP, data_offset); 2214 } 2215 break; 2216 } 2217 2218 case Primitive::kPrimLong: { 2219 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 2220 Location out = locations->Out(); 2221 if (index.IsConstant()) { 2222 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 2223 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), obj, offset); 2224 } else { 2225 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8)); 2226 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), IP, data_offset); 2227 } 2228 break; 2229 } 2230 2231 case Primitive::kPrimFloat: 2232 case Primitive::kPrimDouble: 2233 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 2234 UNREACHABLE(); 2235 case Primitive::kPrimVoid: 2236 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 2237 UNREACHABLE(); 2238 } 2239} 2240 2241void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) { 2242 Primitive::Type value_type = instruction->GetComponentType(); 2243 bool is_object = value_type == Primitive::kPrimNot; 2244 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 2245 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall); 2246 if (is_object) { 2247 InvokeRuntimeCallingConvention calling_convention; 2248 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2249 locations->SetInAt(1, Location::RegisterLocation(calling_convention.GetRegisterAt(1))); 2250 locations->SetInAt(2, Location::RegisterLocation(calling_convention.GetRegisterAt(2))); 2251 } else { 2252 locations->SetInAt(0, Location::RequiresRegister()); 2253 locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1))); 2254 locations->SetInAt(2, Location::RequiresRegister()); 2255 } 2256} 2257 2258void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { 2259 LocationSummary* locations = instruction->GetLocations(); 2260 Register obj = locations->InAt(0).As<Register>(); 2261 Location index = locations->InAt(1); 2262 Primitive::Type value_type = instruction->GetComponentType(); 2263 2264 switch (value_type) { 2265 case Primitive::kPrimBoolean: 2266 case Primitive::kPrimByte: { 2267 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 2268 Register value = locations->InAt(2).As<Register>(); 2269 if (index.IsConstant()) { 2270 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 2271 __ StoreToOffset(kStoreByte, value, obj, offset); 2272 } else { 2273 __ add(IP, obj, ShifterOperand(index.As<Register>())); 2274 __ StoreToOffset(kStoreByte, value, IP, data_offset); 2275 } 2276 break; 2277 } 2278 2279 case Primitive::kPrimShort: 2280 case Primitive::kPrimChar: { 2281 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 2282 Register value = locations->InAt(2).As<Register>(); 2283 if (index.IsConstant()) { 2284 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 2285 __ StoreToOffset(kStoreHalfword, value, obj, offset); 2286 } else { 2287 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_2)); 2288 __ StoreToOffset(kStoreHalfword, value, IP, data_offset); 2289 } 2290 break; 2291 } 2292 2293 case Primitive::kPrimInt: { 2294 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 2295 Register value = locations->InAt(2).As<Register>(); 2296 if (index.IsConstant()) { 2297 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 2298 __ StoreToOffset(kStoreWord, value, obj, offset); 2299 } else { 2300 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_4)); 2301 __ StoreToOffset(kStoreWord, value, IP, data_offset); 2302 } 2303 break; 2304 } 2305 2306 case Primitive::kPrimNot: { 2307 codegen_->InvokeRuntime(QUICK_ENTRY_POINT(pAputObject), instruction, instruction->GetDexPc()); 2308 break; 2309 } 2310 2311 case Primitive::kPrimLong: { 2312 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 2313 Location value = locations->InAt(2); 2314 if (index.IsConstant()) { 2315 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 2316 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), obj, offset); 2317 } else { 2318 __ add(IP, obj, ShifterOperand(index.As<Register>(), LSL, TIMES_8)); 2319 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), IP, data_offset); 2320 } 2321 break; 2322 } 2323 2324 case Primitive::kPrimFloat: 2325 case Primitive::kPrimDouble: 2326 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 2327 UNREACHABLE(); 2328 case Primitive::kPrimVoid: 2329 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 2330 UNREACHABLE(); 2331 } 2332} 2333 2334void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) { 2335 LocationSummary* locations = 2336 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2337 locations->SetInAt(0, Location::RequiresRegister()); 2338 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2339} 2340 2341void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) { 2342 LocationSummary* locations = instruction->GetLocations(); 2343 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 2344 Register obj = locations->InAt(0).As<Register>(); 2345 Register out = locations->Out().As<Register>(); 2346 __ LoadFromOffset(kLoadWord, out, obj, offset); 2347} 2348 2349void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { 2350 LocationSummary* locations = 2351 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2352 locations->SetInAt(0, Location::RequiresRegister()); 2353 locations->SetInAt(1, Location::RequiresRegister()); 2354 if (instruction->HasUses()) { 2355 locations->SetOut(Location::SameAsFirstInput()); 2356 } 2357} 2358 2359void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { 2360 LocationSummary* locations = instruction->GetLocations(); 2361 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM( 2362 instruction, locations->InAt(0), locations->InAt(1)); 2363 codegen_->AddSlowPath(slow_path); 2364 2365 Register index = locations->InAt(0).As<Register>(); 2366 Register length = locations->InAt(1).As<Register>(); 2367 2368 __ cmp(index, ShifterOperand(length)); 2369 __ b(slow_path->GetEntryLabel(), CS); 2370} 2371 2372void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) { 2373 Label is_null; 2374 __ CompareAndBranchIfZero(value, &is_null); 2375 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value()); 2376 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift); 2377 __ strb(card, Address(card, temp)); 2378 __ Bind(&is_null); 2379} 2380 2381void LocationsBuilderARM::VisitTemporary(HTemporary* temp) { 2382 temp->SetLocations(nullptr); 2383} 2384 2385void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) { 2386 // Nothing to do, this is driven by the code generator. 2387 UNUSED(temp); 2388} 2389 2390void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) { 2391 UNUSED(instruction); 2392 LOG(FATAL) << "Unreachable"; 2393} 2394 2395void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) { 2396 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 2397} 2398 2399void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) { 2400 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 2401} 2402 2403void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) { 2404 HBasicBlock* block = instruction->GetBlock(); 2405 if (block->GetLoopInformation() != nullptr) { 2406 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 2407 // The back edge will generate the suspend check. 2408 return; 2409 } 2410 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 2411 // The goto will generate the suspend check. 2412 return; 2413 } 2414 GenerateSuspendCheck(instruction, nullptr); 2415} 2416 2417void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction, 2418 HBasicBlock* successor) { 2419 SuspendCheckSlowPathARM* slow_path = 2420 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor); 2421 codegen_->AddSlowPath(slow_path); 2422 2423 __ LoadFromOffset( 2424 kLoadUnsignedHalfword, IP, TR, Thread::ThreadFlagsOffset<kArmWordSize>().Int32Value()); 2425 __ cmp(IP, ShifterOperand(0)); 2426 // TODO: Figure out the branch offsets and use cbz/cbnz. 2427 if (successor == nullptr) { 2428 __ b(slow_path->GetEntryLabel(), NE); 2429 __ Bind(slow_path->GetReturnLabel()); 2430 } else { 2431 __ b(codegen_->GetLabelOf(successor), EQ); 2432 __ b(slow_path->GetEntryLabel()); 2433 } 2434} 2435 2436ArmAssembler* ParallelMoveResolverARM::GetAssembler() const { 2437 return codegen_->GetAssembler(); 2438} 2439 2440void ParallelMoveResolverARM::EmitMove(size_t index) { 2441 MoveOperands* move = moves_.Get(index); 2442 Location source = move->GetSource(); 2443 Location destination = move->GetDestination(); 2444 2445 if (source.IsRegister()) { 2446 if (destination.IsRegister()) { 2447 __ Mov(destination.As<Register>(), source.As<Register>()); 2448 } else { 2449 DCHECK(destination.IsStackSlot()); 2450 __ StoreToOffset(kStoreWord, source.As<Register>(), 2451 SP, destination.GetStackIndex()); 2452 } 2453 } else if (source.IsStackSlot()) { 2454 if (destination.IsRegister()) { 2455 __ LoadFromOffset(kLoadWord, destination.As<Register>(), 2456 SP, source.GetStackIndex()); 2457 } else { 2458 DCHECK(destination.IsStackSlot()); 2459 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 2460 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 2461 } 2462 } else { 2463 DCHECK(source.IsConstant()); 2464 DCHECK(source.GetConstant()->IsIntConstant()); 2465 int32_t value = source.GetConstant()->AsIntConstant()->GetValue(); 2466 if (destination.IsRegister()) { 2467 __ LoadImmediate(destination.As<Register>(), value); 2468 } else { 2469 DCHECK(destination.IsStackSlot()); 2470 __ LoadImmediate(IP, value); 2471 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 2472 } 2473 } 2474} 2475 2476void ParallelMoveResolverARM::Exchange(Register reg, int mem) { 2477 __ Mov(IP, reg); 2478 __ LoadFromOffset(kLoadWord, reg, SP, mem); 2479 __ StoreToOffset(kStoreWord, IP, SP, mem); 2480} 2481 2482void ParallelMoveResolverARM::Exchange(int mem1, int mem2) { 2483 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters()); 2484 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; 2485 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()), 2486 SP, mem1 + stack_offset); 2487 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset); 2488 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()), 2489 SP, mem2 + stack_offset); 2490 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset); 2491} 2492 2493void ParallelMoveResolverARM::EmitSwap(size_t index) { 2494 MoveOperands* move = moves_.Get(index); 2495 Location source = move->GetSource(); 2496 Location destination = move->GetDestination(); 2497 2498 if (source.IsRegister() && destination.IsRegister()) { 2499 DCHECK_NE(source.As<Register>(), IP); 2500 DCHECK_NE(destination.As<Register>(), IP); 2501 __ Mov(IP, source.As<Register>()); 2502 __ Mov(source.As<Register>(), destination.As<Register>()); 2503 __ Mov(destination.As<Register>(), IP); 2504 } else if (source.IsRegister() && destination.IsStackSlot()) { 2505 Exchange(source.As<Register>(), destination.GetStackIndex()); 2506 } else if (source.IsStackSlot() && destination.IsRegister()) { 2507 Exchange(destination.As<Register>(), source.GetStackIndex()); 2508 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 2509 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 2510 } else { 2511 LOG(FATAL) << "Unimplemented"; 2512 } 2513} 2514 2515void ParallelMoveResolverARM::SpillScratch(int reg) { 2516 __ Push(static_cast<Register>(reg)); 2517} 2518 2519void ParallelMoveResolverARM::RestoreScratch(int reg) { 2520 __ Pop(static_cast<Register>(reg)); 2521} 2522 2523void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) { 2524 LocationSummary::CallKind call_kind = cls->CanCallRuntime() 2525 ? LocationSummary::kCallOnSlowPath 2526 : LocationSummary::kNoCall; 2527 LocationSummary* locations = 2528 new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); 2529 locations->SetOut(Location::RequiresRegister()); 2530} 2531 2532void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { 2533 Register out = cls->GetLocations()->Out().As<Register>(); 2534 if (cls->IsReferrersClass()) { 2535 DCHECK(!cls->CanCallRuntime()); 2536 DCHECK(!cls->MustGenerateClinitCheck()); 2537 codegen_->LoadCurrentMethod(out); 2538 __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()); 2539 } else { 2540 DCHECK(cls->CanCallRuntime()); 2541 codegen_->LoadCurrentMethod(out); 2542 __ LoadFromOffset( 2543 kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()); 2544 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); 2545 2546 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( 2547 cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); 2548 codegen_->AddSlowPath(slow_path); 2549 __ cmp(out, ShifterOperand(0)); 2550 __ b(slow_path->GetEntryLabel(), EQ); 2551 if (cls->MustGenerateClinitCheck()) { 2552 GenerateClassInitializationCheck(slow_path, out); 2553 } else { 2554 __ Bind(slow_path->GetExitLabel()); 2555 } 2556 } 2557} 2558 2559void LocationsBuilderARM::VisitClinitCheck(HClinitCheck* check) { 2560 LocationSummary* locations = 2561 new (GetGraph()->GetArena()) LocationSummary(check, LocationSummary::kCallOnSlowPath); 2562 locations->SetInAt(0, Location::RequiresRegister()); 2563 if (check->HasUses()) { 2564 locations->SetOut(Location::SameAsFirstInput()); 2565 } 2566} 2567 2568void InstructionCodeGeneratorARM::VisitClinitCheck(HClinitCheck* check) { 2569 // We assume the class is not null. 2570 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( 2571 check->GetLoadClass(), check, check->GetDexPc(), true); 2572 codegen_->AddSlowPath(slow_path); 2573 GenerateClassInitializationCheck(slow_path, check->GetLocations()->InAt(0).As<Register>()); 2574} 2575 2576void InstructionCodeGeneratorARM::GenerateClassInitializationCheck( 2577 SlowPathCodeARM* slow_path, Register class_reg) { 2578 __ LoadFromOffset(kLoadWord, IP, class_reg, mirror::Class::StatusOffset().Int32Value()); 2579 __ cmp(IP, ShifterOperand(mirror::Class::kStatusInitialized)); 2580 __ b(slow_path->GetEntryLabel(), LT); 2581 // Even if the initialized flag is set, we may be in a situation where caches are not synced 2582 // properly. Therefore, we do a memory fence. 2583 __ dmb(ISH); 2584 __ Bind(slow_path->GetExitLabel()); 2585} 2586 2587void LocationsBuilderARM::VisitStaticFieldGet(HStaticFieldGet* instruction) { 2588 LocationSummary* locations = 2589 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2590 locations->SetInAt(0, Location::RequiresRegister()); 2591 locations->SetOut(Location::RequiresRegister(), Location::kNoOutputOverlap); 2592} 2593 2594void InstructionCodeGeneratorARM::VisitStaticFieldGet(HStaticFieldGet* instruction) { 2595 LocationSummary* locations = instruction->GetLocations(); 2596 Register cls = locations->InAt(0).As<Register>(); 2597 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 2598 2599 switch (instruction->GetType()) { 2600 case Primitive::kPrimBoolean: { 2601 Register out = locations->Out().As<Register>(); 2602 __ LoadFromOffset(kLoadUnsignedByte, out, cls, offset); 2603 break; 2604 } 2605 2606 case Primitive::kPrimByte: { 2607 Register out = locations->Out().As<Register>(); 2608 __ LoadFromOffset(kLoadSignedByte, out, cls, offset); 2609 break; 2610 } 2611 2612 case Primitive::kPrimShort: { 2613 Register out = locations->Out().As<Register>(); 2614 __ LoadFromOffset(kLoadSignedHalfword, out, cls, offset); 2615 break; 2616 } 2617 2618 case Primitive::kPrimChar: { 2619 Register out = locations->Out().As<Register>(); 2620 __ LoadFromOffset(kLoadUnsignedHalfword, out, cls, offset); 2621 break; 2622 } 2623 2624 case Primitive::kPrimInt: 2625 case Primitive::kPrimNot: { 2626 Register out = locations->Out().As<Register>(); 2627 __ LoadFromOffset(kLoadWord, out, cls, offset); 2628 break; 2629 } 2630 2631 case Primitive::kPrimLong: { 2632 // TODO: support volatile. 2633 Location out = locations->Out(); 2634 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow<Register>(), cls, offset); 2635 break; 2636 } 2637 2638 case Primitive::kPrimFloat: { 2639 SRegister out = locations->Out().As<SRegister>(); 2640 __ LoadSFromOffset(out, cls, offset); 2641 break; 2642 } 2643 2644 case Primitive::kPrimDouble: { 2645 DRegister out = FromLowSToD(locations->Out().AsFpuRegisterPairLow<SRegister>()); 2646 __ LoadDFromOffset(out, cls, offset); 2647 break; 2648 } 2649 2650 case Primitive::kPrimVoid: 2651 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 2652 UNREACHABLE(); 2653 } 2654} 2655 2656void LocationsBuilderARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { 2657 LocationSummary* locations = 2658 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2659 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot; 2660 locations->SetInAt(0, Location::RequiresRegister()); 2661 locations->SetInAt(1, Location::RequiresRegister()); 2662 // Temporary registers for the write barrier. 2663 if (is_object_type) { 2664 locations->AddTemp(Location::RequiresRegister()); 2665 locations->AddTemp(Location::RequiresRegister()); 2666 } 2667} 2668 2669void InstructionCodeGeneratorARM::VisitStaticFieldSet(HStaticFieldSet* instruction) { 2670 LocationSummary* locations = instruction->GetLocations(); 2671 Register cls = locations->InAt(0).As<Register>(); 2672 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 2673 Primitive::Type field_type = instruction->GetFieldType(); 2674 2675 switch (field_type) { 2676 case Primitive::kPrimBoolean: 2677 case Primitive::kPrimByte: { 2678 Register value = locations->InAt(1).As<Register>(); 2679 __ StoreToOffset(kStoreByte, value, cls, offset); 2680 break; 2681 } 2682 2683 case Primitive::kPrimShort: 2684 case Primitive::kPrimChar: { 2685 Register value = locations->InAt(1).As<Register>(); 2686 __ StoreToOffset(kStoreHalfword, value, cls, offset); 2687 break; 2688 } 2689 2690 case Primitive::kPrimInt: 2691 case Primitive::kPrimNot: { 2692 Register value = locations->InAt(1).As<Register>(); 2693 __ StoreToOffset(kStoreWord, value, cls, offset); 2694 if (field_type == Primitive::kPrimNot) { 2695 Register temp = locations->GetTemp(0).As<Register>(); 2696 Register card = locations->GetTemp(1).As<Register>(); 2697 codegen_->MarkGCCard(temp, card, cls, value); 2698 } 2699 break; 2700 } 2701 2702 case Primitive::kPrimLong: { 2703 Location value = locations->InAt(1); 2704 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow<Register>(), cls, offset); 2705 break; 2706 } 2707 2708 case Primitive::kPrimFloat: { 2709 SRegister value = locations->InAt(1).As<SRegister>(); 2710 __ StoreSToOffset(value, cls, offset); 2711 break; 2712 } 2713 2714 case Primitive::kPrimDouble: { 2715 DRegister value = FromLowSToD(locations->InAt(1).AsFpuRegisterPairLow<SRegister>()); 2716 __ StoreDToOffset(value, cls, offset); 2717 break; 2718 } 2719 2720 case Primitive::kPrimVoid: 2721 LOG(FATAL) << "Unreachable type " << field_type; 2722 UNREACHABLE(); 2723 } 2724} 2725 2726void LocationsBuilderARM::VisitLoadString(HLoadString* load) { 2727 LocationSummary* locations = 2728 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kCallOnSlowPath); 2729 locations->SetOut(Location::RequiresRegister()); 2730} 2731 2732void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { 2733 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load); 2734 codegen_->AddSlowPath(slow_path); 2735 2736 Register out = load->GetLocations()->Out().As<Register>(); 2737 codegen_->LoadCurrentMethod(out); 2738 __ LoadFromOffset( 2739 kLoadWord, out, out, mirror::ArtMethod::DexCacheStringsOffset().Int32Value()); 2740 __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(load->GetStringIndex())); 2741 __ cmp(out, ShifterOperand(0)); 2742 __ b(slow_path->GetEntryLabel(), EQ); 2743 __ Bind(slow_path->GetExitLabel()); 2744} 2745 2746void LocationsBuilderARM::VisitLoadException(HLoadException* load) { 2747 LocationSummary* locations = 2748 new (GetGraph()->GetArena()) LocationSummary(load, LocationSummary::kNoCall); 2749 locations->SetOut(Location::RequiresRegister()); 2750} 2751 2752void InstructionCodeGeneratorARM::VisitLoadException(HLoadException* load) { 2753 Register out = load->GetLocations()->Out().As<Register>(); 2754 int32_t offset = Thread::ExceptionOffset<kArmWordSize>().Int32Value(); 2755 __ LoadFromOffset(kLoadWord, out, TR, offset); 2756 __ LoadImmediate(IP, 0); 2757 __ StoreToOffset(kStoreWord, IP, TR, offset); 2758} 2759 2760void LocationsBuilderARM::VisitThrow(HThrow* instruction) { 2761 LocationSummary* locations = 2762 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2763 InvokeRuntimeCallingConvention calling_convention; 2764 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2765} 2766 2767void InstructionCodeGeneratorARM::VisitThrow(HThrow* instruction) { 2768 codegen_->InvokeRuntime( 2769 QUICK_ENTRY_POINT(pDeliverException), instruction, instruction->GetDexPc()); 2770} 2771 2772void LocationsBuilderARM::VisitInstanceOf(HInstanceOf* instruction) { 2773 LocationSummary::CallKind call_kind = instruction->IsClassFinal() 2774 ? LocationSummary::kNoCall 2775 : LocationSummary::kCallOnSlowPath; 2776 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind); 2777 locations->SetInAt(0, Location::RequiresRegister()); 2778 locations->SetInAt(1, Location::RequiresRegister()); 2779 locations->SetOut(Location::RequiresRegister()); 2780} 2781 2782void InstructionCodeGeneratorARM::VisitInstanceOf(HInstanceOf* instruction) { 2783 LocationSummary* locations = instruction->GetLocations(); 2784 Register obj = locations->InAt(0).As<Register>(); 2785 Register cls = locations->InAt(1).As<Register>(); 2786 Register out = locations->Out().As<Register>(); 2787 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 2788 Label done, zero; 2789 SlowPathCodeARM* slow_path = nullptr; 2790 2791 // Return 0 if `obj` is null. 2792 // TODO: avoid this check if we know obj is not null. 2793 __ cmp(obj, ShifterOperand(0)); 2794 __ b(&zero, EQ); 2795 // Compare the class of `obj` with `cls`. 2796 __ LoadFromOffset(kLoadWord, out, obj, class_offset); 2797 __ cmp(out, ShifterOperand(cls)); 2798 if (instruction->IsClassFinal()) { 2799 // Classes must be equal for the instanceof to succeed. 2800 __ b(&zero, NE); 2801 __ LoadImmediate(out, 1); 2802 __ b(&done); 2803 } else { 2804 // If the classes are not equal, we go into a slow path. 2805 DCHECK(locations->OnlyCallsOnSlowPath()); 2806 slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( 2807 instruction, locations->InAt(1), locations->Out(), instruction->GetDexPc()); 2808 codegen_->AddSlowPath(slow_path); 2809 __ b(slow_path->GetEntryLabel(), NE); 2810 __ LoadImmediate(out, 1); 2811 __ b(&done); 2812 } 2813 __ Bind(&zero); 2814 __ LoadImmediate(out, 0); 2815 if (slow_path != nullptr) { 2816 __ Bind(slow_path->GetExitLabel()); 2817 } 2818 __ Bind(&done); 2819} 2820 2821void LocationsBuilderARM::VisitCheckCast(HCheckCast* instruction) { 2822 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 2823 instruction, LocationSummary::kCallOnSlowPath); 2824 locations->SetInAt(0, Location::RequiresRegister()); 2825 locations->SetInAt(1, Location::RequiresRegister()); 2826 locations->AddTemp(Location::RequiresRegister()); 2827} 2828 2829void InstructionCodeGeneratorARM::VisitCheckCast(HCheckCast* instruction) { 2830 LocationSummary* locations = instruction->GetLocations(); 2831 Register obj = locations->InAt(0).As<Register>(); 2832 Register cls = locations->InAt(1).As<Register>(); 2833 Register temp = locations->GetTemp(0).As<Register>(); 2834 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 2835 2836 SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) TypeCheckSlowPathARM( 2837 instruction, locations->InAt(1), locations->GetTemp(0), instruction->GetDexPc()); 2838 codegen_->AddSlowPath(slow_path); 2839 2840 // TODO: avoid this check if we know obj is not null. 2841 __ cmp(obj, ShifterOperand(0)); 2842 __ b(slow_path->GetExitLabel(), EQ); 2843 // Compare the class of `obj` with `cls`. 2844 __ LoadFromOffset(kLoadWord, temp, obj, class_offset); 2845 __ cmp(temp, ShifterOperand(cls)); 2846 __ b(slow_path->GetEntryLabel(), NE); 2847 __ Bind(slow_path->GetExitLabel()); 2848} 2849 2850void LocationsBuilderARM::VisitMonitorOperation(HMonitorOperation* instruction) { 2851 LocationSummary* locations = 2852 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 2853 InvokeRuntimeCallingConvention calling_convention; 2854 locations->SetInAt(0, Location::RegisterLocation(calling_convention.GetRegisterAt(0))); 2855} 2856 2857void InstructionCodeGeneratorARM::VisitMonitorOperation(HMonitorOperation* instruction) { 2858 codegen_->InvokeRuntime(instruction->IsEnter() 2859 ? QUICK_ENTRY_POINT(pLockObject) : QUICK_ENTRY_POINT(pUnlockObject), 2860 instruction, 2861 instruction->GetDexPc()); 2862} 2863 2864void LocationsBuilderARM::VisitAnd(HAnd* instruction) { HandleBitwiseOperation(instruction); } 2865void LocationsBuilderARM::VisitOr(HOr* instruction) { HandleBitwiseOperation(instruction); } 2866void LocationsBuilderARM::VisitXor(HXor* instruction) { HandleBitwiseOperation(instruction); } 2867 2868void LocationsBuilderARM::HandleBitwiseOperation(HBinaryOperation* instruction) { 2869 LocationSummary* locations = 2870 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 2871 DCHECK(instruction->GetResultType() == Primitive::kPrimInt 2872 || instruction->GetResultType() == Primitive::kPrimLong); 2873 locations->SetInAt(0, Location::RequiresRegister()); 2874 locations->SetInAt(1, Location::RequiresRegister()); 2875 bool output_overlaps = (instruction->GetResultType() == Primitive::kPrimLong); 2876 locations->SetOut(Location::RequiresRegister(), output_overlaps); 2877} 2878 2879void InstructionCodeGeneratorARM::VisitAnd(HAnd* instruction) { 2880 HandleBitwiseOperation(instruction); 2881} 2882 2883void InstructionCodeGeneratorARM::VisitOr(HOr* instruction) { 2884 HandleBitwiseOperation(instruction); 2885} 2886 2887void InstructionCodeGeneratorARM::VisitXor(HXor* instruction) { 2888 HandleBitwiseOperation(instruction); 2889} 2890 2891void InstructionCodeGeneratorARM::HandleBitwiseOperation(HBinaryOperation* instruction) { 2892 LocationSummary* locations = instruction->GetLocations(); 2893 2894 if (instruction->GetResultType() == Primitive::kPrimInt) { 2895 Register first = locations->InAt(0).As<Register>(); 2896 Register second = locations->InAt(1).As<Register>(); 2897 Register out = locations->Out().As<Register>(); 2898 if (instruction->IsAnd()) { 2899 __ and_(out, first, ShifterOperand(second)); 2900 } else if (instruction->IsOr()) { 2901 __ orr(out, first, ShifterOperand(second)); 2902 } else { 2903 DCHECK(instruction->IsXor()); 2904 __ eor(out, first, ShifterOperand(second)); 2905 } 2906 } else { 2907 DCHECK_EQ(instruction->GetResultType(), Primitive::kPrimLong); 2908 Location first = locations->InAt(0); 2909 Location second = locations->InAt(1); 2910 Location out = locations->Out(); 2911 if (instruction->IsAnd()) { 2912 __ and_(out.AsRegisterPairLow<Register>(), 2913 first.AsRegisterPairLow<Register>(), 2914 ShifterOperand(second.AsRegisterPairLow<Register>())); 2915 __ and_(out.AsRegisterPairHigh<Register>(), 2916 first.AsRegisterPairHigh<Register>(), 2917 ShifterOperand(second.AsRegisterPairHigh<Register>())); 2918 } else if (instruction->IsOr()) { 2919 __ orr(out.AsRegisterPairLow<Register>(), 2920 first.AsRegisterPairLow<Register>(), 2921 ShifterOperand(second.AsRegisterPairLow<Register>())); 2922 __ orr(out.AsRegisterPairHigh<Register>(), 2923 first.AsRegisterPairHigh<Register>(), 2924 ShifterOperand(second.AsRegisterPairHigh<Register>())); 2925 } else { 2926 DCHECK(instruction->IsXor()); 2927 __ eor(out.AsRegisterPairLow<Register>(), 2928 first.AsRegisterPairLow<Register>(), 2929 ShifterOperand(second.AsRegisterPairLow<Register>())); 2930 __ eor(out.AsRegisterPairHigh<Register>(), 2931 first.AsRegisterPairHigh<Register>(), 2932 ShifterOperand(second.AsRegisterPairHigh<Register>())); 2933 } 2934 } 2935} 2936 2937} // namespace arm 2938} // namespace art 2939