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:
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   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 (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     AddPfmCounterName(Def->getValueAsDef("CycleCounter"));
85     AddPfmCounterName(Def->getValueAsDef("UopsCounter"));
86   }
87   unsigned Index = 0;
88   for (auto &NameAndIndex : PfmCounterNameTable)
89     NameAndIndex.second = Index++;
90   return PfmCounterNameTable;
91 }
92 
93 ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK)
94     : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) {
95   std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");
96   if (Targets.size() == 0)
97     PrintFatalError("No 'Target' subclasses defined!");
98   if (Targets.size() != 1)
99     PrintFatalError("Multiple subclasses of Target defined!");
100   Target = std::string(Targets[0]->getName());
101 }
102 
103 void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
104                                           unsigned &IssueCountersTableOffset,
105                                           raw_ostream &OS) const {
106   const auto CycleCounter =
107       Def.getValueAsDef("CycleCounter")->getValueAsString("Counter");
108   const auto UopsCounter =
109       Def.getValueAsDef("UopsCounter")->getValueAsString("Counter");
110   const size_t NumIssueCounters =
111       Def.getValueAsListOfDefs("IssueCounters").size();
112 
113   OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()
114      << " = {\n";
115 
116   // Cycle Counter.
117   if (CycleCounter.empty())
118     OS << "  nullptr,  // No cycle counter.\n";
119   else
120     OS << "  " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter)
121        << "],  // Cycle counter\n";
122 
123   // Uops Counter.
124   if (UopsCounter.empty())
125     OS << "  nullptr,  // No uops counter.\n";
126   else
127     OS << "  " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter)
128        << "],  // Uops counter\n";
129 
130   // Issue Counters
131   if (NumIssueCounters == 0)
132     OS << "  nullptr,  // No issue counters.\n  0\n";
133   else
134     OS << "  " << Target << "PfmIssueCounters + " << IssueCountersTableOffset
135        << ", " << NumIssueCounters << " // Issue counters.\n";
136 
137   OS << "};\n";
138   IssueCountersTableOffset += NumIssueCounters;
139 }
140 
141 void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
142   // Emit the counter name table.
143   OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";
144   for (const auto &NameAndIndex : PfmCounterNameTable)
145     OS << "  \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
146        << "\n";
147   OS << "};\n\n";
148 
149   // Emit the IssueCounters table.
150   const auto PfmCounterDefs =
151       Records.getAllDerivedDefinitions("ProcPfmCounters");
152   // Only emit if non-empty.
153   const bool HasAtLeastOnePfmIssueCounter =
154       llvm::any_of(PfmCounterDefs, [](const Record *Def) {
155         return !Def->getValueAsListOfDefs("IssueCounters").empty();
156       });
157   if (HasAtLeastOnePfmIssueCounter) {
158     OS << "static const PfmCountersInfo::IssueCounter " << Target
159        << "PfmIssueCounters[] = {\n";
160     for (const Record *Def : PfmCounterDefs) {
161       for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters"))
162         OS << "  { " << Target << "PfmCounterNames["
163            << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \""
164            << ICDef->getValueAsString("ResourceName") << "\"},\n";
165     }
166     OS << "};\n";
167   }
168 
169   // Now generate the PfmCountersInfo.
170   unsigned IssueCountersTableOffset = 0;
171   for (const Record *Def : PfmCounterDefs)
172     emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS);
173 
174   OS << "\n";
175 } // namespace
176 
177 void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {
178   std::vector<Record *> Bindings =
179       Records.getAllDerivedDefinitions("PfmCountersBinding");
180   assert(!Bindings.empty() && "there must be at least one binding");
181   llvm::sort(Bindings, [](const Record *L, const Record *R) {
182     return L->getValueAsString("CpuName") < R->getValueAsString("CpuName");
183   });
184 
185   OS << "// Sorted (by CpuName) array of pfm counters.\n"
186      << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";
187   for (Record *Binding : Bindings) {
188     // Emit as { "cpu", procinit },
189     OS << "  { \""                                                        //
190        << Binding->getValueAsString("CpuName") << "\","                   //
191        << " &" << Target << Binding->getValueAsDef("Counters")->getName() //
192        << " },\n";
193   }
194   OS << "};\n\n";
195 }
196 
197 void ExegesisEmitter::run(raw_ostream &OS) const {
198   emitSourceFileHeader("Exegesis Tables", OS);
199   emitPfmCounters(OS);
200   emitPfmCountersLookupTable(OS);
201 }
202 
203 } // end anonymous namespace
204 
205 static TableGen::Emitter::OptClass<ExegesisEmitter>
206     X("gen-exegesis", "Generate llvm-exegesis tables");
207