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/Debug.h"
17 #include "llvm/Support/raw_ostream.h"
18 #include "llvm/TableGen/Error.h"
19 #include "llvm/TableGen/Record.h"
20 #include "llvm/TableGen/TableGenBackend.h"
21 #include <cassert>
22 #include <map>
23 #include <string>
24 #include <vector>
25 
26 using namespace llvm;
27 
28 #define DEBUG_TYPE "exegesis-emitter"
29 
30 namespace {
31 
32 class ExegesisEmitter {
33 public:
34   ExegesisEmitter(RecordKeeper &RK);
35 
36   void run(raw_ostream &OS) const;
37 
38 private:
39   unsigned getPfmCounterId(llvm::StringRef Name) const {
40     const auto It = PfmCounterNameTable.find(Name);
41     if (It == PfmCounterNameTable.end())
42       PrintFatalError("no pfm counter id for " + Name);
43     return It->second;
44   }
45 
46   // Collects all the ProcPfmCounters definitions available in this target.
47   void emitPfmCounters(raw_ostream &OS) const;
48 
49   void emitPfmCountersInfo(const Record &Def,
50                            unsigned &IssueCountersTableOffset,
51                            raw_ostream &OS) const;
52 
53   void emitPfmCountersLookupTable(raw_ostream &OS) const;
54 
55   RecordKeeper &Records;
56   std::string Target;
57 
58   // Table of counter name -> counter index.
59   const std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
60 };
61 
62 static std::map<llvm::StringRef, unsigned>
63 collectPfmCounters(const RecordKeeper &Records) {
64   std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
65   const auto AddPfmCounterName = [&PfmCounterNameTable](
66                                      const Record *PfmCounterDef) {
67     const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter");
68     if (!Counter.empty())
69       PfmCounterNameTable.emplace(Counter, 0);
70   };
71   for (Record *Def : 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     AddPfmCounterName(Def->getValueAsDef("CycleCounter"));
86     AddPfmCounterName(Def->getValueAsDef("UopsCounter"));
87   }
88   unsigned Index = 0;
89   for (auto &NameAndIndex : PfmCounterNameTable)
90     NameAndIndex.second = Index++;
91   return PfmCounterNameTable;
92 }
93 
94 ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK)
95     : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) {
96   std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");
97   if (Targets.size() == 0)
98     PrintFatalError("No 'Target' subclasses defined!");
99   if (Targets.size() != 1)
100     PrintFatalError("Multiple subclasses of Target defined!");
101   Target = std::string(Targets[0]->getName());
102 }
103 
104 void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
105                                           unsigned &IssueCountersTableOffset,
106                                           raw_ostream &OS) const {
107   const auto CycleCounter =
108       Def.getValueAsDef("CycleCounter")->getValueAsString("Counter");
109   const auto UopsCounter =
110       Def.getValueAsDef("UopsCounter")->getValueAsString("Counter");
111   const size_t NumIssueCounters =
112       Def.getValueAsListOfDefs("IssueCounters").size();
113 
114   OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()
115      << " = {\n";
116 
117   // Cycle Counter.
118   if (CycleCounter.empty())
119     OS << "  nullptr,  // No cycle counter.\n";
120   else
121     OS << "  " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter)
122        << "],  // Cycle counter\n";
123 
124   // Uops Counter.
125   if (UopsCounter.empty())
126     OS << "  nullptr,  // No uops counter.\n";
127   else
128     OS << "  " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter)
129        << "],  // Uops counter\n";
130 
131   // Issue Counters
132   if (NumIssueCounters == 0)
133     OS << "  nullptr,  // No issue counters.\n  0\n";
134   else
135     OS << "  " << Target << "PfmIssueCounters + " << IssueCountersTableOffset
136        << ", " << NumIssueCounters << " // Issue counters.\n";
137 
138   OS << "};\n";
139   IssueCountersTableOffset += NumIssueCounters;
140 }
141 
142 void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
143   // Emit the counter name table.
144   OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";
145   for (const auto &NameAndIndex : PfmCounterNameTable)
146     OS << "  \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
147        << "\n";
148   OS << "};\n\n";
149 
150   // Emit the IssueCounters table.
151   const auto PfmCounterDefs =
152       Records.getAllDerivedDefinitions("ProcPfmCounters");
153   // Only emit if non-empty.
154   const bool HasAtLeastOnePfmIssueCounter =
155       llvm::any_of(PfmCounterDefs, [](const Record *Def) {
156         return !Def->getValueAsListOfDefs("IssueCounters").empty();
157       });
158   if (HasAtLeastOnePfmIssueCounter) {
159     OS << "static const PfmCountersInfo::IssueCounter " << Target
160        << "PfmIssueCounters[] = {\n";
161     for (const Record *Def : PfmCounterDefs) {
162       for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters"))
163         OS << "  { " << Target << "PfmCounterNames["
164            << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \""
165            << ICDef->getValueAsString("ResourceName") << "\"},\n";
166     }
167     OS << "};\n";
168   }
169 
170   // Now generate the PfmCountersInfo.
171   unsigned IssueCountersTableOffset = 0;
172   for (const Record *Def : PfmCounterDefs)
173     emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS);
174 
175   OS << "\n";
176 } // namespace
177 
178 void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {
179   std::vector<Record *> Bindings =
180       Records.getAllDerivedDefinitions("PfmCountersBinding");
181   assert(!Bindings.empty() && "there must be at least one binding");
182   llvm::sort(Bindings, [](const Record *L, const Record *R) {
183     return L->getValueAsString("CpuName") < R->getValueAsString("CpuName");
184   });
185 
186   OS << "// Sorted (by CpuName) array of pfm counters.\n"
187      << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";
188   for (Record *Binding : Bindings) {
189     // Emit as { "cpu", procinit },
190     OS << "  { \""                                                        //
191        << Binding->getValueAsString("CpuName") << "\","                   //
192        << " &" << Target << Binding->getValueAsDef("Counters")->getName() //
193        << " },\n";
194   }
195   OS << "};\n\n";
196 }
197 
198 void ExegesisEmitter::run(raw_ostream &OS) const {
199   emitSourceFileHeader("Exegesis Tables", OS);
200   emitPfmCounters(OS);
201   emitPfmCountersLookupTable(OS);
202 }
203 
204 } // end anonymous namespace
205 
206 namespace llvm {
207 
208 void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) {
209   ExegesisEmitter(RK).run(OS);
210 }
211 
212 } // end namespace llvm
213