[llvm] [SelectionDAG] Wire up -gen-sdnode-info TableGen backend (PR #125358)

Sergei Barannikov via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 1 12:31:06 PST 2025


https://github.com/s-barannikov updated https://github.com/llvm/llvm-project/pull/125358

>From 4b2c60bfd3e3cea0d603bd811e0def67dcb5adc9 Mon Sep 17 00:00:00 2001
From: Sergei Barannikov <barannikov88 at gmail.com>
Date: Sat, 16 Nov 2024 00:53:08 +0300
Subject: [PATCH] [SelectionDAG] Wire up -gen-sdnode-info TableGen backend

This patch introduces SelectionDAGGenTargetInfo and SDNodeInfo classes,
which provide methods for accessing the generated SDNode descriptions.

RFC: https://discourse.llvm.org/t/rfc-tablegen-erating-sdnode-descriptions
Draft PR: #119709
---
 llvm/include/llvm/CodeGen/SDNodeInfo.h        | 115 ++++++++++++++++
 .../llvm/CodeGen/SelectionDAGTargetInfo.h     |  48 +++++++
 llvm/include/llvm/CodeGen/TargetLowering.h    |   5 -
 llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt  |   1 +
 llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp  | 128 ++++++++++++++++++
 .../lib/CodeGen/SelectionDAG/SelectionDAG.cpp |   8 +-
 .../SelectionDAG/SelectionDAGDumper.cpp       |   4 +
 .../SelectionDAG/SelectionDAGTargetInfo.cpp   |   2 +
 .../Target/AArch64/AArch64ISelLowering.cpp    |  80 -----------
 llvm/lib/Target/AArch64/AArch64ISelLowering.h |   4 -
 .../AArch64/AArch64SelectionDAGInfo.cpp       |  79 +++++++++++
 .../Target/AArch64/AArch64SelectionDAGInfo.h  |   3 +
 12 files changed, 384 insertions(+), 93 deletions(-)
 create mode 100644 llvm/include/llvm/CodeGen/SDNodeInfo.h
 create mode 100644 llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp

diff --git a/llvm/include/llvm/CodeGen/SDNodeInfo.h b/llvm/include/llvm/CodeGen/SDNodeInfo.h
new file mode 100644
index 000000000000000..4842401e612efc9
--- /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_INCLUDE_LLVM_CODEGEN_SDNODEINFO_H
+#define LLVM_INCLUDE_LLVM_CODEGEN_SDNODEINFO_H
+
+#include "ISDOpcodes.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringTable.h"
+#include "llvm/CodeGenTypes/MachineValueType.h"
+
+namespace llvm {
+
+class SDNode;
+class SelectionDAG;
+
+enum SDNP {
+  SDNPHasChain,
+  SDNPOutGlue,
+  SDNPInGlue,
+  SDNPOptInGlue,
+  SDNPMemOperand,
+  SDNPVariadic,
+};
+
+enum SDTC {
+  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 {
+  unsigned NumResults;
+  int 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<SDTypeConstraint> 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_INCLUDE_LLVM_CODEGEN_SDNODEINFO_H
diff --git a/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h b/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h
index ef5ae5dba58de48..a3846541d31b11b 100644
--- a/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h
+++ b/llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h
@@ -15,6 +15,7 @@
 #ifndef LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H
 #define LLVM_CODEGEN_SELECTIONDAGTARGETINFO_H
 
+#include "SDNodeInfo.h"
 #include "llvm/CodeGen/MachineMemOperand.h"
 #include "llvm/CodeGen/SelectionDAGNodes.h"
 #include "llvm/Support/CodeGen.h"
@@ -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 9fcd2ac9514e564..fea710b9b660c86 100644
--- a/llvm/include/llvm/CodeGen/TargetLowering.h
+++ b/llvm/include/llvm/CodeGen/TargetLowering.h
@@ -4930,11 +4930,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 cbfbfa3a321bcf5..93a742a19aa7936 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 000000000000000..e3f6c98a9a90a07
--- /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 b416c0efbbc4fc6..b08d1e1d960badc 100644
--- a/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
+++ b/llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp
@@ -1155,11 +1155,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) {
+static void VerifySDNode(const SelectionDAG &DAG, SDNode *N) {
   switch (N->getOpcode()) {
   default:
-    if (N->getOpcode() > ISD::BUILTIN_OP_END)
-      TLI->verifyTargetSDNode(N);
+    if (N->isTargetOpcode())
+      DAG.getSelectionDAGInfo().verifyTargetNode(DAG, N);
     break;
   case ISD::BUILD_PAIR: {
     EVT VT = N->getValueType(0);
@@ -1203,7 +1203,7 @@ void SelectionDAG::InsertNode(SDNode *N) {
   AllNodes.push_back(N);
 #ifndef NDEBUG
   N->PersistentId = NextPersistentId++;
-  VerifySDNode(N, TLI);
+  VerifySDNode(*this, 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 f63c8dd3df1c838..8f5795253f37f97 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"
@@ -68,6 +69,9 @@ std::string SDNode::getOperationName(const SelectionDAG *G) const {
       return "<<Unknown Machine Node #" + utostr(getOpcode()) + ">>";
     }
     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 0f3b36658f10ad3..f4422a15bf9dfe6 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 84f6d421b70f961..8276fcf8679d14e 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp
@@ -30076,83 +30076,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<ConstantSDNode>(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 b26f28dc79f886a..891940786edaf5e 100644
--- a/llvm/lib/Target/AArch64/AArch64ISelLowering.h
+++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.h
@@ -1040,10 +1040,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 17adda15d9fc8f2..da2cd1ada365368 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<ConstantSDNode>(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 7efe49c72065552..9c11833b3f67e49 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,



More information about the llvm-commits mailing list