Skip to content

[SelectionDAG] Wire up -gen-sdnode-info TableGen backend #125358

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 5 commits into from
Apr 6, 2025

Conversation

s-barannikov
Copy link
Contributor

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

@llvmbot
Copy link
Member

llvmbot commented Feb 1, 2025

@llvm/pr-subscribers-backend-aarch64

@llvm/pr-subscribers-llvm-selectiondag

Author: Sergei Barannikov (s-barannikov)

Changes

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


Patch is 24.76 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/125358.diff

12 Files Affected:

  • (added) llvm/include/llvm/CodeGen/SDNodeInfo.h (+115)
  • (modified) llvm/include/llvm/CodeGen/SelectionDAGTargetInfo.h (+48)
  • (modified) llvm/include/llvm/CodeGen/TargetLowering.h (-5)
  • (modified) llvm/lib/CodeGen/SelectionDAG/CMakeLists.txt (+1)
  • (added) llvm/lib/CodeGen/SelectionDAG/SDNodeInfo.cpp (+128)
  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAG.cpp (+4-4)
  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGDumper.cpp (+4)
  • (modified) llvm/lib/CodeGen/SelectionDAG/SelectionDAGTargetInfo.cpp (+2)
  • (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.cpp (-80)
  • (modified) llvm/lib/Target/AArch64/AArch64ISelLowering.h (-4)
  • (modified) llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.cpp (+79)
  • (modified) llvm/lib/Target/AArch64/AArch64SelectionDAGInfo.h (+3)
diff --git a/llvm/include/llvm/CodeGen/SDNodeInfo.h b/llvm/include/llvm/CodeGen/SDNodeInfo.h
new file mode 100644
index 00000000000000..4842401e612efc
--- /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 ef5ae5dba58de4..a3846541d31b11 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 9fcd2ac9514e56..fea710b9b660c8 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 cbfbfa3a321bcf..93a742a19aa793 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 00000000000000..e3f6c98a9a90a0
--- /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 b416c0efbbc4fc..b08d1e1d960bad 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 f63c8dd3df1c83..8f5795253f37f9 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 0f3b36658f10ad..f4422a15bf9dfe 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 84f6d421b70f96..8276fcf8679d14 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 b26f28dc79f886..891940786edaf5 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 --g...
[truncated]

ExpectedVT.getEVTString() + ", got " + ActualVT.getEVTString());
}

