code_generator_arm.cc revision 7fb49da8ec62e8a10ed9419ade9f32c6b1174687
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.h" 22#include "mirror/art_method.h" 23#include "mirror/class.h" 24#include "thread.h" 25#include "utils/assembler.h" 26#include "utils/arm/assembler_arm.h" 27#include "utils/arm/managed_register_arm.h" 28#include "utils/stack_checks.h" 29 30namespace art { 31 32arm::ArmManagedRegister Location::AsArm() const { 33 return reg().AsArm(); 34} 35 36namespace arm { 37 38static constexpr bool kExplicitStackOverflowCheck = false; 39 40static constexpr int kNumberOfPushedRegistersAtEntry = 1 + 2; // LR, R6, R7 41static constexpr int kCurrentMethodStackOffset = 0; 42 43static Location ArmCoreLocation(Register reg) { 44 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg)); 45} 46 47static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1, R2 }; 48static constexpr size_t kRuntimeParameterCoreRegistersLength = 49 arraysize(kRuntimeParameterCoreRegisters); 50static constexpr DRegister kRuntimeParameterFpuRegisters[] = { }; 51static constexpr size_t kRuntimeParameterFpuRegistersLength = 0; 52 53class InvokeRuntimeCallingConvention : public CallingConvention<Register, DRegister> { 54 public: 55 InvokeRuntimeCallingConvention() 56 : CallingConvention(kRuntimeParameterCoreRegisters, 57 kRuntimeParameterCoreRegistersLength, 58 kRuntimeParameterFpuRegisters, 59 kRuntimeParameterFpuRegistersLength) {} 60 61 private: 62 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 63}; 64 65#define __ reinterpret_cast<ArmAssembler*>(codegen->GetAssembler())-> 66 67class NullCheckSlowPathARM : public SlowPathCode { 68 public: 69 explicit NullCheckSlowPathARM(HNullCheck* instruction) : instruction_(instruction) {} 70 71 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 72 __ Bind(GetEntryLabel()); 73 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowNullPointer).Int32Value(); 74 __ ldr(LR, Address(TR, offset)); 75 __ blx(LR); 76 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 77 } 78 79 private: 80 HNullCheck* const instruction_; 81 DISALLOW_COPY_AND_ASSIGN(NullCheckSlowPathARM); 82}; 83 84class StackOverflowCheckSlowPathARM : public SlowPathCode { 85 public: 86 StackOverflowCheckSlowPathARM() {} 87 88 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 89 __ Bind(GetEntryLabel()); 90 __ LoadFromOffset(kLoadWord, PC, TR, 91 QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowStackOverflow).Int32Value()); 92 } 93 94 private: 95 DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM); 96}; 97 98class SuspendCheckSlowPathARM : public SlowPathCode { 99 public: 100 explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction, HBasicBlock* successor) 101 : instruction_(instruction), successor_(successor) {} 102 103 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 104 __ Bind(GetEntryLabel()); 105 codegen->SaveLiveRegisters(instruction_->GetLocations()); 106 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value(); 107 __ ldr(LR, Address(TR, offset)); 108 __ blx(LR); 109 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 110 codegen->RestoreLiveRegisters(instruction_->GetLocations()); 111 if (successor_ == nullptr) { 112 __ b(GetReturnLabel()); 113 } else { 114 __ b(codegen->GetLabelOf(successor_)); 115 } 116 } 117 118 Label* GetReturnLabel() { 119 DCHECK(successor_ == nullptr); 120 return &return_label_; 121 } 122 123 private: 124 HSuspendCheck* const instruction_; 125 // If not null, the block to branch to after the suspend check. 126 HBasicBlock* const successor_; 127 128 // If `successor_` is null, the label to branch to after the suspend check. 129 Label return_label_; 130 131 DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM); 132}; 133 134class BoundsCheckSlowPathARM : public SlowPathCode { 135 public: 136 BoundsCheckSlowPathARM(HBoundsCheck* instruction, 137 Location index_location, 138 Location length_location) 139 : instruction_(instruction), 140 index_location_(index_location), 141 length_location_(length_location) {} 142 143 virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { 144 CodeGeneratorARM* arm_codegen = reinterpret_cast<CodeGeneratorARM*>(codegen); 145 __ Bind(GetEntryLabel()); 146 InvokeRuntimeCallingConvention calling_convention; 147 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(0)), index_location_); 148 arm_codegen->Move32(ArmCoreLocation(calling_convention.GetRegisterAt(1)), length_location_); 149 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pThrowArrayBounds).Int32Value(); 150 __ ldr(LR, Address(TR, offset)); 151 __ blx(LR); 152 codegen->RecordPcInfo(instruction_, instruction_->GetDexPc()); 153 } 154 155 private: 156 HBoundsCheck* const instruction_; 157 const Location index_location_; 158 const Location length_location_; 159 160 DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathARM); 161}; 162 163#undef __ 164#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> 165 166inline Condition ARMCondition(IfCondition cond) { 167 switch (cond) { 168 case kCondEQ: return EQ; 169 case kCondNE: return NE; 170 case kCondLT: return LT; 171 case kCondLE: return LE; 172 case kCondGT: return GT; 173 case kCondGE: return GE; 174 default: 175 LOG(FATAL) << "Unknown if condition"; 176 } 177 return EQ; // Unreachable. 178} 179 180inline Condition ARMOppositeCondition(IfCondition cond) { 181 switch (cond) { 182 case kCondEQ: return NE; 183 case kCondNE: return EQ; 184 case kCondLT: return GE; 185 case kCondLE: return GT; 186 case kCondGT: return LE; 187 case kCondGE: return LT; 188 default: 189 LOG(FATAL) << "Unknown if condition"; 190 } 191 return EQ; // Unreachable. 192} 193 194void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const { 195 stream << ArmManagedRegister::FromCoreRegister(Register(reg)); 196} 197 198void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 199 stream << ArmManagedRegister::FromDRegister(DRegister(reg)); 200} 201 202void CodeGeneratorARM::SaveCoreRegister(Location stack_location, uint32_t reg_id) { 203 __ str(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex())); 204} 205 206void CodeGeneratorARM::RestoreCoreRegister(Location stack_location, uint32_t reg_id) { 207 __ ldr(static_cast<Register>(reg_id), Address(SP, stack_location.GetStackIndex())); 208} 209 210CodeGeneratorARM::CodeGeneratorARM(HGraph* graph) 211 : CodeGenerator(graph, kNumberOfRegIds), 212 location_builder_(graph, this), 213 instruction_visitor_(graph, this), 214 move_resolver_(graph->GetArena(), this), 215 assembler_(true) {} 216 217size_t CodeGeneratorARM::FrameEntrySpillSize() const { 218 return kNumberOfPushedRegistersAtEntry * kArmWordSize; 219} 220 221static bool* GetBlockedRegisterPairs(bool* blocked_registers) { 222 return blocked_registers + kNumberOfAllocIds; 223} 224 225static bool* GetBlockedDRegisters(bool* blocked_registers) { 226 return blocked_registers + kNumberOfCoreRegisters + kNumberOfSRegisters; 227} 228 229ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type, 230 bool* blocked_registers) const { 231 switch (type) { 232 case Primitive::kPrimLong: { 233 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers); 234 size_t reg = AllocateFreeRegisterInternal(blocked_register_pairs, kNumberOfRegisterPairs); 235 ArmManagedRegister pair = 236 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg)); 237 blocked_registers[pair.AsRegisterPairLow()] = true; 238 blocked_registers[pair.AsRegisterPairHigh()] = true; 239 // Block all other register pairs that share a register with `pair`. 240 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 241 ArmManagedRegister current = 242 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 243 if (current.AsRegisterPairLow() == pair.AsRegisterPairLow() 244 || current.AsRegisterPairLow() == pair.AsRegisterPairHigh() 245 || current.AsRegisterPairHigh() == pair.AsRegisterPairLow() 246 || current.AsRegisterPairHigh() == pair.AsRegisterPairHigh()) { 247 blocked_register_pairs[i] = true; 248 } 249 } 250 return pair; 251 } 252 253 case Primitive::kPrimByte: 254 case Primitive::kPrimBoolean: 255 case Primitive::kPrimChar: 256 case Primitive::kPrimShort: 257 case Primitive::kPrimInt: 258 case Primitive::kPrimNot: { 259 int reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters); 260 // Block all register pairs that contain `reg`. 261 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers); 262 for (int i = 0; i < kNumberOfRegisterPairs; i++) { 263 ArmManagedRegister current = 264 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); 265 if (current.AsRegisterPairLow() == reg || current.AsRegisterPairHigh() == reg) { 266 blocked_register_pairs[i] = true; 267 } 268 } 269 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg)); 270 } 271 272 case Primitive::kPrimFloat: 273 case Primitive::kPrimDouble: { 274 int reg = AllocateFreeRegisterInternal(GetBlockedDRegisters(blocked_registers), kNumberOfDRegisters); 275 return ArmManagedRegister::FromDRegister(static_cast<DRegister>(reg)); 276 } 277 278 case Primitive::kPrimVoid: 279 LOG(FATAL) << "Unreachable type " << type; 280 } 281 282 return ManagedRegister::NoRegister(); 283} 284 285void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const { 286 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers); 287 bool* blocked_fpu_registers = GetBlockedDRegisters(blocked_registers); 288 289 // Don't allocate the dalvik style register pair passing. 290 blocked_register_pairs[R1_R2] = true; 291 292 // Stack register, LR and PC are always reserved. 293 blocked_registers[SP] = true; 294 blocked_registers[LR] = true; 295 blocked_registers[PC] = true; 296 297 // Reserve R4 for suspend check. 298 blocked_registers[R4] = true; 299 blocked_register_pairs[R4_R5] = true; 300 301 // Reserve thread register. 302 blocked_registers[TR] = true; 303 304 // Reserve temp register. 305 blocked_registers[IP] = true; 306 307 // TODO: We currently don't use Quick's callee saved registers. 308 // We always save and restore R6 and R7 to make sure we can use three 309 // register pairs for long operations. 310 blocked_registers[R5] = true; 311 blocked_registers[R8] = true; 312 blocked_registers[R10] = true; 313 blocked_registers[R11] = true; 314 315 blocked_fpu_registers[D8] = true; 316 blocked_fpu_registers[D9] = true; 317 blocked_fpu_registers[D10] = true; 318 blocked_fpu_registers[D11] = true; 319 blocked_fpu_registers[D12] = true; 320 blocked_fpu_registers[D13] = true; 321 blocked_fpu_registers[D14] = true; 322 blocked_fpu_registers[D15] = true; 323} 324 325size_t CodeGeneratorARM::GetNumberOfRegisters() const { 326 return kNumberOfRegIds; 327} 328 329InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) 330 : HGraphVisitor(graph), 331 assembler_(codegen->GetAssembler()), 332 codegen_(codegen) {} 333 334void CodeGeneratorARM::GenerateFrameEntry() { 335 bool skip_overflow_check = IsLeafMethod() && !FrameNeedsStackCheck(GetFrameSize(), InstructionSet::kArm); 336 if (!skip_overflow_check) { 337 if (kExplicitStackOverflowCheck) { 338 SlowPathCode* slow_path = new (GetGraph()->GetArena()) StackOverflowCheckSlowPathARM(); 339 AddSlowPath(slow_path); 340 341 __ LoadFromOffset(kLoadWord, IP, TR, Thread::StackEndOffset<kArmWordSize>().Int32Value()); 342 __ cmp(SP, ShifterOperand(IP)); 343 __ b(slow_path->GetEntryLabel(), CC); 344 } else { 345 __ AddConstant(IP, SP, -static_cast<int32_t>(GetStackOverflowReservedBytes(kArm))); 346 __ ldr(IP, Address(IP, 0)); 347 RecordPcInfo(nullptr, 0); 348 } 349 } 350 351 core_spill_mask_ |= (1 << LR | 1 << R6 | 1 << R7); 352 __ PushList(1 << LR | 1 << R6 | 1 << R7); 353 354 // The return PC has already been pushed on the stack. 355 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize)); 356 __ str(R0, Address(SP, 0)); 357} 358 359void CodeGeneratorARM::GenerateFrameExit() { 360 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize); 361 __ PopList(1 << PC | 1 << R6 | 1 << R7); 362} 363 364void CodeGeneratorARM::Bind(Label* label) { 365 __ Bind(label); 366} 367 368Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const { 369 switch (load->GetType()) { 370 case Primitive::kPrimLong: 371 case Primitive::kPrimDouble: 372 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 373 break; 374 375 case Primitive::kPrimInt: 376 case Primitive::kPrimNot: 377 case Primitive::kPrimFloat: 378 return Location::StackSlot(GetStackSlot(load->GetLocal())); 379 380 case Primitive::kPrimBoolean: 381 case Primitive::kPrimByte: 382 case Primitive::kPrimChar: 383 case Primitive::kPrimShort: 384 case Primitive::kPrimVoid: 385 LOG(FATAL) << "Unexpected type " << load->GetType(); 386 } 387 388 LOG(FATAL) << "Unreachable"; 389 return Location(); 390} 391 392Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { 393 switch (type) { 394 case Primitive::kPrimBoolean: 395 case Primitive::kPrimByte: 396 case Primitive::kPrimChar: 397 case Primitive::kPrimShort: 398 case Primitive::kPrimInt: 399 case Primitive::kPrimFloat: 400 case Primitive::kPrimNot: { 401 uint32_t index = gp_index_++; 402 if (index < calling_convention.GetNumberOfRegisters()) { 403 return ArmCoreLocation(calling_convention.GetRegisterAt(index)); 404 } else { 405 return Location::StackSlot(calling_convention.GetStackOffsetOf(index)); 406 } 407 } 408 409 case Primitive::kPrimLong: 410 case Primitive::kPrimDouble: { 411 uint32_t index = gp_index_; 412 gp_index_ += 2; 413 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 414 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair( 415 calling_convention.GetRegisterPairAt(index))); 416 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { 417 return Location::QuickParameter(index); 418 } else { 419 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index)); 420 } 421 } 422 423 case Primitive::kPrimVoid: 424 LOG(FATAL) << "Unexpected parameter type " << type; 425 break; 426 } 427 return Location(); 428} 429 430void CodeGeneratorARM::Move32(Location destination, Location source) { 431 if (source.Equals(destination)) { 432 return; 433 } 434 if (destination.IsRegister()) { 435 if (source.IsRegister()) { 436 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister()); 437 } else if (source.IsFpuRegister()) { 438 __ vmovrs(destination.AsArm().AsCoreRegister(), 439 source.AsArm().AsOverlappingDRegisterLow()); 440 } else { 441 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex())); 442 } 443 } else if (destination.IsFpuRegister()) { 444 if (source.IsRegister()) { 445 __ vmovsr(destination.AsArm().AsOverlappingDRegisterLow(), 446 source.AsArm().AsCoreRegister()); 447 } else if (source.IsFpuRegister()) { 448 __ vmovs(destination.AsArm().AsOverlappingDRegisterLow(), 449 source.AsArm().AsOverlappingDRegisterLow()); 450 } else { 451 __ vldrs(destination.AsArm().AsOverlappingDRegisterLow(), 452 Address(SP, source.GetStackIndex())); 453 } 454 } else { 455 DCHECK(destination.IsStackSlot()); 456 if (source.IsRegister()) { 457 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex())); 458 } else if (source.IsFpuRegister()) { 459 __ vstrs(source.AsArm().AsOverlappingDRegisterLow(), 460 Address(SP, destination.GetStackIndex())); 461 } else { 462 DCHECK(source.IsStackSlot()); 463 __ ldr(IP, Address(SP, source.GetStackIndex())); 464 __ str(IP, Address(SP, destination.GetStackIndex())); 465 } 466 } 467} 468 469void CodeGeneratorARM::Move64(Location destination, Location source) { 470 if (source.Equals(destination)) { 471 return; 472 } 473 if (destination.IsRegister()) { 474 if (source.IsRegister()) { 475 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow()); 476 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh()); 477 } else if (source.IsFpuRegister()) { 478 LOG(FATAL) << "Unimplemented"; 479 } else if (source.IsQuickParameter()) { 480 uint32_t argument_index = source.GetQuickParameterIndex(); 481 InvokeDexCallingConvention calling_convention; 482 __ Mov(destination.AsArm().AsRegisterPairLow(), 483 calling_convention.GetRegisterAt(argument_index)); 484 __ ldr(destination.AsArm().AsRegisterPairHigh(), 485 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize())); 486 } else { 487 DCHECK(source.IsDoubleStackSlot()); 488 if (destination.AsArm().AsRegisterPair() == R1_R2) { 489 __ ldr(R1, Address(SP, source.GetStackIndex())); 490 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize))); 491 } else { 492 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(), 493 SP, source.GetStackIndex()); 494 } 495 } 496 } else if (destination.IsFpuRegister()) { 497 if (source.IsDoubleStackSlot()) { 498 __ vldrd(destination.AsArm().AsDRegister(), Address(SP, source.GetStackIndex())); 499 } else { 500 LOG(FATAL) << "Unimplemented"; 501 } 502 } else if (destination.IsQuickParameter()) { 503 InvokeDexCallingConvention calling_convention; 504 uint32_t argument_index = destination.GetQuickParameterIndex(); 505 if (source.IsRegister()) { 506 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow()); 507 __ str(source.AsArm().AsRegisterPairHigh(), 508 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1))); 509 } else if (source.IsFpuRegister()) { 510 LOG(FATAL) << "Unimplemented"; 511 } else { 512 DCHECK(source.IsDoubleStackSlot()); 513 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex())); 514 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize))); 515 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1))); 516 } 517 } else { 518 DCHECK(destination.IsDoubleStackSlot()); 519 if (source.IsRegister()) { 520 if (source.AsArm().AsRegisterPair() == R1_R2) { 521 __ str(R1, Address(SP, destination.GetStackIndex())); 522 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 523 } else { 524 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(), 525 SP, destination.GetStackIndex()); 526 } 527 } else if (source.IsQuickParameter()) { 528 InvokeDexCallingConvention calling_convention; 529 uint32_t argument_index = source.GetQuickParameterIndex(); 530 __ str(calling_convention.GetRegisterAt(argument_index), 531 Address(SP, destination.GetStackIndex())); 532 __ ldr(R0, 533 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize())); 534 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 535 } else if (source.IsFpuRegister()) { 536 __ vstrd(source.AsArm().AsDRegister(), Address(SP, destination.GetStackIndex())); 537 } else { 538 DCHECK(source.IsDoubleStackSlot()); 539 __ ldr(IP, Address(SP, source.GetStackIndex())); 540 __ str(IP, Address(SP, destination.GetStackIndex())); 541 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize))); 542 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 543 } 544 } 545} 546 547void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 548 LocationSummary* locations = instruction->GetLocations(); 549 if (locations != nullptr && locations->Out().Equals(location)) { 550 return; 551 } 552 553 if (instruction->AsIntConstant() != nullptr) { 554 int32_t value = instruction->AsIntConstant()->GetValue(); 555 if (location.IsRegister()) { 556 __ LoadImmediate(location.AsArm().AsCoreRegister(), value); 557 } else { 558 DCHECK(location.IsStackSlot()); 559 __ LoadImmediate(IP, value); 560 __ str(IP, Address(SP, location.GetStackIndex())); 561 } 562 } else if (instruction->AsLongConstant() != nullptr) { 563 int64_t value = instruction->AsLongConstant()->GetValue(); 564 if (location.IsRegister()) { 565 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value)); 566 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value)); 567 } else { 568 DCHECK(location.IsDoubleStackSlot()); 569 __ LoadImmediate(IP, Low32Bits(value)); 570 __ str(IP, Address(SP, location.GetStackIndex())); 571 __ LoadImmediate(IP, High32Bits(value)); 572 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize))); 573 } 574 } else if (instruction->AsLoadLocal() != nullptr) { 575 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 576 switch (instruction->GetType()) { 577 case Primitive::kPrimBoolean: 578 case Primitive::kPrimByte: 579 case Primitive::kPrimChar: 580 case Primitive::kPrimShort: 581 case Primitive::kPrimInt: 582 case Primitive::kPrimNot: 583 case Primitive::kPrimFloat: 584 Move32(location, Location::StackSlot(stack_slot)); 585 break; 586 587 case Primitive::kPrimLong: 588 case Primitive::kPrimDouble: 589 Move64(location, Location::DoubleStackSlot(stack_slot)); 590 break; 591 592 default: 593 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 594 } 595 } else { 596 DCHECK((instruction->GetNext() == move_for) || instruction->GetNext()->IsTemporary()); 597 switch (instruction->GetType()) { 598 case Primitive::kPrimBoolean: 599 case Primitive::kPrimByte: 600 case Primitive::kPrimChar: 601 case Primitive::kPrimShort: 602 case Primitive::kPrimNot: 603 case Primitive::kPrimInt: 604 case Primitive::kPrimFloat: 605 Move32(location, locations->Out()); 606 break; 607 608 case Primitive::kPrimLong: 609 case Primitive::kPrimDouble: 610 Move64(location, locations->Out()); 611 break; 612 613 default: 614 LOG(FATAL) << "Unexpected type " << instruction->GetType(); 615 } 616 } 617} 618 619void LocationsBuilderARM::VisitGoto(HGoto* got) { 620 got->SetLocations(nullptr); 621} 622 623void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { 624 HBasicBlock* successor = got->GetSuccessor(); 625 DCHECK(!successor->IsExitBlock()); 626 627 HBasicBlock* block = got->GetBlock(); 628 HInstruction* previous = got->GetPrevious(); 629 630 HLoopInformation* info = block->GetLoopInformation(); 631 if (info != nullptr && info->IsBackEdge(block) && info->HasSuspendCheck()) { 632 codegen_->ClearSpillSlotsFromLoopPhisInStackMap(info->GetSuspendCheck()); 633 GenerateSuspendCheck(info->GetSuspendCheck(), successor); 634 return; 635 } 636 637 if (block->IsEntryBlock() && (previous != nullptr) && previous->IsSuspendCheck()) { 638 GenerateSuspendCheck(previous->AsSuspendCheck(), nullptr); 639 } 640 if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 641 __ b(codegen_->GetLabelOf(successor)); 642 } 643} 644 645void LocationsBuilderARM::VisitExit(HExit* exit) { 646 exit->SetLocations(nullptr); 647} 648 649void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { 650 if (kIsDebugBuild) { 651 __ Comment("Unreachable"); 652 __ bkpt(0); 653 } 654} 655 656void LocationsBuilderARM::VisitIf(HIf* if_instr) { 657 LocationSummary* locations = 658 new (GetGraph()->GetArena()) LocationSummary(if_instr, LocationSummary::kNoCall); 659 HInstruction* cond = if_instr->InputAt(0); 660 DCHECK(cond->IsCondition()); 661 HCondition* condition = cond->AsCondition(); 662 if (condition->NeedsMaterialization()) { 663 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 664 } 665} 666 667void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 668 HInstruction* cond = if_instr->InputAt(0); 669 DCHECK(cond->IsCondition()); 670 HCondition* condition = cond->AsCondition(); 671 if (condition->NeedsMaterialization()) { 672 // Condition has been materialized, compare the output to 0 673 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister()); 674 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), 675 ShifterOperand(0)); 676 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE); 677 } else { 678 // Condition has not been materialized, use its inputs as the comparison and its 679 // condition as the branch condition. 680 LocationSummary* locations = condition->GetLocations(); 681 if (locations->InAt(1).IsRegister()) { 682 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), 683 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 684 } else { 685 DCHECK(locations->InAt(1).IsConstant()); 686 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 687 ShifterOperand operand; 688 if (ShifterOperand::CanHoldArm(value, &operand)) { 689 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value)); 690 } else { 691 Register temp = IP; 692 __ LoadImmediate(temp, value); 693 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp)); 694 } 695 } 696 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), 697 ARMCondition(condition->GetCondition())); 698 } 699 700 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) { 701 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); 702 } 703} 704 705 706void LocationsBuilderARM::VisitCondition(HCondition* comp) { 707 LocationSummary* locations = 708 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); 709 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 710 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry); 711 if (comp->NeedsMaterialization()) { 712 locations->SetOut(Location::RequiresRegister()); 713 } 714} 715 716void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) { 717 if (!comp->NeedsMaterialization()) return; 718 719 LocationSummary* locations = comp->GetLocations(); 720 if (locations->InAt(1).IsRegister()) { 721 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), 722 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 723 } else { 724 DCHECK(locations->InAt(1).IsConstant()); 725 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 726 ShifterOperand operand; 727 if (ShifterOperand::CanHoldArm(value, &operand)) { 728 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value)); 729 } else { 730 Register temp = IP; 731 __ LoadImmediate(temp, value); 732 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp)); 733 } 734 } 735 __ it(ARMCondition(comp->GetCondition()), kItElse); 736 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), 737 ARMCondition(comp->GetCondition())); 738 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), 739 ARMOppositeCondition(comp->GetCondition())); 740} 741 742void LocationsBuilderARM::VisitEqual(HEqual* comp) { 743 VisitCondition(comp); 744} 745 746void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) { 747 VisitCondition(comp); 748} 749 750void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) { 751 VisitCondition(comp); 752} 753 754void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) { 755 VisitCondition(comp); 756} 757 758void LocationsBuilderARM::VisitLessThan(HLessThan* comp) { 759 VisitCondition(comp); 760} 761 762void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) { 763 VisitCondition(comp); 764} 765 766void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 767 VisitCondition(comp); 768} 769 770void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 771 VisitCondition(comp); 772} 773 774void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) { 775 VisitCondition(comp); 776} 777 778void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) { 779 VisitCondition(comp); 780} 781 782void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 783 VisitCondition(comp); 784} 785 786void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 787 VisitCondition(comp); 788} 789 790void LocationsBuilderARM::VisitLocal(HLocal* local) { 791 local->SetLocations(nullptr); 792} 793 794void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 795 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 796} 797 798void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 799 load->SetLocations(nullptr); 800} 801 802void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 803 // Nothing to do, this is driven by the code generator. 804} 805 806void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 807 LocationSummary* locations = 808 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall); 809 switch (store->InputAt(1)->GetType()) { 810 case Primitive::kPrimBoolean: 811 case Primitive::kPrimByte: 812 case Primitive::kPrimChar: 813 case Primitive::kPrimShort: 814 case Primitive::kPrimInt: 815 case Primitive::kPrimNot: 816 case Primitive::kPrimFloat: 817 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 818 break; 819 820 case Primitive::kPrimLong: 821 case Primitive::kPrimDouble: 822 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 823 break; 824 825 default: 826 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType(); 827 } 828} 829 830void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 831} 832 833void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 834 LocationSummary* locations = 835 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 836 locations->SetOut(Location::ConstantLocation(constant)); 837} 838 839void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 840} 841 842void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { 843 LocationSummary* locations = 844 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 845 locations->SetOut(Location::ConstantLocation(constant)); 846} 847 848void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { 849 // Will be generated at use site. 850} 851 852void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 853 ret->SetLocations(nullptr); 854} 855 856void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 857 codegen_->GenerateFrameExit(); 858} 859 860void LocationsBuilderARM::VisitReturn(HReturn* ret) { 861 LocationSummary* locations = 862 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall); 863 switch (ret->InputAt(0)->GetType()) { 864 case Primitive::kPrimBoolean: 865 case Primitive::kPrimByte: 866 case Primitive::kPrimChar: 867 case Primitive::kPrimShort: 868 case Primitive::kPrimInt: 869 case Primitive::kPrimNot: 870 case Primitive::kPrimFloat: 871 locations->SetInAt(0, ArmCoreLocation(R0)); 872 break; 873 874 case Primitive::kPrimLong: 875 case Primitive::kPrimDouble: 876 locations->SetInAt( 877 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 878 break; 879 880 default: 881 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 882 } 883} 884 885void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 886 if (kIsDebugBuild) { 887 switch (ret->InputAt(0)->GetType()) { 888 case Primitive::kPrimBoolean: 889 case Primitive::kPrimByte: 890 case Primitive::kPrimChar: 891 case Primitive::kPrimShort: 892 case Primitive::kPrimInt: 893 case Primitive::kPrimNot: 894 case Primitive::kPrimFloat: 895 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0); 896 break; 897 898 case Primitive::kPrimLong: 899 case Primitive::kPrimDouble: 900 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1); 901 break; 902 903 default: 904 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 905 } 906 } 907 codegen_->GenerateFrameExit(); 908} 909 910void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { 911 HandleInvoke(invoke); 912} 913 914void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) { 915 __ ldr(reg, Address(SP, kCurrentMethodStackOffset)); 916} 917 918void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { 919 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister(); 920 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>); 921 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() + 922 invoke->GetIndexInDexCache() * kArmWordSize; 923 924 // TODO: Implement all kinds of calls: 925 // 1) boot -> boot 926 // 2) app -> boot 927 // 3) app -> app 928 // 929 // Currently we implement the app -> app logic, which looks up in the resolve cache. 930 931 // temp = method; 932 LoadCurrentMethod(temp); 933 // temp = temp->dex_cache_resolved_methods_; 934 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); 935 // temp = temp[index_in_cache] 936 __ ldr(temp, Address(temp, index_in_cache)); 937 // LR = temp[offset_of_quick_compiled_code] 938 __ ldr(LR, Address(temp, 939 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); 940 // LR() 941 __ blx(LR); 942 943 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 944 DCHECK(!codegen_->IsLeafMethod()); 945} 946 947void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 948 HandleInvoke(invoke); 949} 950 951void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { 952 LocationSummary* locations = 953 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); 954 locations->AddTemp(ArmCoreLocation(R0)); 955 956 InvokeDexCallingConventionVisitor calling_convention_visitor; 957 for (size_t i = 0; i < invoke->InputCount(); i++) { 958 HInstruction* input = invoke->InputAt(i); 959 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 960 } 961 962 switch (invoke->GetType()) { 963 case Primitive::kPrimBoolean: 964 case Primitive::kPrimByte: 965 case Primitive::kPrimChar: 966 case Primitive::kPrimShort: 967 case Primitive::kPrimInt: 968 case Primitive::kPrimNot: 969 case Primitive::kPrimFloat: 970 locations->SetOut(ArmCoreLocation(R0)); 971 break; 972 973 case Primitive::kPrimLong: 974 case Primitive::kPrimDouble: 975 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 976 break; 977 978 case Primitive::kPrimVoid: 979 break; 980 } 981} 982 983 984void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 985 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister(); 986 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() + 987 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); 988 LocationSummary* locations = invoke->GetLocations(); 989 Location receiver = locations->InAt(0); 990 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 991 // temp = object->GetClass(); 992 if (receiver.IsStackSlot()) { 993 __ ldr(temp, Address(SP, receiver.GetStackIndex())); 994 __ ldr(temp, Address(temp, class_offset)); 995 } else { 996 __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset)); 997 } 998 // temp = temp->GetMethodAt(method_offset); 999 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); 1000 __ ldr(temp, Address(temp, method_offset)); 1001 // LR = temp->GetEntryPoint(); 1002 __ ldr(LR, Address(temp, entry_point)); 1003 // LR(); 1004 __ blx(LR); 1005 DCHECK(!codegen_->IsLeafMethod()); 1006 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1007} 1008 1009void LocationsBuilderARM::VisitAdd(HAdd* add) { 1010 LocationSummary* locations = 1011 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); 1012 switch (add->GetResultType()) { 1013 case Primitive::kPrimInt: 1014 case Primitive::kPrimLong: { 1015 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong; 1016 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); 1017 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry); 1018 locations->SetOut(Location::RequiresRegister()); 1019 break; 1020 } 1021 1022 case Primitive::kPrimFloat: 1023 case Primitive::kPrimDouble: { 1024 locations->SetInAt(0, Location::RequiresFpuRegister()); 1025 locations->SetInAt(1, Location::RequiresFpuRegister()); 1026 locations->SetOut(Location::RequiresFpuRegister()); 1027 break; 1028 } 1029 1030 default: 1031 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1032 } 1033} 1034 1035void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 1036 LocationSummary* locations = add->GetLocations(); 1037 switch (add->GetResultType()) { 1038 case Primitive::kPrimInt: 1039 if (locations->InAt(1).IsRegister()) { 1040 __ add(locations->Out().AsArm().AsCoreRegister(), 1041 locations->InAt(0).AsArm().AsCoreRegister(), 1042 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 1043 } else { 1044 __ AddConstant(locations->Out().AsArm().AsCoreRegister(), 1045 locations->InAt(0).AsArm().AsCoreRegister(), 1046 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()); 1047 } 1048 break; 1049 1050 case Primitive::kPrimLong: 1051 __ adds(locations->Out().AsArm().AsRegisterPairLow(), 1052 locations->InAt(0).AsArm().AsRegisterPairLow(), 1053 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); 1054 __ adc(locations->Out().AsArm().AsRegisterPairHigh(), 1055 locations->InAt(0).AsArm().AsRegisterPairHigh(), 1056 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 1057 break; 1058 1059 case Primitive::kPrimFloat: 1060 __ vadds(locations->Out().AsArm().AsOverlappingDRegisterLow(), 1061 locations->InAt(0).AsArm().AsOverlappingDRegisterLow(), 1062 locations->InAt(1).AsArm().AsOverlappingDRegisterLow()); 1063 break; 1064 1065 case Primitive::kPrimDouble: 1066 __ vaddd(locations->Out().AsArm().AsDRegister(), 1067 locations->InAt(0).AsArm().AsDRegister(), 1068 locations->InAt(1).AsArm().AsDRegister()); 1069 break; 1070 1071 default: 1072 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1073 } 1074} 1075 1076void LocationsBuilderARM::VisitSub(HSub* sub) { 1077 LocationSummary* locations = 1078 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall); 1079 switch (sub->GetResultType()) { 1080 case Primitive::kPrimInt: 1081 case Primitive::kPrimLong: { 1082 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong; 1083 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); 1084 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry); 1085 locations->SetOut(Location::RequiresRegister()); 1086 break; 1087 } 1088 1089 case Primitive::kPrimBoolean: 1090 case Primitive::kPrimByte: 1091 case Primitive::kPrimChar: 1092 case Primitive::kPrimShort: 1093 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1094 break; 1095 1096 default: 1097 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 1098 } 1099} 1100 1101void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { 1102 LocationSummary* locations = sub->GetLocations(); 1103 switch (sub->GetResultType()) { 1104 case Primitive::kPrimInt: { 1105 if (locations->InAt(1).IsRegister()) { 1106 __ sub(locations->Out().AsArm().AsCoreRegister(), 1107 locations->InAt(0).AsArm().AsCoreRegister(), 1108 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 1109 } else { 1110 __ AddConstant(locations->Out().AsArm().AsCoreRegister(), 1111 locations->InAt(0).AsArm().AsCoreRegister(), 1112 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()); 1113 } 1114 break; 1115 } 1116 1117 case Primitive::kPrimLong: 1118 __ subs(locations->Out().AsArm().AsRegisterPairLow(), 1119 locations->InAt(0).AsArm().AsRegisterPairLow(), 1120 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); 1121 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(), 1122 locations->InAt(0).AsArm().AsRegisterPairHigh(), 1123 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 1124 break; 1125 1126 case Primitive::kPrimBoolean: 1127 case Primitive::kPrimByte: 1128 case Primitive::kPrimChar: 1129 case Primitive::kPrimShort: 1130 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1131 break; 1132 1133 default: 1134 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 1135 } 1136} 1137 1138void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 1139 LocationSummary* locations = 1140 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1141 InvokeRuntimeCallingConvention calling_convention; 1142 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0))); 1143 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1))); 1144 locations->SetOut(ArmCoreLocation(R0)); 1145} 1146 1147void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 1148 InvokeRuntimeCallingConvention calling_convention; 1149 LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 1150 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 1151 1152 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value(); 1153 __ ldr(LR, Address(TR, offset)); 1154 __ blx(LR); 1155 1156 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 1157 DCHECK(!codegen_->IsLeafMethod()); 1158} 1159 1160void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 1161 LocationSummary* locations = 1162 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1163 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 1164 if (location.IsStackSlot()) { 1165 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1166 } else if (location.IsDoubleStackSlot()) { 1167 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1168 } 1169 locations->SetOut(location); 1170} 1171 1172void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 1173 // Nothing to do, the parameter is already at its location. 1174} 1175 1176void LocationsBuilderARM::VisitNot(HNot* instruction) { 1177 LocationSummary* locations = 1178 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1179 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1180 locations->SetOut(Location::RequiresRegister()); 1181} 1182 1183void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { 1184 LocationSummary* locations = instruction->GetLocations(); 1185 __ eor(locations->Out().AsArm().AsCoreRegister(), 1186 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1)); 1187} 1188 1189void LocationsBuilderARM::VisitCompare(HCompare* compare) { 1190 LocationSummary* locations = 1191 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 1192 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1193 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry); 1194 locations->SetOut(Location::RequiresRegister()); 1195} 1196 1197void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { 1198 Label greater, done; 1199 LocationSummary* locations = compare->GetLocations(); 1200 switch (compare->InputAt(0)->GetType()) { 1201 case Primitive::kPrimLong: { 1202 Register output = locations->Out().AsArm().AsCoreRegister(); 1203 ArmManagedRegister left = locations->InAt(0).AsArm(); 1204 ArmManagedRegister right = locations->InAt(1).AsArm(); 1205 Label less, greater, done; 1206 __ cmp(left.AsRegisterPairHigh(), 1207 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare. 1208 __ b(&less, LT); 1209 __ b(&greater, GT); 1210 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect 1211 // the status flags. 1212 __ LoadImmediate(output, 0); 1213 __ cmp(left.AsRegisterPairLow(), 1214 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare. 1215 __ b(&done, EQ); 1216 __ b(&less, CC); 1217 1218 __ Bind(&greater); 1219 __ LoadImmediate(output, 1); 1220 __ b(&done); 1221 1222 __ Bind(&less); 1223 __ LoadImmediate(output, -1); 1224 1225 __ Bind(&done); 1226 break; 1227 } 1228 default: 1229 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType(); 1230 } 1231} 1232 1233void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 1234 LocationSummary* locations = 1235 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1236 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 1237 locations->SetInAt(i, Location::Any()); 1238 } 1239 locations->SetOut(Location::Any()); 1240} 1241 1242void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 1243 LOG(FATAL) << "Unreachable"; 1244} 1245 1246void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1247 LocationSummary* locations = 1248 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1249 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot; 1250 bool dies_at_entry = !is_object_type; 1251 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); 1252 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry); 1253 // Temporary registers for the write barrier. 1254 if (is_object_type) { 1255 locations->AddTemp(Location::RequiresRegister()); 1256 locations->AddTemp(Location::RequiresRegister()); 1257 } 1258} 1259 1260void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1261 LocationSummary* locations = instruction->GetLocations(); 1262 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1263 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1264 Primitive::Type field_type = instruction->GetFieldType(); 1265 1266 switch (field_type) { 1267 case Primitive::kPrimBoolean: 1268 case Primitive::kPrimByte: { 1269 Register value = locations->InAt(1).AsArm().AsCoreRegister(); 1270 __ StoreToOffset(kStoreByte, value, obj, offset); 1271 break; 1272 } 1273 1274 case Primitive::kPrimShort: 1275 case Primitive::kPrimChar: { 1276 Register value = locations->InAt(1).AsArm().AsCoreRegister(); 1277 __ StoreToOffset(kStoreHalfword, value, obj, offset); 1278 break; 1279 } 1280 1281 case Primitive::kPrimInt: 1282 case Primitive::kPrimNot: { 1283 Register value = locations->InAt(1).AsArm().AsCoreRegister(); 1284 __ StoreToOffset(kStoreWord, value, obj, offset); 1285 if (field_type == Primitive::kPrimNot) { 1286 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister(); 1287 Register card = locations->GetTemp(1).AsArm().AsCoreRegister(); 1288 codegen_->MarkGCCard(temp, card, obj, value); 1289 } 1290 break; 1291 } 1292 1293 case Primitive::kPrimLong: { 1294 ArmManagedRegister value = locations->InAt(1).AsArm(); 1295 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset); 1296 break; 1297 } 1298 1299 case Primitive::kPrimFloat: 1300 case Primitive::kPrimDouble: 1301 LOG(FATAL) << "Unimplemented register type " << field_type; 1302 1303 case Primitive::kPrimVoid: 1304 LOG(FATAL) << "Unreachable type " << field_type; 1305 } 1306} 1307 1308void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 1309 LocationSummary* locations = 1310 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1311 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1312 locations->SetOut(Location::RequiresRegister()); 1313} 1314 1315void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 1316 LocationSummary* locations = instruction->GetLocations(); 1317 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1318 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1319 1320 switch (instruction->GetType()) { 1321 case Primitive::kPrimBoolean: { 1322 Register out = locations->Out().AsArm().AsCoreRegister(); 1323 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 1324 break; 1325 } 1326 1327 case Primitive::kPrimByte: { 1328 Register out = locations->Out().AsArm().AsCoreRegister(); 1329 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 1330 break; 1331 } 1332 1333 case Primitive::kPrimShort: { 1334 Register out = locations->Out().AsArm().AsCoreRegister(); 1335 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 1336 break; 1337 } 1338 1339 case Primitive::kPrimChar: { 1340 Register out = locations->Out().AsArm().AsCoreRegister(); 1341 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 1342 break; 1343 } 1344 1345 case Primitive::kPrimInt: 1346 case Primitive::kPrimNot: { 1347 Register out = locations->Out().AsArm().AsCoreRegister(); 1348 __ LoadFromOffset(kLoadWord, out, obj, offset); 1349 break; 1350 } 1351 1352 case Primitive::kPrimLong: { 1353 // TODO: support volatile. 1354 ArmManagedRegister out = locations->Out().AsArm(); 1355 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset); 1356 break; 1357 } 1358 1359 case Primitive::kPrimFloat: 1360 case Primitive::kPrimDouble: 1361 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1362 1363 case Primitive::kPrimVoid: 1364 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1365 } 1366} 1367 1368void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { 1369 LocationSummary* locations = 1370 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1371 locations->SetInAt(0, Location::RequiresRegister()); 1372 if (instruction->HasUses()) { 1373 locations->SetOut(Location::SameAsFirstInput()); 1374 } 1375} 1376 1377void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { 1378 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); 1379 codegen_->AddSlowPath(slow_path); 1380 1381 LocationSummary* locations = instruction->GetLocations(); 1382 Location obj = locations->InAt(0); 1383 1384 if (obj.IsRegister()) { 1385 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0)); 1386 __ b(slow_path->GetEntryLabel(), EQ); 1387 } else { 1388 DCHECK(obj.IsConstant()) << obj; 1389 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); 1390 __ b(slow_path->GetEntryLabel()); 1391 } 1392} 1393 1394void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { 1395 LocationSummary* locations = 1396 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1397 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1398 locations->SetInAt( 1399 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); 1400 locations->SetOut(Location::RequiresRegister()); 1401} 1402 1403void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { 1404 LocationSummary* locations = instruction->GetLocations(); 1405 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1406 Location index = locations->InAt(1); 1407 1408 switch (instruction->GetType()) { 1409 case Primitive::kPrimBoolean: { 1410 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 1411 Register out = locations->Out().AsArm().AsCoreRegister(); 1412 if (index.IsConstant()) { 1413 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1414 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 1415 } else { 1416 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister())); 1417 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset); 1418 } 1419 break; 1420 } 1421 1422 case Primitive::kPrimByte: { 1423 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 1424 Register out = locations->Out().AsArm().AsCoreRegister(); 1425 if (index.IsConstant()) { 1426 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1427 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 1428 } else { 1429 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister())); 1430 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset); 1431 } 1432 break; 1433 } 1434 1435 case Primitive::kPrimShort: { 1436 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 1437 Register out = locations->Out().AsArm().AsCoreRegister(); 1438 if (index.IsConstant()) { 1439 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1440 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 1441 } else { 1442 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2)); 1443 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset); 1444 } 1445 break; 1446 } 1447 1448 case Primitive::kPrimChar: { 1449 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 1450 Register out = locations->Out().AsArm().AsCoreRegister(); 1451 if (index.IsConstant()) { 1452 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1453 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 1454 } else { 1455 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2)); 1456 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset); 1457 } 1458 break; 1459 } 1460 1461 case Primitive::kPrimInt: 1462 case Primitive::kPrimNot: { 1463 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t)); 1464 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 1465 Register out = locations->Out().AsArm().AsCoreRegister(); 1466 if (index.IsConstant()) { 1467 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 1468 __ LoadFromOffset(kLoadWord, out, obj, offset); 1469 } else { 1470 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4)); 1471 __ LoadFromOffset(kLoadWord, out, IP, data_offset); 1472 } 1473 break; 1474 } 1475 1476 case Primitive::kPrimLong: { 1477 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 1478 ArmManagedRegister out = locations->Out().AsArm(); 1479 if (index.IsConstant()) { 1480 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 1481 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset); 1482 } else { 1483 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8)); 1484 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset); 1485 } 1486 break; 1487 } 1488 1489 case Primitive::kPrimFloat: 1490 case Primitive::kPrimDouble: 1491 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1492 1493 case Primitive::kPrimVoid: 1494 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1495 } 1496} 1497 1498void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) { 1499 Primitive::Type value_type = instruction->GetComponentType(); 1500 bool is_object = value_type == Primitive::kPrimNot; 1501 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 1502 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall); 1503 if (is_object) { 1504 InvokeRuntimeCallingConvention calling_convention; 1505 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0))); 1506 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1))); 1507 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2))); 1508 } else { 1509 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1510 locations->SetInAt( 1511 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); 1512 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry); 1513 } 1514} 1515 1516void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { 1517 LocationSummary* locations = instruction->GetLocations(); 1518 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1519 Location index = locations->InAt(1); 1520 Primitive::Type value_type = instruction->GetComponentType(); 1521 1522 switch (value_type) { 1523 case Primitive::kPrimBoolean: 1524 case Primitive::kPrimByte: { 1525 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 1526 Register value = locations->InAt(2).AsArm().AsCoreRegister(); 1527 if (index.IsConstant()) { 1528 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1529 __ StoreToOffset(kStoreByte, value, obj, offset); 1530 } else { 1531 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister())); 1532 __ StoreToOffset(kStoreByte, value, IP, data_offset); 1533 } 1534 break; 1535 } 1536 1537 case Primitive::kPrimShort: 1538 case Primitive::kPrimChar: { 1539 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 1540 Register value = locations->InAt(2).AsArm().AsCoreRegister(); 1541 if (index.IsConstant()) { 1542 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1543 __ StoreToOffset(kStoreHalfword, value, obj, offset); 1544 } else { 1545 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2)); 1546 __ StoreToOffset(kStoreHalfword, value, IP, data_offset); 1547 } 1548 break; 1549 } 1550 1551 case Primitive::kPrimInt: { 1552 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 1553 Register value = locations->InAt(2).AsArm().AsCoreRegister(); 1554 if (index.IsConstant()) { 1555 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 1556 __ StoreToOffset(kStoreWord, value, obj, offset); 1557 } else { 1558 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4)); 1559 __ StoreToOffset(kStoreWord, value, IP, data_offset); 1560 } 1561 break; 1562 } 1563 1564 case Primitive::kPrimNot: { 1565 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value(); 1566 __ ldr(LR, Address(TR, offset)); 1567 __ blx(LR); 1568 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 1569 DCHECK(!codegen_->IsLeafMethod()); 1570 break; 1571 } 1572 1573 case Primitive::kPrimLong: { 1574 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 1575 ArmManagedRegister value = locations->InAt(2).AsArm(); 1576 if (index.IsConstant()) { 1577 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 1578 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset); 1579 } else { 1580 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8)); 1581 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset); 1582 } 1583 break; 1584 } 1585 1586 case Primitive::kPrimFloat: 1587 case Primitive::kPrimDouble: 1588 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1589 1590 case Primitive::kPrimVoid: 1591 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1592 } 1593} 1594 1595void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) { 1596 LocationSummary* locations = 1597 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1598 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1599 locations->SetOut(Location::RequiresRegister()); 1600} 1601 1602void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) { 1603 LocationSummary* locations = instruction->GetLocations(); 1604 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 1605 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1606 Register out = locations->Out().AsArm().AsCoreRegister(); 1607 __ LoadFromOffset(kLoadWord, out, obj, offset); 1608} 1609 1610void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { 1611 LocationSummary* locations = 1612 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1613 locations->SetInAt(0, Location::RequiresRegister()); 1614 locations->SetInAt(1, Location::RequiresRegister()); 1615 if (instruction->HasUses()) { 1616 locations->SetOut(Location::SameAsFirstInput()); 1617 } 1618} 1619 1620void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { 1621 LocationSummary* locations = instruction->GetLocations(); 1622 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM( 1623 instruction, locations->InAt(0), locations->InAt(1)); 1624 codegen_->AddSlowPath(slow_path); 1625 1626 Register index = locations->InAt(0).AsArm().AsCoreRegister(); 1627 Register length = locations->InAt(1).AsArm().AsCoreRegister(); 1628 1629 __ cmp(index, ShifterOperand(length)); 1630 __ b(slow_path->GetEntryLabel(), CS); 1631} 1632 1633void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) { 1634 Label is_null; 1635 __ CompareAndBranchIfZero(value, &is_null); 1636 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value()); 1637 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift); 1638 __ strb(card, Address(card, temp)); 1639 __ Bind(&is_null); 1640} 1641 1642void LocationsBuilderARM::VisitTemporary(HTemporary* temp) { 1643 temp->SetLocations(nullptr); 1644} 1645 1646void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) { 1647 // Nothing to do, this is driven by the code generator. 1648} 1649 1650void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) { 1651 LOG(FATAL) << "Unreachable"; 1652} 1653 1654void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) { 1655 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 1656} 1657 1658void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) { 1659 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 1660} 1661 1662void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) { 1663 HBasicBlock* block = instruction->GetBlock(); 1664 if (block->GetLoopInformation() != nullptr) { 1665 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 1666 // The back edge will generate the suspend check. 1667 return; 1668 } 1669 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 1670 // The goto will generate the suspend check. 1671 return; 1672 } 1673 GenerateSuspendCheck(instruction, nullptr); 1674} 1675 1676void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction, 1677 HBasicBlock* successor) { 1678 SuspendCheckSlowPathARM* slow_path = 1679 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor); 1680 codegen_->AddSlowPath(slow_path); 1681 1682 __ subs(R4, R4, ShifterOperand(1)); 1683 if (successor == nullptr) { 1684 __ b(slow_path->GetEntryLabel(), EQ); 1685 __ Bind(slow_path->GetReturnLabel()); 1686 } else { 1687 __ b(codegen_->GetLabelOf(successor), NE); 1688 __ b(slow_path->GetEntryLabel()); 1689 } 1690} 1691 1692ArmAssembler* ParallelMoveResolverARM::GetAssembler() const { 1693 return codegen_->GetAssembler(); 1694} 1695 1696void ParallelMoveResolverARM::EmitMove(size_t index) { 1697 MoveOperands* move = moves_.Get(index); 1698 Location source = move->GetSource(); 1699 Location destination = move->GetDestination(); 1700 1701 if (source.IsRegister()) { 1702 if (destination.IsRegister()) { 1703 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister()); 1704 } else { 1705 DCHECK(destination.IsStackSlot()); 1706 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(), 1707 SP, destination.GetStackIndex()); 1708 } 1709 } else if (source.IsStackSlot()) { 1710 if (destination.IsRegister()) { 1711 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(), 1712 SP, source.GetStackIndex()); 1713 } else { 1714 DCHECK(destination.IsStackSlot()); 1715 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 1716 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 1717 } 1718 } else { 1719 DCHECK(source.IsConstant()); 1720 DCHECK(source.GetConstant()->AsIntConstant() != nullptr); 1721 int32_t value = source.GetConstant()->AsIntConstant()->GetValue(); 1722 if (destination.IsRegister()) { 1723 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value); 1724 } else { 1725 DCHECK(destination.IsStackSlot()); 1726 __ LoadImmediate(IP, value); 1727 __ str(IP, Address(SP, destination.GetStackIndex())); 1728 } 1729 } 1730} 1731 1732void ParallelMoveResolverARM::Exchange(Register reg, int mem) { 1733 __ Mov(IP, reg); 1734 __ LoadFromOffset(kLoadWord, reg, SP, mem); 1735 __ StoreToOffset(kStoreWord, IP, SP, mem); 1736} 1737 1738void ParallelMoveResolverARM::Exchange(int mem1, int mem2) { 1739 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters()); 1740 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; 1741 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()), 1742 SP, mem1 + stack_offset); 1743 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset); 1744 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()), 1745 SP, mem2 + stack_offset); 1746 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset); 1747} 1748 1749void ParallelMoveResolverARM::EmitSwap(size_t index) { 1750 MoveOperands* move = moves_.Get(index); 1751 Location source = move->GetSource(); 1752 Location destination = move->GetDestination(); 1753 1754 if (source.IsRegister() && destination.IsRegister()) { 1755 DCHECK_NE(source.AsArm().AsCoreRegister(), IP); 1756 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP); 1757 __ Mov(IP, source.AsArm().AsCoreRegister()); 1758 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister()); 1759 __ Mov(destination.AsArm().AsCoreRegister(), IP); 1760 } else if (source.IsRegister() && destination.IsStackSlot()) { 1761 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex()); 1762 } else if (source.IsStackSlot() && destination.IsRegister()) { 1763 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex()); 1764 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 1765 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 1766 } else { 1767 LOG(FATAL) << "Unimplemented"; 1768 } 1769} 1770 1771void ParallelMoveResolverARM::SpillScratch(int reg) { 1772 __ Push(static_cast<Register>(reg)); 1773} 1774 1775void ParallelMoveResolverARM::RestoreScratch(int reg) { 1776 __ Pop(static_cast<Register>(reg)); 1777} 1778 1779} // namespace arm 1780} // namespace art 1781