Index: include/llvm/Target/GlobalISel/RegisterBank.td =================================================================== --- /dev/null +++ include/llvm/Target/GlobalISel/RegisterBank.td @@ -0,0 +1,20 @@ +//===- RegisterBank.td - Register bank definitions ---------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +class RegisterBank classes> { + string Name = name; + list RegisterClasses = classes; + // FIXME: The PartialMapping enum omits a small number of sizes at the + // moment. This lists the sizes that ought to exist according to the + // register classes but currently don't. + list ExcludePartialMappings = []; +} Index: include/llvm/Target/Target.td =================================================================== --- include/llvm/Target/Target.td +++ include/llvm/Target/Target.td @@ -1340,3 +1340,8 @@ // Pull in the common support for DAG isel generation. // include "llvm/Target/TargetSelectionDAG.td" + +//===----------------------------------------------------------------------===// +// Pull in the common support for GlobalISel. +// +include "llvm/Target/GlobalISel/RegisterBank.td" Index: lib/Target/AArch64/AArch64.td =================================================================== --- lib/Target/AArch64/AArch64.td +++ lib/Target/AArch64/AArch64.td @@ -121,6 +121,7 @@ //===----------------------------------------------------------------------===// include "AArch64RegisterInfo.td" +include "AArch64RegisterBanks.td" include "AArch64CallingConvention.td" //===----------------------------------------------------------------------===// Index: lib/Target/AArch64/AArch64GenRegisterBankInfo.def =================================================================== --- lib/Target/AArch64/AArch64GenRegisterBankInfo.def +++ lib/Target/AArch64/AArch64GenRegisterBankInfo.def @@ -18,12 +18,6 @@ namespace llvm { namespace AArch64 { -RegisterBank GPRRegBank; -RegisterBank FPRRegBank; -RegisterBank CCRRegBank; - -RegisterBank *RegBanks[] = {&GPRRegBank, &FPRRegBank, &CCRRegBank}; - // PartialMappings. enum PartialMappingIdx { None = -1, Index: lib/Target/AArch64/AArch64RegisterBankInfo.h =================================================================== --- lib/Target/AArch64/AArch64RegisterBankInfo.h +++ lib/Target/AArch64/AArch64RegisterBankInfo.h @@ -16,23 +16,13 @@ #include "llvm/CodeGen/GlobalISel/RegisterBankInfo.h" +#define TBLGEN_REGISTERBANKINFO_H +#include "AArch64GenRegisterBank.inc" + namespace llvm { class TargetRegisterInfo; -namespace AArch64 { -enum { - GPRRegBankID = 0, /// General Purpose Registers: W, X. - FPRRegBankID = 1, /// Floating Point/Vector Registers: B, H, S, D, Q. - CCRRegBankID = 2, /// Conditional register: NZCV. - NumRegisterBanks -}; - -extern RegisterBank GPRRegBank; -extern RegisterBank FPRRegBank; -extern RegisterBank CCRRegBank; -} // End AArch64 namespace. - /// This class provides the information for the target register banks. class AArch64RegisterBankInfo final : public RegisterBankInfo { /// See RegisterBankInfo::applyMapping. @@ -80,6 +70,10 @@ getInstrAlternativeMappings(const MachineInstr &MI) const override; InstructionMapping getInstrMapping(const MachineInstr &MI) const override; + +private: +#define TBLGEN_REGISTERBANKINFO_PRIVATE_H +#include "AArch64GenRegisterBank.inc" }; } // End llvm namespace. #endif Index: lib/Target/AArch64/AArch64RegisterBankInfo.cpp =================================================================== --- lib/Target/AArch64/AArch64RegisterBankInfo.cpp +++ lib/Target/AArch64/AArch64RegisterBankInfo.cpp @@ -23,6 +23,8 @@ // This file will be TableGen'ed at some point. #include "AArch64GenRegisterBankInfo.def" +#define TBLGEN_REGISTERBANKINFO_CPP +#include "AArch64GenRegisterBank.inc" using namespace llvm; @@ -41,77 +43,13 @@ 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); + initGeneratedInfo(TRI); +// Now, the content. +// Check partial mapping. 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. -// Check partial mapping. #define CHECK_PARTIALMAP(Idx, ValStartIdx, ValLength, RB) \ do { \ const PartialMapping &Map = \ Index: lib/Target/AArch64/AArch64RegisterBanks.td =================================================================== --- /dev/null +++ lib/Target/AArch64/AArch64RegisterBanks.td @@ -0,0 +1,24 @@ +//=- AArch64RegisterBank.td - Describe the AArch64 Banks -----*- tablegen -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +/// General Purpose Registers: W, X. +def GPRRegBank : RegisterBank<"GPR", [GPR64all]>; + +/// Floating Point/Vector Registers: B, H, S, D, Q. +def FPRRegBank : RegisterBank<"FPR", [QQQQ]> { + let ExcludePartialMappings = [8, 16, 192, 384]; +} + +/// Conditional register: NZCV. +def CCRRegBank : RegisterBank<"CCR", [CCR]> { + let ExcludePartialMappings = [32]; +} Index: lib/Target/AArch64/CMakeLists.txt =================================================================== --- lib/Target/AArch64/CMakeLists.txt +++ lib/Target/AArch64/CMakeLists.txt @@ -1,5 +1,6 @@ set(LLVM_TARGET_DEFINITIONS AArch64.td) +tablegen(LLVM AArch64GenRegisterBank.inc -gen-register-bank) tablegen(LLVM AArch64GenRegisterInfo.inc -gen-register-info) tablegen(LLVM AArch64GenInstrInfo.inc -gen-instr-info) tablegen(LLVM AArch64GenMCCodeEmitter.inc -gen-emitter) Index: utils/TableGen/CMakeLists.txt =================================================================== --- utils/TableGen/CMakeLists.txt +++ utils/TableGen/CMakeLists.txt @@ -26,6 +26,7 @@ IntrinsicEmitter.cpp OptParserEmitter.cpp PseudoLoweringEmitter.cpp + RegisterBankEmitter.cpp RegisterInfoEmitter.cpp SearchableTableEmitter.cpp SubtargetEmitter.cpp Index: utils/TableGen/RegisterBankEmitter.cpp =================================================================== --- /dev/null +++ utils/TableGen/RegisterBankEmitter.cpp @@ -0,0 +1,371 @@ +//===- RegisterBankEmitter.cpp - Generate a Register Bank Desc. -*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend is responsible for emitting a description of a target +// register bank for a code generator. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/BitVector.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" + +#include "CodeGenRegisters.h" + +using namespace llvm; + +namespace { +class RegisterBank { +public: + typedef std::vector PartialMappingsTy; + + /// A vector of register classes. The StringRef indicates why the register + /// class is included in the register bank. + typedef std::vector> + RegisterClassesTy; + +private: + const Record &TheDef; + + /// This is just enough information to emit an assertion correctly. We don't + /// handle partial mappings yet. + PartialMappingsTy PartialMappings; + + /// The register classes that are covered by the register bank. + RegisterClassesTy RCs; + + /// Used to report the register class associated with the min/max partial + /// mapping. It should be replaced when ExcludePartialMappings is removed. + const CodeGenRegisterClass *RCWithLargestRegsSize; + + /// Used to report the register class associated with the min/max partial + /// mapping. It should be replaced when ExcludePartialMappings is removed. + const CodeGenRegisterClass *RCWithSmallestRegsSize; + + void definePartialMapping(unsigned Size) { + PartialMappings.emplace_back(Size); + } + +public: + RegisterBank(const Record &TheDef) + : TheDef(TheDef), PartialMappings(), RCs(), + RCWithLargestRegsSize(nullptr), RCWithSmallestRegsSize(nullptr) {} + RegisterBank(const Record *TheDef) : RegisterBank(*TheDef) {} + + /// Get the human-readable name for the bank. + std::string getName() const { return TheDef.getValueAsString("Name"); } + + /// Get the name of the enumerator in the ID enumeration. + Twine getEnumeratorName() const { return TheDef.getName() + "ID"; } + + /// Get the name of the global instance variable. + StringRef getInstanceVarName() const { return TheDef.getName(); } + + const Record &getDef() const { return TheDef; } + + /// Get the register classes listed in the RegisterBank.RegisterClasses field. + std::vector + getExplictlySpecifiedRegisterClasses( + CodeGenRegBank &RegisterClassHierarchy) const { + std::vector RCs; + for (const auto &RCDef : getDef().getValueAsListOfDefs("RegisterClasses")) + RCs.push_back(RegisterClassHierarchy.getRegClass(RCDef)); + return RCs; + } + + /// Add a register class to the bank. + void addRegisterClass(const CodeGenRegisterClass *RC, const StringRef Kind) { + // FIXME? We really want the register size rather than the spill size + // since the spill size may be bigger on some targets with + // limited load/store instructions. However, we don't store the + // 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. + const auto &Exclude = + getDef().getValueAsListOfInts("ExcludePartialMappings"); + if (std::find(Exclude.begin(), Exclude.end(), RC->SpillSize) == + Exclude.end()) { + if (RCWithLargestRegsSize == nullptr) + RCWithLargestRegsSize = RC; + else if (RCWithLargestRegsSize->SpillSize < RC->SpillSize) + RCWithLargestRegsSize = RC; + + if (RCWithSmallestRegsSize == nullptr) + RCWithSmallestRegsSize = RC; + else if (RCWithSmallestRegsSize->SpillSize > RC->SpillSize) + RCWithSmallestRegsSize = RC; + + definePartialMapping(RC->SpillSize); + } + + RCs.emplace_back(RC, Kind); + } + const CodeGenRegisterClass *getRCWithLargestRegsSize() const { + return RCWithLargestRegsSize; + } + const CodeGenRegisterClass *getRCWithSmallestRegsSize() const { + return RCWithSmallestRegsSize; + } + iterator_range + register_classes() const { + return llvm::make_range(RCs.begin(), RCs.end()); + } + + void finalizePartialMappings() { + std::sort(PartialMappings.begin(), PartialMappings.end()); + PartialMappings.erase( + std::unique(PartialMappings.begin(), PartialMappings.end()), + PartialMappings.end()); + } + + bool hasPartialMappings() const { + return partial_mappings().begin() != partial_mappings().end(); + } + + /// This range is not valid if finalizePartialMappings() has not been + /// called. + iterator_range + partial_mappings() const { + return llvm::make_range(PartialMappings.begin(), PartialMappings.end()); + } +}; + +class RegisterBankEmitter { +private: + RecordKeeper &Records; + CodeGenRegBank RegisterClassHierarchy; + + void emitHeader(raw_ostream &OS, const StringRef TargetName, + const std::vector &Banks); + void emitRegisterBankInfoPrivateMembers(raw_ostream &OS); + void + emitRegisterBankInfoImplementation(raw_ostream &OS, + const StringRef TargetName, + std::vector &Banks); + +public: + RegisterBankEmitter(RecordKeeper &R) + : Records(R), RegisterClassHierarchy(Records) {} + + void run(raw_ostream &OS); +}; + +} // end anonymous namespace + +/// Emit code to declare the ID enumeration and external global instance +/// variables. +void RegisterBankEmitter::emitHeader(raw_ostream &OS, + const StringRef TargetName, + const std::vector &Banks) { + // RegisterBankInfo.h + OS << "#ifdef TBLGEN_REGISTERBANKINFO_H\n" + << "#undef TBLGEN_REGISTERBANKINFO_H\n" + << "namespace llvm {\n" + << "namespace " << TargetName << " {\n" + << "enum {\n"; + for (const auto &Bank : Banks) + OS << " " << Bank.getEnumeratorName().str() << ",\n"; + OS << " NumRegisterBanks,\n" + << " NoRegisterBankID = ~0U,\n"; + OS << "};\n" + << "\n" + << "extern RegisterBank NoRegisterBank;\n"; + for (const auto &Bank : Banks) + OS << "extern RegisterBank " << Bank.getInstanceVarName() << ";\n"; + OS << "} // end namespace " << TargetName << "\n" + << "} // end namespace llvm\n" + << "#endif // TBLGEN_REGISTERBANKINFO_H\n\n"; +} + +/// Emit declarations of tablegen-erated members of RegisterBankInfo. +void RegisterBankEmitter::emitRegisterBankInfoPrivateMembers(raw_ostream &OS) { + // RegisterBankInfo private members + OS << "#ifdef TBLGEN_REGISTERBANKINFO_PRIVATE_H\n" + << "#undef TBLGEN_REGISTERBANKINFO_PRIVATE_H\n" + << "void initGeneratedInfo(const TargetRegisterInfo &TRI);\n" + << "#endif // TBLGEN_REGISTERBANKINFO_PRIVATE_H\n\n"; +} + +/// Visit each register class belonging to the given register bank. +/// +/// A class belongs to the bank iff: +/// * It is explicitly specified +/// * It is a subclass of a class that is a member. +/// * It is a class containing subregisters of the registers of a class that +/// is a member. +static void visitSelfAndSubclassesAndClassesWithSubRegs( + CodeGenRegBank &RegisterClassHierarchy, const RegisterBank &Bank, + std::function visitFn) { + for (const CodeGenRegisterClass *RC : + Bank.getExplictlySpecifiedRegisterClasses(RegisterClassHierarchy)) { + // Visit each explicitly named class. + visitFn(RC, "self"); + + for (const auto &PossibleSubclass : + RegisterClassHierarchy.getRegClasses()) { + // Visit each subclass of an explicitly named class + if (RC != &PossibleSubclass && RC->hasSubClass(&PossibleSubclass)) + visitFn(&PossibleSubclass, "Subclass"); + + // Visit each class that has a subregister of RC + for (const auto &SubIdx : RegisterClassHierarchy.getSubRegIndices()) { + BitVector BV(RegisterClassHierarchy.getRegClasses().size()); + PossibleSubclass.getSuperRegClasses(&SubIdx, BV); + if (BV.test(RC->EnumValue)) + visitFn(&PossibleSubclass, "Class with subregs"); + } + } + } +} + +/// Emit an assertion that enumerator values are consecutive and in the same +/// order as the iterator. +static void emitPartialMappingSortedAssertion( + raw_ostream &OS, RegisterBank::PartialMappingsTy::const_iterator Begin, + RegisterBank::PartialMappingsTy::const_iterator End, + StringRef Enumeration, StringRef EnumeratorPrefix) { + OS << " assert("; + for (RegisterBank::PartialMappingsTy::const_iterator I = Begin; + I != End && I + 1 != End; ++I) { + OS << Enumeration << "::" << EnumeratorPrefix << *I + << " + 1 == " << Enumeration << "::" << EnumeratorPrefix << *(I + 1) + << " &&\n "; + } + OS << "\"" << EnumeratorPrefix << " indices not properly ordered\");\n"; +} + +void RegisterBankEmitter::emitRegisterBankInfoImplementation( + raw_ostream &OS, StringRef TargetName, + std::vector &Banks) { + // RegisterBankInfo.cpp + OS << "#ifdef TBLGEN_REGISTERBANKINFO_CPP\n" + << "#undef TBLGEN_REGISTERBANKINFO_CPP\n" + << "namespace llvm {\n" + << "namespace " << TargetName << " {\n"; + + // Declare the global instance variables. + OS << "RegisterBank NoRegisterBank;\n"; + for (const auto &Bank : Banks) + OS << "RegisterBank " << Bank.getInstanceVarName() << ";\n"; + OS << "\n"; + + // Declare the map of ID's to global instance variables. + OS << "RegisterBank *RegBanks[] = {\n"; + for (const auto &Bank : Banks) + OS << " &" << Bank.getInstanceVarName() << ",\n"; + OS << "};\n" + << "} // end namespace " << TargetName << "\n\n"; + + OS << "void " << TargetName << "RegisterBankInfo::initGeneratedInfo(const " + "TargetRegisterInfo &TRI) {\n"; + for (const auto &Bank : Banks) { + Twine QualifiedBank = TargetName + "::" + Bank.getInstanceVarName().str(); + Twine QualifiedBankID = TargetName + "::" + Bank.getEnumeratorName().str(); + OS << " createRegisterBank(" << QualifiedBankID << ", \"" << Bank.getName() + << "\");\n"; + + for (const CodeGenRegisterClass *RC : + Bank.getExplictlySpecifiedRegisterClasses(RegisterClassHierarchy)) { + Twine QualifiedRegClassID = + TargetName + "::" + RC->getName() + "RegClassID"; + OS << " addRegBankCoverage(" << QualifiedBankID << ", " + << QualifiedRegClassID << ", TRI);\n"; + } + + OS << "#ifndef NDEBUG\n" + << " {\n" + << " const RegisterBank &RB = getRegBank(" << QualifiedBankID + << ");\n" + << " assert(&" << QualifiedBank + << " == &RB && \"The order in RegBanks is messed up\");\n"; + + for (const auto &Pair : Bank.register_classes()) { + const CodeGenRegisterClass *RC = Pair.first; + const StringRef Kind = Pair.second; + // Assert that the class was added by addRegBankCoverage. + OS << " assert(RB.covers(*TRI.getRegClass(" << RC->getQualifiedName() + << "RegClassID)) && \"" << Kind << " not added?\");\n"; + } + + Twine PartialMappingEnumerationName = TargetName + "::PartialMappingIdx"; + // PartialMappingIdx is sorted with smallest sizes first. In addition to + // this FirstX and LastX are aliases of the first and last sizes in the + // list. + if (!Bank.hasPartialMappings()) { + OS << " // No asserts on " << PartialMappingEnumerationName.str() + << " required because there are no valid sizes\n"; + } else { + OS << " assert(" << PartialMappingEnumerationName.str() + << "::" << Bank.getName() << Bank.getRCWithSmallestRegsSize()->SpillSize + << " == " << PartialMappingEnumerationName << "::First" + << Bank.getName() << " && " + << "\"" << Bank.getName() << Bank.getRCWithSmallestRegsSize()->SpillSize + << " not last in the " << Bank.getName() << " list\");\n"; + OS << " assert(" << PartialMappingEnumerationName.str() + << "::" << Bank.getName() << Bank.getRCWithLargestRegsSize()->SpillSize + << " == " << PartialMappingEnumerationName.str() << "::Last" + << Bank.getName() << " && " + << "\"" << Bank.getName() << Bank.getRCWithLargestRegsSize()->SpillSize + << " not last in the " << Bank.getName() << " list\");\n"; + OS << " assert(" << PartialMappingEnumerationName.str() << "::First" + << Bank.getName() << " <= " << PartialMappingEnumerationName.str() + << "::Last" << Bank.getName() << " && \"" << Bank.getName() + << " list is backward\");\n"; + + emitPartialMappingSortedAssertion( + OS, Bank.partial_mappings().begin(), Bank.partial_mappings().end(), + PartialMappingEnumerationName.str(), Bank.getName()); + + OS << " assert(RB.getSize() == " + << Bank.getRCWithLargestRegsSize()->SpillSize << " && \"" + << Bank.getName() << " should hold up to " + << Bank.getRCWithLargestRegsSize()->SpillSize << "-bits via " + << Bank.getRCWithLargestRegsSize()->getName() << "\");\n"; + } + OS << " }\n" + << "#endif // NDEBUG\n"; + } + OS << "}\n"; + OS << "} // end namespace llvm\n" + << "#endif // TBLGEN_REGISTERBANKINFO_CPP\n\n"; +} + +void RegisterBankEmitter::run(raw_ostream &OS) { + std::vector Targets = Records.getAllDerivedDefinitions("Target"); + if (Targets.size() != 1) + PrintFatalError("ERROR: Too many or too few subclasses of Target defined!"); + StringRef TargetName = Targets[0]->getName(); + + std::vector Banks; + for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) { + RegisterBank Bank(V); + + visitSelfAndSubclassesAndClassesWithSubRegs( + RegisterClassHierarchy, Bank, + [&OS, &Bank](const CodeGenRegisterClass *RC, StringRef Kind) { + Bank.addRegisterClass(RC, Kind); + }); + + Bank.finalizePartialMappings(); + Banks.push_back(Bank); + } + + OS << "// This file is generated. Do not edit.\n\n"; + emitHeader(OS, TargetName, Banks); + emitRegisterBankInfoPrivateMembers(OS); + emitRegisterBankInfoImplementation(OS, TargetName, Banks); +} + +namespace llvm { + +void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS) { + RegisterBankEmitter(RK).run(OS); +} + +} // end namespace llvm Index: utils/TableGen/TableGen.cpp =================================================================== --- utils/TableGen/TableGen.cpp +++ utils/TableGen/TableGen.cpp @@ -45,6 +45,7 @@ GenCTags, GenAttributes, GenSearchableTables, + GenRegisterBank, }; namespace { @@ -91,7 +92,9 @@ clEnumValN(GenAttributes, "gen-attrs", "Generate attributes"), clEnumValN(GenSearchableTables, "gen-searchable-tables", - "Generate generic binary-searchable table"))); + "Generate generic binary-searchable table"), + clEnumValN(GenRegisterBank, "gen-register-bank", + "Generate registers bank descriptions"))); cl::opt Class("class", cl::desc("Print Enum list for this class"), @@ -177,6 +180,9 @@ case GenSearchableTables: EmitSearchableTables(Records, OS); break; + case GenRegisterBank: + EmitRegisterBank(Records, OS); + break; } return false; Index: utils/TableGen/TableGenBackends.h =================================================================== --- utils/TableGen/TableGenBackends.h +++ utils/TableGen/TableGenBackends.h @@ -80,6 +80,7 @@ void EmitCTags(RecordKeeper &RK, raw_ostream &OS); void EmitAttributes(RecordKeeper &RK, raw_ostream &OS); void EmitSearchableTables(RecordKeeper &RK, raw_ostream &OS); +void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS); } // End llvm namespace