diff --git a/llvm/include/llvm/CodeGen/SDNodeInfo.h b/llvm/include/llvm/CodeGen/SDNodeInfo.h new file mode 100644 index 0000000000000..3992db31638b8 --- /dev/null +++ b/llvm/include/llvm/CodeGen/SDNodeInfo.h @@ -0,0 +1,115 @@ +//==------------------------------------------------------------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_CODEGEN_SDNODEINFO_H +#define LLVM_CODEGEN_SDNODEINFO_H + +#include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/StringTable.h" +#include "llvm/CodeGen/ISDOpcodes.h" +#include "llvm/CodeGenTypes/MachineValueType.h" + +namespace llvm { + +class SDNode; +class SelectionDAG; + +enum SDNP { + SDNPHasChain, + SDNPOutGlue, + SDNPInGlue, + SDNPOptInGlue, + SDNPMemOperand, + SDNPVariadic, +}; + +enum SDTC : uint8_t { + SDTCisVT, + SDTCisPtrTy, + SDTCisInt, + SDTCisFP, + SDTCisVec, + SDTCisSameAs, + SDTCisVTSmallerThanOp, + SDTCisOpSmallerThanOp, + SDTCisEltOfVec, + SDTCisSubVecOfVec, + SDTCVecEltisVT, + SDTCisSameNumEltsAs, + SDTCisSameSizeAs, +}; + +enum SDNF { + SDNFIsStrictFP, +}; + +struct SDTypeConstraint { + SDTC Kind; + uint8_t OpNo; + uint8_t OtherOpNo; + MVT::SimpleValueType VT; +}; + +struct SDNodeDesc { + uint16_t NumResults; + int16_t NumOperands; + uint32_t Properties; + uint32_t Flags; + uint32_t TSFlags; + unsigned NameOffset; + unsigned ConstraintOffset; + unsigned ConstraintCount; + + bool hasProperty(SDNP Property) const { return Properties & (1 << Property); } + + bool hasFlag(SDNF Flag) const { return Flags & (1 << Flag); } +}; + +class SDNodeInfo final { + unsigned NumOpcodes; + const SDNodeDesc *Descs; + StringTable Names; + const SDTypeConstraint *Constraints; + +public: + constexpr SDNodeInfo(unsigned NumOpcodes, const SDNodeDesc *Descs, + StringTable Names, const SDTypeConstraint *Constraints) + : NumOpcodes(NumOpcodes), Descs(Descs), Names(Names), + Constraints(Constraints) {} + + /// Returns true if there is a generated description for a node with the given + /// target-specific opcode. + bool hasDesc(unsigned Opcode) const { + assert(Opcode >= ISD::BUILTIN_OP_END && "Expected target-specific opcode"); + return Opcode < ISD::BUILTIN_OP_END + NumOpcodes; + } + + /// Returns the description of a node with the given opcode. + const SDNodeDesc &getDesc(unsigned Opcode) const { + assert(hasDesc(Opcode)); + return Descs[Opcode - ISD::BUILTIN_OP_END]; + } + + /// Returns operand constraints for a node with the given opcode. + ArrayRef getConstraints(unsigned Opcode) const { + const SDNodeDesc &Desc = getDesc(Opcode); + return ArrayRef(&Constraints[Desc.ConstraintOffset], Desc.ConstraintCount); + } + + /// Returns the name of the given target-specific opcode, suitable for + /// debug printing. + StringRef getName(unsigned Opcode) const { + return Names[getDesc(Opcode).NameOffset]; + } + + void verifyNode(const SelectionDAG &DAG, const SDNode *N) const; +}; + +} // namespace llvm + +#endif // LLVM_CODEGEN_SDNODEINFO_H diff --git a/llvm/include/llvm/CodeGen/SelectionDAG.h b/llvm/include/llvm/CodeGen/SelectionDAG.h index 15a2370e5d8b8..d06e2b19fa0b5 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAG.h +++ b/llvm/include/llvm/CodeGen/SelectionDAG.h @@ -2445,6 +2445,9 @@ class SelectionDAG { const SDLoc &DLoc); private: +#ifndef NDEBUG + void verifyNode(SDNode *N) const; +#endif void InsertNode(SDNode *N); bool RemoveNodeFromCSEMaps(SDNode *N); void AddModifiedNodeToCSEMaps(SDNode *N); diff --git a/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h b/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h index ef5ae5dba58de..463f0ec350d9c 100644 --- a/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h +++ b/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h @@ -16,6 +16,7 @@ #define LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H #include "llvm/CodeGen/MachineMemOperand.h" +#include "llvm/CodeGen/SDNodeInfo.h" #include "llvm/CodeGen/SelectionDAGNodes.h" #include "llvm/Support/CodeGen.h" #include @@ -35,6 +36,12 @@ class SelectionDAGTargetInfo { SelectionDAGTargetInfo &operator=(const SelectionDAGTargetInfo &) = delete; virtual ~SelectionDAGTargetInfo(); + /// Returns the name of the given target-specific opcode, suitable for + /// debug printing. + virtual const char *getTargetNodeName(unsigned Opcode) const { + return nullptr; + } + /// Returns true if a node with the given target-specific opcode has /// a memory operand. Nodes with such opcodes can only be created with /// `SelectionDAG::getMemIntrinsicNode`. @@ -48,6 +55,10 @@ class SelectionDAGTargetInfo { /// may raise a floating-point exception. virtual bool mayRaiseFPException(unsigned Opcode) const; + /// Checks that the given target-specific node is valid. Aborts if it is not. + virtual void verifyTargetNode(const SelectionDAG &DAG, + const SDNode *N) const {} + /// Emit target-specific code that performs a memcpy. /// This can be used by targets to provide code sequences for cases /// that don't fit the target's parameters for simple loads/stores and can be @@ -176,6 +187,43 @@ class SelectionDAGTargetInfo { } }; +/// Proxy class that targets should inherit from if they wish to use +/// the generated node descriptions. +class SelectionDAGGenTargetInfo : public SelectionDAGTargetInfo { +protected: + const SDNodeInfo &GenNodeInfo; + + explicit SelectionDAGGenTargetInfo(const SDNodeInfo &GenNodeInfo) + : GenNodeInfo(GenNodeInfo) {} + +public: + ~SelectionDAGGenTargetInfo() override; + + const char *getTargetNodeName(unsigned Opcode) const override { + assert(GenNodeInfo.hasDesc(Opcode) && + "The name should be provided by the derived class"); + return GenNodeInfo.getName(Opcode).data(); + } + + bool isTargetMemoryOpcode(unsigned Opcode) const override { + if (GenNodeInfo.hasDesc(Opcode)) + return GenNodeInfo.getDesc(Opcode).hasProperty(SDNPMemOperand); + return false; + } + + bool isTargetStrictFPOpcode(unsigned Opcode) const override { + if (GenNodeInfo.hasDesc(Opcode)) + return GenNodeInfo.getDesc(Opcode).hasFlag(SDNFIsStrictFP); + return false; + } + + void verifyTargetNode(const SelectionDAG &DAG, + const SDNode *N) const override { + if (GenNodeInfo.hasDesc(N->getOpcode())) + GenNodeInfo.verifyNode(DAG, N); + } +}; + } // end namespace llvm #endif // LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H diff --git a/llvm/include/llvm/CodeGen/TargetLowering.h b/llvm/include/llvm/CodeGen/TargetLowering.h index 29bf1d467ae0e..16066226f1896 100644 --- a/llvm/include/llvm/CodeGen/TargetLowering.h +++ b/llvm/include/llvm/CodeGen/TargetLowering.h @@ -4989,11 +4989,6 @@ class TargetLowering : public TargetLoweringBase { bool verifyReturnAddressArgumentIsConstant(SDValue Op, SelectionDAG &DAG) const; -#ifndef NDEBUG - /// Check the given SDNode. Aborts if it is invalid. - virtual void verifyTargetSDNode(const SDNode *N) const {}; -#endif - //===--------------------------------------------------------------------===// // Inline Asm Support hooks // diff --git a/llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt b/llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt index cbfbfa3a321bc..93a742a19aa79 100644 --- a/llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt +++ b/llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt @@ -11,6 +11,7 @@ add_llvm_component_library(LLVMSelectionDAG LegalizeVectorOps.cpp LegalizeVectorTypes.cpp ResourcePriorityQueue.cpp + SDNodeInfo.cpp ScheduleDAGFast.cpp ScheduleDAGRRList.cpp ScheduleDAGSDNodes.cpp diff --git a/llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp new file mode 100644 index 0000000000000..e3f6c98a9a90a --- /dev/null +++ b/llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp @@ -0,0 +1,128 @@ +//==------------------------------------------------------------------------==// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/CodeGen/SDNodeInfo.h" +#include "llvm/CodeGen/SelectionDAGNodes.h" + +using namespace llvm; + +static void reportNodeError(const SelectionDAG &DAG, const SDNode *N, + const Twine &Msg) { + std::string S; + raw_string_ostream SS(S); + SS << "invalid node: " << Msg << '\n'; + N->printrWithDepth(SS, &DAG, 2); + report_fatal_error(StringRef(S)); +} + +static void checkResultType(const SelectionDAG &DAG, const SDNode *N, + unsigned ResIdx, EVT ExpectedVT) { + EVT ActualVT = N->getValueType(ResIdx); + if (ActualVT != ExpectedVT) + reportNodeError( + DAG, N, + "result #" + Twine(ResIdx) + " has invalid type; expected " + + ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString()); +} + +static void checkOperandType(const SelectionDAG &DAG, const SDNode *N, + unsigned OpIdx, EVT ExpectedVT) { + EVT ActualVT = N->getOperand(OpIdx).getValueType(); + if (ActualVT != ExpectedVT) + reportNodeError( + DAG, N, + "operand #" + Twine(OpIdx) + " has invalid type; expected " + + ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString()); +} + +void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const { + const SDNodeDesc &Desc = getDesc(N->getOpcode()); + bool HasChain = Desc.hasProperty(SDNPHasChain); + bool HasOutGlue = Desc.hasProperty(SDNPOutGlue); + bool HasInGlue = Desc.hasProperty(SDNPInGlue); + bool HasOptInGlue = Desc.hasProperty(SDNPOptInGlue); + bool IsVariadic = Desc.hasProperty(SDNPVariadic); + + unsigned ActualNumResults = N->getNumValues(); + unsigned ExpectedNumResults = Desc.NumResults + HasChain + HasOutGlue; + + if (ActualNumResults != ExpectedNumResults) + reportNodeError(DAG, N, + "invalid number of results; expected " + + Twine(ExpectedNumResults) + ", got " + + Twine(ActualNumResults)); + + // Chain result comes after all normal results. + if (HasChain) { + unsigned ChainResIdx = Desc.NumResults; + checkResultType(DAG, N, ChainResIdx, MVT::Other); + } + + // Glue result comes last. + if (HasOutGlue) { + unsigned GlueResIdx = Desc.NumResults + HasChain; + checkResultType(DAG, N, GlueResIdx, MVT::Glue); + } + + // In the most general case, the operands of a node go in the following order: + // chain, fix#0, ..., fix#M-1, var#0, ... var#N-1, glue + // If the number of operands is < 0, M can be any; + // If the node has SDNPVariadic property, N can be any. + bool HasOptionalOperands = Desc.NumOperands < 0 || IsVariadic; + + unsigned ActualNumOperands = N->getNumOperands(); + unsigned ExpectedMinNumOperands = + (Desc.NumOperands >= 0 ? Desc.NumOperands : 0) + HasChain + HasInGlue; + + // Check the lower bound. + if (ActualNumOperands < ExpectedMinNumOperands) { + StringRef How = HasOptionalOperands ? "at least " : ""; + reportNodeError(DAG, N, + "invalid number of operands; expected " + How + + Twine(ExpectedMinNumOperands) + ", got " + + Twine(ActualNumOperands)); + } + + // Check the upper bound. We can only do this if the number of fixed operands + // is known and there are no variadic operands. + if (Desc.NumOperands >= 0 && !IsVariadic) { + // Account for optional input glue. + unsigned ExpectedMaxNumOperands = ExpectedMinNumOperands + HasOptInGlue; + if (ActualNumOperands > ExpectedMaxNumOperands) { + StringRef How = HasOptInGlue ? "at most " : ""; + reportNodeError(DAG, N, + "invalid number of operands; expected " + How + + Twine(ExpectedMaxNumOperands) + ", got " + + Twine(ActualNumOperands)); + } + } + + // Chain operand comes first. + if (HasChain) + checkOperandType(DAG, N, 0, MVT::Other); + + // Glue operand comes last. + if (HasInGlue) + checkOperandType(DAG, N, ActualNumOperands - 1, MVT::Glue); + if (HasOptInGlue && ActualNumOperands >= 1 && + N->getOperand(ActualNumOperands - 1).getValueType() == MVT::Glue) + HasInGlue = true; + + // Check variadic operands. These should be Register or RegisterMask. + if (IsVariadic && Desc.NumOperands >= 0) { + unsigned VarOpStart = HasChain + Desc.NumOperands; + unsigned VarOpEnd = ActualNumOperands - HasInGlue; + for (unsigned OpIdx = VarOpStart; OpIdx != VarOpEnd; ++OpIdx) { + unsigned OpOpcode = N->getOperand(OpIdx).getOpcode(); + if (OpOpcode != ISD::Register && OpOpcode != ISD::RegisterMask) + reportNodeError(DAG, N, + "variadic operand #" + Twine(OpIdx) + + " must be Register or RegisterMask"); + } + } +} diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp index 69548d0462318..f2777bbf247b0 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp @@ -1146,11 +1146,11 @@ void SelectionDAG::DeallocateNode(SDNode *N) { #ifndef NDEBUG /// VerifySDNode - Check the given SDNode. Aborts if it is invalid. -static void VerifySDNode(SDNode *N, const TargetLowering *TLI) { +void SelectionDAG::verifyNode(SDNode *N) const { switch (N->getOpcode()) { default: - if (N->getOpcode() > ISD::BUILTIN_OP_END) - TLI->verifyTargetSDNode(N); + if (N->isTargetOpcode()) + getSelectionDAGInfo().verifyTargetNode(*this, N); break; case ISD::BUILD_PAIR: { EVT VT = N->getValueType(0); @@ -1194,7 +1194,7 @@ void SelectionDAG::InsertNode(SDNode *N) { AllNodes.push_back(N); #ifndef NDEBUG N->PersistentId = NextPersistentId++; - VerifySDNode(N, TLI); + verifyNode(N); #endif for (DAGUpdateListener *DUL = UpdateListeners; DUL; DUL = DUL->Next) DUL->NodeInserted(N); diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp index 64ecff8d71f98..958c070ed50de 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp @@ -21,6 +21,7 @@ #include "llvm/CodeGen/MachineMemOperand.h" #include "llvm/CodeGen/SelectionDAG.h" #include "llvm/CodeGen/SelectionDAGNodes.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/CodeGen/TargetInstrInfo.h" #include "llvm/CodeGen/TargetLowering.h" #include "llvm/CodeGen/TargetRegisterInfo.h" @@ -67,6 +68,9 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const { return "<>"; } if (G) { + const SelectionDAGTargetInfo &TSI = G->getSelectionDAGInfo(); + if (const char *Name = TSI.getTargetNodeName(getOpcode())) + return Name; const TargetLowering &TLI = G->getTargetLoweringInfo(); const char *Name = TLI.getTargetNodeName(getOpcode()); if (Name) return Name; diff --git a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGTargetInfo.cpp b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGTargetInfo.cpp index 0f3b36658f10a..f4422a15bf9df 100644 --- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAGTargetInfo.cpp +++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAGTargetInfo.cpp @@ -16,6 +16,8 @@ using namespace llvm; SelectionDAGTargetInfo::~SelectionDAGTargetInfo() = default; +SelectionDAGGenTargetInfo::~SelectionDAGGenTargetInfo() = default; + bool SelectionDAGTargetInfo::mayRaiseFPException(unsigned Opcode) const { // FIXME: All target memory opcodes are currently automatically considered // to possibly raise FP exceptions. See rev. 63336795. diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index a1ba3922996a1..0534d2d546325 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -30223,83 +30223,3 @@ bool AArch64TargetLowering::isTypeDesirableForOp(unsigned Opc, EVT VT) const { return TargetLowering::isTypeDesirableForOp(Opc, VT); } - -#ifndef NDEBUG -void AArch64TargetLowering::verifyTargetSDNode(const SDNode *N) const { - switch (N->getOpcode()) { - default: - break; - case AArch64ISD::SADDWT: - case AArch64ISD::SADDWB: - case AArch64ISD::UADDWT: - case AArch64ISD::UADDWB: { - assert(N->getNumValues() == 1 && "Expected one result!"); - assert(N->getNumOperands() == 2 && "Expected two operands!"); - EVT VT = N->getValueType(0); - EVT Op0VT = N->getOperand(0).getValueType(); - EVT Op1VT = N->getOperand(1).getValueType(); - assert(VT.isVector() && Op0VT.isVector() && Op1VT.isVector() && - VT.isInteger() && Op0VT.isInteger() && Op1VT.isInteger() && - "Expected integer vectors!"); - assert(VT == Op0VT && - "Expected result and first input to have the same type!"); - assert(Op0VT.getSizeInBits() == Op1VT.getSizeInBits() && - "Expected vectors of equal size!"); - assert(Op0VT.getVectorElementCount() * 2 == Op1VT.getVectorElementCount() && - "Expected result vector and first input vector to have half the " - "lanes of the second input vector!"); - break; - } - case AArch64ISD::SUNPKLO: - case AArch64ISD::SUNPKHI: - case AArch64ISD::UUNPKLO: - case AArch64ISD::UUNPKHI: { - assert(N->getNumValues() == 1 && "Expected one result!"); - assert(N->getNumOperands() == 1 && "Expected one operand!"); - EVT VT = N->getValueType(0); - EVT OpVT = N->getOperand(0).getValueType(); - assert(OpVT.isVector() && VT.isVector() && OpVT.isInteger() && - VT.isInteger() && "Expected integer vectors!"); - assert(OpVT.getSizeInBits() == VT.getSizeInBits() && - "Expected vectors of equal size!"); - assert(OpVT.getVectorElementCount() == VT.getVectorElementCount() * 2 && - "Expected result vector with half the lanes of its input!"); - break; - } - case AArch64ISD::TRN1: - case AArch64ISD::TRN2: - case AArch64ISD::UZP1: - case AArch64ISD::UZP2: - case AArch64ISD::ZIP1: - case AArch64ISD::ZIP2: { - assert(N->getNumValues() == 1 && "Expected one result!"); - assert(N->getNumOperands() == 2 && "Expected two operands!"); - EVT VT = N->getValueType(0); - EVT Op0VT = N->getOperand(0).getValueType(); - EVT Op1VT = N->getOperand(1).getValueType(); - assert(VT.isVector() && Op0VT.isVector() && Op1VT.isVector() && - "Expected vectors!"); - assert(VT == Op0VT && VT == Op1VT && "Expected matching vectors!"); - break; - } - case AArch64ISD::RSHRNB_I: { - assert(N->getNumValues() == 1 && "Expected one result!"); - assert(N->getNumOperands() == 2 && "Expected two operands!"); - EVT VT = N->getValueType(0); - EVT Op0VT = N->getOperand(0).getValueType(); - EVT Op1VT = N->getOperand(1).getValueType(); - assert(VT.isVector() && VT.isInteger() && - "Expected integer vector result type!"); - assert(Op0VT.isVector() && Op0VT.isInteger() && - "Expected first operand to be an integer vector!"); - assert(VT.getSizeInBits() == Op0VT.getSizeInBits() && - "Expected vectors of equal size!"); - assert(VT.getVectorElementCount() == Op0VT.getVectorElementCount() * 2 && - "Expected input vector with half the lanes of its result!"); - assert(Op1VT == MVT::i32 && isa(N->getOperand(1)) && - "Expected second operand to be a constant i32!"); - break; - } - } -} -#endif diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.h b/llvm/lib/Target/AArch64/AArch64ISelLowering.h index ba275e18fa126..0d51ef2be8631 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h @@ -1038,10 +1038,6 @@ class AArch64TargetLowering : public TargetLowering { /// True if stack clash protection is enabled for this functions. bool hasInlineStackProbe(const MachineFunction &MF) const override; -#ifndef NDEBUG - void verifyTargetSDNode(const SDNode *N) const override; -#endif - private: /// Keep a pointer to the AArch64Subtarget around so that we can /// make the right decision when generating code for different targets. diff --git a/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.cpp b/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.cpp index 17adda15d9fc8..da2cd1ada3653 100644 --- a/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.cpp +++ b/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.cpp @@ -33,6 +33,85 @@ bool AArch64SelectionDAGInfo::isTargetStrictFPOpcode(unsigned Opcode) const { Opcode <= AArch64ISD::LAST_STRICTFP_OPCODE; } +void AArch64SelectionDAGInfo::verifyTargetNode(const SelectionDAG &DAG, + const SDNode *N) const { + switch (N->getOpcode()) { + default: + break; + case AArch64ISD::SADDWT: + case AArch64ISD::SADDWB: + case AArch64ISD::UADDWT: + case AArch64ISD::UADDWB: { + assert(N->getNumValues() == 1 && "Expected one result!"); + assert(N->getNumOperands() == 2 && "Expected two operands!"); + EVT VT = N->getValueType(0); + EVT Op0VT = N->getOperand(0).getValueType(); + EVT Op1VT = N->getOperand(1).getValueType(); + assert(VT.isVector() && Op0VT.isVector() && Op1VT.isVector() && + VT.isInteger() && Op0VT.isInteger() && Op1VT.isInteger() && + "Expected integer vectors!"); + assert(VT == Op0VT && + "Expected result and first input to have the same type!"); + assert(Op0VT.getSizeInBits() == Op1VT.getSizeInBits() && + "Expected vectors of equal size!"); + assert(Op0VT.getVectorElementCount() * 2 == Op1VT.getVectorElementCount() && + "Expected result vector and first input vector to have half the " + "lanes of the second input vector!"); + break; + } + case AArch64ISD::SUNPKLO: + case AArch64ISD::SUNPKHI: + case AArch64ISD::UUNPKLO: + case AArch64ISD::UUNPKHI: { + assert(N->getNumValues() == 1 && "Expected one result!"); + assert(N->getNumOperands() == 1 && "Expected one operand!"); + EVT VT = N->getValueType(0); + EVT OpVT = N->getOperand(0).getValueType(); + assert(OpVT.isVector() && VT.isVector() && OpVT.isInteger() && + VT.isInteger() && "Expected integer vectors!"); + assert(OpVT.getSizeInBits() == VT.getSizeInBits() && + "Expected vectors of equal size!"); + assert(OpVT.getVectorElementCount() == VT.getVectorElementCount() * 2 && + "Expected result vector with half the lanes of its input!"); + break; + } + case AArch64ISD::TRN1: + case AArch64ISD::TRN2: + case AArch64ISD::UZP1: + case AArch64ISD::UZP2: + case AArch64ISD::ZIP1: + case AArch64ISD::ZIP2: { + assert(N->getNumValues() == 1 && "Expected one result!"); + assert(N->getNumOperands() == 2 && "Expected two operands!"); + EVT VT = N->getValueType(0); + EVT Op0VT = N->getOperand(0).getValueType(); + EVT Op1VT = N->getOperand(1).getValueType(); + assert(VT.isVector() && Op0VT.isVector() && Op1VT.isVector() && + "Expected vectors!"); + assert(VT == Op0VT && VT == Op1VT && "Expected matching vectors!"); + break; + } + case AArch64ISD::RSHRNB_I: { + assert(N->getNumValues() == 1 && "Expected one result!"); + assert(N->getNumOperands() == 2 && "Expected two operands!"); + EVT VT = N->getValueType(0); + EVT Op0VT = N->getOperand(0).getValueType(); + EVT Op1VT = N->getOperand(1).getValueType(); + assert(VT.isVector() && VT.isInteger() && + "Expected integer vector result type!"); + assert(Op0VT.isVector() && Op0VT.isInteger() && + "Expected first operand to be an integer vector!"); + assert(VT.getSizeInBits() == Op0VT.getSizeInBits() && + "Expected vectors of equal size!"); + assert(VT.getVectorElementCount() == Op0VT.getVectorElementCount() * 2 && + "Expected input vector with half the lanes of its result!"); + assert(Op1VT == MVT::i32 && isa(N->getOperand(1)) && + "Expected second operand to be a constant i32!"); + break; + } + } +} + SDValue AArch64SelectionDAGInfo::EmitMOPS(unsigned Opcode, SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue SrcOrValue, diff --git a/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.h b/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.h index 7efe49c720655..9c11833b3f67e 100644 --- a/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.h +++ b/llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.h @@ -23,6 +23,9 @@ class AArch64SelectionDAGInfo : public SelectionDAGTargetInfo { bool isTargetStrictFPOpcode(unsigned Opcode) const override; + void verifyTargetNode(const SelectionDAG &DAG, + const SDNode *N) const override; + SDValue EmitMOPS(unsigned Opcode, SelectionDAG &DAG, const SDLoc &DL, SDValue Chain, SDValue Dst, SDValue SrcOrValue, SDValue Size, Align Alignment, bool isVolatile,