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