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