xref: /freebsd/contrib/llvm-project/llvm/utils/TableGen/SDNodeInfoEmitter.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
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