Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/ExegesisEmitter.cpp
35258 views
//===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This tablegen backend emits llvm-exegesis information.9//10//===----------------------------------------------------------------------===//1112#include "llvm/ADT/STLExtras.h"13#include "llvm/ADT/SmallSet.h"14#include "llvm/ADT/StringRef.h"15#include "llvm/Support/raw_ostream.h"16#include "llvm/TableGen/Error.h"17#include "llvm/TableGen/Record.h"18#include "llvm/TableGen/TableGenBackend.h"19#include <cassert>20#include <map>21#include <string>22#include <vector>2324using namespace llvm;2526#define DEBUG_TYPE "exegesis-emitter"2728namespace {2930class ExegesisEmitter {31public:32ExegesisEmitter(RecordKeeper &RK);3334void run(raw_ostream &OS) const;3536private:37unsigned getPfmCounterId(llvm::StringRef Name) const {38const auto It = PfmCounterNameTable.find(Name);39if (It == PfmCounterNameTable.end())40PrintFatalError("no pfm counter id for " + Name);41return It->second;42}4344// Collects all the ProcPfmCounters definitions available in this target.45void emitPfmCounters(raw_ostream &OS) const;4647void emitPfmCountersInfo(const Record &Def,48unsigned &IssueCountersTableOffset,49raw_ostream &OS) const;5051void emitPfmCountersLookupTable(raw_ostream &OS) const;5253RecordKeeper &Records;54std::string Target;5556// Table of counter name -> counter index.57const std::map<llvm::StringRef, unsigned> PfmCounterNameTable;58};5960static std::map<llvm::StringRef, unsigned>61collectPfmCounters(const RecordKeeper &Records) {62std::map<llvm::StringRef, unsigned> PfmCounterNameTable;63const auto AddPfmCounterName = [&PfmCounterNameTable](64const Record *PfmCounterDef) {65const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter");66if (!Counter.empty())67PfmCounterNameTable.emplace(Counter, 0);68};69for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) {70// Check that ResourceNames are unique.71llvm::SmallSet<llvm::StringRef, 16> Seen;72for (const Record *IssueCounter :73Def->getValueAsListOfDefs("IssueCounters")) {74const llvm::StringRef ResourceName =75IssueCounter->getValueAsString("ResourceName");76if (ResourceName.empty())77PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName");78if (!Seen.insert(ResourceName).second)79PrintFatalError(IssueCounter->getLoc(),80"duplicate ResourceName " + ResourceName);81AddPfmCounterName(IssueCounter);82}8384for (const Record *ValidationCounter :85Def->getValueAsListOfDefs("ValidationCounters"))86AddPfmCounterName(ValidationCounter);8788AddPfmCounterName(Def->getValueAsDef("CycleCounter"));89AddPfmCounterName(Def->getValueAsDef("UopsCounter"));90}91unsigned Index = 0;92for (auto &NameAndIndex : PfmCounterNameTable)93NameAndIndex.second = Index++;94return PfmCounterNameTable;95}9697ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK)98: Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) {99std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");100if (Targets.size() == 0)101PrintFatalError("No 'Target' subclasses defined!");102if (Targets.size() != 1)103PrintFatalError("Multiple subclasses of Target defined!");104Target = std::string(Targets[0]->getName());105}106107struct ValidationCounterInfo {108int64_t EventNumber;109StringRef EventName;110unsigned PfmCounterID;111};112113bool EventNumberLess(const ValidationCounterInfo &LHS,114const ValidationCounterInfo &RHS) {115return LHS.EventNumber < RHS.EventNumber;116}117118void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,119unsigned &IssueCountersTableOffset,120raw_ostream &OS) const {121const auto CycleCounter =122Def.getValueAsDef("CycleCounter")->getValueAsString("Counter");123const auto UopsCounter =124Def.getValueAsDef("UopsCounter")->getValueAsString("Counter");125const size_t NumIssueCounters =126Def.getValueAsListOfDefs("IssueCounters").size();127const size_t NumValidationCounters =128Def.getValueAsListOfDefs("ValidationCounters").size();129130// Emit Validation Counters Array131if (NumValidationCounters != 0) {132std::vector<ValidationCounterInfo> ValidationCounters;133ValidationCounters.reserve(NumValidationCounters);134for (const Record *ValidationCounter :135Def.getValueAsListOfDefs("ValidationCounters")) {136ValidationCounters.push_back(137{ValidationCounter->getValueAsDef("EventType")138->getValueAsInt("EventNumber"),139ValidationCounter->getValueAsDef("EventType")->getName(),140getPfmCounterId(ValidationCounter->getValueAsString("Counter"))});141}142std::sort(ValidationCounters.begin(), ValidationCounters.end(),143EventNumberLess);144OS << "\nstatic const std::pair<ValidationEvent, const char*> " << Target145<< Def.getName() << "ValidationCounters[] = {\n";146for (const ValidationCounterInfo &VCI : ValidationCounters) {147OS << " { " << VCI.EventName << ", " << Target << "PfmCounterNames["148<< VCI.PfmCounterID << "]},\n";149}150OS << "};\n";151}152153OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()154<< " = {\n";155156// Cycle Counter.157if (CycleCounter.empty())158OS << " nullptr, // No cycle counter.\n";159else160OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter)161<< "], // Cycle counter\n";162163// Uops Counter.164if (UopsCounter.empty())165OS << " nullptr, // No uops counter.\n";166else167OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter)168<< "], // Uops counter\n";169170// Issue Counters171if (NumIssueCounters == 0)172OS << " nullptr, 0, // No issue counters\n";173else174OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset175<< ", " << NumIssueCounters << ", // Issue counters.\n";176177// Validation Counters178if (NumValidationCounters == 0)179OS << " nullptr, 0 // No validation counters.\n";180else181OS << " " << Target << Def.getName() << "ValidationCounters, "182<< NumValidationCounters << " // Validation counters.\n";183184OS << "};\n";185IssueCountersTableOffset += NumIssueCounters;186}187188void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {189// Emit the counter name table.190OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";191for (const auto &NameAndIndex : PfmCounterNameTable)192OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second193<< "\n";194OS << "};\n\n";195196// Emit the IssueCounters table.197const auto PfmCounterDefs =198Records.getAllDerivedDefinitions("ProcPfmCounters");199// Only emit if non-empty.200const bool HasAtLeastOnePfmIssueCounter =201llvm::any_of(PfmCounterDefs, [](const Record *Def) {202return !Def->getValueAsListOfDefs("IssueCounters").empty();203});204if (HasAtLeastOnePfmIssueCounter) {205OS << "static const PfmCountersInfo::IssueCounter " << Target206<< "PfmIssueCounters[] = {\n";207for (const Record *Def : PfmCounterDefs) {208for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters"))209OS << " { " << Target << "PfmCounterNames["210<< getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \""211<< ICDef->getValueAsString("ResourceName") << "\"},\n";212}213OS << "};\n";214}215216// Now generate the PfmCountersInfo.217unsigned IssueCountersTableOffset = 0;218for (const Record *Def : PfmCounterDefs)219emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS);220221OS << "\n";222} // namespace223224void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {225std::vector<Record *> Bindings =226Records.getAllDerivedDefinitions("PfmCountersBinding");227assert(!Bindings.empty() && "there must be at least one binding");228llvm::sort(Bindings, [](const Record *L, const Record *R) {229return L->getValueAsString("CpuName") < R->getValueAsString("CpuName");230});231232OS << "// Sorted (by CpuName) array of pfm counters.\n"233<< "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";234for (Record *Binding : Bindings) {235// Emit as { "cpu", procinit },236OS << " { \"" //237<< Binding->getValueAsString("CpuName") << "\"," //238<< " &" << Target << Binding->getValueAsDef("Counters")->getName() //239<< " },\n";240}241OS << "};\n\n";242}243244void ExegesisEmitter::run(raw_ostream &OS) const {245emitSourceFileHeader("Exegesis Tables", OS);246emitPfmCounters(OS);247emitPfmCountersLookupTable(OS);248}249250} // end anonymous namespace251252static TableGen::Emitter::OptClass<ExegesisEmitter>253X("gen-exegesis", "Generate llvm-exegesis tables");254255256