xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/ExegesisEmitter.cpp (revision 297eecfb02bb25902531dbb5c3b9a88caf8adf29)
10b57cec5SDimitry Andric //===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
90b57cec5SDimitry Andric // This tablegen backend emits llvm-exegesis information.
100b57cec5SDimitry Andric //
110b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h"
140b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h"
150b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h"
160b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
170b57cec5SDimitry Andric #include "llvm/TableGen/Error.h"
180b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
190b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
200b57cec5SDimitry Andric #include <cassert>
210b57cec5SDimitry Andric #include <map>
220b57cec5SDimitry Andric #include <string>
230b57cec5SDimitry Andric #include <vector>
240b57cec5SDimitry Andric 
250b57cec5SDimitry Andric using namespace llvm;
260b57cec5SDimitry Andric 
270b57cec5SDimitry Andric #define DEBUG_TYPE "exegesis-emitter"
280b57cec5SDimitry Andric 
290b57cec5SDimitry Andric namespace {
300b57cec5SDimitry Andric 
310b57cec5SDimitry Andric class ExegesisEmitter {
320b57cec5SDimitry Andric public:
330b57cec5SDimitry Andric   ExegesisEmitter(RecordKeeper &RK);
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric   void run(raw_ostream &OS) const;
360b57cec5SDimitry Andric 
370b57cec5SDimitry Andric private:
380b57cec5SDimitry Andric   unsigned getPfmCounterId(llvm::StringRef Name) const {
390b57cec5SDimitry Andric     const auto It = PfmCounterNameTable.find(Name);
400b57cec5SDimitry Andric     if (It == PfmCounterNameTable.end())
410b57cec5SDimitry Andric       PrintFatalError("no pfm counter id for " + Name);
420b57cec5SDimitry Andric     return It->second;
430b57cec5SDimitry Andric   }
440b57cec5SDimitry Andric 
450b57cec5SDimitry Andric   // Collects all the ProcPfmCounters definitions available in this target.
460b57cec5SDimitry Andric   void emitPfmCounters(raw_ostream &OS) const;
470b57cec5SDimitry Andric 
480b57cec5SDimitry Andric   void emitPfmCountersInfo(const Record &Def,
490b57cec5SDimitry Andric                            unsigned &IssueCountersTableOffset,
500b57cec5SDimitry Andric                            raw_ostream &OS) const;
510b57cec5SDimitry Andric 
520b57cec5SDimitry Andric   void emitPfmCountersLookupTable(raw_ostream &OS) const;
530b57cec5SDimitry Andric 
540b57cec5SDimitry Andric   RecordKeeper &Records;
550b57cec5SDimitry Andric   std::string Target;
560b57cec5SDimitry Andric 
570b57cec5SDimitry Andric   // Table of counter name -> counter index.
580b57cec5SDimitry Andric   const std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
590b57cec5SDimitry Andric };
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric static std::map<llvm::StringRef, unsigned>
620b57cec5SDimitry Andric collectPfmCounters(const RecordKeeper &Records) {
630b57cec5SDimitry Andric   std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
640b57cec5SDimitry Andric   const auto AddPfmCounterName = [&PfmCounterNameTable](
650b57cec5SDimitry Andric                                      const Record *PfmCounterDef) {
660b57cec5SDimitry Andric     const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter");
670b57cec5SDimitry Andric     if (!Counter.empty())
680b57cec5SDimitry Andric       PfmCounterNameTable.emplace(Counter, 0);
690b57cec5SDimitry Andric   };
700b57cec5SDimitry Andric   for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) {
710b57cec5SDimitry Andric     // Check that ResourceNames are unique.
720b57cec5SDimitry Andric     llvm::SmallSet<llvm::StringRef, 16> Seen;
730b57cec5SDimitry Andric     for (const Record *IssueCounter :
740b57cec5SDimitry Andric          Def->getValueAsListOfDefs("IssueCounters")) {
750b57cec5SDimitry Andric       const llvm::StringRef ResourceName =
760b57cec5SDimitry Andric           IssueCounter->getValueAsString("ResourceName");
770b57cec5SDimitry Andric       if (ResourceName.empty())
780b57cec5SDimitry Andric         PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName");
790b57cec5SDimitry Andric       if (!Seen.insert(ResourceName).second)
800b57cec5SDimitry Andric         PrintFatalError(IssueCounter->getLoc(),
810b57cec5SDimitry Andric                         "duplicate ResourceName " + ResourceName);
820b57cec5SDimitry Andric       AddPfmCounterName(IssueCounter);
830b57cec5SDimitry Andric     }
84*297eecfbSDimitry Andric 
85*297eecfbSDimitry Andric     for (const Record *ValidationCounter :
86*297eecfbSDimitry Andric          Def->getValueAsListOfDefs("ValidationCounters"))
87*297eecfbSDimitry Andric       AddPfmCounterName(ValidationCounter);
88*297eecfbSDimitry Andric 
890b57cec5SDimitry Andric     AddPfmCounterName(Def->getValueAsDef("CycleCounter"));
900b57cec5SDimitry Andric     AddPfmCounterName(Def->getValueAsDef("UopsCounter"));
910b57cec5SDimitry Andric   }
920b57cec5SDimitry Andric   unsigned Index = 0;
930b57cec5SDimitry Andric   for (auto &NameAndIndex : PfmCounterNameTable)
940b57cec5SDimitry Andric     NameAndIndex.second = Index++;
950b57cec5SDimitry Andric   return PfmCounterNameTable;
960b57cec5SDimitry Andric }
970b57cec5SDimitry Andric 
980b57cec5SDimitry Andric ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK)
990b57cec5SDimitry Andric     : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) {
1000b57cec5SDimitry Andric   std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");
1010b57cec5SDimitry Andric   if (Targets.size() == 0)
102fe6060f1SDimitry Andric     PrintFatalError("No 'Target' subclasses defined!");
1030b57cec5SDimitry Andric   if (Targets.size() != 1)
104fe6060f1SDimitry Andric     PrintFatalError("Multiple subclasses of Target defined!");
1055ffd83dbSDimitry Andric   Target = std::string(Targets[0]->getName());
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
108*297eecfbSDimitry Andric struct ValidationCounterInfo {
109*297eecfbSDimitry Andric   int64_t EventNumber;
110*297eecfbSDimitry Andric   StringRef EventName;
111*297eecfbSDimitry Andric   unsigned PfmCounterID;
112*297eecfbSDimitry Andric };
113*297eecfbSDimitry Andric 
114*297eecfbSDimitry Andric bool EventNumberLess(const ValidationCounterInfo &LHS,
115*297eecfbSDimitry Andric                      const ValidationCounterInfo &RHS) {
116*297eecfbSDimitry Andric   return LHS.EventNumber < RHS.EventNumber;
117*297eecfbSDimitry Andric }
118*297eecfbSDimitry Andric 
1190b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
1200b57cec5SDimitry Andric                                           unsigned &IssueCountersTableOffset,
1210b57cec5SDimitry Andric                                           raw_ostream &OS) const {
1220b57cec5SDimitry Andric   const auto CycleCounter =
1230b57cec5SDimitry Andric       Def.getValueAsDef("CycleCounter")->getValueAsString("Counter");
1240b57cec5SDimitry Andric   const auto UopsCounter =
1250b57cec5SDimitry Andric       Def.getValueAsDef("UopsCounter")->getValueAsString("Counter");
1260b57cec5SDimitry Andric   const size_t NumIssueCounters =
1270b57cec5SDimitry Andric       Def.getValueAsListOfDefs("IssueCounters").size();
128*297eecfbSDimitry Andric   const size_t NumValidationCounters =
129*297eecfbSDimitry Andric       Def.getValueAsListOfDefs("ValidationCounters").size();
130*297eecfbSDimitry Andric 
131*297eecfbSDimitry Andric   // Emit Validation Counters Array
132*297eecfbSDimitry Andric   if (NumValidationCounters != 0) {
133*297eecfbSDimitry Andric     std::vector<ValidationCounterInfo> ValidationCounters;
134*297eecfbSDimitry Andric     ValidationCounters.reserve(NumValidationCounters);
135*297eecfbSDimitry Andric     for (const Record *ValidationCounter :
136*297eecfbSDimitry Andric          Def.getValueAsListOfDefs("ValidationCounters")) {
137*297eecfbSDimitry Andric       ValidationCounters.push_back(
138*297eecfbSDimitry Andric           {ValidationCounter->getValueAsDef("EventType")
139*297eecfbSDimitry Andric                ->getValueAsInt("EventNumber"),
140*297eecfbSDimitry Andric            ValidationCounter->getValueAsDef("EventType")->getName(),
141*297eecfbSDimitry Andric            getPfmCounterId(ValidationCounter->getValueAsString("Counter"))});
142*297eecfbSDimitry Andric     }
143*297eecfbSDimitry Andric     std::sort(ValidationCounters.begin(), ValidationCounters.end(),
144*297eecfbSDimitry Andric               EventNumberLess);
145*297eecfbSDimitry Andric     OS << "\nstatic const std::pair<ValidationEvent, const char*> " << Target
146*297eecfbSDimitry Andric        << Def.getName() << "ValidationCounters[] = {\n";
147*297eecfbSDimitry Andric     for (const ValidationCounterInfo &VCI : ValidationCounters) {
148*297eecfbSDimitry Andric       OS << "  { " << VCI.EventName << ", " << Target << "PfmCounterNames["
149*297eecfbSDimitry Andric          << VCI.PfmCounterID << "]},\n";
150*297eecfbSDimitry Andric     }
151*297eecfbSDimitry Andric     OS << "};\n";
152*297eecfbSDimitry Andric   }
1530b57cec5SDimitry Andric 
1540b57cec5SDimitry Andric   OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()
1550b57cec5SDimitry Andric      << " = {\n";
1560b57cec5SDimitry Andric 
1570b57cec5SDimitry Andric   // Cycle Counter.
1580b57cec5SDimitry Andric   if (CycleCounter.empty())
1590b57cec5SDimitry Andric     OS << "  nullptr,  // No cycle counter.\n";
1600b57cec5SDimitry Andric   else
1610b57cec5SDimitry Andric     OS << "  " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter)
1620b57cec5SDimitry Andric        << "],  // Cycle counter\n";
1630b57cec5SDimitry Andric 
1640b57cec5SDimitry Andric   // Uops Counter.
1650b57cec5SDimitry Andric   if (UopsCounter.empty())
1660b57cec5SDimitry Andric     OS << "  nullptr,  // No uops counter.\n";
1670b57cec5SDimitry Andric   else
1680b57cec5SDimitry Andric     OS << "  " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter)
1690b57cec5SDimitry Andric        << "],  // Uops counter\n";
1700b57cec5SDimitry Andric 
1710b57cec5SDimitry Andric   // Issue Counters
1720b57cec5SDimitry Andric   if (NumIssueCounters == 0)
173*297eecfbSDimitry Andric     OS << "  nullptr, 0, // No issue counters\n";
1740b57cec5SDimitry Andric   else
1750b57cec5SDimitry Andric     OS << "  " << Target << "PfmIssueCounters + " << IssueCountersTableOffset
176*297eecfbSDimitry Andric        << ", " << NumIssueCounters << ", // Issue counters.\n";
177*297eecfbSDimitry Andric 
178*297eecfbSDimitry Andric   // Validation Counters
179*297eecfbSDimitry Andric   if (NumValidationCounters == 0)
180*297eecfbSDimitry Andric     OS << "  nullptr, 0 // No validation counters.\n";
181*297eecfbSDimitry Andric   else
182*297eecfbSDimitry Andric     OS << "  " << Target << Def.getName() << "ValidationCounters, "
183*297eecfbSDimitry Andric        << NumValidationCounters << " // Validation counters.\n";
1840b57cec5SDimitry Andric 
1850b57cec5SDimitry Andric   OS << "};\n";
1860b57cec5SDimitry Andric   IssueCountersTableOffset += NumIssueCounters;
1870b57cec5SDimitry Andric }
1880b57cec5SDimitry Andric 
1890b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
1900b57cec5SDimitry Andric   // Emit the counter name table.
1910b57cec5SDimitry Andric   OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";
1920b57cec5SDimitry Andric   for (const auto &NameAndIndex : PfmCounterNameTable)
1930b57cec5SDimitry Andric     OS << "  \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
1940b57cec5SDimitry Andric        << "\n";
1950b57cec5SDimitry Andric   OS << "};\n\n";
1960b57cec5SDimitry Andric 
1970b57cec5SDimitry Andric   // Emit the IssueCounters table.
1980b57cec5SDimitry Andric   const auto PfmCounterDefs =
1990b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("ProcPfmCounters");
2000b57cec5SDimitry Andric   // Only emit if non-empty.
2010b57cec5SDimitry Andric   const bool HasAtLeastOnePfmIssueCounter =
2020b57cec5SDimitry Andric       llvm::any_of(PfmCounterDefs, [](const Record *Def) {
2030b57cec5SDimitry Andric         return !Def->getValueAsListOfDefs("IssueCounters").empty();
2040b57cec5SDimitry Andric       });
2050b57cec5SDimitry Andric   if (HasAtLeastOnePfmIssueCounter) {
2060b57cec5SDimitry Andric     OS << "static const PfmCountersInfo::IssueCounter " << Target
2070b57cec5SDimitry Andric        << "PfmIssueCounters[] = {\n";
2080b57cec5SDimitry Andric     for (const Record *Def : PfmCounterDefs) {
2090b57cec5SDimitry Andric       for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters"))
2100b57cec5SDimitry Andric         OS << "  { " << Target << "PfmCounterNames["
2110b57cec5SDimitry Andric            << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \""
2120b57cec5SDimitry Andric            << ICDef->getValueAsString("ResourceName") << "\"},\n";
2130b57cec5SDimitry Andric     }
2140b57cec5SDimitry Andric     OS << "};\n";
2150b57cec5SDimitry Andric   }
2160b57cec5SDimitry Andric 
2170b57cec5SDimitry Andric   // Now generate the PfmCountersInfo.
2180b57cec5SDimitry Andric   unsigned IssueCountersTableOffset = 0;
2190b57cec5SDimitry Andric   for (const Record *Def : PfmCounterDefs)
2200b57cec5SDimitry Andric     emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS);
2210b57cec5SDimitry Andric 
2220b57cec5SDimitry Andric   OS << "\n";
2230b57cec5SDimitry Andric } // namespace
2240b57cec5SDimitry Andric 
2250b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {
2260b57cec5SDimitry Andric   std::vector<Record *> Bindings =
2270b57cec5SDimitry Andric       Records.getAllDerivedDefinitions("PfmCountersBinding");
2280b57cec5SDimitry Andric   assert(!Bindings.empty() && "there must be at least one binding");
2290b57cec5SDimitry Andric   llvm::sort(Bindings, [](const Record *L, const Record *R) {
2300b57cec5SDimitry Andric     return L->getValueAsString("CpuName") < R->getValueAsString("CpuName");
2310b57cec5SDimitry Andric   });
2320b57cec5SDimitry Andric 
2330b57cec5SDimitry Andric   OS << "// Sorted (by CpuName) array of pfm counters.\n"
2340b57cec5SDimitry Andric      << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";
2350b57cec5SDimitry Andric   for (Record *Binding : Bindings) {
2360b57cec5SDimitry Andric     // Emit as { "cpu", procinit },
2370b57cec5SDimitry Andric     OS << "  { \""                                                        //
2380b57cec5SDimitry Andric        << Binding->getValueAsString("CpuName") << "\","                   //
2390b57cec5SDimitry Andric        << " &" << Target << Binding->getValueAsDef("Counters")->getName() //
2400b57cec5SDimitry Andric        << " },\n";
2410b57cec5SDimitry Andric   }
2420b57cec5SDimitry Andric   OS << "};\n\n";
2430b57cec5SDimitry Andric }
2440b57cec5SDimitry Andric 
2450b57cec5SDimitry Andric void ExegesisEmitter::run(raw_ostream &OS) const {
2460b57cec5SDimitry Andric   emitSourceFileHeader("Exegesis Tables", OS);
2470b57cec5SDimitry Andric   emitPfmCounters(OS);
2480b57cec5SDimitry Andric   emitPfmCountersLookupTable(OS);
2490b57cec5SDimitry Andric }
2500b57cec5SDimitry Andric 
2510b57cec5SDimitry Andric } // end anonymous namespace
2520b57cec5SDimitry Andric 
25306c3fb27SDimitry Andric static TableGen::Emitter::OptClass<ExegesisEmitter>
25406c3fb27SDimitry Andric     X("gen-exegesis", "Generate llvm-exegesis tables");
255