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