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