xref: /llvm-project/llvm/utils/TableGen/SDNodeInfoEmitter.cpp (revision f4de28a63c81c909df28b6b065fad19e2189c54e)
16aeffcdbSSergei Barannikov //===----------------------------------------------------------------------===//
26aeffcdbSSergei Barannikov //
36aeffcdbSSergei Barannikov // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
46aeffcdbSSergei Barannikov // See https://llvm.org/LICENSE.txt for license information.
56aeffcdbSSergei Barannikov // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
66aeffcdbSSergei Barannikov //
76aeffcdbSSergei Barannikov //===----------------------------------------------------------------------===//
86aeffcdbSSergei Barannikov 
96aeffcdbSSergei Barannikov #include "Basic/SequenceToOffsetTable.h"
106aeffcdbSSergei Barannikov #include "Common/CodeGenDAGPatterns.h" // For SDNodeInfo.
116aeffcdbSSergei Barannikov #include "llvm/Support/CommandLine.h"
126aeffcdbSSergei Barannikov #include "llvm/TableGen/Error.h"
136aeffcdbSSergei Barannikov #include "llvm/TableGen/StringToOffsetTable.h"
146aeffcdbSSergei Barannikov #include "llvm/TableGen/TableGenBackend.h"
156aeffcdbSSergei Barannikov 
166aeffcdbSSergei Barannikov using namespace llvm;
176aeffcdbSSergei Barannikov 
186aeffcdbSSergei Barannikov static cl::OptionCategory SDNodeInfoEmitterCat("Options for -gen-sdnode-info");
196aeffcdbSSergei Barannikov 
206aeffcdbSSergei Barannikov static cl::opt<std::string> TargetSDNodeNamespace(
216aeffcdbSSergei Barannikov     "sdnode-namespace", cl::cat(SDNodeInfoEmitterCat),
226aeffcdbSSergei Barannikov     cl::desc("Specify target SDNode namespace (default=<Target>ISD)"));
236aeffcdbSSergei Barannikov 
246aeffcdbSSergei Barannikov static cl::opt<bool> WarnOnSkippedNodes(
256aeffcdbSSergei Barannikov     "warn-on-skipped-nodes", cl::cat(SDNodeInfoEmitterCat),
266aeffcdbSSergei Barannikov     cl::desc("Explain why a node was skipped (default=true)"), cl::init(true));
276aeffcdbSSergei Barannikov 
286aeffcdbSSergei Barannikov namespace {
296aeffcdbSSergei Barannikov 
306aeffcdbSSergei Barannikov class SDNodeInfoEmitter {
316aeffcdbSSergei Barannikov   const RecordKeeper &RK;
326aeffcdbSSergei Barannikov   const CodeGenTarget Target;
336aeffcdbSSergei Barannikov   std::map<StringRef, SmallVector<SDNodeInfo, 2>> NodesByName;
346aeffcdbSSergei Barannikov 
356aeffcdbSSergei Barannikov public:
366aeffcdbSSergei Barannikov   explicit SDNodeInfoEmitter(const RecordKeeper &RK);
376aeffcdbSSergei Barannikov 
386aeffcdbSSergei Barannikov   void run(raw_ostream &OS) const;
396aeffcdbSSergei Barannikov 
406aeffcdbSSergei Barannikov private:
416aeffcdbSSergei Barannikov   void emitEnum(raw_ostream &OS) const;
426aeffcdbSSergei Barannikov 
436aeffcdbSSergei Barannikov   std::vector<unsigned> emitNodeNames(raw_ostream &OS) const;
446aeffcdbSSergei Barannikov 
456aeffcdbSSergei Barannikov   std::vector<std::pair<unsigned, unsigned>>
466aeffcdbSSergei Barannikov   emitTypeConstraints(raw_ostream &OS) const;
476aeffcdbSSergei Barannikov 
486aeffcdbSSergei Barannikov   void emitDescs(raw_ostream &OS) const;
496aeffcdbSSergei Barannikov };
506aeffcdbSSergei Barannikov 
516aeffcdbSSergei Barannikov } // namespace
526aeffcdbSSergei Barannikov 
536aeffcdbSSergei Barannikov static bool haveCompatibleDescriptions(const SDNodeInfo &N1,
546aeffcdbSSergei Barannikov                                        const SDNodeInfo &N2) {
556aeffcdbSSergei Barannikov   // Number of results/operands must match.
566aeffcdbSSergei Barannikov   if (N1.getNumResults() != N2.getNumResults() ||
576aeffcdbSSergei Barannikov       N1.getNumOperands() != N2.getNumOperands())
586aeffcdbSSergei Barannikov     return false;
596aeffcdbSSergei Barannikov 
606aeffcdbSSergei Barannikov   // Flags must match.
616aeffcdbSSergei Barannikov   if (N1.isStrictFP() != N2.isStrictFP() || N1.getTSFlags() != N2.getTSFlags())
626aeffcdbSSergei Barannikov     return false;
636aeffcdbSSergei Barannikov 
646aeffcdbSSergei Barannikov   // We're only interested in a subset of node properties. Properties like
656aeffcdbSSergei Barannikov   // SDNPAssociative and SDNPCommutative do not impose constraints on nodes,
666aeffcdbSSergei Barannikov   // and sometimes differ between nodes sharing the same enum name.
676aeffcdbSSergei Barannikov   constexpr unsigned PropMask = (1 << SDNPHasChain) | (1 << SDNPOutGlue) |
686aeffcdbSSergei Barannikov                                 (1 << SDNPInGlue) | (1 << SDNPOptInGlue) |
696aeffcdbSSergei Barannikov                                 (1 << SDNPMemOperand) | (1 << SDNPVariadic);
706aeffcdbSSergei Barannikov 
716aeffcdbSSergei Barannikov   return (N1.getProperties() & PropMask) == (N2.getProperties() & PropMask);
726aeffcdbSSergei Barannikov }
736aeffcdbSSergei Barannikov 
746aeffcdbSSergei Barannikov static bool haveCompatibleDescriptions(ArrayRef<SDNodeInfo> Nodes) {
756aeffcdbSSergei Barannikov   const SDNodeInfo &N = Nodes.front();
766aeffcdbSSergei Barannikov   return all_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) {
776aeffcdbSSergei Barannikov     return haveCompatibleDescriptions(Other, N);
786aeffcdbSSergei Barannikov   });
796aeffcdbSSergei Barannikov }
806aeffcdbSSergei Barannikov 
816aeffcdbSSergei Barannikov static void warnOnSkippedNode(const SDNodeInfo &N, const Twine &Reason) {
826aeffcdbSSergei Barannikov   PrintWarning(N.getRecord()->getLoc(), "skipped node: " + Reason);
836aeffcdbSSergei Barannikov }
846aeffcdbSSergei Barannikov 
856aeffcdbSSergei Barannikov SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK)
866aeffcdbSSergei Barannikov     : RK(RK), Target(RK) {
876aeffcdbSSergei Barannikov   const CodeGenHwModes &HwModes = Target.getHwModes();
886aeffcdbSSergei Barannikov 
896aeffcdbSSergei Barannikov   // Figure out target SDNode namespace.
906aeffcdbSSergei Barannikov   if (!TargetSDNodeNamespace.getNumOccurrences())
916aeffcdbSSergei Barannikov     TargetSDNodeNamespace = Target.getName().str() + "ISD";
926aeffcdbSSergei Barannikov 
936aeffcdbSSergei Barannikov   // Filter nodes by the target SDNode namespace and create a mapping
946aeffcdbSSergei Barannikov   // from an enum name to a list of nodes that have that name.
956aeffcdbSSergei Barannikov   // The mapping is usually 1:1, but in rare cases it can be 1:N.
966aeffcdbSSergei Barannikov   for (const Record *R : RK.getAllDerivedDefinitions("SDNode")) {
976aeffcdbSSergei Barannikov     SDNodeInfo Node(R, HwModes);
986aeffcdbSSergei Barannikov     auto [NS, EnumName] = Node.getEnumName().split("::");
996aeffcdbSSergei Barannikov 
1006aeffcdbSSergei Barannikov     if (NS.empty() || EnumName.empty()) {
1016aeffcdbSSergei Barannikov       if (WarnOnSkippedNodes)
1026aeffcdbSSergei Barannikov         warnOnSkippedNode(Node, "invalid enum name");
1036aeffcdbSSergei Barannikov       continue;
1046aeffcdbSSergei Barannikov     }
1056aeffcdbSSergei Barannikov 
1066aeffcdbSSergei Barannikov     if (NS != TargetSDNodeNamespace)
1076aeffcdbSSergei Barannikov       continue;
1086aeffcdbSSergei Barannikov 
1096aeffcdbSSergei Barannikov     NodesByName[EnumName].push_back(std::move(Node));
1106aeffcdbSSergei Barannikov   }
1116aeffcdbSSergei Barannikov 
1126aeffcdbSSergei Barannikov   // Filter out nodes that have different "prototypes" and/or flags.
1136aeffcdbSSergei Barannikov   // Don't look at type constraints though, we will simply skip emitting
1146aeffcdbSSergei Barannikov   // the constraints if they differ.
1156aeffcdbSSergei Barannikov   decltype(NodesByName)::iterator Next;
1166aeffcdbSSergei Barannikov   for (auto I = NodesByName.begin(), E = NodesByName.end(); I != E; I = Next) {
1176aeffcdbSSergei Barannikov     Next = std::next(I);
1186aeffcdbSSergei Barannikov 
1196aeffcdbSSergei Barannikov     if (haveCompatibleDescriptions(I->second))
1206aeffcdbSSergei Barannikov       continue;
1216aeffcdbSSergei Barannikov 
1226aeffcdbSSergei Barannikov     if (WarnOnSkippedNodes)
1236aeffcdbSSergei Barannikov       for (const SDNodeInfo &N : I->second)
1246aeffcdbSSergei Barannikov         warnOnSkippedNode(N, "incompatible description");
1256aeffcdbSSergei Barannikov 
1266aeffcdbSSergei Barannikov     NodesByName.erase(I);
1276aeffcdbSSergei Barannikov   }
1286aeffcdbSSergei Barannikov }
1296aeffcdbSSergei Barannikov 
1306aeffcdbSSergei Barannikov void SDNodeInfoEmitter::emitEnum(raw_ostream &OS) const {
1316aeffcdbSSergei Barannikov   OS << "#ifdef GET_SDNODE_ENUM\n";
1326aeffcdbSSergei Barannikov   OS << "#undef GET_SDNODE_ENUM\n\n";
1336aeffcdbSSergei Barannikov   OS << "namespace llvm::" << TargetSDNodeNamespace << " {\n\n";
1346aeffcdbSSergei Barannikov 
1356aeffcdbSSergei Barannikov   if (!NodesByName.empty()) {
1366aeffcdbSSergei Barannikov     StringRef FirstName = NodesByName.begin()->first;
1376aeffcdbSSergei Barannikov     StringRef LastName = NodesByName.rbegin()->first;
1386aeffcdbSSergei Barannikov 
1396aeffcdbSSergei Barannikov     OS << "enum GenNodeType : unsigned {\n";
1406aeffcdbSSergei Barannikov     OS << "  " << FirstName << " = ISD::BUILTIN_OP_END,\n";
1416aeffcdbSSergei Barannikov 
1426aeffcdbSSergei Barannikov     for (StringRef EnumName : make_first_range(drop_begin(NodesByName)))
1436aeffcdbSSergei Barannikov       OS << "  " << EnumName << ",\n";
1446aeffcdbSSergei Barannikov 
1456aeffcdbSSergei Barannikov     OS << "};\n\n";
1466aeffcdbSSergei Barannikov     OS << "static constexpr unsigned GENERATED_OPCODE_END = " << LastName
1476aeffcdbSSergei Barannikov        << " + 1;\n\n";
1486aeffcdbSSergei Barannikov   } else {
1496aeffcdbSSergei Barannikov     OS << "static constexpr unsigned GENERATED_OPCODE_END = "
1506aeffcdbSSergei Barannikov           "ISD::BUILTIN_OP_END;\n\n";
1516aeffcdbSSergei Barannikov   }
1526aeffcdbSSergei Barannikov 
1536aeffcdbSSergei Barannikov   OS << "} // namespace llvm::" << TargetSDNodeNamespace << "\n\n";
1546aeffcdbSSergei Barannikov   OS << "#endif // GET_SDNODE_ENUM\n\n";
1556aeffcdbSSergei Barannikov }
1566aeffcdbSSergei Barannikov 
1576aeffcdbSSergei Barannikov std::vector<unsigned> SDNodeInfoEmitter::emitNodeNames(raw_ostream &OS) const {
1586aeffcdbSSergei Barannikov   StringToOffsetTable NameTable;
1596aeffcdbSSergei Barannikov 
1606aeffcdbSSergei Barannikov   std::vector<unsigned> NameOffsets;
1616aeffcdbSSergei Barannikov   NameOffsets.reserve(NodesByName.size());
1626aeffcdbSSergei Barannikov 
1636aeffcdbSSergei Barannikov   for (StringRef EnumName : make_first_range(NodesByName)) {
1646aeffcdbSSergei Barannikov     SmallString<64> DebugName;
1656aeffcdbSSergei Barannikov     raw_svector_ostream SS(DebugName);
1666aeffcdbSSergei Barannikov     SS << TargetSDNodeNamespace << "::" << EnumName;
1676aeffcdbSSergei Barannikov     NameOffsets.push_back(NameTable.GetOrAddStringOffset(DebugName));
1686aeffcdbSSergei Barannikov   }
1696aeffcdbSSergei Barannikov 
170*f4de28a6SChandler Carruth   NameTable.EmitStringTableDef(OS, Target.getName() + "SDNodeNames");
1716aeffcdbSSergei Barannikov   OS << '\n';
1726aeffcdbSSergei Barannikov 
1736aeffcdbSSergei Barannikov   return NameOffsets;
1746aeffcdbSSergei Barannikov }
1756aeffcdbSSergei Barannikov 
1766aeffcdbSSergei Barannikov static StringRef getTypeConstraintKindName(SDTypeConstraint::KindTy Kind) {
1776aeffcdbSSergei Barannikov #define CASE(NAME)                                                             \
1786aeffcdbSSergei Barannikov   case SDTypeConstraint::NAME:                                                 \
1796aeffcdbSSergei Barannikov     return #NAME
1806aeffcdbSSergei Barannikov 
1816aeffcdbSSergei Barannikov   switch (Kind) {
1826aeffcdbSSergei Barannikov     CASE(SDTCisVT);
1836aeffcdbSSergei Barannikov     CASE(SDTCisPtrTy);
1846aeffcdbSSergei Barannikov     CASE(SDTCisInt);
1856aeffcdbSSergei Barannikov     CASE(SDTCisFP);
1866aeffcdbSSergei Barannikov     CASE(SDTCisVec);
1876aeffcdbSSergei Barannikov     CASE(SDTCisSameAs);
1886aeffcdbSSergei Barannikov     CASE(SDTCisVTSmallerThanOp);
1896aeffcdbSSergei Barannikov     CASE(SDTCisOpSmallerThanOp);
1906aeffcdbSSergei Barannikov     CASE(SDTCisEltOfVec);
1916aeffcdbSSergei Barannikov     CASE(SDTCisSubVecOfVec);
1926aeffcdbSSergei Barannikov     CASE(SDTCVecEltisVT);
1936aeffcdbSSergei Barannikov     CASE(SDTCisSameNumEltsAs);
1946aeffcdbSSergei Barannikov     CASE(SDTCisSameSizeAs);
1956aeffcdbSSergei Barannikov   }
1966aeffcdbSSergei Barannikov   llvm_unreachable("Unknown constraint kind"); // Make MSVC happy.
1976aeffcdbSSergei Barannikov #undef CASE
1986aeffcdbSSergei Barannikov }
1996aeffcdbSSergei Barannikov 
2006aeffcdbSSergei Barannikov static void emitTypeConstraint(raw_ostream &OS, SDTypeConstraint C) {
2016aeffcdbSSergei Barannikov   unsigned OtherOpNo = 0;
2026aeffcdbSSergei Barannikov   MVT VT;
2036aeffcdbSSergei Barannikov 
2046aeffcdbSSergei Barannikov   switch (C.ConstraintType) {
2056aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisVT:
2066aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCVecEltisVT:
2076aeffcdbSSergei Barannikov     if (C.VVT.isSimple())
2086aeffcdbSSergei Barannikov       VT = C.VVT.getSimple();
2096aeffcdbSSergei Barannikov     break;
2106aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisPtrTy:
2116aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisInt:
2126aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisFP:
2136aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisVec:
2146aeffcdbSSergei Barannikov     break;
2156aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisSameAs:
2166aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisVTSmallerThanOp:
2176aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisOpSmallerThanOp:
2186aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisEltOfVec:
2196aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisSubVecOfVec:
2206aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisSameNumEltsAs:
2216aeffcdbSSergei Barannikov   case SDTypeConstraint::SDTCisSameSizeAs:
2226aeffcdbSSergei Barannikov     OtherOpNo = C.OtherOperandNo;
2236aeffcdbSSergei Barannikov     break;
2246aeffcdbSSergei Barannikov   }
2256aeffcdbSSergei Barannikov 
2266aeffcdbSSergei Barannikov   StringRef KindName = getTypeConstraintKindName(C.ConstraintType);
2276aeffcdbSSergei Barannikov   StringRef VTName = VT.SimpleTy == MVT::INVALID_SIMPLE_VALUE_TYPE
2286aeffcdbSSergei Barannikov                          ? "MVT::INVALID_SIMPLE_VALUE_TYPE"
2296aeffcdbSSergei Barannikov                          : getEnumName(VT.SimpleTy);
2306aeffcdbSSergei Barannikov   OS << formatv("{{{}, {}, {}, {}}", KindName, C.OperandNo, OtherOpNo, VTName);
2316aeffcdbSSergei Barannikov }
2326aeffcdbSSergei Barannikov 
2336aeffcdbSSergei Barannikov std::vector<std::pair<unsigned, unsigned>>
2346aeffcdbSSergei Barannikov SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const {
2356aeffcdbSSergei Barannikov   using ConstraintsVecTy = SmallVector<SDTypeConstraint, 0>;
2366aeffcdbSSergei Barannikov   SequenceToOffsetTable<ConstraintsVecTy> ConstraintTable(
2376aeffcdbSSergei Barannikov       /*Terminator=*/std::nullopt);
2386aeffcdbSSergei Barannikov 
2396aeffcdbSSergei Barannikov   std::vector<std::pair<unsigned, unsigned>> ConstraintOffsetsAndCounts;
2406aeffcdbSSergei Barannikov   ConstraintOffsetsAndCounts.reserve(NodesByName.size());
2416aeffcdbSSergei Barannikov 
2426aeffcdbSSergei Barannikov   SmallVector<StringRef> SkippedNodes;
2436aeffcdbSSergei Barannikov   for (const auto &[EnumName, Nodes] : NodesByName) {
2446aeffcdbSSergei Barannikov     ArrayRef<SDTypeConstraint> Constraints = Nodes.front().getTypeConstraints();
2456aeffcdbSSergei Barannikov 
2466aeffcdbSSergei Barannikov     bool IsAmbiguous = any_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) {
2476aeffcdbSSergei Barannikov       return ArrayRef(Other.getTypeConstraints()) != Constraints;
2486aeffcdbSSergei Barannikov     });
2496aeffcdbSSergei Barannikov 
2506aeffcdbSSergei Barannikov     // If nodes with the same enum name have different constraints,
2516aeffcdbSSergei Barannikov     // treat them as if they had no constraints at all.
2526aeffcdbSSergei Barannikov     if (IsAmbiguous) {
2536aeffcdbSSergei Barannikov       SkippedNodes.push_back(EnumName);
2546aeffcdbSSergei Barannikov       continue;
2556aeffcdbSSergei Barannikov     }
2566aeffcdbSSergei Barannikov 
2576aeffcdbSSergei Barannikov     // Don't add empty sequences to the table. This slightly simplifies
2586aeffcdbSSergei Barannikov     // the implementation and makes the output less confusing if the table
2596aeffcdbSSergei Barannikov     // ends up empty.
2606aeffcdbSSergei Barannikov     if (Constraints.empty())
2616aeffcdbSSergei Barannikov       continue;
2626aeffcdbSSergei Barannikov 
2636aeffcdbSSergei Barannikov     // SequenceToOffsetTable reuses the storage if a sequence matches another
2646aeffcdbSSergei Barannikov     // sequence's *suffix*. It is more likely that we have a matching *prefix*,
2656aeffcdbSSergei Barannikov     // so reverse the order to increase the likelihood of a match.
2666aeffcdbSSergei Barannikov     ConstraintTable.add(ConstraintsVecTy(reverse(Constraints)));
2676aeffcdbSSergei Barannikov   }
2686aeffcdbSSergei Barannikov 
2696aeffcdbSSergei Barannikov   ConstraintTable.layout();
2706aeffcdbSSergei Barannikov 
2716aeffcdbSSergei Barannikov   OS << "static const SDTypeConstraint " << Target.getName()
2726aeffcdbSSergei Barannikov      << "SDTypeConstraints[] = {\n";
2736aeffcdbSSergei Barannikov   ConstraintTable.emit(OS, emitTypeConstraint);
2746aeffcdbSSergei Barannikov   OS << "};\n\n";
2756aeffcdbSSergei Barannikov 
2766aeffcdbSSergei Barannikov   for (const auto &[EnumName, Nodes] : NodesByName) {
2776aeffcdbSSergei Barannikov     ArrayRef<SDTypeConstraint> Constraints = Nodes.front().getTypeConstraints();
2786aeffcdbSSergei Barannikov 
2796aeffcdbSSergei Barannikov     if (Constraints.empty() || is_contained(SkippedNodes, EnumName)) {
2806aeffcdbSSergei Barannikov       ConstraintOffsetsAndCounts.emplace_back(/*Offset=*/0, /*Size=*/0);
2816aeffcdbSSergei Barannikov       continue;
2826aeffcdbSSergei Barannikov     }
2836aeffcdbSSergei Barannikov 
2846aeffcdbSSergei Barannikov     unsigned ConstraintsOffset =
2856aeffcdbSSergei Barannikov         ConstraintTable.get(ConstraintsVecTy(reverse(Constraints)));
2866aeffcdbSSergei Barannikov     ConstraintOffsetsAndCounts.emplace_back(ConstraintsOffset,
2876aeffcdbSSergei Barannikov                                             Constraints.size());
2886aeffcdbSSergei Barannikov   }
2896aeffcdbSSergei Barannikov 
2906aeffcdbSSergei Barannikov   return ConstraintOffsetsAndCounts;
2916aeffcdbSSergei Barannikov }
2926aeffcdbSSergei Barannikov 
2936aeffcdbSSergei Barannikov static void emitDesc(raw_ostream &OS, StringRef EnumName,
2946aeffcdbSSergei Barannikov                      ArrayRef<SDNodeInfo> Nodes, unsigned NameOffset,
2956aeffcdbSSergei Barannikov                      unsigned ConstraintsOffset, unsigned ConstraintCount) {
2966aeffcdbSSergei Barannikov   assert(haveCompatibleDescriptions(Nodes));
2976aeffcdbSSergei Barannikov   const SDNodeInfo &N = Nodes.front();
2986aeffcdbSSergei Barannikov   OS << "    {" << N.getNumResults() << ", " << N.getNumOperands() << ", 0";
2996aeffcdbSSergei Barannikov 
3006aeffcdbSSergei Barannikov   // Emitted properties must be kept in sync with haveCompatibleDescriptions.
3016aeffcdbSSergei Barannikov   unsigned Properties = N.getProperties();
3026aeffcdbSSergei Barannikov   if (Properties & (1 << SDNPHasChain))
3036aeffcdbSSergei Barannikov     OS << "|1<<SDNPHasChain";
3046aeffcdbSSergei Barannikov   if (Properties & (1 << SDNPOutGlue))
3056aeffcdbSSergei Barannikov     OS << "|1<<SDNPOutGlue";
3066aeffcdbSSergei Barannikov   if (Properties & (1 << SDNPInGlue))
3076aeffcdbSSergei Barannikov     OS << "|1<<SDNPInGlue";
3086aeffcdbSSergei Barannikov   if (Properties & (1 << SDNPOptInGlue))
3096aeffcdbSSergei Barannikov     OS << "|1<<SDNPOptInGlue";
3106aeffcdbSSergei Barannikov   if (Properties & (1 << SDNPVariadic))
3116aeffcdbSSergei Barannikov     OS << "|1<<SDNPVariadic";
3126aeffcdbSSergei Barannikov   if (Properties & (1 << SDNPMemOperand))
3136aeffcdbSSergei Barannikov     OS << "|1<<SDNPMemOperand";
3146aeffcdbSSergei Barannikov 
3156aeffcdbSSergei Barannikov   OS << ", 0";
3166aeffcdbSSergei Barannikov   if (N.isStrictFP())
3176aeffcdbSSergei Barannikov     OS << "|1<<SDNFIsStrictFP";
3186aeffcdbSSergei Barannikov 
3196aeffcdbSSergei Barannikov   OS << formatv(", {}, {}, {}, {}}, // {}\n", N.getTSFlags(), NameOffset,
3206aeffcdbSSergei Barannikov                 ConstraintsOffset, ConstraintCount, EnumName);
3216aeffcdbSSergei Barannikov }
3226aeffcdbSSergei Barannikov 
3236aeffcdbSSergei Barannikov void SDNodeInfoEmitter::emitDescs(raw_ostream &OS) const {
3246aeffcdbSSergei Barannikov   StringRef TargetName = Target.getName();
3256aeffcdbSSergei Barannikov 
3266aeffcdbSSergei Barannikov   OS << "#ifdef GET_SDNODE_DESC\n";
3276aeffcdbSSergei Barannikov   OS << "#undef GET_SDNODE_DESC\n\n";
3286aeffcdbSSergei Barannikov   OS << "namespace llvm {\n";
3296aeffcdbSSergei Barannikov 
3306aeffcdbSSergei Barannikov   std::vector<unsigned> NameOffsets = emitNodeNames(OS);
3316aeffcdbSSergei Barannikov   std::vector<std::pair<unsigned, unsigned>> ConstraintOffsetsAndCounts =
3326aeffcdbSSergei Barannikov       emitTypeConstraints(OS);
3336aeffcdbSSergei Barannikov 
3346aeffcdbSSergei Barannikov   OS << "static const SDNodeDesc " << TargetName << "SDNodeDescs[] = {\n";
3356aeffcdbSSergei Barannikov 
3366aeffcdbSSergei Barannikov   for (const auto &[NameAndNodes, NameOffset, ConstraintOffsetAndCount] :
3376aeffcdbSSergei Barannikov        zip_equal(NodesByName, NameOffsets, ConstraintOffsetsAndCounts))
3386aeffcdbSSergei Barannikov     emitDesc(OS, NameAndNodes.first, NameAndNodes.second, NameOffset,
3396aeffcdbSSergei Barannikov              ConstraintOffsetAndCount.first, ConstraintOffsetAndCount.second);
3406aeffcdbSSergei Barannikov 
3416aeffcdbSSergei Barannikov   OS << "};\n\n";
3426aeffcdbSSergei Barannikov 
3436aeffcdbSSergei Barannikov   OS << formatv("static const SDNodeInfo {0}GenSDNodeInfo(\n"
3446aeffcdbSSergei Barannikov                 "    /*NumOpcodes=*/{1}, {0}SDNodeDescs,\n"
3456aeffcdbSSergei Barannikov                 "    {0}SDNodeNames, {0}SDTypeConstraints);\n\n",
3466aeffcdbSSergei Barannikov                 TargetName, NodesByName.size());
3476aeffcdbSSergei Barannikov 
3486aeffcdbSSergei Barannikov   OS << "} // namespace llvm\n\n";
3496aeffcdbSSergei Barannikov   OS << "#endif // GET_SDNODE_DESC\n\n";
3506aeffcdbSSergei Barannikov }
3516aeffcdbSSergei Barannikov 
3526aeffcdbSSergei Barannikov void SDNodeInfoEmitter::run(raw_ostream &OS) const {
3536aeffcdbSSergei Barannikov   emitSourceFileHeader("Target SDNode descriptions", OS, RK);
3546aeffcdbSSergei Barannikov   emitEnum(OS);
3556aeffcdbSSergei Barannikov   emitDescs(OS);
3566aeffcdbSSergei Barannikov }
3576aeffcdbSSergei Barannikov 
3586aeffcdbSSergei Barannikov static TableGen::Emitter::OptClass<SDNodeInfoEmitter>
3596aeffcdbSSergei Barannikov     X("gen-sd-node-info", "Generate target SDNode descriptions");
360