diff options
Diffstat (limited to 'llvm/utils/TableGen/ExegesisEmitter.cpp')
-rw-r--r-- | llvm/utils/TableGen/ExegesisEmitter.cpp | 215 |
1 files changed, 215 insertions, 0 deletions
diff --git a/llvm/utils/TableGen/ExegesisEmitter.cpp b/llvm/utils/TableGen/ExegesisEmitter.cpp new file mode 100644 index 000000000000..976d5f51776f --- /dev/null +++ b/llvm/utils/TableGen/ExegesisEmitter.cpp @@ -0,0 +1,215 @@ +//===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This tablegen backend emits llvm-exegesis information. +// +//===----------------------------------------------------------------------===// + +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" +#include "llvm/ADT/StringRef.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/Format.h" +#include "llvm/Support/raw_ostream.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/Record.h" +#include "llvm/TableGen/TableGenBackend.h" +#include <algorithm> +#include <cassert> +#include <cstdint> +#include <map> +#include <string> +#include <vector> + +using namespace llvm; + +#define DEBUG_TYPE "exegesis-emitter" + +namespace { + +class ExegesisEmitter { +public: + ExegesisEmitter(RecordKeeper &RK); + + void run(raw_ostream &OS) const; + +private: + unsigned getPfmCounterId(llvm::StringRef Name) const { + const auto It = PfmCounterNameTable.find(Name); + if (It == PfmCounterNameTable.end()) + PrintFatalError("no pfm counter id for " + Name); + return It->second; + } + + // Collects all the ProcPfmCounters definitions available in this target. + void emitPfmCounters(raw_ostream &OS) const; + + void emitPfmCountersInfo(const Record &Def, + unsigned &IssueCountersTableOffset, + raw_ostream &OS) const; + + void emitPfmCountersLookupTable(raw_ostream &OS) const; + + RecordKeeper &Records; + std::string Target; + + // Table of counter name -> counter index. + const std::map<llvm::StringRef, unsigned> PfmCounterNameTable; +}; + +static std::map<llvm::StringRef, unsigned> +collectPfmCounters(const RecordKeeper &Records) { + std::map<llvm::StringRef, unsigned> PfmCounterNameTable; + const auto AddPfmCounterName = [&PfmCounterNameTable]( + const Record *PfmCounterDef) { + const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter"); + if (!Counter.empty()) + PfmCounterNameTable.emplace(Counter, 0); + }; + for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) { + // Check that ResourceNames are unique. + llvm::SmallSet<llvm::StringRef, 16> Seen; + for (const Record *IssueCounter : + Def->getValueAsListOfDefs("IssueCounters")) { + const llvm::StringRef ResourceName = + IssueCounter->getValueAsString("ResourceName"); + if (ResourceName.empty()) + PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName"); + if (!Seen.insert(ResourceName).second) + PrintFatalError(IssueCounter->getLoc(), + "duplicate ResourceName " + ResourceName); + AddPfmCounterName(IssueCounter); + } + AddPfmCounterName(Def->getValueAsDef("CycleCounter")); + AddPfmCounterName(Def->getValueAsDef("UopsCounter")); + } + unsigned Index = 0; + for (auto &NameAndIndex : PfmCounterNameTable) + NameAndIndex.second = Index++; + return PfmCounterNameTable; +} + +ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK) + : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) { + std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target"); + if (Targets.size() == 0) + PrintFatalError("ERROR: No 'Target' subclasses defined!"); + if (Targets.size() != 1) + PrintFatalError("ERROR: Multiple subclasses of Target defined!"); + Target = Targets[0]->getName(); +} + +void ExegesisEmitter::emitPfmCountersInfo(const Record &Def, + unsigned &IssueCountersTableOffset, + raw_ostream &OS) const { + const auto CycleCounter = + Def.getValueAsDef("CycleCounter")->getValueAsString("Counter"); + const auto UopsCounter = + Def.getValueAsDef("UopsCounter")->getValueAsString("Counter"); + const size_t NumIssueCounters = + Def.getValueAsListOfDefs("IssueCounters").size(); + + OS << "\nstatic const PfmCountersInfo " << Target << Def.getName() + << " = {\n"; + + // Cycle Counter. + if (CycleCounter.empty()) + OS << " nullptr, // No cycle counter.\n"; + else + OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter) + << "], // Cycle counter\n"; + + // Uops Counter. + if (UopsCounter.empty()) + OS << " nullptr, // No uops counter.\n"; + else + OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter) + << "], // Uops counter\n"; + + // Issue Counters + if (NumIssueCounters == 0) + OS << " nullptr, // No issue counters.\n 0\n"; + else + OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset + << ", " << NumIssueCounters << " // Issue counters.\n"; + + OS << "};\n"; + IssueCountersTableOffset += NumIssueCounters; +} + +void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const { + // Emit the counter name table. + OS << "\nstatic const char* " << Target << "PfmCounterNames[] = {\n"; + for (const auto &NameAndIndex : PfmCounterNameTable) + OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second + << "\n"; + OS << "};\n\n"; + + // Emit the IssueCounters table. + const auto PfmCounterDefs = + Records.getAllDerivedDefinitions("ProcPfmCounters"); + // Only emit if non-empty. + const bool HasAtLeastOnePfmIssueCounter = + llvm::any_of(PfmCounterDefs, [](const Record *Def) { + return !Def->getValueAsListOfDefs("IssueCounters").empty(); + }); + if (HasAtLeastOnePfmIssueCounter) { + OS << "static const PfmCountersInfo::IssueCounter " << Target + << "PfmIssueCounters[] = {\n"; + for (const Record *Def : PfmCounterDefs) { + for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters")) + OS << " { " << Target << "PfmCounterNames[" + << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \"" + << ICDef->getValueAsString("ResourceName") << "\"},\n"; + } + OS << "};\n"; + } + + // Now generate the PfmCountersInfo. + unsigned IssueCountersTableOffset = 0; + for (const Record *Def : PfmCounterDefs) + emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS); + + OS << "\n"; +} // namespace + +void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const { + std::vector<Record *> Bindings = + Records.getAllDerivedDefinitions("PfmCountersBinding"); + assert(!Bindings.empty() && "there must be at least one binding"); + llvm::sort(Bindings, [](const Record *L, const Record *R) { + return L->getValueAsString("CpuName") < R->getValueAsString("CpuName"); + }); + + OS << "// Sorted (by CpuName) array of pfm counters.\n" + << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n"; + for (Record *Binding : Bindings) { + // Emit as { "cpu", procinit }, + OS << " { \"" // + << Binding->getValueAsString("CpuName") << "\"," // + << " &" << Target << Binding->getValueAsDef("Counters")->getName() // + << " },\n"; + } + OS << "};\n\n"; +} + +void ExegesisEmitter::run(raw_ostream &OS) const { + emitSourceFileHeader("Exegesis Tables", OS); + emitPfmCounters(OS); + emitPfmCountersLookupTable(OS); +} + +} // end anonymous namespace + +namespace llvm { + +void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) { + ExegesisEmitter(RK).run(OS); +} + +} // end namespace llvm |