1 //===- AArch64RegisterBankInfo.cpp -------------------------------*- C++ -*-==// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 /// \file 10 /// This file implements the targeting of the RegisterBankInfo class for 11 /// AArch64. 12 /// \todo This should be generated by TableGen. 13 //===----------------------------------------------------------------------===// 14 15 #include "AArch64RegisterBankInfo.h" 16 #include "AArch64InstrInfo.h" // For XXXRegClassID. 17 #include "llvm/CodeGen/LowLevelType.h" 18 #include "llvm/CodeGen/MachineRegisterInfo.h" 19 #include "llvm/CodeGen/GlobalISel/RegisterBank.h" 20 #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" 21 #include "llvm/Target/TargetRegisterInfo.h" 22 #include "llvm/Target/TargetSubtargetInfo.h" 23 24 // This file will be TableGen'ed at some point. 25 #include "AArch64GenRegisterBankInfo.def" 26 27 using namespace llvm; 28 29 #ifndef LLVM_BUILD_GLOBAL_ISEL 30 #error "You shouldn't build this" 31 #endif 32 33 AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI) 34 : RegisterBankInfo(AArch64::RegBanks, AArch64::NumRegisterBanks) { 35 static bool AlreadyInit = false; 36 // We have only one set of register banks, whatever the subtarget 37 // is. Therefore, the initialization of the RegBanks table should be 38 // done only once. Indeed the table of all register banks 39 // (AArch64::RegBanks) is unique in the compiler. At some point, it 40 // will get tablegen'ed and the whole constructor becomes empty. 41 if (AlreadyInit) 42 return; 43 AlreadyInit = true; 44 45 const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID); 46 (void)RBGPR; 47 assert(&AArch64::GPRRegBank == &RBGPR && 48 "The order in RegBanks is messed up"); 49 50 const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID); 51 (void)RBFPR; 52 assert(&AArch64::FPRRegBank == &RBFPR && 53 "The order in RegBanks is messed up"); 54 55 const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID); 56 (void)RBCCR; 57 assert(&AArch64::CCRRegBank == &RBCCR && 58 "The order in RegBanks is messed up"); 59 60 // The GPR register bank is fully defined by all the registers in 61 // GR64all + its subclasses. 62 assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) && 63 "Subclass not added?"); 64 assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit"); 65 66 // The FPR register bank is fully defined by all the registers in 67 // GR64all + its subclasses. 68 assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) && 69 "Subclass not added?"); 70 assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) && 71 "Subclass not added?"); 72 assert(RBFPR.getSize() == 512 && 73 "FPRs should hold up to 512-bit via QQQQ sequence"); 74 75 assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) && 76 "Class not added?"); 77 assert(RBCCR.getSize() == 32 && "CCR should hold up to 32-bit"); 78 79 // Check that the TableGen'ed like file is in sync we our expectations. 80 // First, the Idx. 81 assert(AArch64::PartialMappingIdx::PMI_GPR32 == 82 AArch64::PartialMappingIdx::PMI_FirstGPR && 83 "GPR32 index not first in the GPR list"); 84 assert(AArch64::PartialMappingIdx::PMI_GPR64 == 85 AArch64::PartialMappingIdx::PMI_LastGPR && 86 "GPR64 index not last in the GPR list"); 87 assert(AArch64::PartialMappingIdx::PMI_FirstGPR <= 88 AArch64::PartialMappingIdx::PMI_LastGPR && 89 "GPR list is backward"); 90 assert(AArch64::PartialMappingIdx::PMI_FPR32 == 91 AArch64::PartialMappingIdx::PMI_FirstFPR && 92 "FPR32 index not first in the FPR list"); 93 assert(AArch64::PartialMappingIdx::PMI_FPR512 == 94 AArch64::PartialMappingIdx::PMI_LastFPR && 95 "FPR512 index not last in the FPR list"); 96 assert(AArch64::PartialMappingIdx::PMI_FirstFPR <= 97 AArch64::PartialMappingIdx::PMI_LastFPR && 98 "FPR list is backward"); 99 assert(AArch64::PartialMappingIdx::PMI_FPR32 + 1 == 100 AArch64::PartialMappingIdx::PMI_FPR64 && 101 AArch64::PartialMappingIdx::PMI_FPR64 + 1 == 102 AArch64::PartialMappingIdx::PMI_FPR128 && 103 AArch64::PartialMappingIdx::PMI_FPR128 + 1 == 104 AArch64::PartialMappingIdx::PMI_FPR256 && 105 AArch64::PartialMappingIdx::PMI_FPR256 + 1 == 106 AArch64::PartialMappingIdx::PMI_FPR512 && 107 "FPR indices not properly ordered"); 108 // Now, the content. 109 // Check partial mapping. 110 #define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \ 111 do { \ 112 const PartialMapping &Map = \ 113 AArch64::PartMappings[AArch64::PartialMappingIdx::Idx - \ 114 AArch64::PartialMappingIdx::PMI_Min]; \ 115 (void)Map; \ 116 assert(Map.StartIdx == ValStartIdx && Map.Length == ValLength && \ 117 Map.RegBank == &RB && #Idx " is incorrectly initialized"); \ 118 } while (0) 119 120 CHECK_PARTIALMAP(PMI_GPR32, 0, 32, RBGPR); 121 CHECK_PARTIALMAP(PMI_GPR64, 0, 64, RBGPR); 122 CHECK_PARTIALMAP(PMI_FPR32, 0, 32, RBFPR); 123 CHECK_PARTIALMAP(PMI_FPR64, 0, 64, RBFPR); 124 CHECK_PARTIALMAP(PMI_FPR128, 0, 128, RBFPR); 125 CHECK_PARTIALMAP(PMI_FPR256, 0, 256, RBFPR); 126 CHECK_PARTIALMAP(PMI_FPR512, 0, 512, RBFPR); 127 128 // Check value mapping. 129 #define CHECK_VALUEMAP_IMPL(RBName, Size, Offset) \ 130 do { \ 131 unsigned PartialMapBaseIdx = \ 132 AArch64::PartialMappingIdx::PMI_##RBName##Size - \ 133 AArch64::PartialMappingIdx::PMI_Min; \ 134 (void)PartialMapBaseIdx; \ 135 const ValueMapping &Map = AArch64::getValueMapping( \ 136 AArch64::PartialMappingIdx::PMI_First##RBName, Size)[Offset]; \ 137 (void)Map; \ 138 assert(Map.BreakDown == &AArch64::PartMappings[PartialMapBaseIdx] && \ 139 Map.NumBreakDowns == 1 && #RBName #Size \ 140 " " #Offset " is incorrectly initialized"); \ 141 } while (0) 142 143 #define CHECK_VALUEMAP(RBName, Size) CHECK_VALUEMAP_IMPL(RBName, Size, 0) 144 145 CHECK_VALUEMAP(GPR, 32); 146 CHECK_VALUEMAP(GPR, 64); 147 CHECK_VALUEMAP(FPR, 32); 148 CHECK_VALUEMAP(FPR, 64); 149 CHECK_VALUEMAP(FPR, 128); 150 CHECK_VALUEMAP(FPR, 256); 151 CHECK_VALUEMAP(FPR, 512); 152 153 // Check the value mapping for 3-operands instructions where all the operands 154 // map to the same value mapping. 155 #define CHECK_VALUEMAP_3OPS(RBName, Size) \ 156 do { \ 157 CHECK_VALUEMAP_IMPL(RBName, Size, 0); \ 158 CHECK_VALUEMAP_IMPL(RBName, Size, 1); \ 159 CHECK_VALUEMAP_IMPL(RBName, Size, 2); \ 160 } while (0) 161 162 CHECK_VALUEMAP_3OPS(GPR, 32); 163 CHECK_VALUEMAP_3OPS(GPR, 64); 164 CHECK_VALUEMAP_3OPS(FPR, 32); 165 CHECK_VALUEMAP_3OPS(FPR, 64); 166 CHECK_VALUEMAP_3OPS(FPR, 128); 167 CHECK_VALUEMAP_3OPS(FPR, 256); 168 CHECK_VALUEMAP_3OPS(FPR, 512); 169 170 #define CHECK_VALUEMAP_CROSSREGCPY(RBNameDst, RBNameSrc, Size) \ 171 do { \ 172 unsigned PartialMapDstIdx = \ 173 AArch64::PMI_##RBNameDst##Size - AArch64::PMI_Min; \ 174 unsigned PartialMapSrcIdx = \ 175 AArch64::PMI_##RBNameSrc##Size - AArch64::PMI_Min; \ 176 (void) PartialMapDstIdx; \ 177 (void) PartialMapSrcIdx; \ 178 const ValueMapping *Map = AArch64::getCopyMapping( \ 179 AArch64::PMI_First##RBNameDst == AArch64::PMI_FirstGPR, \ 180 AArch64::PMI_First##RBNameSrc == AArch64::PMI_FirstGPR, Size); \ 181 (void) Map; \ 182 assert(Map[0].BreakDown == &AArch64::PartMappings[PartialMapDstIdx] && \ 183 Map[0].NumBreakDowns == 1 && #RBNameDst #Size \ 184 " Dst is incorrectly initialized"); \ 185 assert(Map[1].BreakDown == &AArch64::PartMappings[PartialMapSrcIdx] && \ 186 Map[1].NumBreakDowns == 1 && #RBNameSrc #Size \ 187 " Src is incorrectly initialized"); \ 188 \ 189 } while (0) 190 191 CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 32); 192 CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 32); 193 CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 64); 194 CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 64); 195 CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 32); 196 CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 32); 197 CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 64); 198 CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 64); 199 200 assert(verify(TRI) && "Invalid register bank information"); 201 } 202 203 unsigned AArch64RegisterBankInfo::copyCost(const RegisterBank &A, 204 const RegisterBank &B, 205 unsigned Size) const { 206 // What do we do with different size? 207 // copy are same size. 208 // Will introduce other hooks for different size: 209 // * extract cost. 210 // * build_sequence cost. 211 212 // Copy from (resp. to) GPR to (resp. from) FPR involves FMOV. 213 // FIXME: This should be deduced from the scheduling model. 214 if (&A == &AArch64::GPRRegBank && &B == &AArch64::FPRRegBank) 215 // FMOVXDr or FMOVWSr. 216 return 5; 217 if (&A == &AArch64::FPRRegBank && &B == &AArch64::GPRRegBank) 218 // FMOVDXr or FMOVSWr. 219 return 4; 220 221 return RegisterBankInfo::copyCost(A, B, Size); 222 } 223 224 const RegisterBank &AArch64RegisterBankInfo::getRegBankFromRegClass( 225 const TargetRegisterClass &RC) const { 226 switch (RC.getID()) { 227 case AArch64::FPR8RegClassID: 228 case AArch64::FPR16RegClassID: 229 case AArch64::FPR32RegClassID: 230 case AArch64::FPR64RegClassID: 231 case AArch64::FPR128RegClassID: 232 case AArch64::FPR128_loRegClassID: 233 case AArch64::DDRegClassID: 234 case AArch64::DDDRegClassID: 235 case AArch64::DDDDRegClassID: 236 case AArch64::QQRegClassID: 237 case AArch64::QQQRegClassID: 238 case AArch64::QQQQRegClassID: 239 return getRegBank(AArch64::FPRRegBankID); 240 case AArch64::GPR32commonRegClassID: 241 case AArch64::GPR32RegClassID: 242 case AArch64::GPR32spRegClassID: 243 case AArch64::GPR32sponlyRegClassID: 244 case AArch64::GPR32allRegClassID: 245 case AArch64::GPR64commonRegClassID: 246 case AArch64::GPR64RegClassID: 247 case AArch64::GPR64spRegClassID: 248 case AArch64::GPR64sponlyRegClassID: 249 case AArch64::GPR64allRegClassID: 250 case AArch64::tcGPR64RegClassID: 251 case AArch64::WSeqPairsClassRegClassID: 252 case AArch64::XSeqPairsClassRegClassID: 253 return getRegBank(AArch64::GPRRegBankID); 254 case AArch64::CCRRegClassID: 255 return getRegBank(AArch64::CCRRegBankID); 256 default: 257 llvm_unreachable("Register class not supported"); 258 } 259 } 260 261 RegisterBankInfo::InstructionMappings 262 AArch64RegisterBankInfo::getInstrAlternativeMappings( 263 const MachineInstr &MI) const { 264 const MachineFunction &MF = *MI.getParent()->getParent(); 265 const TargetSubtargetInfo &STI = MF.getSubtarget(); 266 const TargetRegisterInfo &TRI = *STI.getRegisterInfo(); 267 const MachineRegisterInfo &MRI = MF.getRegInfo(); 268 269 switch (MI.getOpcode()) { 270 case TargetOpcode::G_OR: { 271 // 32 and 64-bit or can be mapped on either FPR or 272 // GPR for the same cost. 273 unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); 274 if (Size != 32 && Size != 64) 275 break; 276 277 // If the instruction has any implicit-defs or uses, 278 // do not mess with it. 279 if (MI.getNumOperands() != 3) 280 break; 281 InstructionMappings AltMappings; 282 InstructionMapping GPRMapping( 283 /*ID*/ 1, /*Cost*/ 1, 284 AArch64::getValueMapping(AArch64::PMI_FirstGPR, Size), 285 /*NumOperands*/ 3); 286 InstructionMapping FPRMapping( 287 /*ID*/ 2, /*Cost*/ 1, 288 AArch64::getValueMapping(AArch64::PMI_FirstFPR, Size), 289 /*NumOperands*/ 3); 290 291 AltMappings.emplace_back(std::move(GPRMapping)); 292 AltMappings.emplace_back(std::move(FPRMapping)); 293 return AltMappings; 294 } 295 case TargetOpcode::G_BITCAST: { 296 unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); 297 if (Size != 32 && Size != 64) 298 break; 299 300 // If the instruction has any implicit-defs or uses, 301 // do not mess with it. 302 if (MI.getNumOperands() != 2) 303 break; 304 305 InstructionMappings AltMappings; 306 InstructionMapping GPRMapping( 307 /*ID*/ 1, /*Cost*/ 1, 308 AArch64::getCopyMapping(/*DstIsGPR*/ true, /*SrcIsGPR*/ true, Size), 309 /*NumOperands*/ 2); 310 InstructionMapping FPRMapping( 311 /*ID*/ 2, /*Cost*/ 1, 312 AArch64::getCopyMapping(/*DstIsGPR*/ false, /*SrcIsGPR*/ false, Size), 313 /*NumOperands*/ 2); 314 InstructionMapping GPRToFPRMapping( 315 /*ID*/ 3, 316 /*Cost*/ copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, Size), 317 AArch64::getCopyMapping(/*DstIsGPR*/ false, /*SrcIsGPR*/ true, Size), 318 /*NumOperands*/ 2); 319 InstructionMapping FPRToGPRMapping( 320 /*ID*/ 3, 321 /*Cost*/ copyCost(AArch64::GPRRegBank, AArch64::FPRRegBank, Size), 322 AArch64::getCopyMapping(/*DstIsGPR*/ true, /*SrcIsGPR*/ false, Size), 323 /*NumOperands*/ 2); 324 325 AltMappings.emplace_back(std::move(GPRMapping)); 326 AltMappings.emplace_back(std::move(FPRMapping)); 327 AltMappings.emplace_back(std::move(GPRToFPRMapping)); 328 AltMappings.emplace_back(std::move(FPRToGPRMapping)); 329 return AltMappings; 330 } 331 case TargetOpcode::G_LOAD: { 332 unsigned Size = getSizeInBits(MI.getOperand(0).getReg(), MRI, TRI); 333 if (Size != 64) 334 break; 335 336 // If the instruction has any implicit-defs or uses, 337 // do not mess with it. 338 if (MI.getNumOperands() != 2) 339 break; 340 341 InstructionMappings AltMappings; 342 InstructionMapping GPRMapping( 343 /*ID*/ 1, /*Cost*/ 1, 344 getOperandsMapping( 345 {AArch64::getValueMapping(AArch64::PMI_FirstGPR, Size), 346 // Addresses are GPR 64-bit. 347 AArch64::getValueMapping(AArch64::PMI_FirstGPR, 64)}), 348 /*NumOperands*/ 2); 349 InstructionMapping FPRMapping( 350 /*ID*/ 2, /*Cost*/ 1, 351 getOperandsMapping( 352 {AArch64::getValueMapping(AArch64::PMI_FirstFPR, Size), 353 // Addresses are GPR 64-bit. 354 AArch64::getValueMapping(AArch64::PMI_FirstGPR, 64)}), 355 /*NumOperands*/ 2); 356 357 AltMappings.emplace_back(std::move(GPRMapping)); 358 AltMappings.emplace_back(std::move(FPRMapping)); 359 return AltMappings; 360 } 361 default: 362 break; 363 } 364 return RegisterBankInfo::getInstrAlternativeMappings(MI); 365 } 366 367 void AArch64RegisterBankInfo::applyMappingImpl( 368 const OperandsMapper &OpdMapper) const { 369 switch (OpdMapper.getMI().getOpcode()) { 370 case TargetOpcode::G_OR: 371 case TargetOpcode::G_BITCAST: 372 case TargetOpcode::G_LOAD: { 373 // Those ID must match getInstrAlternativeMappings. 374 assert((OpdMapper.getInstrMapping().getID() >= 1 && 375 OpdMapper.getInstrMapping().getID() <= 4) && 376 "Don't know how to handle that ID"); 377 return applyDefaultMapping(OpdMapper); 378 } 379 default: 380 llvm_unreachable("Don't know how to handle that operation"); 381 } 382 } 383 384 /// Returns whether opcode \p Opc is a pre-isel generic floating-point opcode, 385 /// having only floating-point operands. 386 static bool isPreISelGenericFloatingPointOpcode(unsigned Opc) { 387 switch (Opc) { 388 case TargetOpcode::G_FADD: 389 case TargetOpcode::G_FSUB: 390 case TargetOpcode::G_FMUL: 391 case TargetOpcode::G_FDIV: 392 case TargetOpcode::G_FCONSTANT: 393 case TargetOpcode::G_FPEXT: 394 case TargetOpcode::G_FPTRUNC: 395 return true; 396 } 397 return false; 398 } 399 400 RegisterBankInfo::InstructionMapping 401 AArch64RegisterBankInfo::getSameKindOfOperandsMapping(const MachineInstr &MI) { 402 const unsigned Opc = MI.getOpcode(); 403 const MachineFunction &MF = *MI.getParent()->getParent(); 404 const MachineRegisterInfo &MRI = MF.getRegInfo(); 405 406 unsigned NumOperands = MI.getNumOperands(); 407 assert(NumOperands <= 3 && 408 "This code is for instructions with 3 or less operands"); 409 410 LLT Ty = MRI.getType(MI.getOperand(0).getReg()); 411 unsigned Size = Ty.getSizeInBits(); 412 bool IsFPR = Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc); 413 414 #ifndef NDEBUG 415 // Make sure all the operands are using similar size and type. 416 // Should probably be checked by the machine verifier. 417 // This code won't catch cases where the number of lanes is 418 // different between the operands. 419 // If we want to go to that level of details, it is probably 420 // best to check that the types are the same, period. 421 // Currently, we just check that the register banks are the same 422 // for each types. 423 for (unsigned Idx = 1; Idx != NumOperands; ++Idx) { 424 LLT OpTy = MRI.getType(MI.getOperand(Idx).getReg()); 425 assert(AArch64::getRegBankBaseIdxOffset(OpTy.getSizeInBits()) == 426 AArch64::getRegBankBaseIdxOffset(Size) && 427 "Operand has incompatible size"); 428 bool OpIsFPR = OpTy.isVector() || isPreISelGenericFloatingPointOpcode(Opc); 429 (void)OpIsFPR; 430 assert(IsFPR == OpIsFPR && "Operand has incompatible type"); 431 } 432 #endif // End NDEBUG. 433 434 AArch64::PartialMappingIdx RBIdx = 435 IsFPR ? AArch64::PMI_FirstFPR : AArch64::PMI_FirstGPR; 436 437 return InstructionMapping{DefaultMappingID, 1, 438 AArch64::getValueMapping(RBIdx, Size), NumOperands}; 439 } 440 441 RegisterBankInfo::InstructionMapping 442 AArch64RegisterBankInfo::getInstrMapping(const MachineInstr &MI) const { 443 const unsigned Opc = MI.getOpcode(); 444 const MachineFunction &MF = *MI.getParent()->getParent(); 445 const MachineRegisterInfo &MRI = MF.getRegInfo(); 446 447 // Try the default logic for non-generic instructions that are either copies 448 // or already have some operands assigned to banks. 449 if (!isPreISelGenericOpcode(Opc)) { 450 RegisterBankInfo::InstructionMapping Mapping = getInstrMappingImpl(MI); 451 if (Mapping.isValid()) 452 return Mapping; 453 } 454 455 switch (Opc) { 456 // G_{F|S|U}REM are not listed because they are not legal. 457 // Arithmetic ops. 458 case TargetOpcode::G_ADD: 459 case TargetOpcode::G_SUB: 460 case TargetOpcode::G_GEP: 461 case TargetOpcode::G_MUL: 462 case TargetOpcode::G_SDIV: 463 case TargetOpcode::G_UDIV: 464 // Bitwise ops. 465 case TargetOpcode::G_AND: 466 case TargetOpcode::G_OR: 467 case TargetOpcode::G_XOR: 468 // Shifts. 469 case TargetOpcode::G_SHL: 470 case TargetOpcode::G_LSHR: 471 case TargetOpcode::G_ASHR: 472 // Floating point ops. 473 case TargetOpcode::G_FADD: 474 case TargetOpcode::G_FSUB: 475 case TargetOpcode::G_FMUL: 476 case TargetOpcode::G_FDIV: 477 return getSameKindOfOperandsMapping(MI); 478 case TargetOpcode::G_BITCAST: { 479 LLT DstTy = MRI.getType(MI.getOperand(0).getReg()); 480 LLT SrcTy = MRI.getType(MI.getOperand(1).getReg()); 481 unsigned Size = DstTy.getSizeInBits(); 482 bool DstIsGPR = !DstTy.isVector(); 483 bool SrcIsGPR = !SrcTy.isVector(); 484 const RegisterBank &DstRB = 485 DstIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank; 486 const RegisterBank &SrcRB = 487 SrcIsGPR ? AArch64::GPRRegBank : AArch64::FPRRegBank; 488 return InstructionMapping{DefaultMappingID, copyCost(DstRB, SrcRB, Size), 489 AArch64::getCopyMapping(DstIsGPR, SrcIsGPR, Size), 490 /*NumOperands*/ 2}; 491 } 492 case TargetOpcode::G_SEQUENCE: 493 // FIXME: support this, but the generic code is really not going to do 494 // anything sane. 495 return InstructionMapping(); 496 default: 497 break; 498 } 499 500 unsigned NumOperands = MI.getNumOperands(); 501 502 // Track the size and bank of each register. We don't do partial mappings. 503 SmallVector<unsigned, 4> OpSize(NumOperands); 504 SmallVector<AArch64::PartialMappingIdx, 4> OpRegBankIdx(NumOperands); 505 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) { 506 auto &MO = MI.getOperand(Idx); 507 if (!MO.isReg()) 508 continue; 509 510 LLT Ty = MRI.getType(MO.getReg()); 511 OpSize[Idx] = Ty.getSizeInBits(); 512 513 // As a top-level guess, vectors go in FPRs, scalars and pointers in GPRs. 514 // For floating-point instructions, scalars go in FPRs. 515 if (Ty.isVector() || isPreISelGenericFloatingPointOpcode(Opc)) 516 OpRegBankIdx[Idx] = AArch64::PMI_FirstFPR; 517 else 518 OpRegBankIdx[Idx] = AArch64::PMI_FirstGPR; 519 } 520 521 unsigned Cost = 1; 522 // Some of the floating-point instructions have mixed GPR and FPR operands: 523 // fine-tune the computed mapping. 524 switch (Opc) { 525 case TargetOpcode::G_SITOFP: 526 case TargetOpcode::G_UITOFP: { 527 OpRegBankIdx = {AArch64::PMI_FirstFPR, AArch64::PMI_FirstGPR}; 528 break; 529 } 530 case TargetOpcode::G_FPTOSI: 531 case TargetOpcode::G_FPTOUI: { 532 OpRegBankIdx = {AArch64::PMI_FirstGPR, AArch64::PMI_FirstFPR}; 533 break; 534 } 535 case TargetOpcode::G_FCMP: { 536 OpRegBankIdx = {AArch64::PMI_FirstGPR, 537 /* Predicate */ AArch64::PMI_None, AArch64::PMI_FirstFPR, 538 AArch64::PMI_FirstFPR}; 539 break; 540 } 541 case TargetOpcode::G_BITCAST: { 542 // This is going to be a cross register bank copy and this is expensive. 543 if (OpRegBankIdx[0] != OpRegBankIdx[1]) 544 Cost = 545 copyCost(*AArch64::PartMappings[OpRegBankIdx[0]].RegBank, 546 *AArch64::PartMappings[OpRegBankIdx[1]].RegBank, OpSize[0]); 547 break; 548 } 549 case TargetOpcode::G_LOAD: { 550 // Loading in vector unit is slightly more expensive. 551 // This is actually only true for the LD1R and co instructions, 552 // but anyway for the fast mode this number does not matter and 553 // for the greedy mode the cost of the cross bank copy will 554 // offset this number. 555 // FIXME: Should be derived from the scheduling model. 556 if (OpRegBankIdx[0] >= AArch64::PMI_FirstFPR) 557 Cost = 2; 558 } 559 } 560 561 // Finally construct the computed mapping. 562 RegisterBankInfo::InstructionMapping Mapping = 563 InstructionMapping{DefaultMappingID, Cost, nullptr, NumOperands}; 564 SmallVector<const ValueMapping *, 8> OpdsMapping(NumOperands); 565 for (unsigned Idx = 0; Idx < NumOperands; ++Idx) 566 if (MI.getOperand(Idx).isReg()) 567 OpdsMapping[Idx] = 568 AArch64::getValueMapping(OpRegBankIdx[Idx], OpSize[Idx]); 569 570 Mapping.setOperandsMapping(getOperandsMapping(OpdsMapping)); 571 return Mapping; 572 } 573