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