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 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 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 114 bool EventNumberLess(const ValidationCounterInfo &LHS, 115 const ValidationCounterInfo &RHS) { 116 return LHS.EventNumber < RHS.EventNumber; 117 } 118 119 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 189 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 225 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 245 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