summaryrefslogtreecommitdiff
path: root/llvm/lib/CodeGen
diff options
context:
space:
mode:
authorSergei Barannikov <barannikov88@gmail.com>2025-11-16 18:26:03 +0300
committerGitHub <noreply@github.com>2025-11-16 18:26:03 +0300
commite413343ca7ee65ecf04fc455abb55604c7191e34 (patch)
tree4f044992a04e16f7d9caeb5608aea9a847dd94c2 /llvm/lib/CodeGen
parentb8059e757fb95b1d3cd9b657e540bf2cd47dad82 (diff)
[SelectionDAG] Verify SDTCisVT and SDTCVecEltisVT constraints (#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: https://github.com/llvm/llvm-project/pull/150125
Diffstat (limited to 'llvm/lib/CodeGen')
-rw-r--r--llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp116
1 files changed, 116 insertions, 0 deletions
diff --git a/llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp
index e3f6c98a9a90..da763dfb212f 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp
@@ -7,7 +7,10 @@
//===----------------------------------------------------------------------===//
#include "llvm/CodeGen/SDNodeInfo.h"
+#include "llvm/CodeGen/SelectionDAG.h"
#include "llvm/CodeGen/SelectionDAGNodes.h"
+#include "llvm/CodeGen/TargetLowering.h"
+#include "llvm/CodeGen/TargetSubtargetInfo.h"
using namespace llvm;
@@ -40,6 +43,32 @@ static void checkOperandType(const SelectionDAG &DAG, const SDNode *N,
ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString());
}
+namespace {
+
+/// Similar to SDValue, but also records whether it is a result or an operand
+/// of a node so we can provide more precise diagnostics.
+class SDNodeValue {
+ const SDNode *N;
+ unsigned Idx;
+ bool IsRes;
+
+public:
+ SDNodeValue(const SDNode *N, unsigned Idx, bool IsRes)
+ : N(N), Idx(Idx), IsRes(IsRes) {}
+
+ SDValue getValue() const {
+ return IsRes ? SDValue(const_cast<SDNode *>(N), Idx) : N->getOperand(Idx);
+ }
+
+ EVT getValueType() const { return getValue().getValueType(); }
+
+ friend raw_ostream &operator<<(raw_ostream &OS, const SDNodeValue &Op) {
+ return OS << (Op.IsRes ? "result" : "operand") << " #" << Op.Idx;
+ }
+};
+
+} // namespace
+
void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
const SDNodeDesc &Desc = getDesc(N->getOpcode());
bool HasChain = Desc.hasProperty(SDNPHasChain);
@@ -125,4 +154,91 @@ void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
" must be Register or RegisterMask");
}
}
+
+ unsigned VTHwMode =
+ DAG.getSubtarget().getHwMode(MCSubtargetInfo::HwMode_ValueType);
+
+ // Returns a constrained or constraining value (result or operand) of a node.
+ // ValIdx is the index of a node's value, as defined by SDTypeConstraint;
+ // that is, it indexes a node's operands after its results and ignores
+ // chain/glue values.
+ auto GetConstraintValue = [&](unsigned ValIdx) {
+ if (ValIdx < Desc.NumResults)
+ return SDNodeValue(N, ValIdx, /*IsRes=*/true);
+ return SDNodeValue(N, HasChain + (ValIdx - Desc.NumResults),
+ /*IsRes=*/false);
+ };
+
+ auto GetConstraintVT = [&](const SDTypeConstraint &C) {
+ if (!C.NumHwModes)
+ return static_cast<MVT::SimpleValueType>(C.VT);
+ for (auto [Mode, VT] : ArrayRef(&VTByHwModeTable[C.VT], C.NumHwModes))
+ if (Mode == VTHwMode)
+ return VT;
+ llvm_unreachable("No value type for this HW mode");
+ };
+
+ SmallString<128> ES;
+ raw_svector_ostream SS(ES);
+
+ for (const SDTypeConstraint &C : getConstraints(N->getOpcode())) {
+ SDNodeValue Val = GetConstraintValue(C.ConstrainedValIdx);
+ EVT VT = Val.getValueType();
+
+ switch (C.Kind) {
+ case SDTCisVT: {
+ EVT ExpectedVT = GetConstraintVT(C);
+
+ bool IsPtr = ExpectedVT == MVT::iPTR;
+ if (IsPtr)
+ ExpectedVT =
+ DAG.getTargetLoweringInfo().getPointerTy(DAG.getDataLayout());
+
+ if (VT != ExpectedVT) {
+ SS << Val << " must have type " << ExpectedVT;
+ if (IsPtr)
+ SS << " (iPTR)";
+ SS << ", but has type " << VT;
+ reportNodeError(DAG, N, SS.str());
+ }
+ break;
+ }
+ case SDTCisPtrTy:
+ break;
+ case SDTCisInt:
+ break;
+ case SDTCisFP:
+ break;
+ case SDTCisVec:
+ break;
+ case SDTCisSameAs:
+ break;
+ case SDTCisVTSmallerThanOp:
+ break;
+ case SDTCisOpSmallerThanOp:
+ break;
+ case SDTCisEltOfVec:
+ break;
+ case SDTCisSubVecOfVec:
+ break;
+ case SDTCVecEltisVT: {
+ EVT ExpectedVT = GetConstraintVT(C);
+
+ if (!VT.isVector()) {
+ SS << Val << " must have vector type";
+ reportNodeError(DAG, N, SS.str());
+ }
+ if (VT.getVectorElementType() != ExpectedVT) {
+ SS << Val << " must have " << ExpectedVT << " element type, but has "
+ << VT.getVectorElementType() << " element type";
+ reportNodeError(DAG, N, SS.str());
+ }
+ break;
+ }
+ case SDTCisSameNumEltsAs:
+ break;
+ case SDTCisSameSizeAs:
+ break;
+ }
+ }
}