Skip to content

Commit e413343

Browse files
authored
[SelectionDAG] Verify SDTCisVT and SDTCVecEltisVT constraints (llvm#150125)
Teach `SDNodeInfoEmitter` TableGen backend to process `SDTypeConstraint` records and emit tables for them. The tables are used by `SDNodeInfo::verifyNode()` to validate a node being created. This PR only adds validation code for `SDTCisVT` and `SDTCVecEltisVT` constraints to keep it smaller. Pull Request: llvm#150125
1 parent b8059e7 commit e413343

File tree

20 files changed

+359
-107
lines changed

20 files changed

+359
-107
lines changed

llvm/include/llvm/CodeGen/SDNodeInfo.h

Lines changed: 17 additions & 5 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;
53-
uint8_t OpNo;
54-
uint8_t OtherOpNo;
55-
MVT::SimpleValueType VT;
58+
uint8_t ConstrainedValIdx;
59+
uint8_t ConstrainingValIdx;
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: 116 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,32 @@ static void checkOperandType(const SelectionDAG &DAG, const SDNode *N,
4043
ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString());
4144
}
4245

46+
namespace {
47+
48+
/// Similar to SDValue, but also records whether it is a result or an operand
49+
/// of a node so we can provide more precise diagnostics.
50+
class SDNodeValue {
51+
const SDNode *N;
52+
unsigned Idx;
53+
bool IsRes;
54+
55+
public:
56+
SDNodeValue(const SDNode *N, unsigned Idx, bool IsRes)
57+
: N(N), Idx(Idx), IsRes(IsRes) {}
58+
59+
SDValue getValue() const {
60+
return IsRes ? SDValue(const_cast<SDNode *>(N), Idx) : N->getOperand(Idx);
61+
}
62+
63+
EVT getValueType() const { return getValue().getValueType(); }
64+
65+
friend raw_ostream &operator<<(raw_ostream &OS, const SDNodeValue &Op) {
66+
return OS << (Op.IsRes ? "result" : "operand") << " #" << Op.Idx;
67+
}
68+
};
69+
70+
} // namespace
71+
4372
void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
4473
const SDNodeDesc &Desc = getDesc(N->getOpcode());
4574
bool HasChain = Desc.hasProperty(SDNPHasChain);
@@ -125,4 +154,91 @@ void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
125154
" must be Register or RegisterMask");
126155
}
127156
}
157+
158+
unsigned VTHwMode =
159+
DAG.getSubtarget().getHwMode(MCSubtargetInfo::HwMode_ValueType);
160+
161+
// Returns a constrained or constraining value (result or operand) of a node.
162+
// ValIdx is the index of a node's value, as defined by SDTypeConstraint;
163+
// that is, it indexes a node's operands after its results and ignores
164+
// chain/glue values.
165+
auto GetConstraintValue = [&](unsigned ValIdx) {
166+
if (ValIdx < Desc.NumResults)
167+
return SDNodeValue(N, ValIdx, /*IsRes=*/true);
168+
return SDNodeValue(N, HasChain + (ValIdx - Desc.NumResults),
169+
/*IsRes=*/false);
170+
};
171+
172+
auto GetConstraintVT = [&](const SDTypeConstraint &C) {
173+
if (!C.NumHwModes)
174+
return static_cast<MVT::SimpleValueType>(C.VT);
175+
for (auto [Mode, VT] : ArrayRef(&VTByHwModeTable[C.VT], C.NumHwModes))
176+
if (Mode == VTHwMode)
177+
return VT;
178+
llvm_unreachable("No value type for this HW mode");
179+
};
180+
181+
SmallString<128> ES;
182+
raw_svector_ostream SS(ES);
183+
184+
for (const SDTypeConstraint &C : getConstraints(N->getOpcode())) {
185+
SDNodeValue Val = GetConstraintValue(C.ConstrainedValIdx);
186+
EVT VT = Val.getValueType();
187+
188+
switch (C.Kind) {
189+
case SDTCisVT: {
190+
EVT ExpectedVT = GetConstraintVT(C);
191+
192+
bool IsPtr = ExpectedVT == MVT::iPTR;
193+
if (IsPtr)
194+
ExpectedVT =
195+
DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
196+
197+
if (VT != ExpectedVT) {
198+
SS << Val << " must have type " << ExpectedVT;
199+
if (IsPtr)
200+
SS << " (iPTR)";
201+
SS << ", but has type " << VT;
202+
reportNodeError(DAG, N, SS.str());
203+
}
204+
break;
205+
}
206+
case SDTCisPtrTy:
207+
break;
208+
case SDTCisInt:
209+
break;
210+
case SDTCisFP:
211+
break;
212+
case SDTCisVec:
213+
break;
214+
case SDTCisSameAs:
215+
break;
216+
case SDTCisVTSmallerThanOp:
217+
break;
218+
case SDTCisOpSmallerThanOp:
219+
break;
220+
case SDTCisEltOfVec:
221+
break;
222+
case SDTCisSubVecOfVec:
223+
break;
224+
case SDTCVecEltisVT: {
225+
EVT ExpectedVT = GetConstraintVT(C);
226+
227+
if (!VT.isVector()) {
228+
SS << Val << " must have vector type";
229+
reportNodeError(DAG, N, SS.str());
230+
}
231+
if (VT.getVectorElementType() != ExpectedVT) {
232+
SS << Val << " must have " << ExpectedVT << " element type, but has "
233+
<< VT.getVectorElementType() << " element type";
234+
reportNodeError(DAG, N, SS.str());
235+
}
236+
break;
237+
}
238+
case SDTCisSameNumEltsAs:
239+
break;
240+
case SDTCisSameSizeAs:
241+
break;
242+
}
243+
}
128244
}

