bool RegisterBank::verify(const TargetRegisterInfo &TRI) const { assert(isValid() && "Invalid register bank"); for (unsigned RCId = 0, End = TRI.getNumRegClasses(); RCId != End; ++RCId) { const TargetRegisterClass &RC = *TRI.getRegClass(RCId); if (!covers(RC)) continue; // Verify that the register bank covers all the sub classes of the // classes it covers. // Use a different (slow in that case) method than // RegisterBankInfo to find the subclasses of RC, to make sure // both agree on the covers. for (unsigned SubRCId = 0; SubRCId != End; ++SubRCId) { const TargetRegisterClass &SubRC = *TRI.getRegClass(RCId); if (!RC.hasSubClassEq(&SubRC)) continue; // Verify that the Size of the register bank is big enough to cover // all the register classes it covers. assert((getSize() >= SubRC.getSize() * 8) && "Size is not big enough for all the subclasses!"); assert(covers(SubRC) && "Not all subclasses are covered"); } } return true; }
AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI) : RegisterBankInfo(AArch64::NumRegisterBanks) { // Initialize the GPR bank. createRegisterBank(AArch64::GPRRegBankID, "GPR"); // The GPR register bank is fully defined by all the registers in // GR64all + its subclasses. addRegBankCoverage(AArch64::GPRRegBankID, AArch64::GPR64allRegClassID, TRI); const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID); (void)RBGPR; assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) && "Subclass not added?"); assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit"); // Initialize the FPR bank. createRegisterBank(AArch64::FPRRegBankID, "FPR"); // The FPR register bank is fully defined by all the registers in // GR64all + its subclasses. addRegBankCoverage(AArch64::FPRRegBankID, AArch64::QQQQRegClassID, TRI); const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID); (void)RBFPR; assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) && "Subclass not added?"); assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) && "Subclass not added?"); assert(RBFPR.getSize() == 512 && "FPRs should hold up to 512-bit via QQQQ sequence"); // Initialize the CCR bank. createRegisterBank(AArch64::CCRRegBankID, "CCR"); addRegBankCoverage(AArch64::CCRRegBankID, AArch64::CCRRegClassID, TRI); const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID); (void)RBCCR; assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) && "Class not added?"); assert(RBCCR.getSize() == 32 && "CCR should hold up to 32-bit"); verify(TRI); }
X86RegisterBankInfo::X86RegisterBankInfo(const TargetRegisterInfo &TRI) : X86GenRegisterBankInfo() { // validate RegBank initialization. const RegisterBank &RBGPR = getRegBank(X86::GPRRegBankID); (void)RBGPR; assert(&X86::GPRRegBank == &RBGPR && "Incorrect RegBanks inizalization."); // The GPR register bank is fully defined by all the registers in // GR64 + its subclasses. assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) && "Subclass not added?"); assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit"); }
ARMRegisterBankInfo::ARMRegisterBankInfo(const TargetRegisterInfo &TRI) : ARMGenRegisterBankInfo() { static bool AlreadyInit = false; // We have only one set of register banks, whatever the subtarget // is. Therefore, the initialization of the RegBanks table should be // done only once. Indeed the table of all register banks // (ARM::RegBanks) is unique in the compiler. At some point, it // will get tablegen'ed and the whole constructor becomes empty. if (AlreadyInit) return; AlreadyInit = true; const RegisterBank &RBGPR = getRegBank(ARM::GPRRegBankID); (void)RBGPR; assert(&ARM::GPRRegBank == &RBGPR && "The order in RegBanks is messed up"); // Initialize the GPR bank. assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRRegClassID)) && "Subclass not added?"); assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRwithAPSRRegClassID)) && "Subclass not added?"); assert(RBGPR.covers(*TRI.getRegClass(ARM::GPRnopcRegClassID)) && "Subclass not added?"); assert(RBGPR.covers(*TRI.getRegClass(ARM::rGPRRegClassID)) && "Subclass not added?"); assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPRRegClassID)) && "Subclass not added?"); assert(RBGPR.covers(*TRI.getRegClass(ARM::tcGPRRegClassID)) && "Subclass not added?"); assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPR_and_tcGPRRegClassID)) && "Subclass not added?"); assert(RBGPR.getSize() == 32 && "GPRs should hold up to 32-bit"); #ifndef NDEBUG ARM::checkPartialMappings(); ARM::checkValueMappings(); #endif }
AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI) : RegisterBankInfo(AArch64::RegBanks, AArch64::NumRegisterBanks) { static bool AlreadyInit = false; // We have only one set of register banks, whatever the subtarget // is. Therefore, the initialization of the RegBanks table should be // done only once. Indeed the table of all register banks // (AArch64::RegBanks) is unique in the compiler. At some point, it // will get tablegen'ed and the whole constructor becomes empty. if (AlreadyInit) return; AlreadyInit = true; // Initialize the GPR bank. createRegisterBank(AArch64::GPRRegBankID, "GPR"); // The GPR register bank is fully defined by all the registers in // GR64all + its subclasses. addRegBankCoverage(AArch64::GPRRegBankID, AArch64::GPR64allRegClassID, TRI); const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID); (void)RBGPR; assert(&AArch64::GPRRegBank == &RBGPR && "The order in RegBanks is messed up"); assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) && "Subclass not added?"); assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit"); // Initialize the FPR bank. createRegisterBank(AArch64::FPRRegBankID, "FPR"); // The FPR register bank is fully defined by all the registers in // GR64all + its subclasses. addRegBankCoverage(AArch64::FPRRegBankID, AArch64::QQQQRegClassID, TRI); const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID); (void)RBFPR; assert(&AArch64::FPRRegBank == &RBFPR && "The order in RegBanks is messed up"); assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) && "Subclass not added?"); assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) && "Subclass not added?"); assert(RBFPR.getSize() == 512 && "FPRs should hold up to 512-bit via QQQQ sequence"); // Initialize the CCR bank. createRegisterBank(AArch64::CCRRegBankID, "CCR"); addRegBankCoverage(AArch64::CCRRegBankID, AArch64::CCRRegClassID, TRI); const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID); (void)RBCCR; assert(&AArch64::CCRRegBank == &RBCCR && "The order in RegBanks is messed up"); assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) && "Class not added?"); assert(RBCCR.getSize() == 32 && "CCR should hold up to 32-bit"); // Check that the TableGen'ed like file is in sync we our expectations. // First, the Idx. assert(AArch64::PartialMappingIdx::GPR32 == AArch64::PartialMappingIdx::FirstGPR && "GPR32 index not first in the GPR list"); assert(AArch64::PartialMappingIdx::GPR64 == AArch64::PartialMappingIdx::LastGPR && "GPR64 index not last in the GPR list"); assert(AArch64::PartialMappingIdx::FirstGPR <= AArch64::PartialMappingIdx::LastGPR && "GPR list is backward"); assert(AArch64::PartialMappingIdx::FPR32 == AArch64::PartialMappingIdx::FirstFPR && "FPR32 index not first in the FPR list"); assert(AArch64::PartialMappingIdx::FPR512 == AArch64::PartialMappingIdx::LastFPR && "FPR512 index not last in the FPR list"); assert(AArch64::PartialMappingIdx::FirstFPR <= AArch64::PartialMappingIdx::LastFPR && "FPR list is backward"); assert(AArch64::PartialMappingIdx::FPR32 + 1 == AArch64::PartialMappingIdx::FPR64 && AArch64::PartialMappingIdx::FPR64 + 1 == AArch64::PartialMappingIdx::FPR128 && AArch64::PartialMappingIdx::FPR128 + 1 == AArch64::PartialMappingIdx::FPR256 && AArch64::PartialMappingIdx::FPR256 + 1 == AArch64::PartialMappingIdx::FPR512 && "FPR indices not properly ordered"); // Now, the content. #define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \ do { \ const PartialMapping &Map = \ AArch64::PartMappings[AArch64::PartialMappingIdx::Idx]; \ (void) Map; \ assert(Map.StartIdx == ValStartIdx && Map.Length == ValLength && \ Map.RegBank == &RB && #Idx " is incorrectly initialized"); \ } while (0) CHECK_PARTIALMAP(GPR32, 0, 32, RBGPR); CHECK_PARTIALMAP(GPR64, 0, 64, RBGPR); CHECK_PARTIALMAP(FPR32, 0, 32, RBFPR); CHECK_PARTIALMAP(FPR64, 0, 64, RBFPR); CHECK_PARTIALMAP(FPR128, 0, 128, RBFPR); CHECK_PARTIALMAP(FPR256, 0, 256, RBFPR); CHECK_PARTIALMAP(FPR512, 0, 512, RBFPR); assert(verify(TRI) && "Invalid register bank information"); }
AArch64RegisterBankInfo::AArch64RegisterBankInfo(const TargetRegisterInfo &TRI) : AArch64GenRegisterBankInfo() { static bool AlreadyInit = false; // We have only one set of register banks, whatever the subtarget // is. Therefore, the initialization of the RegBanks table should be // done only once. Indeed the table of all register banks // (AArch64::RegBanks) is unique in the compiler. At some point, it // will get tablegen'ed and the whole constructor becomes empty. if (AlreadyInit) return; AlreadyInit = true; const RegisterBank &RBGPR = getRegBank(AArch64::GPRRegBankID); (void)RBGPR; assert(&AArch64::GPRRegBank == &RBGPR && "The order in RegBanks is messed up"); const RegisterBank &RBFPR = getRegBank(AArch64::FPRRegBankID); (void)RBFPR; assert(&AArch64::FPRRegBank == &RBFPR && "The order in RegBanks is messed up"); const RegisterBank &RBCCR = getRegBank(AArch64::CCRRegBankID); (void)RBCCR; assert(&AArch64::CCRRegBank == &RBCCR && "The order in RegBanks is messed up"); // The GPR register bank is fully defined by all the registers in // GR64all + its subclasses. assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) && "Subclass not added?"); assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit"); // The FPR register bank is fully defined by all the registers in // GR64all + its subclasses. assert(RBFPR.covers(*TRI.getRegClass(AArch64::QQRegClassID)) && "Subclass not added?"); assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) && "Subclass not added?"); assert(RBFPR.getSize() == 512 && "FPRs should hold up to 512-bit via QQQQ sequence"); assert(RBCCR.covers(*TRI.getRegClass(AArch64::CCRRegClassID)) && "Class not added?"); assert(RBCCR.getSize() == 32 && "CCR should hold up to 32-bit"); // Check that the TableGen'ed like file is in sync we our expectations. // First, the Idx. assert(checkPartialMappingIdx(PMI_FirstGPR, PMI_LastGPR, {PMI_GPR32, PMI_GPR64}) && "PartialMappingIdx's are incorrectly ordered"); assert(checkPartialMappingIdx( PMI_FirstFPR, PMI_LastFPR, {PMI_FPR32, PMI_FPR64, PMI_FPR128, PMI_FPR256, PMI_FPR512}) && "PartialMappingIdx's are incorrectly ordered"); // Now, the content. // Check partial mapping. #define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \ do { \ assert( \ checkPartialMap(PartialMappingIdx::Idx, ValStartIdx, ValLength, RB) && \ #Idx " is incorrectly initialized"); \ } while (false) CHECK_PARTIALMAP(PMI_GPR32, 0, 32, RBGPR); CHECK_PARTIALMAP(PMI_GPR64, 0, 64, RBGPR); CHECK_PARTIALMAP(PMI_FPR32, 0, 32, RBFPR); CHECK_PARTIALMAP(PMI_FPR64, 0, 64, RBFPR); CHECK_PARTIALMAP(PMI_FPR128, 0, 128, RBFPR); CHECK_PARTIALMAP(PMI_FPR256, 0, 256, RBFPR); CHECK_PARTIALMAP(PMI_FPR512, 0, 512, RBFPR); // Check value mapping. #define CHECK_VALUEMAP_IMPL(RBName, Size, Offset) \ do { \ assert(checkValueMapImpl(PartialMappingIdx::PMI_##RBName##Size, \ PartialMappingIdx::PMI_First##RBName, Size, \ Offset) && \ #RBName #Size " " #Offset " is incorrectly initialized"); \ } while (false) #define CHECK_VALUEMAP(RBName, Size) CHECK_VALUEMAP_IMPL(RBName, Size, 0) CHECK_VALUEMAP(GPR, 32); CHECK_VALUEMAP(GPR, 64); CHECK_VALUEMAP(FPR, 32); CHECK_VALUEMAP(FPR, 64); CHECK_VALUEMAP(FPR, 128); CHECK_VALUEMAP(FPR, 256); CHECK_VALUEMAP(FPR, 512); // Check the value mapping for 3-operands instructions where all the operands // map to the same value mapping. #define CHECK_VALUEMAP_3OPS(RBName, Size) \ do { \ CHECK_VALUEMAP_IMPL(RBName, Size, 0); \ CHECK_VALUEMAP_IMPL(RBName, Size, 1); \ CHECK_VALUEMAP_IMPL(RBName, Size, 2); \ } while (false) CHECK_VALUEMAP_3OPS(GPR, 32); CHECK_VALUEMAP_3OPS(GPR, 64); CHECK_VALUEMAP_3OPS(FPR, 32); CHECK_VALUEMAP_3OPS(FPR, 64); CHECK_VALUEMAP_3OPS(FPR, 128); CHECK_VALUEMAP_3OPS(FPR, 256); CHECK_VALUEMAP_3OPS(FPR, 512); #define CHECK_VALUEMAP_CROSSREGCPY(RBNameDst, RBNameSrc, Size) \ do { \ unsigned PartialMapDstIdx = PMI_##RBNameDst##Size - PMI_Min; \ unsigned PartialMapSrcIdx = PMI_##RBNameSrc##Size - PMI_Min; \ (void)PartialMapDstIdx; \ (void)PartialMapSrcIdx; \ const ValueMapping *Map = getCopyMapping( \ AArch64::RBNameDst##RegBankID, AArch64::RBNameSrc##RegBankID, Size); \ (void)Map; \ assert(Map[0].BreakDown == \ &AArch64GenRegisterBankInfo::PartMappings[PartialMapDstIdx] && \ Map[0].NumBreakDowns == 1 && #RBNameDst #Size \ " Dst is incorrectly initialized"); \ assert(Map[1].BreakDown == \ &AArch64GenRegisterBankInfo::PartMappings[PartialMapSrcIdx] && \ Map[1].NumBreakDowns == 1 && #RBNameSrc #Size \ " Src is incorrectly initialized"); \ \ } while (false) CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 32); CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 32); CHECK_VALUEMAP_CROSSREGCPY(GPR, GPR, 64); CHECK_VALUEMAP_CROSSREGCPY(GPR, FPR, 64); CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 32); CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 32); CHECK_VALUEMAP_CROSSREGCPY(FPR, FPR, 64); CHECK_VALUEMAP_CROSSREGCPY(FPR, GPR, 64); assert(verify(TRI) && "Invalid register bank information"); }
void RegisterBankInfo::addRegBankCoverage(unsigned ID, unsigned RCId, const TargetRegisterInfo &TRI, bool AddTypeMapping) { RegisterBank &RB = getRegBank(ID); unsigned NbOfRegClasses = TRI.getNumRegClasses(); DEBUG(dbgs() << "Add coverage for: " << RB << '\n'); // Check if RB is underconstruction. if (!RB.isValid()) RB.ContainedRegClasses.resize(NbOfRegClasses); else if (RB.covers(*TRI.getRegClass(RCId))) // If RB already covers this register class, there is nothing // to do. return; BitVector &Covered = RB.ContainedRegClasses; SmallVector<unsigned, 8> WorkList; WorkList.push_back(RCId); Covered.set(RCId); unsigned &MaxSize = RB.Size; do { unsigned RCId = WorkList.pop_back_val(); const TargetRegisterClass &CurRC = *TRI.getRegClass(RCId); DEBUG(dbgs() << "Examine: " << TRI.getRegClassName(&CurRC) << "(Size*8: " << (CurRC.getSize() * 8) << ")\n"); // Remember the biggest size in bits. MaxSize = std::max(MaxSize, CurRC.getSize() * 8); // If we have been asked to record the type supported by this // register bank, do it now. if (AddTypeMapping) for (MVT::SimpleValueType SVT : make_range(CurRC.vt_begin(), CurRC.vt_end())) recordRegBankForType(getRegBank(ID), SVT); // Walk through all sub register classes and push them into the worklist. bool First = true; for (BitMaskClassIterator It(CurRC.getSubClassMask(), TRI); It.isValid(); ++It) { unsigned SubRCId = It.getID(); if (!Covered.test(SubRCId)) { if (First) DEBUG(dbgs() << " Enqueue sub-class: "); DEBUG(dbgs() << TRI.getRegClassName(TRI.getRegClass(SubRCId)) << ", "); WorkList.push_back(SubRCId); // Remember that we saw the sub class. Covered.set(SubRCId); First = false; } } if (!First) DEBUG(dbgs() << '\n'); // Push also all the register classes that can be accessed via a // subreg index, i.e., its subreg-class (which is different than // its subclass). // // Note: It would probably be faster to go the other way around // and have this method add only super classes, since this // information is available in a more efficient way. However, it // feels less natural for the client of this APIs plus we will // TableGen the whole bitset at some point, so compile time for // the initialization is not very important. First = true; for (unsigned SubRCId = 0; SubRCId < NbOfRegClasses; ++SubRCId) { if (Covered.test(SubRCId)) continue; bool Pushed = false; const TargetRegisterClass *SubRC = TRI.getRegClass(SubRCId); for (SuperRegClassIterator SuperRCIt(SubRC, &TRI); SuperRCIt.isValid(); ++SuperRCIt) { if (Pushed) break; for (BitMaskClassIterator It(SuperRCIt.getMask(), TRI); It.isValid(); ++It) { unsigned SuperRCId = It.getID(); if (SuperRCId == RCId) { if (First) DEBUG(dbgs() << " Enqueue subreg-class: "); DEBUG(dbgs() << TRI.getRegClassName(SubRC) << ", "); WorkList.push_back(SubRCId); // Remember that we saw the sub class. Covered.set(SubRCId); Pushed = true; First = false; break; } } } } if (!First) DEBUG(dbgs() << '\n'); } while (!WorkList.empty()); }