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/Debug.h"
170b57cec5SDimitry Andric #include "llvm/Support/Format.h"
180b57cec5SDimitry Andric #include "llvm/Support/raw_ostream.h"
190b57cec5SDimitry Andric #include "llvm/TableGen/Error.h"
200b57cec5SDimitry Andric #include "llvm/TableGen/Record.h"
210b57cec5SDimitry Andric #include "llvm/TableGen/TableGenBackend.h"
220b57cec5SDimitry Andric #include <algorithm>
230b57cec5SDimitry Andric #include <cassert>
240b57cec5SDimitry Andric #include <cstdint>
250b57cec5SDimitry Andric #include <map>
260b57cec5SDimitry Andric #include <string>
270b57cec5SDimitry Andric #include <vector>
280b57cec5SDimitry Andric
290b57cec5SDimitry Andric using namespace llvm;
300b57cec5SDimitry Andric
310b57cec5SDimitry Andric #define DEBUG_TYPE "exegesis-emitter"
320b57cec5SDimitry Andric
330b57cec5SDimitry Andric namespace {
340b57cec5SDimitry Andric
350b57cec5SDimitry Andric class ExegesisEmitter {
360b57cec5SDimitry Andric public:
370b57cec5SDimitry Andric ExegesisEmitter(RecordKeeper &RK);
380b57cec5SDimitry Andric
390b57cec5SDimitry Andric void run(raw_ostream &OS) const;
400b57cec5SDimitry Andric
410b57cec5SDimitry Andric private:
getPfmCounterId(llvm::StringRef Name) const420b57cec5SDimitry Andric unsigned getPfmCounterId(llvm::StringRef Name) const {
430b57cec5SDimitry Andric const auto It = PfmCounterNameTable.find(Name);
440b57cec5SDimitry Andric if (It == PfmCounterNameTable.end())
450b57cec5SDimitry Andric PrintFatalError("no pfm counter id for " + Name);
460b57cec5SDimitry Andric return It->second;
470b57cec5SDimitry Andric }
480b57cec5SDimitry Andric
490b57cec5SDimitry Andric // Collects all the ProcPfmCounters definitions available in this target.
500b57cec5SDimitry Andric void emitPfmCounters(raw_ostream &OS) const;
510b57cec5SDimitry Andric
520b57cec5SDimitry Andric void emitPfmCountersInfo(const Record &Def,
530b57cec5SDimitry Andric unsigned &IssueCountersTableOffset,
540b57cec5SDimitry Andric raw_ostream &OS) const;
550b57cec5SDimitry Andric
560b57cec5SDimitry Andric void emitPfmCountersLookupTable(raw_ostream &OS) const;
570b57cec5SDimitry Andric
580b57cec5SDimitry Andric RecordKeeper &Records;
590b57cec5SDimitry Andric std::string Target;
600b57cec5SDimitry Andric
610b57cec5SDimitry Andric // Table of counter name -> counter index.
620b57cec5SDimitry Andric const std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
630b57cec5SDimitry Andric };
640b57cec5SDimitry Andric
650b57cec5SDimitry Andric static std::map<llvm::StringRef, unsigned>
collectPfmCounters(const RecordKeeper & Records)660b57cec5SDimitry Andric collectPfmCounters(const RecordKeeper &Records) {
670b57cec5SDimitry Andric std::map<llvm::StringRef, unsigned> PfmCounterNameTable;
680b57cec5SDimitry Andric const auto AddPfmCounterName = [&PfmCounterNameTable](
690b57cec5SDimitry Andric const Record *PfmCounterDef) {
700b57cec5SDimitry Andric const llvm::StringRef Counter = PfmCounterDef->getValueAsString("Counter");
710b57cec5SDimitry Andric if (!Counter.empty())
720b57cec5SDimitry Andric PfmCounterNameTable.emplace(Counter, 0);
730b57cec5SDimitry Andric };
740b57cec5SDimitry Andric for (Record *Def : Records.getAllDerivedDefinitions("ProcPfmCounters")) {
750b57cec5SDimitry Andric // Check that ResourceNames are unique.
760b57cec5SDimitry Andric llvm::SmallSet<llvm::StringRef, 16> Seen;
770b57cec5SDimitry Andric for (const Record *IssueCounter :
780b57cec5SDimitry Andric Def->getValueAsListOfDefs("IssueCounters")) {
790b57cec5SDimitry Andric const llvm::StringRef ResourceName =
800b57cec5SDimitry Andric IssueCounter->getValueAsString("ResourceName");
810b57cec5SDimitry Andric if (ResourceName.empty())
820b57cec5SDimitry Andric PrintFatalError(IssueCounter->getLoc(), "invalid empty ResourceName");
830b57cec5SDimitry Andric if (!Seen.insert(ResourceName).second)
840b57cec5SDimitry Andric PrintFatalError(IssueCounter->getLoc(),
850b57cec5SDimitry Andric "duplicate ResourceName " + ResourceName);
860b57cec5SDimitry Andric AddPfmCounterName(IssueCounter);
870b57cec5SDimitry Andric }
880b57cec5SDimitry Andric AddPfmCounterName(Def->getValueAsDef("CycleCounter"));
890b57cec5SDimitry Andric AddPfmCounterName(Def->getValueAsDef("UopsCounter"));
900b57cec5SDimitry Andric }
910b57cec5SDimitry Andric unsigned Index = 0;
920b57cec5SDimitry Andric for (auto &NameAndIndex : PfmCounterNameTable)
930b57cec5SDimitry Andric NameAndIndex.second = Index++;
940b57cec5SDimitry Andric return PfmCounterNameTable;
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric
ExegesisEmitter(RecordKeeper & RK)970b57cec5SDimitry Andric ExegesisEmitter::ExegesisEmitter(RecordKeeper &RK)
980b57cec5SDimitry Andric : Records(RK), PfmCounterNameTable(collectPfmCounters(RK)) {
990b57cec5SDimitry Andric std::vector<Record *> Targets = Records.getAllDerivedDefinitions("Target");
1000b57cec5SDimitry Andric if (Targets.size() == 0)
101*5f7ddb14SDimitry Andric PrintFatalError("No 'Target' subclasses defined!");
1020b57cec5SDimitry Andric if (Targets.size() != 1)
103*5f7ddb14SDimitry Andric PrintFatalError("Multiple subclasses of Target defined!");
1045ffd83dbSDimitry Andric Target = std::string(Targets[0]->getName());
1050b57cec5SDimitry Andric }
1060b57cec5SDimitry Andric
emitPfmCountersInfo(const Record & Def,unsigned & IssueCountersTableOffset,raw_ostream & OS) const1070b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCountersInfo(const Record &Def,
1080b57cec5SDimitry Andric unsigned &IssueCountersTableOffset,
1090b57cec5SDimitry Andric raw_ostream &OS) const {
1100b57cec5SDimitry Andric const auto CycleCounter =
1110b57cec5SDimitry Andric Def.getValueAsDef("CycleCounter")->getValueAsString("Counter");
1120b57cec5SDimitry Andric const auto UopsCounter =
1130b57cec5SDimitry Andric Def.getValueAsDef("UopsCounter")->getValueAsString("Counter");
1140b57cec5SDimitry Andric const size_t NumIssueCounters =
1150b57cec5SDimitry Andric Def.getValueAsListOfDefs("IssueCounters").size();
1160b57cec5SDimitry Andric
1170b57cec5SDimitry Andric OS << "\nstatic const PfmCountersInfo " << Target << Def.getName()
1180b57cec5SDimitry Andric << " = {\n";
1190b57cec5SDimitry Andric
1200b57cec5SDimitry Andric // Cycle Counter.
1210b57cec5SDimitry Andric if (CycleCounter.empty())
1220b57cec5SDimitry Andric OS << " nullptr, // No cycle counter.\n";
1230b57cec5SDimitry Andric else
1240b57cec5SDimitry Andric OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(CycleCounter)
1250b57cec5SDimitry Andric << "], // Cycle counter\n";
1260b57cec5SDimitry Andric
1270b57cec5SDimitry Andric // Uops Counter.
1280b57cec5SDimitry Andric if (UopsCounter.empty())
1290b57cec5SDimitry Andric OS << " nullptr, // No uops counter.\n";
1300b57cec5SDimitry Andric else
1310b57cec5SDimitry Andric OS << " " << Target << "PfmCounterNames[" << getPfmCounterId(UopsCounter)
1320b57cec5SDimitry Andric << "], // Uops counter\n";
1330b57cec5SDimitry Andric
1340b57cec5SDimitry Andric // Issue Counters
1350b57cec5SDimitry Andric if (NumIssueCounters == 0)
1360b57cec5SDimitry Andric OS << " nullptr, // No issue counters.\n 0\n";
1370b57cec5SDimitry Andric else
1380b57cec5SDimitry Andric OS << " " << Target << "PfmIssueCounters + " << IssueCountersTableOffset
1390b57cec5SDimitry Andric << ", " << NumIssueCounters << " // Issue counters.\n";
1400b57cec5SDimitry Andric
1410b57cec5SDimitry Andric OS << "};\n";
1420b57cec5SDimitry Andric IssueCountersTableOffset += NumIssueCounters;
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric
emitPfmCounters(raw_ostream & OS) const1450b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCounters(raw_ostream &OS) const {
1460b57cec5SDimitry Andric // Emit the counter name table.
1470b57cec5SDimitry Andric OS << "\nstatic const char *" << Target << "PfmCounterNames[] = {\n";
1480b57cec5SDimitry Andric for (const auto &NameAndIndex : PfmCounterNameTable)
1490b57cec5SDimitry Andric OS << " \"" << NameAndIndex.first << "\", // " << NameAndIndex.second
1500b57cec5SDimitry Andric << "\n";
1510b57cec5SDimitry Andric OS << "};\n\n";
1520b57cec5SDimitry Andric
1530b57cec5SDimitry Andric // Emit the IssueCounters table.
1540b57cec5SDimitry Andric const auto PfmCounterDefs =
1550b57cec5SDimitry Andric Records.getAllDerivedDefinitions("ProcPfmCounters");
1560b57cec5SDimitry Andric // Only emit if non-empty.
1570b57cec5SDimitry Andric const bool HasAtLeastOnePfmIssueCounter =
1580b57cec5SDimitry Andric llvm::any_of(PfmCounterDefs, [](const Record *Def) {
1590b57cec5SDimitry Andric return !Def->getValueAsListOfDefs("IssueCounters").empty();
1600b57cec5SDimitry Andric });
1610b57cec5SDimitry Andric if (HasAtLeastOnePfmIssueCounter) {
1620b57cec5SDimitry Andric OS << "static const PfmCountersInfo::IssueCounter " << Target
1630b57cec5SDimitry Andric << "PfmIssueCounters[] = {\n";
1640b57cec5SDimitry Andric for (const Record *Def : PfmCounterDefs) {
1650b57cec5SDimitry Andric for (const Record *ICDef : Def->getValueAsListOfDefs("IssueCounters"))
1660b57cec5SDimitry Andric OS << " { " << Target << "PfmCounterNames["
1670b57cec5SDimitry Andric << getPfmCounterId(ICDef->getValueAsString("Counter")) << "], \""
1680b57cec5SDimitry Andric << ICDef->getValueAsString("ResourceName") << "\"},\n";
1690b57cec5SDimitry Andric }
1700b57cec5SDimitry Andric OS << "};\n";
1710b57cec5SDimitry Andric }
1720b57cec5SDimitry Andric
1730b57cec5SDimitry Andric // Now generate the PfmCountersInfo.
1740b57cec5SDimitry Andric unsigned IssueCountersTableOffset = 0;
1750b57cec5SDimitry Andric for (const Record *Def : PfmCounterDefs)
1760b57cec5SDimitry Andric emitPfmCountersInfo(*Def, IssueCountersTableOffset, OS);
1770b57cec5SDimitry Andric
1780b57cec5SDimitry Andric OS << "\n";
1790b57cec5SDimitry Andric } // namespace
1800b57cec5SDimitry Andric
emitPfmCountersLookupTable(raw_ostream & OS) const1810b57cec5SDimitry Andric void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream &OS) const {
1820b57cec5SDimitry Andric std::vector<Record *> Bindings =
1830b57cec5SDimitry Andric Records.getAllDerivedDefinitions("PfmCountersBinding");
1840b57cec5SDimitry Andric assert(!Bindings.empty() && "there must be at least one binding");
1850b57cec5SDimitry Andric llvm::sort(Bindings, [](const Record *L, const Record *R) {
1860b57cec5SDimitry Andric return L->getValueAsString("CpuName") < R->getValueAsString("CpuName");
1870b57cec5SDimitry Andric });
1880b57cec5SDimitry Andric
1890b57cec5SDimitry Andric OS << "// Sorted (by CpuName) array of pfm counters.\n"
1900b57cec5SDimitry Andric << "static const CpuAndPfmCounters " << Target << "CpuPfmCounters[] = {\n";
1910b57cec5SDimitry Andric for (Record *Binding : Bindings) {
1920b57cec5SDimitry Andric // Emit as { "cpu", procinit },
1930b57cec5SDimitry Andric OS << " { \"" //
1940b57cec5SDimitry Andric << Binding->getValueAsString("CpuName") << "\"," //
1950b57cec5SDimitry Andric << " &" << Target << Binding->getValueAsDef("Counters")->getName() //
1960b57cec5SDimitry Andric << " },\n";
1970b57cec5SDimitry Andric }
1980b57cec5SDimitry Andric OS << "};\n\n";
1990b57cec5SDimitry Andric }
2000b57cec5SDimitry Andric
run(raw_ostream & OS) const2010b57cec5SDimitry Andric void ExegesisEmitter::run(raw_ostream &OS) const {
2020b57cec5SDimitry Andric emitSourceFileHeader("Exegesis Tables", OS);
2030b57cec5SDimitry Andric emitPfmCounters(OS);
2040b57cec5SDimitry Andric emitPfmCountersLookupTable(OS);
2050b57cec5SDimitry Andric }
2060b57cec5SDimitry Andric
2070b57cec5SDimitry Andric } // end anonymous namespace
2080b57cec5SDimitry Andric
2090b57cec5SDimitry Andric namespace llvm {
2100b57cec5SDimitry Andric
EmitExegesis(RecordKeeper & RK,raw_ostream & OS)2110b57cec5SDimitry Andric void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) {
2120b57cec5SDimitry Andric ExegesisEmitter(RK).run(OS);
2130b57cec5SDimitry Andric }
2140b57cec5SDimitry Andric
2150b57cec5SDimitry Andric } // end namespace llvm
216