RegisterBankEmitter.cpp
12.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
//===- RegisterBankEmitter.cpp - Generate a Register Bank Desc. -*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This tablegen backend is responsible for emitting a description of a target
// register bank for a code generator.
//
//===----------------------------------------------------------------------===//
#include "llvm/ADT/BitVector.h"
#include "llvm/Support/Debug.h"
#include "llvm/TableGen/Error.h"
#include "llvm/TableGen/Record.h"
#include "llvm/TableGen/TableGenBackend.h"
#include "CodeGenHwModes.h"
#include "CodeGenRegisters.h"
#include "CodeGenTarget.h"
#define DEBUG_TYPE "register-bank-emitter"
using namespace llvm;
namespace {
class RegisterBank {
/// A vector of register classes that are included in the register bank.
typedef std::vector<const CodeGenRegisterClass *> RegisterClassesTy;
private:
const Record &TheDef;
/// The register classes that are covered by the register bank.
RegisterClassesTy RCs;
/// The register class with the largest register size.
const CodeGenRegisterClass *RCWithLargestRegsSize;
public:
RegisterBank(const Record &TheDef)
: TheDef(TheDef), RCs(), RCWithLargestRegsSize(nullptr) {}
/// Get the human-readable name for the bank.
StringRef getName() const { return TheDef.getValueAsString("Name"); }
/// Get the name of the enumerator in the ID enumeration.
std::string getEnumeratorName() const { return (TheDef.getName() + "ID").str(); }
/// Get the name of the array holding the register class coverage data;
std::string getCoverageArrayName() const {
return (TheDef.getName() + "CoverageData").str();
}
/// Get the name of the global instance variable.
StringRef getInstanceVarName() const { return TheDef.getName(); }
const Record &getDef() const { return TheDef; }
/// Get the register classes listed in the RegisterBank.RegisterClasses field.
std::vector<const CodeGenRegisterClass *>
getExplicitlySpecifiedRegisterClasses(
const CodeGenRegBank &RegisterClassHierarchy) const {
std::vector<const CodeGenRegisterClass *> RCs;
for (const auto *RCDef : getDef().getValueAsListOfDefs("RegisterClasses"))
RCs.push_back(RegisterClassHierarchy.getRegClass(RCDef));
return RCs;
}
/// Add a register class to the bank without duplicates.
void addRegisterClass(const CodeGenRegisterClass *RC) {
if (std::find_if(RCs.begin(), RCs.end(),
[&RC](const CodeGenRegisterClass *X) {
return X == RC;
}) != RCs.end())
return;
// FIXME? We really want the register size rather than the spill size
// since the spill size may be bigger on some targets with
// limited load/store instructions. However, we don't store the
// register size anywhere (we could sum the sizes of the subregisters
// but there may be additional bits too) and we can't derive it from
// the VT's reliably due to Untyped.
if (RCWithLargestRegsSize == nullptr)
RCWithLargestRegsSize = RC;
else if (RCWithLargestRegsSize->RSI.get(DefaultMode).SpillSize <
RC->RSI.get(DefaultMode).SpillSize)
RCWithLargestRegsSize = RC;
assert(RCWithLargestRegsSize && "RC was nullptr?");
RCs.emplace_back(RC);
}
const CodeGenRegisterClass *getRCWithLargestRegsSize() const {
return RCWithLargestRegsSize;
}
iterator_range<typename RegisterClassesTy::const_iterator>
register_classes() const {
return llvm::make_range(RCs.begin(), RCs.end());
}
};
class RegisterBankEmitter {
private:
CodeGenTarget Target;
RecordKeeper &Records;
void emitHeader(raw_ostream &OS, const StringRef TargetName,
const std::vector<RegisterBank> &Banks);
void emitBaseClassDefinition(raw_ostream &OS, const StringRef TargetName,
const std::vector<RegisterBank> &Banks);
void emitBaseClassImplementation(raw_ostream &OS, const StringRef TargetName,
std::vector<RegisterBank> &Banks);
public:
RegisterBankEmitter(RecordKeeper &R) : Target(R), Records(R) {}
void run(raw_ostream &OS);
};
} // end anonymous namespace
/// Emit code to declare the ID enumeration and external global instance
/// variables.
void RegisterBankEmitter::emitHeader(raw_ostream &OS,
const StringRef TargetName,
const std::vector<RegisterBank> &Banks) {
// <Target>RegisterBankInfo.h
OS << "namespace llvm {\n"
<< "namespace " << TargetName << " {\n"
<< "enum : unsigned {\n";
OS << "InvalidRegBankID = ~0u,\n";
unsigned ID = 0;
for (const auto &Bank : Banks)
OS << " " << Bank.getEnumeratorName() << " = " << ID++ << ",\n";
OS << " NumRegisterBanks,\n"
<< "};\n"
<< "} // end namespace " << TargetName << "\n"
<< "} // end namespace llvm\n";
}
/// Emit declarations of the <Target>GenRegisterBankInfo class.
void RegisterBankEmitter::emitBaseClassDefinition(
raw_ostream &OS, const StringRef TargetName,
const std::vector<RegisterBank> &Banks) {
OS << "private:\n"
<< " static RegisterBank *RegBanks[];\n\n"
<< "protected:\n"
<< " " << TargetName << "GenRegisterBankInfo();\n"
<< "\n";
}
/// Visit each register class belonging to the given register bank.
///
/// A class belongs to the bank iff any of these apply:
/// * It is explicitly specified
/// * It is a subclass of a class that is a member.
/// * It is a class containing subregisters of the registers of a class that
/// is a member. This is known as a subreg-class.
///
/// This function must be called for each explicitly specified register class.
///
/// \param RC The register class to search.
/// \param Kind A debug string containing the path the visitor took to reach RC.
/// \param VisitFn The action to take for each class visited. It may be called
/// multiple times for a given class if there are multiple paths
/// to the class.
static void visitRegisterBankClasses(
const CodeGenRegBank &RegisterClassHierarchy,
const CodeGenRegisterClass *RC, const Twine Kind,
std::function<void(const CodeGenRegisterClass *, StringRef)> VisitFn,
SmallPtrSetImpl<const CodeGenRegisterClass *> &VisitedRCs) {
// Make sure we only visit each class once to avoid infinite loops.
if (VisitedRCs.count(RC))
return;
VisitedRCs.insert(RC);
// Visit each explicitly named class.
VisitFn(RC, Kind.str());
for (const auto &PossibleSubclass : RegisterClassHierarchy.getRegClasses()) {
std::string TmpKind =
(Twine(Kind) + " (" + PossibleSubclass.getName() + ")").str();
// Visit each subclass of an explicitly named class.
if (RC != &PossibleSubclass && RC->hasSubClass(&PossibleSubclass))
visitRegisterBankClasses(RegisterClassHierarchy, &PossibleSubclass,
TmpKind + " " + RC->getName() + " subclass",
VisitFn, VisitedRCs);
// Visit each class that contains only subregisters of RC with a common
// subregister-index.
//
// More precisely, PossibleSubclass is a subreg-class iff Reg:SubIdx is in
// PossibleSubclass for all registers Reg from RC using any
// subregister-index SubReg
for (const auto &SubIdx : RegisterClassHierarchy.getSubRegIndices()) {
BitVector BV(RegisterClassHierarchy.getRegClasses().size());
PossibleSubclass.getSuperRegClasses(&SubIdx, BV);
if (BV.test(RC->EnumValue)) {
std::string TmpKind2 = (Twine(TmpKind) + " " + RC->getName() +
" class-with-subregs: " + RC->getName())
.str();
VisitFn(&PossibleSubclass, TmpKind2);
}
}
}
}
void RegisterBankEmitter::emitBaseClassImplementation(
raw_ostream &OS, StringRef TargetName,
std::vector<RegisterBank> &Banks) {
const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();
OS << "namespace llvm {\n"
<< "namespace " << TargetName << " {\n";
for (const auto &Bank : Banks) {
std::vector<std::vector<const CodeGenRegisterClass *>> RCsGroupedByWord(
(RegisterClassHierarchy.getRegClasses().size() + 31) / 32);
for (const auto &RC : Bank.register_classes())
RCsGroupedByWord[RC->EnumValue / 32].push_back(RC);
OS << "const uint32_t " << Bank.getCoverageArrayName() << "[] = {\n";
unsigned LowestIdxInWord = 0;
for (const auto &RCs : RCsGroupedByWord) {
OS << " // " << LowestIdxInWord << "-" << (LowestIdxInWord + 31) << "\n";
for (const auto &RC : RCs) {
std::string QualifiedRegClassID =
(Twine(RC->Namespace) + "::" + RC->getName() + "RegClassID").str();
OS << " (1u << (" << QualifiedRegClassID << " - "
<< LowestIdxInWord << ")) |\n";
}
OS << " 0,\n";
LowestIdxInWord += 32;
}
OS << "};\n";
}
OS << "\n";
for (const auto &Bank : Banks) {
std::string QualifiedBankID =
(TargetName + "::" + Bank.getEnumeratorName()).str();
const CodeGenRegisterClass &RC = *Bank.getRCWithLargestRegsSize();
unsigned Size = RC.RSI.get(DefaultMode).SpillSize;
OS << "RegisterBank " << Bank.getInstanceVarName() << "(/* ID */ "
<< QualifiedBankID << ", /* Name */ \"" << Bank.getName()
<< "\", /* Size */ " << Size << ", "
<< "/* CoveredRegClasses */ " << Bank.getCoverageArrayName()
<< ", /* NumRegClasses */ "
<< RegisterClassHierarchy.getRegClasses().size() << ");\n";
}
OS << "} // end namespace " << TargetName << "\n"
<< "\n";
OS << "RegisterBank *" << TargetName
<< "GenRegisterBankInfo::RegBanks[] = {\n";
for (const auto &Bank : Banks)
OS << " &" << TargetName << "::" << Bank.getInstanceVarName() << ",\n";
OS << "};\n\n";
OS << TargetName << "GenRegisterBankInfo::" << TargetName
<< "GenRegisterBankInfo()\n"
<< " : RegisterBankInfo(RegBanks, " << TargetName
<< "::NumRegisterBanks) {\n"
<< " // Assert that RegBank indices match their ID's\n"
<< "#ifndef NDEBUG\n"
<< " unsigned Index = 0;\n"
<< " for (const auto &RB : RegBanks)\n"
<< " assert(Index++ == RB->getID() && \"Index != ID\");\n"
<< "#endif // NDEBUG\n"
<< "}\n"
<< "} // end namespace llvm\n";
}
void RegisterBankEmitter::run(raw_ostream &OS) {
StringRef TargetName = Target.getName();
const CodeGenRegBank &RegisterClassHierarchy = Target.getRegBank();
std::vector<RegisterBank> Banks;
for (const auto &V : Records.getAllDerivedDefinitions("RegisterBank")) {
SmallPtrSet<const CodeGenRegisterClass *, 8> VisitedRCs;
RegisterBank Bank(*V);
for (const CodeGenRegisterClass *RC :
Bank.getExplicitlySpecifiedRegisterClasses(RegisterClassHierarchy)) {
visitRegisterBankClasses(
RegisterClassHierarchy, RC, "explicit",
[&Bank](const CodeGenRegisterClass *RC, StringRef Kind) {
LLVM_DEBUG(dbgs()
<< "Added " << RC->getName() << "(" << Kind << ")\n");
Bank.addRegisterClass(RC);
},
VisitedRCs);
}
Banks.push_back(Bank);
}
// Warn about ambiguous MIR caused by register bank/class name clashes.
for (const auto &Class : RegisterClassHierarchy.getRegClasses()) {
for (const auto &Bank : Banks) {
if (Bank.getName().lower() == StringRef(Class.getName()).lower()) {
PrintWarning(Bank.getDef().getLoc(), "Register bank names should be "
"distinct from register classes "
"to avoid ambiguous MIR");
PrintNote(Bank.getDef().getLoc(), "RegisterBank was declared here");
PrintNote(Class.getDef()->getLoc(), "RegisterClass was declared here");
}
}
}
emitSourceFileHeader("Register Bank Source Fragments", OS);
OS << "#ifdef GET_REGBANK_DECLARATIONS\n"
<< "#undef GET_REGBANK_DECLARATIONS\n";
emitHeader(OS, TargetName, Banks);
OS << "#endif // GET_REGBANK_DECLARATIONS\n\n"
<< "#ifdef GET_TARGET_REGBANK_CLASS\n"
<< "#undef GET_TARGET_REGBANK_CLASS\n";
emitBaseClassDefinition(OS, TargetName, Banks);
OS << "#endif // GET_TARGET_REGBANK_CLASS\n\n"
<< "#ifdef GET_TARGET_REGBANK_IMPL\n"
<< "#undef GET_TARGET_REGBANK_IMPL\n";
emitBaseClassImplementation(OS, TargetName, Banks);
OS << "#endif // GET_TARGET_REGBANK_IMPL\n";
}
namespace llvm {
void EmitRegisterBank(RecordKeeper &RK, raw_ostream &OS) {
RegisterBankEmitter(RK).run(OS);
}
} // end namespace llvm