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/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: 42 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> 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 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("ERROR: No 'Target' subclasses defined!"); 102 if (Targets.size() != 1) 103 PrintFatalError("ERROR: Multiple subclasses of Target defined!"); 104 Target = Targets[0]->getName(); 105 } 106 107 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 // This is the default, do not emit. 118 if (CycleCounter.empty() && UopsCounter.empty() && NumIssueCounters == 0) 119 return; 120 121 OS << "\nstatic const PfmCountersInfo " << Target << Def.getName() 122 << " = {\n"; 123 124 // Cycle Counter. 125 if (CycleCounter.empty()) 126 OS << " nullptr, // No cycle counter.\n"; 127 else 128 OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter) 129 << "], // Cycle counter\n"; 130 131 // Uops Counter. 132 if (UopsCounter.empty()) 133 OS << " nullptr, // No uops counter.\n"; 134 else 135 OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter) 136 << "], // Uops counter\n"; 137 138 // Issue Counters 139 if (NumIssueCounters == 0) 140 OS << " nullptr, // No issue counters.\n 0\n"; 141 else 142 OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset 143 << ", " << NumIssueCounters << " // Issue counters.\n"; 144 145 OS << "};\n"; 146 IssueCountersTableOffset += NumIssueCounters; 147 } 148 149 void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const { 150 // Emit the counter name table. 151 OS << "\nstatic const char* " << Target << "PfmCounterNames[] = {\n"; 152 for (const auto &NameAndIndex : PfmCounterNameTable) 153 OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second 154 << "\n"; 155 OS << "};\n\n"; 156 157 // Emit the IssueCounters table. 158 const auto PfmCounterDefs = 159 Records.getAllDerivedDefinitions("ProcPfmCounters"); 160 OS << "static const PfmCountersInfo::IssueCounter " << Target 161 << "PfmIssueCounters[] = {\n"; 162 for (const Record *Def : PfmCounterDefs) { 163 for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters")) 164 OS << " { " << Target << "PfmCounterNames[" 165 << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \"" 166 << ICDef->getValueAsString("ResourceName") << "\"},\n"; 167 } 168 169 OS << "};\n"; 170 171 // Now generate the PfmCountersInfo. 172 unsigned IssueCountersTableOffset = 0; 173 for (const Record *Def : PfmCounterDefs) 174 emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS); 175 176 OS << "\n"; 177 } 178 179 void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const { 180 std::vector<Record *> Bindings = 181 Records.getAllDerivedDefinitions("PfmCountersBinding"); 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