code_generator_arm.cc revision 20dfc797dc631bf8d655dcf123f46f13332d3074
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17#include "code_generator_arm.h" 18 19#include "entrypoints/quick/quick_entrypoints.h" 20#include "mirror/array.h" 21#include "mirror/art_method.h" 22#include "thread.h" 23#include "utils/assembler.h" 24#include "utils/arm/assembler_arm.h" 25#include "utils/arm/managed_register_arm.h" 26 27#define __ reinterpret_cast<ArmAssembler*>(GetAssembler())-> 28 29namespace art { 30 31arm::ArmManagedRegister Location::AsArm() const { 32 return reg().AsArm(); 33} 34 35namespace arm { 36 37 38inline Condition ARMCondition(IfCondition cond) { 39 switch (cond) { 40 case kCondEQ: return EQ; 41 case kCondNE: return NE; 42 case kCondLT: return LT; 43 case kCondLE: return LE; 44 case kCondGT: return GT; 45 case kCondGE: return GE; 46 default: 47 LOG(FATAL) << "Unknown if condition"; 48 } 49 return EQ; // Unreachable. 50} 51 52inline Condition ARMOppositeCondition(IfCondition cond) { 53 switch (cond) { 54 case kCondEQ: return NE; 55 case kCondNE: return EQ; 56 case kCondLT: return GE; 57 case kCondLE: return GT; 58 case kCondGT: return LE; 59 case kCondGE: return LT; 60 default: 61 LOG(FATAL) << "Unknown if condition"; 62 } 63 return EQ; // Unreachable. 64} 65 66static constexpr int kNumberOfPushedRegistersAtEntry = 1; 67static constexpr int kCurrentMethodStackOffset = 0; 68 69void CodeGeneratorARM::DumpCoreRegister(std::ostream& stream, int reg) const { 70 stream << ArmManagedRegister::FromCoreRegister(Register(reg)); 71} 72 73void CodeGeneratorARM::DumpFloatingPointRegister(std::ostream& stream, int reg) const { 74 stream << ArmManagedRegister::FromDRegister(DRegister(reg)); 75} 76 77CodeGeneratorARM::CodeGeneratorARM(HGraph* graph) 78 : CodeGenerator(graph, kNumberOfRegIds), 79 location_builder_(graph, this), 80 instruction_visitor_(graph, this), 81 move_resolver_(graph->GetArena(), this) {} 82 83static bool* GetBlockedRegisterPairs(bool* blocked_registers) { 84 return blocked_registers + kNumberOfAllocIds; 85} 86 87ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type, 88 bool* blocked_registers) const { 89 switch (type) { 90 case Primitive::kPrimLong: { 91 size_t reg = AllocateFreeRegisterInternal( 92 GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs); 93 ArmManagedRegister pair = 94 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg)); 95 blocked_registers[pair.AsRegisterPairLow()] = true; 96 blocked_registers[pair.AsRegisterPairHigh()] = true; 97 return pair; 98 } 99 100 case Primitive::kPrimByte: 101 case Primitive::kPrimBoolean: 102 case Primitive::kPrimChar: 103 case Primitive::kPrimShort: 104 case Primitive::kPrimInt: 105 case Primitive::kPrimNot: { 106 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters); 107 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg)); 108 } 109 110 case Primitive::kPrimFloat: 111 case Primitive::kPrimDouble: 112 LOG(FATAL) << "Unimplemented register type " << type; 113 114 case Primitive::kPrimVoid: 115 LOG(FATAL) << "Unreachable type " << type; 116 } 117 118 return ManagedRegister::NoRegister(); 119} 120 121void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const { 122 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers); 123 124 // Don't allocate the dalvik style register pair passing. 125 blocked_register_pairs[R1_R2] = true; 126 127 // Stack register, LR and PC are always reserved. 128 blocked_registers[SP] = true; 129 blocked_registers[LR] = true; 130 blocked_registers[PC] = true; 131 132 // Reserve R4 for suspend check. 133 blocked_registers[R4] = true; 134 blocked_register_pairs[R4_R5] = true; 135 136 // Reserve thread register. 137 blocked_registers[TR] = true; 138 139 // Reserve temp register. 140 blocked_registers[IP] = true; 141 142 // TODO: We currently don't use Quick's callee saved registers. 143 blocked_registers[R5] = true; 144 blocked_registers[R6] = true; 145 blocked_registers[R7] = true; 146 blocked_registers[R8] = true; 147 blocked_registers[R10] = true; 148 blocked_registers[R11] = true; 149 blocked_register_pairs[R6_R7] = true; 150} 151 152size_t CodeGeneratorARM::GetNumberOfRegisters() const { 153 return kNumberOfRegIds; 154} 155 156static Location ArmCoreLocation(Register reg) { 157 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg)); 158} 159 160InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) 161 : HGraphVisitor(graph), 162 assembler_(codegen->GetAssembler()), 163 codegen_(codegen) {} 164 165void CodeGeneratorARM::ComputeFrameSize(size_t number_of_spill_slots) { 166 SetFrameSize(RoundUp( 167 number_of_spill_slots * kVRegSize 168 + kVRegSize // Art method 169 + kNumberOfPushedRegistersAtEntry * kArmWordSize, 170 kStackAlignment)); 171} 172 173void CodeGeneratorARM::GenerateFrameEntry() { 174 core_spill_mask_ |= (1 << LR); 175 __ PushList((1 << LR)); 176 177 // The return PC has already been pushed on the stack. 178 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize)); 179 __ str(R0, Address(SP, 0)); 180} 181 182void CodeGeneratorARM::GenerateFrameExit() { 183 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize); 184 __ PopList((1 << PC)); 185} 186 187void CodeGeneratorARM::Bind(Label* label) { 188 __ Bind(label); 189} 190 191int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const { 192 uint16_t reg_number = local->GetRegNumber(); 193 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); 194 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); 195 if (reg_number >= number_of_vregs - number_of_in_vregs) { 196 // Local is a parameter of the method. It is stored in the caller's frame. 197 return GetFrameSize() + kVRegSize // ART method 198 + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize; 199 } else { 200 // Local is a temporary in this method. It is stored in this method's frame. 201 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize) 202 - kVRegSize // filler. 203 - (number_of_vregs * kVRegSize) 204 + (reg_number * kVRegSize); 205 } 206} 207 208Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const { 209 switch (load->GetType()) { 210 case Primitive::kPrimLong: 211 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 212 break; 213 214 case Primitive::kPrimInt: 215 case Primitive::kPrimNot: 216 return Location::StackSlot(GetStackSlot(load->GetLocal())); 217 218 case Primitive::kPrimFloat: 219 case Primitive::kPrimDouble: 220 LOG(FATAL) << "Unimplemented type " << load->GetType(); 221 222 case Primitive::kPrimBoolean: 223 case Primitive::kPrimByte: 224 case Primitive::kPrimChar: 225 case Primitive::kPrimShort: 226 case Primitive::kPrimVoid: 227 LOG(FATAL) << "Unexpected type " << load->GetType(); 228 } 229 230 LOG(FATAL) << "Unreachable"; 231 return Location(); 232} 233 234Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { 235 switch (type) { 236 case Primitive::kPrimBoolean: 237 case Primitive::kPrimByte: 238 case Primitive::kPrimChar: 239 case Primitive::kPrimShort: 240 case Primitive::kPrimInt: 241 case Primitive::kPrimNot: { 242 uint32_t index = gp_index_++; 243 if (index < calling_convention.GetNumberOfRegisters()) { 244 return ArmCoreLocation(calling_convention.GetRegisterAt(index)); 245 } else { 246 return Location::StackSlot(calling_convention.GetStackOffsetOf(index)); 247 } 248 } 249 250 case Primitive::kPrimLong: { 251 uint32_t index = gp_index_; 252 gp_index_ += 2; 253 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 254 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair( 255 calling_convention.GetRegisterPairAt(index))); 256 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { 257 return Location::QuickParameter(index); 258 } else { 259 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index)); 260 } 261 } 262 263 case Primitive::kPrimDouble: 264 case Primitive::kPrimFloat: 265 LOG(FATAL) << "Unimplemented parameter type " << type; 266 break; 267 268 case Primitive::kPrimVoid: 269 LOG(FATAL) << "Unexpected parameter type " << type; 270 break; 271 } 272 return Location(); 273} 274 275void CodeGeneratorARM::Move32(Location destination, Location source) { 276 if (source.Equals(destination)) { 277 return; 278 } 279 if (destination.IsRegister()) { 280 if (source.IsRegister()) { 281 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister()); 282 } else { 283 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex())); 284 } 285 } else { 286 DCHECK(destination.IsStackSlot()); 287 if (source.IsRegister()) { 288 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex())); 289 } else { 290 __ ldr(IP, Address(SP, source.GetStackIndex())); 291 __ str(IP, Address(SP, destination.GetStackIndex())); 292 } 293 } 294} 295 296void CodeGeneratorARM::Move64(Location destination, Location source) { 297 if (source.Equals(destination)) { 298 return; 299 } 300 if (destination.IsRegister()) { 301 if (source.IsRegister()) { 302 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow()); 303 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh()); 304 } else if (source.IsQuickParameter()) { 305 uint32_t argument_index = source.GetQuickParameterIndex(); 306 InvokeDexCallingConvention calling_convention; 307 __ Mov(destination.AsArm().AsRegisterPairLow(), 308 calling_convention.GetRegisterAt(argument_index)); 309 __ ldr(destination.AsArm().AsRegisterPairHigh(), 310 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize())); 311 } else { 312 DCHECK(source.IsDoubleStackSlot()); 313 if (destination.AsArm().AsRegisterPair() == R1_R2) { 314 __ ldr(R1, Address(SP, source.GetStackIndex())); 315 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize))); 316 } else { 317 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(), 318 SP, source.GetStackIndex()); 319 } 320 } 321 } else if (destination.IsQuickParameter()) { 322 InvokeDexCallingConvention calling_convention; 323 uint32_t argument_index = destination.GetQuickParameterIndex(); 324 if (source.IsRegister()) { 325 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow()); 326 __ str(source.AsArm().AsRegisterPairHigh(), 327 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1))); 328 } else { 329 DCHECK(source.IsDoubleStackSlot()); 330 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex())); 331 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize))); 332 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1))); 333 } 334 } else { 335 DCHECK(destination.IsDoubleStackSlot()); 336 if (source.IsRegister()) { 337 if (source.AsArm().AsRegisterPair() == R1_R2) { 338 __ str(R1, Address(SP, destination.GetStackIndex())); 339 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 340 } else { 341 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(), 342 SP, destination.GetStackIndex()); 343 } 344 } else if (source.IsQuickParameter()) { 345 InvokeDexCallingConvention calling_convention; 346 uint32_t argument_index = source.GetQuickParameterIndex(); 347 __ str(calling_convention.GetRegisterAt(argument_index), 348 Address(SP, destination.GetStackIndex())); 349 __ ldr(R0, 350 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1) + GetFrameSize())); 351 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 352 } else { 353 DCHECK(source.IsDoubleStackSlot()); 354 __ ldr(IP, Address(SP, source.GetStackIndex())); 355 __ str(IP, Address(SP, destination.GetStackIndex())); 356 __ ldr(IP, Address(SP, source.GetHighStackIndex(kArmWordSize))); 357 __ str(IP, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 358 } 359 } 360} 361 362void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 363 if (instruction->AsIntConstant() != nullptr) { 364 int32_t value = instruction->AsIntConstant()->GetValue(); 365 if (location.IsRegister()) { 366 __ LoadImmediate(location.AsArm().AsCoreRegister(), value); 367 } else { 368 __ LoadImmediate(IP, value); 369 __ str(IP, Address(SP, location.GetStackIndex())); 370 } 371 } else if (instruction->AsLongConstant() != nullptr) { 372 int64_t value = instruction->AsLongConstant()->GetValue(); 373 if (location.IsRegister()) { 374 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value)); 375 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value)); 376 } else { 377 __ LoadImmediate(IP, Low32Bits(value)); 378 __ str(IP, Address(SP, location.GetStackIndex())); 379 __ LoadImmediate(IP, High32Bits(value)); 380 __ str(IP, Address(SP, location.GetHighStackIndex(kArmWordSize))); 381 } 382 } else if (instruction->AsLoadLocal() != nullptr) { 383 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 384 switch (instruction->GetType()) { 385 case Primitive::kPrimBoolean: 386 case Primitive::kPrimByte: 387 case Primitive::kPrimChar: 388 case Primitive::kPrimShort: 389 case Primitive::kPrimInt: 390 case Primitive::kPrimNot: 391 Move32(location, Location::StackSlot(stack_slot)); 392 break; 393 394 case Primitive::kPrimLong: 395 Move64(location, Location::DoubleStackSlot(stack_slot)); 396 break; 397 398 default: 399 LOG(FATAL) << "Unimplemented type " << instruction->GetType(); 400 } 401 } else { 402 // This can currently only happen when the instruction that requests the move 403 // is the next to be compiled. 404 DCHECK_EQ(instruction->GetNext(), move_for); 405 switch (instruction->GetType()) { 406 case Primitive::kPrimBoolean: 407 case Primitive::kPrimByte: 408 case Primitive::kPrimChar: 409 case Primitive::kPrimShort: 410 case Primitive::kPrimNot: 411 case Primitive::kPrimInt: 412 Move32(location, instruction->GetLocations()->Out()); 413 break; 414 415 case Primitive::kPrimLong: 416 Move64(location, instruction->GetLocations()->Out()); 417 break; 418 419 default: 420 LOG(FATAL) << "Unimplemented type " << instruction->GetType(); 421 } 422 } 423} 424 425void LocationsBuilderARM::VisitGoto(HGoto* got) { 426 got->SetLocations(nullptr); 427} 428 429void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { 430 HBasicBlock* successor = got->GetSuccessor(); 431 if (GetGraph()->GetExitBlock() == successor) { 432 codegen_->GenerateFrameExit(); 433 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 434 __ b(codegen_->GetLabelOf(successor)); 435 } 436} 437 438void LocationsBuilderARM::VisitExit(HExit* exit) { 439 exit->SetLocations(nullptr); 440} 441 442void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { 443 if (kIsDebugBuild) { 444 __ Comment("Unreachable"); 445 __ bkpt(0); 446 } 447} 448 449void LocationsBuilderARM::VisitIf(HIf* if_instr) { 450 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); 451 locations->SetInAt(0, Location::Any()); 452 if_instr->SetLocations(locations); 453} 454 455void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 456 HInstruction* cond = if_instr->InputAt(0); 457 DCHECK(cond->IsCondition()); 458 HCondition* condition = cond->AsCondition(); 459 if (condition->NeedsMaterialization()) { 460 // Condition has been materialized, compare the output to 0 461 if (!if_instr->GetLocations()->InAt(0).IsRegister()) { 462 LOG(FATAL) << "Materialized condition is not in an ARM register"; 463 } 464 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), 465 ShifterOperand(0)); 466 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), EQ); 467 } else { 468 // Condition has not been materialized, use its inputs as the comparison and its 469 // condition as the branch condition. 470 __ cmp(condition->GetLocations()->InAt(0).AsArm().AsCoreRegister(), 471 ShifterOperand(condition->GetLocations()->InAt(1).AsArm().AsCoreRegister())); 472 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor()), 473 ARMCondition(condition->GetCondition())); 474 } 475 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfFalseSuccessor())) { 476 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor())); 477 } 478} 479 480 481void LocationsBuilderARM::VisitCondition(HCondition* comp) { 482 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(comp); 483 locations->SetInAt(0, Location::RequiresRegister()); 484 locations->SetInAt(1, Location::RequiresRegister()); 485 locations->SetOut(Location::RequiresRegister()); 486 comp->SetLocations(locations); 487} 488 489void InstructionCodeGeneratorARM::VisitCondition(HCondition* comp) { 490 if (comp->NeedsMaterialization()) { 491 LocationSummary* locations = comp->GetLocations(); 492 __ cmp(locations->InAt(0).AsArm().AsCoreRegister(), 493 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 494 __ it(ARMCondition(comp->GetCondition()), kItElse); 495 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), 496 ARMCondition(comp->GetCondition())); 497 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), 498 ARMOppositeCondition(comp->GetCondition())); 499 } 500} 501 502void LocationsBuilderARM::VisitEqual(HEqual* comp) { 503 VisitCondition(comp); 504} 505 506void InstructionCodeGeneratorARM::VisitEqual(HEqual* comp) { 507 VisitCondition(comp); 508} 509 510void LocationsBuilderARM::VisitNotEqual(HNotEqual* comp) { 511 VisitCondition(comp); 512} 513 514void InstructionCodeGeneratorARM::VisitNotEqual(HNotEqual* comp) { 515 VisitCondition(comp); 516} 517 518void LocationsBuilderARM::VisitLessThan(HLessThan* comp) { 519 VisitCondition(comp); 520} 521 522void InstructionCodeGeneratorARM::VisitLessThan(HLessThan* comp) { 523 VisitCondition(comp); 524} 525 526void LocationsBuilderARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 527 VisitCondition(comp); 528} 529 530void InstructionCodeGeneratorARM::VisitLessThanOrEqual(HLessThanOrEqual* comp) { 531 VisitCondition(comp); 532} 533 534void LocationsBuilderARM::VisitGreaterThan(HGreaterThan* comp) { 535 VisitCondition(comp); 536} 537 538void InstructionCodeGeneratorARM::VisitGreaterThan(HGreaterThan* comp) { 539 VisitCondition(comp); 540} 541 542void LocationsBuilderARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 543 VisitCondition(comp); 544} 545 546void InstructionCodeGeneratorARM::VisitGreaterThanOrEqual(HGreaterThanOrEqual* comp) { 547 VisitCondition(comp); 548} 549 550void LocationsBuilderARM::VisitLocal(HLocal* local) { 551 local->SetLocations(nullptr); 552} 553 554void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 555 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 556} 557 558void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 559 load->SetLocations(nullptr); 560} 561 562void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 563 // Nothing to do, this is driven by the code generator. 564} 565 566void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 567 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store); 568 switch (store->InputAt(1)->GetType()) { 569 case Primitive::kPrimBoolean: 570 case Primitive::kPrimByte: 571 case Primitive::kPrimChar: 572 case Primitive::kPrimShort: 573 case Primitive::kPrimInt: 574 case Primitive::kPrimNot: 575 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 576 break; 577 578 case Primitive::kPrimLong: 579 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 580 break; 581 582 default: 583 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType(); 584 } 585 store->SetLocations(locations); 586} 587 588void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 589} 590 591void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 592 // TODO: Support constant locations. 593 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant); 594 locations->SetOut(Location::RequiresRegister()); 595 constant->SetLocations(locations); 596} 597 598void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 599 codegen_->Move(constant, constant->GetLocations()->Out(), nullptr); 600} 601 602void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { 603 // TODO: Support constant locations. 604 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(constant); 605 locations->SetOut(Location::RequiresRegister()); 606 constant->SetLocations(locations); 607} 608 609void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { 610 // Will be generated at use site. 611} 612 613void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 614 ret->SetLocations(nullptr); 615} 616 617void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 618 codegen_->GenerateFrameExit(); 619} 620 621void LocationsBuilderARM::VisitReturn(HReturn* ret) { 622 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret); 623 switch (ret->InputAt(0)->GetType()) { 624 case Primitive::kPrimBoolean: 625 case Primitive::kPrimByte: 626 case Primitive::kPrimChar: 627 case Primitive::kPrimShort: 628 case Primitive::kPrimInt: 629 case Primitive::kPrimNot: 630 locations->SetInAt(0, ArmCoreLocation(R0)); 631 break; 632 633 case Primitive::kPrimLong: 634 locations->SetInAt( 635 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 636 break; 637 638 default: 639 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 640 } 641 642 ret->SetLocations(locations); 643} 644 645void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 646 if (kIsDebugBuild) { 647 switch (ret->InputAt(0)->GetType()) { 648 case Primitive::kPrimBoolean: 649 case Primitive::kPrimByte: 650 case Primitive::kPrimChar: 651 case Primitive::kPrimShort: 652 case Primitive::kPrimInt: 653 case Primitive::kPrimNot: 654 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0); 655 break; 656 657 case Primitive::kPrimLong: 658 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1); 659 break; 660 661 default: 662 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 663 } 664 } 665 codegen_->GenerateFrameExit(); 666} 667 668void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { 669 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); 670 locations->AddTemp(ArmCoreLocation(R0)); 671 672 InvokeDexCallingConventionVisitor calling_convention_visitor; 673 for (size_t i = 0; i < invoke->InputCount(); i++) { 674 HInstruction* input = invoke->InputAt(i); 675 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 676 } 677 678 switch (invoke->GetType()) { 679 case Primitive::kPrimBoolean: 680 case Primitive::kPrimByte: 681 case Primitive::kPrimChar: 682 case Primitive::kPrimShort: 683 case Primitive::kPrimInt: 684 case Primitive::kPrimNot: 685 locations->SetOut(ArmCoreLocation(R0)); 686 break; 687 688 case Primitive::kPrimLong: 689 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 690 break; 691 692 case Primitive::kPrimVoid: 693 break; 694 695 case Primitive::kPrimDouble: 696 case Primitive::kPrimFloat: 697 LOG(FATAL) << "Unimplemented return type " << invoke->GetType(); 698 break; 699 } 700 701 invoke->SetLocations(locations); 702} 703 704void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) { 705 __ ldr(reg, Address(SP, kCurrentMethodStackOffset)); 706} 707 708void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { 709 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister(); 710 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + 711 invoke->GetIndexInDexCache() * kArmWordSize; 712 713 // TODO: Implement all kinds of calls: 714 // 1) boot -> boot 715 // 2) app -> boot 716 // 3) app -> app 717 // 718 // Currently we implement the app -> app logic, which looks up in the resolve cache. 719 720 // temp = method; 721 LoadCurrentMethod(temp); 722 // temp = temp->dex_cache_resolved_methods_; 723 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); 724 // temp = temp[index_in_cache] 725 __ ldr(temp, Address(temp, index_in_cache)); 726 // LR = temp[offset_of_quick_compiled_code] 727 __ ldr(LR, Address(temp, 728 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); 729 // LR() 730 __ blx(LR); 731 732 codegen_->RecordPcInfo(invoke->GetDexPc()); 733} 734 735void LocationsBuilderARM::VisitAdd(HAdd* add) { 736 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); 737 switch (add->GetResultType()) { 738 case Primitive::kPrimInt: 739 case Primitive::kPrimLong: { 740 locations->SetInAt(0, Location::RequiresRegister()); 741 locations->SetInAt(1, Location::RequiresRegister()); 742 locations->SetOut(Location::RequiresRegister()); 743 break; 744 } 745 746 case Primitive::kPrimBoolean: 747 case Primitive::kPrimByte: 748 case Primitive::kPrimChar: 749 case Primitive::kPrimShort: 750 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 751 break; 752 753 default: 754 LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); 755 } 756 add->SetLocations(locations); 757} 758 759void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 760 LocationSummary* locations = add->GetLocations(); 761 switch (add->GetResultType()) { 762 case Primitive::kPrimInt: 763 __ add(locations->Out().AsArm().AsCoreRegister(), 764 locations->InAt(0).AsArm().AsCoreRegister(), 765 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 766 break; 767 768 case Primitive::kPrimLong: 769 __ adds(locations->Out().AsArm().AsRegisterPairLow(), 770 locations->InAt(0).AsArm().AsRegisterPairLow(), 771 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); 772 __ adc(locations->Out().AsArm().AsRegisterPairHigh(), 773 locations->InAt(0).AsArm().AsRegisterPairHigh(), 774 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 775 break; 776 777 case Primitive::kPrimBoolean: 778 case Primitive::kPrimByte: 779 case Primitive::kPrimChar: 780 case Primitive::kPrimShort: 781 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 782 break; 783 784 default: 785 LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); 786 } 787} 788 789void LocationsBuilderARM::VisitSub(HSub* sub) { 790 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub); 791 switch (sub->GetResultType()) { 792 case Primitive::kPrimInt: 793 case Primitive::kPrimLong: { 794 locations->SetInAt(0, Location::RequiresRegister()); 795 locations->SetInAt(1, Location::RequiresRegister()); 796 locations->SetOut(Location::RequiresRegister()); 797 break; 798 } 799 800 case Primitive::kPrimBoolean: 801 case Primitive::kPrimByte: 802 case Primitive::kPrimChar: 803 case Primitive::kPrimShort: 804 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 805 break; 806 807 default: 808 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 809 } 810 sub->SetLocations(locations); 811} 812 813void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { 814 LocationSummary* locations = sub->GetLocations(); 815 switch (sub->GetResultType()) { 816 case Primitive::kPrimInt: 817 __ sub(locations->Out().AsArm().AsCoreRegister(), 818 locations->InAt(0).AsArm().AsCoreRegister(), 819 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 820 break; 821 822 case Primitive::kPrimLong: 823 __ subs(locations->Out().AsArm().AsRegisterPairLow(), 824 locations->InAt(0).AsArm().AsRegisterPairLow(), 825 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); 826 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(), 827 locations->InAt(0).AsArm().AsRegisterPairHigh(), 828 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 829 break; 830 831 case Primitive::kPrimBoolean: 832 case Primitive::kPrimByte: 833 case Primitive::kPrimChar: 834 case Primitive::kPrimShort: 835 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 836 break; 837 838 default: 839 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 840 } 841} 842 843static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 }; 844static constexpr size_t kRuntimeParameterCoreRegistersLength = 845 arraysize(kRuntimeParameterCoreRegisters); 846 847class InvokeRuntimeCallingConvention : public CallingConvention<Register> { 848 public: 849 InvokeRuntimeCallingConvention() 850 : CallingConvention(kRuntimeParameterCoreRegisters, 851 kRuntimeParameterCoreRegistersLength) {} 852 853 private: 854 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 855}; 856 857void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 858 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 859 InvokeRuntimeCallingConvention calling_convention; 860 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0))); 861 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1))); 862 locations->SetOut(ArmCoreLocation(R0)); 863 instruction->SetLocations(locations); 864} 865 866void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 867 InvokeRuntimeCallingConvention calling_convention; 868 LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 869 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 870 871 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value(); 872 __ ldr(LR, Address(TR, offset)); 873 __ blx(LR); 874 875 codegen_->RecordPcInfo(instruction->GetDexPc()); 876} 877 878void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 879 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 880 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 881 if (location.IsStackSlot()) { 882 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 883 } else if (location.IsDoubleStackSlot()) { 884 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 885 } 886 locations->SetOut(location); 887 instruction->SetLocations(locations); 888} 889 890void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 891 // Nothing to do, the parameter is already at its location. 892} 893 894void LocationsBuilderARM::VisitNot(HNot* instruction) { 895 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 896 locations->SetInAt(0, Location::RequiresRegister()); 897 locations->SetOut(Location::RequiresRegister()); 898 instruction->SetLocations(locations); 899} 900 901void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { 902 LocationSummary* locations = instruction->GetLocations(); 903 __ eor(locations->Out().AsArm().AsCoreRegister(), 904 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1)); 905} 906 907void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 908 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 909 for (size_t i = 0, e = instruction->InputCount(); i < e; ++i) { 910 locations->SetInAt(i, Location::Any()); 911 } 912 locations->SetOut(Location::Any()); 913 instruction->SetLocations(locations); 914} 915 916void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 917 LOG(FATAL) << "Unreachable"; 918} 919 920void LocationsBuilderARM::VisitParallelMove(HParallelMove* instruction) { 921 LOG(FATAL) << "Unreachable"; 922} 923 924void InstructionCodeGeneratorARM::VisitParallelMove(HParallelMove* instruction) { 925 codegen_->GetMoveResolver()->EmitNativeCode(instruction); 926} 927 928ArmAssembler* ParallelMoveResolverARM::GetAssembler() const { 929 return codegen_->GetAssembler(); 930} 931 932void ParallelMoveResolverARM::EmitMove(size_t index) { 933 MoveOperands* move = moves_.Get(index); 934 Location source = move->GetSource(); 935 Location destination = move->GetDestination(); 936 937 if (source.IsRegister()) { 938 if (destination.IsRegister()) { 939 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister()); 940 } else { 941 DCHECK(destination.IsStackSlot()); 942 __ StoreToOffset(kStoreWord, source.AsArm().AsCoreRegister(), 943 SP, destination.GetStackIndex()); 944 } 945 } else if (source.IsStackSlot()) { 946 if (destination.IsRegister()) { 947 __ LoadFromOffset(kLoadWord, destination.AsArm().AsCoreRegister(), 948 SP, source.GetStackIndex()); 949 } else { 950 DCHECK(destination.IsStackSlot()); 951 __ LoadFromOffset(kLoadWord, IP, SP, source.GetStackIndex()); 952 __ StoreToOffset(kStoreWord, IP, SP, destination.GetStackIndex()); 953 } 954 } else { 955 LOG(FATAL) << "Unimplemented"; 956 } 957} 958 959void ParallelMoveResolverARM::Exchange(Register reg, int mem) { 960 __ Mov(IP, reg); 961 __ LoadFromOffset(kLoadWord, reg, SP, mem); 962 __ StoreToOffset(kStoreWord, IP, SP, mem); 963} 964 965void ParallelMoveResolverARM::Exchange(int mem1, int mem2) { 966 ScratchRegisterScope ensure_scratch(this, IP, R0, codegen_->GetNumberOfCoreRegisters()); 967 int stack_offset = ensure_scratch.IsSpilled() ? kArmWordSize : 0; 968 __ LoadFromOffset(kLoadWord, static_cast<Register>(ensure_scratch.GetRegister()), 969 SP, mem1 + stack_offset); 970 __ LoadFromOffset(kLoadWord, IP, SP, mem2 + stack_offset); 971 __ StoreToOffset(kStoreWord, static_cast<Register>(ensure_scratch.GetRegister()), 972 SP, mem2 + stack_offset); 973 __ StoreToOffset(kStoreWord, IP, SP, mem1 + stack_offset); 974} 975 976void ParallelMoveResolverARM::EmitSwap(size_t index) { 977 MoveOperands* move = moves_.Get(index); 978 Location source = move->GetSource(); 979 Location destination = move->GetDestination(); 980 981 if (source.IsRegister() && destination.IsRegister()) { 982 DCHECK_NE(source.AsArm().AsCoreRegister(), IP); 983 DCHECK_NE(destination.AsArm().AsCoreRegister(), IP); 984 __ Mov(IP, source.AsArm().AsCoreRegister()); 985 __ Mov(source.AsArm().AsCoreRegister(), destination.AsArm().AsCoreRegister()); 986 __ Mov(destination.AsArm().AsCoreRegister(), IP); 987 } else if (source.IsRegister() && destination.IsStackSlot()) { 988 Exchange(source.AsArm().AsCoreRegister(), destination.GetStackIndex()); 989 } else if (source.IsStackSlot() && destination.IsRegister()) { 990 Exchange(destination.AsArm().AsCoreRegister(), source.GetStackIndex()); 991 } else if (source.IsStackSlot() && destination.IsStackSlot()) { 992 Exchange(source.GetStackIndex(), destination.GetStackIndex()); 993 } else { 994 LOG(FATAL) << "Unimplemented"; 995 } 996} 997 998void ParallelMoveResolverARM::SpillScratch(int reg) { 999 __ Push(static_cast<Register>(reg)); 1000} 1001 1002void ParallelMoveResolverARM::RestoreScratch(int reg) { 1003 __ Pop(static_cast<Register>(reg)); 1004} 1005 1006} // namespace arm 1007} // namespace art 1008