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