llvm/lib/Target/AArch64/AArch64InstrInfo.td

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

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

llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.cpp

Lines changed: 8 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,35 +32,21 @@ AArch64SelectionDAGInfo::AArch64SelectionDAGInfo()
3232

3333
void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
3434
const SDNode *N) const {
35+
switch (N->getOpcode()) {
36+
case AArch64ISD::WrapperLarge:
37+
// operand #0 must have type i32, but has type i64
38+
return;
39+
}
40+
3541
SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
3642

3743
#ifndef NDEBUG
3844
// Some additional checks not yet implemented by verifyTargetNode.
39-
constexpr MVT FlagsVT = MVT::i32;
4045
switch (N->getOpcode()) {
41-
case AArch64ISD::SUBS:
42-
assert(N->getValueType(1) == FlagsVT);
43-
break;
44-
case AArch64ISD::ADC:
45-
case AArch64ISD::SBC:
46-
assert(N->getOperand(2).getValueType() == FlagsVT);
47-
break;
48-
case AArch64ISD::ADCS:
49-
case AArch64ISD::SBCS:
50-
assert(N->getValueType(1) == FlagsVT);
51-
assert(N->getOperand(2).getValueType() == FlagsVT);
52-
break;
53-
case AArch64ISD::CSEL:
54-
case AArch64ISD::CSINC:
55-
case AArch64ISD::BRCOND:
56-
assert(N->getOperand(3).getValueType() == FlagsVT);
57-
break;
5846
case AArch64ISD::SADDWT:
5947
case AArch64ISD::SADDWB:
6048
case AArch64ISD::UADDWT:
6149
case AArch64ISD::UADDWB: {
62-
assert(N->getNumValues() == 1 && "Expected one result!");
63-
assert(N->getNumOperands() == 2 && "Expected two operands!");
6450
EVT VT = N->getValueType(0);
6551
EVT Op0VT = N->getOperand(0).getValueType();
6652
EVT Op1VT = N->getOperand(1).getValueType();
@@ -80,8 +66,6 @@ void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
8066
case AArch64ISD::SUNPKHI:
8167
case AArch64ISD::UUNPKLO:
8268
case AArch64ISD::UUNPKHI: {
83-
assert(N->getNumValues() == 1 && "Expected one result!");
84-
assert(N->getNumOperands() == 1 && "Expected one operand!");
8569
EVT VT = N->getValueType(0);
8670
EVT OpVT = N->getOperand(0).getValueType();
8771
assert(OpVT.isVector() && VT.isVector() && OpVT.isInteger() &&
@@ -98,8 +82,6 @@ void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
9882
case AArch64ISD::UZP2:
9983
case AArch64ISD::ZIP1:
10084
case AArch64ISD::ZIP2: {
101-
assert(N->getNumValues() == 1 && "Expected one result!");
102-
assert(N->getNumOperands() == 2 && "Expected two operands!");
10385
EVT VT = N->getValueType(0);
10486
EVT Op0VT = N->getOperand(0).getValueType();
10587
EVT Op1VT = N->getOperand(1).getValueType();
@@ -109,11 +91,8 @@ void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
10991
break;
11092
}
11193
case AArch64ISD::RSHRNB_I: {
112-
assert(N->getNumValues() == 1 && "Expected one result!");
113-
assert(N->getNumOperands() == 2 && "Expected two operands!");
11494
EVT VT = N->getValueType(0);
11595
EVT Op0VT = N->getOperand(0).getValueType();
116-
EVT Op1VT = N->getOperand(1).getValueType();
11796
assert(VT.isVector() && VT.isInteger() &&
11897
"Expected integer vector result type!");
11998
assert(Op0VT.isVector() && Op0VT.isInteger() &&
@@ -122,8 +101,8 @@ void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
122101
"Expected vectors of equal size!");
123102
assert(VT.getVectorElementCount() == Op0VT.getVectorElementCount() * 2 &&
124103
"Expected input vector with half the lanes of its result!");
125-
assert(Op1VT == MVT::i32 && isa<ConstantSDNode>(N->getOperand(1)) &&
126-
"Expected second operand to be a constant i32!");
104+
assert(isa<ConstantSDNode>(N->getOperand(1)) &&
105+
"Expected second operand to be a constant!");
127106
break;
128107
}
129108
}

llvm/lib/Target/M68k/M68kISelLowering.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1664,7 +1664,7 @@ static SDValue getBitTestCondition(SDValue Src, SDValue BitNo, ISD::CondCode CC,
16641664
if (Src.getValueType() != BitNo.getValueType())
16651665
BitNo = DAG.getNode(ISD::ANY_EXTEND, DL, Src.getValueType(), BitNo);
16661666

1667-
SDValue BTST = DAG.getNode(M68kISD::BTST, DL, MVT::i32, Src, BitNo);
1667+
SDValue BTST = DAG.getNode(M68kISD::BTST, DL, MVT::i8, Src, BitNo);
16681668

16691669
// NOTE BTST sets CCR.Z flag if bit is 0, same as AND with bitmask
16701670
M68k::CondCode Cond = CC == ISD::SETEQ ? M68k::COND_EQ : M68k::COND_NE;

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
@@ -22,27 +22,22 @@ RISCVSelectionDAGInfo::~RISCVSelectionDAGInfo() = default;
2222

2323
void RISCVSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
2424
const SDNode *N) const {
25+
SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
26+
2527
#ifndef NDEBUG
28+
// Some additional checks not yet implemented by verifyTargetNode.
2629
switch (N->getOpcode()) {
27-
default:
28-
return SelectionDAGGenTargetInfo::verifyTargetNode(DAG, N);
2930
case RISCVISD::TUPLE_EXTRACT:
30-
assert(N->getNumOperands() == 2 && "Expected three operands!");
3131
assert(N->getOperand(1).getOpcode() == ISD::TargetConstant &&
32-
N->getOperand(1).getValueType() == MVT::i32 &&
33-
"Expected index to be an i32 target constant!");
32+
"Expected index to be a target constant!");
3433
break;
3534
case RISCVISD::TUPLE_INSERT:
36-
assert(N->getNumOperands() == 3 && "Expected three operands!");
3735
assert(N->getOperand(2).getOpcode() == ISD::TargetConstant &&
38-
N->getOperand(2).getValueType() == MVT::i32 &&
39-
"Expected index to be an i32 target constant!");
36+
"Expected index to be a target constant!");
4037
break;
4138
case RISCVISD::VQDOT_VL:
4239
case RISCVISD::VQDOTU_VL:
4340
case RISCVISD::VQDOTSU_VL: {
44-
assert(N->getNumValues() == 1 && "Expected one result!");
45-
assert(N->getNumOperands() == 5 && "Expected five operands!");
4641
EVT VT = N->getValueType(0);
4742
assert(VT.isScalableVector() && VT.getVectorElementType() == MVT::i32 &&
4843
"Expected result to be an i32 scalable vector");
@@ -52,13 +47,9 @@ void RISCVSelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG,
5247
"Expected result and first 3 operands to have the same type!");
5348
EVT MaskVT = N->getOperand(3).getValueType();
5449
assert(MaskVT.isScalableVector() &&
55-
MaskVT.getVectorElementType() == MVT::i1 &&
5650
MaskVT.getVectorElementCount() == VT.getVectorElementCount() &&
5751
"Expected mask VT to be an i1 scalable vector with same number of "
5852
"elements as the result");
59-
assert((N->getOperand(4).getValueType() == MVT::i32 ||
60-
N->getOperand(4).getValueType() == MVT::i64) &&
61-
"Expect VL operand to be i32 or i64");
6253
break;
6354
}
6455
}

llvm/lib/Target/Sparc/SparcInstrInfo.td

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

372-
def SDT_SPCall : SDTypeProfile<0, -1, [SDTCisVT<0, i32>]>;
372+
def SDT_SPCall : SDTypeProfile<0, -1, [SDTCisVT<0, iPTR>]>;
373373
def call : SDNode<"SPISD::CALL", SDT_SPCall,
374374
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
375375
SDNPVariadic]>;

0 commit comments

Comments
 (0)