Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/RegisterBankEmitter.cpp
96333 views
//===- RegisterBankEmitter.cpp - Generate a Register Bank Desc. -*- C++ -*-===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend is responsible for emitting a description of a target9// register bank for a code generator.10//11//===----------------------------------------------------------------------===//1213#include "Common/CodeGenRegisters.h"14#include "Common/CodeGenTarget.h"15#include "Common/InfoByHwMode.h"16#include "llvm/ADT/BitVector.h"17#include "llvm/Support/Debug.h"18#include "llvm/TableGen/Error.h"19#include "llvm/TableGen/Record.h"20#include "llvm/TableGen/TableGenBackend.h"2122#define DEBUG_TYPE "register-bank-emitter"2324using namespace llvm;2526namespace {27class RegisterBank {2829/// A vector of register classes that are included in the register bank.30typedef std::vector<const CodeGenRegisterClass *> RegisterClassesTy;3132private:33const Record &TheDef;3435/// The register classes that are covered by the register bank.36RegisterClassesTy RCs;3738/// The register class with the largest register size.39std::vector<const CodeGenRegisterClass *> RCsWithLargestRegSize;4041public:42RegisterBank(const Record &TheDef, unsigned NumModeIds)43: TheDef(TheDef), RCsWithLargestRegSize(NumModeIds) {}4445/// Get the human-readable name for the bank.46StringRef getName() const { return TheDef.getValueAsString("Name"); }47/// Get the name of the enumerator in the ID enumeration.48std::string getEnumeratorName() const {49return (TheDef.getName() + "ID").str();50}5152/// Get the name of the array holding the register class coverage data;53std::string getCoverageArrayName() const {54return (TheDef.getName() + "CoverageData").str();55}5657/// Get the name of the global instance variable.58StringRef getInstanceVarName() const { return TheDef.getName(); }5960const Record &getDef() const { return TheDef; }6162/// Get the register classes listed in the RegisterBank.RegisterClasses field.63std::vector<const CodeGenRegisterClass *>64getExplicitlySpecifiedRegisterClasses(65const CodeGenRegBank &RegisterClassHierarchy) const {66std::vector<const CodeGenRegisterClass *> RCs;67for (const auto *RCDef : getDef().getValueAsListOfDefs("RegisterClasses"))68RCs.push_back(RegisterClassHierarchy.getRegClass(RCDef));69return RCs;70}7172/// Add a register class to the bank without duplicates.73void addRegisterClass(const CodeGenRegisterClass *RC) {74if (llvm::is_contained(RCs, RC))75return;7677// FIXME? We really want the register size rather than the spill size78// since the spill size may be bigger on some targets with79// limited load/store instructions. However, we don't store the80// register size anywhere (we could sum the sizes of the subregisters81// but there may be additional bits too) and we can't derive it from82// the VT's reliably due to Untyped.83unsigned NumModeIds = RCsWithLargestRegSize.size();84for (unsigned M = 0; M < NumModeIds; ++M) {85if (RCsWithLargestRegSize[M] == nullptr)86RCsWithLargestRegSize[M] = RC;87else if (RCsWithLargestRegSize[M]->RSI.get(M).SpillSize <88RC->RSI.get(M).SpillSize)89RCsWithLargestRegSize[M] = RC;90assert(RCsWithLargestRegSize[M] && "RC was nullptr?");91}9293RCs.emplace_back(RC);94}9596const CodeGenRegisterClass *getRCWithLargestRegSize(unsigned HwMode) const {97return RCsWithLargestRegSize[HwMode];98}99100iterator_range<typename RegisterClassesTy::const_iterator>101register_classes() const {102return llvm::make_range(RCs.begin(), RCs.end());103}104};105106class RegisterBankEmitter {107private:108CodeGenTarget Target;109RecordKeeper &Records;110111void emitHeader(raw_ostream &OS, const StringRef TargetName,112const std::vector<RegisterBank> &Banks);113void emitBaseClassDefinition(raw_ostream &OS, const StringRef TargetName,114const std::vector<RegisterBank> &Banks);115void emitBaseClassImplementation(raw_ostream &OS, const StringRef TargetName,116std::vector<RegisterBank> &Banks);117118public:119RegisterBankEmitter(RecordKeeper &R) : Target(R), Records(R) {}120121void run(raw_ostream &OS);122};123124} // end anonymous namespace125126/// Emit code to declare the ID enumeration and external global instance127/// variables.128void RegisterBankEmitter::emitHeader(raw_ostream &OS,129const StringRef TargetName,130const std::vector<RegisterBank> &Banks) {131// <Target>RegisterBankInfo.h132OS << "namespace llvm {\n"133<< "namespace " << TargetName << " {\n"134<< "enum : unsigned {\n";135136OS << " InvalidRegBankID = ~0u,\n";137unsigned ID = 0;138for (const auto &Bank : Banks)139OS << " " << Bank.getEnumeratorName() << " = " << ID++ << ",\n";140OS << " NumRegisterBanks,\n"141<< "};\n"142<< "} // end namespace " << TargetName << "\n"143<< "} // end namespace llvm\n";144}145146/// Emit declarations of the <Target>GenRegisterBankInfo class.147void RegisterBankEmitter::emitBaseClassDefinition(148raw_ostream &OS, const StringRef TargetName,149const std::vector<RegisterBank> &Banks) {150OS << "private:\n"151<< " static const RegisterBank *RegBanks[];\n"152<< " static const unsigned Sizes[];\n\n"153<< "protected:\n"154<< " " << TargetName << "GenRegisterBankInfo(unsigned HwMode = 0);\n"155<< "\n";156}157158/// Visit each register class belonging to the given register bank.159///160/// A class belongs to the bank iff any of these apply:161/// * It is explicitly specified162/// * It is a subclass of a class that is a member.163/// * It is a class containing subregisters of the registers of a class that164/// is a member. This is known as a subreg-class.165///166/// This function must be called for each explicitly specified register class.167///168/// \param RC The register class to search.169/// \param Kind A debug string containing the path the visitor took to reach RC.170/// \param VisitFn The action to take for each class visited. It may be called171/// multiple times for a given class if there are multiple paths172/// to the class.173static void visitRegisterBankClasses(174const CodeGenRegBank &RegisterClassHierarchy,175const CodeGenRegisterClass *RC, const Twine &Kind,176std::function<void(const CodeGenRegisterClass *, StringRef)> VisitFn,177SmallPtrSetImpl<const CodeGenRegisterClass *> &VisitedRCs) {178179// Make sure we only visit each class once to avoid infinite loops.180if (!VisitedRCs.insert(RC).second)181return;182183// Visit each explicitly named class.184VisitFn(RC, Kind.str());185186for (const auto &PossibleSubclass : RegisterClassHierarchy.getRegClasses()) {187std::string TmpKind =188(Kind + " (" + PossibleSubclass.getName() + ")").str();189190// Visit each subclass of an explicitly named class.191if (RC != &PossibleSubclass && RC->hasSubClass(&PossibleSubclass))192visitRegisterBankClasses(RegisterClassHierarchy, &PossibleSubclass,193TmpKind + " " + RC->getName() + " subclass",194VisitFn, VisitedRCs);195196// Visit each class that contains only subregisters of RC with a common197// subregister-index.198//199// More precisely, PossibleSubclass is a subreg-class iff Reg:SubIdx is in200// PossibleSubclass for all registers Reg from RC using any201// subregister-index SubReg202for (const auto &SubIdx : RegisterClassHierarchy.getSubRegIndices()) {203BitVector BV(RegisterClassHierarchy.getRegClasses().size());204PossibleSubclass.getSuperRegClasses(&SubIdx, BV);205if (BV.test(RC->EnumValue)) {206std::string TmpKind2 = (Twine(TmpKind) + " " + RC->getName() +207" class-with-subregs: " + RC->getName())208.str();209VisitFn(&PossibleSubclass, TmpKind2);210}211}212}213}214215void RegisterBankEmitter::emitBaseClassImplementation(216raw_ostream &OS, StringRef TargetName, std::vector<RegisterBank> &Banks) {217const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();218const CodeGenHwModes &CGH = Target.getHwModes();219220OS << "namespace llvm {\n"221<< "namespace " << TargetName << " {\n";222for (const auto &Bank : Banks) {223std::vector<std::vector<const CodeGenRegisterClass *>> RCsGroupedByWord(224(RegisterClassHierarchy.getRegClasses().size() + 31) / 32);225226for (const auto &RC : Bank.register_classes())227RCsGroupedByWord[RC->EnumValue / 32].push_back(RC);228229OS << "const uint32_t " << Bank.getCoverageArrayName() << "[] = {\n";230unsigned LowestIdxInWord = 0;231for (const auto &RCs : RCsGroupedByWord) {232OS << " // " << LowestIdxInWord << "-" << (LowestIdxInWord + 31)233<< "\n";234for (const auto &RC : RCs) {235OS << " (1u << (" << RC->getQualifiedIdName() << " - "236<< LowestIdxInWord << ")) |\n";237}238OS << " 0,\n";239LowestIdxInWord += 32;240}241OS << "};\n";242}243OS << "\n";244245for (const auto &Bank : Banks) {246std::string QualifiedBankID =247(TargetName + "::" + Bank.getEnumeratorName()).str();248OS << "constexpr RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ "249<< QualifiedBankID << ", /* Name */ \"" << Bank.getName() << "\", "250<< "/* CoveredRegClasses */ " << Bank.getCoverageArrayName()251<< ", /* NumRegClasses */ "252<< RegisterClassHierarchy.getRegClasses().size() << ");\n";253}254OS << "} // end namespace " << TargetName << "\n"255<< "\n";256257OS << "const RegisterBank *" << TargetName258<< "GenRegisterBankInfo::RegBanks[] = {\n";259for (const auto &Bank : Banks)260OS << " &" << TargetName << "::" << Bank.getInstanceVarName() << ",\n";261OS << "};\n\n";262263unsigned NumModeIds = CGH.getNumModeIds();264OS << "const unsigned " << TargetName << "GenRegisterBankInfo::Sizes[] = {\n";265for (unsigned M = 0; M < NumModeIds; ++M) {266OS << " // Mode = " << M << " (";267if (M == DefaultMode)268OS << "Default";269else270OS << CGH.getMode(M).Name;271OS << ")\n";272for (const auto &Bank : Banks) {273const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegSize(M);274unsigned Size = RC.RSI.get(M).SpillSize;275OS << " " << Size << ",\n";276}277}278OS << "};\n\n";279280OS << TargetName << "GenRegisterBankInfo::" << TargetName281<< "GenRegisterBankInfo(unsigned HwMode)\n"282<< " : RegisterBankInfo(RegBanks, " << TargetName283<< "::NumRegisterBanks, Sizes, HwMode) {\n"284<< " // Assert that RegBank indices match their ID's\n"285<< "#ifndef NDEBUG\n"286<< " for (auto RB : enumerate(RegBanks))\n"287<< " assert(RB.index() == RB.value()->getID() && \"Index != ID\");\n"288<< "#endif // NDEBUG\n"289<< "}\n"290<< "} // end namespace llvm\n";291}292293void RegisterBankEmitter::run(raw_ostream &OS) {294StringRef TargetName = Target.getName();295const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();296const CodeGenHwModes &CGH = Target.getHwModes();297298Records.startTimer("Analyze records");299std::vector<RegisterBank> Banks;300for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) {301SmallPtrSet<const CodeGenRegisterClass *, 8> VisitedRCs;302RegisterBank Bank(*V, CGH.getNumModeIds());303304for (const CodeGenRegisterClass *RC :305Bank.getExplicitlySpecifiedRegisterClasses(RegisterClassHierarchy)) {306visitRegisterBankClasses(307RegisterClassHierarchy, RC, "explicit",308[&Bank](const CodeGenRegisterClass *RC, StringRef Kind) {309LLVM_DEBUG(dbgs()310<< "Added " << RC->getName() << "(" << Kind << ")\n");311Bank.addRegisterClass(RC);312},313VisitedRCs);314}315316Banks.push_back(Bank);317}318319// Warn about ambiguous MIR caused by register bank/class name clashes.320Records.startTimer("Warn ambiguous");321for (const auto &Class : RegisterClassHierarchy.getRegClasses()) {322for (const auto &Bank : Banks) {323if (Bank.getName().lower() == StringRef(Class.getName()).lower()) {324PrintWarning(Bank.getDef().getLoc(), "Register bank names should be "325"distinct from register classes "326"to avoid ambiguous MIR");327PrintNote(Bank.getDef().getLoc(), "RegisterBank was declared here");328PrintNote(Class.getDef()->getLoc(), "RegisterClass was declared here");329}330}331}332333Records.startTimer("Emit output");334emitSourceFileHeader("Register Bank Source Fragments", OS);335OS << "#ifdef GET_REGBANK_DECLARATIONS\n"336<< "#undef GET_REGBANK_DECLARATIONS\n";337emitHeader(OS, TargetName, Banks);338OS << "#endif // GET_REGBANK_DECLARATIONS\n\n"339<< "#ifdef GET_TARGET_REGBANK_CLASS\n"340<< "#undef GET_TARGET_REGBANK_CLASS\n";341emitBaseClassDefinition(OS, TargetName, Banks);342OS << "#endif // GET_TARGET_REGBANK_CLASS\n\n"343<< "#ifdef GET_TARGET_REGBANK_IMPL\n"344<< "#undef GET_TARGET_REGBANK_IMPL\n";345emitBaseClassImplementation(OS, TargetName, Banks);346OS << "#endif // GET_TARGET_REGBANK_IMPL\n";347}348349static TableGen::Emitter::OptClass<RegisterBankEmitter>350X("gen-register-bank", "Generate registers bank descriptions");351352353