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