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