141c8af39SClement Courbet //===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===//
241c8af39SClement Courbet //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
641c8af39SClement Courbet //
741c8af39SClement Courbet //===----------------------------------------------------------------------===//
841c8af39SClement Courbet //
941c8af39SClement Courbet // This tablegen backend emits llvm-exegesis information.
1041c8af39SClement Courbet //
1141c8af39SClement Courbet //===----------------------------------------------------------------------===//
1241c8af39SClement Courbet
13eee2e06eSClement Courbet #include "llvm/ADT/STLExtras.h"
1441c8af39SClement Courbet #include "llvm/ADT/SmallSet.h"
1541c8af39SClement Courbet #include "llvm/ADT/StringRef.h"
1641c8af39SClement Courbet #include "llvm/Support/raw_ostream.h"
1741c8af39SClement Courbet #include "llvm/TableGen/Error.h"
1841c8af39SClement Courbet #include "llvm/TableGen/Record.h"
1941c8af39SClement Courbet #include "llvm/TableGen/TableGenBackend.h"
2041c8af39SClement Courbet #include <cassert>
2141c8af39SClement Courbet #include <map>
2241c8af39SClement Courbet #include <string>
2341c8af39SClement Courbet #include <vector>
2441c8af39SClement Courbet
2541c8af39SClement Courbet using namespace llvm;
2641c8af39SClement Courbet
2741c8af39SClement Courbet #define DEBUG_TYPE "exegesis-emitter"
2841c8af39SClement Courbet
2941c8af39SClement Courbet namespace {
3041c8af39SClement Courbet
3141c8af39SClement Courbet class ExegesisEmitter {
3241c8af39SClement Courbet public:
3341c8af39SClement Courbet ExegesisEmitter(RecordKeeper &RK);
3441c8af39SClement Courbet
3541c8af39SClement Courbet void run(raw_ostream &OS) const;
3641c8af39SClement Courbet
3741c8af39SClement Courbet private:
getPfmCounterId(llvm::StringRef Name) const3841c8af39SClement Courbet unsigned getPfmCounterId(llvm::StringRef Name) const {
3941c8af39SClement Courbet const auto It = PfmCounterNameTable.find(Name);
4041c8af39SClement Courbet if (It == PfmCounterNameTable.end())
4141c8af39SClement Courbet PrintFatalError("no pfm counter id for " + Name);
4241c8af39SClement Courbet return It->second;
4341c8af39SClement Courbet }
4441c8af39SClement Courbet
4541c8af39SClement Courbet // Collects all the ProcPfmCounters definitions available in this target.
4641c8af39SClement Courbet void emitPfmCounters(raw_ostream &OS) const;
4741c8af39SClement Courbet
4841c8af39SClement Courbet void emitPfmCountersInfo(const Record &Def,
4941c8af39SClement Courbet unsigned &IssueCountersTableOffset,
5041c8af39SClement Courbet raw_ostream &OS) const;
5141c8af39SClement Courbet
5241c8af39SClement Courbet void emitPfmCountersLookupTable(raw_ostream &OS) const;
5341c8af39SClement Courbet
5441c8af39SClement Courbet RecordKeeper &Records;
5541c8af39SClement Courbet std::string Target;
5641c8af39SClement Courbet
5741c8af39SClement Courbet // Table of counter name -> counter index.
5841c8af39SClement Courbet const std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
5941c8af39SClement Courbet };
6041c8af39SClement Courbet
6141c8af39SClement Courbet static std::map<llvm::StringRef, unsigned>
collectPfmCounters(const RecordKeeper & Records)6241c8af39SClement Courbet collectPfmCounters(const RecordKeeper &Records) {
6341c8af39SClement Courbet std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
6441c8af39SClement Courbet const auto AddPfmCounterName = [&PfmCounterNameTable](
6541c8af39SClement Courbet const Record *PfmCounterDef) {
6641c8af39SClement Courbet const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter");
6741c8af39SClement Courbet if (!Counter.empty())
6841c8af39SClement Courbet PfmCounterNameTable.emplace(Counter, 0);
6941c8af39SClement Courbet };
7041c8af39SClement Courbet for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) {
7141c8af39SClement Courbet // Check that ResourceNames are unique.
7241c8af39SClement Courbet llvm::SmallSet<llvm::StringRef, 16> Seen;
7341c8af39SClement Courbet for (const Record *IssueCounter :
7441c8af39SClement Courbet Def->getValueAsListOfDefs("IssueCounters")) {
7541c8af39SClement Courbet const llvm::StringRef ResourceName =
7641c8af39SClement Courbet IssueCounter->getValueAsString("ResourceName");
7741c8af39SClement Courbet if (ResourceName.empty())
7841c8af39SClement Courbet PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName");
7941c8af39SClement Courbet if (!Seen.insert(ResourceName).second)
8041c8af39SClement Courbet PrintFatalError(IssueCounter->getLoc(),
8141c8af39SClement Courbet "duplicate ResourceName " + ResourceName);
8241c8af39SClement Courbet AddPfmCounterName(IssueCounter);
8341c8af39SClement Courbet }
8441c8af39SClement Courbet AddPfmCounterName(Def->getValueAsDef("CycleCounter"));
8541c8af39SClement Courbet AddPfmCounterName(Def->getValueAsDef("UopsCounter"));
8641c8af39SClement Courbet }
8741c8af39SClement Courbet unsigned Index = 0;
8841c8af39SClement Courbet for (auto &NameAndIndex : PfmCounterNameTable)
8941c8af39SClement Courbet NameAndIndex.second = Index++;
9041c8af39SClement Courbet return PfmCounterNameTable;
9141c8af39SClement Courbet }
9241c8af39SClement Courbet
ExegesisEmitter(RecordKeeper & RK)9341c8af39SClement Courbet ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK)
9441c8af39SClement Courbet : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) {
9541c8af39SClement Courbet std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");
9641c8af39SClement Courbet if (Targets.size() == 0)
97*fefd03a8Sqixingxue PrintFatalError("No 'Target' subclasses defined!");
9841c8af39SClement Courbet if (Targets.size() != 1)
99*fefd03a8Sqixingxue PrintFatalError("Multiple subclasses of Target defined!");
100adcd0268SBenjamin Kramer Target = std::string(Targets[0]->getName());
10141c8af39SClement Courbet }
10241c8af39SClement Courbet
emitPfmCountersInfo(const Record & Def,unsigned & IssueCountersTableOffset,raw_ostream & OS) const10341c8af39SClement Courbet void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
10441c8af39SClement Courbet unsigned &IssueCountersTableOffset,
10541c8af39SClement Courbet raw_ostream &OS) const {
10641c8af39SClement Courbet const auto CycleCounter =
10741c8af39SClement Courbet Def.getValueAsDef("CycleCounter")->getValueAsString("Counter");
10841c8af39SClement Courbet const auto UopsCounter =
10941c8af39SClement Courbet Def.getValueAsDef("UopsCounter")->getValueAsString("Counter");
11041c8af39SClement Courbet const size_t NumIssueCounters =
11141c8af39SClement Courbet Def.getValueAsListOfDefs("IssueCounters").size();
11241c8af39SClement Courbet
11341c8af39SClement Courbet OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()
11441c8af39SClement Courbet << " = {\n";
11541c8af39SClement Courbet
11641c8af39SClement Courbet // Cycle Counter.
11741c8af39SClement Courbet if (CycleCounter.empty())
11841c8af39SClement Courbet OS << " nullptr, // No cycle counter.\n";
11941c8af39SClement Courbet else
12041c8af39SClement Courbet OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter)
12141c8af39SClement Courbet << "], // Cycle counter\n";
12241c8af39SClement Courbet
12341c8af39SClement Courbet // Uops Counter.
12441c8af39SClement Courbet if (UopsCounter.empty())
12541c8af39SClement Courbet OS << " nullptr, // No uops counter.\n";
12641c8af39SClement Courbet else
12741c8af39SClement Courbet OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter)
12841c8af39SClement Courbet << "], // Uops counter\n";
12941c8af39SClement Courbet
13041c8af39SClement Courbet // Issue Counters
13141c8af39SClement Courbet if (NumIssueCounters == 0)
13241c8af39SClement Courbet OS << " nullptr, // No issue counters.\n 0\n";
13341c8af39SClement Courbet else
13441c8af39SClement Courbet OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset
13541c8af39SClement Courbet << ", " << NumIssueCounters << " // Issue counters.\n";
13641c8af39SClement Courbet
13741c8af39SClement Courbet OS << "};\n";
13841c8af39SClement Courbet IssueCountersTableOffset += NumIssueCounters;
13941c8af39SClement Courbet }
14041c8af39SClement Courbet
emitPfmCounters(raw_ostream & OS) const14141c8af39SClement Courbet void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
14241c8af39SClement Courbet // Emit the counter name table.
14341c8af39SClement Courbet OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";
14441c8af39SClement Courbet for (const auto &NameAndIndex : PfmCounterNameTable)
14541c8af39SClement Courbet OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
14641c8af39SClement Courbet << "\n";
14741c8af39SClement Courbet OS << "};\n\n";
14841c8af39SClement Courbet
14941c8af39SClement Courbet // Emit the IssueCounters table.
15041c8af39SClement Courbet const auto PfmCounterDefs =
15141c8af39SClement Courbet Records.getAllDerivedDefinitions("ProcPfmCounters");
152eee2e06eSClement Courbet // Only emit if non-empty.
153eee2e06eSClement Courbet const bool HasAtLeastOnePfmIssueCounter =
154eee2e06eSClement Courbet llvm::any_of(PfmCounterDefs, [](const Record *Def) {
155eee2e06eSClement Courbet return !Def->getValueAsListOfDefs("IssueCounters").empty();
156eee2e06eSClement Courbet });
157eee2e06eSClement Courbet if (HasAtLeastOnePfmIssueCounter) {
15841c8af39SClement Courbet OS << "static const PfmCountersInfo::IssueCounter " << Target
15941c8af39SClement Courbet << "PfmIssueCounters[] = {\n";
16041c8af39SClement Courbet for (const Record *Def : PfmCounterDefs) {
16141c8af39SClement Courbet for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters"))
16241c8af39SClement Courbet OS << " { " << Target << "PfmCounterNames["
16341c8af39SClement Courbet << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \""
16441c8af39SClement Courbet << ICDef->getValueAsString("ResourceName") << "\"},\n";
16541c8af39SClement Courbet }
16641c8af39SClement Courbet OS << "};\n";
167eee2e06eSClement Courbet }
16841c8af39SClement Courbet
16941c8af39SClement Courbet // Now generate the PfmCountersInfo.
17041c8af39SClement Courbet unsigned IssueCountersTableOffset = 0;
17141c8af39SClement Courbet for (const Record *Def : PfmCounterDefs)
17241c8af39SClement Courbet emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS);
17341c8af39SClement Courbet
17441c8af39SClement Courbet OS << "\n";
175eee2e06eSClement Courbet } // namespace
17641c8af39SClement Courbet
emitPfmCountersLookupTable(raw_ostream & OS) const17741c8af39SClement Courbet void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {
17841c8af39SClement Courbet std::vector<Record *> Bindings =
17941c8af39SClement Courbet Records.getAllDerivedDefinitions("PfmCountersBinding");
180eee2e06eSClement Courbet assert(!Bindings.empty() && "there must be at least one binding");
18141c8af39SClement Courbet llvm::sort(Bindings, [](const Record *L, const Record *R) {
18241c8af39SClement Courbet return L->getValueAsString("CpuName") < R->getValueAsString("CpuName");
18341c8af39SClement Courbet });
18441c8af39SClement Courbet
18541c8af39SClement Courbet OS << "// Sorted (by CpuName) array of pfm counters.\n"
18641c8af39SClement Courbet << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";
18741c8af39SClement Courbet for (Record *Binding : Bindings) {
18841c8af39SClement Courbet // Emit as { "cpu", procinit },
18941c8af39SClement Courbet OS << " { \"" //
19041c8af39SClement Courbet << Binding->getValueAsString("CpuName") << "\"," //
19141c8af39SClement Courbet << " &" << Target << Binding->getValueAsDef("Counters")->getName() //
19241c8af39SClement Courbet << " },\n";
19341c8af39SClement Courbet }
19441c8af39SClement Courbet OS << "};\n\n";
19541c8af39SClement Courbet }
19641c8af39SClement Courbet
run(raw_ostream & OS) const19741c8af39SClement Courbet void ExegesisEmitter::run(raw_ostream &OS) const {
19841c8af39SClement Courbet emitSourceFileHeader("Exegesis Tables", OS);
19941c8af39SClement Courbet emitPfmCounters(OS);
20041c8af39SClement Courbet emitPfmCountersLookupTable(OS);
20141c8af39SClement Courbet }
20241c8af39SClement Courbet
20341c8af39SClement Courbet } // end anonymous namespace
20441c8af39SClement Courbet
20541c8af39SClement Courbet namespace llvm {
20641c8af39SClement Courbet
EmitExegesis(RecordKeeper & RK,raw_ostream & OS)20741c8af39SClement Courbet void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) {
20841c8af39SClement Courbet ExegesisEmitter(RK).run(OS);
20941c8af39SClement Courbet }
21041c8af39SClement Courbet
21141c8af39SClement Courbet } // end namespace llvm
212