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