ExegesisEmitter.cpp revision 355940
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
29using namespace llvm;
30
31#define DEBUG_TYPE "exegesis-emitter"
32
33namespace {
34
35class ExegesisEmitter {
36public:
37  ExegesisEmitter(RecordKeeper &RK);
38
39  void run(raw_ostream &OS) const;
40
41private:
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
65static std::map<llvm::StringRef, unsigned>
66collectPfmCounters(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
97ExegesisEmitter::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
107void 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
145void 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
181void 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
201void ExegesisEmitter::run(raw_ostream &OS) const {
202  emitSourceFileHeader("Exegesis Tables", OS);
203  emitPfmCounters(OS);
204  emitPfmCountersLookupTable(OS);
205}
206
207} // end anonymous namespace
208
209namespace llvm {
210
211void EmitExegesis(RecordKeeper &RK, raw_ostream &OS) {
212  ExegesisEmitter(RK).run(OS);
213}
214
215} // end namespace llvm
216