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/raw_ostream.h"
17 #include "llvm/TableGen/Error.h"
18 #include "llvm/TableGen/Record.h"
19 #include "llvm/TableGen/TableGenBackend.h"
27 #define DEBUG_TYPE "exegesis-emitter"
31 class ExegesisEmitter
{
33 ExegesisEmitter(const RecordKeeper
&RK
);
35 void run(raw_ostream
&OS
) const;
38 unsigned getPfmCounterId(llvm::StringRef Name
) const {
39 const auto It
= PfmCounterNameTable
.find(Name
);
40 if (It
== PfmCounterNameTable
.end())
41 PrintFatalError("no pfm counter id for " + Name
);
45 // Collects all the ProcPfmCounters definitions available in this target.
46 void emitPfmCounters(raw_ostream
&OS
) const;
48 void emitPfmCountersInfo(const Record
&Def
,
49 unsigned &IssueCountersTableOffset
,
50 raw_ostream
&OS
) const;
52 void emitPfmCountersLookupTable(raw_ostream
&OS
) const;
54 const RecordKeeper
&Records
;
57 // Table of counter name -> counter index.
58 const std::map
<llvm::StringRef
, unsigned> PfmCounterNameTable
;
61 static std::map
<llvm::StringRef
, unsigned>
62 collectPfmCounters(const RecordKeeper
&Records
) {
63 std::map
<llvm::StringRef
, unsigned> PfmCounterNameTable
;
64 const auto AddPfmCounterName
= [&PfmCounterNameTable
](
65 const Record
*PfmCounterDef
) {
66 const llvm::StringRef Counter
= PfmCounterDef
->getValueAsString("Counter");
68 PfmCounterNameTable
.emplace(Counter
, 0);
70 for (const Record
*Def
:
71 Records
.getAllDerivedDefinitions("ProcPfmCounters")) {
72 // Check that ResourceNames are unique.
73 llvm::SmallSet
<llvm::StringRef
, 16> Seen
;
74 for (const Record
*IssueCounter
:
75 Def
->getValueAsListOfDefs("IssueCounters")) {
76 const llvm::StringRef ResourceName
=
77 IssueCounter
->getValueAsString("ResourceName");
78 if (ResourceName
.empty())
79 PrintFatalError(IssueCounter
->getLoc(), "invalid empty ResourceName");
80 if (!Seen
.insert(ResourceName
).second
)
81 PrintFatalError(IssueCounter
->getLoc(),
82 "duplicate ResourceName " + ResourceName
);
83 AddPfmCounterName(IssueCounter
);
86 for (const Record
*ValidationCounter
:
87 Def
->getValueAsListOfDefs("ValidationCounters"))
88 AddPfmCounterName(ValidationCounter
);
90 AddPfmCounterName(Def
->getValueAsDef("CycleCounter"));
91 AddPfmCounterName(Def
->getValueAsDef("UopsCounter"));
94 for (auto &NameAndIndex
: PfmCounterNameTable
)
95 NameAndIndex
.second
= Index
++;
96 return PfmCounterNameTable
;
99 ExegesisEmitter::ExegesisEmitter(const RecordKeeper
&RK
)
100 : Records(RK
), PfmCounterNameTable(collectPfmCounters(RK
)) {
101 ArrayRef
<const Record
*> Targets
= Records
.getAllDerivedDefinitions("Target");
102 if (Targets
.size() == 0)
103 PrintFatalError("No 'Target' subclasses defined!");
104 if (Targets
.size() != 1)
105 PrintFatalError("Multiple subclasses of Target defined!");
106 Target
= std::string(Targets
[0]->getName());
109 struct ValidationCounterInfo
{
112 unsigned PfmCounterID
;
115 bool EventNumberLess(const ValidationCounterInfo
&LHS
,
116 const ValidationCounterInfo
&RHS
) {
117 return LHS
.EventNumber
< RHS
.EventNumber
;
120 void ExegesisEmitter::emitPfmCountersInfo(const Record
&Def
,
121 unsigned &IssueCountersTableOffset
,
122 raw_ostream
&OS
) const {
123 const auto CycleCounter
=
124 Def
.getValueAsDef("CycleCounter")->getValueAsString("Counter");
125 const auto UopsCounter
=
126 Def
.getValueAsDef("UopsCounter")->getValueAsString("Counter");
127 const size_t NumIssueCounters
=
128 Def
.getValueAsListOfDefs("IssueCounters").size();
129 const size_t NumValidationCounters
=
130 Def
.getValueAsListOfDefs("ValidationCounters").size();
132 // Emit Validation Counters Array
133 if (NumValidationCounters
!= 0) {
134 std::vector
<ValidationCounterInfo
> ValidationCounters
;
135 ValidationCounters
.reserve(NumValidationCounters
);
136 for (const Record
*ValidationCounter
:
137 Def
.getValueAsListOfDefs("ValidationCounters")) {
138 ValidationCounters
.push_back(
139 {ValidationCounter
->getValueAsDef("EventType")
140 ->getValueAsInt("EventNumber"),
141 ValidationCounter
->getValueAsDef("EventType")->getName(),
142 getPfmCounterId(ValidationCounter
->getValueAsString("Counter"))});
144 std::sort(ValidationCounters
.begin(), ValidationCounters
.end(),
146 OS
<< "\nstatic const std::pair<ValidationEvent, const char*> " << Target
147 << Def
.getName() << "ValidationCounters[] = {\n";
148 for (const ValidationCounterInfo
&VCI
: ValidationCounters
) {
149 OS
<< " { " << VCI
.EventName
<< ", " << Target
<< "PfmCounterNames["
150 << VCI
.PfmCounterID
<< "]},\n";
155 OS
<< "\nstatic const PfmCountersInfo " << Target
<< Def
.getName()
159 if (CycleCounter
.empty())
160 OS
<< " nullptr, // No cycle counter.\n";
162 OS
<< " " << Target
<< "PfmCounterNames[" << getPfmCounterId(CycleCounter
)
163 << "], // Cycle counter\n";
166 if (UopsCounter
.empty())
167 OS
<< " nullptr, // No uops counter.\n";
169 OS
<< " " << Target
<< "PfmCounterNames[" << getPfmCounterId(UopsCounter
)
170 << "], // Uops counter\n";
173 if (NumIssueCounters
== 0)
174 OS
<< " nullptr, 0, // No issue counters\n";
176 OS
<< " " << Target
<< "PfmIssueCounters + " << IssueCountersTableOffset
177 << ", " << NumIssueCounters
<< ", // Issue counters.\n";
179 // Validation Counters
180 if (NumValidationCounters
== 0)
181 OS
<< " nullptr, 0 // No validation counters.\n";
183 OS
<< " " << Target
<< Def
.getName() << "ValidationCounters, "
184 << NumValidationCounters
<< " // Validation counters.\n";
187 IssueCountersTableOffset
+= NumIssueCounters
;
190 void ExegesisEmitter::emitPfmCounters(raw_ostream
&OS
) const {
191 // Emit the counter name table.
192 OS
<< "\nstatic const char *" << Target
<< "PfmCounterNames[] = {\n";
193 for (const auto &NameAndIndex
: PfmCounterNameTable
)
194 OS
<< " \"" << NameAndIndex
.first
<< "\", // " << NameAndIndex
.second
198 // Emit the IssueCounters table.
199 const auto PfmCounterDefs
=
200 Records
.getAllDerivedDefinitions("ProcPfmCounters");
201 // Only emit if non-empty.
202 const bool HasAtLeastOnePfmIssueCounter
=
203 llvm::any_of(PfmCounterDefs
, [](const Record
*Def
) {
204 return !Def
->getValueAsListOfDefs("IssueCounters").empty();
206 if (HasAtLeastOnePfmIssueCounter
) {
207 OS
<< "static const PfmCountersInfo::IssueCounter " << Target
208 << "PfmIssueCounters[] = {\n";
209 for (const Record
*Def
: PfmCounterDefs
) {
210 for (const Record
*ICDef
: Def
->getValueAsListOfDefs("IssueCounters"))
211 OS
<< " { " << Target
<< "PfmCounterNames["
212 << getPfmCounterId(ICDef
->getValueAsString("Counter")) << "], \""
213 << ICDef
->getValueAsString("ResourceName") << "\"},\n";
218 // Now generate the PfmCountersInfo.
219 unsigned IssueCountersTableOffset
= 0;
220 for (const Record
*Def
: PfmCounterDefs
)
221 emitPfmCountersInfo(*Def
, IssueCountersTableOffset
, OS
);
226 void ExegesisEmitter::emitPfmCountersLookupTable(raw_ostream
&OS
) const {
227 std::vector
<const Record
*> Bindings
=
228 Records
.getAllDerivedDefinitions("PfmCountersBinding");
229 assert(!Bindings
.empty() && "there must be at least one binding");
230 llvm::sort(Bindings
, [](const Record
*L
, const Record
*R
) {
231 return L
->getValueAsString("CpuName") < R
->getValueAsString("CpuName");
234 OS
<< "// Sorted (by CpuName) array of pfm counters.\n"
235 << "static const CpuAndPfmCounters " << Target
<< "CpuPfmCounters[] = {\n";
236 for (const Record
*Binding
: Bindings
) {
237 // Emit as { "cpu", procinit },
239 << Binding
->getValueAsString("CpuName") << "\"," //
240 << " &" << Target
<< Binding
->getValueAsDef("Counters")->getName() //
246 void ExegesisEmitter::run(raw_ostream
&OS
) const {
247 emitSourceFileHeader("Exegesis Tables", OS
);
249 emitPfmCountersLookupTable(OS
);
252 } // end anonymous namespace
254 static TableGen::Emitter::OptClass
<ExegesisEmitter
>
255 X("gen-exegesis", "Generate llvm-exegesis tables");