Skip to content

Commit 9ec5e48

Browse files
committed
[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).
1 parent 63d3bd6 commit 9ec5e48

File tree

9 files changed

+777
-49
lines changed

9 files changed

+777
-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<64> 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: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
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+
50+
51+
//--- trivial-node.td
52+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %t/trivial-node.td \
53+
// RUN: | FileCheck %t/trivial-node.td
54+
55+
include "llvm/Target/Target.td"
56+
57+
def MyTarget : Target;
58+
59+
def my_noop : SDNode<"MyTargetISD::NOOP", SDTypeProfile<0, 0, []>>;
60+
61+
// CHECK: namespace llvm::MyTargetISD {
62+
// CHECK-EMPTY:
63+
// CHECK-NEXT: enum GenNodeType : unsigned {
64+
// CHECK-NEXT: NOOP = ISD::BUILTIN_OP_END,
65+
// CHECK-NEXT: };
66+
// CHECK-EMPTY:
67+
// CHECK-NEXT: static constexpr unsigned GENERATED_OPCODE_END = NOOP + 1;
68+
// CHECK-EMPTY:
69+
// CHECK-NEXT: } // namespace llvm::MyTargetISD
70+
71+
// CHECK: static const char MyTargetSDNodeNames[] =
72+
// CHECK-NEXT: "MyTargetISD::NOOP\0"
73+
// CHECK-NEXT: "\0";
74+
75+
// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
76+
// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}
77+
// CHECK-NEXT: };
78+
// CHECK-EMPTY:
79+
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
80+
// CHECK-NEXT: {0, 0, 0, 0, 0, 0, 0, 0}, // NOOP
81+
// CHECK-NEXT: };
82+
// CHECK-EMPTY:
83+
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
84+
// CHECK-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs,
85+
// 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);
Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
// RUN: llvm-tblgen -gen-sd-node-info -I %p/../../../include %s 2> %t.warn | FileCheck %s
2+
// RUN: FileCheck --check-prefix=WARN --implicit-check-not=warning %s < %t.warn
3+
4+
// RUN: llvm-tblgen -gen-sd-node-info -warn-on-skipped-nodes=false \
5+
// RUN: -I %p/../../../include %s 2> %t.nowarn | FileCheck %s
6+
// RUN: not test -s %t.nowarn
7+
8+
include "llvm/Target/Target.td"
9+
10+
def MyTarget : Target;
11+
12+
// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name
13+
def bad_name_1 : SDNode<"", SDTypeProfile<0, 0, []>>;
14+
15+
// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name
16+
def bad_name_2 : SDNode<"NODE", SDTypeProfile<0, 0, []>>;
17+
18+
// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name
19+
def bad_name_3 : SDNode<"MyTargetISD::", SDTypeProfile<0, 0, []>>;
20+
21+
// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name
22+
def bad_name_4 : SDNode<"MyISD::", SDTypeProfile<0, 0, []>>;
23+
24+
// WARN: [[#@LINE+1]]:5: warning: skipped node: invalid enum name
25+
def bad_name_5 : SDNode<"::NODE", SDTypeProfile<0, 0, []>>;
26+
27+
28+
// Standard namespace.
29+
def silent_1 : SDNode<"ISD::SILENT", SDTypeProfile<0, 0, []>>;
30+
31+
// Different namespace.
32+
def silent_2 : SDNode<"MyISD::SILENT", SDTypeProfile<0, 0, []>>;
33+
34+
35+
// Different number of results.
36+
// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description
37+
// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description
38+
def node_1a : SDNode<"MyTargetISD::NODE_1", SDTypeProfile<0, 0, []>>;
39+
def node_1b : SDNode<"MyTargetISD::NODE_1", SDTypeProfile<1, 0, []>>;
40+
41+
// Different number of operands.
42+
// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description
43+
// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description
44+
def node_2a : SDNode<"MyTargetISD::NODE_2", SDTypeProfile<0, 0, []>>;
45+
def node_2b : SDNode<"MyTargetISD::NODE_2", SDTypeProfile<0, 1, []>>;
46+
47+
// Different value of IsStrictFP.
48+
// WARN: [[#@LINE+3]]:5: warning: skipped node: incompatible description
49+
// WARN: [[#@LINE+3]]:5: warning: skipped node: incompatible description
50+
let IsStrictFP = true in
51+
def node_3a : SDNode<"MyTargetISD::NODE_3", SDTypeProfile<0, 0, []>>;
52+
def node_3b : SDNode<"MyTargetISD::NODE_3", SDTypeProfile<0, 0, []>>;
53+
54+
// Different value of TSFlags.
55+
// WARN: [[#@LINE+3]]:5: warning: skipped node: incompatible description
56+
// WARN: [[#@LINE+3]]:5: warning: skipped node: incompatible description
57+
let TSFlags = 1 in
58+
def node_4a : SDNode<"MyTargetISD::NODE_4", SDTypeProfile<0, 0, []>>;
59+
def node_4b : SDNode<"MyTargetISD::NODE_4", SDTypeProfile<0, 0, []>>;
60+
61+
// Different properties.
62+
// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description
63+
// WARN: [[#@LINE+2]]:5: warning: skipped node: incompatible description
64+
def node_5a : SDNode<"MyTargetISD::NODE_5", SDTypeProfile<0, 0, []>>;
65+
def node_5b : SDNode<"MyTargetISD::NODE_5", SDTypeProfile<0, 0, []>, [SDNPHasChain]>;
66+
67+
68+
// CHECK: enum GenNodeType : unsigned {
69+
// CHECK-NEXT: COMPAT = ISD::BUILTIN_OP_END,
70+
// CHECK-NEXT: };
71+
72+
// CHECK: static const char MyTargetSDNodeNames[] =
73+
// CHECK-NEXT: "MyTargetISD::COMPAT\0"
74+
// CHECK-NEXT: "\0";
75+
76+
// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
77+
// CHECK-NEXT: /* dummy */ {SDTCisVT, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE}
78+
// CHECK-NEXT: };
79+
// CHECK-EMPTY:
80+
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
81+
// CHECK-NEXT: {1, -1, 0, 0, 0, 0, 0, 0}, // COMPAT
82+
// CHECK-NEXT: };
83+
// CHECK-EMPTY:
84+
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
85+
// CHECK-NEXT: /*NumOpcodes=*/1, MyTargetSDNodeDescs,
86+
// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
87+
88+
def compat_a : SDNode<"MyTargetISD::COMPAT", SDTypeProfile<1, -1, []>>;
89+
def compat_b : SDNode<"MyTargetISD::COMPAT", SDTypeProfile<1, -1, [SDTCisVT<0, untyped>]>>;
90+
def compat_c : SDNode<"MyTargetISD::COMPAT", SDTypeProfile<1, -1, [SDTCisVT<0, untyped>]>,
91+
[SDNPCommutative, SDNPAssociative, SDNPMayStore, SDNPMayLoad, SDNPSideEffect]>;

llvm/utils/TableGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ add_tablegen(llvm-tblgen LLVM
6060
PseudoLoweringEmitter.cpp
6161
RegisterBankEmitter.cpp
6262
RegisterInfoEmitter.cpp
63+
SDNodeInfoEmitter.cpp
6364
SearchableTableEmitter.cpp
6465
SubtargetEmitter.cpp
6566
WebAssemblyDisassemblerEmitter.cpp

0 commit comments

Comments
 (0)