From 9ec5e4855fadd8e4ebc2e15d6f4b9c4d95dd6db7 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Wed, 15 Jan 2025 06:01:54 +0300 Subject: [PATCH 1/7] [TableGen] Add a backend generating SDNode descriptions This patch adds a simplistic backend that gathers all target-specific SelectionDAG nodes and emits descriptions for most of them. This includes generating node enumeration, node names, and information about node "prototype" that can be used to verify that a node is valid. The patch also extends SDNode by adding target-specific flags, which are also included in the generated tables. Part of #119709, [RFC](https://discourse.llvm.org/t/rfc-tablegen-erating-sdnode-descriptions/83627). --- .../include/llvm/Target/TargetSelectionDAG.td | 2 + .../ambiguous-constraints.td | 73 ++++ llvm/test/TableGen/SDNodeInfoEmitter/basic.td | 85 ++++ .../TableGen/SDNodeInfoEmitter/namespace.td | 62 +++ .../SDNodeInfoEmitter/skipped-nodes.td | 91 +++++ llvm/utils/TableGen/CMakeLists.txt | 1 + .../TableGen/Common/CodeGenDAGPatterns.cpp | 103 +++-- .../TableGen/Common/CodeGenDAGPatterns.h | 42 +- llvm/utils/TableGen/SDNodeInfoEmitter.cpp | 367 ++++++++++++++++++ 9 files changed, 777 insertions(+), 49 deletions(-) create mode 100644 llvm/test/TableGen/SDNodeInfoEmitter/ambiguous-constraints.td create mode 100644 llvm/test/TableGen/SDNodeInfoEmitter/basic.td create mode 100644 llvm/test/TableGen/SDNodeInfoEmitter/namespace.td create mode 100644 llvm/test/TableGen/SDNodeInfoEmitter/skipped-nodes.td create mode 100644 llvm/utils/TableGen/SDNodeInfoEmitter.cpp diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td index bee0a4298c786..cd2ca3a08bd69 100644 --- a/llvm/include/llvm/Target/TargetSelectionDAG.td +++ b/llvm/include/llvm/Target/TargetSelectionDAG.td @@ -353,6 +353,8 @@ class SDNode TSFlags = 0; } // Special TableGen-recognized dag nodes diff --git a/llvm/test/TableGen/SDNodeInfoEmitter/ambiguous-constraints.td b/llvm/test/TableGen/SDNodeInfoEmitter/ambiguous-constraints.td new file mode 100644 index 0000000000000..668464190e6d8 --- /dev/null +++ b/llvm/test/TableGen/SDNodeInfoEmitter/ambiguous-constraints.td @@ -0,0 +1,73 @@ +// RUN: split-file %s %t + +//--- test1.td +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/test1.td | FileCheck %t/test1.td + +include "llvm/Target/Target.td" + +def MyTarget : Target; + +def my_node_a : SDNode<"MyTargetISD::NODE", SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>>; +def my_node_b : SDNode<"MyTargetISD::NODE", SDTypeProfile<1, 0, [SDTCisVT<0, f32>]>>; + +// CHECK: enum GenNodeType : unsigned { +// CHECK-NEXT: NODE = ISD::BUILTIN_OP_END, +// CHECK-NEXT: }; + +// CHECK: static const char MyTargetSDNodeNames[] = +// CHECK-NEXT: "MyTargetISD::NODE\0" +// CHECK-NEXT: "\0"; + +// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = { +// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE} +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = { +// CHECK-NEXT: {1, 0, 0, 0, 0, 0, 0, 0}, // NODE +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo( +// CHECK-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs, +// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); + + +//--- test2.td +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/test2.td | FileCheck %t/test2.td + +include "llvm/Target/Target.td" + +def MyTarget : Target; + +def my_node_1a : SDNode<"MyTargetISD::NODE_1", SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>>; +def my_node_1b : SDNode<"MyTargetISD::NODE_1", SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>>; +def my_node_2a : SDNode<"MyTargetISD::NODE_2", SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>>; +def my_node_2b : SDNode<"MyTargetISD::NODE_2", SDTypeProfile<1, 0, [SDTCisVT<0, untyped>]>>; + +// CHECK: namespace llvm::MyTargetISD { +// CHECK-EMPTY: +// CHECK-NEXT: enum GenNodeType : unsigned { +// CHECK-NEXT: NODE_1 = ISD::BUILTIN_OP_END, +// CHECK-NEXT: NODE_2, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NODE_2 + 1; +// CHECK-EMPTY: +// CHECK-NEXT: } // namespace llvm::MyTargetISD + +// CHECK: static const char MyTargetSDNodeNames[] = +// CHECK-NEXT: "MyTargetISD::NODE_1\0" +// CHECK-NEXT: "MyTargetISD::NODE_2\0" +// CHECK-NEXT: "\0"; + +// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = { +// CHECK-NEXT: /* 0 */ {SDTCisVT, 0, 0, MVT::i32}, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = { +// CHECK-NEXT: {1, 0, 0, 0, 0, 0, 0, 1}, // NODE_1 +// CHECK-NEXT: {1, 0, 0, 0, 0, 20, 0, 0}, // NODE_2 +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo( +// CHECK-NEXT: /*NumOpcodes=*/2, MyTargetSDNodeDescs, +// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); diff --git a/llvm/test/TableGen/SDNodeInfoEmitter/basic.td b/llvm/test/TableGen/SDNodeInfoEmitter/basic.td new file mode 100644 index 0000000000000..7f5085e31e02c --- /dev/null +++ b/llvm/test/TableGen/SDNodeInfoEmitter/basic.td @@ -0,0 +1,85 @@ +// RUN: split-file %s %t + +//--- no-nodes.td +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/no-nodes.td \ +// RUN: | FileCheck %t/no-nodes.td + +include "llvm/Target/Target.td" + +def MyTarget : Target; + +// CHECK: #ifdef GET_SDNODE_ENUM +// CHECK-NEXT: #undef GET_SDNODE_ENUM +// CHECK-EMPTY: +// CHECK-NEXT: namespace llvm::MyTargetISD { +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = ISD::BUILTIN_OP_END; +// CHECK-EMPTY: +// CHECK-NEXT: } // namespace llvm::MyTargetISD +// CHECK-EMPTY: +// CHECK-NEXT: #endif // GET_SDNODE_ENUM +// CHECK-EMPTY: +// CHECK-NEXT: #ifdef GET_SDNODE_DESC +// CHECK-NEXT: #undef GET_SDNODE_DESC +// CHECK-EMPTY: +// CHECK-NEXT: namespace llvm { +// CHECK-EMPTY: +// CHECK-NEXT: #ifdef __GNUC__ +// CHECK-NEXT: #pragma GCC diagnostic push +// CHECK-NEXT: #pragma GCC diagnostic ignored "-Woverlength-strings" +// CHECK-NEXT: #endif +// CHECK-NEXT: static const char MyTargetSDNodeNames[] = +// CHECK-NEXT: "\0"; +// CHECK-NEXT: #ifdef __GNUC__ +// CHECK-NEXT: #pragma GCC diagnostic pop +// CHECK-NEXT: #endif +// CHECK-EMPTY: +// CHECK-NEXT: static const SDTypeConstraint MyTargetSDTypeConstraints[] = { +// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE} +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = { +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo( +// CHECK-NEXT: /*NumOpcodes=*/0, MyTargetSDNodeDescs, +// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); +// CHECK-EMPTY: +// CHECK-NEXT: } // namespace llvm + + +//--- trivial-node.td +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/trivial-node.td \ +// RUN: | FileCheck %t/trivial-node.td + +include "llvm/Target/Target.td" + +def MyTarget : Target; + +def my_noop : SDNode<"MyTargetISD::NOOP", SDTypeProfile<0, 0, []>>; + +// CHECK: namespace llvm::MyTargetISD { +// CHECK-EMPTY: +// CHECK-NEXT: enum GenNodeType : unsigned { +// CHECK-NEXT: NOOP = ISD::BUILTIN_OP_END, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NOOP + 1; +// CHECK-EMPTY: +// CHECK-NEXT: } // namespace llvm::MyTargetISD + +// CHECK: static const char MyTargetSDNodeNames[] = +// CHECK-NEXT: "MyTargetISD::NOOP\0" +// CHECK-NEXT: "\0"; + +// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = { +// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE} +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = { +// CHECK-NEXT: {0, 0, 0, 0, 0, 0, 0, 0}, // NOOP +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo( +// CHECK-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs, +// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); diff --git a/llvm/test/TableGen/SDNodeInfoEmitter/namespace.td b/llvm/test/TableGen/SDNodeInfoEmitter/namespace.td new file mode 100644 index 0000000000000..844c12bd182fc --- /dev/null +++ b/llvm/test/TableGen/SDNodeInfoEmitter/namespace.td @@ -0,0 +1,62 @@ +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %s -sdnode-namespace=EmptyISD \ +// RUN: | FileCheck %s -check-prefix=EMPTY + +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %s \ +// RUN: | FileCheck %s --check-prefixes=COMMON,TARGET -DNS=MyTargetISD +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %s -sdnode-namespace=MyCustomISD \ +// RUN: | FileCheck %s -check-prefixes=COMMON,CUSTOM -DNS=MyCustomISD + +include "llvm/Target/Target.td" + +def MyTarget : Target; + +def node_1 : SDNode<"MyTargetISD::NODE", SDTypeProfile<1, 0, [SDTCisVT<0, i1>]>>; +def node_2 : SDNode<"MyCustomISD::NODE", SDTypeProfile<0, 1, [SDTCisVT<0, i2>]>>; + +// EMPTY: namespace llvm::EmptyISD { +// EMPTY-EMPTY: +// EMPTY-NEXT: static constexpr unsigned GENERATED_OPCODE_END = ISD::BUILTIN_OP_END; +// EMPTY-EMPTY: +// EMPTY-NEXT: } // namespace llvm::EmptyISD + +// EMPTY: static const char MyTargetSDNodeNames[] = +// EMPTY-NEXT: "\0"; + +// EMPTY: static const SDTypeConstraint MyTargetSDTypeConstraints[] = { +// EMPTY-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE} +// EMPTY-NEXT: }; +// EMPTY-EMPTY: +// EMPTY-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = { +// EMPTY-NEXT: }; +// EMPTY-EMPTY: +// EMPTY-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo( +// EMPTY-NEXT: /*NumOpcodes=*/0, MyTargetSDNodeDescs, +// EMPTY-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); + +// COMMON: namespace llvm::[[NS]] { +// COMMON-EMPTY: +// COMMON-NEXT: enum GenNodeType : unsigned { +// COMMON-NEXT: NODE = ISD::BUILTIN_OP_END, +// COMMON-NEXT: }; +// COMMON-EMPTY: +// COMMON-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NODE + 1; +// COMMON-EMPTY: +// COMMON-NEXT: } // namespace llvm::[[NS]] + +// COMMON: static const char MyTargetSDNodeNames[] = +// COMMON-NEXT: "[[NS]]::NODE\0" +// COMMON-NEXT: "\0"; + +// COMMON: static const SDTypeConstraint MyTargetSDTypeConstraints[] = { +// TARGET-NEXT: /* 0 */ {SDTCisVT, 0, 0, MVT::i1}, +// CUSTOM-NEXT: /* 0 */ {SDTCisVT, 0, 0, MVT::i2}, +// COMMON-NEXT: }; +// COMMON-EMPTY: +// COMMON-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = { +// TARGET-NEXT: {1, 0, 0, 0, 0, 0, 0, 1}, // NODE +// CUSTOM-NEXT: {0, 1, 0, 0, 0, 0, 0, 1}, // NODE +// COMMON-NEXT: }; +// COMMON-EMPTY: +// COMMON-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo( +// COMMON-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs, +// COMMON-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); diff --git a/llvm/test/TableGen/SDNodeInfoEmitter/skipped-nodes.td b/llvm/test/TableGen/SDNodeInfoEmitter/skipped-nodes.td new file mode 100644 index 0000000000000..ed278f262ca8f --- /dev/null +++ b/llvm/test/TableGen/SDNodeInfoEmitter/skipped-nodes.td @@ -0,0 +1,91 @@ +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %s 2> %t.warn | FileCheck %s +// RUN: FileCheck --check-prefix=WARN --implicit-check-not=warning %s < %t.warn + +// RUN: llvm-tblgen -gen-sd-node-info -warn-on-skipped-nodes=false \ +// RUN: -I %p/../../../include %s 2> %t.nowarn | FileCheck %s +// RUN: not test -s %t.nowarn + +include "llvm/Target/Target.td" + +def MyTarget : Target; + +// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name +def bad_name_1 : SDNode<"", SDTypeProfile<0, 0, []>>; + +// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name +def bad_name_2 : SDNode<"NODE", SDTypeProfile<0, 0, []>>; + +// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name +def bad_name_3 : SDNode<"MyTargetISD::", SDTypeProfile<0, 0, []>>; + +// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name +def bad_name_4 : SDNode<"MyISD::", SDTypeProfile<0, 0, []>>; + +// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name +def bad_name_5 : SDNode<"::NODE", SDTypeProfile<0, 0, []>>; + + +// Standard namespace. +def silent_1 : SDNode<"ISD::SILENT", SDTypeProfile<0, 0, []>>; + +// Different namespace. +def silent_2 : SDNode<"MyISD::SILENT", SDTypeProfile<0, 0, []>>; + + +// Different number of results. +// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description +// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description +def node_1a : SDNode<"MyTargetISD::NODE_1", SDTypeProfile<0, 0, []>>; +def node_1b : SDNode<"MyTargetISD::NODE_1", SDTypeProfile<1, 0, []>>; + +// Different number of operands. +// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description +// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description +def node_2a : SDNode<"MyTargetISD::NODE_2", SDTypeProfile<0, 0, []>>; +def node_2b : SDNode<"MyTargetISD::NODE_2", SDTypeProfile<0, 1, []>>; + +// Different value of IsStrictFP. +// WARN: [[#@LINE+3]]:5: warning: skipped node: incompatible description +// WARN: [[#@LINE+3]]:5: warning: skipped node: incompatible description +let IsStrictFP = true in +def node_3a : SDNode<"MyTargetISD::NODE_3", SDTypeProfile<0, 0, []>>; +def node_3b : SDNode<"MyTargetISD::NODE_3", SDTypeProfile<0, 0, []>>; + +// Different value of TSFlags. +// WARN: [[#@LINE+3]]:5: warning: skipped node: incompatible description +// WARN: [[#@LINE+3]]:5: warning: skipped node: incompatible description +let TSFlags = 1 in +def node_4a : SDNode<"MyTargetISD::NODE_4", SDTypeProfile<0, 0, []>>; +def node_4b : SDNode<"MyTargetISD::NODE_4", SDTypeProfile<0, 0, []>>; + +// Different properties. +// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description +// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description +def node_5a : SDNode<"MyTargetISD::NODE_5", SDTypeProfile<0, 0, []>>; +def node_5b : SDNode<"MyTargetISD::NODE_5", SDTypeProfile<0, 0, []>, [SDNPHasChain]>; + + +// CHECK: enum GenNodeType : unsigned { +// CHECK-NEXT: COMPAT = ISD::BUILTIN_OP_END, +// CHECK-NEXT: }; + +// CHECK: static const char MyTargetSDNodeNames[] = +// CHECK-NEXT: "MyTargetISD::COMPAT\0" +// CHECK-NEXT: "\0"; + +// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = { +// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE} +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = { +// CHECK-NEXT: {1, -1, 0, 0, 0, 0, 0, 0}, // COMPAT +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo( +// CHECK-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs, +// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); + +def compat_a : SDNode<"MyTargetISD::COMPAT", SDTypeProfile<1, -1, []>>; +def compat_b : SDNode<"MyTargetISD::COMPAT", SDTypeProfile<1, -1, [SDTCisVT<0, untyped>]>>; +def compat_c : SDNode<"MyTargetISD::COMPAT", SDTypeProfile<1, -1, [SDTCisVT<0, untyped>]>, + [SDNPCommutative, SDNPAssociative, SDNPMayStore, SDNPMayLoad, SDNPSideEffect]>; diff --git a/llvm/utils/TableGen/CMakeLists.txt b/llvm/utils/TableGen/CMakeLists.txt index 96a74c6fd89f7..67291214c14e6 100644 --- a/llvm/utils/TableGen/CMakeLists.txt +++ b/llvm/utils/TableGen/CMakeLists.txt @@ -60,6 +60,7 @@ add_tablegen(llvm-tblgen LLVM PseudoLoweringEmitter.cpp RegisterBankEmitter.cpp RegisterInfoEmitter.cpp + SDNodeInfoEmitter.cpp SearchableTableEmitter.cpp SubtargetEmitter.cpp WebAssemblyDisassemblerEmitter.cpp diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp index 1a61d32b4869a..6629baa6e071e 100644 --- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp @@ -1537,21 +1537,19 @@ SDTypeConstraint::SDTypeConstraint(const Record *R, const CodeGenHwModes &CGH) { ConstraintType = SDTCisVec; } else if (R->isSubClassOf("SDTCisSameAs")) { ConstraintType = SDTCisSameAs; - x.SDTCisSameAs_Info.OtherOperandNum = R->getValueAsInt("OtherOperandNum"); + OtherOperandNo = R->getValueAsInt("OtherOperandNum"); } else if (R->isSubClassOf("SDTCisVTSmallerThanOp")) { ConstraintType = SDTCisVTSmallerThanOp; - x.SDTCisVTSmallerThanOp_Info.OtherOperandNum = - R->getValueAsInt("OtherOperandNum"); + OtherOperandNo = R->getValueAsInt("OtherOperandNum"); } else if (R->isSubClassOf("SDTCisOpSmallerThanOp")) { ConstraintType = SDTCisOpSmallerThanOp; - x.SDTCisOpSmallerThanOp_Info.BigOperandNum = - R->getValueAsInt("BigOperandNum"); + OtherOperandNo = R->getValueAsInt("BigOperandNum"); } else if (R->isSubClassOf("SDTCisEltOfVec")) { ConstraintType = SDTCisEltOfVec; - x.SDTCisEltOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum"); + OtherOperandNo = R->getValueAsInt("OtherOpNum"); } else if (R->isSubClassOf("SDTCisSubVecOfVec")) { ConstraintType = SDTCisSubVecOfVec; - x.SDTCisSubVecOfVec_Info.OtherOperandNum = R->getValueAsInt("OtherOpNum"); + OtherOperandNo = R->getValueAsInt("OtherOpNum"); } else if (R->isSubClassOf("SDTCVecEltisVT")) { ConstraintType = SDTCVecEltisVT; VVT = getValueTypeByHwMode(R->getValueAsDef("VT"), CGH); @@ -1566,12 +1564,10 @@ SDTypeConstraint::SDTypeConstraint(const Record *R, const CodeGenHwModes &CGH) { } } else if (R->isSubClassOf("SDTCisSameNumEltsAs")) { ConstraintType = SDTCisSameNumEltsAs; - x.SDTCisSameNumEltsAs_Info.OtherOperandNum = - R->getValueAsInt("OtherOperandNum"); + OtherOperandNo = R->getValueAsInt("OtherOperandNum"); } else if (R->isSubClassOf("SDTCisSameSizeAs")) { ConstraintType = SDTCisSameSizeAs; - x.SDTCisSameSizeAs_Info.OtherOperandNum = - R->getValueAsInt("OtherOperandNum"); + OtherOperandNo = R->getValueAsInt("OtherOperandNum"); } else { PrintFatalError(R->getLoc(), "Unrecognized SDTypeConstraint '" + R->getName() + "'!\n"); @@ -1632,7 +1628,7 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode &N, case SDTCisSameAs: { unsigned OResNo = 0; TreePatternNode &OtherNode = - getOperandNum(x.SDTCisSameAs_Info.OtherOperandNum, N, NodeInfo, OResNo); + getOperandNum(OtherOperandNo, N, NodeInfo, OResNo); return (int)NodeToApply.UpdateNodeType(ResNo, OtherNode.getExtType(OResNo), TP) | (int)OtherNode.UpdateNodeType(OResNo, NodeToApply.getExtType(ResNo), @@ -1654,23 +1650,23 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode &N, TypeSetByHwMode TypeListTmp(VVT); unsigned OResNo = 0; - TreePatternNode &OtherNode = getOperandNum( - x.SDTCisVTSmallerThanOp_Info.OtherOperandNum, N, NodeInfo, OResNo); + TreePatternNode &OtherNode = + getOperandNum(OtherOperandNo, N, NodeInfo, OResNo); return TI.EnforceSmallerThan(TypeListTmp, OtherNode.getExtType(OResNo), /*SmallIsVT*/ true); } case SDTCisOpSmallerThanOp: { unsigned BResNo = 0; - TreePatternNode &BigOperand = getOperandNum( - x.SDTCisOpSmallerThanOp_Info.BigOperandNum, N, NodeInfo, BResNo); + TreePatternNode &BigOperand = + getOperandNum(OtherOperandNo, N, NodeInfo, BResNo); return TI.EnforceSmallerThan(NodeToApply.getExtType(ResNo), BigOperand.getExtType(BResNo)); } case SDTCisEltOfVec: { unsigned VResNo = 0; - TreePatternNode &VecOperand = getOperandNum( - x.SDTCisEltOfVec_Info.OtherOperandNum, N, NodeInfo, VResNo); + TreePatternNode &VecOperand = + getOperandNum(OtherOperandNo, N, NodeInfo, VResNo); // Filter vector types out of VecOperand that don't have the right element // type. return TI.EnforceVectorEltTypeIs(VecOperand.getExtType(VResNo), @@ -1678,8 +1674,8 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode &N, } case SDTCisSubVecOfVec: { unsigned VResNo = 0; - TreePatternNode &BigVecOperand = getOperandNum( - x.SDTCisSubVecOfVec_Info.OtherOperandNum, N, NodeInfo, VResNo); + TreePatternNode &BigVecOperand = + getOperandNum(OtherOperandNo, N, NodeInfo, VResNo); // Filter vector types out of BigVecOperand that don't have the // right subvector type. @@ -1691,15 +1687,15 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode &N, } case SDTCisSameNumEltsAs: { unsigned OResNo = 0; - TreePatternNode &OtherNode = getOperandNum( - x.SDTCisSameNumEltsAs_Info.OtherOperandNum, N, NodeInfo, OResNo); + TreePatternNode &OtherNode = + getOperandNum(OtherOperandNo, N, NodeInfo, OResNo); return TI.EnforceSameNumElts(OtherNode.getExtType(OResNo), NodeToApply.getExtType(ResNo)); } case SDTCisSameSizeAs: { unsigned OResNo = 0; - TreePatternNode &OtherNode = getOperandNum( - x.SDTCisSameSizeAs_Info.OtherOperandNum, N, NodeInfo, OResNo); + TreePatternNode &OtherNode = + getOperandNum(OtherOperandNo, N, NodeInfo, OResNo); return TI.EnforceSameSize(OtherNode.getExtType(OResNo), NodeToApply.getExtType(ResNo)); } @@ -1707,6 +1703,58 @@ bool SDTypeConstraint::ApplyTypeConstraint(TreePatternNode &N, llvm_unreachable("Invalid ConstraintType!"); } +bool llvm::operator==(const SDTypeConstraint &LHS, + const SDTypeConstraint &RHS) { + if (std::tie(LHS.OperandNo, LHS.ConstraintType) != + std::tie(RHS.OperandNo, RHS.ConstraintType)) + return false; + switch (LHS.ConstraintType) { + case SDTypeConstraint::SDTCisVT: + case SDTypeConstraint::SDTCVecEltisVT: + return LHS.VVT == RHS.VVT; + case SDTypeConstraint::SDTCisPtrTy: + case SDTypeConstraint::SDTCisInt: + case SDTypeConstraint::SDTCisFP: + case SDTypeConstraint::SDTCisVec: + break; + case SDTypeConstraint::SDTCisSameAs: + case SDTypeConstraint::SDTCisVTSmallerThanOp: + case SDTypeConstraint::SDTCisOpSmallerThanOp: + case SDTypeConstraint::SDTCisEltOfVec: + case SDTypeConstraint::SDTCisSubVecOfVec: + case SDTypeConstraint::SDTCisSameNumEltsAs: + case SDTypeConstraint::SDTCisSameSizeAs: + return LHS.OtherOperandNo == RHS.OtherOperandNo; + } + return true; +} + +bool llvm::operator<(const SDTypeConstraint &LHS, const SDTypeConstraint &RHS) { + if (std::tie(LHS.OperandNo, LHS.ConstraintType) != + std::tie(RHS.OperandNo, RHS.ConstraintType)) + return std::tie(LHS.OperandNo, LHS.ConstraintType) < + std::tie(RHS.OperandNo, RHS.ConstraintType); + switch (LHS.ConstraintType) { + case SDTypeConstraint::SDTCisVT: + case SDTypeConstraint::SDTCVecEltisVT: + return LHS.VVT < RHS.VVT; + case SDTypeConstraint::SDTCisPtrTy: + case SDTypeConstraint::SDTCisInt: + case SDTypeConstraint::SDTCisFP: + case SDTypeConstraint::SDTCisVec: + break; + case SDTypeConstraint::SDTCisSameAs: + case SDTypeConstraint::SDTCisVTSmallerThanOp: + case SDTypeConstraint::SDTCisOpSmallerThanOp: + case SDTypeConstraint::SDTCisEltOfVec: + case SDTypeConstraint::SDTCisSubVecOfVec: + case SDTypeConstraint::SDTCisSameNumEltsAs: + case SDTypeConstraint::SDTCisSameSizeAs: + return LHS.OtherOperandNo < RHS.OtherOperandNo; + } + return false; +} + // Update the node type to match an instruction operand or result as specified // in the ins or outs lists on the instruction definition. Return true if the // type was actually changed. @@ -1797,6 +1845,13 @@ SDNodeInfo::SDNodeInfo(const Record *R, const CodeGenHwModes &CGH) : Def(R) { // Parse the properties. Properties = parseSDPatternOperatorProperties(R); + IsStrictFP = R->getValueAsBit("IsStrictFP"); + + std::optional MaybeTSFlags = + R->getValueAsBitsInit("TSFlags")->convertInitializerToInt(); + if (!MaybeTSFlags) + PrintFatalError(R->getLoc(), "Invalid TSFlags"); + TSFlags = *MaybeTSFlags; // Parse the type constraints. for (const Record *R : TypeProfile->getValueAsListOfDefs("Constraints")) diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h index f8c3917293825..5735a6ccbcda9 100644 --- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h @@ -354,10 +354,11 @@ typedef StringSet<> MultipleUseVarSet; /// SDTypeConstraint - This is a discriminated union of constraints, /// corresponding to the SDTypeConstraint tablegen class in Target.td. struct SDTypeConstraint { + SDTypeConstraint() = default; SDTypeConstraint(const Record *R, const CodeGenHwModes &CGH); unsigned OperandNo; // The operand # this constraint applies to. - enum { + enum KindTy { SDTCisVT, SDTCisPtrTy, SDTCisInt, @@ -373,29 +374,7 @@ struct SDTypeConstraint { SDTCisSameSizeAs } ConstraintType; - union { // The discriminated union. - struct { - unsigned OtherOperandNum; - } SDTCisSameAs_Info; - struct { - unsigned OtherOperandNum; - } SDTCisVTSmallerThanOp_Info; - struct { - unsigned BigOperandNum; - } SDTCisOpSmallerThanOp_Info; - struct { - unsigned OtherOperandNum; - } SDTCisEltOfVec_Info; - struct { - unsigned OtherOperandNum; - } SDTCisSubVecOfVec_Info; - struct { - unsigned OtherOperandNum; - } SDTCisSameNumEltsAs_Info; - struct { - unsigned OtherOperandNum; - } SDTCisSameSizeAs_Info; - } x; + unsigned OtherOperandNo; // The VT for SDTCisVT and SDTCVecEltisVT. // Must not be in the union because it has a non-trivial destructor. @@ -407,6 +386,11 @@ struct SDTypeConstraint { /// is flagged. bool ApplyTypeConstraint(TreePatternNode &N, const SDNodeInfo &NodeInfo, TreePattern &TP) const; + + friend bool operator==(const SDTypeConstraint &LHS, + const SDTypeConstraint &RHS); + friend bool operator<(const SDTypeConstraint &LHS, + const SDTypeConstraint &RHS); }; /// ScopedName - A name of a node associated with a "scope" that indicates @@ -438,9 +422,11 @@ class SDNodeInfo { const Record *Def; StringRef EnumName; StringRef SDClassName; - unsigned Properties; unsigned NumResults; int NumOperands; + unsigned Properties; + bool IsStrictFP; + uint64_t TSFlags; std::vector TypeConstraints; public: @@ -465,10 +451,16 @@ class SDNodeInfo { /// MVT::SimpleValueType. Otherwise, return MVT::Other. MVT::SimpleValueType getKnownType(unsigned ResNo) const; + unsigned getProperties() const { return Properties; } + /// hasProperty - Return true if this node has the specified property. /// bool hasProperty(enum SDNP Prop) const { return Properties & (1 << Prop); } + bool isStrictFP() const { return IsStrictFP; } + + uint64_t getTSFlags() const { return TSFlags; } + /// ApplyTypeConstraints - Given a node in a pattern, apply the type /// constraints for this node to the operands of the node. This returns /// true if it makes a change, false otherwise. If a type contradiction is diff --git a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp new file mode 100644 index 0000000000000..fad23027de720 --- /dev/null +++ b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp @@ -0,0 +1,367 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Basic/SequenceToOffsetTable.h" +#include "Common/CodeGenDAGPatterns.h" // For SDNodeInfo. +#include "llvm/Support/CommandLine.h" +#include "llvm/TableGen/Error.h" +#include "llvm/TableGen/StringToOffsetTable.h" +#include "llvm/TableGen/TableGenBackend.h" + +using namespace llvm; + +static cl::OptionCategory SDNodeInfoEmitterCat("Options for -gen-sdnode-info"); + +static cl::opt TargetSDNodeNamespace( + "sdnode-namespace", cl::cat(SDNodeInfoEmitterCat), + cl::desc("Specify target SDNode namespace (default=ISD)")); + +static cl::opt WarnOnSkippedNodes( + "warn-on-skipped-nodes", cl::cat(SDNodeInfoEmitterCat), + cl::desc("Explain why a node was skipped (default=true)"), cl::init(true)); + +namespace { + +class SDNodeInfoEmitter { + const RecordKeeper &RK; + const CodeGenTarget Target; + std::vector AllNodes; + std::map> TargetNodesByName; + +public: + explicit SDNodeInfoEmitter(const RecordKeeper &RK); + + void run(raw_ostream &OS) const; + +private: + void emitEnum(raw_ostream &OS) const; + + std::vector emitNodeNames(raw_ostream &OS) const; + + std::vector> + emitTypeConstraints(raw_ostream &OS) const; + + void emitDescs(raw_ostream &OS) const; +}; + +} // namespace + +static bool haveCompatibleDescriptions(const SDNodeInfo *N1, + const SDNodeInfo *N2) { + // Number of results/operands must match. + if (N1->getNumResults() != N2->getNumResults() || + N1->getNumOperands() != N2->getNumOperands()) + return false; + + // Flags must match. + if (N1->isStrictFP() != N2->isStrictFP() || + N1->getTSFlags() != N2->getTSFlags()) + return false; + + // We're only interested in a subset of node properties. Properties like + // SDNPAssociative and SDNPCommutative do not impose constraints on nodes, + // and sometimes differ between nodes sharing the same enum name. + constexpr unsigned PropMask = (1 << SDNPHasChain) | (1 << SDNPOutGlue) | + (1 << SDNPInGlue) | (1 << SDNPOptInGlue) | + (1 << SDNPMemOperand) | (1 << SDNPVariadic); + + return (N1->getProperties() & PropMask) == (N2->getProperties() & PropMask); +} + +static bool haveCompatibleDescriptions(ArrayRef Nodes) { + const SDNodeInfo *N = Nodes.front(); + return all_of(drop_begin(Nodes), [&](const SDNodeInfo *Other) { + return haveCompatibleDescriptions(Other, N); + }); +} + +static void warnOnSkippedNode(const SDNodeInfo *N, const Twine &Reason) { + PrintWarning(N->getRecord()->getLoc(), "skipped node: " + Reason); +} + +SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK) + : RK(RK), Target(RK) { + const CodeGenHwModes &HwModes = Target.getHwModes(); + + // Figure out target SDNode namespace. + if (!TargetSDNodeNamespace.getNumOccurrences()) + TargetSDNodeNamespace = Target.getName().str() + "ISD"; + + // Parse all SDNode records. + for (const Record *R : RK.getAllDerivedDefinitions("SDNode")) + AllNodes.emplace_back(R, HwModes); + + // Filter nodes by the target SDNode namespace and create a mapping + // from an enum name to a list of nodes that have that name. + // The mapping is usually 1:1, but in rare cases it can be 1:N. + for (const SDNodeInfo &Node : AllNodes) { + StringRef QualifiedEnumName = Node.getEnumName(); + auto [NS, EnumName] = QualifiedEnumName.split("::"); + + if (NS.empty() || EnumName.empty()) { + if (WarnOnSkippedNodes) + warnOnSkippedNode(&Node, "invalid enum name"); + continue; + } + + if (NS != TargetSDNodeNamespace) + continue; + + TargetNodesByName[EnumName].push_back(&Node); + } + + // Filter out nodes that have different "prototypes" and/or flags. + // Don't look at type constraints though, we will simply skip emitting + // the constraints if they differ. + decltype(TargetNodesByName)::iterator Next; + for (auto I = TargetNodesByName.begin(), E = TargetNodesByName.end(); I != E; + I = Next) { + Next = std::next(I); + + if (haveCompatibleDescriptions(I->second)) + continue; + + if (WarnOnSkippedNodes) + for (const SDNodeInfo *N : I->second) + warnOnSkippedNode(N, "incompatible description"); + + TargetNodesByName.erase(I); + } +} + +void SDNodeInfoEmitter::emitEnum(raw_ostream &OS) const { + OS << "#ifdef GET_SDNODE_ENUM\n"; + OS << "#undef GET_SDNODE_ENUM\n\n"; + OS << "namespace llvm::" << TargetSDNodeNamespace << " {\n\n"; + + if (!TargetNodesByName.empty()) { + StringRef FirstName = TargetNodesByName.begin()->first; + StringRef LastName = TargetNodesByName.rbegin()->first; + + OS << "enum GenNodeType : unsigned {\n"; + OS << " " << FirstName << " = ISD::BUILTIN_OP_END,\n"; + + for (StringRef EnumName : make_first_range(drop_begin(TargetNodesByName))) + OS << " " << EnumName << ",\n"; + + OS << "};\n\n"; + OS << "static constexpr unsigned GENERATED_OPCODE_END = " << LastName + << " + 1;\n\n"; + } else { + OS << "static constexpr unsigned GENERATED_OPCODE_END = " + "ISD::BUILTIN_OP_END;\n\n"; + } + + OS << "} // namespace llvm::" << TargetSDNodeNamespace << "\n\n"; + OS << "#endif // GET_SDNODE_ENUM\n\n"; +} + +std::vector SDNodeInfoEmitter::emitNodeNames(raw_ostream &OS) const { + StringToOffsetTable NameTable; + + std::vector NameOffsets; + NameOffsets.reserve(TargetNodesByName.size()); + + for (StringRef EnumName : make_first_range(TargetNodesByName)) { + SmallString<64> DebugName; + (TargetSDNodeNamespace + "::" + EnumName).toVector(DebugName); + NameOffsets.push_back(NameTable.GetOrAddStringOffset(DebugName)); + } + + NameTable.EmitStringLiteralDef( + OS, "static const char " + Target.getName() + "SDNodeNames[]", + /*Indent=*/""); + OS << "\n"; + + return NameOffsets; +} + +static StringRef getTypeConstraintKindName(SDTypeConstraint::KindTy Kind) { +#define CASE(NAME) \ + case SDTypeConstraint::NAME: \ + return #NAME + + switch (Kind) { + CASE(SDTCisVT); + CASE(SDTCisPtrTy); + CASE(SDTCisInt); + CASE(SDTCisFP); + CASE(SDTCisVec); + CASE(SDTCisSameAs); + CASE(SDTCisVTSmallerThanOp); + CASE(SDTCisOpSmallerThanOp); + CASE(SDTCisEltOfVec); + CASE(SDTCisSubVecOfVec); + CASE(SDTCVecEltisVT); + CASE(SDTCisSameNumEltsAs); + CASE(SDTCisSameSizeAs); + } + llvm_unreachable("Unknown constraint kind"); // Make MSVC happy. +#undef CASE +} + +static void emitTypeConstraint(raw_ostream &OS, SDTypeConstraint C) { + unsigned OtherOpNo = 0; + MVT VT; + + switch (C.ConstraintType) { + case SDTypeConstraint::SDTCisVT: + case SDTypeConstraint::SDTCVecEltisVT: + if (C.VVT.isSimple()) + VT = C.VVT.getSimple(); + break; + case SDTypeConstraint::SDTCisPtrTy: + case SDTypeConstraint::SDTCisInt: + case SDTypeConstraint::SDTCisFP: + case SDTypeConstraint::SDTCisVec: + break; + case SDTypeConstraint::SDTCisSameAs: + case SDTypeConstraint::SDTCisVTSmallerThanOp: + case SDTypeConstraint::SDTCisOpSmallerThanOp: + case SDTypeConstraint::SDTCisEltOfVec: + case SDTypeConstraint::SDTCisSubVecOfVec: + case SDTypeConstraint::SDTCisSameNumEltsAs: + case SDTypeConstraint::SDTCisSameSizeAs: + OtherOpNo = C.OtherOperandNo; + break; + } + + StringRef KindName = getTypeConstraintKindName(C.ConstraintType); + StringRef VTName = VT.SimpleTy == MVT::INVALID_SIMPLE_VALUE_TYPE + ? "MVT::INVALID_SIMPLE_VALUE_TYPE" + : getEnumName(VT.SimpleTy); + OS << formatv("{{{}, {}, {}, {}}", KindName, C.OperandNo, OtherOpNo, VTName); +} + +std::vector> +SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const { + using ConstraintsVecTy = SmallVector; + SequenceToOffsetTable ConstraintTable( + /*Terminator=*/std::nullopt); + + std::vector> ConstraintOffsetsAndCounts; + ConstraintOffsetsAndCounts.reserve(TargetNodesByName.size()); + + SmallVector SkippedNodes; + for (const auto &[EnumName, Nodes] : TargetNodesByName) { + ArrayRef Constraints = Nodes.front()->getTypeConstraints(); + + bool IsAmbiguous = any_of(drop_begin(Nodes), [&](const SDNodeInfo *Other) { + return ArrayRef(Other->getTypeConstraints()) != Constraints; + }); + + // If nodes with the same enum name have different constraints, + // treat them as if they had no constraints at all. + if (IsAmbiguous) { + SkippedNodes.push_back(EnumName); + continue; + } + + // Don't add empty sequences to the table. This slightly simplifies + // the implementation and makes the output less confusing if the table + // ends up empty. + if (Constraints.empty()) + continue; + + // SequenceToOffsetTable reuses the storage if a sequence matches another + // sequence's *suffix*. It is more likely that we have a matching *prefix*, + // so reverse the order to increase the likelihood of a match. + ConstraintTable.add(ConstraintsVecTy(reverse(Constraints))); + } + + ConstraintTable.layout(); + + OS << "static const SDTypeConstraint " << Target.getName() + << "SDTypeConstraints[] = {\n"; + ConstraintTable.emit(OS, emitTypeConstraint); + OS << "};\n\n"; + + for (const auto &[EnumName, Nodes] : TargetNodesByName) { + ArrayRef Constraints = Nodes.front()->getTypeConstraints(); + + if (Constraints.empty() || is_contained(SkippedNodes, EnumName)) { + ConstraintOffsetsAndCounts.emplace_back(/*Offset=*/0, /*Size=*/0); + continue; + } + + unsigned ConstraintsOffset = + ConstraintTable.get(ConstraintsVecTy(reverse(Constraints))); + ConstraintOffsetsAndCounts.emplace_back(ConstraintsOffset, + Constraints.size()); + } + + return ConstraintOffsetsAndCounts; +} + +static void emitDesc(raw_ostream &OS, StringRef EnumName, + ArrayRef Nodes, unsigned NameOffset, + unsigned ConstraintsOffset, unsigned ConstraintCount) { + assert(haveCompatibleDescriptions(Nodes)); + const SDNodeInfo *N = Nodes.front(); + OS << " {" << N->getNumResults() << ", " << N->getNumOperands() << ", 0"; + + // Emitted properties must be kept in sync with haveCompatibleDescriptions. + unsigned Properties = N->getProperties(); + if (Properties & (1 << SDNPHasChain)) + OS << "|1<isStrictFP()) + OS << "|1<getTSFlags(), NameOffset, + ConstraintsOffset, ConstraintCount, EnumName); +} + +void SDNodeInfoEmitter::emitDescs(raw_ostream &OS) const { + StringRef TargetName = Target.getName(); + + OS << "#ifdef GET_SDNODE_DESC\n"; + OS << "#undef GET_SDNODE_DESC\n\n"; + OS << "namespace llvm {\n"; + + std::vector NameOffsets = emitNodeNames(OS); + std::vector> ConstraintOffsetsAndCounts = + emitTypeConstraints(OS); + + OS << "static const SDNodeDesc " << TargetName << "SDNodeDescs[] = {\n"; + + for (const auto &[NameAndNodes, NameOffset, ConstraintOffsetAndCount] : + zip_equal(TargetNodesByName, NameOffsets, ConstraintOffsetsAndCounts)) + emitDesc(OS, NameAndNodes.first, NameAndNodes.second, NameOffset, + ConstraintOffsetAndCount.first, ConstraintOffsetAndCount.second); + + OS << "};\n\n"; + + OS << formatv("static const SDNodeInfo {0}GenSDNodeInfo(\n" + " /*NumOpcodes=*/{1}, {0}SDNodeDescs,\n" + " {0}SDNodeNames, {0}SDTypeConstraints);\n\n", + TargetName, TargetNodesByName.size()); + + OS << "} // namespace llvm\n\n"; + OS << "#endif // GET_SDNODE_DESC\n\n"; +} + +void SDNodeInfoEmitter::run(raw_ostream &OS) const { + emitSourceFileHeader("Target SDNode descriptions", OS, RK); + emitEnum(OS); + emitDescs(OS); +} + +static TableGen::Emitter::OptClass + X("gen-sd-node-info", "Generate target SDNode descriptions"); From b34b6470960e27f09add4cbcb50517ee433e7d32 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Wed, 15 Jan 2025 08:26:19 +0300 Subject: [PATCH 2/7] Add missing check lines to a test --- llvm/test/TableGen/SDNodeInfoEmitter/basic.td | 2 ++ 1 file changed, 2 insertions(+) diff --git a/llvm/test/TableGen/SDNodeInfoEmitter/basic.td b/llvm/test/TableGen/SDNodeInfoEmitter/basic.td index 7f5085e31e02c..dbe6def710689 100644 --- a/llvm/test/TableGen/SDNodeInfoEmitter/basic.td +++ b/llvm/test/TableGen/SDNodeInfoEmitter/basic.td @@ -46,6 +46,8 @@ def MyTarget : Target; // CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); // CHECK-EMPTY: // CHECK-NEXT: } // namespace llvm +// CHECK-EMPTY: +// CHECK-NEXT: #endif // GET_SDNODE_DESC //--- trivial-node.td From 0b27718caaa1ded117375123bc8cdc1d142e5056 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Wed, 15 Jan 2025 08:34:53 +0300 Subject: [PATCH 3/7] Address review comments * Add missing template parameter to ArrayRef * Shrink TSFlags to 32 bits --- llvm/include/llvm/Target/TargetSelectionDAG.td | 2 +- llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp | 3 ++- llvm/utils/TableGen/Common/CodeGenDAGPatterns.h | 4 ++-- llvm/utils/TableGen/SDNodeInfoEmitter.cpp | 6 ++++-- 4 files changed, 9 insertions(+), 6 deletions(-) diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td index cd2ca3a08bd69..7f3c2be90d820 100644 --- a/llvm/include/llvm/Target/TargetSelectionDAG.td +++ b/llvm/include/llvm/Target/TargetSelectionDAG.td @@ -354,7 +354,7 @@ class SDNode TSFlags = 0; + bits<32> TSFlags = 0; } // Special TableGen-recognized dag nodes diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp index 6629baa6e071e..d155da3bed48f 100644 --- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.cpp @@ -1847,10 +1847,11 @@ SDNodeInfo::SDNodeInfo(const Record *R, const CodeGenHwModes &CGH) : Def(R) { Properties = parseSDPatternOperatorProperties(R); IsStrictFP = R->getValueAsBit("IsStrictFP"); - std::optional MaybeTSFlags = + std::optional MaybeTSFlags = R->getValueAsBitsInit("TSFlags")->convertInitializerToInt(); if (!MaybeTSFlags) PrintFatalError(R->getLoc(), "Invalid TSFlags"); + assert(isUInt<32>(*MaybeTSFlags) && "TSFlags bit width out of sync"); TSFlags = *MaybeTSFlags; // Parse the type constraints. diff --git a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h index 5735a6ccbcda9..6a6f1a6ac437c 100644 --- a/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/Common/CodeGenDAGPatterns.h @@ -426,7 +426,7 @@ class SDNodeInfo { int NumOperands; unsigned Properties; bool IsStrictFP; - uint64_t TSFlags; + uint32_t TSFlags; std::vector TypeConstraints; public: @@ -459,7 +459,7 @@ class SDNodeInfo { bool isStrictFP() const { return IsStrictFP; } - uint64_t getTSFlags() const { return TSFlags; } + uint32_t getTSFlags() const { return TSFlags; } /// ApplyTypeConstraints - Given a node in a pattern, apply the type /// constraints for this node to the operands of the node. This returns diff --git a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp index fad23027de720..17b5581004565 100644 --- a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp +++ b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp @@ -249,7 +249,8 @@ SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const { SmallVector SkippedNodes; for (const auto &[EnumName, Nodes] : TargetNodesByName) { - ArrayRef Constraints = Nodes.front()->getTypeConstraints(); + ArrayRef Constraints = + Nodes.front()->getTypeConstraints(); bool IsAmbiguous = any_of(drop_begin(Nodes), [&](const SDNodeInfo *Other) { return ArrayRef(Other->getTypeConstraints()) != Constraints; @@ -282,7 +283,8 @@ SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const { OS << "};\n\n"; for (const auto &[EnumName, Nodes] : TargetNodesByName) { - ArrayRef Constraints = Nodes.front()->getTypeConstraints(); + ArrayRef Constraints = + Nodes.front()->getTypeConstraints(); if (Constraints.empty() || is_contained(SkippedNodes, EnumName)) { ConstraintOffsetsAndCounts.emplace_back(/*Offset=*/0, /*Size=*/0); From 4db8ac318f62590cbfd97e53f4c94c80de12d349 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Wed, 15 Jan 2025 09:32:45 +0300 Subject: [PATCH 4/7] Add a more complex test --- llvm/test/TableGen/SDNodeInfoEmitter/basic.td | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/llvm/test/TableGen/SDNodeInfoEmitter/basic.td b/llvm/test/TableGen/SDNodeInfoEmitter/basic.td index dbe6def710689..5332b4f458dfd 100644 --- a/llvm/test/TableGen/SDNodeInfoEmitter/basic.td +++ b/llvm/test/TableGen/SDNodeInfoEmitter/basic.td @@ -85,3 +85,99 @@ def my_noop : SDNode<"MyTargetISD::NOOP", SDTypeProfile<0, 0, []>>; // CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo( // CHECK-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs, // CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints); + +//--- advanced.td +// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/advanced.td \ +// RUN: | FileCheck %t/advanced.td + +include "llvm/Target/Target.td" + +def MyTarget : Target; + +def my_node_1 : SDNode< + "MyTargetISD::NODE_1", + SDTypeProfile<1, 1, [SDTCisVT<0, i1>, SDTCisVT<1, i2>]>, + [SDNPHasChain] +>; + +let TSFlags = 42 in +def my_node_2 : SDNode< + "MyTargetISD::NODE_2", + SDTypeProfile<3, 1, [ + // Prefix of my_node_3 constraints. + SDTCisVT<0, i1>, + SDTCisPtrTy<1>, + SDTCisInt<2>, + SDTCisFP<3>, + ]>, + [SDNPMayStore, SDNPMayLoad, SDNPSideEffect, + SDNPMemOperand, SDNPVariadic] +>; + +let IsStrictFP = true, TSFlags = 24 in +def my_node_3 : SDNode< + "MyTargetISD::NODE_3", + SDTypeProfile<2, -1, [ + SDTCisVT<0, i1>, + SDTCisPtrTy<1>, + SDTCisInt<2>, + SDTCisFP<3>, + SDTCisVec<4>, + SDTCisSameAs<6, 5>, + SDTCisVTSmallerThanOp<8, 7>, + SDTCisOpSmallerThanOp<10, 9>, + SDTCisEltOfVec<12, 11>, + SDTCisSubVecOfVec<14, 13>, + SDTCVecEltisVT<15, i32>, + SDTCisSameNumEltsAs<17, 16>, + SDTCisSameSizeAs<19, 18>, + ]>, + [SDNPCommutative, SDNPAssociative, SDNPHasChain, + SDNPOutGlue, SDNPInGlue, SDNPOptInGlue] +>; + +// CHECK: namespace llvm::MyTargetISD { +// CHECK-EMPTY: +// CHECK-NEXT: enum GenNodeType : unsigned { +// CHECK-NEXT: NODE_1 = ISD::BUILTIN_OP_END, +// CHECK-NEXT: NODE_2, +// CHECK-NEXT: NODE_3, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NODE_3 + 1; +// CHECK-EMPTY: +// CHECK-NEXT: } // namespace llvm::MyTargetISD + +// CHECK: static const char MyTargetSDNodeNames[] = +// CHECK-NEXT: "MyTargetISD::NODE_1\0" +// CHECK-NEXT: "MyTargetISD::NODE_2\0" +// CHECK-NEXT: "MyTargetISD::NODE_3\0" +// CHECK-NEXT: "\0"; + +// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = { +// CHECK-NEXT: /* 0 */ {SDTCisVT, 1, 0, MVT::i2}, +// CHECK-SAME: {SDTCisVT, 0, 0, MVT::i1}, +// CHECK-NEXT: /* 2 */ {SDTCisSameSizeAs, 19, 18, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisSameNumEltsAs, 17, 16, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCVecEltisVT, 15, 0, MVT::i32}, +// CHECK-SAME: {SDTCisSubVecOfVec, 14, 13, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisEltOfVec, 12, 11, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisOpSmallerThanOp, 10, 9, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisVTSmallerThanOp, 8, 7, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisSameAs, 6, 5, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisVec, 4, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisFP, 3, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisInt, 2, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisPtrTy, 1, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}, +// CHECK-SAME: {SDTCisVT, 0, 0, MVT::i1}, +// CHECK-NEXT: }; +// CHECK-EMPTY: +// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = { +// CHECK-NEXT: {1, 1, 0|1< Date: Fri, 17 Jan 2025 22:58:15 +0300 Subject: [PATCH 5/7] Use raw_svector_ostream --- llvm/utils/TableGen/SDNodeInfoEmitter.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp index 17b5581004565..51e64f1689f5c 100644 --- a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp +++ b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp @@ -169,14 +169,15 @@ std::vector SDNodeInfoEmitter::emitNodeNames(raw_ostream &OS) const { for (StringRef EnumName : make_first_range(TargetNodesByName)) { SmallString<64> DebugName; - (TargetSDNodeNamespace + "::" + EnumName).toVector(DebugName); + raw_svector_ostream SS(DebugName); + SS << TargetSDNodeNamespace << "::" << EnumName; NameOffsets.push_back(NameTable.GetOrAddStringOffset(DebugName)); } NameTable.EmitStringLiteralDef( OS, "static const char " + Target.getName() + "SDNodeNames[]", /*Indent=*/""); - OS << "\n"; + OS << '\n'; return NameOffsets; } From 01ef09f36be8e6074ad634bc71b2761747983b6d Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Sat, 18 Jan 2025 02:53:47 +0300 Subject: [PATCH 6/7] Merge loops --- llvm/utils/TableGen/SDNodeInfoEmitter.cpp | 64 ++++++++++------------- 1 file changed, 28 insertions(+), 36 deletions(-) diff --git a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp index 51e64f1689f5c..4116dd5058887 100644 --- a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp +++ b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp @@ -30,8 +30,7 @@ namespace { class SDNodeInfoEmitter { const RecordKeeper &RK; const CodeGenTarget Target; - std::vector AllNodes; - std::map> TargetNodesByName; + std::map> TargetNodesByName; public: explicit SDNodeInfoEmitter(const RecordKeeper &RK); @@ -51,16 +50,15 @@ class SDNodeInfoEmitter { } // namespace -static bool haveCompatibleDescriptions(const SDNodeInfo *N1, - const SDNodeInfo *N2) { +static bool haveCompatibleDescriptions(const SDNodeInfo &N1, + const SDNodeInfo &N2) { // Number of results/operands must match. - if (N1->getNumResults() != N2->getNumResults() || - N1->getNumOperands() != N2->getNumOperands()) + if (N1.getNumResults() != N2.getNumResults() || + N1.getNumOperands() != N2.getNumOperands()) return false; // Flags must match. - if (N1->isStrictFP() != N2->isStrictFP() || - N1->getTSFlags() != N2->getTSFlags()) + if (N1.isStrictFP() != N2.isStrictFP() || N1.getTSFlags() != N2.getTSFlags()) return false; // We're only interested in a subset of node properties. Properties like @@ -70,18 +68,18 @@ static bool haveCompatibleDescriptions(const SDNodeInfo *N1, (1 << SDNPInGlue) | (1 << SDNPOptInGlue) | (1 << SDNPMemOperand) | (1 << SDNPVariadic); - return (N1->getProperties() & PropMask) == (N2->getProperties() & PropMask); + return (N1.getProperties() & PropMask) == (N2.getProperties() & PropMask); } -static bool haveCompatibleDescriptions(ArrayRef Nodes) { - const SDNodeInfo *N = Nodes.front(); - return all_of(drop_begin(Nodes), [&](const SDNodeInfo *Other) { +static bool haveCompatibleDescriptions(ArrayRef Nodes) { + const SDNodeInfo &N = Nodes.front(); + return all_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) { return haveCompatibleDescriptions(Other, N); }); } -static void warnOnSkippedNode(const SDNodeInfo *N, const Twine &Reason) { - PrintWarning(N->getRecord()->getLoc(), "skipped node: " + Reason); +static void warnOnSkippedNode(const SDNodeInfo &N, const Twine &Reason) { + PrintWarning(N.getRecord()->getLoc(), "skipped node: " + Reason); } SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK) @@ -92,27 +90,23 @@ SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK) if (!TargetSDNodeNamespace.getNumOccurrences()) TargetSDNodeNamespace = Target.getName().str() + "ISD"; - // Parse all SDNode records. - for (const Record *R : RK.getAllDerivedDefinitions("SDNode")) - AllNodes.emplace_back(R, HwModes); - // Filter nodes by the target SDNode namespace and create a mapping // from an enum name to a list of nodes that have that name. // The mapping is usually 1:1, but in rare cases it can be 1:N. - for (const SDNodeInfo &Node : AllNodes) { - StringRef QualifiedEnumName = Node.getEnumName(); - auto [NS, EnumName] = QualifiedEnumName.split("::"); + for (const Record *R : RK.getAllDerivedDefinitions("SDNode")) { + SDNodeInfo Node(R, HwModes); + auto [NS, EnumName] = Node.getEnumName().split("::"); if (NS.empty() || EnumName.empty()) { if (WarnOnSkippedNodes) - warnOnSkippedNode(&Node, "invalid enum name"); + warnOnSkippedNode(Node, "invalid enum name"); continue; } if (NS != TargetSDNodeNamespace) continue; - TargetNodesByName[EnumName].push_back(&Node); + TargetNodesByName[EnumName].push_back(std::move(Node)); } // Filter out nodes that have different "prototypes" and/or flags. @@ -127,7 +121,7 @@ SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK) continue; if (WarnOnSkippedNodes) - for (const SDNodeInfo *N : I->second) + for (const SDNodeInfo &N : I->second) warnOnSkippedNode(N, "incompatible description"); TargetNodesByName.erase(I); @@ -250,11 +244,10 @@ SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const { SmallVector SkippedNodes; for (const auto &[EnumName, Nodes] : TargetNodesByName) { - ArrayRef Constraints = - Nodes.front()->getTypeConstraints(); + ArrayRef Constraints = Nodes.front().getTypeConstraints(); - bool IsAmbiguous = any_of(drop_begin(Nodes), [&](const SDNodeInfo *Other) { - return ArrayRef(Other->getTypeConstraints()) != Constraints; + bool IsAmbiguous = any_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) { + return ArrayRef(Other.getTypeConstraints()) != Constraints; }); // If nodes with the same enum name have different constraints, @@ -284,8 +277,7 @@ SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const { OS << "};\n\n"; for (const auto &[EnumName, Nodes] : TargetNodesByName) { - ArrayRef Constraints = - Nodes.front()->getTypeConstraints(); + ArrayRef Constraints = Nodes.front().getTypeConstraints(); if (Constraints.empty() || is_contained(SkippedNodes, EnumName)) { ConstraintOffsetsAndCounts.emplace_back(/*Offset=*/0, /*Size=*/0); @@ -302,14 +294,14 @@ SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const { } static void emitDesc(raw_ostream &OS, StringRef EnumName, - ArrayRef Nodes, unsigned NameOffset, + ArrayRef Nodes, unsigned NameOffset, unsigned ConstraintsOffset, unsigned ConstraintCount) { assert(haveCompatibleDescriptions(Nodes)); - const SDNodeInfo *N = Nodes.front(); - OS << " {" << N->getNumResults() << ", " << N->getNumOperands() << ", 0"; + const SDNodeInfo &N = Nodes.front(); + OS << " {" << N.getNumResults() << ", " << N.getNumOperands() << ", 0"; // Emitted properties must be kept in sync with haveCompatibleDescriptions. - unsigned Properties = N->getProperties(); + unsigned Properties = N.getProperties(); if (Properties & (1 << SDNPHasChain)) OS << "|1<isStrictFP()) + if (N.isStrictFP()) OS << "|1<getTSFlags(), NameOffset, + OS << formatv(", {}, {}, {}, {}}, // {}\n", N.getTSFlags(), NameOffset, ConstraintsOffset, ConstraintCount, EnumName); } From 87f46689ec056b6627524353b271836f29e62d95 Mon Sep 17 00:00:00 2001 From: Sergei Barannikov Date: Sat, 18 Jan 2025 02:57:19 +0300 Subject: [PATCH 7/7] Rename TargetNodesByName -> NodesByName --- llvm/utils/TableGen/SDNodeInfoEmitter.cpp | 33 +++++++++++------------ 1 file changed, 16 insertions(+), 17 deletions(-) diff --git a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp index 4116dd5058887..cb971b089f5a4 100644 --- a/llvm/utils/TableGen/SDNodeInfoEmitter.cpp +++ b/llvm/utils/TableGen/SDNodeInfoEmitter.cpp @@ -30,7 +30,7 @@ namespace { class SDNodeInfoEmitter { const RecordKeeper &RK; const CodeGenTarget Target; - std::map> TargetNodesByName; + std::map> NodesByName; public: explicit SDNodeInfoEmitter(const RecordKeeper &RK); @@ -106,15 +106,14 @@ SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK) if (NS != TargetSDNodeNamespace) continue; - TargetNodesByName[EnumName].push_back(std::move(Node)); + NodesByName[EnumName].push_back(std::move(Node)); } // Filter out nodes that have different "prototypes" and/or flags. // Don't look at type constraints though, we will simply skip emitting // the constraints if they differ. - decltype(TargetNodesByName)::iterator Next; - for (auto I = TargetNodesByName.begin(), E = TargetNodesByName.end(); I != E; - I = Next) { + decltype(NodesByName)::iterator Next; + for (auto I = NodesByName.begin(), E = NodesByName.end(); I != E; I = Next) { Next = std::next(I); if (haveCompatibleDescriptions(I->second)) @@ -124,7 +123,7 @@ SDNodeInfoEmitter::SDNodeInfoEmitter(const RecordKeeper &RK) for (const SDNodeInfo &N : I->second) warnOnSkippedNode(N, "incompatible description"); - TargetNodesByName.erase(I); + NodesByName.erase(I); } } @@ -133,14 +132,14 @@ void SDNodeInfoEmitter::emitEnum(raw_ostream &OS) const { OS << "#undef GET_SDNODE_ENUM\n\n"; OS << "namespace llvm::" << TargetSDNodeNamespace << " {\n\n"; - if (!TargetNodesByName.empty()) { - StringRef FirstName = TargetNodesByName.begin()->first; - StringRef LastName = TargetNodesByName.rbegin()->first; + if (!NodesByName.empty()) { + StringRef FirstName = NodesByName.begin()->first; + StringRef LastName = NodesByName.rbegin()->first; OS << "enum GenNodeType : unsigned {\n"; OS << " " << FirstName << " = ISD::BUILTIN_OP_END,\n"; - for (StringRef EnumName : make_first_range(drop_begin(TargetNodesByName))) + for (StringRef EnumName : make_first_range(drop_begin(NodesByName))) OS << " " << EnumName << ",\n"; OS << "};\n\n"; @@ -159,9 +158,9 @@ std::vector SDNodeInfoEmitter::emitNodeNames(raw_ostream &OS) const { StringToOffsetTable NameTable; std::vector NameOffsets; - NameOffsets.reserve(TargetNodesByName.size()); + NameOffsets.reserve(NodesByName.size()); - for (StringRef EnumName : make_first_range(TargetNodesByName)) { + for (StringRef EnumName : make_first_range(NodesByName)) { SmallString<64> DebugName; raw_svector_ostream SS(DebugName); SS << TargetSDNodeNamespace << "::" << EnumName; @@ -240,10 +239,10 @@ SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const { /*Terminator=*/std::nullopt); std::vector> ConstraintOffsetsAndCounts; - ConstraintOffsetsAndCounts.reserve(TargetNodesByName.size()); + ConstraintOffsetsAndCounts.reserve(NodesByName.size()); SmallVector SkippedNodes; - for (const auto &[EnumName, Nodes] : TargetNodesByName) { + for (const auto &[EnumName, Nodes] : NodesByName) { ArrayRef Constraints = Nodes.front().getTypeConstraints(); bool IsAmbiguous = any_of(drop_begin(Nodes), [&](const SDNodeInfo &Other) { @@ -276,7 +275,7 @@ SDNodeInfoEmitter::emitTypeConstraints(raw_ostream &OS) const { ConstraintTable.emit(OS, emitTypeConstraint); OS << "};\n\n"; - for (const auto &[EnumName, Nodes] : TargetNodesByName) { + for (const auto &[EnumName, Nodes] : NodesByName) { ArrayRef Constraints = Nodes.front().getTypeConstraints(); if (Constraints.empty() || is_contained(SkippedNodes, EnumName)) { @@ -337,7 +336,7 @@ void SDNodeInfoEmitter::emitDescs(raw_ostream &OS) const { OS << "static const SDNodeDesc " << TargetName << "SDNodeDescs[] = {\n"; for (const auto &[NameAndNodes, NameOffset, ConstraintOffsetAndCount] : - zip_equal(TargetNodesByName, NameOffsets, ConstraintOffsetsAndCounts)) + zip_equal(NodesByName, NameOffsets, ConstraintOffsetsAndCounts)) emitDesc(OS, NameAndNodes.first, NameAndNodes.second, NameOffset, ConstraintOffsetAndCount.first, ConstraintOffsetAndCount.second); @@ -346,7 +345,7 @@ void SDNodeInfoEmitter::emitDescs(raw_ostream &OS) const { OS << formatv("static const SDNodeInfo {0}GenSDNodeInfo(\n" " /*NumOpcodes=*/{1}, {0}SDNodeDescs,\n" " {0}SDNodeNames, {0}SDTypeConstraints);\n\n", - TargetName, TargetNodesByName.size()); + TargetName, NodesByName.size()); OS << "} // namespace llvm\n\n"; OS << "#endif // GET_SDNODE_DESC\n\n";