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