Skip to content

Commit 7e06e22

Browse files
committed
[SelectionDAG] Verify SDTCisVT and SDTCVecEltisVT constraints
1 parent e89e678 commit 7e06e22

18 files changed

+307
-88
lines changed

llvm/include/llvm/CodeGen/SDNodeInfo.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -48,11 +48,21 @@ enum SDNF {
4848
SDNFIsStrictFP,
4949
};
5050

51+
struct VTByHwModePair {
52+
uint8_t Mode;
53+
MVT::SimpleValueType VT;
54+
};
55+
5156
struct SDTypeConstraint {
5257
SDTC Kind;
5358
uint8_t OpNo;
5459
uint8_t OtherOpNo;
55-
MVT::SimpleValueType VT;
60+
/// For Kind == SDTCisVT or SDTCVecEltisVT:
61+
/// - if not using HwMode, NumHwModes == 0 and VT is MVT::SimpleValueType;
62+
/// - otherwise, VT is offset into VTByHwModeTable and NumHwModes specifies
63+
/// the number of entries.
64+
uint8_t NumHwModes;
65+
uint16_t VT;
5666
};
5767

5868
using SDNodeTSFlags = uint32_t;
@@ -76,13 +86,15 @@ class SDNodeInfo final {
7686
unsigned NumOpcodes;
7787
const SDNodeDesc *Descs;
7888
StringTable Names;
89+
const VTByHwModePair *VTByHwModeTable;
7990
const SDTypeConstraint *Constraints;
8091

8192
public:
8293
constexpr SDNodeInfo(unsigned NumOpcodes, const SDNodeDesc *Descs,
83-
StringTable Names, const SDTypeConstraint *Constraints)
94+
StringTable Names, const VTByHwModePair *VTByHwModeTable,
95+
const SDTypeConstraint *Constraints)
8496
: NumOpcodes(NumOpcodes), Descs(Descs), Names(Names),
85-
Constraints(Constraints) {}
97+
VTByHwModeTable(VTByHwModeTable), Constraints(Constraints) {}
8698

8799
/// Returns true if there is a generated description for a node with the given
88100
/// target-specific opcode.

llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp

Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,10 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "llvm/CodeGen/SDNodeInfo.h"
10+
#include "llvm/CodeGen/SelectionDAG.h"
1011
#include "llvm/CodeGen/SelectionDAGNodes.h"
12+
#include "llvm/CodeGen/TargetLowering.h"
13+
#include "llvm/CodeGen/TargetSubtargetInfo.h"
1114

1215
using namespace llvm;
1316

@@ -40,6 +43,26 @@ static void checkOperandType(const SelectionDAG &DAG, const SDNode *N,
4043
ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString());
4144
}
4245

