| 1 | //==------------------------------------------------------------------------==// |
| 2 | // |
| 3 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
| 4 | // See https://llvm.org/LICENSE.txt for license information. |
| 5 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
| 6 | // |
| 7 | //===----------------------------------------------------------------------===// |
| 8 | |
| 9 | #include "llvm/CodeGen/SDNodeInfo.h" |
| 10 | #include "llvm/CodeGen/SelectionDAG.h" |
| 11 | #include "llvm/CodeGen/SelectionDAGNodes.h" |
| 12 | #include "llvm/CodeGen/TargetLowering.h" |
| 13 | #include "llvm/CodeGen/TargetSubtargetInfo.h" |
| 14 | |
| 15 | using namespace llvm; |
| 16 | |
| 17 | static void reportNodeError(const SelectionDAG &DAG, const SDNode *N, |
| 18 | const Twine &Msg) { |
| 19 | std::string S; |
| 20 | raw_string_ostream SS(S); |
| 21 | SS << "invalid node: " << Msg << '\n'; |
| 22 | N->printrWithDepth(O&: SS, G: &DAG, depth: 2); |
| 23 | report_fatal_error(reason: StringRef(S)); |
| 24 | } |
| 25 | |
| 26 | static void checkResultType(const SelectionDAG &DAG, const SDNode *N, |
| 27 | unsigned ResIdx, EVT ExpectedVT) { |
| 28 | EVT ActualVT = N->getValueType(ResNo: ResIdx); |
| 29 | if (ActualVT != ExpectedVT) |
| 30 | reportNodeError( |
| 31 | DAG, N, |
| 32 | Msg: "result #" + Twine(ResIdx) + " has invalid type; expected " + |
| 33 | ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString()); |
| 34 | } |
| 35 | |
| 36 | static void checkOperandType(const SelectionDAG &DAG, const SDNode *N, |
| 37 | unsigned OpIdx, EVT ExpectedVT) { |
| 38 | EVT ActualVT = N->getOperand(Num: OpIdx).getValueType(); |
| 39 | if (ActualVT != ExpectedVT) |
| 40 | reportNodeError( |
| 41 | DAG, N, |
| 42 | Msg: "operand #" + Twine(OpIdx) + " has invalid type; expected " + |
| 43 | ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString()); |
| 44 | } |
| 45 | |
| 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(Num: 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 | |
| 72 | void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const { |
| 73 | const SDNodeDesc &Desc = getDesc(Opcode: N->getOpcode()); |
| 74 | bool HasChain = Desc.hasProperty(Property: SDNPHasChain); |
| 75 | bool HasOutGlue = Desc.hasProperty(Property: SDNPOutGlue); |
| 76 | bool HasInGlue = Desc.hasProperty(Property: SDNPInGlue); |
| 77 | bool HasOptInGlue = Desc.hasProperty(Property: SDNPOptInGlue); |
| 78 | bool IsVariadic = Desc.hasProperty(Property: SDNPVariadic); |
| 79 | |
| 80 | unsigned ActualNumResults = N->getNumValues(); |
| 81 | unsigned ExpectedNumResults = Desc.NumResults + HasChain + HasOutGlue; |
| 82 | |
| 83 | if (ActualNumResults != ExpectedNumResults) |
| 84 | reportNodeError(DAG, N, |
| 85 | Msg: "invalid number of results; expected " + |
| 86 | Twine(ExpectedNumResults) + ", got " + |
| 87 | Twine(ActualNumResults)); |
| 88 | |
| 89 | // Chain result comes after all normal results. |
| 90 | if (HasChain) { |
| 91 | unsigned ChainResIdx = Desc.NumResults; |
| 92 | checkResultType(DAG, N, ResIdx: ChainResIdx, ExpectedVT: MVT::Other); |
| 93 | } |
| 94 | |
| 95 | // Glue result comes last. |
| 96 | if (HasOutGlue) { |
| 97 | unsigned GlueResIdx = Desc.NumResults + HasChain; |
| 98 | checkResultType(DAG, N, ResIdx: GlueResIdx, ExpectedVT: MVT::Glue); |
| 99 | } |
| 100 | |
| 101 | // In the most general case, the operands of a node go in the following order: |
| 102 | // chain, fix#0, ..., fix#M-1, var#0, ... var#N-1, glue |
| 103 | // If the number of operands is < 0, M can be any; |
| 104 | // If the node has SDNPVariadic property, N can be any. |
| 105 | bool HasOptionalOperands = Desc.NumOperands < 0 || IsVariadic; |
| 106 | |
| 107 | unsigned ActualNumOperands = N->getNumOperands(); |
| 108 | unsigned ExpectedMinNumOperands = |
| 109 | (Desc.NumOperands >= 0 ? Desc.NumOperands : 0) + HasChain + HasInGlue; |
| 110 | |
| 111 | // Check the lower bound. |
| 112 | if (ActualNumOperands < ExpectedMinNumOperands) { |
| 113 | StringRef How = HasOptionalOperands ? "at least " : "" ; |
| 114 | reportNodeError(DAG, N, |
| 115 | Msg: "invalid number of operands; expected " + How + |
| 116 | Twine(ExpectedMinNumOperands) + ", got " + |
| 117 | Twine(ActualNumOperands)); |
| 118 | } |
| 119 | |
| 120 | // Check the upper bound. We can only do this if the number of fixed operands |
| 121 | // is known and there are no variadic operands. |
| 122 | if (Desc.NumOperands >= 0 && !IsVariadic) { |
| 123 | // Account for optional input glue. |
| 124 | unsigned ExpectedMaxNumOperands = ExpectedMinNumOperands + HasOptInGlue; |
| 125 | if (ActualNumOperands > ExpectedMaxNumOperands) { |
| 126 | StringRef How = HasOptInGlue ? "at most " : "" ; |
| 127 | reportNodeError(DAG, N, |
| 128 | Msg: "invalid number of operands; expected " + How + |
| 129 | Twine(ExpectedMaxNumOperands) + ", got " + |
| 130 | Twine(ActualNumOperands)); |
| 131 | } |
| 132 | } |
| 133 | |
| 134 | // Chain operand comes first. |
| 135 | if (HasChain) |
| 136 | checkOperandType(DAG, N, OpIdx: 0, ExpectedVT: MVT::Other); |
| 137 | |
| 138 | // Glue operand comes last. |
| 139 | if (HasInGlue) |
| 140 | checkOperandType(DAG, N, OpIdx: ActualNumOperands - 1, ExpectedVT: MVT::Glue); |
| 141 | if (HasOptInGlue && ActualNumOperands >= 1 && |
| 142 | N->getOperand(Num: ActualNumOperands - 1).getValueType() == MVT::Glue) |
| 143 | HasInGlue = true; |
| 144 | |
| 145 | // Check variadic operands. These should be Register or RegisterMask. |
| 146 | if (IsVariadic && Desc.NumOperands >= 0) { |
| 147 | unsigned VarOpStart = HasChain + Desc.NumOperands; |
| 148 | unsigned VarOpEnd = ActualNumOperands - HasInGlue; |
| 149 | for (unsigned OpIdx = VarOpStart; OpIdx != VarOpEnd; ++OpIdx) { |
| 150 | unsigned OpOpcode = N->getOperand(Num: OpIdx).getOpcode(); |
| 151 | if (OpOpcode != ISD::Register && OpOpcode != ISD::RegisterMask) |
| 152 | reportNodeError(DAG, N, |
| 153 | Msg: "variadic operand #" + Twine(OpIdx) + |
| 154 | " must be Register or RegisterMask" ); |
| 155 | } |
| 156 | } |
| 157 | |
| 158 | unsigned VTHwMode = |
| 159 | DAG.getSubtarget().getHwMode(type: 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(Opcode: 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(DL: 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, Msg: 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, Msg: 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, Msg: SS.str()); |
| 235 | } |
| 236 | break; |
| 237 | } |
| 238 | case SDTCisSameNumEltsAs: |
| 239 | break; |
| 240 | case SDTCisSameSizeAs: |
| 241 | break; |
| 242 | } |
| 243 | } |
| 244 | } |
| 245 | |