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