46+
namespace {
47+
48+
struct ConstraintOp {
49+
const SDNode *N;
50+
unsigned Idx;
51+
bool IsRes;
52+
53+
SDValue getValue() const {
54+
return IsRes ? SDValue(const_cast<SDNode *>(N), Idx) : N->getOperand(Idx);
55+
}
56+
57+
EVT getValueType() const { return getValue().getValueType(); }
58+
};
59+
60+
raw_ostream &operator<<(raw_ostream &OS, const ConstraintOp &Info) {
61+
return OS << (Info.IsRes ? "result" : "operand") << " #" << Info.Idx;
62+
}
63+
64+
} // namespace
65+
4366
void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
4467
const SDNodeDesc &Desc = getDesc(N->getOpcode());
4568
bool HasChain = Desc.hasProperty(SDNPHasChain);
@@ -125,4 +148,86 @@ void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
125148
" must be Register or RegisterMask");
126149
}
127150
}
151+
152+
unsigned VTHwMode =
153+
DAG.getSubtarget().getHwMode(MCSubtargetInfo::HwMode_ValueType);
154+
155+
auto GetConstraintOp = [&](unsigned Idx) {
156+
if (Idx < Desc.NumResults)
157+
return ConstraintOp{N, Idx, /*IsRes=*/true};
158+
return ConstraintOp{N, HasChain + (Idx - Desc.NumResults), /*IsRes=*/false};
159+
};
160+
161+
auto GetConstraintVT = [&](const SDTypeConstraint &C) {
162+
if (!C.NumHwModes)
163+
return static_cast<MVT::SimpleValueType>(C.VT);
164+
for (auto [Mode, VT] : ArrayRef(&VTByHwModeTable[C.VT], C.NumHwModes))
165+
if (Mode == VTHwMode)
166+
return VT;
167+
llvm_unreachable("No value type for this HW mode");
168+
};
169+
170+
SmallString<128> ES;
171+
raw_svector_ostream SS(ES);
172+
173+
for (const SDTypeConstraint &C : getConstraints(N->getOpcode())) {
174+
ConstraintOp Op = GetConstraintOp(C.OpNo);
175+
EVT OpVT = Op.getValue().getValueType();
176+
177+
switch (C.Kind) {
178+
case SDTCisVT: {
179+
EVT ExpectedVT = GetConstraintVT(C);
180+
181+
bool IsPtr = ExpectedVT == MVT::iPTR;
182+
if (IsPtr)
183+
ExpectedVT =
184+
DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
185+
186+
if (OpVT != ExpectedVT) {
187+
SS << Op << " must have type " << ExpectedVT;
188+
if (IsPtr)
189+
SS << " (iPTR)";
190+
SS << ", but has type " << OpVT;
191+
reportNodeError(DAG, N, SS.str());
192+
}
193+
break;
194+
}
195+
case SDTCisPtrTy:
196+
break;
197+
case SDTCisInt:
198+
break;
199+
case SDTCisFP:
200+
break;
201+
case SDTCisVec:
202+
break;
203+
case SDTCisSameAs:
204+
break;
205+
case SDTCisVTSmallerThanOp:
206+
break;
207+
case SDTCisOpSmallerThanOp:
208+
break;
209+
case SDTCisEltOfVec:
210+
break;
211+
case SDTCisSubVecOfVec:
212+
break;
213+
case SDTCVecEltisVT: {
214+
EVT ExpectedVT = GetConstraintVT(C);
215+
216+
if (!OpVT.isVector()) {
217+
SS << Op << " must have vector type";
218+
reportNodeError(DAG, N, SS.str());
219+
}
220+
if (OpVT.getVectorElementType() != ExpectedVT) {
221+
SS << Op << " must have " << ExpectedVT << " element type, but has "
222+
<< OpVT.getVectorElementType() << " element type";
223+
reportNodeError(DAG, N, SS.str());
224+
}
225+
break;
226+
}
227+
case SDTCisSameNumEltsAs:
228+
break;
229+
case SDTCisSameSizeAs:
230+
break;
231+
}
232+
}
128233
}

llvm/lib/Target/AArch64/AArch64InstrInfo.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1144,7 +1144,7 @@ def AArch64msrr : SDNode<"AArch64ISD::MSRR",
11441144
SDTCisVT<2, i64>]>,
11451145
[SDNPHasChain]>;
11461146

1147-
def SD_AArch64rshrnb : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisVec<1>, SDTCisInt<2>]>;
1147+
def SD_AArch64rshrnb : SDTypeProfile<1, 2, [SDTCisVec<0>, SDTCisVec<1>, SDTCisVT<2, i32>]>;
11481148
// Vector narrowing shift by immediate (bottom)
11491149
def AArch64rshrnb : SDNode<"AArch64ISD::RSHRNB_I", SD_AArch64rshrnb>;
11501150
def AArch64rshrnb_pf : PatFrags<(ops node:$rs, node:$i),

llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.cpp

Lines changed: 31 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -32,16 +32,41 @@ AArch64SelectionDAGInfo::AArch64SelectionDAGInfo()
3232