void SDNodeInfo::verifyNode(const SelectionDAG &DAG, const SDNode *N) const {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently this only verifies basic SDNode "prototype" -- the number of operands/results and the types of chain/glue operands/results. I refrained from making use of the imported SDTypeProfile in this patch to keep it smaller (and I need to spend more time on implementing proper type profile checking anyway).

@s-barannikov
Copy link
Contributor Author

Please let me know if I should add anything to the description or comments to the code.

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: llvm#119709
@s-barannikov
Copy link
Contributor Author

ping?

Copy link
Member

@mshockwave mshockwave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have we ever verified normal (non-target) SDNodes using similar logics you put in SDNodeInfo::verifyNode?

@s-barannikov
Copy link
Contributor Author

Have we ever verified normal (non-target) SDNodes using similar logics you put in SDNodeInfo::verifyNode?

This verifySDNode checks BUILD_PAIR and BUILD_VECTOR, and there are also some ad-hoc asserts in SelectionDAG::getNode(), example.

@mshockwave
Copy link
Member

Have we ever verified normal (non-target) SDNodes using similar logics you put in SDNodeInfo::verifyNode?

This verifySDNode checks BUILD_PAIR and BUILD_VECTOR, and there are also some ad-hoc asserts in SelectionDAG::getNode(), example.

Right, but I'm curious whether we should call SDNodeInfo::verifyNode on non-target nodes too. Because I think there is no mechanism to prevent users from inserting chain / glue operands with the wrong order in non-target nodes.

@s-barannikov
Copy link
Contributor Author

Have we ever verified normal (non-target) SDNodes using similar logics you put in SDNodeInfo::verifyNode?

This verifySDNode checks BUILD_PAIR and BUILD_VECTOR, and there are also some ad-hoc asserts in SelectionDAG::getNode(), example.

Right, but I'm curious whether we should call SDNodeInfo::verifyNode on non-target nodes too. Because I think there is no mechanism to prevent users from inserting chain / glue operands with the wrong order in non-target nodes.

SDNodeInfo::verifyNode needs the generated node descriptions to do the checks, and those are currently generated only for target-specific nodes. Generating descriptions for non-target nodes is left as a (distant) future work; there are several difficulties (mainly, various kinds of irregularities) that I don't have time to deal with right now.
For the time being, we could implement custom checks in C++ code for non-target nodes with chains and glues, there aren't too many of them.

@mshockwave
Copy link
Member

SDNodeInfo::verifyNode needs the generated node descriptions to do the checks, and those are currently generated only for target-specific nodes.

Oh yeah you're right

Generating descriptions for non-target nodes is left as a (distant) future work; there are several difficulties (mainly, various kinds of irregularities) that I don't have time to deal with right now.

I vaguely remember we do some sort of check on chain / glue operands, maybe when we're linearizing the DAG, I can't recall the exact location. But in any case, I agree this can leave for future works.

Copy link
Member

@mshockwave mshockwave left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM

@s-barannikov s-barannikov merged commit 0a17427 into llvm:main Apr 6, 2025
11 checks passed
@s-barannikov s-barannikov deleted the sdag/sdnode-info branch April 6, 2025 10:14
llvm-sync bot pushed a commit to arm/arm-toolchain that referenced this pull request Apr 6, 2025
…#125358)

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

Pull Request: llvm/llvm-project#125358
Draft PR: llvm/llvm-project#119709
RFC: https://discourse.llvm.org/t/rfc-tablegen-erating-sdnode-descriptions
@llvm-ci
Copy link
Collaborator

llvm-ci commented Apr 6, 2025

LLVM Buildbot has detected a new failure on builder clang-aarch64-sve-vla running on linaro-g3-04 while building llvm at step 7 "ninja check 1".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/17/builds/7072

Here is the relevant piece of the build log for the reference
Step 7 (ninja check 1) failure: stage 1 checked (failure)
...
PASS: Flang :: Driver/frepack-arrays-contiguity.f90 (25212 of 97665)
PASS: Flang :: Driver/predefined-macros-x86.f90 (25213 of 97665)
PASS: Flang :: Driver/fdefault.f90 (25214 of 97665)
PASS: Flang :: Driver/fixed-line-length.f90 (25215 of 97665)
PASS: Flang :: Driver/print-effective-triple.f90 (25216 of 97665)
PASS: Flang :: Driver/predefined-macros-compiler-version.F90 (25217 of 97665)
PASS: Flang :: Driver/print-resource-dir.F90 (25218 of 97665)
PASS: Flang :: Driver/parse-fir-error.ll (25219 of 97665)
PASS: Flang :: Driver/override-triple.ll (25220 of 97665)
UNRESOLVED: Flang :: Driver/slp-vectorize.ll (25221 of 97665)
******************** TEST 'Flang :: Driver/slp-vectorize.ll' FAILED ********************
Test has no 'RUN:' line
********************
PASS: Clangd Unit Tests :: ./ClangdTests/79/81 (25222 of 97665)
PASS: Flang :: Driver/lto-bc.f90 (25223 of 97665)
PASS: Flang :: Driver/phases.f90 (25224 of 97665)
PASS: Clangd Unit Tests :: ./ClangdTests/69/81 (25225 of 97665)
PASS: Flang :: Driver/pthread.f90 (25226 of 97665)
PASS: Flang :: Driver/scanning-error.f95 (25227 of 97665)
PASS: Flang :: Driver/include-header.f90 (25228 of 97665)
PASS: Flang :: Driver/print-pipeline-passes.f90 (25229 of 97665)
PASS: Flang :: Driver/supported-suffices/f03-suffix.f03 (25230 of 97665)
PASS: Flang :: Driver/print-target-triple.f90 (25231 of 97665)
PASS: Flang :: Driver/std2018-wrong.f90 (25232 of 97665)
PASS: Flang :: Driver/bbc-openmp-version-macro.f90 (25233 of 97665)
PASS: Flang :: Driver/mlink-builtin-bc.f90 (25234 of 97665)
PASS: Flang :: Driver/parse-error.ll (25235 of 97665)
PASS: Flang :: Driver/supported-suffices/f08-suffix.f08 (25236 of 97665)
PASS: Clangd Unit Tests :: ./ClangdTests/75/81 (25237 of 97665)
PASS: Flang :: Driver/tco-code-gen-llvm.fir (25238 of 97665)
PASS: Flang :: Driver/target-gpu-features.f90 (25239 of 97665)
PASS: Flang :: Driver/parse-ir-error.f95 (25240 of 97665)
PASS: Flang :: Driver/pp-fixed-form.f90 (25241 of 97665)
PASS: Flang :: Driver/pass-plugin-not-found.f90 (25242 of 97665)
PASS: Flang :: Driver/q-unused-arguments.f90 (25243 of 97665)
PASS: Flang :: Driver/target.f90 (25244 of 97665)
PASS: Flang :: Driver/unsupported-vscale-max-min.f90 (25245 of 97665)
PASS: Flang :: Driver/no-duplicate-main.f90 (25246 of 97665)
PASS: Flang :: Driver/config-file.f90 (25247 of 97665)
PASS: Flang :: Driver/multiple-input-files.f90 (25248 of 97665)
PASS: Flang :: Driver/optimization-remark-invalid.f90 (25249 of 97665)
PASS: Flang :: Driver/fsave-optimization-record.f90 (25250 of 97665)
PASS: Flang :: Driver/optimization-remark-backend.f90 (25251 of 97665)
PASS: Flang :: Driver/mllvm.f90 (25252 of 97665)
PASS: Flang :: Driver/unparse-with-modules.f90 (25253 of 97665)
PASS: Flang :: Driver/target-machine-error.f90 (25254 of 97665)
PASS: Flang :: Driver/unparse-use-analyzed.f95 (25255 of 97665)
PASS: Flang :: Driver/std2018.f90 (25256 of 97665)
PASS: Flang :: Driver/falias-analysis.f90 (25257 of 97665)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
backend:AArch64 llvm:SelectionDAG SelectionDAGISel as well
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants