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