3333
void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
3434
const SDNode *N) const {
35+
switch (N->getOpcode()) {
36+
case AArch64ISD::ADC:
37+
case AArch64ISD::SBC:
38+
case AArch64ISD::ADCS:
39+
case AArch64ISD::SBCS:
40+
// operand #2 must have type i32, but has type glue
41+
return;
42+
case AArch64ISD::SUBS:
43+
// result #1 must have type i32, but has type glue
44+
return;
45+
case AArch64ISD::CSEL:
46+
case AArch64ISD::CSINC:
47+
case AArch64ISD::BRCOND:
48+
// operand #3 must have type i32, but has type glue
49+
return;
50+
case AArch64ISD::WrapperLarge:
51+
// operand #0 must have type i32, but has type i64
52+
return;
53+
case AArch64ISD::LDNP:
54+
// result #0 must have type v4i32, but has type v2f64
55+
return;
56+
case AArch64ISD::STNP:
57+
// operand #1 must have type v4i32, but has type v2i64
58+
return;
59+
}
60+
61+
SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
62+
3563
#ifndef NDEBUG
64+
// Some additional checks not yet implemented by verifyTargetNode.
3665
switch (N->getOpcode()) {
37-
default:
38-
return SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
3966
case AArch64ISD::SADDWT:
4067
case AArch64ISD::SADDWB:
4168
case AArch64ISD::UADDWT:
4269
case AArch64ISD::UADDWB: {
43-
assert(N->getNumValues() == 1 && "Expected one result!");
44-
assert(N->getNumOperands() == 2 && "Expected two operands!");
4570
EVT VT = N->getValueType(0);
4671
EVT Op0VT = N->getOperand(0).getValueType();
4772
EVT Op1VT = N->getOperand(1).getValueType();
@@ -61,8 +86,6 @@ void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
6186
case AArch64ISD::SUNPKHI:
6287
case AArch64ISD::UUNPKLO:
6388
case AArch64ISD::UUNPKHI: {
64-
assert(N->getNumValues() == 1 && "Expected one result!");
65-
assert(N->getNumOperands() == 1 && "Expected one operand!");
6689
EVT VT = N->getValueType(0);
6790
EVT OpVT = N->getOperand(0).getValueType();
6891
assert(OpVT.isVector() && VT.isVector() && OpVT.isInteger() &&
@@ -79,8 +102,6 @@ void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
79102
case AArch64ISD::UZP2:
80103
case AArch64ISD::ZIP1:
81104
case AArch64ISD::ZIP2: {
82-
assert(N->getNumValues() == 1 && "Expected one result!");
83-
assert(N->getNumOperands() == 2 && "Expected two operands!");
84105
EVT VT = N->getValueType(0);
85106
EVT Op0VT = N->getOperand(0).getValueType();
86107
EVT Op1VT = N->getOperand(1).getValueType();
@@ -90,11 +111,8 @@ void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
90111
break;
91112
}
92113
case AArch64ISD::RSHRNB_I: {
93-
assert(N->getNumValues() == 1 && "Expected one result!");
94-
assert(N->getNumOperands() == 2 && "Expected two operands!");
95114
EVT VT = N->getValueType(0);
96115
EVT Op0VT = N->getOperand(0).getValueType();
97-
EVT Op1VT = N->getOperand(1).getValueType();
98116
assert(VT.isVector() && VT.isInteger() &&
99117
"Expected integer vector result type!");
100118
assert(Op0VT.isVector() && Op0VT.isInteger() &&
@@ -103,8 +121,8 @@ void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
103121
"Expected vectors of equal size!");
104122
assert(VT.getVectorElementCount() == Op0VT.getVectorElementCount() * 2 &&
105123
"Expected input vector with half the lanes of its result!");
106-
assert(Op1VT == MVT::i32 && isa<ConstantSDNode>(N->getOperand(1)) &&
107-
"Expected second operand to be a constant i32!");
124+
assert(isa<ConstantSDNode>(N->getOperand(1)) &&
125+
"Expected second operand to be a constant!");
108126
break;
109127
}
110128
}

llvm/lib/Target/M68k/M68kSelectionDAGInfo.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,19 @@ using namespace llvm;
1616
M68kSelectionDAGInfo::M68kSelectionDAGInfo()
1717
: SelectionDAGGenTargetInfo(M68kGenSDNodeInfo) {}
1818

19+
void M68kSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
20+
const SDNode *N) const {
21+
switch (N->getOpcode()) {
22+
case M68kISD::ADD:
23+
case M68kISD::SUBX:
24+
// result #1 must have type i8, but has type i32
25+
return;
26+
case M68kISD::SETCC:
27+
// operand #1 must have type i8, but has type i32
28+
return;
29+
}
30+
31+
SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
32+
}
33+
1934
M68kSelectionDAGInfo::~M68kSelectionDAGInfo() = default;

llvm/lib/Target/M68k/M68kSelectionDAGInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,9 @@ class M68kSelectionDAGInfo : public SelectionDAGGenTargetInfo {
2121
M68kSelectionDAGInfo();
2222

2323
~M68kSelectionDAGInfo() override;
24+
25+
void verifyTargetNode(const SelectionDAG &DAG,
26+
const SDNode *N) const override;
2427
};
2528

2629
} // namespace llvm

llvm/lib/Target/RISCV/RISCVSelectionDAGInfo.cpp

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,27 +20,22 @@ RISCVSelectionDAGInfo::~RISCVSelectionDAGInfo() = default;
2020

2121
void RISCVSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
2222
const SDNode *N) const {
23+
SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
24+
2325
#ifndef NDEBUG
26+
// Some additional checks not yet implemented by verifyTargetNode.
2427
switch (N->getOpcode()) {
25-
default:
26-
return SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
2728
case RISCVISD::TUPLE_EXTRACT:
28-
assert(N->getNumOperands() == 2 && "Expected three operands!");
2929
assert(N->getOperand(1).getOpcode() == ISD::TargetConstant &&
30-
N->getOperand(1).getValueType() == MVT::i32 &&
31-
"Expected index to be an i32 target constant!");
30+
"Expected index to be a target constant!");
3231
break;
3332
case RISCVISD::TUPLE_INSERT:
34-
assert(N->getNumOperands() == 3 && "Expected three operands!");
3533
assert(N->getOperand(2).getOpcode() == ISD::TargetConstant &&
36-
N->getOperand(2).getValueType() == MVT::i32 &&
37-
"Expected index to be an i32 target constant!");
34+
"Expected index to be a target constant!");
3835
break;
3936
case RISCVISD::VQDOT_VL:
4037
case RISCVISD::VQDOTU_VL:
4138
case RISCVISD::VQDOTSU_VL: {
42-
assert(N->getNumValues() == 1 && "Expected one result!");
43-
assert(N->getNumOperands() == 5 && "Expected five operands!");
4439
EVT VT = N->getValueType(0);
4540
assert(VT.isScalableVector() && VT.getVectorElementType() == MVT::i32 &&
4641
"Expected result to be an i32 scalable vector");
@@ -50,13 +45,9 @@ void RISCVSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
5045
"Expected result and first 3 operands to have the same type!");
5146
EVT MaskVT = N->getOperand(3).getValueType();
5247
assert(MaskVT.isScalableVector() &&
53-
MaskVT.getVectorElementType() == MVT::i1 &&
5448
MaskVT.getVectorElementCount() == VT.getVectorElementCount() &&
5549
"Expected mask VT to be an i1 scalable vector with same number of "
5650
"elements as the result");
57-
assert((N->getOperand(4).getValueType() == MVT::i32 ||
58-
N->getOperand(4).getValueType() == MVT::i64) &&
59-
"Expect VL operand to be i32 or i64");
6051
break;
6152
}
6253
}

