10b57cec5SDimitry Andric //===- RegisterBankEmitter.cpp - Generate a Register Bank Desc. -*- C++ -*-===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This tablegen backend is responsible for emitting a description of a target 100b57cec5SDimitry Andric // register bank for a code generator. 110b57cec5SDimitry Andric // 120b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 130b57cec5SDimitry Andric 140b57cec5SDimitry Andric #include "llvm/ADT/BitVector.h" 150b57cec5SDimitry Andric #include "llvm/Support/Debug.h" 160b57cec5SDimitry Andric #include "llvm/TableGen/Error.h" 170b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 180b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 190b57cec5SDimitry Andric 200b57cec5SDimitry Andric #include "CodeGenRegisters.h" 215ffd83dbSDimitry Andric #include "CodeGenTarget.h" 220b57cec5SDimitry Andric 230b57cec5SDimitry Andric #define DEBUG_TYPE "register-bank-emitter" 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric namespace { 280b57cec5SDimitry Andric class RegisterBank { 290b57cec5SDimitry Andric 300b57cec5SDimitry Andric /// A vector of register classes that are included in the register bank. 310b57cec5SDimitry Andric typedef std::vector<const CodeGenRegisterClass *> RegisterClassesTy; 320b57cec5SDimitry Andric 330b57cec5SDimitry Andric private: 340b57cec5SDimitry Andric const Record &TheDef; 350b57cec5SDimitry Andric 360b57cec5SDimitry Andric /// The register classes that are covered by the register bank. 370b57cec5SDimitry Andric RegisterClassesTy RCs; 380b57cec5SDimitry Andric 390b57cec5SDimitry Andric /// The register class with the largest register size. 400b57cec5SDimitry Andric const CodeGenRegisterClass *RCWithLargestRegsSize; 410b57cec5SDimitry Andric 420b57cec5SDimitry Andric public: 430b57cec5SDimitry Andric RegisterBank(const Record &TheDef) 4404eeddc0SDimitry Andric : TheDef(TheDef), RCWithLargestRegsSize(nullptr) {} 450b57cec5SDimitry Andric 460b57cec5SDimitry Andric /// Get the human-readable name for the bank. 470b57cec5SDimitry Andric StringRef getName() const { return TheDef.getValueAsString("Name"); } 480b57cec5SDimitry Andric /// Get the name of the enumerator in the ID enumeration. 490b57cec5SDimitry Andric std::string getEnumeratorName() const { return (TheDef.getName() + "ID").str(); } 500b57cec5SDimitry Andric 510b57cec5SDimitry Andric /// Get the name of the array holding the register class coverage data; 520b57cec5SDimitry Andric std::string getCoverageArrayName() const { 530b57cec5SDimitry Andric return (TheDef.getName() + "CoverageData").str(); 540b57cec5SDimitry Andric } 550b57cec5SDimitry Andric 560b57cec5SDimitry Andric /// Get the name of the global instance variable. 570b57cec5SDimitry Andric StringRef getInstanceVarName() const { return TheDef.getName(); } 580b57cec5SDimitry Andric 590b57cec5SDimitry Andric const Record &getDef() const { return TheDef; } 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric /// Get the register classes listed in the RegisterBank.RegisterClasses field. 620b57cec5SDimitry Andric std::vector<const CodeGenRegisterClass *> 635ffd83dbSDimitry Andric getExplicitlySpecifiedRegisterClasses( 645ffd83dbSDimitry Andric const CodeGenRegBank &RegisterClassHierarchy) const { 650b57cec5SDimitry Andric std::vector<const CodeGenRegisterClass *> RCs; 665ffd83dbSDimitry Andric for (const auto *RCDef : getDef().getValueAsListOfDefs("RegisterClasses")) 670b57cec5SDimitry Andric RCs.push_back(RegisterClassHierarchy.getRegClass(RCDef)); 680b57cec5SDimitry Andric return RCs; 690b57cec5SDimitry Andric } 700b57cec5SDimitry Andric 710b57cec5SDimitry Andric /// Add a register class to the bank without duplicates. 720b57cec5SDimitry Andric void addRegisterClass(const CodeGenRegisterClass *RC) { 73e8d8bef9SDimitry Andric if (llvm::is_contained(RCs, RC)) 740b57cec5SDimitry Andric return; 750b57cec5SDimitry Andric 760b57cec5SDimitry Andric // FIXME? We really want the register size rather than the spill size 770b57cec5SDimitry Andric // since the spill size may be bigger on some targets with 780b57cec5SDimitry Andric // limited load/store instructions. However, we don't store the 790b57cec5SDimitry Andric // register size anywhere (we could sum the sizes of the subregisters 800b57cec5SDimitry Andric // but there may be additional bits too) and we can't derive it from 810b57cec5SDimitry Andric // the VT's reliably due to Untyped. 820b57cec5SDimitry Andric if (RCWithLargestRegsSize == nullptr) 830b57cec5SDimitry Andric RCWithLargestRegsSize = RC; 840b57cec5SDimitry Andric else if (RCWithLargestRegsSize->RSI.get(DefaultMode).SpillSize < 850b57cec5SDimitry Andric RC->RSI.get(DefaultMode).SpillSize) 860b57cec5SDimitry Andric RCWithLargestRegsSize = RC; 870b57cec5SDimitry Andric assert(RCWithLargestRegsSize && "RC was nullptr?"); 880b57cec5SDimitry Andric 890b57cec5SDimitry Andric RCs.emplace_back(RC); 900b57cec5SDimitry Andric } 910b57cec5SDimitry Andric 920b57cec5SDimitry Andric const CodeGenRegisterClass *getRCWithLargestRegsSize() const { 930b57cec5SDimitry Andric return RCWithLargestRegsSize; 940b57cec5SDimitry Andric } 950b57cec5SDimitry Andric 960b57cec5SDimitry Andric iterator_range<typename RegisterClassesTy::const_iterator> 970b57cec5SDimitry Andric register_classes() const { 980b57cec5SDimitry Andric return llvm::make_range(RCs.begin(), RCs.end()); 990b57cec5SDimitry Andric } 1000b57cec5SDimitry Andric }; 1010b57cec5SDimitry Andric 1020b57cec5SDimitry Andric class RegisterBankEmitter { 1030b57cec5SDimitry Andric private: 1045ffd83dbSDimitry Andric CodeGenTarget Target; 1050b57cec5SDimitry Andric RecordKeeper &Records; 1060b57cec5SDimitry Andric 1070b57cec5SDimitry Andric void emitHeader(raw_ostream &OS, const StringRef TargetName, 1080b57cec5SDimitry Andric const std::vector<RegisterBank> &Banks); 1090b57cec5SDimitry Andric void emitBaseClassDefinition(raw_ostream &OS, const StringRef TargetName, 1100b57cec5SDimitry Andric const std::vector<RegisterBank> &Banks); 1110b57cec5SDimitry Andric void emitBaseClassImplementation(raw_ostream &OS, const StringRef TargetName, 1120b57cec5SDimitry Andric std::vector<RegisterBank> &Banks); 1130b57cec5SDimitry Andric 1140b57cec5SDimitry Andric public: 1155ffd83dbSDimitry Andric RegisterBankEmitter(RecordKeeper &R) : Target(R), Records(R) {} 1160b57cec5SDimitry Andric 1170b57cec5SDimitry Andric void run(raw_ostream &OS); 1180b57cec5SDimitry Andric }; 1190b57cec5SDimitry Andric 1200b57cec5SDimitry Andric } // end anonymous namespace 1210b57cec5SDimitry Andric 1220b57cec5SDimitry Andric /// Emit code to declare the ID enumeration and external global instance 1230b57cec5SDimitry Andric /// variables. 1240b57cec5SDimitry Andric void RegisterBankEmitter::emitHeader(raw_ostream &OS, 1250b57cec5SDimitry Andric const StringRef TargetName, 1260b57cec5SDimitry Andric const std::vector<RegisterBank> &Banks) { 1270b57cec5SDimitry Andric // <Target>RegisterBankInfo.h 1280b57cec5SDimitry Andric OS << "namespace llvm {\n" 1290b57cec5SDimitry Andric << "namespace " << TargetName << " {\n" 130e8d8bef9SDimitry Andric << "enum : unsigned {\n"; 131e8d8bef9SDimitry Andric 132e8d8bef9SDimitry Andric OS << " InvalidRegBankID = ~0u,\n"; 133e8d8bef9SDimitry Andric unsigned ID = 0; 1340b57cec5SDimitry Andric for (const auto &Bank : Banks) 135e8d8bef9SDimitry Andric OS << " " << Bank.getEnumeratorName() << " = " << ID++ << ",\n"; 1360b57cec5SDimitry Andric OS << " NumRegisterBanks,\n" 1370b57cec5SDimitry Andric << "};\n" 1380b57cec5SDimitry Andric << "} // end namespace " << TargetName << "\n" 1390b57cec5SDimitry Andric << "} // end namespace llvm\n"; 1400b57cec5SDimitry Andric } 1410b57cec5SDimitry Andric 1420b57cec5SDimitry Andric /// Emit declarations of the <Target>GenRegisterBankInfo class. 1430b57cec5SDimitry Andric void RegisterBankEmitter::emitBaseClassDefinition( 1440b57cec5SDimitry Andric raw_ostream &OS, const StringRef TargetName, 1450b57cec5SDimitry Andric const std::vector<RegisterBank> &Banks) { 1460b57cec5SDimitry Andric OS << "private:\n" 1470b57cec5SDimitry Andric << " static RegisterBank *RegBanks[];\n\n" 1480b57cec5SDimitry Andric << "protected:\n" 1490b57cec5SDimitry Andric << " " << TargetName << "GenRegisterBankInfo();\n" 1500b57cec5SDimitry Andric << "\n"; 1510b57cec5SDimitry Andric } 1520b57cec5SDimitry Andric 1530b57cec5SDimitry Andric /// Visit each register class belonging to the given register bank. 1540b57cec5SDimitry Andric /// 1550b57cec5SDimitry Andric /// A class belongs to the bank iff any of these apply: 1560b57cec5SDimitry Andric /// * It is explicitly specified 1570b57cec5SDimitry Andric /// * It is a subclass of a class that is a member. 1580b57cec5SDimitry Andric /// * It is a class containing subregisters of the registers of a class that 1590b57cec5SDimitry Andric /// is a member. This is known as a subreg-class. 1600b57cec5SDimitry Andric /// 1610b57cec5SDimitry Andric /// This function must be called for each explicitly specified register class. 1620b57cec5SDimitry Andric /// 1630b57cec5SDimitry Andric /// \param RC The register class to search. 1640b57cec5SDimitry Andric /// \param Kind A debug string containing the path the visitor took to reach RC. 1650b57cec5SDimitry Andric /// \param VisitFn The action to take for each class visited. It may be called 1660b57cec5SDimitry Andric /// multiple times for a given class if there are multiple paths 1670b57cec5SDimitry Andric /// to the class. 1680b57cec5SDimitry Andric static void visitRegisterBankClasses( 1695ffd83dbSDimitry Andric const CodeGenRegBank &RegisterClassHierarchy, 170e8d8bef9SDimitry Andric const CodeGenRegisterClass *RC, const Twine &Kind, 1710b57cec5SDimitry Andric std::function<void(const CodeGenRegisterClass *, StringRef)> VisitFn, 1720b57cec5SDimitry Andric SmallPtrSetImpl<const CodeGenRegisterClass *> &VisitedRCs) { 1730b57cec5SDimitry Andric 1740b57cec5SDimitry Andric // Make sure we only visit each class once to avoid infinite loops. 175*81ad6265SDimitry Andric if (!VisitedRCs.insert(RC).second) 1760b57cec5SDimitry Andric return; 1770b57cec5SDimitry Andric 1780b57cec5SDimitry Andric // Visit each explicitly named class. 1790b57cec5SDimitry Andric VisitFn(RC, Kind.str()); 1800b57cec5SDimitry Andric 1810b57cec5SDimitry Andric for (const auto &PossibleSubclass : RegisterClassHierarchy.getRegClasses()) { 1820b57cec5SDimitry Andric std::string TmpKind = 183e8d8bef9SDimitry Andric (Kind + " (" + PossibleSubclass.getName() + ")").str(); 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric // Visit each subclass of an explicitly named class. 1860b57cec5SDimitry Andric if (RC != &PossibleSubclass && RC->hasSubClass(&PossibleSubclass)) 1870b57cec5SDimitry Andric visitRegisterBankClasses(RegisterClassHierarchy, &PossibleSubclass, 1880b57cec5SDimitry Andric TmpKind + " " + RC->getName() + " subclass", 1890b57cec5SDimitry Andric VisitFn, VisitedRCs); 1900b57cec5SDimitry Andric 1910b57cec5SDimitry Andric // Visit each class that contains only subregisters of RC with a common 1920b57cec5SDimitry Andric // subregister-index. 1930b57cec5SDimitry Andric // 1940b57cec5SDimitry Andric // More precisely, PossibleSubclass is a subreg-class iff Reg:SubIdx is in 1950b57cec5SDimitry Andric // PossibleSubclass for all registers Reg from RC using any 1960b57cec5SDimitry Andric // subregister-index SubReg 1970b57cec5SDimitry Andric for (const auto &SubIdx : RegisterClassHierarchy.getSubRegIndices()) { 1980b57cec5SDimitry Andric BitVector BV(RegisterClassHierarchy.getRegClasses().size()); 1990b57cec5SDimitry Andric PossibleSubclass.getSuperRegClasses(&SubIdx, BV); 2000b57cec5SDimitry Andric if (BV.test(RC->EnumValue)) { 2010b57cec5SDimitry Andric std::string TmpKind2 = (Twine(TmpKind) + " " + RC->getName() + 2020b57cec5SDimitry Andric " class-with-subregs: " + RC->getName()) 2030b57cec5SDimitry Andric .str(); 2040b57cec5SDimitry Andric VisitFn(&PossibleSubclass, TmpKind2); 2050b57cec5SDimitry Andric } 2060b57cec5SDimitry Andric } 2070b57cec5SDimitry Andric } 2080b57cec5SDimitry Andric } 2090b57cec5SDimitry Andric 2100b57cec5SDimitry Andric void RegisterBankEmitter::emitBaseClassImplementation( 2110b57cec5SDimitry Andric raw_ostream &OS, StringRef TargetName, 2120b57cec5SDimitry Andric std::vector<RegisterBank> &Banks) { 2135ffd83dbSDimitry Andric const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank(); 2140b57cec5SDimitry Andric 2150b57cec5SDimitry Andric OS << "namespace llvm {\n" 2160b57cec5SDimitry Andric << "namespace " << TargetName << " {\n"; 2170b57cec5SDimitry Andric for (const auto &Bank : Banks) { 2180b57cec5SDimitry Andric std::vector<std::vector<const CodeGenRegisterClass *>> RCsGroupedByWord( 2190b57cec5SDimitry Andric (RegisterClassHierarchy.getRegClasses().size() + 31) / 32); 2200b57cec5SDimitry Andric 2210b57cec5SDimitry Andric for (const auto &RC : Bank.register_classes()) 2220b57cec5SDimitry Andric RCsGroupedByWord[RC->EnumValue / 32].push_back(RC); 2230b57cec5SDimitry Andric 2240b57cec5SDimitry Andric OS << "const uint32_t " << Bank.getCoverageArrayName() << "[] = {\n"; 2250b57cec5SDimitry Andric unsigned LowestIdxInWord = 0; 2260b57cec5SDimitry Andric for (const auto &RCs : RCsGroupedByWord) { 2270b57cec5SDimitry Andric OS << " // " << LowestIdxInWord << "-" << (LowestIdxInWord + 31) << "\n"; 2280b57cec5SDimitry Andric for (const auto &RC : RCs) { 2290b57cec5SDimitry Andric std::string QualifiedRegClassID = 2300b57cec5SDimitry Andric (Twine(RC->Namespace) + "::" + RC->getName() + "RegClassID").str(); 2310b57cec5SDimitry Andric OS << " (1u << (" << QualifiedRegClassID << " - " 2320b57cec5SDimitry Andric << LowestIdxInWord << ")) |\n"; 2330b57cec5SDimitry Andric } 2340b57cec5SDimitry Andric OS << " 0,\n"; 2350b57cec5SDimitry Andric LowestIdxInWord += 32; 2360b57cec5SDimitry Andric } 2370b57cec5SDimitry Andric OS << "};\n"; 2380b57cec5SDimitry Andric } 2390b57cec5SDimitry Andric OS << "\n"; 2400b57cec5SDimitry Andric 2410b57cec5SDimitry Andric for (const auto &Bank : Banks) { 2420b57cec5SDimitry Andric std::string QualifiedBankID = 2430b57cec5SDimitry Andric (TargetName + "::" + Bank.getEnumeratorName()).str(); 2440b57cec5SDimitry Andric const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegsSize(); 2450b57cec5SDimitry Andric unsigned Size = RC.RSI.get(DefaultMode).SpillSize; 2460b57cec5SDimitry Andric OS << "RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ " 2470b57cec5SDimitry Andric << QualifiedBankID << ", /* Name */ \"" << Bank.getName() 2480b57cec5SDimitry Andric << "\", /* Size */ " << Size << ", " 2490b57cec5SDimitry Andric << "/* CoveredRegClasses */ " << Bank.getCoverageArrayName() 2500b57cec5SDimitry Andric << ", /* NumRegClasses */ " 2510b57cec5SDimitry Andric << RegisterClassHierarchy.getRegClasses().size() << ");\n"; 2520b57cec5SDimitry Andric } 2530b57cec5SDimitry Andric OS << "} // end namespace " << TargetName << "\n" 2540b57cec5SDimitry Andric << "\n"; 2550b57cec5SDimitry Andric 2560b57cec5SDimitry Andric OS << "RegisterBank *" << TargetName 2570b57cec5SDimitry Andric << "GenRegisterBankInfo::RegBanks[] = {\n"; 2580b57cec5SDimitry Andric for (const auto &Bank : Banks) 2590b57cec5SDimitry Andric OS << " &" << TargetName << "::" << Bank.getInstanceVarName() << ",\n"; 2600b57cec5SDimitry Andric OS << "};\n\n"; 2610b57cec5SDimitry Andric 2620b57cec5SDimitry Andric OS << TargetName << "GenRegisterBankInfo::" << TargetName 2630b57cec5SDimitry Andric << "GenRegisterBankInfo()\n" 2640b57cec5SDimitry Andric << " : RegisterBankInfo(RegBanks, " << TargetName 2650b57cec5SDimitry Andric << "::NumRegisterBanks) {\n" 2660b57cec5SDimitry Andric << " // Assert that RegBank indices match their ID's\n" 2670b57cec5SDimitry Andric << "#ifndef NDEBUG\n" 268*81ad6265SDimitry Andric << " for (auto RB : enumerate(RegBanks))\n" 269*81ad6265SDimitry Andric << " assert(RB.index() == RB.value()->getID() && \"Index != ID\");\n" 2700b57cec5SDimitry Andric << "#endif // NDEBUG\n" 2710b57cec5SDimitry Andric << "}\n" 2720b57cec5SDimitry Andric << "} // end namespace llvm\n"; 2730b57cec5SDimitry Andric } 2740b57cec5SDimitry Andric 2750b57cec5SDimitry Andric void RegisterBankEmitter::run(raw_ostream &OS) { 2765ffd83dbSDimitry Andric StringRef TargetName = Target.getName(); 2775ffd83dbSDimitry Andric const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank(); 2780b57cec5SDimitry Andric 279e8d8bef9SDimitry Andric Records.startTimer("Analyze records"); 2800b57cec5SDimitry Andric std::vector<RegisterBank> Banks; 2810b57cec5SDimitry Andric for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) { 2820b57cec5SDimitry Andric SmallPtrSet<const CodeGenRegisterClass *, 8> VisitedRCs; 2830b57cec5SDimitry Andric RegisterBank Bank(*V); 2840b57cec5SDimitry Andric 2850b57cec5SDimitry Andric for (const CodeGenRegisterClass *RC : 2865ffd83dbSDimitry Andric Bank.getExplicitlySpecifiedRegisterClasses(RegisterClassHierarchy)) { 2870b57cec5SDimitry Andric visitRegisterBankClasses( 2880b57cec5SDimitry Andric RegisterClassHierarchy, RC, "explicit", 2890b57cec5SDimitry Andric [&Bank](const CodeGenRegisterClass *RC, StringRef Kind) { 2900b57cec5SDimitry Andric LLVM_DEBUG(dbgs() 2910b57cec5SDimitry Andric << "Added " << RC->getName() << "(" << Kind << ")\n"); 2920b57cec5SDimitry Andric Bank.addRegisterClass(RC); 2930b57cec5SDimitry Andric }, 2940b57cec5SDimitry Andric VisitedRCs); 2950b57cec5SDimitry Andric } 2960b57cec5SDimitry Andric 2970b57cec5SDimitry Andric Banks.push_back(Bank); 2980b57cec5SDimitry Andric } 2990b57cec5SDimitry Andric 3000b57cec5SDimitry Andric // Warn about ambiguous MIR caused by register bank/class name clashes. 301e8d8bef9SDimitry Andric Records.startTimer("Warn ambiguous"); 3025ffd83dbSDimitry Andric for (const auto &Class : RegisterClassHierarchy.getRegClasses()) { 3030b57cec5SDimitry Andric for (const auto &Bank : Banks) { 3045ffd83dbSDimitry Andric if (Bank.getName().lower() == StringRef(Class.getName()).lower()) { 3050b57cec5SDimitry Andric PrintWarning(Bank.getDef().getLoc(), "Register bank names should be " 3060b57cec5SDimitry Andric "distinct from register classes " 3070b57cec5SDimitry Andric "to avoid ambiguous MIR"); 3080b57cec5SDimitry Andric PrintNote(Bank.getDef().getLoc(), "RegisterBank was declared here"); 3095ffd83dbSDimitry Andric PrintNote(Class.getDef()->getLoc(), "RegisterClass was declared here"); 3100b57cec5SDimitry Andric } 3110b57cec5SDimitry Andric } 3120b57cec5SDimitry Andric } 3130b57cec5SDimitry Andric 314e8d8bef9SDimitry Andric Records.startTimer("Emit output"); 3150b57cec5SDimitry Andric emitSourceFileHeader("Register Bank Source Fragments", OS); 3160b57cec5SDimitry Andric OS << "#ifdef GET_REGBANK_DECLARATIONS\n" 3170b57cec5SDimitry Andric << "#undef GET_REGBANK_DECLARATIONS\n"; 3180b57cec5SDimitry Andric emitHeader(OS, TargetName, Banks); 3190b57cec5SDimitry Andric OS << "#endif // GET_REGBANK_DECLARATIONS\n\n" 3200b57cec5SDimitry Andric << "#ifdef GET_TARGET_REGBANK_CLASS\n" 3210b57cec5SDimitry Andric << "#undef GET_TARGET_REGBANK_CLASS\n"; 3220b57cec5SDimitry Andric emitBaseClassDefinition(OS, TargetName, Banks); 3230b57cec5SDimitry Andric OS << "#endif // GET_TARGET_REGBANK_CLASS\n\n" 3240b57cec5SDimitry Andric << "#ifdef GET_TARGET_REGBANK_IMPL\n" 3250b57cec5SDimitry Andric << "#undef GET_TARGET_REGBANK_IMPL\n"; 3260b57cec5SDimitry Andric emitBaseClassImplementation(OS, TargetName, Banks); 3270b57cec5SDimitry Andric OS << "#endif // GET_TARGET_REGBANK_IMPL\n"; 3280b57cec5SDimitry Andric } 3290b57cec5SDimitry Andric 3300b57cec5SDimitry Andric namespace llvm { 3310b57cec5SDimitry Andric 3320b57cec5SDimitry Andric void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS) { 3330b57cec5SDimitry Andric RegisterBankEmitter(RK).run(OS); 3340b57cec5SDimitry Andric } 3350b57cec5SDimitry Andric 3360b57cec5SDimitry Andric } // end namespace llvm 337