Changeset View
Changeset View
Standalone View
Standalone View
llvm/utils/TableGen/RegisterInfoEmitter.cpp
//===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===// | //===- RegisterInfoEmitter.cpp - Generate a Register File Desc. -*- C++ -*-===// | ||||
// | // | ||||
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | ||||
// See https://llvm.org/LICENSE.txt for license information. | // See https://llvm.org/LICENSE.txt for license information. | ||||
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
// | // | ||||
// This tablegen backend is responsible for emitting a description of a target | // This tablegen backend is responsible for emitting a description of a target | ||||
// register file for a code generator. It uses instances of the Register, | // register file for a code generator. It uses instances of the Register, | ||||
// RegisterAliases, and RegisterClass classes to gather this information. | // RegisterAliases, and RegisterClass classes to gather this information. | ||||
// | // | ||||
//===----------------------------------------------------------------------===// | //===----------------------------------------------------------------------===// | ||||
#include "CodeGenRegisters.h" | #include "Printer.h" | ||||
#include "CodeGenTarget.h" | #include "RegisterInfoEmitterTypes.h" | ||||
#include "SequenceToOffsetTable.h" | |||||
#include "Types.h" | |||||
#include "llvm/ADT/ArrayRef.h" | |||||
#include "llvm/ADT/BitVector.h" | |||||
#include "llvm/ADT/STLExtras.h" | |||||
#include "llvm/ADT/SetVector.h" | |||||
#include "llvm/ADT/SmallVector.h" | |||||
#include "llvm/ADT/SparseBitVector.h" | |||||
#include "llvm/ADT/Twine.h" | |||||
#include "llvm/Support/Casting.h" | |||||
#include "llvm/Support/CommandLine.h" | |||||
#include "llvm/Support/Format.h" | |||||
#include "llvm/Support/MachineValueType.h" | |||||
#include "llvm/Support/raw_ostream.h" | |||||
#include "llvm/TableGen/Error.h" | |||||
#include "llvm/TableGen/Record.h" | |||||
#include "llvm/TableGen/SetTheory.h" | |||||
#include "llvm/TableGen/TableGenBackend.h" | |||||
#include <algorithm> | |||||
#include <cassert> | |||||
#include <cstddef> | |||||
#include <cstdint> | |||||
#include <deque> | |||||
#include <iterator> | |||||
#include <set> | |||||
#include <string> | |||||
#include <vector> | |||||
using namespace llvm; | using namespace llvm; | ||||
cl::OptionCategory RegisterInfoCat("Options for -gen-register-info"); | cl::OptionCategory RegisterInfoCat("Options for -gen-register-info"); | ||||
static cl::opt<bool> | static cl::opt<bool> | ||||
RegisterInfoDebug("register-info-debug", cl::init(false), | RegisterInfoDebug("register-info-debug", cl::init(false), | ||||
cl::desc("Dump register information to help debugging"), | cl::desc("Dump register information to help debugging"), | ||||
cl::cat(RegisterInfoCat)); | cl::cat(RegisterInfoCat)); | ||||
namespace { | namespace { | ||||
class RegisterInfoEmitter { | class RegisterInfoEmitter { | ||||
CodeGenTarget Target; | CodeGenTarget Target; | ||||
RecordKeeper &Records; | RecordKeeper &Records; | ||||
PrinterLLVM &PI; | |||||
public: | public: | ||||
RegisterInfoEmitter(RecordKeeper &R) : Target(R), Records(R) { | RegisterInfoEmitter(RecordKeeper &R, PrinterLLVM &PI) | ||||
: Target(R), Records(R), PI(PI) { | |||||
CodeGenRegBank &RegBank = Target.getRegBank(); | CodeGenRegBank &RegBank = Target.getRegBank(); | ||||
RegBank.computeDerivedInfo(); | RegBank.computeDerivedInfo(); | ||||
} | } | ||||
// runEnums - Print out enum values for all of the registers. | |||||
void runEnums(raw_ostream &o, CodeGenTarget &Target, CodeGenRegBank &Bank); | |||||
// runMCDesc - Print out MC register descriptions. | // runMCDesc - Print out MC register descriptions. | ||||
void runMCDesc(raw_ostream &o, CodeGenTarget &Target, CodeGenRegBank &Bank); | void runMCDesc(CodeGenTarget &Target, CodeGenRegBank &Bank); | ||||
// runTargetHeader - Emit a header fragment for the register info emitter. | // runTargetHeader - Emit a header fragment for the register info emitter. | ||||
void runTargetHeader(raw_ostream &o, CodeGenTarget &Target, | void runTargetHeader(CodeGenTarget &Target, | ||||
CodeGenRegBank &Bank); | CodeGenRegBank &Bank); | ||||
// runTargetDesc - Output the target register and register file descriptions. | // runTargetDesc - Output the target register and register file descriptions. | ||||
void runTargetDesc(raw_ostream &o, CodeGenTarget &Target, | void runTargetDesc(CodeGenTarget &Target, | ||||
CodeGenRegBank &Bank); | CodeGenRegBank &Bank); | ||||
// run - Output the register file description. | // run - Output the register file description. | ||||
void run(raw_ostream &o); | void run(); | ||||
void debugDump(raw_ostream &OS); | void debugDump(raw_ostream &OS); | ||||
private: | private: | ||||
void EmitRegMapping(raw_ostream &o, const std::deque<CodeGenRegister> &Regs, | void EmitRegMapping(const std::deque<CodeGenRegister> &Regs, | ||||
bool isCtor); | bool isCtor); | ||||
void EmitRegMappingTables(raw_ostream &o, | void EmitRegMappingTables(const std::deque<CodeGenRegister> &Regs, | ||||
const std::deque<CodeGenRegister> &Regs, | |||||
bool isCtor); | bool isCtor); | ||||
void EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, | void EmitRegUnitPressure(const CodeGenRegBank &RegBank, | ||||
const std::string &ClassName); | const std::string &ClassName); | ||||
void emitComposeSubRegIndices(raw_ostream &OS, CodeGenRegBank &RegBank, | void emitComposeSubRegIndices(CodeGenRegBank &RegBank, | ||||
const std::string &ClassName); | const std::string &ClassName); | ||||
void emitComposeSubRegIndexLaneMask(raw_ostream &OS, CodeGenRegBank &RegBank, | void emitComposeSubRegIndexLaneMask(CodeGenRegBank &RegBank, | ||||
const std::string &ClassName); | const std::string &ClassName); | ||||
}; | }; | ||||
} // end anonymous namespace | } // end anonymous namespace | ||||
// runEnums - Print out enum values for all of the registers. | |||||
void RegisterInfoEmitter::runEnums(raw_ostream &OS, | |||||
CodeGenTarget &Target, CodeGenRegBank &Bank) { | |||||
const auto &Registers = Bank.getRegisters(); | |||||
// Register enums are stored as uint16_t in the tables. Make sure we'll fit. | |||||
assert(Registers.size() <= 0xffff && "Too many regs to fit in tables"); | |||||
StringRef Namespace = Registers.front().TheDef->getValueAsString("Namespace"); | |||||
emitSourceFileHeader("Target Register Enum Values", OS); | |||||
OS << "\n#ifdef GET_REGINFO_ENUM\n"; | |||||
OS << "#undef GET_REGINFO_ENUM\n\n"; | |||||
OS << "namespace llvm {\n\n"; | |||||
OS << "class MCRegisterClass;\n" | |||||
<< "extern const MCRegisterClass " << Target.getName() | |||||
<< "MCRegisterClasses[];\n\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "namespace " << Namespace << " {\n"; | |||||
OS << "enum {\n NoRegister,\n"; | |||||
for (const auto &Reg : Registers) | |||||
OS << " " << Reg.getName() << " = " << Reg.EnumValue << ",\n"; | |||||
assert(Registers.size() == Registers.back().EnumValue && | |||||
"Register enum value mismatch!"); | |||||
OS << " NUM_TARGET_REGS // " << Registers.size()+1 << "\n"; | |||||
OS << "};\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "} // end namespace " << Namespace << "\n"; | |||||
const auto &RegisterClasses = Bank.getRegClasses(); | |||||
if (!RegisterClasses.empty()) { | |||||
// RegisterClass enums are stored as uint16_t in the tables. | |||||
assert(RegisterClasses.size() <= 0xffff && | |||||
"Too many register classes to fit in tables"); | |||||
OS << "\n// Register classes\n\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "namespace " << Namespace << " {\n"; | |||||
OS << "enum {\n"; | |||||
for (const auto &RC : RegisterClasses) | |||||
OS << " " << RC.getName() << "RegClassID" | |||||
<< " = " << RC.EnumValue << ",\n"; | |||||
OS << "\n};\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "} // end namespace " << Namespace << "\n\n"; | |||||
} | |||||
const std::vector<Record*> &RegAltNameIndices = Target.getRegAltNameIndices(); | |||||
// If the only definition is the default NoRegAltName, we don't need to | |||||
// emit anything. | |||||
if (RegAltNameIndices.size() > 1) { | |||||
OS << "\n// Register alternate name indices\n\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "namespace " << Namespace << " {\n"; | |||||
OS << "enum {\n"; | |||||
for (unsigned i = 0, e = RegAltNameIndices.size(); i != e; ++i) | |||||
OS << " " << RegAltNameIndices[i]->getName() << ",\t// " << i << "\n"; | |||||
OS << " NUM_TARGET_REG_ALT_NAMES = " << RegAltNameIndices.size() << "\n"; | |||||
OS << "};\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "} // end namespace " << Namespace << "\n\n"; | |||||
} | |||||
auto &SubRegIndices = Bank.getSubRegIndices(); | |||||
if (!SubRegIndices.empty()) { | |||||
OS << "\n// Subregister indices\n\n"; | |||||
std::string Namespace = SubRegIndices.front().getNamespace(); | |||||
if (!Namespace.empty()) | |||||
OS << "namespace " << Namespace << " {\n"; | |||||
OS << "enum : uint16_t {\n NoSubRegister,\n"; | |||||
unsigned i = 0; | |||||
for (const auto &Idx : SubRegIndices) | |||||
OS << " " << Idx.getName() << ",\t// " << ++i << "\n"; | |||||
OS << " NUM_TARGET_SUBREGS\n};\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "} // end namespace " << Namespace << "\n\n"; | |||||
} | |||||
OS << "// Register pressure sets enum.\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "namespace " << Namespace << " {\n"; | |||||
OS << "enum RegisterPressureSets {\n"; | |||||
unsigned NumSets = Bank.getNumRegPressureSets(); | |||||
for (unsigned i = 0; i < NumSets; ++i ) { | |||||
const RegUnitSet &RegUnits = Bank.getRegSetAt(i); | |||||
OS << " " << RegUnits.Name << " = " << i << ",\n"; | |||||
} | |||||
OS << "};\n"; | |||||
if (!Namespace.empty()) | |||||
OS << "} // end namespace " << Namespace << '\n'; | |||||
OS << '\n'; | |||||
OS << "} // end namespace llvm\n\n"; | |||||
OS << "#endif // GET_REGINFO_ENUM\n\n"; | |||||
} | |||||
static void printInt(raw_ostream &OS, int Val) { | |||||
OS << Val; | |||||
} | |||||
void RegisterInfoEmitter:: | void RegisterInfoEmitter:: | ||||
EmitRegUnitPressure(raw_ostream &OS, const CodeGenRegBank &RegBank, | EmitRegUnitPressure(const CodeGenRegBank &RegBank, | ||||
const std::string &ClassName) { | const std::string &ClassName) { | ||||
unsigned NumRCs = RegBank.getRegClasses().size(); | unsigned NumRCs = RegBank.getRegClasses().size(); | ||||
unsigned NumSets = RegBank.getNumRegPressureSets(); | unsigned NumSets = RegBank.getNumRegPressureSets(); | ||||
OS << "/// Get the weight in units of pressure for this register class.\n" | PI.regInfoEmitRegClassWeight(RegBank, ClassName); | ||||
<< "const RegClassWeight &" << ClassName << "::\n" | |||||
<< "getRegClassWeight(const TargetRegisterClass *RC) const {\n" | |||||
<< " static const RegClassWeight RCWeightTable[] = {\n"; | |||||
for (const auto &RC : RegBank.getRegClasses()) { | |||||
const CodeGenRegister::Vec &Regs = RC.getMembers(); | |||||
OS << " {" << RC.getWeight(RegBank) << ", "; | |||||
if (Regs.empty() || RC.Artificial) | |||||
OS << '0'; | |||||
else { | |||||
std::vector<unsigned> RegUnits; | |||||
RC.buildRegUnitSet(RegBank, RegUnits); | |||||
OS << RegBank.getRegUnitSetWeight(RegUnits); | |||||
} | |||||
OS << "}, \t// " << RC.getName() << "\n"; | |||||
} | |||||
OS << " };\n" | |||||
<< " return RCWeightTable[RC->getID()];\n" | |||||
<< "}\n\n"; | |||||
// Reasonable targets (not ARMv7) have unit weight for all units, so don't | // Reasonable targets (not ARMv7) have unit weight for all units, so don't | ||||
// bother generating a table. | // bother generating a table. | ||||
bool RegUnitsHaveUnitWeight = true; | bool RegUnitsHaveUnitWeight = true; | ||||
for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits(); | for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits(); | ||||
UnitIdx < UnitEnd; ++UnitIdx) { | UnitIdx < UnitEnd; ++UnitIdx) { | ||||
if (RegBank.getRegUnit(UnitIdx).Weight > 1) | if (RegBank.getRegUnit(UnitIdx).Weight > 1) | ||||
RegUnitsHaveUnitWeight = false; | RegUnitsHaveUnitWeight = false; | ||||
} | } | ||||
OS << "/// Get the weight in units of pressure for this register unit.\n" | PI.regInfoEmitRegUnitWeight(RegBank, ClassName, RegUnitsHaveUnitWeight); | ||||
<< "unsigned " << ClassName << "::\n" | PI.regInfoEmitGetNumRegPressureSets(ClassName, NumSets); | ||||
<< "getRegUnitWeight(unsigned RegUnit) const {\n" | PI.regInfoEmitGetRegPressureTables(RegBank, ClassName, NumSets); | ||||
<< " assert(RegUnit < " << RegBank.getNumNativeRegUnits() | |||||
<< " && \"invalid register unit\");\n"; | |||||
if (!RegUnitsHaveUnitWeight) { | |||||
OS << " static const uint8_t RUWeightTable[] = {\n "; | |||||
for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits(); | |||||
UnitIdx < UnitEnd; ++UnitIdx) { | |||||
const RegUnit &RU = RegBank.getRegUnit(UnitIdx); | |||||
assert(RU.Weight < 256 && "RegUnit too heavy"); | |||||
OS << RU.Weight << ", "; | |||||
} | |||||
OS << "};\n" | |||||
<< " return RUWeightTable[RegUnit];\n"; | |||||
} | |||||
else { | |||||
OS << " // All register units have unit weight.\n" | |||||
<< " return 1;\n"; | |||||
} | |||||
OS << "}\n\n"; | |||||
OS << "\n" | |||||
<< "// Get the number of dimensions of register pressure.\n" | |||||
<< "unsigned " << ClassName << "::getNumRegPressureSets() const {\n" | |||||
<< " return " << NumSets << ";\n}\n\n"; | |||||
OS << "// Get the name of this register unit pressure set.\n" | |||||
<< "const char *" << ClassName << "::\n" | |||||
<< "getRegPressureSetName(unsigned Idx) const {\n" | |||||
<< " static const char *PressureNameTable[] = {\n"; | |||||
unsigned MaxRegUnitWeight = 0; | |||||
for (unsigned i = 0; i < NumSets; ++i ) { | |||||
const RegUnitSet &RegUnits = RegBank.getRegSetAt(i); | |||||
MaxRegUnitWeight = std::max(MaxRegUnitWeight, RegUnits.Weight); | |||||
OS << " \"" << RegUnits.Name << "\",\n"; | |||||
} | |||||
OS << " };\n" | |||||
<< " return PressureNameTable[Idx];\n" | |||||
<< "}\n\n"; | |||||
OS << "// Get the register unit pressure limit for this dimension.\n" | |||||
<< "// This limit must be adjusted dynamically for reserved registers.\n" | |||||
<< "unsigned " << ClassName << "::\n" | |||||
<< "getRegPressureSetLimit(const MachineFunction &MF, unsigned Idx) const " | |||||
"{\n" | |||||
<< " static const " << getMinimalTypeForRange(MaxRegUnitWeight, 32) | |||||
<< " PressureLimitTable[] = {\n"; | |||||
for (unsigned i = 0; i < NumSets; ++i ) { | |||||
const RegUnitSet &RegUnits = RegBank.getRegSetAt(i); | |||||
OS << " " << RegUnits.Weight << ", \t// " << i << ": " | |||||
<< RegUnits.Name << "\n"; | |||||
} | |||||
OS << " };\n" | |||||
<< " return PressureLimitTable[Idx];\n" | |||||
<< "}\n\n"; | |||||
SequenceToOffsetTable<std::vector<int>> PSetsSeqs; | SequenceToOffsetTable<std::vector<int>> PSetsSeqs(PI.getLanguage()); | ||||
// This table may be larger than NumRCs if some register units needed a list | // This table may be larger than NumRCs if some register units needed a list | ||||
// of unit sets that did not correspond to a register class. | // of unit sets that did not correspond to a register class. | ||||
unsigned NumRCUnitSets = RegBank.getNumRegClassPressureSetLists(); | unsigned NumRCUnitSets = RegBank.getNumRegClassPressureSetLists(); | ||||
std::vector<std::vector<int>> PSets(NumRCUnitSets); | std::vector<std::vector<int>> PSets(NumRCUnitSets); | ||||
for (unsigned i = 0, e = NumRCUnitSets; i != e; ++i) { | for (unsigned i = 0, e = NumRCUnitSets; i != e; ++i) { | ||||
ArrayRef<unsigned> PSetIDs = RegBank.getRCPressureSetIDs(i); | ArrayRef<unsigned> PSetIDs = RegBank.getRCPressureSetIDs(i); | ||||
PSets[i].reserve(PSetIDs.size()); | PSets[i].reserve(PSetIDs.size()); | ||||
for (unsigned PSetID : PSetIDs) { | for (unsigned PSetID : PSetIDs) { | ||||
PSets[i].push_back(RegBank.getRegPressureSet(PSetID).Order); | PSets[i].push_back(RegBank.getRegPressureSet(PSetID).Order); | ||||
} | } | ||||
llvm::sort(PSets[i]); | llvm::sort(PSets[i]); | ||||
PSetsSeqs.add(PSets[i]); | PSetsSeqs.add(PSets[i]); | ||||
} | } | ||||
PSetsSeqs.layout(); | PSetsSeqs.layout(); | ||||
PI.regInfoEmitRCSetsTable(ClassName, NumRCs, PSetsSeqs, PSets); | |||||
OS << "/// Table of pressure sets per register class or unit.\n" | PI.regInfoEmitGetRegUnitPressureSets(PSetsSeqs, RegBank, | ||||
<< "static const int RCSetsTable[] = {\n"; | ClassName, PSets); | ||||
PSetsSeqs.emit(OS, printInt, "-1"); | |||||
OS << "};\n\n"; | |||||
OS << "/// Get the dimensions of register pressure impacted by this " | |||||
<< "register class.\n" | |||||
<< "/// Returns a -1 terminated array of pressure set IDs\n" | |||||
<< "const int *" << ClassName << "::\n" | |||||
<< "getRegClassPressureSets(const TargetRegisterClass *RC) const {\n"; | |||||
OS << " static const " << getMinimalTypeForRange(PSetsSeqs.size() - 1, 32) | |||||
<< " RCSetStartTable[] = {\n "; | |||||
for (unsigned i = 0, e = NumRCs; i != e; ++i) { | |||||
OS << PSetsSeqs.get(PSets[i]) << ","; | |||||
} | |||||
OS << "};\n" | |||||
<< " return &RCSetsTable[RCSetStartTable[RC->getID()]];\n" | |||||
<< "}\n\n"; | |||||
OS << "/// Get the dimensions of register pressure impacted by this " | |||||
<< "register unit.\n" | |||||
<< "/// Returns a -1 terminated array of pressure set IDs\n" | |||||
<< "const int *" << ClassName << "::\n" | |||||
<< "getRegUnitPressureSets(unsigned RegUnit) const {\n" | |||||
<< " assert(RegUnit < " << RegBank.getNumNativeRegUnits() | |||||
<< " && \"invalid register unit\");\n"; | |||||
OS << " static const " << getMinimalTypeForRange(PSetsSeqs.size() - 1, 32) | |||||
<< " RUSetStartTable[] = {\n "; | |||||
for (unsigned UnitIdx = 0, UnitEnd = RegBank.getNumNativeRegUnits(); | |||||
UnitIdx < UnitEnd; ++UnitIdx) { | |||||
OS << PSetsSeqs.get(PSets[RegBank.getRegUnit(UnitIdx).RegClassUnitSetsIdx]) | |||||
<< ","; | |||||
} | |||||
OS << "};\n" | |||||
<< " return &RCSetsTable[RUSetStartTable[RegUnit]];\n" | |||||
<< "}\n\n"; | |||||
} | } | ||||
using DwarfRegNumsMapPair = std::pair<Record*, std::vector<int64_t>>; | |||||
using DwarfRegNumsVecTy = std::vector<DwarfRegNumsMapPair>; | |||||
static void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) { | static void finalizeDwarfRegNumsKeys(DwarfRegNumsVecTy &DwarfRegNums) { | ||||
// Sort and unique to get a map-like vector. We want the last assignment to | // Sort and unique to get a map-like vector. We want the last assignment to | ||||
// match previous behaviour. | // match previous behaviour. | ||||
llvm::stable_sort(DwarfRegNums, on_first<LessRecordRegister>()); | llvm::stable_sort(DwarfRegNums, on_first<LessRecordRegister>()); | ||||
// Warn about duplicate assignments. | // Warn about duplicate assignments. | ||||
const Record *LastSeenReg = nullptr; | const Record *LastSeenReg = nullptr; | ||||
for (const auto &X : DwarfRegNums) { | for (const auto &X : DwarfRegNums) { | ||||
const auto &Reg = X.first; | const auto &Reg = X.first; | ||||
Show All 9 Lines | auto Last = std::unique( | ||||
DwarfRegNums.begin(), DwarfRegNums.end(), | DwarfRegNums.begin(), DwarfRegNums.end(), | ||||
[](const DwarfRegNumsMapPair &A, const DwarfRegNumsMapPair &B) { | [](const DwarfRegNumsMapPair &A, const DwarfRegNumsMapPair &B) { | ||||
return A.first->getName() == B.first->getName(); | return A.first->getName() == B.first->getName(); | ||||
}); | }); | ||||
DwarfRegNums.erase(Last, DwarfRegNums.end()); | DwarfRegNums.erase(Last, DwarfRegNums.end()); | ||||
} | } | ||||
void RegisterInfoEmitter::EmitRegMappingTables( | void RegisterInfoEmitter::EmitRegMappingTables( | ||||
raw_ostream &OS, const std::deque<CodeGenRegister> &Regs, bool isCtor) { | const std::deque<CodeGenRegister> &Regs, bool isCtor) { | ||||
// Collect all information about dwarf register numbers | // Collect all information about dwarf register numbers | ||||
DwarfRegNumsVecTy DwarfRegNums; | DwarfRegNumsVecTy DwarfRegNums; | ||||
// First, just pull all provided information to the map | // First, just pull all provided information to the map | ||||
unsigned maxLength = 0; | unsigned maxLength = 0; | ||||
for (auto &RE : Regs) { | for (auto &RE : Regs) { | ||||
Record *Reg = RE.TheDef; | Record *Reg = RE.TheDef; | ||||
std::vector<int64_t> RegNums = Reg->getValueAsListOfInts("DwarfNumbers"); | std::vector<int64_t> RegNums = Reg->getValueAsListOfInts("DwarfNumbers"); | ||||
maxLength = std::max((size_t)maxLength, RegNums.size()); | maxLength = std::max((size_t)maxLength, RegNums.size()); | ||||
DwarfRegNums.emplace_back(Reg, std::move(RegNums)); | DwarfRegNums.emplace_back(Reg, std::move(RegNums)); | ||||
} | } | ||||
finalizeDwarfRegNumsKeys(DwarfRegNums); | finalizeDwarfRegNumsKeys(DwarfRegNums); | ||||
if (!maxLength) | if (!maxLength) | ||||
return; | return; | ||||
// Now we know maximal length of number list. Append -1's, where needed | // Now we know maximal length of number list. Append -1's, where needed | ||||
for (auto &DwarfRegNum : DwarfRegNums) | for (auto &DwarfRegNum : DwarfRegNums) | ||||
for (unsigned I = DwarfRegNum.second.size(), E = maxLength; I != E; ++I) | for (unsigned I = DwarfRegNum.second.size(), E = maxLength; I != E; ++I) | ||||
DwarfRegNum.second.push_back(-1); | DwarfRegNum.second.push_back(-1); | ||||
StringRef Namespace = Regs.front().TheDef->getValueAsString("Namespace"); | StringRef Namespace = Regs.front().TheDef->getValueAsString("Namespace"); | ||||
PI.regInfoEmitInfoDwarfRegsRev(Namespace, DwarfRegNums, maxLength, isCtor); | |||||
OS << "// " << Namespace << " Dwarf<->LLVM register mappings.\n"; | |||||
// Emit reverse information about the dwarf register numbers. | |||||
for (unsigned j = 0; j < 2; ++j) { | |||||
for (unsigned I = 0, E = maxLength; I != E; ++I) { | |||||
OS << "extern const MCRegisterInfo::DwarfLLVMRegPair " << Namespace; | |||||
OS << (j == 0 ? "DwarfFlavour" : "EHFlavour"); | |||||
OS << I << "Dwarf2L[]"; | |||||
if (!isCtor) { | |||||
OS << " = {\n"; | |||||
// Store the mapping sorted by the LLVM reg num so lookup can be done | |||||
// with a binary search. | |||||
std::map<uint64_t, Record*> Dwarf2LMap; | |||||
for (auto &DwarfRegNum : DwarfRegNums) { | |||||
int DwarfRegNo = DwarfRegNum.second[I]; | |||||
if (DwarfRegNo < 0) | |||||
continue; | |||||
Dwarf2LMap[DwarfRegNo] = DwarfRegNum.first; | |||||
} | |||||
for (auto &I : Dwarf2LMap) | |||||
OS << " { " << I.first << "U, " << getQualifiedName(I.second) | |||||
<< " },\n"; | |||||
OS << "};\n"; | |||||
} else { | |||||
OS << ";\n"; | |||||
} | |||||
// We have to store the size in a const global, it's used in multiple | |||||
// places. | |||||
OS << "extern const unsigned " << Namespace | |||||
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2LSize"; | |||||
if (!isCtor) | |||||
OS << " = std::size(" << Namespace | |||||
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << I << "Dwarf2L);\n\n"; | |||||
else | |||||
OS << ";\n\n"; | |||||
} | |||||
} | |||||
for (auto &RE : Regs) { | for (auto &RE : Regs) { | ||||
Record *Reg = RE.TheDef; | Record *Reg = RE.TheDef; | ||||
const RecordVal *V = Reg->getValue("DwarfAlias"); | const RecordVal *V = Reg->getValue("DwarfAlias"); | ||||
if (!V || !V->getValue()) | if (!V || !V->getValue()) | ||||
continue; | continue; | ||||
DefInit *DI = cast<DefInit>(V->getValue()); | DefInit *DI = cast<DefInit>(V->getValue()); | ||||
Show All 9 Lines | const auto &RegIter = llvm::lower_bound( | ||||
return LessRecordRegister()(A.first, B); | return LessRecordRegister()(A.first, B); | ||||
}); | }); | ||||
assert(RegIter != DwarfRegNums.end() && RegIter->first == Reg && | assert(RegIter != DwarfRegNums.end() && RegIter->first == Reg && | ||||
"Expected Reg to be present in map"); | "Expected Reg to be present in map"); | ||||
RegIter->second = AliasIter->second; | RegIter->second = AliasIter->second; | ||||
} | } | ||||
// Emit information about the dwarf register numbers. | // Emit information about the dwarf register numbers. | ||||
for (unsigned j = 0; j < 2; ++j) { | PI.regInfoEmitInfoDwarfRegs(Namespace, DwarfRegNums, maxLength, isCtor); | ||||
for (unsigned i = 0, e = maxLength; i != e; ++i) { | |||||
OS << "extern const MCRegisterInfo::DwarfLLVMRegPair " << Namespace; | |||||
OS << (j == 0 ? "DwarfFlavour" : "EHFlavour"); | |||||
OS << i << "L2Dwarf[]"; | |||||
if (!isCtor) { | |||||
OS << " = {\n"; | |||||
// Store the mapping sorted by the Dwarf reg num so lookup can be done | |||||
// with a binary search. | |||||
for (auto &DwarfRegNum : DwarfRegNums) { | |||||
int RegNo = DwarfRegNum.second[i]; | |||||
if (RegNo == -1) // -1 is the default value, don't emit a mapping. | |||||
continue; | |||||
OS << " { " << getQualifiedName(DwarfRegNum.first) << ", " << RegNo | |||||
<< "U },\n"; | |||||
} | |||||
OS << "};\n"; | |||||
} else { | |||||
OS << ";\n"; | |||||
} | |||||
// We have to store the size in a const global, it's used in multiple | |||||
// places. | |||||
OS << "extern const unsigned " << Namespace | |||||
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2DwarfSize"; | |||||
if (!isCtor) | |||||
OS << " = std::size(" << Namespace | |||||
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << i << "L2Dwarf);\n\n"; | |||||
else | |||||
OS << ";\n\n"; | |||||
} | |||||
} | |||||
} | } | ||||
void RegisterInfoEmitter::EmitRegMapping( | void RegisterInfoEmitter::EmitRegMapping( | ||||
raw_ostream &OS, const std::deque<CodeGenRegister> &Regs, bool isCtor) { | const std::deque<CodeGenRegister> &Regs, bool isCtor) { | ||||
// Emit the initializer so the tables from EmitRegMappingTables get wired up | // Emit the initializer so the tables from EmitRegMappingTables get wired up | ||||
// to the MCRegisterInfo object. | // to the MCRegisterInfo object. | ||||
unsigned maxLength = 0; | unsigned maxLength = 0; | ||||
for (auto &RE : Regs) { | for (auto &RE : Regs) { | ||||
Record *Reg = RE.TheDef; | Record *Reg = RE.TheDef; | ||||
maxLength = std::max((size_t)maxLength, | maxLength = std::max((size_t)maxLength, | ||||
Reg->getValueAsListOfInts("DwarfNumbers").size()); | Reg->getValueAsListOfInts("DwarfNumbers").size()); | ||||
} | } | ||||
if (!maxLength) | |||||
return; | |||||
StringRef Namespace = Regs.front().TheDef->getValueAsString("Namespace"); | StringRef Namespace = Regs.front().TheDef->getValueAsString("Namespace"); | ||||
PI.regInfoEmitInfoRegMapping(Namespace, maxLength, isCtor); | |||||
// Emit reverse information about the dwarf register numbers. | |||||
for (unsigned j = 0; j < 2; ++j) { | |||||
OS << " switch ("; | |||||
if (j == 0) | |||||
OS << "DwarfFlavour"; | |||||
else | |||||
OS << "EHFlavour"; | |||||
OS << ") {\n" | |||||
<< " default:\n" | |||||
<< " llvm_unreachable(\"Unknown DWARF flavour\");\n"; | |||||
for (unsigned i = 0, e = maxLength; i != e; ++i) { | |||||
OS << " case " << i << ":\n"; | |||||
OS << " "; | |||||
if (!isCtor) | |||||
OS << "RI->"; | |||||
std::string Tmp; | |||||
raw_string_ostream(Tmp) << Namespace | |||||
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << i | |||||
<< "Dwarf2L"; | |||||
OS << "mapDwarfRegsToLLVMRegs(" << Tmp << ", " << Tmp << "Size, "; | |||||
if (j == 0) | |||||
OS << "false"; | |||||
else | |||||
OS << "true"; | |||||
OS << ");\n"; | |||||
OS << " break;\n"; | |||||
} | |||||
OS << " }\n"; | |||||
} | |||||
// Emit information about the dwarf register numbers. | |||||
for (unsigned j = 0; j < 2; ++j) { | |||||
OS << " switch ("; | |||||
if (j == 0) | |||||
OS << "DwarfFlavour"; | |||||
else | |||||
OS << "EHFlavour"; | |||||
OS << ") {\n" | |||||
<< " default:\n" | |||||
<< " llvm_unreachable(\"Unknown DWARF flavour\");\n"; | |||||
for (unsigned i = 0, e = maxLength; i != e; ++i) { | |||||
OS << " case " << i << ":\n"; | |||||
OS << " "; | |||||
if (!isCtor) | |||||
OS << "RI->"; | |||||
std::string Tmp; | |||||
raw_string_ostream(Tmp) << Namespace | |||||
<< (j == 0 ? "DwarfFlavour" : "EHFlavour") << i | |||||
<< "L2Dwarf"; | |||||
OS << "mapLLVMRegsToDwarfRegs(" << Tmp << ", " << Tmp << "Size, "; | |||||
if (j == 0) | |||||
OS << "false"; | |||||
else | |||||
OS << "true"; | |||||
OS << ");\n"; | |||||
OS << " break;\n"; | |||||
} | |||||
OS << " }\n"; | |||||
} | } | ||||
} | |||||
// Print a BitVector as a sequence of hex numbers using a little-endian mapping. | |||||
// Width is the number of bits per hex number. | |||||
static void printBitVectorAsHex(raw_ostream &OS, | |||||
const BitVector &Bits, | |||||
unsigned Width) { | |||||
assert(Width <= 32 && "Width too large"); | |||||
unsigned Digits = (Width + 3) / 4; | |||||
for (unsigned i = 0, e = Bits.size(); i < e; i += Width) { | |||||
unsigned Value = 0; | |||||
for (unsigned j = 0; j != Width && i + j != e; ++j) | |||||
Value |= Bits.test(i + j) << j; | |||||
OS << format("0x%0*x, ", Digits, Value); | |||||
} | |||||
} | |||||
// Helper to emit a set of bits into a constant byte array. | |||||
class BitVectorEmitter { | |||||
BitVector Values; | |||||
public: | |||||
void add(unsigned v) { | |||||
if (v >= Values.size()) | |||||
Values.resize(((v/8)+1)*8); // Round up to the next byte. | |||||
Values[v] = true; | |||||
} | |||||
void print(raw_ostream &OS) { | |||||
printBitVectorAsHex(OS, Values, 8); | |||||
} | |||||
}; | |||||
static void printSimpleValueType(raw_ostream &OS, MVT::SimpleValueType VT) { | |||||
OS << getEnumName(VT); | |||||
} | |||||
static void printSubRegIndex(raw_ostream &OS, const CodeGenSubRegIndex *Idx) { | |||||
OS << Idx->EnumValue; | |||||
} | |||||
// Differentially encoded register and regunit lists allow for better | |||||
// compression on regular register banks. The sequence is computed from the | |||||
// differential list as: | |||||
// | |||||
// out[0] = InitVal; | |||||
// out[n+1] = out[n] + diff[n]; // n = 0, 1, ... | |||||
// | |||||
// The initial value depends on the specific list. The list is terminated by a | |||||
// 0 differential which means we can't encode repeated elements. | |||||
typedef SmallVector<uint16_t, 4> DiffVec; | |||||
typedef SmallVector<LaneBitmask, 4> MaskVec; | |||||
// Differentially encode a sequence of numbers into V. The starting value and | // Differentially encode a sequence of numbers into V. The starting value and | ||||
// terminating 0 are not added to V, so it will have the same size as List. | // terminating 0 are not added to V, so it will have the same size as List. | ||||
static | static | ||||
DiffVec &diffEncode(DiffVec &V, unsigned InitVal, SparseBitVector<> List) { | DiffVec &diffEncode(DiffVec &V, unsigned InitVal, SparseBitVector<> List) { | ||||
assert(V.empty() && "Clear DiffVec before diffEncode."); | assert(V.empty() && "Clear DiffVec before diffEncode."); | ||||
uint16_t Val = uint16_t(InitVal); | uint16_t Val = uint16_t(InitVal); | ||||
Show All 12 Lines | DiffVec &diffEncode(DiffVec &V, unsigned InitVal, Iter Begin, Iter End) { | ||||
for (Iter I = Begin; I != End; ++I) { | for (Iter I = Begin; I != End; ++I) { | ||||
uint16_t Cur = (*I)->EnumValue; | uint16_t Cur = (*I)->EnumValue; | ||||
V.push_back(Cur - Val); | V.push_back(Cur - Val); | ||||
Val = Cur; | Val = Cur; | ||||
} | } | ||||
return V; | return V; | ||||
} | } | ||||
static void printDiff16(raw_ostream &OS, uint16_t Val) { | |||||
OS << Val; | |||||
} | |||||
static void printMask(raw_ostream &OS, LaneBitmask Val) { | |||||
OS << "LaneBitmask(0x" << PrintLaneMask(Val) << ')'; | |||||
} | |||||
// Try to combine Idx's compose map into Vec if it is compatible. | // Try to combine Idx's compose map into Vec if it is compatible. | ||||
// Return false if it's not possible. | // Return false if it's not possible. | ||||
static bool combine(const CodeGenSubRegIndex *Idx, | static bool combine(const CodeGenSubRegIndex *Idx, | ||||
SmallVectorImpl<CodeGenSubRegIndex*> &Vec) { | SmallVectorImpl<CodeGenSubRegIndex*> &Vec) { | ||||
const CodeGenSubRegIndex::CompMap &Map = Idx->getComposites(); | const CodeGenSubRegIndex::CompMap &Map = Idx->getComposites(); | ||||
for (const auto &I : Map) { | for (const auto &I : Map) { | ||||
CodeGenSubRegIndex *&Entry = Vec[I.first->EnumValue - 1]; | CodeGenSubRegIndex *&Entry = Vec[I.first->EnumValue - 1]; | ||||
if (Entry && Entry != I.second) | if (Entry && Entry != I.second) | ||||
return false; | return false; | ||||
} | } | ||||
// All entries are compatible. Make it so. | // All entries are compatible. Make it so. | ||||
for (const auto &I : Map) { | for (const auto &I : Map) { | ||||
auto *&Entry = Vec[I.first->EnumValue - 1]; | auto *&Entry = Vec[I.first->EnumValue - 1]; | ||||
assert((!Entry || Entry == I.second) && | assert((!Entry || Entry == I.second) && | ||||
"Expected EnumValue to be unique"); | "Expected EnumValue to be unique"); | ||||
Entry = I.second; | Entry = I.second; | ||||
} | } | ||||
return true; | return true; | ||||
} | } | ||||
void | void | ||||
RegisterInfoEmitter::emitComposeSubRegIndices(raw_ostream &OS, | RegisterInfoEmitter::emitComposeSubRegIndices(CodeGenRegBank &RegBank, | ||||
CodeGenRegBank &RegBank, | |||||
const std::string &ClName) { | const std::string &ClName) { | ||||
const auto &SubRegIndices = RegBank.getSubRegIndices(); | const auto &SubRegIndices = RegBank.getSubRegIndices(); | ||||
OS << "unsigned " << ClName | PI.regInfoEmitComposeSubRegIndicesImplHead(ClName); | ||||
<< "::composeSubRegIndicesImpl(unsigned IdxA, unsigned IdxB) const {\n"; | |||||
// Many sub-register indexes are composition-compatible, meaning that | // Many sub-register indexes are composition-compatible, meaning that | ||||
// | // | ||||
// compose(IdxA, IdxB) == compose(IdxA', IdxB) | // compose(IdxA, IdxB) == compose(IdxA', IdxB) | ||||
// | // | ||||
// for many IdxA, IdxA' pairs. Not all sub-register indexes can be composed. | // for many IdxA, IdxA' pairs. Not all sub-register indexes can be composed. | ||||
// The illegal entries can be use as wildcards to compress the table further. | // The illegal entries can be use as wildcards to compress the table further. | ||||
// Map each Sub-register index to a compatible table row. | // Map each Sub-register index to a compatible table row. | ||||
Show All 15 Lines | if (Found == ~0u) { | ||||
Rows.resize(Found + 1); | Rows.resize(Found + 1); | ||||
Rows.back().resize(SubRegIndicesSize); | Rows.back().resize(SubRegIndicesSize); | ||||
combine(&Idx, Rows.back()); | combine(&Idx, Rows.back()); | ||||
} | } | ||||
RowMap.push_back(Found); | RowMap.push_back(Found); | ||||
} | } | ||||
// Output the row map if there is multiple rows. | // Output the row map if there is multiple rows. | ||||
if (Rows.size() > 1) { | PI.regInfoEmitComposeSubRegIndicesImplBody(Rows, SubRegIndicesSize, RowMap); | ||||
OS << " static const " << getMinimalTypeForRange(Rows.size(), 32) | |||||
<< " RowMap[" << SubRegIndicesSize << "] = {\n "; | |||||
for (unsigned i = 0, e = SubRegIndicesSize; i != e; ++i) | |||||
OS << RowMap[i] << ", "; | |||||
OS << "\n };\n"; | |||||
} | |||||
// Output the rows. | |||||
OS << " static const " << getMinimalTypeForRange(SubRegIndicesSize + 1, 32) | |||||
<< " Rows[" << Rows.size() << "][" << SubRegIndicesSize << "] = {\n"; | |||||
for (unsigned r = 0, re = Rows.size(); r != re; ++r) { | |||||
OS << " { "; | |||||
for (unsigned i = 0, e = SubRegIndicesSize; i != e; ++i) | |||||
if (Rows[r][i]) | |||||
OS << Rows[r][i]->getQualifiedName() << ", "; | |||||
else | |||||
OS << "0, "; | |||||
OS << "},\n"; | |||||
} | |||||
OS << " };\n\n"; | |||||
OS << " --IdxA; assert(IdxA < " << SubRegIndicesSize << "); (void) IdxA;\n" | |||||
<< " --IdxB; assert(IdxB < " << SubRegIndicesSize << ");\n"; | |||||
if (Rows.size() > 1) | |||||
OS << " return Rows[RowMap[IdxA]][IdxB];\n"; | |||||
else | |||||
OS << " return Rows[0][IdxB];\n"; | |||||
OS << "}\n\n"; | |||||
} | } | ||||
void | void | ||||
RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(raw_ostream &OS, | RegisterInfoEmitter::emitComposeSubRegIndexLaneMask(CodeGenRegBank &RegBank, | ||||
CodeGenRegBank &RegBank, | |||||
const std::string &ClName) { | const std::string &ClName) { | ||||
// See the comments in computeSubRegLaneMasks() for our goal here. | // See the comments in computeSubRegLaneMasks() for our goal here. | ||||
const auto &SubRegIndices = RegBank.getSubRegIndices(); | const auto &SubRegIndices = RegBank.getSubRegIndices(); | ||||
// Create a list of Mask+Rotate operations, with equivalent entries merged. | // Create a list of Mask+Rotate operations, with equivalent entries merged. | ||||
SmallVector<unsigned, 4> SubReg2SequenceIndexMap; | SmallVector<unsigned, 4> SubReg2SequenceIndexMap; | ||||
SmallVector<SmallVector<MaskRolPair, 1>, 4> Sequences; | SmallVector<SmallVector<MaskRolPair, 1>, 4> Sequences; | ||||
for (const auto &Idx : SubRegIndices) { | for (const auto &Idx : SubRegIndices) { | ||||
Show All 13 Lines | for (const auto &Idx : SubRegIndices) { | ||||
} | } | ||||
if (Found == ~0u) { | if (Found == ~0u) { | ||||
Sequences.push_back(IdxSequence); | Sequences.push_back(IdxSequence); | ||||
Found = SIdx; | Found = SIdx; | ||||
} | } | ||||
SubReg2SequenceIndexMap.push_back(Found); | SubReg2SequenceIndexMap.push_back(Found); | ||||
} | } | ||||
OS << " struct MaskRolOp {\n" | PI.regInfoEmitLaneMaskComposeSeq(Sequences, SubReg2SequenceIndexMap, SubRegIndices); | ||||
" LaneBitmask Mask;\n" | PI.regInfoEmitComposeSubRegIdxLaneMask(ClName, SubRegIndices); | ||||
" uint8_t RotateLeft;\n" | PI.regInfoEmitComposeSubRegIdxLaneMaskRev(ClName, SubRegIndices); | ||||
" };\n" | |||||
" static const MaskRolOp LaneMaskComposeSequences[] = {\n"; | |||||
unsigned Idx = 0; | |||||
for (size_t s = 0, se = Sequences.size(); s != se; ++s) { | |||||
OS << " "; | |||||
const SmallVectorImpl<MaskRolPair> &Sequence = Sequences[s]; | |||||
for (size_t p = 0, pe = Sequence.size(); p != pe; ++p) { | |||||
const MaskRolPair &P = Sequence[p]; | |||||
printMask(OS << "{ ", P.Mask); | |||||
OS << format(", %2u }, ", P.RotateLeft); | |||||
} | |||||
OS << "{ LaneBitmask::getNone(), 0 }"; | |||||
if (s+1 != se) | |||||
OS << ", "; | |||||
OS << " // Sequence " << Idx << "\n"; | |||||
Idx += Sequence.size() + 1; | |||||
} | |||||
auto *IntType = getMinimalTypeForRange(*std::max_element( | |||||
SubReg2SequenceIndexMap.begin(), SubReg2SequenceIndexMap.end())); | |||||
OS << " };\n" | |||||
" static const " | |||||
<< IntType << " CompositeSequences[] = {\n"; | |||||
for (size_t i = 0, e = SubRegIndices.size(); i != e; ++i) { | |||||
OS << " "; | |||||
OS << SubReg2SequenceIndexMap[i]; | |||||
if (i+1 != e) | |||||
OS << ","; | |||||
OS << " // to " << SubRegIndices[i].getName() << "\n"; | |||||
} | |||||
OS << " };\n\n"; | |||||
OS << "LaneBitmask " << ClName | |||||
<< "::composeSubRegIndexLaneMaskImpl(unsigned IdxA, LaneBitmask LaneMask)" | |||||
" const {\n" | |||||
" --IdxA; assert(IdxA < " << SubRegIndices.size() | |||||
<< " && \"Subregister index out of bounds\");\n" | |||||
" LaneBitmask Result;\n" | |||||
" for (const MaskRolOp *Ops =\n" | |||||
" &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n" | |||||
" Ops->Mask.any(); ++Ops) {\n" | |||||
" LaneBitmask::Type M = LaneMask.getAsInteger() & Ops->Mask.getAsInteger();\n" | |||||
" if (unsigned S = Ops->RotateLeft)\n" | |||||
" Result |= LaneBitmask((M << S) | (M >> (LaneBitmask::BitWidth - S)));\n" | |||||
" else\n" | |||||
" Result |= LaneBitmask(M);\n" | |||||
" }\n" | |||||
" return Result;\n" | |||||
"}\n\n"; | |||||
OS << "LaneBitmask " << ClName | |||||
<< "::reverseComposeSubRegIndexLaneMaskImpl(unsigned IdxA, " | |||||
" LaneBitmask LaneMask) const {\n" | |||||
" LaneMask &= getSubRegIndexLaneMask(IdxA);\n" | |||||
" --IdxA; assert(IdxA < " << SubRegIndices.size() | |||||
<< " && \"Subregister index out of bounds\");\n" | |||||
" LaneBitmask Result;\n" | |||||
" for (const MaskRolOp *Ops =\n" | |||||
" &LaneMaskComposeSequences[CompositeSequences[IdxA]];\n" | |||||
" Ops->Mask.any(); ++Ops) {\n" | |||||
" LaneBitmask::Type M = LaneMask.getAsInteger();\n" | |||||
" if (unsigned S = Ops->RotateLeft)\n" | |||||
" Result |= LaneBitmask((M >> S) | (M << (LaneBitmask::BitWidth - S)));\n" | |||||
" else\n" | |||||
" Result |= LaneBitmask(M);\n" | |||||
" }\n" | |||||
" return Result;\n" | |||||
"}\n\n"; | |||||
} | } | ||||
// | // | ||||
// runMCDesc - Print out MC register descriptions. | // runMCDesc - Print out MC register descriptions. | ||||
// | // | ||||
void | void | ||||
RegisterInfoEmitter::runMCDesc(raw_ostream &OS, CodeGenTarget &Target, | RegisterInfoEmitter::runMCDesc(CodeGenTarget &Target, | ||||
CodeGenRegBank &RegBank) { | CodeGenRegBank &RegBank) { | ||||
emitSourceFileHeader("MC Register Information", OS); | PI.regInfoEmitSourceFileHeader("MC Register Information"); | ||||
OS << "\n#ifdef GET_REGINFO_MC_DESC\n"; | |||||
OS << "#undef GET_REGINFO_MC_DESC\n\n"; | |||||
const auto &Regs = RegBank.getRegisters(); | const auto &Regs = RegBank.getRegisters(); | ||||
auto &SubRegIndices = RegBank.getSubRegIndices(); | auto &SubRegIndices = RegBank.getSubRegIndices(); | ||||
// The lists of sub-registers and super-registers go in the same array. That | |||||
// allows us to share suffixes. | |||||
typedef std::vector<const CodeGenRegister*> RegVec; | |||||
// Differentially encoded lists. | // Differentially encoded lists. | ||||
SequenceToOffsetTable<DiffVec> DiffSeqs; | SequenceToOffsetTable<DiffVec> DiffSeqs(PI.getLanguage()); | ||||
SmallVector<DiffVec, 4> SubRegLists(Regs.size()); | SmallVector<DiffVec, 4> SubRegLists(Regs.size()); | ||||
SmallVector<DiffVec, 4> SuperRegLists(Regs.size()); | SmallVector<DiffVec, 4> SuperRegLists(Regs.size()); | ||||
SmallVector<DiffVec, 4> RegUnitLists(Regs.size()); | SmallVector<DiffVec, 4> RegUnitLists(Regs.size()); | ||||
SmallVector<unsigned, 4> RegUnitInitScale(Regs.size()); | SmallVector<unsigned, 4> RegUnitInitScale(Regs.size()); | ||||
// List of lane masks accompanying register unit sequences. | // List of lane masks accompanying register unit sequences. | ||||
SequenceToOffsetTable<MaskVec> LaneMaskSeqs; | SequenceToOffsetTable<MaskVec> LaneMaskSeqs(PI.getLanguage()); | ||||
SmallVector<MaskVec, 4> RegUnitLaneMasks(Regs.size()); | SmallVector<MaskVec, 4> RegUnitLaneMasks(Regs.size()); | ||||
// Keep track of sub-register names as well. These are not differentially | SequenceToOffsetTable<SubRegIdxVec, deref<std::less<>>> SubRegIdxSeqs(PI.getLanguage()); | ||||
// encoded. | |||||
typedef SmallVector<const CodeGenSubRegIndex*, 4> SubRegIdxVec; | |||||
SequenceToOffsetTable<SubRegIdxVec, deref<std::less<>>> SubRegIdxSeqs; | |||||
SmallVector<SubRegIdxVec, 4> SubRegIdxLists(Regs.size()); | SmallVector<SubRegIdxVec, 4> SubRegIdxLists(Regs.size()); | ||||
SequenceToOffsetTable<std::string> RegStrings; | SequenceToOffsetTable<std::string> RegStrings(PI.getLanguage()); | ||||
// Precompute register lists for the SequenceToOffsetTable. | // Precompute register lists for the SequenceToOffsetTable. | ||||
unsigned i = 0; | unsigned i = 0; | ||||
for (auto I = Regs.begin(), E = Regs.end(); I != E; ++I, ++i) { | for (auto I = Regs.begin(), E = Regs.end(); I != E; ++I, ++i) { | ||||
const auto &Reg = *I; | const auto &Reg = *I; | ||||
RegStrings.add(std::string(Reg.getName())); | RegStrings.add(std::string(Reg.getName())); | ||||
// Compute the ordered sub-register list. | // Compute the ordered sub-register list. | ||||
▲ Show 20 Lines • Show All 53 Lines • ▼ Show 20 Lines | #endif | ||||
LaneMaskSeqs.add(LaneMaskVec); | LaneMaskSeqs.add(LaneMaskVec); | ||||
} | } | ||||
// Compute the final layout of the sequence table. | // Compute the final layout of the sequence table. | ||||
DiffSeqs.layout(); | DiffSeqs.layout(); | ||||
LaneMaskSeqs.layout(); | LaneMaskSeqs.layout(); | ||||
SubRegIdxSeqs.layout(); | SubRegIdxSeqs.layout(); | ||||
OS << "namespace llvm {\n\n"; | PI.emitIncludeToggle("GET_REGINFO_MC_DESC", true); | ||||
PI.emitNamespace("llvm", true); | |||||
const std::string &TargetName = std::string(Target.getName()); | const std::string &TargetName = std::string(Target.getName()); | ||||
// Emit the shared table of differential lists. | // Emit the shared table of differential lists. | ||||
OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[] = {\n"; | PI.regInfoEmitRegDiffLists(TargetName, DiffSeqs); | ||||
DiffSeqs.emit(OS, printDiff16); | |||||
OS << "};\n\n"; | |||||
// Emit the shared table of regunit lane mask sequences. | // Emit the shared table of regunit lane mask sequences. | ||||
OS << "extern const LaneBitmask " << TargetName << "LaneMaskLists[] = {\n"; | PI.regInfoEmitLaneMaskLists(TargetName, LaneMaskSeqs); | ||||
LaneMaskSeqs.emit(OS, printMask, "LaneBitmask::getAll()"); | |||||
OS << "};\n\n"; | |||||
// Emit the table of sub-register indexes. | // Emit the table of sub-register indexes. | ||||
OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[] = {\n"; | PI.regInfoEmitSubRegIdxLists(TargetName, SubRegIdxSeqs); | ||||
SubRegIdxSeqs.emit(OS, printSubRegIndex); | |||||
OS << "};\n\n"; | |||||
// Emit the table of sub-register index sizes. | // Emit the table of sub-register index sizes. | ||||
OS << "extern const MCRegisterInfo::SubRegCoveredBits " | PI.regInfoEmitSubRegIdxSizes(TargetName, SubRegIndices); | ||||
<< TargetName << "SubRegIdxRanges[] = {\n"; | |||||
OS << " { " << (uint16_t)-1 << ", " << (uint16_t)-1 << " },\n"; | |||||
for (const auto &Idx : SubRegIndices) { | |||||
OS << " { " << Idx.Offset << ", " << Idx.Size << " },\t// " | |||||
<< Idx.getName() << "\n"; | |||||
} | |||||
OS << "};\n\n"; | |||||
// Emit the string table. | // Emit the string table. | ||||
RegStrings.layout(); | RegStrings.layout(); | ||||
RegStrings.emitStringLiteralDef(OS, Twine("extern const char ") + TargetName + | PI.regInfoEmitSubRegStrTable(TargetName, RegStrings); | ||||
"RegStrings[]"); | |||||
OS << "extern const MCRegisterDesc " << TargetName | |||||
<< "RegDesc[] = { // Descriptors\n"; | |||||
OS << " { " << RegStrings.get("") << ", 0, 0, 0, 0, 0 },\n"; | |||||
// Emit the register descriptors now. | // Emit the register descriptors now. | ||||
i = 0; | PI.regInfoEmitRegDesc(LaneMaskSeqs, | ||||
for (const auto &Reg : Regs) { | Regs, SubRegIdxSeqs, DiffSeqs, | ||||
OS << " { " << RegStrings.get(std::string(Reg.getName())) << ", " | SubRegIdxLists, SubRegLists, | ||||
<< DiffSeqs.get(SubRegLists[i]) << ", " << DiffSeqs.get(SuperRegLists[i]) | SuperRegLists, RegUnitLists, | ||||
<< ", " << SubRegIdxSeqs.get(SubRegIdxLists[i]) << ", " | RegUnitInitScale, RegUnitLaneMasks, | ||||
<< (DiffSeqs.get(RegUnitLists[i]) * 16 + RegUnitInitScale[i]) << ", " | RegStrings); | ||||
<< LaneMaskSeqs.get(RegUnitLaneMasks[i]) << " },\n"; | |||||
++i; | |||||
} | |||||
OS << "};\n\n"; // End of register descriptors... | |||||
// Emit the table of register unit roots. Each regunit has one or two root | // Emit the table of register unit roots. Each regunit has one or two root | ||||
// registers. | // registers. | ||||
OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2] = {\n"; | PI.regInfoEmitRegUnitRoots(TargetName, RegBank); | ||||
for (unsigned i = 0, e = RegBank.getNumNativeRegUnits(); i != e; ++i) { | |||||
ArrayRef<const CodeGenRegister*> Roots = RegBank.getRegUnit(i).getRoots(); | |||||
assert(!Roots.empty() && "All regunits must have a root register."); | |||||
assert(Roots.size() <= 2 && "More than two roots not supported yet."); | |||||
OS << " { "; | |||||
ListSeparator LS; | |||||
for (const CodeGenRegister *R : Roots) | |||||
OS << LS << getQualifiedName(R->TheDef); | |||||
OS << " },\n"; | |||||
} | |||||
OS << "};\n\n"; | |||||
const auto &RegisterClasses = RegBank.getRegClasses(); | const auto &RegisterClasses = RegBank.getRegClasses(); | ||||
// Loop over all of the register classes... emitting each one. | // Loop over all of the register classes... emitting each one. | ||||
OS << "namespace { // Register classes...\n"; | PI.emitNamespace("", true, "Register classes..."); | ||||
SequenceToOffsetTable<std::string> RegClassStrings; | SequenceToOffsetTable<std::string> RegClassStrings(PI.getLanguage()); | ||||
// Emit the register enum value arrays for each RegisterClass | // Emit the register enum value arrays for each RegisterClass | ||||
for (const auto &RC : RegisterClasses) { | PI.regInfoEmitRegClasses(RegisterClasses, RegClassStrings, Target); | ||||
ArrayRef<Record*> Order = RC.getOrder(); | PI.emitNamespace("", false); | ||||
// Give the register class a legal C name if it's anonymous. | |||||
const std::string &Name = RC.getName(); | |||||
RegClassStrings.add(Name); | |||||
// Emit the register list now (unless it would be a zero-length array). | |||||
if (!Order.empty()) { | |||||
OS << " // " << Name << " Register Class...\n" | |||||
<< " const MCPhysReg " << Name << "[] = {\n "; | |||||
for (Record *Reg : Order) { | |||||
OS << getQualifiedName(Reg) << ", "; | |||||
} | |||||
OS << "\n };\n\n"; | |||||
OS << " // " << Name << " Bit set.\n" | |||||
<< " const uint8_t " << Name << "Bits[] = {\n "; | |||||
BitVectorEmitter BVE; | |||||
for (Record *Reg : Order) { | |||||
BVE.add(Target.getRegBank().getReg(Reg)->EnumValue); | |||||
} | |||||
BVE.print(OS); | |||||
OS << "\n };\n\n"; | |||||
} | |||||
} | |||||
OS << "} // end anonymous namespace\n\n"; | |||||
RegClassStrings.layout(); | RegClassStrings.layout(); | ||||
RegClassStrings.emitStringLiteralDef( | PI.regInfoEmitStrLiteralRegClasses(TargetName, RegClassStrings); | ||||
OS, Twine("extern const char ") + TargetName + "RegClassStrings[]"); | |||||
OS << "extern const MCRegisterClass " << TargetName | |||||
<< "MCRegisterClasses[] = {\n"; | |||||
for (const auto &RC : RegisterClasses) { | |||||
ArrayRef<Record *> Order = RC.getOrder(); | |||||
std::string RCName = Order.empty() ? "nullptr" : RC.getName(); | |||||
std::string RCBitsName = Order.empty() ? "nullptr" : RC.getName() + "Bits"; | |||||
std::string RCBitsSize = Order.empty() ? "0" : "sizeof(" + RCBitsName + ")"; | |||||
assert(isInt<8>(RC.CopyCost) && "Copy cost too large."); | |||||
uint32_t RegSize = 0; | |||||
if (RC.RSI.isSimple()) | |||||
RegSize = RC.RSI.getSimple().RegSize; | |||||
OS << " { " << RCName << ", " << RCBitsName << ", " | |||||
<< RegClassStrings.get(RC.getName()) << ", " << RC.getOrder().size() | |||||
<< ", " << RCBitsSize << ", " << RC.getQualifiedName() + "RegClassID" | |||||
<< ", " << RegSize << ", " << RC.CopyCost << ", " | |||||
<< (RC.Allocatable ? "true" : "false") << " },\n"; | |||||
} | |||||
OS << "};\n\n"; | PI.regInfoEmitMCRegClassesTable(TargetName, RegisterClasses, RegClassStrings); | ||||
EmitRegMappingTables(OS, Regs, false); | EmitRegMappingTables(Regs, false); | ||||
// Emit Reg encoding table | // Emit Reg encoding table | ||||
OS << "extern const uint16_t " << TargetName; | PI.regInfoEmitRegEncodingTable(TargetName, Regs); | ||||
OS << "RegEncodingTable[] = {\n"; | |||||
// Add entry for NoRegister | |||||
OS << " 0,\n"; | |||||
for (const auto &RE : Regs) { | |||||
Record *Reg = RE.TheDef; | |||||
BitsInit *BI = Reg->getValueAsBitsInit("HWEncoding"); | |||||
uint64_t Value = 0; | |||||
for (unsigned b = 0, be = BI->getNumBits(); b != be; ++b) { | |||||
if (BitInit *B = dyn_cast<BitInit>(BI->getBit(b))) | |||||
Value |= (uint64_t)B->getValue() << b; | |||||
} | |||||
OS << " " << Value << ",\n"; | |||||
} | |||||
OS << "};\n"; // End of HW encoding table | |||||
// MCRegisterInfo initialization routine. | // MCRegisterInfo initialization routine. | ||||
OS << "static inline void Init" << TargetName | PI.regInfoEmitMCRegInfoInit(TargetName, RegBank, Regs, RegisterClasses, SubRegIndices); | ||||
<< "MCRegisterInfo(MCRegisterInfo *RI, unsigned RA, " | |||||
<< "unsigned DwarfFlavour = 0, unsigned EHFlavour = 0, unsigned PC = 0) " | |||||
"{\n" | |||||
<< " RI->InitMCRegisterInfo(" << TargetName << "RegDesc, " | |||||
<< Regs.size() + 1 << ", RA, PC, " << TargetName << "MCRegisterClasses, " | |||||
<< RegisterClasses.size() << ", " << TargetName << "RegUnitRoots, " | |||||
<< RegBank.getNumNativeRegUnits() << ", " << TargetName << "RegDiffLists, " | |||||
<< TargetName << "LaneMaskLists, " << TargetName << "RegStrings, " | |||||
<< TargetName << "RegClassStrings, " << TargetName << "SubRegIdxLists, " | |||||
<< (std::distance(SubRegIndices.begin(), SubRegIndices.end()) + 1) << ",\n" | |||||
<< TargetName << "SubRegIdxRanges, " << TargetName | |||||
<< "RegEncodingTable);\n\n"; | |||||
EmitRegMapping(OS, Regs, false); | |||||
OS << "}\n\n"; | EmitRegMapping(Regs, false); | ||||
OS << "} // end namespace llvm\n\n"; | PI.emitNamespace("llvm", false); | ||||
OS << "#endif // GET_REGINFO_MC_DESC\n\n"; | PI.emitIncludeToggle("GET_REGINFO_MC_DESC", false); | ||||
} | } | ||||
void | void | ||||
RegisterInfoEmitter::runTargetHeader(raw_ostream &OS, CodeGenTarget &Target, | RegisterInfoEmitter::runTargetHeader(CodeGenTarget &Target, | ||||
CodeGenRegBank &RegBank) { | CodeGenRegBank &RegBank) { | ||||
emitSourceFileHeader("Register Information Header Fragment", OS); | PI.regInfoEmitSourceFileHeader("Register Information Header Fragment"); | ||||
PI.emitIncludeToggle("GET_REGINFO_HEADER", true); | |||||
OS << "\n#ifdef GET_REGINFO_HEADER\n"; | |||||
OS << "#undef GET_REGINFO_HEADER\n\n"; | |||||
const std::string &TargetName = std::string(Target.getName()); | const std::string &TargetName = std::string(Target.getName()); | ||||
std::string ClassName = TargetName + "GenRegisterInfo"; | std::string ClassName = TargetName + "GenRegisterInfo"; | ||||
PI.regInfoEmitHeaderIncludes(); | |||||
OS << "#include \"llvm/CodeGen/TargetRegisterInfo.h\"\n\n"; | PI.emitNamespace("llvm", true); | ||||
OS << "namespace llvm {\n\n"; | |||||
OS << "class " << TargetName << "FrameLowering;\n\n"; | |||||
OS << "struct " << ClassName << " : public TargetRegisterInfo {\n" | |||||
<< " explicit " << ClassName | |||||
<< "(unsigned RA, unsigned D = 0, unsigned E = 0,\n" | |||||
<< " unsigned PC = 0, unsigned HwMode = 0);\n"; | |||||
if (!RegBank.getSubRegIndices().empty()) { | |||||
OS << " unsigned composeSubRegIndicesImpl" | |||||
<< "(unsigned, unsigned) const override;\n" | |||||
<< " LaneBitmask composeSubRegIndexLaneMaskImpl" | |||||
<< "(unsigned, LaneBitmask) const override;\n" | |||||
<< " LaneBitmask reverseComposeSubRegIndexLaneMaskImpl" | |||||
<< "(unsigned, LaneBitmask) const override;\n" | |||||
<< " const TargetRegisterClass *getSubClassWithSubReg" | |||||
<< "(const TargetRegisterClass *, unsigned) const override;\n" | |||||
<< " const TargetRegisterClass *getSubRegisterClass" | |||||
<< "(const TargetRegisterClass *, unsigned) const override;\n"; | |||||
} | |||||
OS << " const RegClassWeight &getRegClassWeight(" | |||||
<< "const TargetRegisterClass *RC) const override;\n" | |||||
<< " unsigned getRegUnitWeight(unsigned RegUnit) const override;\n" | |||||
<< " unsigned getNumRegPressureSets() const override;\n" | |||||
<< " const char *getRegPressureSetName(unsigned Idx) const override;\n" | |||||
<< " unsigned getRegPressureSetLimit(const MachineFunction &MF, unsigned " | |||||
"Idx) const override;\n" | |||||
<< " const int *getRegClassPressureSets(" | |||||
<< "const TargetRegisterClass *RC) const override;\n" | |||||
<< " const int *getRegUnitPressureSets(" | |||||
<< "unsigned RegUnit) const override;\n" | |||||
<< " ArrayRef<const char *> getRegMaskNames() const override;\n" | |||||
<< " ArrayRef<const uint32_t *> getRegMasks() const override;\n" | |||||
<< " bool isGeneralPurposeRegister(const MachineFunction &, " | |||||
<< "MCRegister) const override;\n" | |||||
<< " bool isFixedRegister(const MachineFunction &, " | |||||
<< "MCRegister) const override;\n" | |||||
<< " bool isArgumentRegister(const MachineFunction &, " | |||||
<< "MCRegister) const override;\n" | |||||
<< " bool isConstantPhysReg(MCRegister PhysReg) const override final;\n" | |||||
<< " /// Devirtualized TargetFrameLowering.\n" | |||||
<< " static const " << TargetName << "FrameLowering *getFrameLowering(\n" | |||||
<< " const MachineFunction &MF);\n"; | |||||
const auto &RegisterClasses = RegBank.getRegClasses(); | const auto &RegisterClasses = RegBank.getRegClasses(); | ||||
if (llvm::any_of(RegisterClasses, [](const auto &RC) { return RC.getBaseClassOrder(); })) { | PI.regInfoEmitHeaderDecl(TargetName, ClassName, !RegBank.getSubRegIndices().empty(), | ||||
OS << " const TargetRegisterClass *getPhysRegBaseClass(MCRegister Reg) const override;\n"; | llvm::any_of(RegisterClasses, [](const auto &RC) { return RC.getBaseClassOrder(); })); | ||||
} | |||||
OS << "};\n\n"; | |||||
if (!RegisterClasses.empty()) { | if (!RegisterClasses.empty()) { | ||||
OS << "namespace " << RegisterClasses.front().Namespace | PI.emitNamespace(RegisterClasses.front().Namespace.str(), true, "Register classes"); | ||||
<< " { // Register classes\n"; | PI.regInfoEmitHeaderExternRegClasses(RegisterClasses); | ||||
PI.emitNamespace(RegisterClasses.front().Namespace.str(), false); | |||||
for (const auto &RC : RegisterClasses) { | |||||
const std::string &Name = RC.getName(); | |||||
// Output the extern for the instance. | |||||
OS << " extern const TargetRegisterClass " << Name << "RegClass;\n"; | |||||
} | |||||
OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n\n"; | |||||
} | } | ||||
OS << "} // end namespace llvm\n\n"; | PI.emitNamespace("llvm", false); | ||||
OS << "#endif // GET_REGINFO_HEADER\n\n"; | PI.emitIncludeToggle("GET_REGINFO_HEADER", false); | ||||
} | } | ||||
// | // | ||||
// runTargetDesc - Output the target register and register file descriptions. | // runTargetDesc - Output the target register and register file descriptions. | ||||
// | // | ||||
void | void | ||||
RegisterInfoEmitter::runTargetDesc(raw_ostream &OS, CodeGenTarget &Target, | RegisterInfoEmitter::runTargetDesc(CodeGenTarget &Target, | ||||
CodeGenRegBank &RegBank){ | CodeGenRegBank &RegBank){ | ||||
emitSourceFileHeader("Target Register and Register Classes Information", OS); | PI.regInfoEmitSourceFileHeader("Target Register and Register Classes Information"); | ||||
OS << "\n#ifdef GET_REGINFO_TARGET_DESC\n"; | PI.emitIncludeToggle("GET_REGINFO_TARGET_DESC", true); | ||||
OS << "#undef GET_REGINFO_TARGET_DESC\n\n"; | PI.emitNamespace("llvm", true); | ||||
OS << "namespace llvm {\n\n"; | |||||
// Get access to MCRegisterClass data. | // Get access to MCRegisterClass data. | ||||
OS << "extern const MCRegisterClass " << Target.getName() | PI.regInfoEmitExternRegClassesArr(Target.getName().str()); | ||||
<< "MCRegisterClasses[];\n"; | |||||
// Start out by emitting each of the register classes. | // Start out by emitting each of the register classes. | ||||
const auto &RegisterClasses = RegBank.getRegClasses(); | const auto &RegisterClasses = RegBank.getRegClasses(); | ||||
const auto &SubRegIndices = RegBank.getSubRegIndices(); | const auto &SubRegIndices = RegBank.getSubRegIndices(); | ||||
// Collect all registers belonging to any allocatable class. | // Collect all registers belonging to any allocatable class. | ||||
std::set<Record*> AllocatableRegs; | std::set<Record*> AllocatableRegs; | ||||
// Collect allocatable registers. | // Collect allocatable registers. | ||||
for (const auto &RC : RegisterClasses) { | for (const auto &RC : RegisterClasses) { | ||||
ArrayRef<Record*> Order = RC.getOrder(); | ArrayRef<Record*> Order = RC.getOrder(); | ||||
if (RC.Allocatable) | if (RC.Allocatable) | ||||
AllocatableRegs.insert(Order.begin(), Order.end()); | AllocatableRegs.insert(Order.begin(), Order.end()); | ||||
} | } | ||||
const CodeGenHwModes &CGH = Target.getHwModes(); | const CodeGenHwModes &CGH = Target.getHwModes(); | ||||
unsigned NumModes = CGH.getNumModeIds(); | unsigned NumModes = CGH.getNumModeIds(); | ||||
// Build a shared array of value types. | // Build a shared array of value types. | ||||
SequenceToOffsetTable<std::vector<MVT::SimpleValueType>> VTSeqs; | SequenceToOffsetTable<std::vector<MVT::SimpleValueType>> VTSeqs(PI.getLanguage()); | ||||
for (unsigned M = 0; M < NumModes; ++M) { | for (unsigned M = 0; M < NumModes; ++M) { | ||||
for (const auto &RC : RegisterClasses) { | for (const auto &RC : RegisterClasses) { | ||||
std::vector<MVT::SimpleValueType> S; | std::vector<MVT::SimpleValueType> S; | ||||
for (const ValueTypeByHwMode &VVT : RC.VTs) | for (const ValueTypeByHwMode &VVT : RC.VTs) | ||||
S.push_back(VVT.get(M).SimpleTy); | S.push_back(VVT.get(M).SimpleTy); | ||||
VTSeqs.add(S); | VTSeqs.add(S); | ||||
} | } | ||||
} | } | ||||
VTSeqs.layout(); | VTSeqs.layout(); | ||||
OS << "\nstatic const MVT::SimpleValueType VTLists[] = {\n"; | PI.regInfoEmitVTSeqs(VTSeqs); | ||||
VTSeqs.emit(OS, printSimpleValueType, "MVT::Other"); | |||||
OS << "};\n"; | |||||
// Emit SubRegIndex names, skipping 0. | // Emit SubRegIndex names, skipping 0. | ||||
OS << "\nstatic const char *SubRegIndexNameTable[] = { \""; | PI.regInfoEmitSubRegIdxTable(SubRegIndices); | ||||
for (const auto &Idx : SubRegIndices) { | |||||
OS << Idx.getName(); | |||||
OS << "\", \""; | |||||
} | |||||
OS << "\" };\n\n"; | |||||
// Emit SubRegIndex lane masks, including 0. | |||||
OS << "\nstatic const LaneBitmask SubRegIndexLaneMaskTable[] = {\n " | |||||
"LaneBitmask::getAll(),\n"; | |||||
for (const auto &Idx : SubRegIndices) { | |||||
printMask(OS << " ", Idx.LaneMask); | |||||
OS << ", // " << Idx.getName() << '\n'; | |||||
} | |||||
OS << " };\n\n"; | |||||
OS << "\n"; | |||||
// Now that all of the structs have been emitted, emit the instances. | // Now that all of the structs have been emitted, emit the instances. | ||||
if (!RegisterClasses.empty()) { | if (!RegisterClasses.empty()) { | ||||
OS << "\nstatic const TargetRegisterInfo::RegClassInfo RegClassInfos[]" | PI.regInfoEmitRegClassInfoTable(RegisterClasses, VTSeqs, CGH, NumModes); | ||||
<< " = {\n"; | |||||
for (unsigned M = 0; M < NumModes; ++M) { | |||||
unsigned EV = 0; | |||||
OS << " // Mode = " << M << " ("; | |||||
if (M == 0) | |||||
OS << "Default"; | |||||
else | |||||
OS << CGH.getMode(M).Name; | |||||
OS << ")\n"; | |||||
for (const auto &RC : RegisterClasses) { | |||||
assert(RC.EnumValue == EV && "Unexpected order of register classes"); | |||||
++EV; | |||||
(void)EV; | |||||
const RegSizeInfo &RI = RC.RSI.get(M); | |||||
OS << " { " << RI.RegSize << ", " << RI.SpillSize << ", " | |||||
<< RI.SpillAlignment; | |||||
std::vector<MVT::SimpleValueType> VTs; | |||||
for (const ValueTypeByHwMode &VVT : RC.VTs) | |||||
VTs.push_back(VVT.get(M).SimpleTy); | |||||
OS << ", VTLists+" << VTSeqs.get(VTs) << " }, // " | |||||
<< RC.getName() << '\n'; | |||||
} | |||||
} | |||||
OS << "};\n"; | |||||
OS << "\nstatic const TargetRegisterClass *const " | |||||
<< "NullRegClasses[] = { nullptr };\n\n"; | |||||
// Emit register class bit mask tables. The first bit mask emitted for a | // Emit register class bit mask tables. The first bit mask emitted for a | ||||
// register class, RC, is the set of sub-classes, including RC itself. | // register class, RC, is the set of sub-classes, including RC itself. | ||||
// | // | ||||
// If RC has super-registers, also create a list of subreg indices and bit | // If RC has super-registers, also create a list of subreg indices and bit | ||||
// masks, (Idx, Mask). The bit mask has a bit for every superreg regclass, | // masks, (Idx, Mask). The bit mask has a bit for every superreg regclass, | ||||
// SuperRC, that satisfies: | // SuperRC, that satisfies: | ||||
// | // | ||||
// For all SuperReg in SuperRC: SuperReg:Idx in RC | // For all SuperReg in SuperRC: SuperReg:Idx in RC | ||||
// | // | ||||
// The 0-terminated list of subreg indices starts at: | // The 0-terminated list of subreg indices starts at: | ||||
// | // | ||||
// RC->getSuperRegIndices() = SuperRegIdxSeqs + ... | // RC->getSuperRegIndices() = SuperRegIdxSeqs + ... | ||||
// | // | ||||
// The corresponding bitmasks follow the sub-class mask in memory. Each | // The corresponding bitmasks follow the sub-class mask in memory. Each | ||||
// mask has RCMaskWords uint32_t entries. | // mask has RCMaskWords uint32_t entries. | ||||
// | // | ||||
// Every bit mask present in the list has at least one bit set. | // Every bit mask present in the list has at least one bit set. | ||||
// Compress the sub-reg index lists. | |||||
typedef std::vector<const CodeGenSubRegIndex*> IdxList; | |||||
SmallVector<IdxList, 8> SuperRegIdxLists(RegisterClasses.size()); | SmallVector<IdxList, 8> SuperRegIdxLists(RegisterClasses.size()); | ||||
SequenceToOffsetTable<IdxList, deref<std::less<>>> SuperRegIdxSeqs; | SequenceToOffsetTable<IdxList, deref<std::less<>>> SuperRegIdxSeqs(PI.getLanguage()); | ||||
BitVector MaskBV(RegisterClasses.size()); | BitVector MaskBV(RegisterClasses.size()); | ||||
for (const auto &RC : RegisterClasses) { | PI.regInfoEmitSubClassMaskTable(RegisterClasses, | ||||
OS << "static const uint32_t " << RC.getName() | SuperRegIdxLists, | ||||
<< "SubClassMask[] = {\n "; | SuperRegIdxSeqs, | ||||
printBitVectorAsHex(OS, RC.getSubClasses(), 32); | SubRegIndices, | ||||
MaskBV); | |||||
// Emit super-reg class masks for any relevant SubRegIndices that can | |||||
// project into RC. | |||||
IdxList &SRIList = SuperRegIdxLists[RC.EnumValue]; | |||||
for (auto &Idx : SubRegIndices) { | |||||
MaskBV.reset(); | |||||
RC.getSuperRegClasses(&Idx, MaskBV); | |||||
if (MaskBV.none()) | |||||
continue; | |||||
SRIList.push_back(&Idx); | |||||
OS << "\n "; | |||||
printBitVectorAsHex(OS, MaskBV, 32); | |||||
OS << "// " << Idx.getName(); | |||||
} | |||||
SuperRegIdxSeqs.add(SRIList); | |||||
OS << "\n};\n\n"; | |||||
} | |||||
OS << "static const uint16_t SuperRegIdxSeqs[] = {\n"; | |||||
SuperRegIdxSeqs.layout(); | SuperRegIdxSeqs.layout(); | ||||
SuperRegIdxSeqs.emit(OS, printSubRegIndex); | PI.regInfoEmitSuperRegIdxSeqsTable(SuperRegIdxSeqs); | ||||
OS << "};\n\n"; | |||||
// Emit NULL terminated super-class lists. | // Emit NULL terminated super-class lists. | ||||
for (const auto &RC : RegisterClasses) { | PI.regInfoEmitSuperClassesTable(RegisterClasses); | ||||
ArrayRef<CodeGenRegisterClass*> Supers = RC.getSuperClasses(); | |||||
// Skip classes without supers. We can reuse NullRegClasses. | |||||
if (Supers.empty()) | |||||
continue; | |||||
OS << "static const TargetRegisterClass *const " | |||||
<< RC.getName() << "Superclasses[] = {\n"; | |||||
for (const auto *Super : Supers) | |||||
OS << " &" << Super->getQualifiedName() << "RegClass,\n"; | |||||
OS << " nullptr\n};\n\n"; | |||||
} | |||||
// Emit methods. | // Emit methods. | ||||
for (const auto &RC : RegisterClasses) { | PI.regInfoEmitRegClassMethods(RegisterClasses, Target.getName().str()); | ||||
if (!RC.AltOrderSelect.empty()) { | |||||
OS << "\nstatic inline unsigned " << RC.getName() | |||||
<< "AltOrderSelect(const MachineFunction &MF) {" | |||||
<< RC.AltOrderSelect << "}\n\n" | |||||
<< "static ArrayRef<MCPhysReg> " << RC.getName() | |||||
<< "GetRawAllocationOrder(const MachineFunction &MF) {\n"; | |||||
for (unsigned oi = 1 , oe = RC.getNumOrders(); oi != oe; ++oi) { | |||||
ArrayRef<Record*> Elems = RC.getOrder(oi); | |||||
if (!Elems.empty()) { | |||||
OS << " static const MCPhysReg AltOrder" << oi << "[] = {"; | |||||
for (unsigned elem = 0; elem != Elems.size(); ++elem) | |||||
OS << (elem ? ", " : " ") << getQualifiedName(Elems[elem]); | |||||
OS << " };\n"; | |||||
} | |||||
} | |||||
OS << " const MCRegisterClass &MCR = " << Target.getName() | |||||
<< "MCRegisterClasses[" << RC.getQualifiedName() + "RegClassID];\n" | |||||
<< " const ArrayRef<MCPhysReg> Order[] = {\n" | |||||
<< " makeArrayRef(MCR.begin(), MCR.getNumRegs()"; | |||||
for (unsigned oi = 1, oe = RC.getNumOrders(); oi != oe; ++oi) | |||||
if (RC.getOrder(oi).empty()) | |||||
OS << "),\n ArrayRef<MCPhysReg>("; | |||||
else | |||||
OS << "),\n makeArrayRef(AltOrder" << oi; | |||||
OS << ")\n };\n const unsigned Select = " << RC.getName() | |||||
<< "AltOrderSelect(MF);\n assert(Select < " << RC.getNumOrders() | |||||
<< ");\n return Order[Select];\n}\n"; | |||||
} | |||||
} | |||||
// Now emit the actual value-initialized register class instances. | // Now emit the actual value-initialized register class instances. | ||||
OS << "\nnamespace " << RegisterClasses.front().Namespace | PI.emitNamespace(RegisterClasses.front().Namespace.str(), true, "Register class instances"); | ||||
<< " { // Register class instances\n"; | PI.regInfomitRegClassInstances(RegisterClasses, | ||||
SuperRegIdxSeqs, | |||||
SuperRegIdxLists, | |||||
Target.getName().str()); | |||||
PI.emitNamespace(RegisterClasses.front().Namespace.str(), false); | |||||
} | |||||
for (const auto &RC : RegisterClasses) { | PI.emitNamespace("", true); | ||||
OS << " extern const TargetRegisterClass " << RC.getName() | PI.regInfoEmitRegClassTable(RegisterClasses); | ||||
<< "RegClass = {\n " << '&' << Target.getName() | PI.emitNamespace("", false); | ||||
<< "MCRegisterClasses[" << RC.getName() << "RegClassID],\n " | |||||
<< RC.getName() << "SubClassMask,\n SuperRegIdxSeqs + " | |||||
<< SuperRegIdxSeqs.get(SuperRegIdxLists[RC.EnumValue]) << ",\n "; | |||||
printMask(OS, RC.LaneMask); | |||||
OS << ",\n " << (unsigned)RC.AllocationPriority << ",\n " | |||||
<< (RC.GlobalPriority ? "true" : "false") << ",\n " | |||||
<< format("0x%02x", RC.TSFlags) << ", /* TSFlags */\n " | |||||
<< (RC.HasDisjunctSubRegs ? "true" : "false") | |||||
<< ", /* HasDisjunctSubRegs */\n " | |||||
<< (RC.CoveredBySubRegs ? "true" : "false") | |||||
<< ", /* CoveredBySubRegs */\n "; | |||||
if (RC.getSuperClasses().empty()) | |||||
OS << "NullRegClasses,\n "; | |||||
else | |||||
OS << RC.getName() << "Superclasses,\n "; | |||||
if (RC.AltOrderSelect.empty()) | |||||
OS << "nullptr\n"; | |||||
else | |||||
OS << RC.getName() << "GetRawAllocationOrder\n"; | |||||
OS << " };\n\n"; | |||||
} | |||||
OS << "} // end namespace " << RegisterClasses.front().Namespace << "\n"; | |||||
} | |||||
OS << "\nnamespace {\n"; | |||||
OS << " const TargetRegisterClass *const RegisterClasses[] = {\n"; | |||||
for (const auto &RC : RegisterClasses) | |||||
OS << " &" << RC.getQualifiedName() << "RegClass,\n"; | |||||
OS << " };\n"; | |||||
OS << "} // end anonymous namespace\n"; | |||||
// Emit extra information about registers. | // Emit extra information about registers. | ||||
const std::string &TargetName = std::string(Target.getName()); | const std::string &TargetName = std::string(Target.getName()); | ||||
const auto &Regs = RegBank.getRegisters(); | const auto &Regs = RegBank.getRegisters(); | ||||
unsigned NumRegCosts = 1; | unsigned NumRegCosts = 1; | ||||
for (const auto &Reg : Regs) | for (const auto &Reg : Regs) | ||||
NumRegCosts = std::max((size_t)NumRegCosts, Reg.CostPerUse.size()); | NumRegCosts = std::max((size_t)NumRegCosts, Reg.CostPerUse.size()); | ||||
Show All 13 Lines | for (const auto &Reg : Regs) { | ||||
if (AllocatableRegs.count(Reg.TheDef)) | if (AllocatableRegs.count(Reg.TheDef)) | ||||
InAllocClass.set(Reg.EnumValue); | InAllocClass.set(Reg.EnumValue); | ||||
} | } | ||||
// Emit the cost values as a 1D-array after grouping them by their indices, | // Emit the cost values as a 1D-array after grouping them by their indices, | ||||
// i.e. the costs for all registers corresponds to index 0, 1, 2, etc. | // i.e. the costs for all registers corresponds to index 0, 1, 2, etc. | ||||
// Size of the emitted array should be NumRegCosts * (Regs.size() + 1). | // Size of the emitted array should be NumRegCosts * (Regs.size() + 1). | ||||
OS << "\nstatic const uint8_t " | PI.regInfoEmitCostPerUseTable(AllRegCostPerUse, NumRegCosts); | ||||
<< "CostPerUseTable[] = { \n"; | PI.regInfoEmitInAllocatableClassTable(InAllocClass); | ||||
for (unsigned int I = 0; I < NumRegCosts; ++I) { | PI.regInfoEmitRegExtraDesc(TargetName, NumRegCosts); | ||||
for (unsigned J = I, E = AllRegCostPerUse.size(); J < E; J += NumRegCosts) | // End of register descriptors... | ||||
OS << AllRegCostPerUse[J] << ", "; | |||||
} | |||||
OS << "};\n\n"; | |||||
OS << "\nstatic const bool " | |||||
<< "InAllocatableClassTable[] = { \n"; | |||||
for (unsigned I = 0, E = InAllocClass.size(); I < E; ++I) { | |||||
OS << (InAllocClass[I] ? "true" : "false") << ", "; | |||||
} | |||||
OS << "};\n\n"; | |||||
OS << "\nstatic const TargetRegisterInfoDesc " << TargetName | |||||
<< "RegInfoDesc = { // Extra Descriptors\n"; | |||||
OS << "CostPerUseTable, " << NumRegCosts << ", " | |||||
<< "InAllocatableClassTable"; | |||||
OS << "};\n\n"; // End of register descriptors... | |||||
std::string ClassName = Target.getName().str() + "GenRegisterInfo"; | std::string ClassName = Target.getName().str() + "GenRegisterInfo"; | ||||
auto SubRegIndicesSize = | auto SubRegIndicesSize = | ||||
std::distance(SubRegIndices.begin(), SubRegIndices.end()); | std::distance(SubRegIndices.begin(), SubRegIndices.end()); | ||||
if (!SubRegIndices.empty()) { | if (!SubRegIndices.empty()) { | ||||
emitComposeSubRegIndices(OS, RegBank, ClassName); | emitComposeSubRegIndices(RegBank, ClassName); | ||||
emitComposeSubRegIndexLaneMask(OS, RegBank, ClassName); | emitComposeSubRegIndexLaneMask(RegBank, ClassName); | ||||
} | } | ||||
if (!SubRegIndices.empty()) { | if (!SubRegIndices.empty()) { | ||||
// Emit getSubClassWithSubReg. | PI.regInfoEmitSubClassSubRegGetter(ClassName, | ||||
OS << "const TargetRegisterClass *" << ClassName | SubRegIndicesSize, | ||||
<< "::getSubClassWithSubReg(const TargetRegisterClass *RC, unsigned Idx)" | SubRegIndices, | ||||
<< " const {\n"; | RegisterClasses, | ||||
// Use the smallest type that can hold a regclass ID with room for a | RegBank); | ||||
// sentinel. | |||||
if (RegisterClasses.size() <= UINT8_MAX) | |||||
OS << " static const uint8_t Table["; | |||||
else if (RegisterClasses.size() <= UINT16_MAX) | |||||
OS << " static const uint16_t Table["; | |||||
else | |||||
PrintFatalError("Too many register classes."); | |||||
OS << RegisterClasses.size() << "][" << SubRegIndicesSize << "] = {\n"; | |||||
for (const auto &RC : RegisterClasses) { | |||||
OS << " {\t// " << RC.getName() << "\n"; | |||||
for (auto &Idx : SubRegIndices) { | |||||
if (CodeGenRegisterClass *SRC = RC.getSubClassWithSubReg(&Idx)) | |||||
OS << " " << SRC->EnumValue + 1 << ",\t// " << Idx.getName() | |||||
<< " -> " << SRC->getName() << "\n"; | |||||
else | |||||
OS << " 0,\t// " << Idx.getName() << "\n"; | |||||
} | |||||
OS << " },\n"; | |||||
} | |||||
OS << " };\n assert(RC && \"Missing regclass\");\n" | |||||
<< " if (!Idx) return RC;\n --Idx;\n" | |||||
<< " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n" | |||||
<< " unsigned TV = Table[RC->getID()][Idx];\n" | |||||
<< " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n"; | |||||
// Emit getSubRegisterClass | |||||
OS << "const TargetRegisterClass *" << ClassName | |||||
<< "::getSubRegisterClass(const TargetRegisterClass *RC, unsigned Idx)" | |||||
<< " const {\n"; | |||||
// Use the smallest type that can hold a regclass ID with room for a | |||||
// sentinel. | |||||
if (RegisterClasses.size() <= UINT8_MAX) | |||||
OS << " static const uint8_t Table["; | |||||
else if (RegisterClasses.size() <= UINT16_MAX) | |||||
OS << " static const uint16_t Table["; | |||||
else | |||||
PrintFatalError("Too many register classes."); | |||||
OS << RegisterClasses.size() << "][" << SubRegIndicesSize << "] = {\n"; | |||||
for (const auto &RC : RegisterClasses) { | |||||
OS << " {\t// " << RC.getName() << '\n'; | |||||
for (auto &Idx : SubRegIndices) { | |||||
std::optional<std::pair<CodeGenRegisterClass *, CodeGenRegisterClass *>> | |||||
MatchingSubClass = RC.getMatchingSubClassWithSubRegs(RegBank, &Idx); | |||||
unsigned EnumValue = 0; | |||||
if (MatchingSubClass) { | |||||
CodeGenRegisterClass *SubRegClass = MatchingSubClass->second; | |||||
EnumValue = SubRegClass->EnumValue + 1; | |||||
} | |||||
OS << " " << EnumValue << ",\t// " | |||||
<< RC.getName() << ':' << Idx.getName(); | |||||
if (MatchingSubClass) { | |||||
CodeGenRegisterClass *SubRegClass = MatchingSubClass->second; | |||||
OS << " -> " << SubRegClass->getName(); | |||||
} | |||||
OS << '\n'; | |||||
} | } | ||||
OS << " },\n"; | EmitRegUnitPressure(RegBank, ClassName); | ||||
} | |||||
OS << " };\n assert(RC && \"Missing regclass\");\n" | |||||
<< " if (!Idx) return RC;\n --Idx;\n" | |||||
<< " assert(Idx < " << SubRegIndicesSize << " && \"Bad subreg\");\n" | |||||
<< " unsigned TV = Table[RC->getID()][Idx];\n" | |||||
<< " return TV ? getRegClass(TV - 1) : nullptr;\n}\n\n"; | |||||
} | |||||
EmitRegUnitPressure(OS, RegBank, ClassName); | |||||
// Emit register base class mapper | // Emit register base class mapper | ||||
if (!RegisterClasses.empty()) { | if (!RegisterClasses.empty()) { | ||||
// Collect base classes | // Collect base classes | ||||
SmallVector<const CodeGenRegisterClass*> BaseClasses; | SmallVector<const CodeGenRegisterClass*> BaseClasses; | ||||
for (const auto &RC : RegisterClasses) { | for (const auto &RC : RegisterClasses) { | ||||
if (RC.getBaseClassOrder()) | if (RC.getBaseClassOrder()) | ||||
BaseClasses.push_back(&RC); | BaseClasses.push_back(&RC); | ||||
Show All 13 Lines | if (!BaseClasses.empty()) { | ||||
// Build mapping for Regs (+1 for NoRegister) | // Build mapping for Regs (+1 for NoRegister) | ||||
std::vector<uint8_t> Mapping(Regs.size() + 1, 0); | std::vector<uint8_t> Mapping(Regs.size() + 1, 0); | ||||
for (int RCIdx = BaseClasses.size() - 1; RCIdx >= 0; --RCIdx) { | for (int RCIdx = BaseClasses.size() - 1; RCIdx >= 0; --RCIdx) { | ||||
for (const auto Reg : BaseClasses[RCIdx]->getMembers()) | for (const auto Reg : BaseClasses[RCIdx]->getMembers()) | ||||
Mapping[Reg->EnumValue] = RCIdx + 1; | Mapping[Reg->EnumValue] = RCIdx + 1; | ||||
} | } | ||||
OS << "\n// Register to base register class mapping\n\n"; | PI.regInfoEmitRegBaseClassMapping(ClassName, BaseClasses, Mapping); | ||||
OS << "\n"; | |||||
OS << "const TargetRegisterClass *" << ClassName | |||||
<< "::getPhysRegBaseClass(MCRegister Reg)" | |||||
<< " const {\n"; | |||||
OS << " static const TargetRegisterClass *BaseClasses[" << (BaseClasses.size() + 1) << "] = {\n"; | |||||
OS << " nullptr,\n"; | |||||
for (const auto RC : BaseClasses) | |||||
OS << " &" << RC->getQualifiedName() << "RegClass,\n"; | |||||
OS << " };\n"; | |||||
OS << " static const uint8_t Mapping[" << Mapping.size() << "] = {\n "; | |||||
for (const uint8_t Value : Mapping) | |||||
OS << (unsigned)Value << ","; | |||||
OS << " };\n\n"; | |||||
OS << " assert(Reg < sizeof(Mapping));\n"; | |||||
OS << " return BaseClasses[Mapping[Reg]];\n"; | |||||
OS << "}\n"; | |||||
} | } | ||||
} | } | ||||
// Emit the constructor of the class... | // Emit the constructor of the class... | ||||
OS << "extern const MCRegisterDesc " << TargetName << "RegDesc[];\n"; | PI.regInfoEmitExternTableDecl(TargetName); | ||||
OS << "extern const MCPhysReg " << TargetName << "RegDiffLists[];\n"; | |||||
OS << "extern const LaneBitmask " << TargetName << "LaneMaskLists[];\n"; | EmitRegMappingTables(Regs, true); | ||||
OS << "extern const char " << TargetName << "RegStrings[];\n"; | |||||
OS << "extern const char " << TargetName << "RegClassStrings[];\n"; | |||||
OS << "extern const MCPhysReg " << TargetName << "RegUnitRoots[][2];\n"; | |||||
OS << "extern const uint16_t " << TargetName << "SubRegIdxLists[];\n"; | |||||
OS << "extern const MCRegisterInfo::SubRegCoveredBits " | |||||
<< TargetName << "SubRegIdxRanges[];\n"; | |||||
OS << "extern const uint16_t " << TargetName << "RegEncodingTable[];\n"; | |||||
EmitRegMappingTables(OS, Regs, true); | |||||
OS << ClassName << "::\n" | |||||
<< ClassName | |||||
<< "(unsigned RA, unsigned DwarfFlavour, unsigned EHFlavour,\n" | |||||
" unsigned PC, unsigned HwMode)\n" | |||||
<< " : TargetRegisterInfo(&" << TargetName << "RegInfoDesc" | |||||
<< ", RegisterClasses, RegisterClasses+" << RegisterClasses.size() << ",\n" | |||||
<< " SubRegIndexNameTable, SubRegIndexLaneMaskTable,\n" | |||||
<< " "; | |||||
printMask(OS, RegBank.CoveringLanes); | |||||
OS << ", RegClassInfos, HwMode) {\n" | |||||
<< " InitMCRegisterInfo(" << TargetName << "RegDesc, " << Regs.size() + 1 | |||||
<< ", RA, PC,\n " << TargetName | |||||
<< "MCRegisterClasses, " << RegisterClasses.size() << ",\n" | |||||
<< " " << TargetName << "RegUnitRoots,\n" | |||||
<< " " << RegBank.getNumNativeRegUnits() << ",\n" | |||||
<< " " << TargetName << "RegDiffLists,\n" | |||||
<< " " << TargetName << "LaneMaskLists,\n" | |||||
<< " " << TargetName << "RegStrings,\n" | |||||
<< " " << TargetName << "RegClassStrings,\n" | |||||
<< " " << TargetName << "SubRegIdxLists,\n" | |||||
<< " " << SubRegIndicesSize + 1 << ",\n" | |||||
<< " " << TargetName << "SubRegIdxRanges,\n" | |||||
<< " " << TargetName << "RegEncodingTable);\n\n"; | |||||
EmitRegMapping(OS, Regs, true); | PI.regInfoEmitRegClassInit(TargetName, | ||||
ClassName, | |||||
RegBank, | |||||
RegisterClasses, | |||||
Regs, | |||||
SubRegIndicesSize); | |||||
OS << "}\n\n"; | EmitRegMapping(Regs, true); | ||||
// Emit CalleeSavedRegs information. | // Emit CalleeSavedRegs information. | ||||
std::vector<Record*> CSRSets = | std::vector<Record*> CSRSets = | ||||
Records.getAllDerivedDefinitions("CalleeSavedRegs"); | Records.getAllDerivedDefinitions("CalleeSavedRegs"); | ||||
for (unsigned i = 0, e = CSRSets.size(); i != e; ++i) { | for (unsigned i = 0, e = CSRSets.size(); i != e; ++i) { | ||||
Record *CSRSet = CSRSets[i]; | Record *CSRSet = CSRSets[i]; | ||||
const SetTheory::RecVec *Regs = RegBank.getSets().expand(CSRSet); | const SetTheory::RecVec *Regs = RegBank.getSets().expand(CSRSet); | ||||
assert(Regs && "Cannot expand CalleeSavedRegs instance"); | assert(Regs && "Cannot expand CalleeSavedRegs instance"); | ||||
// Emit the *_SaveList list of callee-saved registers. | // Emit the *_SaveList list of callee-saved registers. | ||||
OS << "static const MCPhysReg " << CSRSet->getName() | PI.regInfoEmitSaveListTable(CSRSet, Regs); | ||||
<< "_SaveList[] = { "; | |||||
for (unsigned r = 0, re = Regs->size(); r != re; ++r) | |||||
OS << getQualifiedName((*Regs)[r]) << ", "; | |||||
OS << "0 };\n"; | |||||
// Emit the *_RegMask bit mask of call-preserved registers. | // Emit the *_RegMask bit mask of call-preserved registers. | ||||
BitVector Covered = RegBank.computeCoveredRegisters(*Regs); | BitVector Covered = RegBank.computeCoveredRegisters(*Regs); | ||||
// Check for an optional OtherPreserved set. | // Check for an optional OtherPreserved set. | ||||
// Add those registers to RegMask, but not to SaveList. | // Add those registers to RegMask, but not to SaveList. | ||||
if (DagInit *OPDag = | if (DagInit *OPDag = | ||||
dyn_cast<DagInit>(CSRSet->getValueInit("OtherPreserved"))) { | dyn_cast<DagInit>(CSRSet->getValueInit("OtherPreserved"))) { | ||||
SetTheory::RecSet OPSet; | SetTheory::RecSet OPSet; | ||||
RegBank.getSets().evaluate(OPDag, OPSet, CSRSet->getLoc()); | RegBank.getSets().evaluate(OPDag, OPSet, CSRSet->getLoc()); | ||||
Covered |= RegBank.computeCoveredRegisters( | Covered |= RegBank.computeCoveredRegisters( | ||||
ArrayRef<Record*>(OPSet.begin(), OPSet.end())); | ArrayRef<Record*>(OPSet.begin(), OPSet.end())); | ||||
} | } | ||||
// Add all constant physical registers to the preserved mask: | // Add all constant physical registers to the preserved mask: | ||||
SetTheory::RecSet ConstantSet; | SetTheory::RecSet ConstantSet; | ||||
for (auto &Reg : RegBank.getRegisters()) { | for (auto &Reg : RegBank.getRegisters()) { | ||||
if (Reg.Constant) | if (Reg.Constant) | ||||
ConstantSet.insert(Reg.TheDef); | ConstantSet.insert(Reg.TheDef); | ||||
} | } | ||||
Covered |= RegBank.computeCoveredRegisters( | Covered |= RegBank.computeCoveredRegisters( | ||||
ArrayRef<Record *>(ConstantSet.begin(), ConstantSet.end())); | ArrayRef<Record *>(ConstantSet.begin(), ConstantSet.end())); | ||||
OS << "static const uint32_t " << CSRSet->getName() | PI.regInfoEmitRegMaskTable(CSRSet->getName().str(), Covered); | ||||
<< "_RegMask[] = { "; | |||||
printBitVectorAsHex(OS, Covered, 32); | |||||
OS << "};\n"; | |||||
} | |||||
OS << "\n\n"; | |||||
OS << "ArrayRef<const uint32_t *> " << ClassName | |||||
<< "::getRegMasks() const {\n"; | |||||
if (!CSRSets.empty()) { | |||||
OS << " static const uint32_t *const Masks[] = {\n"; | |||||
for (Record *CSRSet : CSRSets) | |||||
OS << " " << CSRSet->getName() << "_RegMask,\n"; | |||||
OS << " };\n"; | |||||
OS << " return makeArrayRef(Masks);\n"; | |||||
} else { | |||||
OS << " return std::nullopt;\n"; | |||||
} | } | ||||
OS << "}\n\n"; | PI.emitNewline(2); | ||||
PI.regInfoEmitGetRegMasks(CSRSets, ClassName); | |||||
const std::list<CodeGenRegisterCategory> &RegCategories = | const std::list<CodeGenRegisterCategory> &RegCategories = | ||||
RegBank.getRegCategories(); | RegBank.getRegCategories(); | ||||
OS << "bool " << ClassName << "::\n" | PI.regInfoEmitGPRCheck(ClassName, RegCategories); | ||||
<< "isGeneralPurposeRegister(const MachineFunction &MF, " | PI.regInfoEmitFixedRegCheck(ClassName, RegCategories); | ||||
<< "MCRegister PhysReg) const {\n" | PI.regInfoEmitArgRegCheck(ClassName, RegCategories); | ||||
<< " return\n"; | |||||
for (const CodeGenRegisterCategory &Category : RegCategories) | |||||
if (Category.getName() == "GeneralPurposeRegisters") { | |||||
for (const CodeGenRegisterClass *RC : Category.getClasses()) | |||||
OS << " " << RC->getQualifiedName() | |||||
<< "RegClass.contains(PhysReg) ||\n"; | |||||
break; | |||||
} | |||||
OS << " false;\n"; | |||||
OS << "}\n\n"; | |||||
OS << "bool " << ClassName << "::\n" | PI.regInfoEmitIsConstantPhysReg(Regs, ClassName); | ||||
<< "isFixedRegister(const MachineFunction &MF, " | PI.regInfoEmitGetRegMaskNames(CSRSets, ClassName); | ||||
<< "MCRegister PhysReg) const {\n" | |||||
<< " return\n"; | |||||
for (const CodeGenRegisterCategory &Category : RegCategories) | |||||
if (Category.getName() == "FixedRegisters") { | |||||
for (const CodeGenRegisterClass *RC : Category.getClasses()) | |||||
OS << " " << RC->getQualifiedName() | |||||
<< "RegClass.contains(PhysReg) ||\n"; | |||||
break; | |||||
} | |||||
OS << " false;\n"; | |||||
OS << "}\n\n"; | |||||
OS << "bool " << ClassName << "::\n" | PI.regInfoEmitGetFrameLowering(TargetName); | ||||
<< "isArgumentRegister(const MachineFunction &MF, " | |||||
<< "MCRegister PhysReg) const {\n" | |||||
<< " return\n"; | |||||
for (const CodeGenRegisterCategory &Category : RegCategories) | |||||
if (Category.getName() == "ArgumentRegisters") { | |||||
for (const CodeGenRegisterClass *RC : Category.getClasses()) | |||||
OS << " " << RC->getQualifiedName() | |||||
<< "RegClass.contains(PhysReg) ||\n"; | |||||
break; | |||||
} | |||||
OS << " false;\n"; | |||||
OS << "}\n\n"; | |||||
OS << "bool " << ClassName << "::\n" | |||||
<< "isConstantPhysReg(MCRegister PhysReg) const {\n" | |||||
<< " return\n"; | |||||
for (const auto &Reg : Regs) | |||||
if (Reg.Constant) | |||||
OS << " PhysReg == " << getQualifiedName(Reg.TheDef) << " ||\n"; | |||||
OS << " false;\n"; | |||||
OS << "}\n\n"; | |||||
OS << "ArrayRef<const char *> " << ClassName | |||||
<< "::getRegMaskNames() const {\n"; | |||||
if (!CSRSets.empty()) { | |||||
OS << " static const char *Names[] = {\n"; | |||||
for (Record *CSRSet : CSRSets) | |||||
OS << " " << '"' << CSRSet->getName() << '"' << ",\n"; | |||||
OS << " };\n"; | |||||
OS << " return makeArrayRef(Names);\n"; | |||||
} else { | |||||
OS << " return std::nullopt;\n"; | |||||
} | |||||
OS << "}\n\n"; | |||||
OS << "const " << TargetName << "FrameLowering *\n" << TargetName | |||||
<< "GenRegisterInfo::getFrameLowering(const MachineFunction &MF) {\n" | |||||
<< " return static_cast<const " << TargetName << "FrameLowering *>(\n" | |||||
<< " MF.getSubtarget().getFrameLowering());\n" | |||||
<< "}\n\n"; | |||||
OS << "} // end namespace llvm\n\n"; | PI.emitNamespace("llvm", false); | ||||
OS << "#endif // GET_REGINFO_TARGET_DESC\n\n"; | PI.emitIncludeToggle("GET_REGINFO_TARGET_DESC", false); | ||||
} | } | ||||
void RegisterInfoEmitter::run(raw_ostream &OS) { | void RegisterInfoEmitter::run() { | ||||
CodeGenRegBank &RegBank = Target.getRegBank(); | CodeGenRegBank &RegBank = Target.getRegBank(); | ||||
Records.startTimer("Print enums"); | Records.startTimer("Print enums"); | ||||
runEnums(OS, Target, RegBank); | |||||
PI.regInfoEmitSourceFileHeader("Target Register Enum Values"); | |||||
PI.regInfoEmitEnums(Target, RegBank); | |||||
Records.startTimer("Print MC registers"); | Records.startTimer("Print MC registers"); | ||||
runMCDesc(OS, Target, RegBank); | runMCDesc(Target, RegBank); | ||||
Records.startTimer("Print header fragment"); | Records.startTimer("Print header fragment"); | ||||
runTargetHeader(OS, Target, RegBank); | runTargetHeader(Target, RegBank); | ||||
Records.startTimer("Print target registers"); | Records.startTimer("Print target registers"); | ||||
runTargetDesc(OS, Target, RegBank); | runTargetDesc(Target, RegBank); | ||||
if (RegisterInfoDebug) | if (RegisterInfoDebug) | ||||
debugDump(errs()); | debugDump(errs()); | ||||
} | } | ||||
void RegisterInfoEmitter::debugDump(raw_ostream &OS) { | void RegisterInfoEmitter::debugDump(raw_ostream &ErrOS) { | ||||
rovka: Nit: This looks unrelated, you should commit it separately. | |||||
CodeGenRegBank &RegBank = Target.getRegBank(); | CodeGenRegBank &RegBank = Target.getRegBank(); | ||||
const CodeGenHwModes &CGH = Target.getHwModes(); | const CodeGenHwModes &CGH = Target.getHwModes(); | ||||
unsigned NumModes = CGH.getNumModeIds(); | unsigned NumModes = CGH.getNumModeIds(); | ||||
auto getModeName = [CGH] (unsigned M) -> StringRef { | auto getModeName = [CGH] (unsigned M) -> StringRef { | ||||
if (M == 0) | if (M == 0) | ||||
return "Default"; | return "Default"; | ||||
return CGH.getMode(M).Name; | return CGH.getMode(M).Name; | ||||
}; | }; | ||||
for (const CodeGenRegisterClass &RC : RegBank.getRegClasses()) { | for (const CodeGenRegisterClass &RC : RegBank.getRegClasses()) { | ||||
OS << "RegisterClass " << RC.getName() << ":\n"; | ErrOS << "RegisterClass " << RC.getName() << ":\n"; | ||||
OS << "\tSpillSize: {"; | ErrOS << "\tSpillSize: {"; | ||||
for (unsigned M = 0; M != NumModes; ++M) | for (unsigned M = 0; M != NumModes; ++M) | ||||
OS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillSize; | ErrOS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillSize; | ||||
OS << " }\n\tSpillAlignment: {"; | ErrOS << " }\n\tSpillAlignment: {"; | ||||
for (unsigned M = 0; M != NumModes; ++M) | for (unsigned M = 0; M != NumModes; ++M) | ||||
OS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillAlignment; | ErrOS << ' ' << getModeName(M) << ':' << RC.RSI.get(M).SpillAlignment; | ||||
OS << " }\n\tNumRegs: " << RC.getMembers().size() << '\n'; | ErrOS << " }\n\tNumRegs: " << RC.getMembers().size() << '\n'; | ||||
OS << "\tLaneMask: " << PrintLaneMask(RC.LaneMask) << '\n'; | ErrOS << "\tLaneMask: " << PrintLaneMask(RC.LaneMask) << '\n'; | ||||
OS << "\tHasDisjunctSubRegs: " << RC.HasDisjunctSubRegs << '\n'; | ErrOS << "\tHasDisjunctSubRegs: " << RC.HasDisjunctSubRegs << '\n'; | ||||
OS << "\tCoveredBySubRegs: " << RC.CoveredBySubRegs << '\n'; | ErrOS << "\tCoveredBySubRegs: " << RC.CoveredBySubRegs << '\n'; | ||||
OS << "\tAllocatable: " << RC.Allocatable << '\n'; | ErrOS << "\tAllocatable: " << RC.Allocatable << '\n'; | ||||
OS << "\tAllocationPriority: " << unsigned(RC.AllocationPriority) << '\n'; | ErrOS << "\tAllocationPriority: " << unsigned(RC.AllocationPriority) << '\n'; | ||||
OS << "\tRegs:"; | ErrOS << "\tRegs:"; | ||||
for (const CodeGenRegister *R : RC.getMembers()) { | for (const CodeGenRegister *R : RC.getMembers()) { | ||||
OS << " " << R->getName(); | ErrOS << " " << R->getName(); | ||||
} | } | ||||
OS << '\n'; | ErrOS << '\n'; | ||||
OS << "\tSubClasses:"; | ErrOS << "\tSubClasses:"; | ||||
const BitVector &SubClasses = RC.getSubClasses(); | const BitVector &SubClasses = RC.getSubClasses(); | ||||
for (const CodeGenRegisterClass &SRC : RegBank.getRegClasses()) { | for (const CodeGenRegisterClass &SRC : RegBank.getRegClasses()) { | ||||
if (!SubClasses.test(SRC.EnumValue)) | if (!SubClasses.test(SRC.EnumValue)) | ||||
continue; | continue; | ||||
OS << " " << SRC.getName(); | ErrOS << " " << SRC.getName(); | ||||
} | } | ||||
OS << '\n'; | ErrOS << '\n'; | ||||
OS << "\tSuperClasses:"; | ErrOS << "\tSuperClasses:"; | ||||
for (const CodeGenRegisterClass *SRC : RC.getSuperClasses()) { | for (const CodeGenRegisterClass *SRC : RC.getSuperClasses()) { | ||||
OS << " " << SRC->getName(); | ErrOS << " " << SRC->getName(); | ||||
} | } | ||||
OS << '\n'; | ErrOS << '\n'; | ||||
} | } | ||||
for (const CodeGenSubRegIndex &SRI : RegBank.getSubRegIndices()) { | for (const CodeGenSubRegIndex &SRI : RegBank.getSubRegIndices()) { | ||||
OS << "SubRegIndex " << SRI.getName() << ":\n"; | ErrOS << "SubRegIndex " << SRI.getName() << ":\n"; | ||||
OS << "\tLaneMask: " << PrintLaneMask(SRI.LaneMask) << '\n'; | ErrOS << "\tLaneMask: " << PrintLaneMask(SRI.LaneMask) << '\n'; | ||||
OS << "\tAllSuperRegsCovered: " << SRI.AllSuperRegsCovered << '\n'; | ErrOS << "\tAllSuperRegsCovered: " << SRI.AllSuperRegsCovered << '\n'; | ||||
OS << "\tOffset, Size: " << SRI.Offset << ", " << SRI.Size << '\n'; | ErrOS << "\tOffset, Size: " << SRI.Offset << ", " << SRI.Size << '\n'; | ||||
} | } | ||||
for (const CodeGenRegister &R : RegBank.getRegisters()) { | for (const CodeGenRegister &R : RegBank.getRegisters()) { | ||||
OS << "Register " << R.getName() << ":\n"; | ErrOS << "Register " << R.getName() << ":\n"; | ||||
OS << "\tCostPerUse: "; | ErrOS << "\tCostPerUse: "; | ||||
for (const auto &Cost : R.CostPerUse) | for (const auto &Cost : R.CostPerUse) | ||||
OS << Cost << " "; | ErrOS << Cost << " "; | ||||
OS << '\n'; | ErrOS << '\n'; | ||||
OS << "\tCoveredBySubregs: " << R.CoveredBySubRegs << '\n'; | ErrOS << "\tCoveredBySubregs: " << R.CoveredBySubRegs << '\n'; | ||||
OS << "\tHasDisjunctSubRegs: " << R.HasDisjunctSubRegs << '\n'; | ErrOS << "\tHasDisjunctSubRegs: " << R.HasDisjunctSubRegs << '\n'; | ||||
for (std::pair<CodeGenSubRegIndex*,CodeGenRegister*> P : R.getSubRegs()) { | for (std::pair<CodeGenSubRegIndex*,CodeGenRegister*> P : R.getSubRegs()) { | ||||
OS << "\tSubReg " << P.first->getName() | ErrOS << "\tSubReg " << P.first->getName() | ||||
<< " = " << P.second->getName() << '\n'; | << " = " << P.second->getName() << '\n'; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
namespace llvm { | namespace llvm { | ||||
void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS) { | void EmitRegisterInfo(RecordKeeper &RK, raw_ostream &OS) { | ||||
RegisterInfoEmitter(RK).run(OS); | formatted_raw_ostream FOS(OS); | ||||
PrinterLanguage const PLang = PrinterLLVM::getLanguage(); | |||||
PrinterLLVM *PI = nullptr; | |||||
switch (PLang) { | |||||
default: | |||||
PrintFatalNote( | |||||
"RegisterInfo backend does not support the selected ouput language."); | |||||
return; | |||||
case PRINTER_LANG_CPP: | |||||
PI = new PrinterLLVM(FOS); | |||||
break; | |||||
} | |||||
RegisterInfoEmitter(RK, *PI).run(); | |||||
delete PI; | |||||
} | } | ||||
} // end namespace llvm | } // end namespace llvm |
Nit: This looks unrelated, you should commit it separately.