llvm/lib/Target/Sparc/SparcInstrInfo.td

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_SPCallSeqStart,
352352
def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_SPCallSeqEnd,
353353
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
354354

355-
def SDT_SPCall : SDTypeProfile<0, -1, [SDTCisVT<0, i32>]>;
355+
def SDT_SPCall : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>;
356356
def call : SDNode<"SPISD::CALL", SDT_SPCall,
357357
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
358358
SDNPVariadic]>;

llvm/test/TableGen/SDNodeInfoEmitter/advanced.td

Lines changed: 22 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -65,22 +65,26 @@ def my_node_3 : SDNode<
6565
// CHECK-NEXT: "MyTargetISD::NODE_3\0"
6666
// CHECK-NEXT: ;
6767

68-
// CHECK: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
69-
// CHECK-NEXT: /* 0 */ {SDTCisVT, 1, 0, MVT::i2},
70-
// CHECK-SAME: {SDTCisVT, 0, 0, MVT::i1},
71-
// CHECK-NEXT: /* 2 */ {SDTCisSameSizeAs, 19, 18, MVT::INVALID_SIMPLE_VALUE_TYPE},
72-
// CHECK-SAME: {SDTCisSameNumEltsAs, 17, 16, MVT::INVALID_SIMPLE_VALUE_TYPE},
73-
// CHECK-SAME: {SDTCVecEltisVT, 15, 0, MVT::i32},
74-
// CHECK-SAME: {SDTCisSubVecOfVec, 14, 13, MVT::INVALID_SIMPLE_VALUE_TYPE},
75-
// CHECK-SAME: {SDTCisEltOfVec, 12, 11, MVT::INVALID_SIMPLE_VALUE_TYPE},
76-
// CHECK-SAME: {SDTCisOpSmallerThanOp, 10, 9, MVT::INVALID_SIMPLE_VALUE_TYPE},
77-
// CHECK-SAME: {SDTCisVTSmallerThanOp, 8, 7, MVT::INVALID_SIMPLE_VALUE_TYPE},
78-
// CHECK-SAME: {SDTCisSameAs, 6, 5, MVT::INVALID_SIMPLE_VALUE_TYPE},
79-
// CHECK-SAME: {SDTCisVec, 4, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
80-
// CHECK-SAME: {SDTCisFP, 3, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
81-
// CHECK-SAME: {SDTCisInt, 2, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
82-
// CHECK-SAME: {SDTCisPtrTy, 1, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
83-
// CHECK-SAME: {SDTCisVT, 0, 0, MVT::i1},
68+
// CHECK: static const VTByHwModePair MyTargetVTByHwModeTable[] = {
69+
// CHECK-NEXT: /* dummy */ {0, MVT::INVALID_SIMPLE_VALUE_TYPE}
70+
// CHECK-NEXT: };
71+
// CHECK-EMPTY:
72+
// CHECK-NEXT: static const SDTypeConstraint MyTargetSDTypeConstraints[] = {
73+
// CHECK-NEXT: /* 0 */ {SDTCisVT, 1, 0, 0, MVT::i2},
74+
// CHECK-SAME: {SDTCisVT, 0, 0, 0, MVT::i1},
75+
// CHECK-NEXT: /* 2 */ {SDTCisSameSizeAs, 19, 18, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
76+
// CHECK-SAME: {SDTCisSameNumEltsAs, 17, 16, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
77+
// CHECK-SAME: {SDTCVecEltisVT, 15, 0, 0, MVT::i32},
78+
// CHECK-SAME: {SDTCisSubVecOfVec, 14, 13, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
79+
// CHECK-SAME: {SDTCisEltOfVec, 12, 11, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
80+
// CHECK-SAME: {SDTCisOpSmallerThanOp, 10, 9, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
81+
// CHECK-SAME: {SDTCisVTSmallerThanOp, 8, 7, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
82+
// CHECK-SAME: {SDTCisSameAs, 6, 5, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
83+
// CHECK-SAME: {SDTCisVec, 4, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
84+
// CHECK-SAME: {SDTCisFP, 3, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
85+
// CHECK-SAME: {SDTCisInt, 2, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
86+
// CHECK-SAME: {SDTCisPtrTy, 1, 0, 0, MVT::INVALID_SIMPLE_VALUE_TYPE},
87+
// CHECK-SAME: {SDTCisVT, 0, 0, 0, MVT::i1},
8488
// CHECK-NEXT: };
8589
// CHECK-EMPTY:
8690
// CHECK-NEXT: static const SDNodeDesc MyTargetSDNodeDescs[] = {
@@ -90,5 +94,5 @@ def my_node_3 : SDNode<
9094
// CHECK-NEXT: };
9195
// CHECK-EMPTY:
9296
// CHECK-NEXT: static const SDNodeInfo MyTargetGenSDNodeInfo(
93-
// CHECK-NEXT: /*NumOpcodes=*/3, MyTargetSDNodeDescs,
94-
// CHECK-NEXT: MyTargetSDNodeNames, MyTargetSDTypeConstraints);
97+
// CHECK-NEXT: /*NumOpcodes=*/3, MyTargetSDNodeDescs, MyTargetSDNodeNames,
98+
// CHECK-NEXT: MyTargetVTByHwModeTable, MyTargetSDTypeConstraints);

0 commit comments

Comments
 (0)