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