1 //===- ExegesisEmitter.cpp - Generate exegesis target data ----------------===//
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
7 //===----------------------------------------------------------------------===//
9 // This tablegen backend emits llvm-exegesis information.
11 //===----------------------------------------------------------------------===//
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"
31 #define DEBUG_TYPE "exegesis-emitter"
35 class ExegesisEmitter
{
37 ExegesisEmitter(RecordKeeper
&RK
);
39 void run(raw_ostream
&OS
) const;
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
);
49 // Collects all the ProcPfmCounters definitions available in this target.
50 void emitPfmCounters(raw_ostream
&OS
) const;
52 void emitPfmCountersInfo(const Record
&Def
,
53 unsigned &IssueCountersTableOffset
,
54 raw_ostream
&OS
) const;
56 void emitPfmCountersLookupTable(raw_ostream
&OS
) const;
58 RecordKeeper
&Records
;
61 // Table of counter name -> counter index.
62 const std::map
<llvm::StringRef
, unsigned> PfmCounterNameTable
;
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");
72 PfmCounterNameTable
.emplace(Counter
, 0);
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
);
88 AddPfmCounterName(Def
->getValueAsDef("CycleCounter"));
89 AddPfmCounterName(Def
->getValueAsDef("UopsCounter"));
92 for (auto &NameAndIndex
: PfmCounterNameTable
)
93 NameAndIndex
.second
= Index
++;
94 return PfmCounterNameTable
;
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();
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();
117 OS
<< "\nstatic const PfmCountersInfo " << Target
<< Def
.getName()
121 if (CycleCounter
.empty())
122 OS
<< " nullptr, // No cycle counter.\n";
124 OS
<< " " << Target
<< "PfmCounterNames[" << getPfmCounterId(CycleCounter
)
125 << "], // Cycle counter\n";
128 if (UopsCounter
.empty())
129 OS
<< " nullptr, // No uops counter.\n";
131 OS
<< " " << Target
<< "PfmCounterNames[" << getPfmCounterId(UopsCounter
)
132 << "], // Uops counter\n";
135 if (NumIssueCounters
== 0)
136 OS
<< " nullptr, // No issue counters.\n 0\n";
138 OS
<< " " << Target
<< "PfmIssueCounters + " << IssueCountersTableOffset
139 << ", " << NumIssueCounters
<< " // Issue counters.\n";
142 IssueCountersTableOffset
+= NumIssueCounters
;
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
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();
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";
173 // Now generate the PfmCountersInfo.
174 unsigned IssueCountersTableOffset
= 0;
175 for (const Record
*Def
: PfmCounterDefs
)
176 emitPfmCountersInfo(*Def
, IssueCountersTableOffset
, OS
);
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");
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 },
194 << Binding
->getValueAsString("CpuName") << "\"," //
195 << " &" << Target
<< Binding
->getValueAsDef("Counters")->getName() //
201 void ExegesisEmitter::run(raw_ostream
&OS
) const {
202 emitSourceFileHeader("Exegesis Tables", OS
);
204 emitPfmCountersLookupTable(OS
);
207 } // end anonymous namespace
211 void EmitExegesis(RecordKeeper
&RK
, raw_ostream
&OS
) {
212 ExegesisEmitter(RK
).run(OS
);
215 } // end namespace llvm