code_generator_arm.cc revision 01ef345767ea609417fc511e42007705c9667546
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 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 661 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 662 } 663} 664 665void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 666 HInstruction* cond = if_instr->InputAt(0); 667 if (!cond->IsCondition() || cond->AsCondition()->NeedsMaterialization()) { 668 // Condition has been materialized, compare the output to 0 669 DCHECK(if_instr->GetLocations()->InAt(0).IsRegister()); 670 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), 671 ShifterOperand(0)); 672 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), NE); 673 } else { 674 // Condition has not been materialized, use its inputs as the comparison and its 675 // condition as the branch condition. 676 LocationSummary* locations = cond->GetLocations(); 677 if (locations->InAt(1).IsRegister()) { 678 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), 679 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 680 } else { 681 DCHECK(locations->InAt(1).IsConstant()); 682 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 683 ShifterOperand operand; 684 if (ShifterOperand::CanHoldArm(value, &operand)) { 685 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value)); 686 } else { 687 Register temp = IP; 688 __ LoadImmediate(temp, value); 689 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp)); 690 } 691 } 692 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), 693 ARMCondition(cond->AsCondition()->GetCondition())); 694 } 695 696 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) { 697 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); 698 } 699} 700 701 702void LocationsBuilderARM::VisitCondition(HCondition* comp) { 703 LocationSummary* locations = 704 new (GetGraph()->GetArena()) LocationSummary(comp, LocationSummary::kNoCall); 705 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 706 locations->SetInAt(1, Location::RegisterOrConstant(comp->InputAt(1)), Location::kDiesAtEntry); 707 if (comp->NeedsMaterialization()) { 708 locations->SetOut(Location::RequiresRegister()); 709 } 710} 711 712void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) { 713 if (!comp->NeedsMaterialization()) return; 714 715 LocationSummary* locations = comp->GetLocations(); 716 if (locations->InAt(1).IsRegister()) { 717 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), 718 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 719 } else { 720 DCHECK(locations->InAt(1).IsConstant()); 721 int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue(); 722 ShifterOperand operand; 723 if (ShifterOperand::CanHoldArm(value, &operand)) { 724 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(value)); 725 } else { 726 Register temp = IP; 727 __ LoadImmediate(temp, value); 728 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(temp)); 729 } 730 } 731 __ it(ARMCondition(comp->GetCondition()), kItElse); 732 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), 733 ARMCondition(comp->GetCondition())); 734 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), 735 ARMOppositeCondition(comp->GetCondition())); 736} 737 738void LocationsBuilderARM::VisitEqual(HEqual* comp) { 739 VisitCondition(comp); 740} 741 742void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) { 743 VisitCondition(comp); 744} 745 746void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) { 747 VisitCondition(comp); 748} 749 750void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) { 751 VisitCondition(comp); 752} 753 754void LocationsBuilderARM::VisitLessThan(HLessThan* comp) { 755 VisitCondition(comp); 756} 757 758void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) { 759 VisitCondition(comp); 760} 761 762void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 763 VisitCondition(comp); 764} 765 766void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 767 VisitCondition(comp); 768} 769 770void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) { 771 VisitCondition(comp); 772} 773 774void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) { 775 VisitCondition(comp); 776} 777 778void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 779 VisitCondition(comp); 780} 781 782void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 783 VisitCondition(comp); 784} 785 786void LocationsBuilderARM::VisitLocal(HLocal* local) { 787 local->SetLocations(nullptr); 788} 789 790void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 791 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 792} 793 794void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 795 load->SetLocations(nullptr); 796} 797 798void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 799 // Nothing to do, this is driven by the code generator. 800} 801 802void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 803 LocationSummary* locations = 804 new (GetGraph()->GetArena()) LocationSummary(store, LocationSummary::kNoCall); 805 switch (store->InputAt(1)->GetType()) { 806 case Primitive::kPrimBoolean: 807 case Primitive::kPrimByte: 808 case Primitive::kPrimChar: 809 case Primitive::kPrimShort: 810 case Primitive::kPrimInt: 811 case Primitive::kPrimNot: 812 case Primitive::kPrimFloat: 813 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 814 break; 815 816 case Primitive::kPrimLong: 817 case Primitive::kPrimDouble: 818 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 819 break; 820 821 default: 822 LOG(FATAL) << "Unexpected local type " << store->InputAt(1)->GetType(); 823 } 824} 825 826void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 827} 828 829void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 830 LocationSummary* locations = 831 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 832 locations->SetOut(Location::ConstantLocation(constant)); 833} 834 835void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 836} 837 838void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { 839 LocationSummary* locations = 840 new (GetGraph()->GetArena()) LocationSummary(constant, LocationSummary::kNoCall); 841 locations->SetOut(Location::ConstantLocation(constant)); 842} 843 844void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { 845 // Will be generated at use site. 846} 847 848void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 849 ret->SetLocations(nullptr); 850} 851 852void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 853 codegen_->GenerateFrameExit(); 854} 855 856void LocationsBuilderARM::VisitReturn(HReturn* ret) { 857 LocationSummary* locations = 858 new (GetGraph()->GetArena()) LocationSummary(ret, LocationSummary::kNoCall); 859 switch (ret->InputAt(0)->GetType()) { 860 case Primitive::kPrimBoolean: 861 case Primitive::kPrimByte: 862 case Primitive::kPrimChar: 863 case Primitive::kPrimShort: 864 case Primitive::kPrimInt: 865 case Primitive::kPrimNot: 866 case Primitive::kPrimFloat: 867 locations->SetInAt(0, ArmCoreLocation(R0)); 868 break; 869 870 case Primitive::kPrimLong: 871 case Primitive::kPrimDouble: 872 locations->SetInAt( 873 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 874 break; 875 876 default: 877 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 878 } 879} 880 881void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 882 if (kIsDebugBuild) { 883 switch (ret->InputAt(0)->GetType()) { 884 case Primitive::kPrimBoolean: 885 case Primitive::kPrimByte: 886 case Primitive::kPrimChar: 887 case Primitive::kPrimShort: 888 case Primitive::kPrimInt: 889 case Primitive::kPrimNot: 890 case Primitive::kPrimFloat: 891 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0); 892 break; 893 894 case Primitive::kPrimLong: 895 case Primitive::kPrimDouble: 896 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1); 897 break; 898 899 default: 900 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 901 } 902 } 903 codegen_->GenerateFrameExit(); 904} 905 906void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { 907 HandleInvoke(invoke); 908} 909 910void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) { 911 __ ldr(reg, Address(SP, kCurrentMethodStackOffset)); 912} 913 914void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { 915 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister(); 916 uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>); 917 size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() + 918 invoke->GetIndexInDexCache() * kArmWordSize; 919 920 // TODO: Implement all kinds of calls: 921 // 1) boot -> boot 922 // 2) app -> boot 923 // 3) app -> app 924 // 925 // Currently we implement the app -> app logic, which looks up in the resolve cache. 926 927 // temp = method; 928 LoadCurrentMethod(temp); 929 // temp = temp->dex_cache_resolved_methods_; 930 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); 931 // temp = temp[index_in_cache] 932 __ ldr(temp, Address(temp, index_in_cache)); 933 // LR = temp[offset_of_quick_compiled_code] 934 __ ldr(LR, Address(temp, 935 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); 936 // LR() 937 __ blx(LR); 938 939 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 940 DCHECK(!codegen_->IsLeafMethod()); 941} 942 943void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 944 HandleInvoke(invoke); 945} 946 947void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { 948 LocationSummary* locations = 949 new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); 950 locations->AddTemp(ArmCoreLocation(R0)); 951 952 InvokeDexCallingConventionVisitor calling_convention_visitor; 953 for (size_t i = 0; i < invoke->InputCount(); i++) { 954 HInstruction* input = invoke->InputAt(i); 955 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 956 } 957 958 switch (invoke->GetType()) { 959 case Primitive::kPrimBoolean: 960 case Primitive::kPrimByte: 961 case Primitive::kPrimChar: 962 case Primitive::kPrimShort: 963 case Primitive::kPrimInt: 964 case Primitive::kPrimNot: 965 case Primitive::kPrimFloat: 966 locations->SetOut(ArmCoreLocation(R0)); 967 break; 968 969 case Primitive::kPrimLong: 970 case Primitive::kPrimDouble: 971 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 972 break; 973 974 case Primitive::kPrimVoid: 975 break; 976 } 977} 978 979 980void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) { 981 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister(); 982 uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() + 983 invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry); 984 LocationSummary* locations = invoke->GetLocations(); 985 Location receiver = locations->InAt(0); 986 uint32_t class_offset = mirror::Object::ClassOffset().Int32Value(); 987 // temp = object->GetClass(); 988 if (receiver.IsStackSlot()) { 989 __ ldr(temp, Address(SP, receiver.GetStackIndex())); 990 __ ldr(temp, Address(temp, class_offset)); 991 } else { 992 __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset)); 993 } 994 // temp = temp->GetMethodAt(method_offset); 995 uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value(); 996 __ ldr(temp, Address(temp, method_offset)); 997 // LR = temp->GetEntryPoint(); 998 __ ldr(LR, Address(temp, entry_point)); 999 // LR(); 1000 __ blx(LR); 1001 DCHECK(!codegen_->IsLeafMethod()); 1002 codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); 1003} 1004 1005void LocationsBuilderARM::VisitAdd(HAdd* add) { 1006 LocationSummary* locations = 1007 new (GetGraph()->GetArena()) LocationSummary(add, LocationSummary::kNoCall); 1008 switch (add->GetResultType()) { 1009 case Primitive::kPrimInt: 1010 case Primitive::kPrimLong: { 1011 bool dies_at_entry = add->GetResultType() != Primitive::kPrimLong; 1012 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); 1013 locations->SetInAt(1, Location::RegisterOrConstant(add->InputAt(1)), dies_at_entry); 1014 locations->SetOut(Location::RequiresRegister()); 1015 break; 1016 } 1017 1018 case Primitive::kPrimFloat: 1019 case Primitive::kPrimDouble: { 1020 locations->SetInAt(0, Location::RequiresFpuRegister()); 1021 locations->SetInAt(1, Location::RequiresFpuRegister()); 1022 locations->SetOut(Location::RequiresFpuRegister()); 1023 break; 1024 } 1025 1026 default: 1027 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1028 } 1029} 1030 1031void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 1032 LocationSummary* locations = add->GetLocations(); 1033 switch (add->GetResultType()) { 1034 case Primitive::kPrimInt: 1035 if (locations->InAt(1).IsRegister()) { 1036 __ add(locations->Out().AsArm().AsCoreRegister(), 1037 locations->InAt(0).AsArm().AsCoreRegister(), 1038 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 1039 } else { 1040 __ AddConstant(locations->Out().AsArm().AsCoreRegister(), 1041 locations->InAt(0).AsArm().AsCoreRegister(), 1042 locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()); 1043 } 1044 break; 1045 1046 case Primitive::kPrimLong: 1047 __ adds(locations->Out().AsArm().AsRegisterPairLow(), 1048 locations->InAt(0).AsArm().AsRegisterPairLow(), 1049 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); 1050 __ adc(locations->Out().AsArm().AsRegisterPairHigh(), 1051 locations->InAt(0).AsArm().AsRegisterPairHigh(), 1052 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 1053 break; 1054 1055 case Primitive::kPrimFloat: 1056 __ vadds(locations->Out().AsArm().AsOverlappingDRegisterLow(), 1057 locations->InAt(0).AsArm().AsOverlappingDRegisterLow(), 1058 locations->InAt(1).AsArm().AsOverlappingDRegisterLow()); 1059 break; 1060 1061 case Primitive::kPrimDouble: 1062 __ vaddd(locations->Out().AsArm().AsDRegister(), 1063 locations->InAt(0).AsArm().AsDRegister(), 1064 locations->InAt(1).AsArm().AsDRegister()); 1065 break; 1066 1067 default: 1068 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 1069 } 1070} 1071 1072void LocationsBuilderARM::VisitSub(HSub* sub) { 1073 LocationSummary* locations = 1074 new (GetGraph()->GetArena()) LocationSummary(sub, LocationSummary::kNoCall); 1075 switch (sub->GetResultType()) { 1076 case Primitive::kPrimInt: 1077 case Primitive::kPrimLong: { 1078 bool dies_at_entry = sub->GetResultType() != Primitive::kPrimLong; 1079 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); 1080 locations->SetInAt(1, Location::RegisterOrConstant(sub->InputAt(1)), dies_at_entry); 1081 locations->SetOut(Location::RequiresRegister()); 1082 break; 1083 } 1084 1085 case Primitive::kPrimBoolean: 1086 case Primitive::kPrimByte: 1087 case Primitive::kPrimChar: 1088 case Primitive::kPrimShort: 1089 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1090 break; 1091 1092 default: 1093 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 1094 } 1095} 1096 1097void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { 1098 LocationSummary* locations = sub->GetLocations(); 1099 switch (sub->GetResultType()) { 1100 case Primitive::kPrimInt: { 1101 if (locations->InAt(1).IsRegister()) { 1102 __ sub(locations->Out().AsArm().AsCoreRegister(), 1103 locations->InAt(0).AsArm().AsCoreRegister(), 1104 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 1105 } else { 1106 __ AddConstant(locations->Out().AsArm().AsCoreRegister(), 1107 locations->InAt(0).AsArm().AsCoreRegister(), 1108 -locations->InAt(1).GetConstant()->AsIntConstant()->GetValue()); 1109 } 1110 break; 1111 } 1112 1113 case Primitive::kPrimLong: 1114 __ subs(locations->Out().AsArm().AsRegisterPairLow(), 1115 locations->InAt(0).AsArm().AsRegisterPairLow(), 1116 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); 1117 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(), 1118 locations->InAt(0).AsArm().AsRegisterPairHigh(), 1119 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 1120 break; 1121 1122 case Primitive::kPrimBoolean: 1123 case Primitive::kPrimByte: 1124 case Primitive::kPrimChar: 1125 case Primitive::kPrimShort: 1126 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 1127 break; 1128 1129 default: 1130 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 1131 } 1132} 1133 1134void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 1135 LocationSummary* locations = 1136 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCall); 1137 InvokeRuntimeCallingConvention calling_convention; 1138 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0))); 1139 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1))); 1140 locations->SetOut(ArmCoreLocation(R0)); 1141} 1142 1143void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 1144 InvokeRuntimeCallingConvention calling_convention; 1145 LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 1146 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 1147 1148 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value(); 1149 __ ldr(LR, Address(TR, offset)); 1150 __ blx(LR); 1151 1152 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 1153 DCHECK(!codegen_->IsLeafMethod()); 1154} 1155 1156void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 1157 LocationSummary* locations = 1158 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1159 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 1160 if (location.IsStackSlot()) { 1161 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1162 } else if (location.IsDoubleStackSlot()) { 1163 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 1164 } 1165 locations->SetOut(location); 1166} 1167 1168void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 1169 // Nothing to do, the parameter is already at its location. 1170} 1171 1172void LocationsBuilderARM::VisitNot(HNot* instruction) { 1173 LocationSummary* locations = 1174 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1175 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1176 locations->SetOut(Location::RequiresRegister()); 1177} 1178 1179void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { 1180 LocationSummary* locations = instruction->GetLocations(); 1181 __ eor(locations->Out().AsArm().AsCoreRegister(), 1182 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1)); 1183} 1184 1185void LocationsBuilderARM::VisitCompare(HCompare* compare) { 1186 LocationSummary* locations = 1187 new (GetGraph()->GetArena()) LocationSummary(compare, LocationSummary::kNoCall); 1188 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1189 locations->SetInAt(1, Location::RequiresRegister(), Location::kDiesAtEntry); 1190 locations->SetOut(Location::RequiresRegister()); 1191} 1192 1193void InstructionCodeGeneratorARM::VisitCompare(HCompare* compare) { 1194 Label greater, done; 1195 LocationSummary* locations = compare->GetLocations(); 1196 switch (compare->InputAt(0)->GetType()) { 1197 case Primitive::kPrimLong: { 1198 Register output = locations->Out().AsArm().AsCoreRegister(); 1199 ArmManagedRegister left = locations->InAt(0).AsArm(); 1200 ArmManagedRegister right = locations->InAt(1).AsArm(); 1201 Label less, greater, done; 1202 __ cmp(left.AsRegisterPairHigh(), 1203 ShifterOperand(right.AsRegisterPairHigh())); // Signed compare. 1204 __ b(&less, LT); 1205 __ b(&greater, GT); 1206 // Do LoadImmediate before any `cmp`, as LoadImmediate might affect 1207 // the status flags. 1208 __ LoadImmediate(output, 0); 1209 __ cmp(left.AsRegisterPairLow(), 1210 ShifterOperand(right.AsRegisterPairLow())); // Unsigned compare. 1211 __ b(&done, EQ); 1212 __ b(&less, CC); 1213 1214 __ Bind(&greater); 1215 __ LoadImmediate(output, 1); 1216 __ b(&done); 1217 1218 __ Bind(&less); 1219 __ LoadImmediate(output, -1); 1220 1221 __ Bind(&done); 1222 break; 1223 } 1224 default: 1225 LOG(FATAL) << "Unimplemented compare type " << compare->InputAt(0)->GetType(); 1226 } 1227} 1228 1229void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 1230 LocationSummary* locations = 1231 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1232 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 1233 locations->SetInAt(i, Location::Any()); 1234 } 1235 locations->SetOut(Location::Any()); 1236} 1237 1238void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 1239 LOG(FATAL) << "Unreachable"; 1240} 1241 1242void LocationsBuilderARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1243 LocationSummary* locations = 1244 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1245 bool is_object_type = instruction->GetFieldType() == Primitive::kPrimNot; 1246 bool dies_at_entry = !is_object_type; 1247 locations->SetInAt(0, Location::RequiresRegister(), dies_at_entry); 1248 locations->SetInAt(1, Location::RequiresRegister(), dies_at_entry); 1249 // Temporary registers for the write barrier. 1250 if (is_object_type) { 1251 locations->AddTemp(Location::RequiresRegister()); 1252 locations->AddTemp(Location::RequiresRegister()); 1253 } 1254} 1255 1256void InstructionCodeGeneratorARM::VisitInstanceFieldSet(HInstanceFieldSet* instruction) { 1257 LocationSummary* locations = instruction->GetLocations(); 1258 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1259 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1260 Primitive::Type field_type = instruction->GetFieldType(); 1261 1262 switch (field_type) { 1263 case Primitive::kPrimBoolean: 1264 case Primitive::kPrimByte: { 1265 Register value = locations->InAt(1).AsArm().AsCoreRegister(); 1266 __ StoreToOffset(kStoreByte, value, obj, offset); 1267 break; 1268 } 1269 1270 case Primitive::kPrimShort: 1271 case Primitive::kPrimChar: { 1272 Register value = locations->InAt(1).AsArm().AsCoreRegister(); 1273 __ StoreToOffset(kStoreHalfword, value, obj, offset); 1274 break; 1275 } 1276 1277 case Primitive::kPrimInt: 1278 case Primitive::kPrimNot: { 1279 Register value = locations->InAt(1).AsArm().AsCoreRegister(); 1280 __ StoreToOffset(kStoreWord, value, obj, offset); 1281 if (field_type == Primitive::kPrimNot) { 1282 Register temp = locations->GetTemp(0).AsArm().AsCoreRegister(); 1283 Register card = locations->GetTemp(1).AsArm().AsCoreRegister(); 1284 codegen_->MarkGCCard(temp, card, obj, value); 1285 } 1286 break; 1287 } 1288 1289 case Primitive::kPrimLong: { 1290 ArmManagedRegister value = locations->InAt(1).AsArm(); 1291 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset); 1292 break; 1293 } 1294 1295 case Primitive::kPrimFloat: 1296 case Primitive::kPrimDouble: 1297 LOG(FATAL) << "Unimplemented register type " << field_type; 1298 1299 case Primitive::kPrimVoid: 1300 LOG(FATAL) << "Unreachable type " << field_type; 1301 } 1302} 1303 1304void LocationsBuilderARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 1305 LocationSummary* locations = 1306 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1307 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1308 locations->SetOut(Location::RequiresRegister()); 1309} 1310 1311void InstructionCodeGeneratorARM::VisitInstanceFieldGet(HInstanceFieldGet* instruction) { 1312 LocationSummary* locations = instruction->GetLocations(); 1313 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1314 uint32_t offset = instruction->GetFieldOffset().Uint32Value(); 1315 1316 switch (instruction->GetType()) { 1317 case Primitive::kPrimBoolean: { 1318 Register out = locations->Out().AsArm().AsCoreRegister(); 1319 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 1320 break; 1321 } 1322 1323 case Primitive::kPrimByte: { 1324 Register out = locations->Out().AsArm().AsCoreRegister(); 1325 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 1326 break; 1327 } 1328 1329 case Primitive::kPrimShort: { 1330 Register out = locations->Out().AsArm().AsCoreRegister(); 1331 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 1332 break; 1333 } 1334 1335 case Primitive::kPrimChar: { 1336 Register out = locations->Out().AsArm().AsCoreRegister(); 1337 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 1338 break; 1339 } 1340 1341 case Primitive::kPrimInt: 1342 case Primitive::kPrimNot: { 1343 Register out = locations->Out().AsArm().AsCoreRegister(); 1344 __ LoadFromOffset(kLoadWord, out, obj, offset); 1345 break; 1346 } 1347 1348 case Primitive::kPrimLong: { 1349 // TODO: support volatile. 1350 ArmManagedRegister out = locations->Out().AsArm(); 1351 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset); 1352 break; 1353 } 1354 1355 case Primitive::kPrimFloat: 1356 case Primitive::kPrimDouble: 1357 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1358 1359 case Primitive::kPrimVoid: 1360 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1361 } 1362} 1363 1364void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) { 1365 LocationSummary* locations = 1366 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1367 locations->SetInAt(0, Location::RequiresRegister()); 1368 if (instruction->HasUses()) { 1369 locations->SetOut(Location::SameAsFirstInput()); 1370 } 1371} 1372 1373void InstructionCodeGeneratorARM::VisitNullCheck(HNullCheck* instruction) { 1374 SlowPathCode* slow_path = new (GetGraph()->GetArena()) NullCheckSlowPathARM(instruction); 1375 codegen_->AddSlowPath(slow_path); 1376 1377 LocationSummary* locations = instruction->GetLocations(); 1378 Location obj = locations->InAt(0); 1379 1380 if (obj.IsRegister()) { 1381 __ cmp(obj.AsArm().AsCoreRegister(), ShifterOperand(0)); 1382 __ b(slow_path->GetEntryLabel(), EQ); 1383 } else { 1384 DCHECK(obj.IsConstant()) << obj; 1385 DCHECK_EQ(obj.GetConstant()->AsIntConstant()->GetValue(), 0); 1386 __ b(slow_path->GetEntryLabel()); 1387 } 1388} 1389 1390void LocationsBuilderARM::VisitArrayGet(HArrayGet* instruction) { 1391 LocationSummary* locations = 1392 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1393 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1394 locations->SetInAt( 1395 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); 1396 locations->SetOut(Location::RequiresRegister()); 1397} 1398 1399void InstructionCodeGeneratorARM::VisitArrayGet(HArrayGet* instruction) { 1400 LocationSummary* locations = instruction->GetLocations(); 1401 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1402 Location index = locations->InAt(1); 1403 1404 switch (instruction->GetType()) { 1405 case Primitive::kPrimBoolean: { 1406 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 1407 Register out = locations->Out().AsArm().AsCoreRegister(); 1408 if (index.IsConstant()) { 1409 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1410 __ LoadFromOffset(kLoadUnsignedByte, out, obj, offset); 1411 } else { 1412 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister())); 1413 __ LoadFromOffset(kLoadUnsignedByte, out, IP, data_offset); 1414 } 1415 break; 1416 } 1417 1418 case Primitive::kPrimByte: { 1419 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int8_t)).Uint32Value(); 1420 Register out = locations->Out().AsArm().AsCoreRegister(); 1421 if (index.IsConstant()) { 1422 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1423 __ LoadFromOffset(kLoadSignedByte, out, obj, offset); 1424 } else { 1425 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister())); 1426 __ LoadFromOffset(kLoadSignedByte, out, IP, data_offset); 1427 } 1428 break; 1429 } 1430 1431 case Primitive::kPrimShort: { 1432 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int16_t)).Uint32Value(); 1433 Register out = locations->Out().AsArm().AsCoreRegister(); 1434 if (index.IsConstant()) { 1435 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1436 __ LoadFromOffset(kLoadSignedHalfword, out, obj, offset); 1437 } else { 1438 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2)); 1439 __ LoadFromOffset(kLoadSignedHalfword, out, IP, data_offset); 1440 } 1441 break; 1442 } 1443 1444 case Primitive::kPrimChar: { 1445 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 1446 Register out = locations->Out().AsArm().AsCoreRegister(); 1447 if (index.IsConstant()) { 1448 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1449 __ LoadFromOffset(kLoadUnsignedHalfword, out, obj, offset); 1450 } else { 1451 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2)); 1452 __ LoadFromOffset(kLoadUnsignedHalfword, out, IP, data_offset); 1453 } 1454 break; 1455 } 1456 1457 case Primitive::kPrimInt: 1458 case Primitive::kPrimNot: { 1459 DCHECK_EQ(sizeof(mirror::HeapReference<mirror::Object>), sizeof(int32_t)); 1460 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 1461 Register out = locations->Out().AsArm().AsCoreRegister(); 1462 if (index.IsConstant()) { 1463 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 1464 __ LoadFromOffset(kLoadWord, out, obj, offset); 1465 } else { 1466 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4)); 1467 __ LoadFromOffset(kLoadWord, out, IP, data_offset); 1468 } 1469 break; 1470 } 1471 1472 case Primitive::kPrimLong: { 1473 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 1474 ArmManagedRegister out = locations->Out().AsArm(); 1475 if (index.IsConstant()) { 1476 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 1477 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), obj, offset); 1478 } else { 1479 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8)); 1480 __ LoadFromOffset(kLoadWordPair, out.AsRegisterPairLow(), IP, data_offset); 1481 } 1482 break; 1483 } 1484 1485 case Primitive::kPrimFloat: 1486 case Primitive::kPrimDouble: 1487 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1488 1489 case Primitive::kPrimVoid: 1490 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1491 } 1492} 1493 1494void LocationsBuilderARM::VisitArraySet(HArraySet* instruction) { 1495 Primitive::Type value_type = instruction->GetComponentType(); 1496 bool is_object = value_type == Primitive::kPrimNot; 1497 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary( 1498 instruction, is_object ? LocationSummary::kCall : LocationSummary::kNoCall); 1499 if (is_object) { 1500 InvokeRuntimeCallingConvention calling_convention; 1501 locations->SetInAt(0, ArmCoreLocation(calling_convention.GetRegisterAt(0))); 1502 locations->SetInAt(1, ArmCoreLocation(calling_convention.GetRegisterAt(1))); 1503 locations->SetInAt(2, ArmCoreLocation(calling_convention.GetRegisterAt(2))); 1504 } else { 1505 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1506 locations->SetInAt( 1507 1, Location::RegisterOrConstant(instruction->InputAt(1)), Location::kDiesAtEntry); 1508 locations->SetInAt(2, Location::RequiresRegister(), Location::kDiesAtEntry); 1509 } 1510} 1511 1512void InstructionCodeGeneratorARM::VisitArraySet(HArraySet* instruction) { 1513 LocationSummary* locations = instruction->GetLocations(); 1514 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1515 Location index = locations->InAt(1); 1516 Primitive::Type value_type = instruction->GetComponentType(); 1517 1518 switch (value_type) { 1519 case Primitive::kPrimBoolean: 1520 case Primitive::kPrimByte: { 1521 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint8_t)).Uint32Value(); 1522 Register value = locations->InAt(2).AsArm().AsCoreRegister(); 1523 if (index.IsConstant()) { 1524 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_1) + data_offset; 1525 __ StoreToOffset(kStoreByte, value, obj, offset); 1526 } else { 1527 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister())); 1528 __ StoreToOffset(kStoreByte, value, IP, data_offset); 1529 } 1530 break; 1531 } 1532 1533 case Primitive::kPrimShort: 1534 case Primitive::kPrimChar: { 1535 uint32_t data_offset = mirror::Array::DataOffset(sizeof(uint16_t)).Uint32Value(); 1536 Register value = locations->InAt(2).AsArm().AsCoreRegister(); 1537 if (index.IsConstant()) { 1538 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_2) + data_offset; 1539 __ StoreToOffset(kStoreHalfword, value, obj, offset); 1540 } else { 1541 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_2)); 1542 __ StoreToOffset(kStoreHalfword, value, IP, data_offset); 1543 } 1544 break; 1545 } 1546 1547 case Primitive::kPrimInt: { 1548 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int32_t)).Uint32Value(); 1549 Register value = locations->InAt(2).AsArm().AsCoreRegister(); 1550 if (index.IsConstant()) { 1551 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_4) + data_offset; 1552 __ StoreToOffset(kStoreWord, value, obj, offset); 1553 } else { 1554 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_4)); 1555 __ StoreToOffset(kStoreWord, value, IP, data_offset); 1556 } 1557 break; 1558 } 1559 1560 case Primitive::kPrimNot: { 1561 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAputObject).Int32Value(); 1562 __ ldr(LR, Address(TR, offset)); 1563 __ blx(LR); 1564 codegen_->RecordPcInfo(instruction, instruction->GetDexPc()); 1565 DCHECK(!codegen_->IsLeafMethod()); 1566 break; 1567 } 1568 1569 case Primitive::kPrimLong: { 1570 uint32_t data_offset = mirror::Array::DataOffset(sizeof(int64_t)).Uint32Value(); 1571 ArmManagedRegister value = locations->InAt(2).AsArm(); 1572 if (index.IsConstant()) { 1573 size_t offset = (index.GetConstant()->AsIntConstant()->GetValue() << TIMES_8) + data_offset; 1574 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), obj, offset); 1575 } else { 1576 __ add(IP, obj, ShifterOperand(index.AsArm().AsCoreRegister(), LSL, TIMES_8)); 1577 __ StoreToOffset(kStoreWordPair, value.AsRegisterPairLow(), IP, data_offset); 1578 } 1579 break; 1580 } 1581 1582 case Primitive::kPrimFloat: 1583 case Primitive::kPrimDouble: 1584 LOG(FATAL) << "Unimplemented register type " << instruction->GetType(); 1585 1586 case Primitive::kPrimVoid: 1587 LOG(FATAL) << "Unreachable type " << instruction->GetType(); 1588 } 1589} 1590 1591void LocationsBuilderARM::VisitArrayLength(HArrayLength* instruction) { 1592 LocationSummary* locations = 1593 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1594 locations->SetInAt(0, Location::RequiresRegister(), Location::kDiesAtEntry); 1595 locations->SetOut(Location::RequiresRegister()); 1596} 1597 1598void InstructionCodeGeneratorARM::VisitArrayLength(HArrayLength* instruction) { 1599 LocationSummary* locations = instruction->GetLocations(); 1600 uint32_t offset = mirror::Array::LengthOffset().Uint32Value(); 1601 Register obj = locations->InAt(0).AsArm().AsCoreRegister(); 1602 Register out = locations->Out().AsArm().AsCoreRegister(); 1603 __ LoadFromOffset(kLoadWord, out, obj, offset); 1604} 1605 1606void LocationsBuilderARM::VisitBoundsCheck(HBoundsCheck* instruction) { 1607 LocationSummary* locations = 1608 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); 1609 locations->SetInAt(0, Location::RequiresRegister()); 1610 locations->SetInAt(1, Location::RequiresRegister()); 1611 if (instruction->HasUses()) { 1612 locations->SetOut(Location::SameAsFirstInput()); 1613 } 1614} 1615 1616void InstructionCodeGeneratorARM::VisitBoundsCheck(HBoundsCheck* instruction) { 1617 LocationSummary* locations = instruction->GetLocations(); 1618 SlowPathCode* slow_path = new (GetGraph()->GetArena()) BoundsCheckSlowPathARM( 1619 instruction, locations->InAt(0), locations->InAt(1)); 1620 codegen_->AddSlowPath(slow_path); 1621 1622 Register index = locations->InAt(0).AsArm().AsCoreRegister(); 1623 Register length = locations->InAt(1).AsArm().AsCoreRegister(); 1624 1625 __ cmp(index, ShifterOperand(length)); 1626 __ b(slow_path->GetEntryLabel(), CS); 1627} 1628 1629void CodeGeneratorARM::MarkGCCard(Register temp, Register card, Register object, Register value) { 1630 Label is_null; 1631 __ CompareAndBranchIfZero(value, &is_null); 1632 __ LoadFromOffset(kLoadWord, card, TR, Thread::CardTableOffset<kArmWordSize>().Int32Value()); 1633 __ Lsr(temp, object, gc::accounting::CardTable::kCardShift); 1634 __ strb(card, Address(card, temp)); 1635 __ Bind(&is_null); 1636} 1637 1638void LocationsBuilderARM::VisitTemporary(HTemporary* temp) { 1639 temp->SetLocations(nullptr); 1640} 1641 1642void InstructionCodeGeneratorARM::VisitTemporary(HTemporary* temp) { 1643 // Nothing to do, this is driven by the code generator. 1644} 1645 1646void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) { 1647 LOG(FATAL) << "Unreachable"; 1648} 1649 1650void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) { 1651 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 1652} 1653 1654void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) { 1655 new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath); 1656} 1657 1658void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) { 1659 HBasicBlock* block = instruction->GetBlock(); 1660 if (block->GetLoopInformation() != nullptr) { 1661 DCHECK(block->GetLoopInformation()->GetSuspendCheck() == instruction); 1662 // The back edge will generate the suspend check. 1663 return; 1664 } 1665 if (block->IsEntryBlock() && instruction->GetNext()->IsGoto()) { 1666 // The goto will generate the suspend check. 1667 return; 1668 } 1669 GenerateSuspendCheck(instruction, nullptr); 1670} 1671 1672void InstructionCodeGeneratorARM::GenerateSuspendCheck(HSuspendCheck* instruction, 1673 HBasicBlock* successor) { 1674 SuspendCheckSlowPathARM* slow_path = 1675 new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction, successor); 1676 codegen_->AddSlowPath(slow_path); 1677 1678 __ subs(R4, R4, ShifterOperand(1)); 1679 if (successor == nullptr) { 1680 __ b(slow_path->GetEntryLabel(), EQ); 1681 __ Bind(slow_path->GetReturnLabel()); 1682 } else { 1683 __ b(codegen_->GetLabelOf(successor), NE); 1684 __ b(slow_path->GetEntryLabel()); 1685 } 1686} 1687 1688ArmAssembler* ParallelMoveResolverARM::GetAssembler() const { 1689 return codegen_->GetAssembler(); 1690} 1691 1692void ParallelMoveResolverARM::EmitMove(size_t index) { 1693 MoveOperands* move = moves_.Get(index); 1694 Location source = move->GetSource(); 1695 Location destination = move->GetDestination(); 1696 1697 if (source.IsRegister()) { 1698 if (destination.IsRegister()) { 1699 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister()); 1700 } else { 1701 DCHECK(destination.IsStackSlot()); 1702 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(), 1703 SP, destination.GetStackIndex()); 1704 } 1705 } else if (source.IsStackSlot()) { 1706 if (destination.IsRegister()) { 1707 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(), 1708 SP, source.GetStackIndex()); 1709 } else { 1710 DCHECK(destination.IsStackSlot()); 1711 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 1712 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 1713 } 1714 } else { 1715 DCHECK(source.IsConstant()); 1716 DCHECK(source.GetConstant()->AsIntConstant() != nullptr); 1717 int32_t value = source.GetConstant()->AsIntConstant()->GetValue(); 1718 if (destination.IsRegister()) { 1719 __ LoadImmediate(destination.AsArm().AsCoreRegister(), value); 1720 } else { 1721 DCHECK(destination.IsStackSlot()); 1722 __ LoadImmediate(IP, value); 1723 __ str(IP, Address(SP, destination.GetStackIndex())); 1724 } 1725 } 1726} 1727 1728void ParallelMoveResolverARM::Exchange(Register reg, int mem) { 1729 __ Mov(IP, reg); 1730 __ LoadFromOffset(kLoadWord, reg, SP, mem); 1731 __ StoreToOffset(kStoreWord, IP, SP, mem); 1732} 1733 1734void ParallelMoveResolverARM::Exchange(int mem1, int mem2) { 1735 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters()); 1736 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; 1737 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()), 1738 SP, mem1 + stack_offset); 1739 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset); 1740 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()), 1741 SP, mem2 + stack_offset); 1742 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset); 1743} 1744 1745void ParallelMoveResolverARM::EmitSwap(size_t index) { 1746 MoveOperands* move = moves_.Get(index); 1747 Location source = move->GetSource(); 1748 Location destination = move->GetDestination(); 1749 1750 if (source.IsRegister() && destination.IsRegister()) { 1751 DCHECK_NE(source.AsArm().AsCoreRegister(), IP); 1752 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP); 1753 __ Mov(IP, source.AsArm().AsCoreRegister()); 1754 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister()); 1755 __ Mov(destination.AsArm().AsCoreRegister(), IP); 1756 } else if (source.IsRegister() && destination.IsStackSlot()) { 1757 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex()); 1758 } else if (source.IsStackSlot() && destination.IsRegister()) { 1759 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex()); 1760 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 1761 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 1762 } else { 1763 LOG(FATAL) << "Unimplemented"; 1764 } 1765} 1766 1767void ParallelMoveResolverARM::SpillScratch(int reg) { 1768 __ Push(static_cast<Register>(reg)); 1769} 1770 1771void ParallelMoveResolverARM::RestoreScratch(int reg) { 1772 __ Pop(static_cast<Register>(reg)); 1773} 1774 1775} // namespace arm 1776} // namespace art 1777