Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/contrib/llvm-project/llvm/utils/TableGen/SDNodeInfoEmitter.cpp
213765 views
1
//===----------------------------------------------------------------------===//
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
#include "Basic/SequenceToOffsetTable.h"
10
#include "Common/CodeGenDAGPatterns.h" // For SDNodeInfo.
11
#include "llvm/Support/CommandLine.h"
12
#include "llvm/Support/FormatVariadic.h"
13
#include "llvm/TableGen/Error.h"
14
#include "llvm/TableGen/StringToOffsetTable.h"
15
#include "llvm/TableGen/TableGenBackend.h"
16
17
using namespace llvm;
18
19
static cl::OptionCategory SDNodeInfoEmitterCat("Options for -gen-sdnode-info");
20
21
static cl::opt<std::string> TargetSDNodeNamespace(
22
"sdnode-namespace", cl::cat(SDNodeInfoEmitterCat),
23
cl::desc("Specify target SDNode namespace (default=<Target>ISD)"));
24
25
static cl::opt<bool> WarnOnSkippedNodes(
26
"warn-on-skipped-nodes", cl::cat(SDNodeInfoEmitterCat),
27
cl::desc("Explain why a node was skipped (default=true)"), cl::init(true));
28
29
namespace {
30
31
class SDNodeInfoEmitter {
32
const RecordKeeper &RK;
33
const CodeGenTarget Target;
34
std::map<StringRef, SmallVector<SDNodeInfo, 2>> NodesByName;
35
36
public:
37
explicit SDNodeInfoEmitter(const RecordKeeper &RK);
38
39
void run(raw_ostream &OS) const;
40
41
private:
42
void emitEnum(raw_ostream &OS) const;
43
44
std::vector<unsigned> emitNodeNames(raw_ostream &OS) const;
45
46
std::vector<std::pair<unsigned, unsigned>>
47
emitTypeConstraints(raw_ostream &OS) const;
48
49
void emitDescs(raw_ostream &OS) const;
50
};
51
52
} // namespace
53
54
static bool haveCompatibleDescriptions(const SDNodeInfo &N1,
55
const SDNodeInfo &N2) {
56
// Number of results/operands must match.
57
if (N1.getNumResults() != N2.getNumResults() ||
58
N1.getNumOperands() != N2.getNumOperands())
59
return false;
60
61
// Flags must match.
62
if (N1.isStrictFP() != N2.isStrictFP() || N1.getTSFlags() != N2.getTSFlags())
63
return false;
64
65
// We're only interested in a subset of node properties. Properties like
66
// SDNPAssociative and SDNPCommutative do not impose constraints on nodes,
67
// and sometimes differ between nodes sharing the same enum name.
68
constexpr unsigned PropMask = (1 << SDNPHasChain) | (1 << SDNPOutGlue) |
69
(1 << SDNPInGlue) | (1 << SDNPOptInGlue) |
70
(1 << SDNPMemOperand) | (1 << SDNPVariadic);
71
72
return (N1.getProperties() & PropMask) == (N2.getProperties() & PropMask);
73
}
74
75
static bool haveCompatibleDescriptions(ArrayRef<SDNodeInfo> Nodes) {
76
const SDNodeInfo &N = Nodes.front();
77
return all_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) {
78
return haveCompatibleDescriptions(Other, N);
79
});
80
}
81
82
static void warnOnSkippedNode(const SDNodeInfo &N, const Twine &Reason) {
83
PrintWarning(N.getRecord()->getLoc(), "skipped node: " + Reason);
84
}
85
86
SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK)
87
: RK(RK), Target(RK) {
88
const CodeGenHwModes &HwModes = Target.getHwModes();
89
90
// Figure out target SDNode namespace.
91
if (!TargetSDNodeNamespace.getNumOccurrences())
92
TargetSDNodeNamespace = Target.getName().str() + "ISD";
93
94
// Filter nodes by the target SDNode namespace and create a mapping
95
// from an enum name to a list of nodes that have that name.
96
// The mapping is usually 1:1, but in rare cases it can be 1:N.
97
for (const Record *R : RK.getAllDerivedDefinitions("SDNode")) {
98
SDNodeInfo Node(R, HwModes);
99
auto [NS, EnumName] = Node.getEnumName().split("::");
100
101
if (NS.empty() || EnumName.empty()) {
102
if (WarnOnSkippedNodes)
103
warnOnSkippedNode(Node, "invalid enum name");
104
continue;
105
}
106
107
if (NS != TargetSDNodeNamespace)
108
continue;
109
110
NodesByName[EnumName].push_back(std::move(Node));
111
}
112
113
// Filter out nodes that have different "prototypes" and/or flags.
114
// Don't look at type constraints though, we will simply skip emitting
115
// the constraints if they differ.
116
decltype(NodesByName)::iterator Next;
117
for (auto I = NodesByName.begin(), E = NodesByName.end(); I != E; I = Next) {
118
Next = std::next(I);
119
120
if (haveCompatibleDescriptions(I->second))
121
continue;
122
123
if (WarnOnSkippedNodes)
124
for (const SDNodeInfo &N : I->second)
125
warnOnSkippedNode(N, "incompatible description");
126
127
NodesByName.erase(I);
128
}
129
}
130
131
void SDNodeInfoEmitter::emitEnum(raw_ostream &OS) const {
132
OS << "#ifdef GET_SDNODE_ENUM\n";
133
OS << "#undef GET_SDNODE_ENUM\n\n";
134
OS << "namespace llvm::" << TargetSDNodeNamespace << " {\n\n";
135
136
if (!NodesByName.empty()) {
137
StringRef FirstName = NodesByName.begin()->first;
138
StringRef LastName = NodesByName.rbegin()->first;
139
140
OS << "enum GenNodeType : unsigned {\n";
141
OS << " " << FirstName << " = ISD::BUILTIN_OP_END,\n";
142
143
for (StringRef EnumName : make_first_range(drop_begin(NodesByName)))
144
OS << " " << EnumName << ",\n";
145
146
OS << "};\n\n";
147
OS << "static constexpr unsigned GENERATED_OPCODE_END = " << LastName
148
<< " + 1;\n\n";
149
} else {
150
OS << "static constexpr unsigned GENERATED_OPCODE_END = "
151
"ISD::BUILTIN_OP_END;\n\n";
152
}
153
154
OS << "} // namespace llvm::" << TargetSDNodeNamespace << "\n\n";
155
OS << "#endif // GET_SDNODE_ENUM\n\n";
156
}
157
158
std::vector<unsigned> SDNodeInfoEmitter::emitNodeNames(raw_ostream &OS) const {
159
StringToOffsetTable NameTable;
160
161
std::vector<unsigned> NameOffsets;
162
NameOffsets.reserve(NodesByName.size());
163
164
for (StringRef EnumName : make_first_range(NodesByName)) {
165
SmallString<64> DebugName;
166
raw_svector_ostream SS(DebugName);
167
SS << TargetSDNodeNamespace << "::" << EnumName;
168
NameOffsets.push_back(NameTable.GetOrAddStringOffset(DebugName));
169
}
170
171
NameTable.EmitStringTableDef(OS, Target.getName() + "SDNodeNames");
172
OS << '\n';
173
174
return NameOffsets;
175
}
176
177
static StringRef getTypeConstraintKindName(SDTypeConstraint::KindTy Kind) {
178
#define CASE(NAME) \
179
case SDTypeConstraint::NAME: \
180
return #NAME
181
182
switch (Kind) {
183
CASE(SDTCisVT);
184
CASE(SDTCisPtrTy);
185
CASE(SDTCisInt);
186
CASE(SDTCisFP);
187
CASE(SDTCisVec);
188
CASE(SDTCisSameAs);
189
CASE(SDTCisVTSmallerThanOp);
190
CASE(SDTCisOpSmallerThanOp);
191
CASE(SDTCisEltOfVec);
192
CASE(SDTCisSubVecOfVec);
193
CASE(SDTCVecEltisVT);
194
CASE(SDTCisSameNumEltsAs);
195
CASE(SDTCisSameSizeAs);
196
}
197
llvm_unreachable("Unknown constraint kind"); // Make MSVC happy.
198
#undef CASE
199
}
200
201
static void emitTypeConstraint(raw_ostream &OS, SDTypeConstraint C) {
202
unsigned OtherOpNo = 0;
203
MVT VT;
204
205
switch (C.ConstraintType) {
206
case SDTypeConstraint::SDTCisVT:
207
case SDTypeConstraint::SDTCVecEltisVT:
208
if (C.VVT.isSimple())
209
VT = C.VVT.getSimple();
210
break;
211
case SDTypeConstraint::SDTCisPtrTy:
212
case SDTypeConstraint::SDTCisInt:
213
case SDTypeConstraint::SDTCisFP:
214
case SDTypeConstraint::SDTCisVec:
215
break;
216
case SDTypeConstraint::SDTCisSameAs:
217
case SDTypeConstraint::SDTCisVTSmallerThanOp:
218
case SDTypeConstraint::SDTCisOpSmallerThanOp:
219
case SDTypeConstraint::SDTCisEltOfVec:
220
case SDTypeConstraint::SDTCisSubVecOfVec:
221
case SDTypeConstraint::SDTCisSameNumEltsAs:
222
case SDTypeConstraint::SDTCisSameSizeAs:
223
OtherOpNo = C.OtherOperandNo;
224
break;
225
}
226
227
StringRef KindName = getTypeConstraintKindName(C.ConstraintType);
228
StringRef VTName = VT.SimpleTy == MVT::INVALID_SIMPLE_VALUE_TYPE
229
? "MVT::INVALID_SIMPLE_VALUE_TYPE"
230
: getEnumName(VT.SimpleTy);
231
OS << formatv("{{{}, {}, {}, {}}", KindName, C.OperandNo, OtherOpNo, VTName);
232
}
233
234
std::vector<std::pair<unsigned, unsigned>>
235
SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const {
236
using ConstraintsVecTy = SmallVector<SDTypeConstraint, 0>;
237
SequenceToOffsetTable<ConstraintsVecTy> ConstraintTable(
238
/*Terminator=*/std::nullopt);
239
240
std::vector<std::pair<unsigned, unsigned>> ConstraintOffsetsAndCounts;
241
ConstraintOffsetsAndCounts.reserve(NodesByName.size());
242
243
SmallVector<StringRef> SkippedNodes;
244
for (const auto &[EnumName, Nodes] : NodesByName) {
245
ArrayRef<SDTypeConstraint> Constraints = Nodes.front().getTypeConstraints();
246
247
bool IsAmbiguous = any_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) {
248
return ArrayRef(Other.getTypeConstraints()) != Constraints;
249
});
250
251
// If nodes with the same enum name have different constraints,
252
// treat them as if they had no constraints at all.
253
if (IsAmbiguous) {
254
SkippedNodes.push_back(EnumName);
255
continue;
256
}
257
258
// Don't add empty sequences to the table. This slightly simplifies
259
// the implementation and makes the output less confusing if the table
260
// ends up empty.
261
if (Constraints.empty())
262
continue;
263
264
// SequenceToOffsetTable reuses the storage if a sequence matches another
265
// sequence's *suffix*. It is more likely that we have a matching *prefix*,
266
// so reverse the order to increase the likelihood of a match.
267
ConstraintTable.add(ConstraintsVecTy(reverse(Constraints)));
268
}
269
270
ConstraintTable.layout();
271
272
OS << "static const SDTypeConstraint " << Target.getName()
273
<< "SDTypeConstraints[] = {\n";
274
ConstraintTable.emit(OS, emitTypeConstraint);
275
OS << "};\n\n";
276
277
for (const auto &[EnumName, Nodes] : NodesByName) {
278
ArrayRef<SDTypeConstraint> Constraints = Nodes.front().getTypeConstraints();
279
280
if (Constraints.empty() || is_contained(SkippedNodes, EnumName)) {
281
ConstraintOffsetsAndCounts.emplace_back(/*Offset=*/0, /*Size=*/0);
282
continue;
283
}
284
285
unsigned ConstraintsOffset =
286
ConstraintTable.get(ConstraintsVecTy(reverse(Constraints)));
287
ConstraintOffsetsAndCounts.emplace_back(ConstraintsOffset,
288
Constraints.size());
289
}
290
291
return ConstraintOffsetsAndCounts;
292
}
293
294
static void emitDesc(raw_ostream &OS, StringRef EnumName,
295
ArrayRef<SDNodeInfo> Nodes, unsigned NameOffset,
296
unsigned ConstraintsOffset, unsigned ConstraintCount) {
297
assert(haveCompatibleDescriptions(Nodes));
298
const SDNodeInfo &N = Nodes.front();
299
OS << " {" << N.getNumResults() << ", " << N.getNumOperands() << ", 0";
300
301
// Emitted properties must be kept in sync with haveCompatibleDescriptions.
302
unsigned Properties = N.getProperties();
303
if (Properties & (1 << SDNPHasChain))
304
OS << "|1<<SDNPHasChain";
305
if (Properties & (1 << SDNPOutGlue))
306
OS << "|1<<SDNPOutGlue";
307
if (Properties & (1 << SDNPInGlue))
308
OS << "|1<<SDNPInGlue";
309
if (Properties & (1 << SDNPOptInGlue))
310
OS << "|1<<SDNPOptInGlue";
311
if (Properties & (1 << SDNPVariadic))
312
OS << "|1<<SDNPVariadic";
313
if (Properties & (1 << SDNPMemOperand))
314
OS << "|1<<SDNPMemOperand";
315
316
OS << ", 0";
317
if (N.isStrictFP())
318
OS << "|1<<SDNFIsStrictFP";
319
320
OS << formatv(", {}, {}, {}, {}}, // {}\n", N.getTSFlags(), NameOffset,
321
ConstraintsOffset, ConstraintCount, EnumName);
322
}
323
324
void SDNodeInfoEmitter::emitDescs(raw_ostream &OS) const {
325
StringRef TargetName = Target.getName();
326
327
OS << "#ifdef GET_SDNODE_DESC\n";
328
OS << "#undef GET_SDNODE_DESC\n\n";
329
OS << "namespace llvm {\n";
330
331
std::vector<unsigned> NameOffsets = emitNodeNames(OS);
332
std::vector<std::pair<unsigned, unsigned>> ConstraintOffsetsAndCounts =
333
emitTypeConstraints(OS);
334
335
OS << "static const SDNodeDesc " << TargetName << "SDNodeDescs[] = {\n";
336
337
for (const auto &[NameAndNodes, NameOffset, ConstraintOffsetAndCount] :
338
zip_equal(NodesByName, NameOffsets, ConstraintOffsetsAndCounts))
339
emitDesc(OS, NameAndNodes.first, NameAndNodes.second, NameOffset,
340
ConstraintOffsetAndCount.first, ConstraintOffsetAndCount.second);
341
342
OS << "};\n\n";
343
344
OS << formatv("static const SDNodeInfo {0}GenSDNodeInfo(\n"
345
" /*NumOpcodes=*/{1}, {0}SDNodeDescs,\n"
346
" {0}SDNodeNames, {0}SDTypeConstraints);\n\n",
347
TargetName, NodesByName.size());
348
349
OS << "} // namespace llvm\n\n";
350
OS << "#endif // GET_SDNODE_DESC\n\n";
351
}
352
353
void SDNodeInfoEmitter::run(raw_ostream &OS) const {
354
emitSourceFileHeader("Target SDNode descriptions", OS, RK);
355
emitEnum(OS);
356
emitDescs(OS);
357
}
358
359
static TableGen::Emitter::OptClass<SDNodeInfoEmitter>
360
X("gen-sd-node-info", "Generate target SDNode descriptions");
361
362