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