Skip to content

Commit 6aeffcd

Browse files
authored
[TableGen] Add a backend generating SDNode descriptions (llvm#123002)
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 llvm#119709, [RFC](https://discourse.llvm.org/t/rfc-tablegen-erating-sdnode-descriptions/83627). Pull Request: llvm#123002
1 parent 382bafc commit 6aeffcd

File tree

9 files changed

+870
-49
lines changed

9 files changed

+870
-49
lines changed

llvm/include/llvm/Target/TargetSelectionDAG.td

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ class SDNode<string opcode, SDTypeProfile typeprof,
353353
string SDClass = sdclass;
354354
let Properties = props;
355355
SDTypeProfile TypeProfile = typeprof;
356+
bit IsStrictFP = false;
357+
bits<32> TSFlags = 0;
356358
}
357359

358360
// Special TableGen-recognized dag nodes
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
// RUN: split-file %s %t
2+
3+
//--- test1.td
4+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/test1.td | FileCheck %t/test1.td
5+
6+
include "llvm/Target/Target.td"
7+
8+
def MyTarget : Target;
9+
10+
def my_node_a : SDNode<"MyTargetISD::NODE", SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>>;
11+
def my_node_b : SDNode<"MyTargetISD::NODE", SDTypeProfile<1, 0, [SDTCisVT<0, f32>]>>;
12+
13+
// CHECK: enum GenNodeType : unsigned {
14+
// CHECK-NEXT: NODE = ISD::BUILTIN_OP_END,
15+
// CHECK-NEXT: };
16+
17+
// CHECK: static const char MyTargetSDNodeNames[] =
18+
// CHECK-NEXT: "MyTargetISD::NODE\0"
19+
// CHECK-NEXT: "\0";
20+
21+
// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
22+
// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}
23+
// CHECK-NEXT: };
24+
// CHECK-EMPTY:
25+
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
26+
// CHECK-NEXT: {1, 0, 0, 0, 0, 0, 0, 0}, // NODE
27+
// CHECK-NEXT: };
28+
// CHECK-EMPTY:
29+
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
30+
// CHECK-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs,
31+
// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
32+
33+
34+
//--- test2.td
35+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/test2.td | FileCheck %t/test2.td
36+
37+
include "llvm/Target/Target.td"
38+
39+
def MyTarget : Target;
40+
41+
def my_node_1a : SDNode<"MyTargetISD::NODE_1", SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>>;
42+
def my_node_1b : SDNode<"MyTargetISD::NODE_1", SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>>;
43+
def my_node_2a : SDNode<"MyTargetISD::NODE_2", SDTypeProfile<1, 0, [SDTCisVT<0, i32>]>>;
44+
def my_node_2b : SDNode<"MyTargetISD::NODE_2", SDTypeProfile<1, 0, [SDTCisVT<0, untyped>]>>;
45+
46+
// CHECK: namespace llvm::MyTargetISD {
47+
// CHECK-EMPTY:
48+
// CHECK-NEXT: enum GenNodeType : unsigned {
49+
// CHECK-NEXT: NODE_1 = ISD::BUILTIN_OP_END,
50+
// CHECK-NEXT: NODE_2,
51+
// CHECK-NEXT: };
52+
// CHECK-EMPTY:
53+
// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NODE_2 + 1;
54+
// CHECK-EMPTY:
55+
// CHECK-NEXT: } // namespace llvm::MyTargetISD
56+
57+
// CHECK: static const char MyTargetSDNodeNames[] =
58+
// CHECK-NEXT: "MyTargetISD::NODE_1\0"
59+
// CHECK-NEXT: "MyTargetISD::NODE_2\0"
60+
// CHECK-NEXT: "\0";
61+
62+
// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
63+
// CHECK-NEXT: /* 0 */ {SDTCisVT, 0, 0, MVT::i32},
64+
// CHECK-NEXT: };
65+
// CHECK-EMPTY:
66+
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
67+
// CHECK-NEXT: {1, 0, 0, 0, 0, 0, 0, 1}, // NODE_1
68+
// CHECK-NEXT: {1, 0, 0, 0, 0, 20, 0, 0}, // NODE_2
69+
// CHECK-NEXT: };
70+
// CHECK-EMPTY:
71+
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
72+
// CHECK-NEXT: /*NumOpcodes=*/2, MyTargetSDNodeDescs,
73+
// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
Lines changed: 183 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,183 @@
1+
// RUN: split-file %s %t
2+
3+
//--- no-nodes.td
4+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/no-nodes.td \
5+
// RUN: | FileCheck %t/no-nodes.td
6+
7+
include "llvm/Target/Target.td"
8+
9+
def MyTarget : Target;
10+
11+
// CHECK: #ifdef GET_SDNODE_ENUM
12+
// CHECK-NEXT: #undef GET_SDNODE_ENUM
13+
// CHECK-EMPTY:
14+
// CHECK-NEXT: namespace llvm::MyTargetISD {
15+
// CHECK-EMPTY:
16+
// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = ISD::BUILTIN_OP_END;
17+
// CHECK-EMPTY:
18+
// CHECK-NEXT: } // namespace llvm::MyTargetISD
19+
// CHECK-EMPTY:
20+
// CHECK-NEXT: #endif // GET_SDNODE_ENUM
21+
// CHECK-EMPTY:
22+
// CHECK-NEXT: #ifdef GET_SDNODE_DESC
23+
// CHECK-NEXT: #undef GET_SDNODE_DESC
24+
// CHECK-EMPTY:
25+
// CHECK-NEXT: namespace llvm {
26+
// CHECK-EMPTY:
27+
// CHECK-NEXT: #ifdef __GNUC__
28+
// CHECK-NEXT: #pragma GCC diagnostic push
29+
// CHECK-NEXT: #pragma GCC diagnostic ignored "-Woverlength-strings"
30+
// CHECK-NEXT: #endif
31+
// CHECK-NEXT: static const char MyTargetSDNodeNames[] =
32+
// CHECK-NEXT: "\0";
33+
// CHECK-NEXT: #ifdef __GNUC__
34+
// CHECK-NEXT: #pragma GCC diagnostic pop
35+
// CHECK-NEXT: #endif
36+
// CHECK-EMPTY:
37+
// CHECK-NEXT: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
38+
// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}
39+
// CHECK-NEXT: };
40+
// CHECK-EMPTY:
41+
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
42+
// CHECK-NEXT: };
43+
// CHECK-EMPTY:
44+
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
45+
// CHECK-NEXT: /*NumOpcodes=*/0, MyTargetSDNodeDescs,
46+
// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
47+
// CHECK-EMPTY:
48+
// CHECK-NEXT: } // namespace llvm
49+
// CHECK-EMPTY:
50+
// CHECK-NEXT: #endif // GET_SDNODE_DESC
51+
52+
53+
//--- trivial-node.td
54+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/trivial-node.td \
55+
// RUN: | FileCheck %t/trivial-node.td
56+
57+
include "llvm/Target/Target.td"
58+
59+
def MyTarget : Target;
60+
61+
def my_noop : SDNode<"MyTargetISD::NOOP", SDTypeProfile<0, 0, []>>;
62+
63+
// CHECK: namespace llvm::MyTargetISD {
64+
// CHECK-EMPTY:
65+
// CHECK-NEXT: enum GenNodeType : unsigned {
66+
// CHECK-NEXT: NOOP = ISD::BUILTIN_OP_END,
67+
// CHECK-NEXT: };
68+
// CHECK-EMPTY:
69+
// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NOOP + 1;
70+
// CHECK-EMPTY:
71+
// CHECK-NEXT: } // namespace llvm::MyTargetISD
72+
73+
// CHECK: static const char MyTargetSDNodeNames[] =
74+
// CHECK-NEXT: "MyTargetISD::NOOP\0"
75+
// CHECK-NEXT: "\0";
76+
77+
// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
78+
// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}
79+
// CHECK-NEXT: };
80+
// CHECK-EMPTY:
81+
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
82+
// CHECK-NEXT: {0, 0, 0, 0, 0, 0, 0, 0}, // NOOP
83+
// CHECK-NEXT: };
84+
// CHECK-EMPTY:
85+
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
86+
// CHECK-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs,
87+
// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
88+
89+
//--- advanced.td
90+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/advanced.td \
91+
// RUN: | FileCheck %t/advanced.td
92+
93+
include "llvm/Target/Target.td"
94+
95+
def MyTarget : Target;
96+
97+
def my_node_1 : SDNode<
98+
"MyTargetISD::NODE_1",
99+
SDTypeProfile<1, 1, [SDTCisVT<0, i1>, SDTCisVT<1, i2>]>,
100+
[SDNPHasChain]
101+
>;
102+
103+
let TSFlags = 42 in
104+
def my_node_2 : SDNode<
105+
"MyTargetISD::NODE_2",
106+
SDTypeProfile<3, 1, [
107+
// Prefix of my_node_3 constraints.
108+
SDTCisVT<0, i1>,
109+
SDTCisPtrTy<1>,
110+
SDTCisInt<2>,
111+
SDTCisFP<3>,
112+
]>,
113+
[SDNPMayStore, SDNPMayLoad, SDNPSideEffect,
114+
SDNPMemOperand, SDNPVariadic]
115+
>;
116+
117+
let IsStrictFP = true, TSFlags = 24 in
118+
def my_node_3 : SDNode<
119+
"MyTargetISD::NODE_3",
120+
SDTypeProfile<2, -1, [
121+
SDTCisVT<0, i1>,
122+
SDTCisPtrTy<1>,
123+
SDTCisInt<2>,
124+
SDTCisFP<3>,
125+
SDTCisVec<4>,
126+
SDTCisSameAs<6, 5>,
127+
SDTCisVTSmallerThanOp<8, 7>,
128+
SDTCisOpSmallerThanOp<10, 9>,
129+
SDTCisEltOfVec<12, 11>,
130+
SDTCisSubVecOfVec<14, 13>,
131+
SDTCVecEltisVT<15, i32>,
132+
SDTCisSameNumEltsAs<17, 16>,
133+
SDTCisSameSizeAs<19, 18>,
134+
]>,
135+
[SDNPCommutative, SDNPAssociative, SDNPHasChain,
136+
SDNPOutGlue, SDNPInGlue, SDNPOptInGlue]
137+
>;
138+
139+
// CHECK: namespace llvm::MyTargetISD {
140+
// CHECK-EMPTY:
141+
// CHECK-NEXT: enum GenNodeType : unsigned {
142+
// CHECK-NEXT: NODE_1 = ISD::BUILTIN_OP_END,
143+
// CHECK-NEXT: NODE_2,
144+
// CHECK-NEXT: NODE_3,
145+
// CHECK-NEXT: };
146+
// CHECK-EMPTY:
147+
// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NODE_3 + 1;
148+
// CHECK-EMPTY:
149+
// CHECK-NEXT: } // namespace llvm::MyTargetISD
150+
151+
// CHECK: static const char MyTargetSDNodeNames[] =
152+
// CHECK-NEXT: "MyTargetISD::NODE_1\0"
153+
// CHECK-NEXT: "MyTargetISD::NODE_2\0"
154+
// CHECK-NEXT: "MyTargetISD::NODE_3\0"
155+
// CHECK-NEXT: "\0";
156+
157+
// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
158+
// CHECK-NEXT: /* 0 */ {SDTCisVT, 1, 0, MVT::i2},
159+
// CHECK-SAME: {SDTCisVT, 0, 0, MVT::i1},
160+
// CHECK-NEXT: /* 2 */ {SDTCisSameSizeAs, 19, 18, MVT::INVALID_SIMPLE_VALUE_TYPE},
161+
// CHECK-SAME: {SDTCisSameNumEltsAs, 17, 16, MVT::INVALID_SIMPLE_VALUE_TYPE},
162+
// CHECK-SAME: {SDTCVecEltisVT, 15, 0, MVT::i32},
163+
// CHECK-SAME: {SDTCisSubVecOfVec, 14, 13, MVT::INVALID_SIMPLE_VALUE_TYPE},
164+
// CHECK-SAME: {SDTCisEltOfVec, 12, 11, MVT::INVALID_SIMPLE_VALUE_TYPE},
165+
// CHECK-SAME: {SDTCisOpSmallerThanOp, 10, 9, MVT::INVALID_SIMPLE_VALUE_TYPE},
166+
// CHECK-SAME: {SDTCisVTSmallerThanOp, 8, 7, MVT::INVALID_SIMPLE_VALUE_TYPE},
167+
// CHECK-SAME: {SDTCisSameAs, 6, 5, MVT::INVALID_SIMPLE_VALUE_TYPE},
168+
// CHECK-SAME: {SDTCisVec, 4, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
169+
// CHECK-SAME: {SDTCisFP, 3, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
170+
// CHECK-SAME: {SDTCisInt, 2, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
171+
// CHECK-SAME: {SDTCisPtrTy, 1, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
172+
// CHECK-SAME: {SDTCisVT, 0, 0, MVT::i1},
173+
// CHECK-NEXT: };
174+
// CHECK-EMPTY:
175+
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
176+
// CHECK-NEXT: {1, 1, 0|1<<SDNPHasChain, 0, 0, 0, 0, 2}, // NODE_1
177+
// CHECK-NEXT: {3, 1, 0|1<<SDNPVariadic|1<<SDNPMemOperand, 0, 42, 20, 11, 4}, // NODE_2
178+
// CHECK-NEXT: {2, -1, 0|1<<SDNPHasChain|1<<SDNPOutGlue|1<<SDNPInGlue|1<<SDNPOptInGlue, 0|1<<SDNFIsStrictFP, 24, 40, 2, 13}, // NODE_3
179+
// CHECK-NEXT: };
180+
// CHECK-EMPTY:
181+
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
182+
// CHECK-NEXT: /*NumOpcodes=*/3, MyTargetSDNodeDescs,
183+
// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %s -sdnode-namespace=EmptyISD \
2+
// RUN: | FileCheck %s -check-prefix=EMPTY
3+
4+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %s \
5+
// RUN: | FileCheck %s --check-prefixes=COMMON,TARGET -DNS=MyTargetISD
6+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %s -sdnode-namespace=MyCustomISD \
7+
// RUN: | FileCheck %s -check-prefixes=COMMON,CUSTOM -DNS=MyCustomISD
8+
9+
include "llvm/Target/Target.td"
10+
11+
def MyTarget : Target;
12+
13+
def node_1 : SDNode<"MyTargetISD::NODE", SDTypeProfile<1, 0, [SDTCisVT<0, i1>]>>;
14+
def node_2 : SDNode<"MyCustomISD::NODE", SDTypeProfile<0, 1, [SDTCisVT<0, i2>]>>;
15+
16+
// EMPTY: namespace llvm::EmptyISD {
17+
// EMPTY-EMPTY:
18+
// EMPTY-NEXT: static constexpr unsigned GENERATED_OPCODE_END = ISD::BUILTIN_OP_END;
19+
// EMPTY-EMPTY:
20+
// EMPTY-NEXT: } // namespace llvm::EmptyISD
21+
22+
// EMPTY: static const char MyTargetSDNodeNames[] =
23+
// EMPTY-NEXT: "\0";
24+
25+
// EMPTY: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
26+
// EMPTY-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}
27+
// EMPTY-NEXT: };
28+
// EMPTY-EMPTY:
29+
// EMPTY-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
30+
// EMPTY-NEXT: };
31+
// EMPTY-EMPTY:
32+
// EMPTY-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
33+
// EMPTY-NEXT: /*NumOpcodes=*/0, MyTargetSDNodeDescs,
34+
// EMPTY-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
35+
36+
// COMMON: namespace llvm::[[NS]] {
37+
// COMMON-EMPTY:
38+
// COMMON-NEXT: enum GenNodeType : unsigned {
39+
// COMMON-NEXT: NODE = ISD::BUILTIN_OP_END,
40+
// COMMON-NEXT: };
41+
// COMMON-EMPTY:
42+
// COMMON-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NODE + 1;
43+
// COMMON-EMPTY:
44+
// COMMON-NEXT: } // namespace llvm::[[NS]]
45+
46+
// COMMON: static const char MyTargetSDNodeNames[] =
47+
// COMMON-NEXT: "[[NS]]::NODE\0"
48+
// COMMON-NEXT: "\0";
49+
50+
// COMMON: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
51+
// TARGET-NEXT: /* 0 */ {SDTCisVT, 0, 0, MVT::i1},
52+
// CUSTOM-NEXT: /* 0 */ {SDTCisVT, 0, 0, MVT::i2},
53+
// COMMON-NEXT: };
54+
// COMMON-EMPTY:
55+
// COMMON-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
56+
// TARGET-NEXT: {1, 0, 0, 0, 0, 0, 0, 1}, // NODE
57+
// CUSTOM-NEXT: {0, 1, 0, 0, 0, 0, 0, 1}, // NODE
58+
// COMMON-NEXT: };
59+
// COMMON-EMPTY:
60+
// COMMON-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
61+
// COMMON-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs,
62+
// COMMON-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);

0 commit comments

Comments
 (0)