10b57cec5SDimitry Andric //===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===// 20b57cec5SDimitry Andric // 30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 60b57cec5SDimitry Andric // 70b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 80b57cec5SDimitry Andric // 90b57cec5SDimitry Andric // This tablegen backend emits llvm-exegesis information. 100b57cec5SDimitry Andric // 110b57cec5SDimitry Andric //===----------------------------------------------------------------------===// 120b57cec5SDimitry Andric 130b57cec5SDimitry Andric #include "llvm/ADT/STLExtras.h" 140b57cec5SDimitry Andric #include "llvm/ADT/SmallSet.h" 150b57cec5SDimitry Andric #include "llvm/ADT/StringRef.h" 160b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h" 170b57cec5SDimitry Andric #include "llvm/TableGen/Error.h" 180b57cec5SDimitry Andric #include "llvm/TableGen/Record.h" 190b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h" 200b57cec5SDimitry Andric #include <cassert> 210b57cec5SDimitry Andric #include <map> 220b57cec5SDimitry Andric #include <string> 230b57cec5SDimitry Andric #include <vector> 240b57cec5SDimitry Andric 250b57cec5SDimitry Andric using namespace llvm; 260b57cec5SDimitry Andric 270b57cec5SDimitry Andric #define DEBUG_TYPE "exegesis-emitter" 280b57cec5SDimitry Andric 290b57cec5SDimitry Andric namespace { 300b57cec5SDimitry Andric 310b57cec5SDimitry Andric class ExegesisEmitter { 320b57cec5SDimitry Andric public: 330b57cec5SDimitry Andric ExegesisEmitter(RecordKeeper &RK); 340b57cec5SDimitry Andric 350b57cec5SDimitry Andric void run(raw_ostream &OS) const; 360b57cec5SDimitry Andric 370b57cec5SDimitry Andric private: 380b57cec5SDimitry Andric unsigned getPfmCounterId(llvm::StringRef Name) const { 390b57cec5SDimitry Andric const auto It = PfmCounterNameTable.find(Name); 400b57cec5SDimitry Andric if (It == PfmCounterNameTable.end()) 410b57cec5SDimitry Andric PrintFatalError("no pfm counter id for " + Name); 420b57cec5SDimitry Andric return It->second; 430b57cec5SDimitry Andric } 440b57cec5SDimitry Andric 450b57cec5SDimitry Andric // Collects all the ProcPfmCounters definitions available in this target. 460b57cec5SDimitry Andric void emitPfmCounters(raw_ostream &OS) const; 470b57cec5SDimitry Andric 480b57cec5SDimitry Andric void emitPfmCountersInfo(const Record &Def, 490b57cec5SDimitry Andric unsigned &IssueCountersTableOffset, 500b57cec5SDimitry Andric raw_ostream &OS) const; 510b57cec5SDimitry Andric 520b57cec5SDimitry Andric void emitPfmCountersLookupTable(raw_ostream &OS) const; 530b57cec5SDimitry Andric 540b57cec5SDimitry Andric RecordKeeper &Records; 550b57cec5SDimitry Andric std::string Target; 560b57cec5SDimitry Andric 570b57cec5SDimitry Andric // Table of counter name -> counter index. 580b57cec5SDimitry Andric const std::map<llvm::StringRef, unsigned> PfmCounterNameTable; 590b57cec5SDimitry Andric }; 600b57cec5SDimitry Andric 610b57cec5SDimitry Andric static std::map<llvm::StringRef, unsigned> 620b57cec5SDimitry Andric collectPfmCounters(const RecordKeeper &Records) { 630b57cec5SDimitry Andric std::map<llvm::StringRef, unsigned> PfmCounterNameTable; 640b57cec5SDimitry Andric const auto AddPfmCounterName = [&PfmCounterNameTable]( 650b57cec5SDimitry Andric const Record *PfmCounterDef) { 660b57cec5SDimitry Andric const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter"); 670b57cec5SDimitry Andric if (!Counter.empty()) 680b57cec5SDimitry Andric PfmCounterNameTable.emplace(Counter, 0); 690b57cec5SDimitry Andric }; 700b57cec5SDimitry Andric for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) { 710b57cec5SDimitry Andric // Check that ResourceNames are unique. 720b57cec5SDimitry Andric llvm::SmallSet<llvm::StringRef, 16> Seen; 730b57cec5SDimitry Andric for (const Record *IssueCounter : 740b57cec5SDimitry Andric Def->getValueAsListOfDefs("IssueCounters")) { 750b57cec5SDimitry Andric const llvm::StringRef ResourceName = 760b57cec5SDimitry Andric IssueCounter->getValueAsString("ResourceName"); 770b57cec5SDimitry Andric if (ResourceName.empty()) 780b57cec5SDimitry Andric PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName"); 790b57cec5SDimitry Andric if (!Seen.insert(ResourceName).second) 800b57cec5SDimitry Andric PrintFatalError(IssueCounter->getLoc(), 810b57cec5SDimitry Andric "duplicate ResourceName " + ResourceName); 820b57cec5SDimitry Andric AddPfmCounterName(IssueCounter); 830b57cec5SDimitry Andric } 84*297eecfbSDimitry Andric 85*297eecfbSDimitry Andric for (const Record *ValidationCounter : 86*297eecfbSDimitry Andric Def->getValueAsListOfDefs("ValidationCounters")) 87*297eecfbSDimitry Andric AddPfmCounterName(ValidationCounter); 88*297eecfbSDimitry Andric 890b57cec5SDimitry Andric AddPfmCounterName(Def->getValueAsDef("CycleCounter")); 900b57cec5SDimitry Andric AddPfmCounterName(Def->getValueAsDef("UopsCounter")); 910b57cec5SDimitry Andric } 920b57cec5SDimitry Andric unsigned Index = 0; 930b57cec5SDimitry Andric for (auto &NameAndIndex : PfmCounterNameTable) 940b57cec5SDimitry Andric NameAndIndex.second = Index++; 950b57cec5SDimitry Andric return PfmCounterNameTable; 960b57cec5SDimitry Andric } 970b57cec5SDimitry Andric 980b57cec5SDimitry Andric ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK) 990b57cec5SDimitry Andric : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) { 1000b57cec5SDimitry Andric std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target"); 1010b57cec5SDimitry Andric if (Targets.size() == 0) 102fe6060f1SDimitry Andric PrintFatalError("No 'Target' subclasses defined!"); 1030b57cec5SDimitry Andric if (Targets.size() != 1) 104fe6060f1SDimitry Andric PrintFatalError("Multiple subclasses of Target defined!"); 1055ffd83dbSDimitry Andric Target = std::string(Targets[0]->getName()); 1060b57cec5SDimitry Andric } 1070b57cec5SDimitry Andric 108*297eecfbSDimitry Andric struct ValidationCounterInfo { 109*297eecfbSDimitry Andric int64_t EventNumber; 110*297eecfbSDimitry Andric StringRef EventName; 111*297eecfbSDimitry Andric unsigned PfmCounterID; 112*297eecfbSDimitry Andric }; 113*297eecfbSDimitry Andric 114*297eecfbSDimitry Andric bool EventNumberLess(const ValidationCounterInfo &LHS, 115*297eecfbSDimitry Andric const ValidationCounterInfo &RHS) { 116*297eecfbSDimitry Andric return LHS.EventNumber < RHS.EventNumber; 117*297eecfbSDimitry Andric } 118*297eecfbSDimitry Andric 1190b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCountersInfo(const Record &Def, 1200b57cec5SDimitry Andric unsigned &IssueCountersTableOffset, 1210b57cec5SDimitry Andric raw_ostream &OS) const { 1220b57cec5SDimitry Andric const auto CycleCounter = 1230b57cec5SDimitry Andric Def.getValueAsDef("CycleCounter")->getValueAsString("Counter"); 1240b57cec5SDimitry Andric const auto UopsCounter = 1250b57cec5SDimitry Andric Def.getValueAsDef("UopsCounter")->getValueAsString("Counter"); 1260b57cec5SDimitry Andric const size_t NumIssueCounters = 1270b57cec5SDimitry Andric Def.getValueAsListOfDefs("IssueCounters").size(); 128*297eecfbSDimitry Andric const size_t NumValidationCounters = 129*297eecfbSDimitry Andric Def.getValueAsListOfDefs("ValidationCounters").size(); 130*297eecfbSDimitry Andric 131*297eecfbSDimitry Andric // Emit Validation Counters Array 132*297eecfbSDimitry Andric if (NumValidationCounters != 0) { 133*297eecfbSDimitry Andric std::vector<ValidationCounterInfo> ValidationCounters; 134*297eecfbSDimitry Andric ValidationCounters.reserve(NumValidationCounters); 135*297eecfbSDimitry Andric for (const Record *ValidationCounter : 136*297eecfbSDimitry Andric Def.getValueAsListOfDefs("ValidationCounters")) { 137*297eecfbSDimitry Andric ValidationCounters.push_back( 138*297eecfbSDimitry Andric {ValidationCounter->getValueAsDef("EventType") 139*297eecfbSDimitry Andric ->getValueAsInt("EventNumber"), 140*297eecfbSDimitry Andric ValidationCounter->getValueAsDef("EventType")->getName(), 141*297eecfbSDimitry Andric getPfmCounterId(ValidationCounter->getValueAsString("Counter"))}); 142*297eecfbSDimitry Andric } 143*297eecfbSDimitry Andric std::sort(ValidationCounters.begin(), ValidationCounters.end(), 144*297eecfbSDimitry Andric EventNumberLess); 145*297eecfbSDimitry Andric OS << "\nstatic const std::pair<ValidationEvent, const char*> " << Target 146*297eecfbSDimitry Andric << Def.getName() << "ValidationCounters[] = {\n"; 147*297eecfbSDimitry Andric for (const ValidationCounterInfo &VCI : ValidationCounters) { 148*297eecfbSDimitry Andric OS << " { " << VCI.EventName << ", " << Target << "PfmCounterNames[" 149*297eecfbSDimitry Andric << VCI.PfmCounterID << "]},\n"; 150*297eecfbSDimitry Andric } 151*297eecfbSDimitry Andric OS << "};\n"; 152*297eecfbSDimitry Andric } 1530b57cec5SDimitry Andric 1540b57cec5SDimitry Andric OS << "\nstatic const PfmCountersInfo " << Target << Def.getName() 1550b57cec5SDimitry Andric << " = {\n"; 1560b57cec5SDimitry Andric 1570b57cec5SDimitry Andric // Cycle Counter. 1580b57cec5SDimitry Andric if (CycleCounter.empty()) 1590b57cec5SDimitry Andric OS << " nullptr, // No cycle counter.\n"; 1600b57cec5SDimitry Andric else 1610b57cec5SDimitry Andric OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter) 1620b57cec5SDimitry Andric << "], // Cycle counter\n"; 1630b57cec5SDimitry Andric 1640b57cec5SDimitry Andric // Uops Counter. 1650b57cec5SDimitry Andric if (UopsCounter.empty()) 1660b57cec5SDimitry Andric OS << " nullptr, // No uops counter.\n"; 1670b57cec5SDimitry Andric else 1680b57cec5SDimitry Andric OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter) 1690b57cec5SDimitry Andric << "], // Uops counter\n"; 1700b57cec5SDimitry Andric 1710b57cec5SDimitry Andric // Issue Counters 1720b57cec5SDimitry Andric if (NumIssueCounters == 0) 173*297eecfbSDimitry Andric OS << " nullptr, 0, // No issue counters\n"; 1740b57cec5SDimitry Andric else 1750b57cec5SDimitry Andric OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset 176*297eecfbSDimitry Andric << ", " << NumIssueCounters << ", // Issue counters.\n"; 177*297eecfbSDimitry Andric 178*297eecfbSDimitry Andric // Validation Counters 179*297eecfbSDimitry Andric if (NumValidationCounters == 0) 180*297eecfbSDimitry Andric OS << " nullptr, 0 // No validation counters.\n"; 181*297eecfbSDimitry Andric else 182*297eecfbSDimitry Andric OS << " " << Target << Def.getName() << "ValidationCounters, " 183*297eecfbSDimitry Andric << NumValidationCounters << " // Validation counters.\n"; 1840b57cec5SDimitry Andric 1850b57cec5SDimitry Andric OS << "};\n"; 1860b57cec5SDimitry Andric IssueCountersTableOffset += NumIssueCounters; 1870b57cec5SDimitry Andric } 1880b57cec5SDimitry Andric 1890b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const { 1900b57cec5SDimitry Andric // Emit the counter name table. 1910b57cec5SDimitry Andric OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n"; 1920b57cec5SDimitry Andric for (const auto &NameAndIndex : PfmCounterNameTable) 1930b57cec5SDimitry Andric OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second 1940b57cec5SDimitry Andric << "\n"; 1950b57cec5SDimitry Andric OS << "};\n\n"; 1960b57cec5SDimitry Andric 1970b57cec5SDimitry Andric // Emit the IssueCounters table. 1980b57cec5SDimitry Andric const auto PfmCounterDefs = 1990b57cec5SDimitry Andric Records.getAllDerivedDefinitions("ProcPfmCounters"); 2000b57cec5SDimitry Andric // Only emit if non-empty. 2010b57cec5SDimitry Andric const bool HasAtLeastOnePfmIssueCounter = 2020b57cec5SDimitry Andric llvm::any_of(PfmCounterDefs, [](const Record *Def) { 2030b57cec5SDimitry Andric return !Def->getValueAsListOfDefs("IssueCounters").empty(); 2040b57cec5SDimitry Andric }); 2050b57cec5SDimitry Andric if (HasAtLeastOnePfmIssueCounter) { 2060b57cec5SDimitry Andric OS << "static const PfmCountersInfo::IssueCounter " << Target 2070b57cec5SDimitry Andric << "PfmIssueCounters[] = {\n"; 2080b57cec5SDimitry Andric for (const Record *Def : PfmCounterDefs) { 2090b57cec5SDimitry Andric for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters")) 2100b57cec5SDimitry Andric OS << " { " << Target << "PfmCounterNames[" 2110b57cec5SDimitry Andric << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \"" 2120b57cec5SDimitry Andric << ICDef->getValueAsString("ResourceName") << "\"},\n"; 2130b57cec5SDimitry Andric } 2140b57cec5SDimitry Andric OS << "};\n"; 2150b57cec5SDimitry Andric } 2160b57cec5SDimitry Andric 2170b57cec5SDimitry Andric // Now generate the PfmCountersInfo. 2180b57cec5SDimitry Andric unsigned IssueCountersTableOffset = 0; 2190b57cec5SDimitry Andric for (const Record *Def : PfmCounterDefs) 2200b57cec5SDimitry Andric emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS); 2210b57cec5SDimitry Andric 2220b57cec5SDimitry Andric OS << "\n"; 2230b57cec5SDimitry Andric } // namespace 2240b57cec5SDimitry Andric 2250b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const { 2260b57cec5SDimitry Andric std::vector<Record *> Bindings = 2270b57cec5SDimitry Andric Records.getAllDerivedDefinitions("PfmCountersBinding"); 2280b57cec5SDimitry Andric assert(!Bindings.empty() && "there must be at least one binding"); 2290b57cec5SDimitry Andric llvm::sort(Bindings, [](const Record *L, const Record *R) { 2300b57cec5SDimitry Andric return L->getValueAsString("CpuName") < R->getValueAsString("CpuName"); 2310b57cec5SDimitry Andric }); 2320b57cec5SDimitry Andric 2330b57cec5SDimitry Andric OS << "// Sorted (by CpuName) array of pfm counters.\n" 2340b57cec5SDimitry Andric << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n"; 2350b57cec5SDimitry Andric for (Record *Binding : Bindings) { 2360b57cec5SDimitry Andric // Emit as { "cpu", procinit }, 2370b57cec5SDimitry Andric OS << " { \"" // 2380b57cec5SDimitry Andric << Binding->getValueAsString("CpuName") << "\"," // 2390b57cec5SDimitry Andric << " &" << Target << Binding->getValueAsDef("Counters")->getName() // 2400b57cec5SDimitry Andric << " },\n"; 2410b57cec5SDimitry Andric } 2420b57cec5SDimitry Andric OS << "};\n\n"; 2430b57cec5SDimitry Andric } 2440b57cec5SDimitry Andric 2450b57cec5SDimitry Andric void ExegesisEmitter::run(raw_ostream &OS) const { 2460b57cec5SDimitry Andric emitSourceFileHeader("Exegesis Tables", OS); 2470b57cec5SDimitry Andric emitPfmCounters(OS); 2480b57cec5SDimitry Andric emitPfmCountersLookupTable(OS); 2490b57cec5SDimitry Andric } 2500b57cec5SDimitry Andric 2510b57cec5SDimitry Andric } // end anonymous namespace 2520b57cec5SDimitry Andric 25306c3fb27SDimitry Andric static TableGen::Emitter::OptClass<ExegesisEmitter> 25406c3fb27SDimitry Andric X("gen-exegesis", "Generate llvm-exegesis tables"); 255