This patch adds logic for determining RegisterBank size to RegisterBankInfo, which allows accounting for the HwMode of the target. Individual RegisterBanks cannot be constructed with HwMode information as construction is generated by TableGen, but a RegisterBankInfo subclass can provide the HwMode as a constructor argument. The HwMode is used to select the appropriate RegisterBank size from an array relating sizes to RegisterBanks.
Targets simply need to provide the HwMode argument to the <target>GenRegisterBankInfo constructor. The RISC-V RegisterBankInfo constructor has been updated accordingly (plus an unused argument removed).
Reviewed By: simoncook, craig.topper
Differential Revision: https://reviews.llvm.org/D76007
private:
unsigned ID;
const char *Name;
- unsigned Size;
BitVector ContainedRegClasses;
/// Sentinel value used to recognize register bank not properly
friend RegisterBankInfo;
public:
- RegisterBank(unsigned ID, const char *Name, unsigned Size,
- const uint32_t *CoveredClasses, unsigned NumRegClasses);
+ RegisterBank(unsigned ID, const char *Name, const uint32_t *CoveredClasses,
+ unsigned NumRegClasses);
/// Get the identifier of this register bank.
unsigned getID() const { return ID; }
/// Should be used only for debugging purposes.
const char *getName() const { return Name; }
- /// Get the maximal size in bits that fits in this register bank.
- unsigned getSize() const { return Size; }
-
/// Check whether this instance is ready to be used.
bool isValid() const;
/// \note This method does not check anything when assertions are disabled.
///
/// \return True is the check was successful.
- bool verify(const TargetRegisterInfo &TRI) const;
+ bool verify(const RegisterBankInfo &RBI, const TargetRegisterInfo &TRI) const;
/// Check whether this register bank covers \p RC.
/// In other words, check if this register bank fully covers
#include "llvm/ADT/iterator_range.h"
#include "llvm/CodeGen/LowLevelType.h"
#include "llvm/CodeGen/Register.h"
+#include "llvm/CodeGen/RegisterBank.h"
#include "llvm/Support/ErrorHandling.h"
#include <cassert>
#include <initializer_list>
class MachineInstr;
class MachineRegisterInfo;
class raw_ostream;
-class RegisterBank;
class TargetInstrInfo;
class TargetRegisterClass;
class TargetRegisterInfo;
/// \note This method does not check anything when assertions are disabled.
///
/// \return True is the check was successful.
- bool verify() const;
+ bool verify(const RegisterBankInfo &RBI) const;
};
/// Helper struct that represents how a value is mapped through
/// \note This method does not check anything when assertions are disabled.
///
/// \return True is the check was successful.
- bool verify(unsigned MeaningfulBitWidth) const;
+ bool verify(const RegisterBankInfo &RBI, unsigned MeaningfulBitWidth) const;
/// Print this on dbgs() stream.
void dump() const;
protected:
/// Hold the set of supported register banks.
- RegisterBank **RegBanks;
+ const RegisterBank **RegBanks;
/// Total number of register banks.
unsigned NumRegBanks;
+ /// Hold the sizes of the register banks for all HwModes.
+ const unsigned *Sizes;
+
+ /// Current HwMode for the target.
+ unsigned HwMode;
+
/// Keep dynamically allocated PartialMapping in a separate map.
/// This shouldn't be needed when everything gets TableGen'ed.
mutable DenseMap<unsigned, std::unique_ptr<const PartialMapping>>
/// Create a RegisterBankInfo that can accommodate up to \p NumRegBanks
/// RegisterBank instances.
- RegisterBankInfo(RegisterBank **RegBanks, unsigned NumRegBanks);
+ RegisterBankInfo(const RegisterBank **RegBanks, unsigned NumRegBanks,
+ const unsigned *Sizes, unsigned HwMode);
/// This constructor is meaningless.
/// It just provides a default constructor that can be used at link time
}
/// Get the register bank identified by \p ID.
- RegisterBank &getRegBank(unsigned ID) {
+ const RegisterBank &getRegBank(unsigned ID) {
assert(ID < getNumRegBanks() && "Accessing an unknown register bank");
return *RegBanks[ID];
}
return const_cast<RegisterBankInfo *>(this)->getRegBank(ID);
}
+ /// Get the maximum size in bits that fits in the given register bank.
+ unsigned getMaximumSize(unsigned RegBankID) const {
+ return Sizes[RegBankID + HwMode * NumRegBanks];
+ }
+
/// Get the register bank of \p Reg.
/// If Reg has not been assigned a register, a register class,
/// or a register bank, then this returns nullptr.
}
const RegisterBank *RegBank = MRI->getRegBankOrNull(Reg);
+ const RegisterBankInfo *RBI = MF->getSubtarget().getRegBankInfo();
// If we're post-RegBankSelect, the gvreg must have a bank.
if (!RegBank && isFunctionRegBankSelected) {
// Make sure the register fits into its register bank if any.
if (RegBank && Ty.isValid() &&
- RegBank->getSize() < Ty.getSizeInBits()) {
+ RBI->getMaximumSize(RegBank->getID()) < Ty.getSizeInBits()) {
report("Register bank is too small for virtual register", MO,
MONum);
errs() << "Register bank " << RegBank->getName() << " too small("
- << RegBank->getSize() << ") to fit " << Ty.getSizeInBits()
- << "-bits\n";
+ << RBI->getMaximumSize(RegBank->getID()) << ") to fit "
+ << Ty.getSizeInBits() << "-bits\n";
return;
}
}
#include "llvm/CodeGen/RegisterBank.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/CodeGen/RegisterBankInfo.h"
#include "llvm/CodeGen/TargetRegisterInfo.h"
#include "llvm/Config/llvm-config.h"
#include "llvm/Support/Debug.h"
const unsigned RegisterBank::InvalidID = UINT_MAX;
-RegisterBank::RegisterBank(
- unsigned ID, const char *Name, unsigned Size,
- const uint32_t *CoveredClasses, unsigned NumRegClasses)
- : ID(ID), Name(Name), Size(Size) {
+RegisterBank::RegisterBank(unsigned ID, const char *Name,
+ const uint32_t *CoveredClasses,
+ unsigned NumRegClasses)
+ : ID(ID), Name(Name) {
ContainedRegClasses.resize(NumRegClasses);
ContainedRegClasses.setBitsInMask(CoveredClasses);
}
-bool RegisterBank::verify(const TargetRegisterInfo &TRI) const {
+bool RegisterBank::verify(const RegisterBankInfo &RBI,
+ 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);
// Verify that the Size of the register bank is big enough to cover
// all the register classes it covers.
- assert(getSize() >= TRI.getRegSizeInBits(SubRC) &&
+ assert(RBI.getMaximumSize(getID()) >= TRI.getRegSizeInBits(SubRC) &&
"Size is not big enough for all the subclasses!");
assert(covers(SubRC) && "Not all subclasses are covered");
}
}
bool RegisterBank::isValid() const {
- return ID != InvalidID && Name != nullptr && Size != 0 &&
+ return ID != InvalidID && Name != nullptr &&
// A register bank that does not cover anything is useless.
!ContainedRegClasses.empty();
}
OS << getName();
if (!IsForDebug)
return;
- OS << "(ID:" << getID() << ", Size:" << getSize() << ")\n"
+ OS << "(ID:" << getID() << ")\n"
<< "isValid:" << isValid() << '\n'
<< "Number of Covered register classes: " << ContainedRegClasses.count()
<< '\n';
//------------------------------------------------------------------------------
// RegisterBankInfo implementation.
//------------------------------------------------------------------------------
-RegisterBankInfo::RegisterBankInfo(RegisterBank **RegBanks,
- unsigned NumRegBanks)
- : RegBanks(RegBanks), NumRegBanks(NumRegBanks) {
+RegisterBankInfo::RegisterBankInfo(const RegisterBank **RegBanks,
+ unsigned NumRegBanks, const unsigned *Sizes,
+ unsigned HwMode)
+ : RegBanks(RegBanks), NumRegBanks(NumRegBanks), Sizes(Sizes),
+ HwMode(HwMode) {
#ifndef NDEBUG
for (unsigned Idx = 0, End = getNumRegBanks(); Idx != End; ++Idx) {
assert(RegBanks[Idx] != nullptr && "Invalid RegisterBank");
assert(Idx == RegBank.getID() &&
"ID does not match the index in the array");
LLVM_DEBUG(dbgs() << "Verify " << RegBank << '\n');
- assert(RegBank.verify(TRI) && "RegBank is invalid");
+ assert(RegBank.verify(*this, TRI) && "RegBank is invalid");
}
#endif // NDEBUG
return true;
}
#endif
-bool RegisterBankInfo::PartialMapping::verify() const {
+bool RegisterBankInfo::PartialMapping::verify(
+ const RegisterBankInfo &RBI) const {
assert(RegBank && "Register bank not set");
assert(Length && "Empty mapping");
assert((StartIdx <= getHighBitIdx()) && "Overflow, switch to APInt?");
// Check if the minimum width fits into RegBank.
- assert(RegBank->getSize() >= Length && "Register bank too small for Mask");
+ assert(RBI.getMaximumSize(RegBank->getID()) >= Length &&
+ "Register bank too small for Mask");
return true;
}
return true;
}
-bool RegisterBankInfo::ValueMapping::verify(unsigned MeaningfulBitWidth) const {
+bool RegisterBankInfo::ValueMapping::verify(const RegisterBankInfo &RBI,
+ unsigned MeaningfulBitWidth) const {
assert(NumBreakDowns && "Value mapped nowhere?!");
unsigned OrigValueBitWidth = 0;
for (const RegisterBankInfo::PartialMapping &PartMap : *this) {
// Check that each register bank is big enough to hold the partial value:
// this check is done by PartialMapping::verify
- assert(PartMap.verify() && "Partial mapping is invalid");
+ assert(PartMap.verify(RBI) && "Partial mapping is invalid");
// The original value should completely be mapped.
// Thus the maximum accessed index + 1 is the size of the original value.
OrigValueBitWidth =
(void)MOMapping;
// Register size in bits.
// This size must match what the mapping expects.
- assert(MOMapping.verify(RBI->getSizeInBits(
- Reg, MF.getRegInfo(), *MF.getSubtarget().getRegisterInfo())) &&
+ assert(MOMapping.verify(*RBI, RBI->getSizeInBits(
+ Reg, MF.getRegInfo(),
+ *MF.getSubtarget().getRegisterInfo())) &&
"Value mapping is invalid");
}
return true;
// GR64all + its subclasses.
assert(RBGPR.covers(*TRI.getRegClass(AArch64::GPR32RegClassID)) &&
"Subclass not added?");
- assert(RBGPR.getSize() == 128 && "GPRs should hold up to 128-bit");
+ assert(getMaximumSize(RBGPR.getID()) == 128 &&
+ "GPRs should hold up to 128-bit");
// The FPR register bank is fully defined by all the registers in
// GR64all + its subclasses.
"Subclass not added?");
assert(RBFPR.covers(*TRI.getRegClass(AArch64::FPR64RegClassID)) &&
"Subclass not added?");
- assert(RBFPR.getSize() == 512 &&
+ assert(getMaximumSize(RBFPR.getID()) == 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");
+ assert(getMaximumSize(RBCCR.getID()) == 32 &&
+ "CCR should hold up to 32-bit");
// Check that the TableGen'ed like file is in sync we our expectations.
// First, the Idx.
"Subclass not added?");
assert(RBGPR.covers(*TRI.getRegClass(ARM::tGPROdd_and_tcGPRRegClassID)) &&
"Subclass not added?");
- assert(RBGPR.getSize() == 32 && "GPRs should hold up to 32-bit");
+ assert(getMaximumSize(RBGPR.getID()) == 32 &&
+ "GPRs should hold up to 32-bit");
#ifndef NDEBUG
ARM::checkPartialMappings();
using namespace llvm;
-RISCVRegisterBankInfo::RISCVRegisterBankInfo(const TargetRegisterInfo &TRI) {}
+RISCVRegisterBankInfo::RISCVRegisterBankInfo(unsigned HwMode)
+ : RISCVGenRegisterBankInfo(HwMode) {}
/// This class provides the information for the target register banks.
class RISCVRegisterBankInfo final : public RISCVGenRegisterBankInfo {
public:
- RISCVRegisterBankInfo(const TargetRegisterInfo &TRI);
+ RISCVRegisterBankInfo(unsigned HwMode);
};
} // end namespace llvm
#endif
CallLoweringInfo.reset(new RISCVCallLowering(*getTargetLowering()));
Legalizer.reset(new RISCVLegalizerInfo(*this));
- auto *RBI = new RISCVRegisterBankInfo(*getRegisterInfo());
+ auto *RBI = new RISCVRegisterBankInfo(getHwMode());
RegBankInfo.reset(RBI);
InstSelector.reset(createRISCVInstructionSelector(
*static_cast<const RISCVTargetMachine *>(&TM), *this, *RBI));
// GR64 + its subclasses.
assert(RBGPR.covers(*TRI.getRegClass(X86::GR64RegClassID)) &&
"Subclass not added?");
- assert(RBGPR.getSize() == 64 && "GPRs should hold up to 64-bit");
+ assert(getMaximumSize(RBGPR.getID()) == 64 &&
+ "GPRs should hold up to 64-bit");
}
const RegisterBank &
RegisterClassesTy RCs;
/// The register class with the largest register size.
- const CodeGenRegisterClass *RCWithLargestRegsSize;
+ std::vector<const CodeGenRegisterClass *> RCsWithLargestRegSize;
public:
- RegisterBank(const Record &TheDef)
- : TheDef(TheDef), RCWithLargestRegsSize(nullptr) {}
+ RegisterBank(const Record &TheDef, unsigned NumModeIds)
+ : TheDef(TheDef), RCsWithLargestRegSize(NumModeIds) {}
/// Get the human-readable name for the bank.
StringRef getName() const { return TheDef.getValueAsString("Name"); }
// register size anywhere (we could sum the sizes of the subregisters
// but there may be additional bits too) and we can't derive it from
// the VT's reliably due to Untyped.
- if (RCWithLargestRegsSize == nullptr)
- RCWithLargestRegsSize = RC;
- else if (RCWithLargestRegsSize->RSI.get(DefaultMode).SpillSize <
- RC->RSI.get(DefaultMode).SpillSize)
- RCWithLargestRegsSize = RC;
- assert(RCWithLargestRegsSize && "RC was nullptr?");
+ unsigned NumModeIds = RCsWithLargestRegSize.size();
+ for (unsigned M = 0; M < NumModeIds; ++M) {
+ if (RCsWithLargestRegSize[M] == nullptr)
+ RCsWithLargestRegSize[M] = RC;
+ else if (RCsWithLargestRegSize[M]->RSI.get(M).SpillSize <
+ RC->RSI.get(M).SpillSize)
+ RCsWithLargestRegSize[M] = RC;
+ assert(RCsWithLargestRegSize[M] && "RC was nullptr?");
+ }
RCs.emplace_back(RC);
}
- const CodeGenRegisterClass *getRCWithLargestRegsSize() const {
- return RCWithLargestRegsSize;
+ const CodeGenRegisterClass *getRCWithLargestRegSize(unsigned HwMode) const {
+ return RCsWithLargestRegSize[HwMode];
}
iterator_range<typename RegisterClassesTy::const_iterator>
raw_ostream &OS, const StringRef TargetName,
const std::vector<RegisterBank> &Banks) {
OS << "private:\n"
- << " static RegisterBank *RegBanks[];\n\n"
+ << " static const RegisterBank *RegBanks[];\n"
+ << " static const unsigned Sizes[];\n\n"
<< "protected:\n"
- << " " << TargetName << "GenRegisterBankInfo();\n"
+ << " " << TargetName << "GenRegisterBankInfo(unsigned HwMode = 0);\n"
<< "\n";
}
raw_ostream &OS, StringRef TargetName,
std::vector<RegisterBank> &Banks) {
const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();
+ const CodeGenHwModes &CGH = Target.getHwModes();
OS << "namespace llvm {\n"
<< "namespace " << TargetName << " {\n";
for (const auto &Bank : Banks) {
std::string QualifiedBankID =
(TargetName + "::" + Bank.getEnumeratorName()).str();
- const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegsSize();
- unsigned Size = RC.RSI.get(DefaultMode).SpillSize;
- OS << "RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ "
- << QualifiedBankID << ", /* Name */ \"" << Bank.getName()
- << "\", /* Size */ " << Size << ", "
+ OS << "const RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ "
+ << QualifiedBankID << ", /* Name */ \"" << Bank.getName() << "\", "
<< "/* CoveredRegClasses */ " << Bank.getCoverageArrayName()
<< ", /* NumRegClasses */ "
<< RegisterClassHierarchy.getRegClasses().size() << ");\n";
OS << "} // end namespace " << TargetName << "\n"
<< "\n";
- OS << "RegisterBank *" << TargetName
+ OS << "const RegisterBank *" << TargetName
<< "GenRegisterBankInfo::RegBanks[] = {\n";
for (const auto &Bank : Banks)
OS << " &" << TargetName << "::" << Bank.getInstanceVarName() << ",\n";
OS << "};\n\n";
+ unsigned NumModeIds = CGH.getNumModeIds();
+ OS << "const unsigned " << TargetName << "GenRegisterBankInfo::Sizes[] = {\n";
+ for (unsigned M = 0; M < NumModeIds; ++M) {
+ OS << " // Mode = " << M << " (";
+ if (M == DefaultMode)
+ OS << "Default";
+ else
+ OS << CGH.getMode(M).Name;
+ OS << ")\n";
+ for (const auto &Bank : Banks) {
+ const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegSize(M);
+ unsigned Size = RC.RSI.get(M).SpillSize;
+ OS << " " << Size << ",\n";
+ }
+ }
+ OS << "};\n\n";
+
OS << TargetName << "GenRegisterBankInfo::" << TargetName
- << "GenRegisterBankInfo()\n"
+ << "GenRegisterBankInfo(unsigned HwMode)\n"
<< " : RegisterBankInfo(RegBanks, " << TargetName
- << "::NumRegisterBanks) {\n"
+ << "::NumRegisterBanks, Sizes, HwMode) {\n"
<< " // Assert that RegBank indices match their ID's\n"
<< "#ifndef NDEBUG\n"
<< " for (auto RB : enumerate(RegBanks))\n"
void RegisterBankEmitter::run(raw_ostream &OS) {
StringRef TargetName = Target.getName();
const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();
+ const CodeGenHwModes &CGH = Target.getHwModes();
Records.startTimer("Analyze records");
std::vector<RegisterBank> Banks;
for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) {
SmallPtrSet<const CodeGenRegisterClass *, 8> VisitedRCs;
- RegisterBank Bank(*V);
+ RegisterBank Bank(*V, CGH.getNumModeIds());
for (const CodeGenRegisterClass *RC :
Bank.getExplicitlySpecifiedRegisterClasses(RegisterClassHierarchy)) {