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 AddPfmCounterName(Def->getValueAsDef("CycleCounter")); 85 AddPfmCounterName(Def->getValueAsDef("UopsCounter")); 86 } 87 unsigned Index = 0; 88 for (auto &NameAndIndex : PfmCounterNameTable) 89 NameAndIndex.second = Index++; 90 return PfmCounterNameTable; 91 } 92 93 ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK) 94 : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) { 95 std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target"); 96 if (Targets.size() == 0) 97 PrintFatalError("No 'Target' subclasses defined!"); 98 if (Targets.size() != 1) 99 PrintFatalError("Multiple subclasses of Target defined!"); 100 Target = std::string(Targets[0]->getName()); 101 } 102 103 void ExegesisEmitter::emitPfmCountersInfo(const Record &Def, 104 unsigned &IssueCountersTableOffset, 105 raw_ostream &OS) const { 106 const auto CycleCounter = 107 Def.getValueAsDef("CycleCounter")->getValueAsString("Counter"); 108 const auto UopsCounter = 109 Def.getValueAsDef("UopsCounter")->getValueAsString("Counter"); 110 const size_t NumIssueCounters = 111 Def.getValueAsListOfDefs("IssueCounters").size(); 112 113 OS << "\nstatic const PfmCountersInfo " << Target << Def.getName() 114 << " = {\n"; 115 116 // Cycle Counter. 117 if (CycleCounter.empty()) 118 OS << " nullptr, // No cycle counter.\n"; 119 else 120 OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter) 121 << "], // Cycle counter\n"; 122 123 // Uops Counter. 124 if (UopsCounter.empty()) 125 OS << " nullptr, // No uops counter.\n"; 126 else 127 OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter) 128 << "], // Uops counter\n"; 129 130 // Issue Counters 131 if (NumIssueCounters == 0) 132 OS << " nullptr, // No issue counters.\n 0\n"; 133 else 134 OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset 135 << ", " << NumIssueCounters << " // Issue counters.\n"; 136 137 OS << "};\n"; 138 IssueCountersTableOffset += NumIssueCounters; 139 } 140 141 void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const { 142 // Emit the counter name table. 143 OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n"; 144 for (const auto &NameAndIndex : PfmCounterNameTable) 145 OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second 146 << "\n"; 147 OS << "};\n\n"; 148 149 // Emit the IssueCounters table. 150 const auto PfmCounterDefs = 151 Records.getAllDerivedDefinitions("ProcPfmCounters"); 152 // Only emit if non-empty. 153 const bool HasAtLeastOnePfmIssueCounter = 154 llvm::any_of(PfmCounterDefs, [](const Record *Def) { 155 return !Def->getValueAsListOfDefs("IssueCounters").empty(); 156 }); 157 if (HasAtLeastOnePfmIssueCounter) { 158 OS << "static const PfmCountersInfo::IssueCounter " << Target 159 << "PfmIssueCounters[] = {\n"; 160 for (const Record *Def : PfmCounterDefs) { 161 for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters")) 162 OS << " { " << Target << "PfmCounterNames[" 163 << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \"" 164 << ICDef->getValueAsString("ResourceName") << "\"},\n"; 165 } 166 OS << "};\n"; 167 } 168 169 // Now generate the PfmCountersInfo. 170 unsigned IssueCountersTableOffset = 0; 171 for (const Record *Def : PfmCounterDefs) 172 emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS); 173 174 OS << "\n"; 175 } // namespace 176 177 void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const { 178 std::vector<Record *> Bindings = 179 Records.getAllDerivedDefinitions("PfmCountersBinding"); 180 assert(!Bindings.empty() && "there must be at least one binding"); 181 llvm::sort(Bindings, [](const Record *L, const Record *R) { 182 return L->getValueAsString("CpuName") < R->getValueAsString("CpuName"); 183 }); 184 185 OS << "// Sorted (by CpuName) array of pfm counters.\n" 186 << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n"; 187 for (Record *Binding : Bindings) { 188 // Emit as { "cpu", procinit }, 189 OS << " { \"" // 190 << Binding->getValueAsString("CpuName") << "\"," // 191 << " &" << Target << Binding->getValueAsDef("Counters")->getName() // 192 << " },\n"; 193 } 194 OS << "};\n\n"; 195 } 196 197 void ExegesisEmitter::run(raw_ostream &OS) const { 198 emitSourceFileHeader("Exegesis Tables", OS); 199 emitPfmCounters(OS); 200 emitPfmCountersLookupTable(OS); 201 } 202 203 } // end anonymous namespace 204 205 namespace llvm { 206 207 void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) { 208 ExegesisEmitter(RK).run(OS); 209 } 210 211 } // end namespace llvm 212