[CodeGen][NFC] Remove RegisterClasses pointer array (#207204)

All MCRegisterClasses are stored consecutively in memory. Therefore, we
can remove the RegisterClassses pointer array and save 17kiB in
.data.rel.ro.
This commit is contained in:
Alexis Engelke 2026-07-03 08:33:37 +02:00 committed by GitHub
parent 51e0c89315
commit 4d8ec19680
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
18 changed files with 78 additions and 115 deletions

View file

@ -71,7 +71,6 @@ struct RegClassWeight {
///
class LLVM_ABI TargetRegisterInfo : public MCRegisterInfo {
public:
using regclass_iterator = const TargetRegisterClass * const *;
using vt_iterator = const MVT::SimpleValueType *;
struct RegClassInfo {
unsigned RegSize, SpillSize, SpillAlignment;
@ -95,7 +94,6 @@ private:
// Pointer to array of lane masks, one per sub-reg index.
const LaneBitmask *SubRegIndexLaneMasks;
regclass_iterator RegClassBegin, RegClassEnd; // List of regclasses
LaneBitmask CoveringLanes;
const RegClassInfo *const RCInfos;
const MVT::SimpleValueType *const RCVTLists;
@ -103,7 +101,6 @@ private:
protected:
TargetRegisterInfo(const TargetRegisterInfoDesc *ID,
ArrayRef<const TargetRegisterClass *> RegisterClasses,
const char *SubRegIndexStrings,
ArrayRef<uint32_t> SubRegIndexNameOffsets,
const SubRegCoveredBits *SubRegIdxRanges,
@ -494,13 +491,6 @@ public:
/// remove pseudo-registers that should be ignored).
virtual void adjustStackMapLiveOutMask(uint32_t *Mask) const {}
/// Return a super-register of register \p Reg such that its sub-register of
/// index \p SubIdx is \p Reg.
MCRegister getMatchingSuperReg(MCRegister Reg, unsigned SubIdx,
const TargetRegisterClass *RC) const {
return MCRegisterInfo::getMatchingSuperReg(Reg, SubIdx, RC);
}
/// Return a subclass of the register class \p A so that each register in it
/// has a sub-register of sub-register index \p Idx which is in the register
/// class \p B.
@ -713,27 +703,10 @@ protected:
}
public:
/// Register class iterators
regclass_iterator regclass_begin() const { return RegClassBegin; }
regclass_iterator regclass_end() const { return RegClassEnd; }
iterator_range<regclass_iterator> regclasses() const {
return make_range(regclass_begin(), regclass_end());
}
unsigned getNumRegClasses() const {
return (unsigned)(regclass_end()-regclass_begin());
}
/// Returns the register class associated with the enumeration value.
/// See class MCOperandInfo.
const TargetRegisterClass *getRegClass(unsigned i) const {
assert(i < getNumRegClasses() && "Register Class ID out of range");
return RegClassBegin[i];
}
/// Returns the name of the register class.
const char *getRegClassName(const TargetRegisterClass *Class) const {
return MCRegisterInfo::getRegClassName(Class);
return &MCRegisterInfo::getRegClass(i);
}
/// Find the largest common subclass of A and B.

View file

@ -1078,8 +1078,8 @@ MLocTracker::MLocTracker(MachineFunction &MF, const TargetInstrInfo &TII,
}
// There may also be strange register class sizes (think x86 fp80s).
for (const TargetRegisterClass *RC : TRI.regclasses()) {
unsigned Size = TRI.getRegSizeInBits(*RC);
for (const TargetRegisterClass &RC : TRI.regclasses()) {
unsigned Size = TRI.getRegSizeInBits(RC);
// We might see special reserved values as sizes, and classes for other
// stuff the machine tries to model. If it's more than 512 bits, then it
@ -1590,9 +1590,9 @@ std::optional<ValueIDNum> InstrRefBasedLDV::getValueForInstrRef(
// FIXME: no index for this?
Register Reg = MTracker->LocIdxToLocID[L];
const TargetRegisterClass *TRC = nullptr;
for (const auto *TRCI : TRI->regclasses())
if (TRCI->contains(Reg))
TRC = TRCI;
for (const auto &TRCI : TRI->regclasses())
if (TRCI.contains(Reg))
TRC = &TRCI;
assert(TRC && "Couldn't find target register class?");
// If the register we have isn't the right size or in the right place,

View file

@ -743,10 +743,10 @@ bool MachineCopyPropagation::isForwardableRegClassCopy(const MachineInstr &Copy,
MCRegister UseDst = getDstMCReg(*UseICopyOperands);
bool Found = false;
bool IsCrossClass = false;
for (const TargetRegisterClass *RC : TRI->regclasses()) {
if (RC->contains(CopySrc) && RC->contains(UseDst)) {
for (const TargetRegisterClass &RC : TRI->regclasses()) {
if (RC.contains(CopySrc) && RC.contains(UseDst)) {
Found = true;
if (TRI->getCrossCopyRegClass(RC) != RC) {
if (TRI->getCrossCopyRegClass(&RC) != &RC) {
IsCrossClass = true;
break;
}
@ -759,9 +759,9 @@ bool MachineCopyPropagation::isForwardableRegClassCopy(const MachineInstr &Copy,
// The forwarded copy would be cross-class. Only do this if the original copy
// was also cross-class.
MCRegister CopyDst = getDstMCReg(CopyOperands);
for (const TargetRegisterClass *RC : TRI->regclasses()) {
if (RC->contains(CopySrc) && RC->contains(CopyDst) &&
TRI->getCrossCopyRegClass(RC) != RC)
for (const TargetRegisterClass &RC : TRI->regclasses()) {
if (RC.contains(CopySrc) && RC.contains(CopyDst) &&
TRI->getCrossCopyRegClass(&RC) != &RC)
return true;
}
return false;

View file

@ -108,8 +108,8 @@ static bool hasPhysRegClassForType(const TargetRegisterInfo &TRI,
if (TRI.isTypeLegalForClass(*RC, Ty))
return true;
return llvm::any_of(TRI.regclasses(), [&](const TargetRegisterClass *RC) {
return RC->contains(Reg) && TRI.isTypeLegalForClass(*RC, Ty);
return llvm::any_of(TRI.regclasses(), [&](const TargetRegisterClass &RC) {
return RC.contains(Reg) && TRI.isTypeLegalForClass(RC, Ty);
});
}

View file

@ -31,16 +31,16 @@ PhysicalRegisterInfo::PhysicalRegisterInfo(const TargetRegisterInfo &tri,
RegInfos.resize(TRI.getNumRegs());
BitVector BadRC(TRI.getNumRegs());
for (const TargetRegisterClass *RC : TRI.regclasses()) {
for (MCPhysReg R : *RC) {
for (const TargetRegisterClass &RC : TRI.regclasses()) {
for (MCPhysReg R : RC) {
RegInfo &RI = RegInfos[R];
if (RI.RegClass != nullptr && !BadRC[R]) {
if (RC->LaneMask != RI.RegClass->LaneMask) {
if (RC.LaneMask != RI.RegClass->LaneMask) {
BadRC.set(R);
RI.RegClass = nullptr;
}
} else
RI.RegClass = RC;
RI.RegClass = &RC;
}
}

View file

@ -205,8 +205,8 @@ void RegisterClassInfo::compute(const TargetRegisterClass *RC) const {
unsigned RegisterClassInfo::computePSetLimit(unsigned Idx) const {
const TargetRegisterClass *RC = nullptr;
unsigned NumRCUnits = 0;
for (const TargetRegisterClass *C : TRI->regclasses()) {
const int *PSetID = TRI->getRegClassPressureSets(C);
for (const TargetRegisterClass &C : TRI->regclasses()) {
const int *PSetID = TRI->getRegClassPressureSets(&C);
for (; *PSetID != -1; ++PSetID) {
if ((unsigned)*PSetID == Idx)
break;
@ -216,9 +216,9 @@ unsigned RegisterClassInfo::computePSetLimit(unsigned Idx) const {
// Found a register class that counts against this pressure set.
// For efficiency, only compute the set order for the largest set.
unsigned NUnits = TRI->getRegClassWeight(C).WeightLimit;
unsigned NUnits = TRI->getRegClassWeight(&C).WeightLimit;
if (!RC || NUnits > NumRCUnits) {
RC = C;
RC = &C;
NumRCUnits = NUnits;
}
}

View file

@ -56,8 +56,8 @@ ResourcePriorityQueue::ResourcePriorityQueue(SelectionDAGISel *IS)
RegPressure.resize(NumRC);
llvm::fill(RegLimit, 0);
llvm::fill(RegPressure, 0);
for (const TargetRegisterClass *RC : TRI->regclasses())
RegLimit[RC->getID()] = TRI->getRegPressureLimit(RC, *IS->MF);
for (const TargetRegisterClass &RC : TRI->regclasses())
RegLimit[RC.getID()] = TRI->getRegPressureLimit(&RC, *IS->MF);
ParallelLiveRanges = 0;
HorizontalVerticalBalance = 0;
@ -358,16 +358,15 @@ int ResourcePriorityQueue::regPressureDelta(SUnit *SU, bool RawPressure) {
return RegBalance;
if (RawPressure) {
for (const TargetRegisterClass *RC : TRI->regclasses())
RegBalance += rawRegPressureDelta(SU, RC->getID());
for (const TargetRegisterClass &RC : TRI->regclasses())
RegBalance += rawRegPressureDelta(SU, RC.getID());
}
else {
for (const TargetRegisterClass *RC : TRI->regclasses()) {
if ((RegPressure[RC->getID()] +
rawRegPressureDelta(SU, RC->getID()) > 0) &&
(RegPressure[RC->getID()] +
rawRegPressureDelta(SU, RC->getID()) >= RegLimit[RC->getID()]))
RegBalance += rawRegPressureDelta(SU, RC->getID());
for (const TargetRegisterClass &RC : TRI->regclasses()) {
if ((RegPressure[RC.getID()] + rawRegPressureDelta(SU, RC.getID()) > 0) &&
(RegPressure[RC.getID()] + rawRegPressureDelta(SU, RC.getID()) >=
RegLimit[RC.getID()]))
RegBalance += rawRegPressureDelta(SU, RC.getID());
}
}

View file

@ -1747,8 +1747,8 @@ public:
RegPressure.resize(NumRC);
llvm::fill(RegLimit, 0);
llvm::fill(RegPressure, 0);
for (const TargetRegisterClass *RC : TRI->regclasses())
RegLimit[RC->getID()] = tri->getRegPressureLimit(RC, MF);
for (const TargetRegisterClass &RC : TRI->regclasses())
RegLimit[RC.getID()] = tri->getRegPressureLimit(&RC, MF);
}
}
@ -2056,11 +2056,11 @@ unsigned RegReductionPQBase::getNodePriority(const SUnit *SU) const {
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
LLVM_DUMP_METHOD void RegReductionPQBase::dumpRegPressure() const {
for (const TargetRegisterClass *RC : TRI->regclasses()) {
unsigned Id = RC->getID();
for (const TargetRegisterClass &RC : TRI->regclasses()) {
unsigned Id = RC.getID();
unsigned RP = RegPressure[Id];
if (!RP) continue;
LLVM_DEBUG(dbgs() << TRI->getRegClassName(RC) << ": " << RP << " / "
LLVM_DEBUG(dbgs() << TRI->getRegClassName(&RC) << ": " << RP << " / "
<< RegLimit[Id] << '\n');
}
}

View file

@ -5988,21 +5988,21 @@ TargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *RI,
std::make_pair(0u, static_cast<const TargetRegisterClass *>(nullptr));
// Figure out which register class contains this reg.
for (const TargetRegisterClass *RC : RI->regclasses()) {
for (const TargetRegisterClass &RC : RI->regclasses()) {
// If none of the value types for this register class are valid, we
// can't use it. For example, 64-bit reg classes on 32-bit targets.
if (!isLegalRC(*RI, *RC))
if (!isLegalRC(*RI, RC))
continue;
for (const MCPhysReg &PR : *RC) {
for (const MCPhysReg &PR : RC) {
if (RegName.equals_insensitive(RI->getRegAsmName(PR))) {
std::pair<unsigned, const TargetRegisterClass *> S =
std::make_pair(PR, RC);
std::make_pair(PR, &RC);
// If this register class has the requested value type, return it,
// otherwise keep searching and return the first class found
// if no other is found which explicitly has the requested type.
if (RI->isTypeLegalForClass(*RC, VT))
if (RI->isTypeLegalForClass(RC, VT))
return S;
if (!R.second)
R = S;

View file

@ -50,9 +50,8 @@ static cl::opt<unsigned>
cl::init(5000));
TargetRegisterInfo::TargetRegisterInfo(
const TargetRegisterInfoDesc *ID,
ArrayRef<const TargetRegisterClass *> RegisterClasses,
const char *SubRegIndexStrings, ArrayRef<uint32_t> SubRegIndexNameOffsets,
const TargetRegisterInfoDesc *ID, const char *SubRegIndexStrings,
ArrayRef<uint32_t> SubRegIndexNameOffsets,
const SubRegCoveredBits *SubRegIdxRanges,
const LaneBitmask *SubRegIndexLaneMasks, LaneBitmask CoveringLanes,
const RegClassInfo *const RCInfos,
@ -60,9 +59,7 @@ TargetRegisterInfo::TargetRegisterInfo(
: InfoDesc(ID), SubRegIndexStrings(SubRegIndexStrings),
SubRegIndexNameOffsets(SubRegIndexNameOffsets),
SubRegIdxRanges(SubRegIdxRanges),
SubRegIndexLaneMasks(SubRegIndexLaneMasks),
RegClassBegin(RegisterClasses.begin()),
RegClassEnd(RegisterClasses.end()), CoveringLanes(CoveringLanes),
SubRegIndexLaneMasks(SubRegIndexLaneMasks), CoveringLanes(CoveringLanes),
RCInfos(RCInfos), RCVTLists(RCVTLists), HwMode(Mode) {}
TargetRegisterInfo::~TargetRegisterInfo() = default;
@ -212,9 +209,9 @@ getCommonMinimalPhysRegClass(const TargetRegisterInfo *TRI, MCRegister Reg1,
// Pick the most specific register class that contains both physregs.
const TargetRegisterClass *BestRC = nullptr;
for (const TargetRegisterClass *RC : TRI->regclasses()) {
if (RC->contains(Reg1, Reg2) && (!BestRC || BestRC->hasSubClass(RC)))
BestRC = RC;
for (const TargetRegisterClass &RC : TRI->regclasses()) {
if (RC.contains(Reg1, Reg2) && (!BestRC || BestRC->hasSubClass(&RC)))
BestRC = &RC;
}
assert(BestRC && "Couldn't find the register class");
@ -247,9 +244,9 @@ BitVector TargetRegisterInfo::getAllocatableSet(const MachineFunction &MF,
if (SubClass)
getAllocatableSetForRC(MF, SubClass, Allocatable);
} else {
for (const TargetRegisterClass *C : regclasses())
if (C->isAllocatable())
getAllocatableSetForRC(MF, C, Allocatable);
for (const TargetRegisterClass &C : regclasses())
if (C.isAllocatable())
getAllocatableSetForRC(MF, &C, Allocatable);
}
// Mask out the reserved registers

View file

@ -645,10 +645,10 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
//
unsigned MaxNumSGPRs = ST.getMaxNumSGPRs(MF);
unsigned TotalNumSGPRs = AMDGPU::SGPR_32RegClass.getNumRegs();
for (const TargetRegisterClass *RC : regclasses()) {
if (RC->isBaseClass() && isSGPRClass(RC)) {
unsigned NumRegs = divideCeil(getRegSizeInBits(*RC), 32);
for (MCPhysReg Reg : *RC) {
for (const TargetRegisterClass &RC : regclasses()) {
if (RC.isBaseClass() && isSGPRClass(&RC)) {
unsigned NumRegs = divideCeil(getRegSizeInBits(RC), 32);
for (MCPhysReg Reg : RC) {
unsigned Index = getHWRegIndex(Reg);
if (Index + NumRegs > MaxNumSGPRs && Index < TotalNumSGPRs &&
Reg != AMDGPU::VCC_LO && Reg != AMDGPU::VCC_HI &&
@ -701,10 +701,10 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
//
auto [MaxNumVGPRs, MaxNumAGPRs] = ST.getMaxNumVectorRegs(MF.getFunction());
for (const TargetRegisterClass *RC : regclasses()) {
if (RC->isBaseClass() && isVGPRClass(RC)) {
unsigned NumRegs = divideCeil(getRegSizeInBits(*RC), 32);
for (MCPhysReg Reg : *RC) {
for (const TargetRegisterClass &RC : regclasses()) {
if (RC.isBaseClass() && isVGPRClass(&RC)) {
unsigned NumRegs = divideCeil(getRegSizeInBits(RC), 32);
for (MCPhysReg Reg : RC) {
unsigned Index = getHWRegIndex(Reg);
if (Index + NumRegs > MaxNumVGPRs)
Reserved.set(Reg);
@ -715,10 +715,10 @@ BitVector SIRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
// Reserve all the AGPRs if there are no instructions to use it.
if (!ST.hasMAIInsts())
MaxNumAGPRs = 0;
for (const TargetRegisterClass *RC : regclasses()) {
if (RC->isBaseClass() && isAGPRClass(RC)) {
unsigned NumRegs = divideCeil(getRegSizeInBits(*RC), 32);
for (MCPhysReg Reg : *RC) {
for (const TargetRegisterClass &RC : regclasses()) {
if (RC.isBaseClass() && isAGPRClass(&RC)) {
unsigned NumRegs = divideCeil(getRegSizeInBits(RC), 32);
for (MCPhysReg Reg : RC) {
unsigned Index = getHWRegIndex(Reg);
if (Index + NumRegs > MaxNumAGPRs)
Reserved.set(Reg);

View file

@ -219,10 +219,10 @@ HexagonBlockRanges::HexagonBlockRanges(MachineFunction &mf)
TII(*HST.getInstrInfo()), TRI(*HST.getRegisterInfo()),
Reserved(TRI.getReservedRegs(mf)) {
// Consider all non-allocatable registers as reserved.
for (const TargetRegisterClass *RC : TRI.regclasses()) {
if (RC->isAllocatable())
for (const TargetRegisterClass &RC : TRI.regclasses()) {
if (RC.isAllocatable())
continue;
for (unsigned R : *RC)
for (unsigned R : RC)
Reserved[R] = true;
}
}

View file

@ -1663,13 +1663,13 @@ void NVPTXAsmPrinter::setAndEmitFunctionVirtualRegisters(
// Emit declaration of the virtual registers or 'physical' registers for
// each register class
for (const TargetRegisterClass *RC : TRI->regclasses()) {
const unsigned N = VRegMapping[RC].size();
for (const TargetRegisterClass &RC : TRI->regclasses()) {
const unsigned N = VRegMapping[&RC].size();
// Only declare those registers that may be used.
if (N) {
const StringRef RCName = getNVPTXRegClassName(RC);
const StringRef RCStr = getNVPTXRegClassStr(RC);
const StringRef RCName = getNVPTXRegClassName(&RC);
const StringRef RCStr = getNVPTXRegClassStr(&RC);
O << "\t.reg " << RCName << " \t" << RCStr << "<" << (N + 1) << ">;\n";
}
}

View file

@ -31,4 +31,4 @@ def MyTarget : Target;
// CHECK: static const TargetRegisterInfoDesc MyTargetRegInfoDesc = { // Extra Descriptors
// CHECK-NEXT: MyTargetCostPerUseTable, 2, MyTargetInAllocatableClassTable};
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc, MyTargetRegisterClasses,
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc,

View file

@ -49,4 +49,4 @@ def MyTarget : Target;
// CHECK: static const TargetRegisterInfoDesc MyTargetRegInfoDesc = { // Extra Descriptors
// CHECK-NEXT: MyTargetCostPerUseTable, 2, MyTargetInAllocatableClassTable};
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc, MyTargetRegisterClasses,
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc,

View file

@ -33,4 +33,4 @@ def MyTarget : Target;
// CHECK: static const TargetRegisterInfoDesc MyTargetRegInfoDesc = { // Extra Descriptors
// CHECK-NEXT: MyTargetCostPerUseTable, 1, MyTargetInAllocatableClassTable};
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc, MyTargetRegisterClasses,
// CHECK: TargetRegisterInfo(&MyTargetRegInfoDesc,

View file

@ -23,7 +23,7 @@ protected:
class BogusRegisterInfo : public TargetRegisterInfo {
public:
BogusRegisterInfo()
: TargetRegisterInfo(nullptr, {}, nullptr, {}, nullptr, nullptr,
: TargetRegisterInfo(nullptr, nullptr, {}, nullptr, nullptr,
LaneBitmask(~0u), nullptr, nullptr) {
InitMCRegisterInfo(nullptr, 0, 0, 0, nullptr, 0, nullptr, 0, nullptr,
nullptr, nullptr, nullptr, nullptr, 0, nullptr);

View file

@ -1590,12 +1590,6 @@ void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, raw_ostream &MainOS,
}
}
OS << "static const TargetRegisterClass *const " << TargetName
<< "RegisterClasses[] = {\n";
for (const auto &RC : RegisterClasses)
OS << " &" << RC.getQualifiedName() << "RegClass,\n";
OS << " };\n";
// Emit extra information about registers.
const auto &Regs = RegBank.getRegisters();
unsigned NumRegCosts = 1;
@ -1794,9 +1788,9 @@ void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, raw_ostream &MainOS,
" unsigned RCID = Mapping[Reg.id()];\n"
" if (RCID == InvalidRegClassID)\n"
" return nullptr;\n"
" return "
" return &"
<< TargetName
<< "RegisterClasses[RCID];\n"
<< "MCRegisterClassStorage.Classes[RCID];\n"
"}\n";
}
}
@ -1827,9 +1821,9 @@ void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, raw_ostream &MainOS,
" unsigned RCID = Mapping[Reg.id()];\n"
" if (RCID == InvalidRegClassID)\n"
" return nullptr;\n"
" return "
" return &"
<< TargetName
<< "RegisterClasses[RCID];\n"
<< "MCRegisterClassStorage.Classes[RCID];\n"
"}\n";
}
@ -1851,7 +1845,7 @@ void RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, raw_ostream &MainOS,
{0}::
{0}(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour,
unsigned PC, unsigned HwMode)
: TargetRegisterInfo(&{1}RegInfoDesc, {1}RegisterClasses,
: TargetRegisterInfo(&{1}RegInfoDesc,
{1}SubRegIndexStrings, {1}SubRegIndexNameOffsets,
{1}SubRegIdxRangeTable, {1}SubRegIndexLaneMaskTable,