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
25 using namespace llvm;
26
27 #define DEBUG_TYPE "exegesis-emitter"
28
29 namespace {
30
31 class ExegesisEmitter {
32 public:
33 ExegesisEmitter(RecordKeeper &RK);
34
35 void run(raw_ostream &OS) const;
36
37 private:
getPfmCounterId(llvm::StringRef Name) const38 unsigned getPfmCounterId(llvm::StringRef Name) const {
39 const auto It = PfmCounterNameTable.find(Name);
40 if (It == PfmCounterNameTable.end())
41 PrintFatalError("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 RecordKeeper &Records;
55 std::string Target;
56
57 // Table of counter name -> counter index.
58 const std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
59 };
60
61 static std::map<llvm::StringRef, unsigned>
collectPfmCounters(const RecordKeeper & Records)62 collectPfmCounters(const RecordKeeper &Records) {
63 std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
64 const auto AddPfmCounterName = [&PfmCounterNameTable](
65 const Record *PfmCounterDef) {
66 const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter");
67 if (!Counter.empty())
68 PfmCounterNameTable.emplace(Counter, 0);
69 };
70 for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) {
71 // Check that ResourceNames are unique.
72 llvm::SmallSet<llvm::StringRef, 16> Seen;
73 for (const Record *IssueCounter :
74 Def->getValueAsListOfDefs("IssueCounters")) {
75 const llvm::StringRef ResourceName =
76 IssueCounter->getValueAsString("ResourceName");
77 if (ResourceName.empty())
78 PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName");
79 if (!Seen.insert(ResourceName).second)
80 PrintFatalError(IssueCounter->getLoc(),
81 "duplicate ResourceName " + ResourceName);
82 AddPfmCounterName(IssueCounter);
83 }
84
85 for (const Record *ValidationCounter :
86 Def->getValueAsListOfDefs("ValidationCounters"))
87 AddPfmCounterName(ValidationCounter);
88
89 AddPfmCounterName(Def->getValueAsDef("CycleCounter"));
90 AddPfmCounterName(Def->getValueAsDef("UopsCounter"));
91 }
92 unsigned Index = 0;
93 for (auto &NameAndIndex : PfmCounterNameTable)
94 NameAndIndex.second = Index++;
95 return PfmCounterNameTable;
96 }
97
ExegesisEmitter(RecordKeeper & RK)98 ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK)
99 : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) {
100 std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");
101 if (Targets.size() == 0)
102 PrintFatalError("No 'Target' subclasses defined!");
103 if (Targets.size() != 1)
104 PrintFatalError("Multiple subclasses of Target defined!");
105 Target = std::string(Targets[0]->getName());
106 }
107
108 struct ValidationCounterInfo {
109 int64_t EventNumber;
110 StringRef EventName;
111 unsigned PfmCounterID;
112 };
113
EventNumberLess(const ValidationCounterInfo & LHS,const ValidationCounterInfo & RHS)114 bool EventNumberLess(const ValidationCounterInfo &LHS,
115 const ValidationCounterInfo &RHS) {
116 return LHS.EventNumber < RHS.EventNumber;
117 }
118
emitPfmCountersInfo(const Record & Def,unsigned & IssueCountersTableOffset,raw_ostream & OS) const119 void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
120 unsigned &IssueCountersTableOffset,
121 raw_ostream &OS) const {
122 const auto CycleCounter =
123 Def.getValueAsDef("CycleCounter")->getValueAsString("Counter");
124 const auto UopsCounter =
125 Def.getValueAsDef("UopsCounter")->getValueAsString("Counter");
126 const size_t NumIssueCounters =
127 Def.getValueAsListOfDefs("IssueCounters").size();
128 const size_t NumValidationCounters =
129 Def.getValueAsListOfDefs("ValidationCounters").size();
130
131 // Emit Validation Counters Array
132 if (NumValidationCounters != 0) {
133 std::vector<ValidationCounterInfo> ValidationCounters;
134 ValidationCounters.reserve(NumValidationCounters);
135 for (const Record *ValidationCounter :
136 Def.getValueAsListOfDefs("ValidationCounters")) {
137 ValidationCounters.push_back(
138 {ValidationCounter->getValueAsDef("EventType")
139 ->getValueAsInt("EventNumber"),
140 ValidationCounter->getValueAsDef("EventType")->getName(),
141 getPfmCounterId(ValidationCounter->getValueAsString("Counter"))});
142 }
143 std::sort(ValidationCounters.begin(), ValidationCounters.end(),
144 EventNumberLess);
145 OS << "\nstatic const std::pair<ValidationEvent, const char*> " << Target
146 << Def.getName() << "ValidationCounters[] = {\n";
147 for (const ValidationCounterInfo &VCI : ValidationCounters) {
148 OS << " { " << VCI.EventName << ", " << Target << "PfmCounterNames["
149 << VCI.PfmCounterID << "]},\n";
150 }
151 OS << "};\n";
152 }
153
154 OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()
155 << " = {\n";
156
157 // Cycle Counter.
158 if (CycleCounter.empty())
159 OS << " nullptr, // No cycle counter.\n";
160 else
161 OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter)
162 << "], // Cycle counter\n";
163
164 // Uops Counter.
165 if (UopsCounter.empty())
166 OS << " nullptr, // No uops counter.\n";
167 else
168 OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter)
169 << "], // Uops counter\n";
170
171 // Issue Counters
172 if (NumIssueCounters == 0)
173 OS << " nullptr, 0, // No issue counters\n";
174 else
175 OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset
176 << ", " << NumIssueCounters << ", // Issue counters.\n";
177
178 // Validation Counters
179 if (NumValidationCounters == 0)
180 OS << " nullptr, 0 // No validation counters.\n";
181 else
182 OS << " " << Target << Def.getName() << "ValidationCounters, "
183 << NumValidationCounters << " // Validation counters.\n";
184
185 OS << "};\n";
186 IssueCountersTableOffset += NumIssueCounters;
187 }
188
emitPfmCounters(raw_ostream & OS) const189 void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
190 // Emit the counter name table.
191 OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";
192 for (const auto &NameAndIndex : PfmCounterNameTable)
193 OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
194 << "\n";
195 OS << "};\n\n";
196
197 // Emit the IssueCounters table.
198 const auto PfmCounterDefs =
199 Records.getAllDerivedDefinitions("ProcPfmCounters");
200 // Only emit if non-empty.
201 const bool HasAtLeastOnePfmIssueCounter =
202 llvm::any_of(PfmCounterDefs, [](const Record *Def) {
203 return !Def->getValueAsListOfDefs("IssueCounters").empty();
204 });
205 if (HasAtLeastOnePfmIssueCounter) {
206 OS << "static const PfmCountersInfo::IssueCounter " << Target
207 << "PfmIssueCounters[] = {\n";
208 for (const Record *Def : PfmCounterDefs) {
209 for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters"))
210 OS << " { " << Target << "PfmCounterNames["
211 << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \""
212 << ICDef->getValueAsString("ResourceName") << "\"},\n";
213 }
214 OS << "};\n";
215 }
216
217 // Now generate the PfmCountersInfo.
218 unsigned IssueCountersTableOffset = 0;
219 for (const Record *Def : PfmCounterDefs)
220 emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS);
221
222 OS << "\n";
223 } // namespace
224
emitPfmCountersLookupTable(raw_ostream & OS) const225 void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {
226 std::vector<Record *> Bindings =
227 Records.getAllDerivedDefinitions("PfmCountersBinding");
228 assert(!Bindings.empty() && "there must be at least one binding");
229 llvm::sort(Bindings, [](const Record *L, const Record *R) {
230 return L->getValueAsString("CpuName") < R->getValueAsString("CpuName");
231 });
232
233 OS << "// Sorted (by CpuName) array of pfm counters.\n"
234 << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";
235 for (Record *Binding : Bindings) {
236 // Emit as { "cpu", procinit },
237 OS << " { \"" //
238 << Binding->getValueAsString("CpuName") << "\"," //
239 << " &" << Target << Binding->getValueAsDef("Counters")->getName() //
240 << " },\n";
241 }
242 OS << "};\n\n";
243 }
244
run(raw_ostream & OS) const245 void ExegesisEmitter::run(raw_ostream &OS) const {
246 emitSourceFileHeader("Exegesis Tables", OS);
247 emitPfmCounters(OS);
248 emitPfmCountersLookupTable(OS);
249 }
250
251 } // end anonymous namespace
252
253 static TableGen::Emitter::OptClass<ExegesisEmitter>
254 X("gen-exegesis", "Generate llvm-exegesis tables");
255