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