code_generator_arm.cc revision b0fa5dc7769c1e054032f39de0a3f6d6dd06f8cf
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#include "utils/assembler.h" 19#include "utils/arm/assembler_arm.h" 20#include "utils/arm/managed_register_arm.h" 21 22#include "entrypoints/quick/quick_entrypoints.h" 23#include "mirror/array.h" 24#include "mirror/art_method.h" 25#include "thread.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 37static constexpr int kNumberOfPushedRegistersAtEntry = 1; 38static constexpr int kCurrentMethodStackOffset = 0; 39 40CodeGeneratorARM::CodeGeneratorARM(HGraph* graph) 41 : CodeGenerator(graph, kNumberOfRegIds), 42 location_builder_(graph, this), 43 instruction_visitor_(graph, this) {} 44 45static bool* GetBlockedRegisterPairs(bool* blocked_registers) { 46 return blocked_registers + kNumberOfAllocIds; 47} 48 49ManagedRegister CodeGeneratorARM::AllocateFreeRegister(Primitive::Type type, 50 bool* blocked_registers) const { 51 switch (type) { 52 case Primitive::kPrimLong: { 53 size_t reg = AllocateFreeRegisterInternal( 54 GetBlockedRegisterPairs(blocked_registers), kNumberOfRegisterPairs); 55 ArmManagedRegister pair = 56 ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(reg)); 57 blocked_registers[pair.AsRegisterPairLow()] = true; 58 blocked_registers[pair.AsRegisterPairHigh()] = true; 59 return pair; 60 } 61 62 case Primitive::kPrimByte: 63 case Primitive::kPrimBoolean: 64 case Primitive::kPrimChar: 65 case Primitive::kPrimShort: 66 case Primitive::kPrimInt: 67 case Primitive::kPrimNot: { 68 size_t reg = AllocateFreeRegisterInternal(blocked_registers, kNumberOfCoreRegisters); 69 return ArmManagedRegister::FromCoreRegister(static_cast<Register>(reg)); 70 } 71 72 case Primitive::kPrimFloat: 73 case Primitive::kPrimDouble: 74 LOG(FATAL) << "Unimplemented register type " << type; 75 76 case Primitive::kPrimVoid: 77 LOG(FATAL) << "Unreachable type " << type; 78 } 79 80 return ManagedRegister::NoRegister(); 81} 82 83void CodeGeneratorARM::SetupBlockedRegisters(bool* blocked_registers) const { 84 bool* blocked_register_pairs = GetBlockedRegisterPairs(blocked_registers); 85 86 // Don't allocate the dalvik style register pair passing. 87 blocked_register_pairs[R1_R2] = true; 88 89 // Stack register, LR and PC are always reserved. 90 blocked_registers[SP] = true; 91 blocked_registers[LR] = true; 92 blocked_registers[PC] = true; 93 94 // Reserve R4 for suspend check. 95 blocked_registers[R4] = true; 96 blocked_register_pairs[R4_R5] = true; 97 98 // Reserve thread register. 99 blocked_registers[TR] = true; 100 101 // TODO: We currently don't use Quick's callee saved registers. 102 blocked_registers[R5] = true; 103 blocked_registers[R6] = true; 104 blocked_registers[R7] = true; 105 blocked_registers[R8] = true; 106 blocked_registers[R10] = true; 107 blocked_registers[R11] = true; 108 blocked_register_pairs[R6_R7] = true; 109} 110 111size_t CodeGeneratorARM::GetNumberOfRegisters() const { 112 return kNumberOfRegIds; 113} 114 115static Location ArmCoreLocation(Register reg) { 116 return Location::RegisterLocation(ArmManagedRegister::FromCoreRegister(reg)); 117} 118 119InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) 120 : HGraphVisitor(graph), 121 assembler_(codegen->GetAssembler()), 122 codegen_(codegen) {} 123 124void CodeGeneratorARM::GenerateFrameEntry() { 125 core_spill_mask_ |= (1 << LR); 126 __ PushList((1 << LR)); 127 128 SetFrameSize(RoundUp( 129 (GetGraph()->GetMaximumNumberOfOutVRegs() + GetGraph()->GetNumberOfVRegs()) * kVRegSize 130 + kVRegSize // filler 131 + kArmWordSize // Art method 132 + kNumberOfPushedRegistersAtEntry * kArmWordSize, 133 kStackAlignment)); 134 // The return PC has already been pushed on the stack. 135 __ AddConstant(SP, -(GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize)); 136 __ str(R0, Address(SP, 0)); 137} 138 139void CodeGeneratorARM::GenerateFrameExit() { 140 __ AddConstant(SP, GetFrameSize() - kNumberOfPushedRegistersAtEntry * kArmWordSize); 141 __ PopList((1 << PC)); 142} 143 144void CodeGeneratorARM::Bind(Label* label) { 145 __ Bind(label); 146} 147 148int32_t CodeGeneratorARM::GetStackSlot(HLocal* local) const { 149 uint16_t reg_number = local->GetRegNumber(); 150 uint16_t number_of_vregs = GetGraph()->GetNumberOfVRegs(); 151 uint16_t number_of_in_vregs = GetGraph()->GetNumberOfInVRegs(); 152 if (reg_number >= number_of_vregs - number_of_in_vregs) { 153 // Local is a parameter of the method. It is stored in the caller's frame. 154 return GetFrameSize() + kArmWordSize // ART method 155 + (reg_number - number_of_vregs + number_of_in_vregs) * kVRegSize; 156 } else { 157 // Local is a temporary in this method. It is stored in this method's frame. 158 return GetFrameSize() - (kNumberOfPushedRegistersAtEntry * kArmWordSize) 159 - kVRegSize // filler. 160 - (number_of_vregs * kVRegSize) 161 + (reg_number * kVRegSize); 162 } 163} 164 165Location CodeGeneratorARM::GetStackLocation(HLoadLocal* load) const { 166 switch (load->GetType()) { 167 case Primitive::kPrimLong: 168 return Location::DoubleStackSlot(GetStackSlot(load->GetLocal())); 169 break; 170 171 case Primitive::kPrimInt: 172 case Primitive::kPrimNot: 173 return Location::StackSlot(GetStackSlot(load->GetLocal())); 174 175 case Primitive::kPrimFloat: 176 case Primitive::kPrimDouble: 177 LOG(FATAL) << "Unimplemented type " << load->GetType(); 178 179 case Primitive::kPrimBoolean: 180 case Primitive::kPrimByte: 181 case Primitive::kPrimChar: 182 case Primitive::kPrimShort: 183 case Primitive::kPrimVoid: 184 LOG(FATAL) << "Unexpected type " << load->GetType(); 185 } 186 187 LOG(FATAL) << "Unreachable"; 188 return Location(); 189} 190 191Location InvokeDexCallingConventionVisitor::GetNextLocation(Primitive::Type type) { 192 switch (type) { 193 case Primitive::kPrimBoolean: 194 case Primitive::kPrimByte: 195 case Primitive::kPrimChar: 196 case Primitive::kPrimShort: 197 case Primitive::kPrimInt: 198 case Primitive::kPrimNot: { 199 uint32_t index = gp_index_++; 200 if (index < calling_convention.GetNumberOfRegisters()) { 201 return ArmCoreLocation(calling_convention.GetRegisterAt(index)); 202 } else { 203 return Location::StackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize)); 204 } 205 } 206 207 case Primitive::kPrimLong: { 208 uint32_t index = gp_index_; 209 gp_index_ += 2; 210 if (index + 1 < calling_convention.GetNumberOfRegisters()) { 211 return Location::RegisterLocation(ArmManagedRegister::FromRegisterPair( 212 calling_convention.GetRegisterPairAt(index))); 213 } else if (index + 1 == calling_convention.GetNumberOfRegisters()) { 214 return Location::QuickParameter(index); 215 } else { 216 return Location::DoubleStackSlot(calling_convention.GetStackOffsetOf(index, kArmWordSize)); 217 } 218 } 219 220 case Primitive::kPrimDouble: 221 case Primitive::kPrimFloat: 222 LOG(FATAL) << "Unimplemented parameter type " << type; 223 break; 224 225 case Primitive::kPrimVoid: 226 LOG(FATAL) << "Unexpected parameter type " << type; 227 break; 228 } 229 return Location(); 230} 231 232void CodeGeneratorARM::Move32(Location destination, Location source) { 233 if (source.Equals(destination)) { 234 return; 235 } 236 if (destination.IsRegister()) { 237 if (source.IsRegister()) { 238 __ Mov(destination.AsArm().AsCoreRegister(), source.AsArm().AsCoreRegister()); 239 } else { 240 __ ldr(destination.AsArm().AsCoreRegister(), Address(SP, source.GetStackIndex())); 241 } 242 } else { 243 DCHECK(destination.IsStackSlot()); 244 if (source.IsRegister()) { 245 __ str(source.AsArm().AsCoreRegister(), Address(SP, destination.GetStackIndex())); 246 } else { 247 __ ldr(R0, Address(SP, source.GetStackIndex())); 248 __ str(R0, Address(SP, destination.GetStackIndex())); 249 } 250 } 251} 252 253void CodeGeneratorARM::Move64(Location destination, Location source) { 254 if (source.Equals(destination)) { 255 return; 256 } 257 if (destination.IsRegister()) { 258 if (source.IsRegister()) { 259 __ Mov(destination.AsArm().AsRegisterPairLow(), source.AsArm().AsRegisterPairLow()); 260 __ Mov(destination.AsArm().AsRegisterPairHigh(), source.AsArm().AsRegisterPairHigh()); 261 } else if (source.IsQuickParameter()) { 262 uint32_t argument_index = source.GetQuickParameterIndex(); 263 InvokeDexCallingConvention calling_convention; 264 __ Mov(destination.AsArm().AsRegisterPairLow(), 265 calling_convention.GetRegisterAt(argument_index)); 266 __ ldr(destination.AsArm().AsRegisterPairHigh(), 267 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize())); 268 } else { 269 DCHECK(source.IsDoubleStackSlot()); 270 if (destination.AsArm().AsRegisterPair() == R1_R2) { 271 __ ldr(R1, Address(SP, source.GetStackIndex())); 272 __ ldr(R2, Address(SP, source.GetHighStackIndex(kArmWordSize))); 273 } else { 274 __ LoadFromOffset(kLoadWordPair, destination.AsArm().AsRegisterPairLow(), 275 SP, source.GetStackIndex()); 276 } 277 } 278 } else if (destination.IsQuickParameter()) { 279 InvokeDexCallingConvention calling_convention; 280 uint32_t argument_index = destination.GetQuickParameterIndex(); 281 if (source.IsRegister()) { 282 __ Mov(calling_convention.GetRegisterAt(argument_index), source.AsArm().AsRegisterPairLow()); 283 __ str(source.AsArm().AsRegisterPairHigh(), 284 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize))); 285 } else { 286 DCHECK(source.IsDoubleStackSlot()); 287 __ ldr(calling_convention.GetRegisterAt(argument_index), Address(SP, source.GetStackIndex())); 288 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize))); 289 __ str(R0, Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize))); 290 } 291 } else { 292 DCHECK(destination.IsDoubleStackSlot()); 293 if (source.IsRegister()) { 294 if (source.AsArm().AsRegisterPair() == R1_R2) { 295 __ str(R1, Address(SP, destination.GetStackIndex())); 296 __ str(R2, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 297 } else { 298 __ StoreToOffset(kStoreWordPair, source.AsArm().AsRegisterPairLow(), 299 SP, destination.GetStackIndex()); 300 } 301 } else if (source.IsQuickParameter()) { 302 InvokeDexCallingConvention calling_convention; 303 uint32_t argument_index = source.GetQuickParameterIndex(); 304 __ str(calling_convention.GetRegisterAt(argument_index), 305 Address(SP, destination.GetStackIndex())); 306 __ ldr(R0, 307 Address(SP, calling_convention.GetStackOffsetOf(argument_index + 1, kArmWordSize) + GetFrameSize())); 308 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 309 } else { 310 DCHECK(source.IsDoubleStackSlot()); 311 __ ldr(R0, Address(SP, source.GetStackIndex())); 312 __ str(R0, Address(SP, destination.GetStackIndex())); 313 __ ldr(R0, Address(SP, source.GetHighStackIndex(kArmWordSize))); 314 __ str(R0, Address(SP, destination.GetHighStackIndex(kArmWordSize))); 315 } 316 } 317} 318 319void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { 320 if (instruction->AsIntConstant() != nullptr) { 321 int32_t value = instruction->AsIntConstant()->GetValue(); 322 if (location.IsRegister()) { 323 __ LoadImmediate(location.AsArm().AsCoreRegister(), value); 324 } else { 325 __ LoadImmediate(R0, value); 326 __ str(R0, Address(SP, location.GetStackIndex())); 327 } 328 } else if (instruction->AsLongConstant() != nullptr) { 329 int64_t value = instruction->AsLongConstant()->GetValue(); 330 if (location.IsRegister()) { 331 __ LoadImmediate(location.AsArm().AsRegisterPairLow(), Low32Bits(value)); 332 __ LoadImmediate(location.AsArm().AsRegisterPairHigh(), High32Bits(value)); 333 } else { 334 __ LoadImmediate(R0, Low32Bits(value)); 335 __ str(R0, Address(SP, location.GetStackIndex())); 336 __ LoadImmediate(R0, High32Bits(value)); 337 __ str(R0, Address(SP, location.GetHighStackIndex(kArmWordSize))); 338 } 339 } else if (instruction->AsLoadLocal() != nullptr) { 340 uint32_t stack_slot = GetStackSlot(instruction->AsLoadLocal()->GetLocal()); 341 switch (instruction->GetType()) { 342 case Primitive::kPrimBoolean: 343 case Primitive::kPrimByte: 344 case Primitive::kPrimChar: 345 case Primitive::kPrimShort: 346 case Primitive::kPrimInt: 347 case Primitive::kPrimNot: 348 Move32(location, Location::StackSlot(stack_slot)); 349 break; 350 351 case Primitive::kPrimLong: 352 Move64(location, Location::DoubleStackSlot(stack_slot)); 353 break; 354 355 default: 356 LOG(FATAL) << "Unimplemented type " << instruction->GetType(); 357 } 358 } else { 359 // This can currently only happen when the instruction that requests the move 360 // is the next to be compiled. 361 DCHECK_EQ(instruction->GetNext(), move_for); 362 switch (instruction->GetType()) { 363 case Primitive::kPrimBoolean: 364 case Primitive::kPrimByte: 365 case Primitive::kPrimChar: 366 case Primitive::kPrimShort: 367 case Primitive::kPrimNot: 368 case Primitive::kPrimInt: 369 Move32(location, instruction->GetLocations()->Out()); 370 break; 371 372 case Primitive::kPrimLong: 373 Move64(location, instruction->GetLocations()->Out()); 374 break; 375 376 default: 377 LOG(FATAL) << "Unimplemented type " << instruction->GetType(); 378 } 379 } 380} 381 382void LocationsBuilderARM::VisitGoto(HGoto* got) { 383 got->SetLocations(nullptr); 384} 385 386void InstructionCodeGeneratorARM::VisitGoto(HGoto* got) { 387 HBasicBlock* successor = got->GetSuccessor(); 388 if (GetGraph()->GetExitBlock() == successor) { 389 codegen_->GenerateFrameExit(); 390 } else if (!codegen_->GoesToNextBlock(got->GetBlock(), successor)) { 391 __ b(codegen_->GetLabelOf(successor)); 392 } 393} 394 395void LocationsBuilderARM::VisitExit(HExit* exit) { 396 exit->SetLocations(nullptr); 397} 398 399void InstructionCodeGeneratorARM::VisitExit(HExit* exit) { 400 if (kIsDebugBuild) { 401 __ Comment("Unreachable"); 402 __ bkpt(0); 403 } 404} 405 406void LocationsBuilderARM::VisitIf(HIf* if_instr) { 407 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(if_instr); 408 locations->SetInAt(0, Location::RequiresRegister()); 409 if_instr->SetLocations(locations); 410} 411 412void InstructionCodeGeneratorARM::VisitIf(HIf* if_instr) { 413 // TODO: Generate the input as a condition, instead of materializing in a register. 414 __ cmp(if_instr->GetLocations()->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(0)); 415 __ b(codegen_->GetLabelOf(if_instr->IfFalseSuccessor()), EQ); 416 if (!codegen_->GoesToNextBlock(if_instr->GetBlock(), if_instr->IfTrueSuccessor())) { 417 __ b(codegen_->GetLabelOf(if_instr->IfTrueSuccessor())); 418 } 419} 420 421void LocationsBuilderARM::VisitEqual(HEqual* equal) { 422 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(equal); 423 locations->SetInAt(0, Location::RequiresRegister()); 424 locations->SetInAt(1, Location::RequiresRegister()); 425 locations->SetOut(Location::RequiresRegister()); 426 equal->SetLocations(locations); 427} 428 429void InstructionCodeGeneratorARM::VisitEqual(HEqual* equal) { 430 LocationSummary* locations = equal->GetLocations(); 431 __ teq(locations->InAt(0).AsArm().AsCoreRegister(), 432 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 433 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(1), EQ); 434 __ mov(locations->Out().AsArm().AsCoreRegister(), ShifterOperand(0), NE); 435} 436 437void LocationsBuilderARM::VisitLocal(HLocal* local) { 438 local->SetLocations(nullptr); 439} 440 441void InstructionCodeGeneratorARM::VisitLocal(HLocal* local) { 442 DCHECK_EQ(local->GetBlock(), GetGraph()->GetEntryBlock()); 443} 444 445void LocationsBuilderARM::VisitLoadLocal(HLoadLocal* load) { 446 load->SetLocations(nullptr); 447} 448 449void InstructionCodeGeneratorARM::VisitLoadLocal(HLoadLocal* load) { 450 // Nothing to do, this is driven by the code generator. 451} 452 453void LocationsBuilderARM::VisitStoreLocal(HStoreLocal* store) { 454 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(store); 455 switch (store->InputAt(1)->GetType()) { 456 case Primitive::kPrimBoolean: 457 case Primitive::kPrimByte: 458 case Primitive::kPrimChar: 459 case Primitive::kPrimShort: 460 case Primitive::kPrimInt: 461 case Primitive::kPrimNot: 462 locations->SetInAt(1, Location::StackSlot(codegen_->GetStackSlot(store->GetLocal()))); 463 break; 464 465 case Primitive::kPrimLong: 466 locations->SetInAt(1, Location::DoubleStackSlot(codegen_->GetStackSlot(store->GetLocal()))); 467 break; 468 469 default: 470 LOG(FATAL) << "Unimplemented local type " << store->InputAt(1)->GetType(); 471 } 472 store->SetLocations(locations); 473} 474 475void InstructionCodeGeneratorARM::VisitStoreLocal(HStoreLocal* store) { 476} 477 478void LocationsBuilderARM::VisitIntConstant(HIntConstant* constant) { 479 constant->SetLocations(nullptr); 480} 481 482void InstructionCodeGeneratorARM::VisitIntConstant(HIntConstant* constant) { 483 // Will be generated at use site. 484} 485 486void LocationsBuilderARM::VisitLongConstant(HLongConstant* constant) { 487 constant->SetLocations(nullptr); 488} 489 490void InstructionCodeGeneratorARM::VisitLongConstant(HLongConstant* constant) { 491 // Will be generated at use site. 492} 493 494void LocationsBuilderARM::VisitReturnVoid(HReturnVoid* ret) { 495 ret->SetLocations(nullptr); 496} 497 498void InstructionCodeGeneratorARM::VisitReturnVoid(HReturnVoid* ret) { 499 codegen_->GenerateFrameExit(); 500} 501 502void LocationsBuilderARM::VisitReturn(HReturn* ret) { 503 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(ret); 504 switch (ret->InputAt(0)->GetType()) { 505 case Primitive::kPrimBoolean: 506 case Primitive::kPrimByte: 507 case Primitive::kPrimChar: 508 case Primitive::kPrimShort: 509 case Primitive::kPrimInt: 510 case Primitive::kPrimNot: 511 locations->SetInAt(0, ArmCoreLocation(R0)); 512 break; 513 514 case Primitive::kPrimLong: 515 locations->SetInAt( 516 0, Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 517 break; 518 519 default: 520 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 521 } 522 523 ret->SetLocations(locations); 524} 525 526void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { 527 if (kIsDebugBuild) { 528 switch (ret->InputAt(0)->GetType()) { 529 case Primitive::kPrimBoolean: 530 case Primitive::kPrimByte: 531 case Primitive::kPrimChar: 532 case Primitive::kPrimShort: 533 case Primitive::kPrimInt: 534 case Primitive::kPrimNot: 535 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsCoreRegister(), R0); 536 break; 537 538 case Primitive::kPrimLong: 539 DCHECK_EQ(ret->GetLocations()->InAt(0).AsArm().AsRegisterPair(), R0_R1); 540 break; 541 542 default: 543 LOG(FATAL) << "Unimplemented return type " << ret->InputAt(0)->GetType(); 544 } 545 } 546 codegen_->GenerateFrameExit(); 547} 548 549void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) { 550 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke); 551 locations->AddTemp(Location::RequiresRegister()); 552 553 InvokeDexCallingConventionVisitor calling_convention_visitor; 554 for (size_t i = 0; i < invoke->InputCount(); i++) { 555 HInstruction* input = invoke->InputAt(i); 556 locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType())); 557 } 558 559 switch (invoke->GetType()) { 560 case Primitive::kPrimBoolean: 561 case Primitive::kPrimByte: 562 case Primitive::kPrimChar: 563 case Primitive::kPrimShort: 564 case Primitive::kPrimInt: 565 case Primitive::kPrimNot: 566 locations->SetOut(ArmCoreLocation(R0)); 567 break; 568 569 case Primitive::kPrimLong: 570 locations->SetOut(Location::RegisterLocation(ArmManagedRegister::FromRegisterPair(R0_R1))); 571 break; 572 573 case Primitive::kPrimVoid: 574 break; 575 576 case Primitive::kPrimDouble: 577 case Primitive::kPrimFloat: 578 LOG(FATAL) << "Unimplemented return type " << invoke->GetType(); 579 break; 580 } 581 582 invoke->SetLocations(locations); 583} 584 585void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) { 586 __ ldr(reg, Address(SP, kCurrentMethodStackOffset)); 587} 588 589void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) { 590 Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister(); 591 size_t index_in_cache = mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() + 592 invoke->GetIndexInDexCache() * kArmWordSize; 593 594 // TODO: Implement all kinds of calls: 595 // 1) boot -> boot 596 // 2) app -> boot 597 // 3) app -> app 598 // 599 // Currently we implement the app -> app logic, which looks up in the resolve cache. 600 601 // temp = method; 602 LoadCurrentMethod(temp); 603 // temp = temp->dex_cache_resolved_methods_; 604 __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value())); 605 // temp = temp[index_in_cache] 606 __ ldr(temp, Address(temp, index_in_cache)); 607 // LR = temp[offset_of_quick_compiled_code] 608 __ ldr(LR, Address(temp, 609 mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value())); 610 // LR() 611 __ blx(LR); 612 613 codegen_->RecordPcInfo(invoke->GetDexPc()); 614} 615 616void LocationsBuilderARM::VisitAdd(HAdd* add) { 617 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(add); 618 switch (add->GetResultType()) { 619 case Primitive::kPrimInt: 620 case Primitive::kPrimLong: { 621 locations->SetInAt(0, Location::RequiresRegister()); 622 locations->SetInAt(1, Location::RequiresRegister()); 623 locations->SetOut(Location::RequiresRegister()); 624 break; 625 } 626 627 case Primitive::kPrimBoolean: 628 case Primitive::kPrimByte: 629 case Primitive::kPrimChar: 630 case Primitive::kPrimShort: 631 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 632 break; 633 634 default: 635 LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); 636 } 637 add->SetLocations(locations); 638} 639 640void InstructionCodeGeneratorARM::VisitAdd(HAdd* add) { 641 LocationSummary* locations = add->GetLocations(); 642 switch (add->GetResultType()) { 643 case Primitive::kPrimInt: 644 __ add(locations->Out().AsArm().AsCoreRegister(), 645 locations->InAt(0).AsArm().AsCoreRegister(), 646 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 647 break; 648 649 case Primitive::kPrimLong: 650 __ adds(locations->Out().AsArm().AsRegisterPairLow(), 651 locations->InAt(0).AsArm().AsRegisterPairLow(), 652 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); 653 __ adc(locations->Out().AsArm().AsRegisterPairHigh(), 654 locations->InAt(0).AsArm().AsRegisterPairHigh(), 655 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 656 break; 657 658 case Primitive::kPrimBoolean: 659 case Primitive::kPrimByte: 660 case Primitive::kPrimChar: 661 case Primitive::kPrimShort: 662 LOG(FATAL) << "Unexpected add type " << add->GetResultType(); 663 break; 664 665 default: 666 LOG(FATAL) << "Unimplemented add type " << add->GetResultType(); 667 } 668} 669 670void LocationsBuilderARM::VisitSub(HSub* sub) { 671 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(sub); 672 switch (sub->GetResultType()) { 673 case Primitive::kPrimInt: 674 case Primitive::kPrimLong: { 675 locations->SetInAt(0, Location::RequiresRegister()); 676 locations->SetInAt(1, Location::RequiresRegister()); 677 locations->SetOut(Location::RequiresRegister()); 678 break; 679 } 680 681 case Primitive::kPrimBoolean: 682 case Primitive::kPrimByte: 683 case Primitive::kPrimChar: 684 case Primitive::kPrimShort: 685 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 686 break; 687 688 default: 689 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 690 } 691 sub->SetLocations(locations); 692} 693 694void InstructionCodeGeneratorARM::VisitSub(HSub* sub) { 695 LocationSummary* locations = sub->GetLocations(); 696 switch (sub->GetResultType()) { 697 case Primitive::kPrimInt: 698 __ sub(locations->Out().AsArm().AsCoreRegister(), 699 locations->InAt(0).AsArm().AsCoreRegister(), 700 ShifterOperand(locations->InAt(1).AsArm().AsCoreRegister())); 701 break; 702 703 case Primitive::kPrimLong: 704 __ subs(locations->Out().AsArm().AsRegisterPairLow(), 705 locations->InAt(0).AsArm().AsRegisterPairLow(), 706 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairLow())); 707 __ sbc(locations->Out().AsArm().AsRegisterPairHigh(), 708 locations->InAt(0).AsArm().AsRegisterPairHigh(), 709 ShifterOperand(locations->InAt(1).AsArm().AsRegisterPairHigh())); 710 break; 711 712 case Primitive::kPrimBoolean: 713 case Primitive::kPrimByte: 714 case Primitive::kPrimChar: 715 case Primitive::kPrimShort: 716 LOG(FATAL) << "Unexpected sub type " << sub->GetResultType(); 717 break; 718 719 default: 720 LOG(FATAL) << "Unimplemented sub type " << sub->GetResultType(); 721 } 722} 723 724static constexpr Register kRuntimeParameterCoreRegisters[] = { R0, R1 }; 725static constexpr size_t kRuntimeParameterCoreRegistersLength = 726 arraysize(kRuntimeParameterCoreRegisters); 727 728class InvokeRuntimeCallingConvention : public CallingConvention<Register> { 729 public: 730 InvokeRuntimeCallingConvention() 731 : CallingConvention(kRuntimeParameterCoreRegisters, 732 kRuntimeParameterCoreRegistersLength) {} 733 734 private: 735 DISALLOW_COPY_AND_ASSIGN(InvokeRuntimeCallingConvention); 736}; 737 738void LocationsBuilderARM::VisitNewInstance(HNewInstance* instruction) { 739 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 740 InvokeRuntimeCallingConvention calling_convention; 741 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(0))); 742 locations->AddTemp(ArmCoreLocation(calling_convention.GetRegisterAt(1))); 743 locations->SetOut(ArmCoreLocation(R0)); 744 instruction->SetLocations(locations); 745} 746 747void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { 748 InvokeRuntimeCallingConvention calling_convention; 749 LoadCurrentMethod(calling_convention.GetRegisterAt(1)); 750 __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); 751 752 int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pAllocObjectWithAccessCheck).Int32Value(); 753 __ ldr(LR, Address(TR, offset)); 754 __ blx(LR); 755 756 codegen_->RecordPcInfo(instruction->GetDexPc()); 757} 758 759void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { 760 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 761 Location location = parameter_visitor_.GetNextLocation(instruction->GetType()); 762 if (location.IsStackSlot()) { 763 location = Location::StackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 764 } else if (location.IsDoubleStackSlot()) { 765 location = Location::DoubleStackSlot(location.GetStackIndex() + codegen_->GetFrameSize()); 766 } 767 locations->SetOut(location); 768 instruction->SetLocations(locations); 769} 770 771void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { 772 // Nothing to do, the parameter is already at its location. 773} 774 775void LocationsBuilderARM::VisitNot(HNot* instruction) { 776 LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction); 777 locations->SetInAt(0, Location::RequiresRegister()); 778 locations->SetOut(Location::RequiresRegister()); 779 instruction->SetLocations(locations); 780} 781 782void InstructionCodeGeneratorARM::VisitNot(HNot* instruction) { 783 LocationSummary* locations = instruction->GetLocations(); 784 __ eor(locations->Out().AsArm().AsCoreRegister(), 785 locations->InAt(0).AsArm().AsCoreRegister(), ShifterOperand(1)); 786} 787 788void LocationsBuilderARM::VisitPhi(HPhi* instruction) { 789 LOG(FATAL) << "Unimplemented"; 790} 791 792void InstructionCodeGeneratorARM::VisitPhi(HPhi* instruction) { 793 LOG(FATAL) << "Unimplemented"; 794} 795 796} // namespace arm 797} // namespace art 798