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