1//===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This tablegen backend emits llvm-exegesis information.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/ADT/STLExtras.h"
14#include "llvm/ADT/SmallSet.h"
15#include "llvm/ADT/StringRef.h"
16#include "llvm/Support/raw_ostream.h"
17#include "llvm/TableGen/Error.h"
18#include "llvm/TableGen/Record.h"
19#include "llvm/TableGen/TableGenBackend.h"
20#include <cassert>
21#include <map>
22#include <string>
23#include <vector>
24
25using namespace llvm;
26
27#define DEBUG_TYPE "exegesis-emitter"
28
29namespace {
30
31class ExegesisEmitter {
32public:
33 ExegesisEmitter(const RecordKeeper &RK);
34
35 void run(raw_ostream &OS) const;
36
37private:
38 unsigned getPfmCounterId(llvm::StringRef Name) const {
39 const auto It = PfmCounterNameTable.find(x: Name);
40 if (It == PfmCounterNameTable.end())
41 PrintFatalError(Msg: "no pfm counter id for " + Name);
42 return It->second;
43 }
44
45 // Collects all the ProcPfmCounters definitions available in this target.
46 void emitPfmCounters(raw_ostream &OS) const;
47
48 void emitPfmCountersInfo(const Record &Def,
49 unsigned &IssueCountersTableOffset,
50 raw_ostream &OS) const;
51
52 void emitPfmCountersLookupTable(raw_ostream &OS) const;
53
54 const RecordKeeper &Records;
55 std::string Target;
56
57 // Table of counter name -> counter index.
58 const std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
59};
60
61struct ValidationCounterInfo {
62 int64_t EventNumber;
63 StringRef EventName;
64 unsigned PfmCounterID;
65};
66
67} // namespace
68
69static std::map<llvm::StringRef, unsigned>
70collectPfmCounters(const RecordKeeper &Records) {
71 std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
72 const auto AddPfmCounterName = [&PfmCounterNameTable](
73 const Record *PfmCounterDef) {
74 const llvm::StringRef Counter = PfmCounterDef->getValueAsString(FieldName: "Counter");
75 if (!Counter.empty())
76 PfmCounterNameTable.emplace(args: Counter, args: 0);
77 };
78 for (const Record *Def :
79 Records.getAllDerivedDefinitions(ClassName: "ProcPfmCounters")) {
80 // Check that ResourceNames are unique.
81 llvm::SmallSet<llvm::StringRef, 16> Seen;
82 for (const Record *IssueCounter :
83 Def->getValueAsListOfDefs(FieldName: "IssueCounters")) {
84 const llvm::StringRef ResourceName =
85 IssueCounter->getValueAsString(FieldName: "ResourceName");
86 if (ResourceName.empty())
87 PrintFatalError(ErrorLoc: IssueCounter->getLoc(), Msg: "invalid empty ResourceName");
88 if (!Seen.insert(V: ResourceName).second)
89 PrintFatalError(ErrorLoc: IssueCounter->getLoc(),
90 Msg: "duplicate ResourceName " + ResourceName);
91 AddPfmCounterName(IssueCounter);
92 }
93
94 for (const Record *ValidationCounter :
95 Def->getValueAsListOfDefs(FieldName: "ValidationCounters"))
96 AddPfmCounterName(ValidationCounter);
97
98 AddPfmCounterName(Def->getValueAsDef(FieldName: "CycleCounter"));
99 AddPfmCounterName(Def->getValueAsDef(FieldName: "UopsCounter"));
100 }
101 unsigned Index = 0;
102 for (auto &NameAndIndex : PfmCounterNameTable)
103 NameAndIndex.second = Index++;
104 return PfmCounterNameTable;
105}
106
107ExegesisEmitter::ExegesisEmitter(const RecordKeeper &RK)
108 : Records(RK), PfmCounterNameTable(collectPfmCounters(Records: RK)) {
109 ArrayRef<const Record *> Targets = Records.getAllDerivedDefinitions(ClassName: "Target");
110 if (Targets.size() == 0)
111 PrintFatalError(Msg: "No 'Target' subclasses defined!");
112 if (Targets.size() != 1)
113 PrintFatalError(Msg: "Multiple subclasses of Target defined!");
114 Target = Targets[0]->getName().str();
115}
116
117static bool EventNumberLess(const ValidationCounterInfo &LHS,
118 const ValidationCounterInfo &RHS) {
119 return LHS.EventNumber < RHS.EventNumber;
120}
121
122void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
123 unsigned &IssueCountersTableOffset,
124 raw_ostream &OS) const {
125 const auto CycleCounter =
126 Def.getValueAsDef(FieldName: "CycleCounter")->getValueAsString(FieldName: "Counter");
127 const auto UopsCounter =
128 Def.getValueAsDef(FieldName: "UopsCounter")->getValueAsString(FieldName: "Counter");
129 const size_t NumIssueCounters =
130 Def.getValueAsListOfDefs(FieldName: "IssueCounters").size();
131 const size_t NumValidationCounters =
132 Def.getValueAsListOfDefs(FieldName: "ValidationCounters").size();
133
134 // Emit Validation Counters Array
135 if (NumValidationCounters != 0) {
136 std::vector<ValidationCounterInfo> ValidationCounters;
137 ValidationCounters.reserve(n: NumValidationCounters);
138 for (const Record *ValidationCounter :
139 Def.getValueAsListOfDefs(FieldName: "ValidationCounters")) {
140 ValidationCounters.push_back(
141 x: {.EventNumber: ValidationCounter->getValueAsDef(FieldName: "EventType")
142 ->getValueAsInt(FieldName: "EventNumber"),
143 .EventName: ValidationCounter->getValueAsDef(FieldName: "EventType")->getName(),
144 .PfmCounterID: getPfmCounterId(Name: ValidationCounter->getValueAsString(FieldName: "Counter"))});
145 }
146 std::sort(first: ValidationCounters.begin(), last: ValidationCounters.end(),
147 comp: EventNumberLess);
148 OS << "\nstatic const std::pair<ValidationEvent, const char*> " << Target
149 << Def.getName() << "ValidationCounters[] = {\n";
150 for (const ValidationCounterInfo &VCI : ValidationCounters) {
151 OS << " { " << VCI.EventName << ", " << Target << "PfmCounterNames["
152 << VCI.PfmCounterID << "]},\n";
153 }
154 OS << "};\n";
155 }
156
157 OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()
158 << " = {\n";
159
160 // Cycle Counter.
161 if (CycleCounter.empty())
162 OS << " nullptr, // No cycle counter.\n";
163 else
164 OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(Name: CycleCounter)
165 << "], // Cycle counter\n";
166
167 // Uops Counter.
168 if (UopsCounter.empty())
169 OS << " nullptr, // No uops counter.\n";
170 else
171 OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(Name: UopsCounter)
172 << "], // Uops counter\n";
173
174 // Issue Counters
175 if (NumIssueCounters == 0)
176 OS << " nullptr, 0, // No issue counters\n";
177 else
178 OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset
179 << ", " << NumIssueCounters << ", // Issue counters.\n";
180
181 // Validation Counters
182 if (NumValidationCounters == 0)
183 OS << " nullptr, 0 // No validation counters.\n";
184 else
185 OS << " " << Target << Def.getName() << "ValidationCounters, "
186 << NumValidationCounters << " // Validation counters.\n";
187
188 OS << "};\n";
189 IssueCountersTableOffset += NumIssueCounters;
190}
191
192void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
193 // Emit the counter name table.
194 OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";
195 for (const auto &NameAndIndex : PfmCounterNameTable)
196 OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
197 << "\n";
198 OS << "};\n\n";
199
200 // Emit the IssueCounters table.
201 const auto PfmCounterDefs =
202 Records.getAllDerivedDefinitions(ClassName: "ProcPfmCounters");
203 // Only emit if non-empty.
204 const bool HasAtLeastOnePfmIssueCounter =
205 llvm::any_of(Range: PfmCounterDefs, P: [](const Record *Def) {
206 return !Def->getValueAsListOfDefs(FieldName: "IssueCounters").empty();
207 });
208 if (HasAtLeastOnePfmIssueCounter) {
209 OS << "static const PfmCountersInfo::IssueCounter " << Target
210 << "PfmIssueCounters[] = {\n";
211 for (const Record *Def : PfmCounterDefs) {
212 for (const Record *ICDef : Def->getValueAsListOfDefs(FieldName: "IssueCounters"))
213 OS << " { " << Target << "PfmCounterNames["
214 << getPfmCounterId(Name: ICDef->getValueAsString(FieldName: "Counter")) << "], \""
215 << ICDef->getValueAsString(FieldName: "ResourceName") << "\"},\n";
216 }
217 OS << "};\n";
218 }
219
220 // Now generate the PfmCountersInfo.
221 unsigned IssueCountersTableOffset = 0;
222 for (const Record *Def : PfmCounterDefs)
223 emitPfmCountersInfo(Def: *Def, IssueCountersTableOffset, OS);
224
225 OS << "\n";
226}
227
228void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {
229 std::vector<const Record *> Bindings =
230 Records.getAllDerivedDefinitions(ClassName: "PfmCountersBinding");
231 assert(!Bindings.empty() && "there must be at least one binding");
232 llvm::sort(C&: Bindings, Comp: [](const Record *L, const Record *R) {
233 return L->getValueAsString(FieldName: "CpuName") < R->getValueAsString(FieldName: "CpuName");
234 });
235
236 OS << "// Sorted (by CpuName) array of pfm counters.\n"
237 << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";
238 for (const Record *Binding : Bindings) {
239 // Emit as { "cpu", procinit },
240 OS << " { \"" //
241 << Binding->getValueAsString(FieldName: "CpuName") << "\"," //
242 << " &" << Target << Binding->getValueAsDef(FieldName: "Counters")->getName() //
243 << " },\n";
244 }
245 OS << "};\n\n";
246}
247
248void ExegesisEmitter::run(raw_ostream &OS) const {
249 emitSourceFileHeader(Desc: "Exegesis Tables", OS);
250 emitPfmCounters(OS);
251 emitPfmCountersLookupTable(OS);
252}
253
254static TableGen::Emitter::OptClass<ExegesisEmitter>
255 X("gen-exegesis", "Generate llvm-exegesis tables");
256