diff options
| author | Sergei Barannikov <barannikov88@gmail.com> | 2025-11-16 18:26:03 +0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2025-11-16 18:26:03 +0300 |
| commit | e413343ca7ee65ecf04fc455abb55604c7191e34 (patch) | |
| tree | 4f044992a04e16f7d9caeb5608aea9a847dd94c2 /llvm/lib/CodeGen | |
| parent | b8059e757fb95b1d3cd9b657e540bf2cd47dad82 (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.cpp | 116 |
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; + } + } } |
