[llvm] [LLVM-Tablegen] Explicit Type Constraints for Overloaded LLVM Intrinsics (PR #172442)

Dharuni R Acharya via llvm-commits llvm-commits at lists.llvm.org
Sat Feb 7 23:33:35 PST 2026


https://github.com/DharuniRAcharya updated https://github.com/llvm/llvm-project/pull/172442

>From 425a0fe893e65ae9bc88d5094643b811400e2776 Mon Sep 17 00:00:00 2001
From: Dharuni R Acharya <dharunira at nvidia.com>
Date: Tue, 16 Dec 2025 08:43:42 +0000
Subject: [PATCH 1/5] [LLVM-Tablegen] Explicit Type Constraints for Overloaded
 LLVM Intrinsics
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch adds LLVM infrastructure to support explicit type constraints for overloaded intrinsics.
A new constrained type class, AnyTypeOf<[list of LLVMType]>, is added to express allowed
type subsets directly in TableGen, enabling precise IR-level verification of intrinsic type usage.
Type violations are now detected during the LLVM Verifier flow with clear, actionable
diagnostics, improving error reporting and debuggability while keeping verification
consistent with LLVM’s existing pipelines.

Signed-off-by: Dharuni R Acharya <dharunira at nvidia.com>
---
 llvm/include/llvm/IR/Intrinsics.h             |  12 +
 llvm/include/llvm/IR/Intrinsics.td            |  19 ++
 llvm/lib/IR/Intrinsics.cpp                    | 297 +++++++++++++++++-
 llvm/lib/IR/Verifier.cpp                      |  10 +
 .../NVPTX/anytypeof_constraints_invalid.ll    |  51 +++
 .../NVPTX/anytypeof_constraints_valid.ll      |  45 +++
 6 files changed, 418 insertions(+), 16 deletions(-)
 create mode 100644 llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
 create mode 100644 llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll

diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 2c86a43e114ea..3d2dcd5e0da1a 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -181,6 +181,7 @@ namespace Intrinsic {
       AMX,
       PPCQuad,
       AArch64Svcount,
+      ArgumentTypeConstraint,  // For AnyTypeOf - marks constrained argument types.
     } Kind;
 
     union {
@@ -189,6 +190,7 @@ namespace Intrinsic {
       unsigned Pointer_AddressSpace;
       unsigned Struct_NumElements;
       unsigned Argument_Info;
+      unsigned Argument_NumConstraints;
       ElementCount Vector_Width;
     };
 
@@ -231,6 +233,12 @@ namespace Intrinsic {
       return Argument_Info & 0xFFFF;
     }
 
+    // For ArgumentTypeConstraint: get number of allowed types.
+    unsigned getArgumentNumConstraints() const {
+      assert(Kind == ArgumentTypeConstraint);
+      return Argument_NumConstraints;
+    }
+
     static IITDescriptor get(IITDescriptorKind K, unsigned Field) {
       IITDescriptor Result = { K, { Field } };
       return Result;
@@ -278,6 +286,10 @@ namespace Intrinsic {
   LLVM_ABI bool matchIntrinsicVarArg(bool isVarArg,
                                      ArrayRef<IITDescriptor> &Infos);
 
+  /// Verify type constraints for AnyTypeOf constrained intrinsics.
+  LLVM_ABI bool verifyIntrinsicTypeConstraints(ID id, FunctionType *FTy,
+                                               std::string &ErrMsg);
+
   /// Gets the type arguments of an intrinsic call by matching type contraints
   /// specified by the .td file. The overloaded types are pushed into the
   /// AgTys vector.
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index c56b0185b4f1e..028b65c267ab7 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -372,6 +372,8 @@ def IIT_V6 : IIT_Vec<6, 50>;
 def IIT_V10 : IIT_Vec<10, 51>;
 def IIT_V2048 : IIT_Vec<2048, 52>;
 def IIT_V4096 : IIT_Vec<4096, 53>;
+// Constrained type encoding for overloaded intrinsics.
+def IIT_ANYTYPE : IIT_Base<93>;
 }
 
 defvar IIT_all_FixedTypes = !filter(iit, IIT_all,
@@ -448,6 +450,23 @@ class LLVMAnyPointerType : LLVMAnyType<pAny> {
   assert isAny, "pAny should have isOverloaded";
 }
 
+// AnyTypeOf: Constrain overloaded type to specific set of allowed types.
+// Encoding follows the pattern: [IIT_ARG, EncAny, IIT_ANYTYPE, count, type_sigs...].
+class AnyTypeOf<list<LLVMType> allowed_types> : LLVMAnyType<Any> {
+  list<LLVMType> AllowedTypes = allowed_types;
+  
+  // Validation: specifying maximal 255 number of allowed types.
+  assert !le(!size(allowed_types), 255),
+         "AnyTypeOf cannot exceed 255 allowed types";
+  
+  let Sig = !listconcat(
+    [IIT_ARG.Number, EncAnyType<ArgCode>.ret],
+    [IIT_ANYTYPE.Number, !size(allowed_types)],
+    !foldl([]<int>, allowed_types, accum, ty,
+      !listconcat(accum, ty.Sig))
+  );
+}
+
 // Match the type of another intrinsic parameter.  Number is an index into the
 // list of overloaded types for the intrinsic, excluding all the fixed types.
 // The Number value must refer to a previously listed type.  For example:
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index f46d3e5063e43..88762923fd96d 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -353,8 +353,21 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
   case IIT_ARG: {
     unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
     OutputTable.push_back(IITDescriptor::get(IITDescriptor::Argument, ArgInfo));
+
+    if (NextElt < Infos.size() && Infos[NextElt] == IIT_ANYTYPE) {
+      NextElt++;
+
+      unsigned NumTypes = Infos[NextElt++];
+      OutputTable.push_back(IITDescriptor::get(IITDescriptor::ArgumentTypeConstraint, NumTypes));
+      
+      for (unsigned i = 0; i < NumTypes; ++i)
+        DecodeIITType(NextElt, Infos, Info, OutputTable);
+      return;
+    }
     return;
   }
+  case IIT_ANYTYPE:
+    llvm_unreachable("IIT_ANYTYPE must follow IIT_ARG");
   case IIT_EXTEND_ARG: {
     unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
     OutputTable.push_back(
@@ -570,6 +583,8 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
   case IITDescriptor::VecOfAnyPtrsToElt:
     // Return the overloaded type (which determines the pointers address space)
     return Tys[D.getOverloadArgNumber()];
+  case IITDescriptor::ArgumentTypeConstraint:
+    llvm_unreachable("ArgumentTypeConstraint should not appear in DecodeFixedType");
   }
   llvm_unreachable("unhandled");
 }
@@ -582,9 +597,26 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
   ArrayRef<IITDescriptor> TableRef = Table;
   Type *ResultTy = DecodeFixedType(TableRef, Tys, Context);
 
+  if (!TableRef.empty() && TableRef[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+    unsigned NumConstraints = TableRef[0].getArgumentNumConstraints();
+    TableRef = TableRef.slice(1);
+    
+    for (unsigned i = 0; i < NumConstraints; ++i)
+      (void)DecodeFixedType(TableRef, Tys, Context);
+  }
+
   SmallVector<Type *, 8> ArgTys;
-  while (!TableRef.empty())
+  while (!TableRef.empty()) {
     ArgTys.push_back(DecodeFixedType(TableRef, Tys, Context));
+    
+    if (!TableRef.empty() && TableRef[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+      unsigned NumConstraints = TableRef[0].getArgumentNumConstraints();
+      TableRef = TableRef.slice(1);
+      
+      for (unsigned i = 0; i < NumConstraints; ++i)
+        (void)DecodeFixedType(TableRef, Tys, Context);
+    }
+  }
 
   // DecodeFixedType returns Void for IITDescriptor::Void and
   // IITDescriptor::VarArg If we see void type as the type of the last argument,
@@ -833,6 +865,50 @@ bool Intrinsic::hasConstrainedFPRoundingModeOperand(Intrinsic::ID QID) {
   }
 }
 
+// Helper to skip past descriptors for one complete type in AnyTypeOf constraints.
+static unsigned skipDescriptorsForSingleType(ArrayRef<Intrinsic::IITDescriptor> &Infos) {
+  using namespace Intrinsic;
+  
+  if (Infos.empty())
+    return 0;
+  
+  IITDescriptor D = Infos[0];
+  unsigned Count = 1;
+  Infos = Infos.slice(1);
+  
+  switch (D.Kind) {
+  case IITDescriptor::Vector:
+    Count += skipDescriptorsForSingleType(Infos);
+    break;
+    
+  case IITDescriptor::Pointer:
+    break;
+    
+  case IITDescriptor::Struct:
+    for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i)
+      Count += skipDescriptorsForSingleType(Infos);
+    break;
+    
+  case IITDescriptor::SameVecWidthArgument:
+    Count += skipDescriptorsForSingleType(Infos);
+    break;
+    
+  case IITDescriptor::Argument:
+    if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+      unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
+      Count++;
+      Infos = Infos.slice(1);
+      for (unsigned i = 0; i < NumConstraints; ++i)
+        Count += skipDescriptorsForSingleType(Infos);
+    }
+    break;
+
+  default:
+    break;
+  }
+  return Count;
+}
+
 using DeferredIntrinsicMatchPair =
     std::pair<Type *, ArrayRef<Intrinsic::IITDescriptor>>;
 
@@ -919,6 +995,29 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
     // verify that the later instance matches the previous instance.
     if (D.getArgumentNumber() < ArgTys.size())
       return Ty != ArgTys[D.getArgumentNumber()];
+      
+    switch (D.getArgumentKind()) {
+    case IITDescriptor::AK_Any:
+      break;
+    case IITDescriptor::AK_AnyInteger:
+      if (!Ty->isIntOrIntVectorTy())
+        return true;
+      break;
+    case IITDescriptor::AK_AnyFloat:
+      if (!Ty->isFPOrFPVectorTy())
+        return true;
+      break;
+    case IITDescriptor::AK_AnyVector:
+      if (!isa<VectorType>(Ty))
+        return true;
+      break;
+    case IITDescriptor::AK_AnyPointer:
+      if (!isa<PointerType>(Ty))
+        return true;
+      break;
+    case IITDescriptor::AK_MatchType:
+      break;
+    }
 
     if (D.getArgumentNumber() > ArgTys.size() ||
         D.getArgumentKind() == IITDescriptor::AK_MatchType)
@@ -927,22 +1026,18 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
     assert(D.getArgumentNumber() == ArgTys.size() && !IsDeferredCheck &&
            "Table consistency error");
     ArgTys.push_back(Ty);
-
-    switch (D.getArgumentKind()) {
-    case IITDescriptor::AK_Any:
-      return false; // Success
-    case IITDescriptor::AK_AnyInteger:
-      return !Ty->isIntOrIntVectorTy();
-    case IITDescriptor::AK_AnyFloat:
-      return !Ty->isFPOrFPVectorTy();
-    case IITDescriptor::AK_AnyVector:
-      return !isa<VectorType>(Ty);
-    case IITDescriptor::AK_AnyPointer:
-      return !isa<PointerType>(Ty);
-    default:
-      break;
+    
+    if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+      unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
+      Infos = Infos.slice(1); 
+
+      for (unsigned i = 0; i < NumConstraints; ++i)
+        skipDescriptorsForSingleType(Infos);
+  
+      return false;
     }
-    llvm_unreachable("all argument kinds not covered");
+
+    return false;
 
   case IITDescriptor::ExtendArgument: {
     // If this is a forward reference, defer the check for later.
@@ -1058,6 +1153,8 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
       return true;
     return ThisArgVecTy != VectorType::getInteger(ReferenceType);
   }
+  case IITDescriptor::ArgumentTypeConstraint:
+    llvm_unreachable("ArgumentTypeConstraint should be handled in Argument case");
   }
   llvm_unreachable("unhandled");
 }
@@ -1088,6 +1185,174 @@ Intrinsic::matchIntrinsicSignature(FunctionType *FTy,
   return MatchIntrinsicTypes_Match;
 }
 
+// Helper: Check if a type matches AnyTypeOf constraints using matchIntrinsicType.
+static bool verifyTypeAgainstConstraints(
+    Type *Ty, unsigned NumConstraints,
+    ArrayRef<Intrinsic::IITDescriptor> &Infos) {
+  using namespace Intrinsic;
+  
+  bool Matched = false;
+  for (unsigned i = 0; i < NumConstraints && !Matched; ++i) {
+    ArrayRef<IITDescriptor> TypeDesc = Infos;
+    SmallVector<Type *, 4> DummyArgTys;
+    SmallVector<DeferredIntrinsicMatchPair, 2> DummyDeferredChecks;
+    
+    if (!matchIntrinsicType(Ty, TypeDesc, DummyArgTys, DummyDeferredChecks, false)) {
+      Matched = true;
+      for (unsigned j = 0; j < NumConstraints - i; ++j)
+        skipDescriptorsForSingleType(Infos);
+      break;
+    }
+    skipDescriptorsForSingleType(Infos);
+  }
+  
+  return Matched;
+}
+
+// Helper: Format a type as string for error messages.
+static std::string typeToString(Type *Ty) {
+  std::string Str;
+  raw_string_ostream OS(Str);
+  Ty->print(OS);
+  return Str;
+}
+
+bool Intrinsic::verifyIntrinsicTypeConstraints(
+    ID id, FunctionType *FTy,
+    std::string &ErrMsg) {
+  
+  if (id == 0 || id >= Intrinsic::num_intrinsics)
+    return true;
+  
+  SmallVector<IITDescriptor, 8> Table;
+  getIntrinsicInfoTableEntries(id, Table);
+  
+  if (Table.empty())
+    return true;
+  
+  ArrayRef<IITDescriptor> Infos = Table;
+  SmallVector<Type *, 4> ArgTys;
+  
+  // Processing return type.
+  Type *RetTy = FTy->getReturnType();
+  if (!Infos.empty() && Infos[0].Kind == IITDescriptor::Argument) {
+    Infos = Infos.slice(1);
+    
+    if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+      unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
+      Infos = Infos.slice(1);
+      
+      bool Matched = false;
+      
+      // Check if a struct type's elements are all present in AnyTypeOf constraint list. 
+      if (auto *STy = dyn_cast<StructType>(RetTy)) {
+        SmallVector<Type *, 8> AllowedTypes;
+        ArrayRef<IITDescriptor> TempInfos = Infos;
+        for (unsigned i = 0; i < NumConstraints; ++i) {
+          ArrayRef<IITDescriptor> TypeDesc = TempInfos;
+          SmallVector<Type *, 4> DummyTys;
+          Type *ConstraintTy = DecodeFixedType(TypeDesc, DummyTys, FTy->getContext());
+          AllowedTypes.push_back(ConstraintTy);
+          TempInfos = TypeDesc;
+        }
+        
+        Matched = llvm::all_of(STy->elements(), [&](Type *ElemTy) {
+              return llvm::is_contained(AllowedTypes, ElemTy);
+        });
+        
+        if (Matched) {
+          for (unsigned i = 0; i < NumConstraints; ++i)
+            skipDescriptorsForSingleType(Infos);
+          Matched = true;
+        }
+      }
+      
+      if (!Matched) {
+        for (unsigned i = 0; i < NumConstraints && !Matched; ++i) {
+          ArrayRef<IITDescriptor> TypeDesc = Infos;
+          SmallVector<Type *, 4> DummyArgTys;
+          SmallVector<DeferredIntrinsicMatchPair, 2> DummyDeferredChecks;
+          
+          if (!matchIntrinsicType(RetTy, TypeDesc, DummyArgTys, 
+                                  DummyDeferredChecks, false)) {
+            Matched = true;
+            for (unsigned j = 0; j < NumConstraints - i; ++j)
+              skipDescriptorsForSingleType(Infos);
+            break;
+          }
+          skipDescriptorsForSingleType(Infos);
+        }
+      }
+      
+      if (!Matched) {
+        ErrMsg = "Return type '" + typeToString(RetTy) + "' not in allowed types";
+        return false;
+      }
+    }
+  } else if (!Infos.empty() && Infos[0].Kind == IITDescriptor::Struct) {
+    // Handle struct return type with AnyTypeOf constrained elements.
+    auto *STy = dyn_cast<StructType>(RetTy);
+    if (!STy)
+      skipDescriptorsForSingleType(Infos);
+    else {
+      unsigned NumElements = Infos[0].Struct_NumElements;
+      Infos = Infos.slice(1);
+      
+      for (unsigned ElemIdx = 0; ElemIdx < NumElements; ++ElemIdx) {
+        if (Infos.empty())
+          break;
+        
+        if (Infos[0].Kind == IITDescriptor::Argument) {
+          Infos = Infos.slice(1);
+          
+          if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+            unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
+            Infos = Infos.slice(1);
+            
+            Type *ElemTy = STy->getElementType(ElemIdx);
+            if (!verifyTypeAgainstConstraints(ElemTy, NumConstraints, Infos)) {
+              ErrMsg = "Return type struct element " + std::to_string(ElemIdx) + 
+                       " type '" + typeToString(ElemTy) + "' not in allowed types";
+              return false;
+            }
+          }
+        } else
+          skipDescriptorsForSingleType(Infos);
+      }
+    }
+  } else if (!Infos.empty())
+    skipDescriptorsForSingleType(Infos);
+
+  // Processing parameters.
+  for (unsigned ParamIdx = 0; ParamIdx < FTy->getNumParams(); ++ParamIdx) {
+    if (Infos.empty())
+      break;
+    
+    Type *ParamTy = FTy->getParamType(ParamIdx);
+    
+    if (Infos[0].Kind == IITDescriptor::Argument) {
+      unsigned ArgNum = Infos[0].getArgumentNumber();
+      Infos = Infos.slice(1);
+      
+      if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+        unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
+        Infos = Infos.slice(1);
+        
+        if (!verifyTypeAgainstConstraints(ParamTy, NumConstraints, Infos)) {
+          ErrMsg = "Parameter " + std::to_string(ParamIdx) + " type '" + 
+                   typeToString(ParamTy) + "' not in allowed types";
+          return false;
+        }
+        
+        if (ArgNum == ArgTys.size())
+          ArgTys.push_back(ParamTy);
+      } 
+    } else
+      skipDescriptorsForSingleType(Infos);
+  }
+  return true;
+}
+
 bool Intrinsic::matchIntrinsicVarArg(
     bool isVarArg, ArrayRef<Intrinsic::IITDescriptor> &Infos) {
   // If there are no descriptors left, then it can't be a vararg.
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index a2ad95eb5abc4..963c01b5a1db0 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3290,6 +3290,16 @@ void Verifier::visitFunction(const Function &F) {
   }
   }
 
+  // Verify AnyTypeOf type constraints for intrinsic declarations.
+  if (F.isIntrinsic()) {
+    std::string ConstraintErrMsg;
+    if (!Intrinsic::verifyIntrinsicTypeConstraints(F.getIntrinsicID(),
+                                                   F.getFunctionType(),
+                                                   ConstraintErrMsg))
+      CheckFailed("Intrinsic declaration '" + F.getName().str() +
+                  "' violates type constraint: " + ConstraintErrMsg);
+  }
+
   auto *N = F.getSubprogram();
   HasDebugInfo = (N != nullptr);
   if (!HasDebugInfo)
diff --git a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
new file mode 100644
index 0000000000000..7647a04898299
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
@@ -0,0 +1,51 @@
+; RUN: not llvm-as < %s -o /dev/null
+; Test cases for int_nvvm_test_anytype intrinsic - INVALID combinations
+
+; arg0 must be i16 or i32, not i8
+define i32 @invalid_arg0_i8(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i8.i8.i32.p0.i64.i16(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+  ret i32 %result
+}
+
+; arg1 must match arg0 (i16), not i32
+define i32 @invalid_arg1_mismatch_i16_i32(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i16.i32.i32.p0.i64.i16(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+  ret i32 %result
+}
+
+; arg2 must be anyint or float, not double
+define i32 @invalid_arg2_double(i32 %a0, i32 %a1, double %a2, ptr %a3, i64 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.f64.p0.i64.i16(i32 %a0, i32 %a1, double %a2, ptr %a3, i64 %a4, i16 %a5)
+  ret i32 %result
+}
+
+; arg3 must be ptr or ptr addrspace(3), not ptr addrspace(1) (global)
+define i32 @invalid_arg3_ptr_as1_wrong(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i64 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p1.i64.i16(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i64 %a4, i16 %a5)
+  ret i32 %result
+}
+
+; arg4 must be i64 or double, not i32
+define i32 @invalid_arg4_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
+  ret i32 %result
+}
+
+; arg5 must be i16, <4 x i32>, or <4 x f32>, not <2 x i32>
+define i32 @invalid_arg5_v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <2 x i32> %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <2 x i32> %a5)
+  ret i32 %result
+}
+
+define {i32, i8, i64} @invalid_return_type_i8(i32 %arg) {
+  %result = call {i32, i8, i64} @llvm.nvvm.test.return.type.i8(i32 %arg)
+  ret {i32, i8, i64} %result
+}
+
+declare i32 @llvm.nvvm.test.anytype.i8.i8.i32.p0.i64.i16(i8, i8, i32, ptr, i64, i16)
+declare i32 @llvm.nvvm.test.anytype.i16.i32.i32.p0.i64.i16(i16, i32, i32, ptr, i64, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.f64.p0.i64.i16(i32, i32, double, ptr, i64, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p1.i64.i16(i32, i32, i32, ptr addrspace(1), i64, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i32.i16(i32, i32, i32, ptr, i32, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v2i32(i32, i32, i32, ptr, i64, <2 x i32>)
+declare {i32, i8, i64} @llvm.nvvm.test.return.type.i8(i32)
diff --git a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll
new file mode 100644
index 0000000000000..2efa46c04116f
--- /dev/null
+++ b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll
@@ -0,0 +1,45 @@
+; RUN: llvm-as < %s -o /dev/null
+; Test cases for int_nvvm_test_anytype intrinsic - VALID combinations
+
+define i32 @test_arg0_i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i16.i16.i32.p0.i64.i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+  ret i32 %result
+}
+
+define i32 @test_arg0_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+  ret i32 %result
+}
+
+define i32 @test_arg2_anyint(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+  ret i32 %result
+}
+
+define i32 @test_arg3_shared_ptr(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i64 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p3.i64.i16(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i64 %a4, i16 %a5)
+  ret i32 %result
+}
+
+define i32 @test_arg4_double(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.f64.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, i16 %a5)
+  ret i32 %result
+}
+
+define i32 @test_arg5_v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <4 x i32> %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <4 x i32> %a5)
+  ret i32 %result
+}
+
+define {i32, i32, i64} @test_return_type_valid(i32 %arg) {
+  %result = call {i32, i32, i64} @llvm.nvvm.test.return.type.i32(i32 %arg)
+  ret {i32, i32, i64} %result
+}
+
+declare i32 @llvm.nvvm.test.anytype.i16.i16.i32.p0.i64.i16(i16, i16, i32, ptr, i64, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.i16(i32, i32, i32, ptr, i64, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.f32.p0.i64.i16(i32, i32, i32, ptr, i64, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p3.i64.i16(i32, i32, i32, ptr addrspace(3), i64, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.f64.i16(i32, i32, i32, ptr, double, i16)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v4i32(i32, i32, i32, ptr, i64, <4 x i32>)
+declare {i32, i32, i64} @llvm.nvvm.test.return.type.i32(i32)

>From 831b5b4f799ebf8720d22db8cb7c9e44e1179fea Mon Sep 17 00:00:00 2001
From: Dharuni R Acharya <dharunira at nvidia.com>
Date: Wed, 17 Dec 2025 05:03:56 +0000
Subject: [PATCH 2/5] Fix formatting & Resolve conflicts

---
 llvm/include/llvm/IR/Intrinsics.h      |   3 +-
 llvm/include/llvm/IR/IntrinsicsNVVM.td |  12 ++
 llvm/lib/IR/Intrinsics.cpp             | 155 ++++++++++++++-----------
 llvm/lib/IR/Verifier.cpp               |   5 +-
 4 files changed, 102 insertions(+), 73 deletions(-)

diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 3d2dcd5e0da1a..0b1daa102c2a2 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -181,7 +181,8 @@ namespace Intrinsic {
       AMX,
       PPCQuad,
       AArch64Svcount,
-      ArgumentTypeConstraint,  // For AnyTypeOf - marks constrained argument types.
+      ArgumentTypeConstraint, // For AnyTypeOf - marks constrained argument
+                              // types.
     } Kind;
 
     union {
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index bad655c7c4d1c..bb8a8c7caf284 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -3386,4 +3386,16 @@ def int_nvvm_tensormap_replace_fill_mode :
      ArgInfo<ArgIndex<1>, [ArgName<"fill_mode">, 
                            ImmArgPrinter<"printTensormapFillMode">]>]>;
 
+// Test intrinsic - TODO: Add the feature to existing intrinsics and remove these test intrinsics.
+// IIT_LongEncodingTable entry:   /* 25339 */ 4, 15, 0, 93, 2, 3, 4, 15, 7, 15, 8, 93, 2, 15, 9, 7, 15, 16, 93, 2, 14, 24, 3, 15, 24, 93, 2, 5, 8, 15, 32, 93, 3, 3, 10, 4, 10, 7, 0,
+def int_nvvm_test_anytype : Intrinsic<[llvm_i32_ty],
+  [AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, LLVMMatchType<0>, AnyTypeOf<[llvm_anyint_ty, llvm_float_ty]>, AnyTypeOf<[llvm_ptr_ty, llvm_shared_ptr_ty]>,
+   AnyTypeOf<[llvm_i64_ty, llvm_double_ty]>, AnyTypeOf<[llvm_i16_ty, llvm_v4i32_ty, llvm_v4f32_ty]>],
+  [IntrNoMem]>;
+
+// IIT_LongEncodingTable entry:  /* 15435 */ 21, 1, 4, 15, 0, 93, 2, 3, 4, 5, 4, 0,
+def int_nvvm_test_return_type : Intrinsic<[llvm_i32_ty, AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, llvm_i64_ty],
+[llvm_i32_ty],
+[IntrNoMem]>;
+
 } // let TargetPrefix = "nvvm"
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 88762923fd96d..0e349925b2c8c 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -358,8 +358,9 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
       NextElt++;
 
       unsigned NumTypes = Infos[NextElt++];
-      OutputTable.push_back(IITDescriptor::get(IITDescriptor::ArgumentTypeConstraint, NumTypes));
-      
+      OutputTable.push_back(
+          IITDescriptor::get(IITDescriptor::ArgumentTypeConstraint, NumTypes));
+
       for (unsigned i = 0; i < NumTypes; ++i)
         DecodeIITType(NextElt, Infos, Info, OutputTable);
       return;
@@ -584,7 +585,8 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
     // Return the overloaded type (which determines the pointers address space)
     return Tys[D.getOverloadArgNumber()];
   case IITDescriptor::ArgumentTypeConstraint:
-    llvm_unreachable("ArgumentTypeConstraint should not appear in DecodeFixedType");
+    llvm_unreachable(
+        "ArgumentTypeConstraint should not appear in DecodeFixedType");
   }
   llvm_unreachable("unhandled");
 }
@@ -597,10 +599,11 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
   ArrayRef<IITDescriptor> TableRef = Table;
   Type *ResultTy = DecodeFixedType(TableRef, Tys, Context);
 
-  if (!TableRef.empty() && TableRef[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+  if (!TableRef.empty() &&
+      TableRef[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
     unsigned NumConstraints = TableRef[0].getArgumentNumConstraints();
     TableRef = TableRef.slice(1);
-    
+
     for (unsigned i = 0; i < NumConstraints; ++i)
       (void)DecodeFixedType(TableRef, Tys, Context);
   }
@@ -608,11 +611,12 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
   SmallVector<Type *, 8> ArgTys;
   while (!TableRef.empty()) {
     ArgTys.push_back(DecodeFixedType(TableRef, Tys, Context));
-    
-    if (!TableRef.empty() && TableRef[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+
+    if (!TableRef.empty() &&
+        TableRef[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
       unsigned NumConstraints = TableRef[0].getArgumentNumConstraints();
       TableRef = TableRef.slice(1);
-      
+
       for (unsigned i = 0; i < NumConstraints; ++i)
         (void)DecodeFixedType(TableRef, Tys, Context);
     }
@@ -865,36 +869,39 @@ bool Intrinsic::hasConstrainedFPRoundingModeOperand(Intrinsic::ID QID) {
   }
 }
 
-// Helper to skip past descriptors for one complete type in AnyTypeOf constraints.
-static unsigned skipDescriptorsForSingleType(ArrayRef<Intrinsic::IITDescriptor> &Infos) {
+// Helper to skip past descriptors for one complete type in AnyTypeOf
+// constraints.
+static unsigned
+skipDescriptorsForSingleType(ArrayRef<Intrinsic::IITDescriptor> &Infos) {
   using namespace Intrinsic;
-  
+
   if (Infos.empty())
     return 0;
-  
+
   IITDescriptor D = Infos[0];
   unsigned Count = 1;
   Infos = Infos.slice(1);
-  
+
   switch (D.Kind) {
   case IITDescriptor::Vector:
     Count += skipDescriptorsForSingleType(Infos);
     break;
-    
+
   case IITDescriptor::Pointer:
     break;
-    
+
   case IITDescriptor::Struct:
     for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i)
       Count += skipDescriptorsForSingleType(Infos);
     break;
-    
+
   case IITDescriptor::SameVecWidthArgument:
     Count += skipDescriptorsForSingleType(Infos);
     break;
-    
+
   case IITDescriptor::Argument:
-    if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+    if (!Infos.empty() &&
+        Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
       unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
       Count++;
       Infos = Infos.slice(1);
@@ -995,7 +1002,7 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
     // verify that the later instance matches the previous instance.
     if (D.getArgumentNumber() < ArgTys.size())
       return Ty != ArgTys[D.getArgumentNumber()];
-      
+
     switch (D.getArgumentKind()) {
     case IITDescriptor::AK_Any:
       break;
@@ -1026,14 +1033,15 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
     assert(D.getArgumentNumber() == ArgTys.size() && !IsDeferredCheck &&
            "Table consistency error");
     ArgTys.push_back(Ty);
-    
-    if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+
+    if (!Infos.empty() &&
+        Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
       unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
-      Infos = Infos.slice(1); 
+      Infos = Infos.slice(1);
 
       for (unsigned i = 0; i < NumConstraints; ++i)
         skipDescriptorsForSingleType(Infos);
-  
+
       return false;
     }
 
@@ -1154,7 +1162,8 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
     return ThisArgVecTy != VectorType::getInteger(ReferenceType);
   }
   case IITDescriptor::ArgumentTypeConstraint:
-    llvm_unreachable("ArgumentTypeConstraint should be handled in Argument case");
+    llvm_unreachable(
+        "ArgumentTypeConstraint should be handled in Argument case");
   }
   llvm_unreachable("unhandled");
 }
@@ -1185,19 +1194,21 @@ Intrinsic::matchIntrinsicSignature(FunctionType *FTy,
   return MatchIntrinsicTypes_Match;
 }
 
-// Helper: Check if a type matches AnyTypeOf constraints using matchIntrinsicType.
-static bool verifyTypeAgainstConstraints(
-    Type *Ty, unsigned NumConstraints,
-    ArrayRef<Intrinsic::IITDescriptor> &Infos) {
+// Helper: Check if a type matches AnyTypeOf constraints using
+// matchIntrinsicType.
+static bool
+verifyTypeAgainstConstraints(Type *Ty, unsigned NumConstraints,
+                             ArrayRef<Intrinsic::IITDescriptor> &Infos) {
   using namespace Intrinsic;
-  
+
   bool Matched = false;
   for (unsigned i = 0; i < NumConstraints && !Matched; ++i) {
     ArrayRef<IITDescriptor> TypeDesc = Infos;
     SmallVector<Type *, 4> DummyArgTys;
     SmallVector<DeferredIntrinsicMatchPair, 2> DummyDeferredChecks;
-    
-    if (!matchIntrinsicType(Ty, TypeDesc, DummyArgTys, DummyDeferredChecks, false)) {
+
+    if (!matchIntrinsicType(Ty, TypeDesc, DummyArgTys, DummyDeferredChecks,
+                            false)) {
       Matched = true;
       for (unsigned j = 0; j < NumConstraints - i; ++j)
         skipDescriptorsForSingleType(Infos);
@@ -1205,7 +1216,7 @@ static bool verifyTypeAgainstConstraints(
     }
     skipDescriptorsForSingleType(Infos);
   }
-  
+
   return Matched;
 }
 
@@ -1217,63 +1228,65 @@ static std::string typeToString(Type *Ty) {
   return Str;
 }
 
-bool Intrinsic::verifyIntrinsicTypeConstraints(
-    ID id, FunctionType *FTy,
-    std::string &ErrMsg) {
-  
+bool Intrinsic::verifyIntrinsicTypeConstraints(ID id, FunctionType *FTy,
+                                               std::string &ErrMsg) {
+
   if (id == 0 || id >= Intrinsic::num_intrinsics)
     return true;
-  
+
   SmallVector<IITDescriptor, 8> Table;
   getIntrinsicInfoTableEntries(id, Table);
-  
+
   if (Table.empty())
     return true;
-  
+
   ArrayRef<IITDescriptor> Infos = Table;
   SmallVector<Type *, 4> ArgTys;
-  
+
   // Processing return type.
   Type *RetTy = FTy->getReturnType();
   if (!Infos.empty() && Infos[0].Kind == IITDescriptor::Argument) {
     Infos = Infos.slice(1);
-    
-    if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+
+    if (!Infos.empty() &&
+        Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
       unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
       Infos = Infos.slice(1);
-      
+
       bool Matched = false;
-      
-      // Check if a struct type's elements are all present in AnyTypeOf constraint list. 
+
+      // Check if a struct type's elements are all present in AnyTypeOf
+      // constraint list.
       if (auto *STy = dyn_cast<StructType>(RetTy)) {
         SmallVector<Type *, 8> AllowedTypes;
         ArrayRef<IITDescriptor> TempInfos = Infos;
         for (unsigned i = 0; i < NumConstraints; ++i) {
           ArrayRef<IITDescriptor> TypeDesc = TempInfos;
           SmallVector<Type *, 4> DummyTys;
-          Type *ConstraintTy = DecodeFixedType(TypeDesc, DummyTys, FTy->getContext());
+          Type *ConstraintTy =
+              DecodeFixedType(TypeDesc, DummyTys, FTy->getContext());
           AllowedTypes.push_back(ConstraintTy);
           TempInfos = TypeDesc;
         }
-        
+
         Matched = llvm::all_of(STy->elements(), [&](Type *ElemTy) {
-              return llvm::is_contained(AllowedTypes, ElemTy);
+          return llvm::is_contained(AllowedTypes, ElemTy);
         });
-        
+
         if (Matched) {
           for (unsigned i = 0; i < NumConstraints; ++i)
             skipDescriptorsForSingleType(Infos);
           Matched = true;
         }
       }
-      
+
       if (!Matched) {
         for (unsigned i = 0; i < NumConstraints && !Matched; ++i) {
           ArrayRef<IITDescriptor> TypeDesc = Infos;
           SmallVector<Type *, 4> DummyArgTys;
           SmallVector<DeferredIntrinsicMatchPair, 2> DummyDeferredChecks;
-          
-          if (!matchIntrinsicType(RetTy, TypeDesc, DummyArgTys, 
+
+          if (!matchIntrinsicType(RetTy, TypeDesc, DummyArgTys,
                                   DummyDeferredChecks, false)) {
             Matched = true;
             for (unsigned j = 0; j < NumConstraints - i; ++j)
@@ -1283,9 +1296,10 @@ bool Intrinsic::verifyIntrinsicTypeConstraints(
           skipDescriptorsForSingleType(Infos);
         }
       }
-      
+
       if (!Matched) {
-        ErrMsg = "Return type '" + typeToString(RetTy) + "' not in allowed types";
+        ErrMsg =
+            "Return type '" + typeToString(RetTy) + "' not in allowed types";
         return false;
       }
     }
@@ -1297,22 +1311,24 @@ bool Intrinsic::verifyIntrinsicTypeConstraints(
     else {
       unsigned NumElements = Infos[0].Struct_NumElements;
       Infos = Infos.slice(1);
-      
+
       for (unsigned ElemIdx = 0; ElemIdx < NumElements; ++ElemIdx) {
         if (Infos.empty())
           break;
-        
+
         if (Infos[0].Kind == IITDescriptor::Argument) {
           Infos = Infos.slice(1);
-          
-          if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+
+          if (!Infos.empty() &&
+              Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
             unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
             Infos = Infos.slice(1);
-            
+
             Type *ElemTy = STy->getElementType(ElemIdx);
             if (!verifyTypeAgainstConstraints(ElemTy, NumConstraints, Infos)) {
-              ErrMsg = "Return type struct element " + std::to_string(ElemIdx) + 
-                       " type '" + typeToString(ElemTy) + "' not in allowed types";
+              ErrMsg = "Return type struct element " + std::to_string(ElemIdx) +
+                       " type '" + typeToString(ElemTy) +
+                       "' not in allowed types";
               return false;
             }
           }
@@ -1327,26 +1343,27 @@ bool Intrinsic::verifyIntrinsicTypeConstraints(
   for (unsigned ParamIdx = 0; ParamIdx < FTy->getNumParams(); ++ParamIdx) {
     if (Infos.empty())
       break;
-    
+
     Type *ParamTy = FTy->getParamType(ParamIdx);
-    
+
     if (Infos[0].Kind == IITDescriptor::Argument) {
       unsigned ArgNum = Infos[0].getArgumentNumber();
       Infos = Infos.slice(1);
-      
-      if (!Infos.empty() && Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+
+      if (!Infos.empty() &&
+          Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
         unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
         Infos = Infos.slice(1);
-        
+
         if (!verifyTypeAgainstConstraints(ParamTy, NumConstraints, Infos)) {
-          ErrMsg = "Parameter " + std::to_string(ParamIdx) + " type '" + 
+          ErrMsg = "Parameter " + std::to_string(ParamIdx) + " type '" +
                    typeToString(ParamTy) + "' not in allowed types";
           return false;
         }
-        
+
         if (ArgNum == ArgTys.size())
           ArgTys.push_back(ParamTy);
-      } 
+      }
     } else
       skipDescriptorsForSingleType(Infos);
   }
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 963c01b5a1db0..301a57b680d7b 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3293,9 +3293,8 @@ void Verifier::visitFunction(const Function &F) {
   // Verify AnyTypeOf type constraints for intrinsic declarations.
   if (F.isIntrinsic()) {
     std::string ConstraintErrMsg;
-    if (!Intrinsic::verifyIntrinsicTypeConstraints(F.getIntrinsicID(),
-                                                   F.getFunctionType(),
-                                                   ConstraintErrMsg))
+    if (!Intrinsic::verifyIntrinsicTypeConstraints(
+            F.getIntrinsicID(), F.getFunctionType(), ConstraintErrMsg))
       CheckFailed("Intrinsic declaration '" + F.getName().str() +
                   "' violates type constraint: " + ConstraintErrMsg);
   }

>From 0a037107ffcc7d0162651ffc75ef777032bb0942 Mon Sep 17 00:00:00 2001
From: Dharuni R Acharya <dharuniracharya at gmail.com>
Date: Sat, 10 Jan 2026 16:37:10 +0000
Subject: [PATCH 3/5] Addition of NoneTypeOf Implementation

---
 llvm/include/llvm/IR/Intrinsics.h             |   7 +
 llvm/include/llvm/IR/Intrinsics.td            |  18 +
 llvm/include/llvm/IR/IntrinsicsNVVM.td        |   9 +-
 llvm/lib/IR/Intrinsics.cpp                    | 336 ++++++++++++------
 .../NVPTX/anytypeof_constraints_invalid.ll    |  40 +--
 .../NVPTX/anytypeof_constraints_valid.ll      |  38 +-
 .../overloaded-intrinsic-constraints.td       |  43 +++
 7 files changed, 337 insertions(+), 154 deletions(-)
 create mode 100644 llvm/test/TableGen/overloaded-intrinsic-constraints.td

diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 0b1daa102c2a2..dd782a6b5b895 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -183,6 +183,7 @@ namespace Intrinsic {
       AArch64Svcount,
       ArgumentTypeConstraint, // For AnyTypeOf - marks constrained argument
                               // types.
+      ArgumentTypeExclusion,  // For NoneTypeOf - marks excluded argument types.
     } Kind;
 
     union {
@@ -240,6 +241,12 @@ namespace Intrinsic {
       return Argument_NumConstraints;
     }
 
+    // For ArgumentTypeExclusion: get number of excluded types.
+    unsigned getArgumentNumExclusions() const {
+      assert(Kind == ArgumentTypeExclusion);
+      return Argument_NumConstraints;
+    }
+
     static IITDescriptor get(IITDescriptorKind K, unsigned Field) {
       IITDescriptor Result = { K, { Field } };
       return Result;
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 028b65c267ab7..0f02a77b5323e 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -374,6 +374,7 @@ def IIT_V2048 : IIT_Vec<2048, 52>;
 def IIT_V4096 : IIT_Vec<4096, 53>;
 // Constrained type encoding for overloaded intrinsics.
 def IIT_ANYTYPE : IIT_Base<93>;
+def IIT_NONETYPE : IIT_Base<94>;
 }
 
 defvar IIT_all_FixedTypes = !filter(iit, IIT_all,
@@ -467,6 +468,23 @@ class AnyTypeOf<list<LLVMType> allowed_types> : LLVMAnyType<Any> {
   );
 }
 
+// NoneTypeOf: Exclude specific types from overloaded type (inverse of AnyTypeOf).
+// Encoding follows the pattern: [IIT_ARG, EncAny, IIT_NONETYPE, count, type_sigs...].
+class NoneTypeOf<list<LLVMType> excluded_types> : LLVMAnyType<Any> {
+  list<LLVMType> ExcludedTypes = excluded_types;
+  
+  // Validation: specifying maximal 255 number of excluded types.
+  assert !le(!size(excluded_types), 255),
+         "NoneTypeOf cannot exceed 255 excluded types";
+  
+  let Sig = !listconcat(
+    [IIT_ARG.Number, EncAnyType<ArgCode>.ret],
+    [IIT_NONETYPE.Number, !size(excluded_types)],
+    !foldl([]<int>, excluded_types, accum, ty,
+      !listconcat(accum, ty.Sig))
+  );
+}
+
 // Match the type of another intrinsic parameter.  Number is an index into the
 // list of overloaded types for the intrinsic, excluding all the fixed types.
 // The Number value must refer to a previously listed type.  For example:
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index 232a5e89f5941..d0bb6b5232071 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -3387,11 +3387,10 @@ def int_nvvm_tensormap_replace_fill_mode :
                            ImmArgPrinter<"printTensormapFillMode">]>]>;
 
 // Test intrinsic - TODO: Add the feature to existing intrinsics and remove these test intrinsics.
-// IIT_LongEncodingTable entry:   /* 25339 */ 4, 15, 0, 93, 2, 3, 4, 15, 7, 15, 8, 93, 2, 15, 9, 7, 15, 16, 93, 2, 14, 24, 3, 15, 24, 93, 2, 5, 8, 15, 32, 93, 3, 3, 10, 4, 10, 7, 0,
-def int_nvvm_test_anytype : Intrinsic<[llvm_i32_ty],
-  [AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, LLVMMatchType<0>, AnyTypeOf<[llvm_anyint_ty, llvm_float_ty]>, AnyTypeOf<[llvm_ptr_ty, llvm_shared_ptr_ty]>,
-   AnyTypeOf<[llvm_i64_ty, llvm_double_ty]>, AnyTypeOf<[llvm_i16_ty, llvm_v4i32_ty, llvm_v4f32_ty]>],
-  [IntrNoMem]>;
+// IIT_LongEncodingTable entry:  /* 16662 */ 4, 15, 0, 93, 2, 3, 4, 15, 7, 15, 8, 93, 2, 15, 9, 7, 15, 16, 93, 2, 14, 24, 3, 15, 24, 94, 2, 5, 8, 15, 32, 93, 3, 3, 10, 4, 10, 7, 0,
+def int_nvvm_test_type : Intrinsic<[llvm_i32_ty],
+   [AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, LLVMMatchType<0>, AnyTypeOf<[llvm_anyint_ty, llvm_float_ty]>, AnyTypeOf<[llvm_ptr_ty, llvm_shared_ptr_ty]>, NoneTypeOf<[llvm_i64_ty, llvm_double_ty]>, AnyTypeOf<[llvm_i16_ty, llvm_v4i32_ty, llvm_v4f32_ty]>],
+   [IntrNoMem]>;
 
 // IIT_LongEncodingTable entry:  /* 15435 */ 21, 1, 4, 15, 0, 93, 2, 3, 4, 5, 4, 0,
 def int_nvvm_test_return_type : Intrinsic<[llvm_i32_ty, AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, llvm_i64_ty],
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 0e349925b2c8c..91720067e3a41 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -365,10 +365,24 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
         DecodeIITType(NextElt, Infos, Info, OutputTable);
       return;
     }
+
+    if (NextElt < Infos.size() && Infos[NextElt] == IIT_NONETYPE) {
+      NextElt++;
+
+      unsigned NumTypes = Infos[NextElt++];
+      OutputTable.push_back(
+          IITDescriptor::get(IITDescriptor::ArgumentTypeExclusion, NumTypes));
+
+      for (unsigned i = 0; i < NumTypes; ++i)
+        DecodeIITType(NextElt, Infos, Info, OutputTable);
+      return;
+    }
     return;
   }
   case IIT_ANYTYPE:
     llvm_unreachable("IIT_ANYTYPE must follow IIT_ARG");
+  case IIT_NONETYPE:
+    llvm_unreachable("IIT_NONETYPE must follow IIT_ARG");
   case IIT_EXTEND_ARG: {
     unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
     OutputTable.push_back(
@@ -587,6 +601,9 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
   case IITDescriptor::ArgumentTypeConstraint:
     llvm_unreachable(
         "ArgumentTypeConstraint should not appear in DecodeFixedType");
+  case IITDescriptor::ArgumentTypeExclusion:
+    llvm_unreachable(
+        "ArgumentTypeExclusion should not appear in DecodeFixedType");
   }
   llvm_unreachable("unhandled");
 }
@@ -608,6 +625,15 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
       (void)DecodeFixedType(TableRef, Tys, Context);
   }
 
+  if (!TableRef.empty() &&
+      TableRef[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
+    unsigned NumExclusions = TableRef[0].getArgumentNumExclusions();
+    TableRef = TableRef.slice(1);
+
+    for (unsigned i = 0; i < NumExclusions; ++i)
+      (void)DecodeFixedType(TableRef, Tys, Context);
+  }
+
   SmallVector<Type *, 8> ArgTys;
   while (!TableRef.empty()) {
     ArgTys.push_back(DecodeFixedType(TableRef, Tys, Context));
@@ -620,6 +646,15 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
       for (unsigned i = 0; i < NumConstraints; ++i)
         (void)DecodeFixedType(TableRef, Tys, Context);
     }
+
+    if (!TableRef.empty() &&
+        TableRef[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
+      unsigned NumExclusions = TableRef[0].getArgumentNumExclusions();
+      TableRef = TableRef.slice(1);
+
+      for (unsigned i = 0; i < NumExclusions; ++i)
+        (void)DecodeFixedType(TableRef, Tys, Context);
+    }
   }
 
   // DecodeFixedType returns Void for IITDescriptor::Void and
@@ -908,6 +943,14 @@ skipDescriptorsForSingleType(ArrayRef<Intrinsic::IITDescriptor> &Infos) {
       for (unsigned i = 0; i < NumConstraints; ++i)
         Count += skipDescriptorsForSingleType(Infos);
     }
+    if (!Infos.empty() &&
+        Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
+      unsigned NumExclusions = Infos[0].getArgumentNumExclusions();
+      Count++;
+      Infos = Infos.slice(1);
+      for (unsigned i = 0; i < NumExclusions; ++i)
+        Count += skipDescriptorsForSingleType(Infos);
+    }
     break;
 
   default:
@@ -1045,6 +1088,17 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
       return false;
     }
 
+    if (!Infos.empty() &&
+        Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
+      unsigned NumExclusions = Infos[0].getArgumentNumExclusions();
+      Infos = Infos.slice(1);
+
+      for (unsigned i = 0; i < NumExclusions; ++i)
+        skipDescriptorsForSingleType(Infos);
+
+      return false;
+    }
+
     return false;
 
   case IITDescriptor::ExtendArgument: {
@@ -1164,6 +1218,9 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
   case IITDescriptor::ArgumentTypeConstraint:
     llvm_unreachable(
         "ArgumentTypeConstraint should be handled in Argument case");
+  case IITDescriptor::ArgumentTypeExclusion:
+    llvm_unreachable(
+        "ArgumentTypeExclusion should be handled in Argument case");
   }
   llvm_unreachable("unhandled");
 }
@@ -1194,7 +1251,7 @@ Intrinsic::matchIntrinsicSignature(FunctionType *FTy,
   return MatchIntrinsicTypes_Match;
 }
 
-// Helper: Check if a type matches AnyTypeOf constraints using
+// Check if a type matches AnyTypeOf constraints using
 // matchIntrinsicType.
 static bool
 verifyTypeAgainstConstraints(Type *Ty, unsigned NumConstraints,
@@ -1204,10 +1261,10 @@ verifyTypeAgainstConstraints(Type *Ty, unsigned NumConstraints,
   bool Matched = false;
   for (unsigned i = 0; i < NumConstraints && !Matched; ++i) {
     ArrayRef<IITDescriptor> TypeDesc = Infos;
-    SmallVector<Type *, 4> DummyArgTys;
-    SmallVector<DeferredIntrinsicMatchPair, 2> DummyDeferredChecks;
+    SmallVector<Type *, 4> TempArgTys;
+    SmallVector<DeferredIntrinsicMatchPair, 2> TempDeferredChecks;
 
-    if (!matchIntrinsicType(Ty, TypeDesc, DummyArgTys, DummyDeferredChecks,
+    if (!matchIntrinsicType(Ty, TypeDesc, TempArgTys, TempDeferredChecks,
                             false)) {
       Matched = true;
       for (unsigned j = 0; j < NumConstraints - i; ++j)
@@ -1220,7 +1277,7 @@ verifyTypeAgainstConstraints(Type *Ty, unsigned NumConstraints,
   return Matched;
 }
 
-// Helper: Format a type as string for error messages.
+// Format a type as string for error messages.
 static std::string typeToString(Type *Ty) {
   std::string Str;
   raw_string_ostream OS(Str);
@@ -1228,118 +1285,137 @@ static std::string typeToString(Type *Ty) {
   return Str;
 }
 
-bool Intrinsic::verifyIntrinsicTypeConstraints(ID id, FunctionType *FTy,
-                                               std::string &ErrMsg) {
+enum class ConstraintKind {
+  Allowed,
+  Excluded,
+};
 
-  if (id == 0 || id >= Intrinsic::num_intrinsics)
-    return true;
+static bool
+checkAndConsumeConstraintBlock(Type *Ty, ConstraintKind Kind,
+                               ArrayRef<Intrinsic::IITDescriptor> &Infos,
+                               const Twine &Constraint, std::string &ErrMsg) {
+  using namespace Intrinsic;
 
-  SmallVector<IITDescriptor, 8> Table;
-  getIntrinsicInfoTableEntries(id, Table);
+  unsigned Count = Kind == ConstraintKind::Allowed
+                       ? Infos.front().getArgumentNumConstraints()
+                       : Infos.front().getArgumentNumExclusions();
+  Infos = Infos.slice(1);
 
-  if (Table.empty())
+  bool Matches = verifyTypeAgainstConstraints(Ty, Count, Infos);
+  bool Violates = Kind == ConstraintKind::Allowed ? !Matches : Matches;
+  if (!Violates)
     return true;
 
-  ArrayRef<IITDescriptor> Infos = Table;
-  SmallVector<Type *, 4> ArgTys;
+  ErrMsg = (Constraint + " type '" + typeToString(Ty) + "'" +
+            (Kind == ConstraintKind::Allowed ? " not in allowed types"
+                                             : " is in excluded types"))
+               .str();
+  return false;
+}
 
-  // Processing return type.
-  Type *RetTy = FTy->getReturnType();
-  if (!Infos.empty() && Infos[0].Kind == IITDescriptor::Argument) {
-    Infos = Infos.slice(1);
+// Verify the Struct return types.
+static bool
+verifyIntrinsicStructOutputTypes(Type *RetTy,
+                                 ArrayRef<Intrinsic::IITDescriptor> &Infos,
+                                 std::string &ErrMsg) {
+  using namespace Intrinsic;
 
-    if (!Infos.empty() &&
-        Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
-      unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
-      Infos = Infos.slice(1);
+  auto *STy = dyn_cast<StructType>(RetTy);
+  if (!STy) {
+    skipDescriptorsForSingleType(Infos);
+    return false;
+  }
 
-      bool Matched = false;
-
-      // Check if a struct type's elements are all present in AnyTypeOf
-      // constraint list.
-      if (auto *STy = dyn_cast<StructType>(RetTy)) {
-        SmallVector<Type *, 8> AllowedTypes;
-        ArrayRef<IITDescriptor> TempInfos = Infos;
-        for (unsigned i = 0; i < NumConstraints; ++i) {
-          ArrayRef<IITDescriptor> TypeDesc = TempInfos;
-          SmallVector<Type *, 4> DummyTys;
-          Type *ConstraintTy =
-              DecodeFixedType(TypeDesc, DummyTys, FTy->getContext());
-          AllowedTypes.push_back(ConstraintTy);
-          TempInfos = TypeDesc;
-        }
-
-        Matched = llvm::all_of(STy->elements(), [&](Type *ElemTy) {
-          return llvm::is_contained(AllowedTypes, ElemTy);
-        });
-
-        if (Matched) {
-          for (unsigned i = 0; i < NumConstraints; ++i)
-            skipDescriptorsForSingleType(Infos);
-          Matched = true;
-        }
-      }
+  if (Infos.empty() || Infos[0].Kind != IITDescriptor::Struct) {
+    ErrMsg = "Return type struct encoding is malformed";
+    return false;
+  }
 
-      if (!Matched) {
-        for (unsigned i = 0; i < NumConstraints && !Matched; ++i) {
-          ArrayRef<IITDescriptor> TypeDesc = Infos;
-          SmallVector<Type *, 4> DummyArgTys;
-          SmallVector<DeferredIntrinsicMatchPair, 2> DummyDeferredChecks;
-
-          if (!matchIntrinsicType(RetTy, TypeDesc, DummyArgTys,
-                                  DummyDeferredChecks, false)) {
-            Matched = true;
-            for (unsigned j = 0; j < NumConstraints - i; ++j)
-              skipDescriptorsForSingleType(Infos);
-            break;
-          }
-          skipDescriptorsForSingleType(Infos);
-        }
-      }
+  unsigned NumElements = Infos[0].Struct_NumElements;
+  Infos = Infos.slice(1);
 
-      if (!Matched) {
-        ErrMsg =
-            "Return type '" + typeToString(RetTy) + "' not in allowed types";
-        return false;
-      }
-    }
-  } else if (!Infos.empty() && Infos[0].Kind == IITDescriptor::Struct) {
-    // Handle struct return type with AnyTypeOf constrained elements.
-    auto *STy = dyn_cast<StructType>(RetTy);
-    if (!STy)
-      skipDescriptorsForSingleType(Infos);
-    else {
-      unsigned NumElements = Infos[0].Struct_NumElements;
+  for (unsigned ElemIdx = 0; ElemIdx < NumElements; ++ElemIdx) {
+    if (Infos.empty())
+      break;
+
+    if (Infos[0].Kind == IITDescriptor::Argument) {
       Infos = Infos.slice(1);
 
-      for (unsigned ElemIdx = 0; ElemIdx < NumElements; ++ElemIdx) {
-        if (Infos.empty())
-          break;
-
-        if (Infos[0].Kind == IITDescriptor::Argument) {
-          Infos = Infos.slice(1);
-
-          if (!Infos.empty() &&
-              Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
-            unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
-            Infos = Infos.slice(1);
-
-            Type *ElemTy = STy->getElementType(ElemIdx);
-            if (!verifyTypeAgainstConstraints(ElemTy, NumConstraints, Infos)) {
-              ErrMsg = "Return type struct element " + std::to_string(ElemIdx) +
-                       " type '" + typeToString(ElemTy) +
-                       "' not in allowed types";
-              return false;
-            }
-          }
-        } else
-          skipDescriptorsForSingleType(Infos);
+      Type *ElemTy = STy->getElementType(ElemIdx);
+
+      if (!Infos.empty() &&
+          Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+        if (!checkAndConsumeConstraintBlock(
+                ElemTy, ConstraintKind::Allowed, Infos,
+                Twine("Return type struct element ") + Twine(ElemIdx), ErrMsg))
+          return false;
+      } else if (!Infos.empty() &&
+                 Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
+        if (!checkAndConsumeConstraintBlock(
+                ElemTy, ConstraintKind::Excluded, Infos,
+                Twine("Return type struct element ") + Twine(ElemIdx), ErrMsg))
+          return false;
       }
-    }
-  } else if (!Infos.empty())
+    } else
+      skipDescriptorsForSingleType(Infos);
+  }
+
+  return true;
+}
+
+// Verify the non struct return types.
+static bool
+verifyIntrinsicNonStructOutputTypes(Type *RetTy,
+                                    ArrayRef<Intrinsic::IITDescriptor> &Infos,
+                                    std::string &ErrMsg) {
+  using namespace Intrinsic;
+
+  if (Infos.empty())
+    return true;
+
+  if (Infos[0].Kind != IITDescriptor::Argument) {
     skipDescriptorsForSingleType(Infos);
+    return true;
+  }
+
+  Infos = Infos.slice(1);
+
+  if (!Infos.empty() &&
+      Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
+    if (!checkAndConsumeConstraintBlock(RetTy, ConstraintKind::Allowed, Infos,
+                                        "Return type", ErrMsg))
+      return false;
+  } else if (!Infos.empty() &&
+             Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
+    if (!checkAndConsumeConstraintBlock(RetTy, ConstraintKind::Excluded, Infos,
+                                        "Return type", ErrMsg))
+      return false;
+  }
+
+  return true;
+}
+
+// Verify the return types.
+static bool
+verifyIntrinsicOutputTypes(Intrinsic::ID id, FunctionType *FTy,
+                           ArrayRef<Intrinsic::IITDescriptor> &Infos,
+                           std::string &ErrMsg) {
+
+  Type *RetTy = FTy->getReturnType();
+  if (RetTy->isStructTy())
+    return verifyIntrinsicStructOutputTypes(RetTy, Infos, ErrMsg);
+
+  return verifyIntrinsicNonStructOutputTypes(RetTy, Infos, ErrMsg);
+}
+
+// Verify the input parameters.
+static bool verifyIntrinsicInputTypes(Intrinsic::ID id, FunctionType *FTy,
+                                      ArrayRef<Intrinsic::IITDescriptor> &Infos,
+                                      std::string &ErrMsg) {
+  using namespace Intrinsic;
+
+  SmallVector<Type *, 4> ArgTys;
 
-  // Processing parameters.
   for (unsigned ParamIdx = 0; ParamIdx < FTy->getNumParams(); ++ParamIdx) {
     if (Infos.empty())
       break;
@@ -1352,21 +1428,61 @@ bool Intrinsic::verifyIntrinsicTypeConstraints(ID id, FunctionType *FTy,
 
       if (!Infos.empty() &&
           Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
-        unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
-        Infos = Infos.slice(1);
-
-        if (!verifyTypeAgainstConstraints(ParamTy, NumConstraints, Infos)) {
-          ErrMsg = "Parameter " + std::to_string(ParamIdx) + " type '" +
-                   typeToString(ParamTy) + "' not in allowed types";
+        if (!checkAndConsumeConstraintBlock(
+                ParamTy, ConstraintKind::Allowed, Infos,
+                Twine("Parameter ") + Twine(ParamIdx), ErrMsg))
+          return false;
+        if (ArgNum == ArgTys.size())
+          ArgTys.push_back(ParamTy);
+      } else if (!Infos.empty() &&
+                 Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
+        if (!checkAndConsumeConstraintBlock(
+                ParamTy, ConstraintKind::Excluded, Infos,
+                Twine("Parameter ") + Twine(ParamIdx), ErrMsg))
           return false;
-        }
-
         if (ArgNum == ArgTys.size())
           ArgTys.push_back(ParamTy);
       }
     } else
       skipDescriptorsForSingleType(Infos);
   }
+
+  return true;
+}
+
+bool Intrinsic::verifyIntrinsicTypeConstraints(ID id, FunctionType *FTy,
+                                               std::string &ErrMsg) {
+  if (id == 0 || id >= Intrinsic::num_intrinsics)
+    return true;
+
+  if (!isOverloaded(id))
+    return true;
+
+  SmallVector<IITDescriptor, 8> Table;
+  getIntrinsicInfoTableEntries(id, Table);
+  if (Table.empty())
+    return true;
+
+  ArrayRef<IITDescriptor> Infos = Table;
+
+  // if there are no constraint descriptors, skip verification.
+  bool HasConstraints = false;
+  for (const auto &D : Infos) {
+    if (D.Kind == IITDescriptor::ArgumentTypeConstraint ||
+        D.Kind == IITDescriptor::ArgumentTypeExclusion) {
+      HasConstraints = true;
+      break;
+    }
+  }
+  if (!HasConstraints)
+    return true;
+
+  if (!verifyIntrinsicOutputTypes(id, FTy, Infos, ErrMsg))
+    return false;
+
+  if (!verifyIntrinsicInputTypes(id, FTy, Infos, ErrMsg))
+    return false;
+
   return true;
 }
 
diff --git a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
index 7647a04898299..faf97a1875dab 100644
--- a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
+++ b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
@@ -1,39 +1,39 @@
 ; RUN: not llvm-as < %s -o /dev/null
-; Test cases for int_nvvm_test_anytype intrinsic - INVALID combinations
+; Test cases for int_nvvm_test_type intrinsic - INVALID combinations
 
 ; arg0 must be i16 or i32, not i8
-define i32 @invalid_arg0_i8(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i8.i8.i32.p0.i64.i16(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+define i32 @invalid_arg0_i8(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i8.i8.i32.p0.i32.i16(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
   ret i32 %result
 }
 
 ; arg1 must match arg0 (i16), not i32
-define i32 @invalid_arg1_mismatch_i16_i32(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i16.i32.i32.p0.i64.i16(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+define i32 @invalid_arg1_mismatch_i16_i32(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i16.i32.i32.p0.i32.i16(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
   ret i32 %result
 }
 
 ; arg2 must be anyint or float, not double
-define i32 @invalid_arg2_double(i32 %a0, i32 %a1, double %a2, ptr %a3, i64 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.f64.p0.i64.i16(i32 %a0, i32 %a1, double %a2, ptr %a3, i64 %a4, i16 %a5)
+define i32 @invalid_arg2_double(i32 %a0, i32 %a1, double %a2, ptr %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.f64.p0.i32.i16(i32 %a0, i32 %a1, double %a2, ptr %a3, i32 %a4, i16 %a5)
   ret i32 %result
 }
 
 ; arg3 must be ptr or ptr addrspace(3), not ptr addrspace(1) (global)
-define i32 @invalid_arg3_ptr_as1_wrong(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i64 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p1.i64.i16(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i64 %a4, i16 %a5)
+define i32 @invalid_arg3_ptr_as1_wrong(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p1.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i32 %a4, i16 %a5)
   ret i32 %result
 }
 
-; arg4 must be i64 or double, not i32
-define i32 @invalid_arg4_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
+; arg4 must not be i64 or double
+define i32 @test_arg4_double(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.f64.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, i16 %a5)
   ret i32 %result
 }
 
 ; arg5 must be i16, <4 x i32>, or <4 x f32>, not <2 x i32>
-define i32 @invalid_arg5_v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <2 x i32> %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <2 x i32> %a5)
+define i32 @invalid_arg5_v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, <2 x i32> %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, <2 x i32> %a5)
   ret i32 %result
 }
 
@@ -42,10 +42,10 @@ define {i32, i8, i64} @invalid_return_type_i8(i32 %arg) {
   ret {i32, i8, i64} %result
 }
 
-declare i32 @llvm.nvvm.test.anytype.i8.i8.i32.p0.i64.i16(i8, i8, i32, ptr, i64, i16)
-declare i32 @llvm.nvvm.test.anytype.i16.i32.i32.p0.i64.i16(i16, i32, i32, ptr, i64, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.f64.p0.i64.i16(i32, i32, double, ptr, i64, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p1.i64.i16(i32, i32, i32, ptr addrspace(1), i64, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i32.i16(i32, i32, i32, ptr, i32, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v2i32(i32, i32, i32, ptr, i64, <2 x i32>)
+declare i32 @llvm.nvvm.test.type.i8.i8.i32.p0.i32.i16(i8, i8, i32, ptr, i32, i16)
+declare i32 @llvm.nvvm.test.type.i16.i32.i32.p0.i32.i16(i16, i32, i32, ptr, i32, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.f64.p0.i32.i16(i32, i32, double, ptr, i32, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.i32.p1.i32.i16(i32, i32, i32, ptr addrspace(1), i32, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.f64.i16(i32, i32, i32, ptr, double, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.v2i32(i32, i32, i32, ptr, i32, <2 x i32>)
 declare {i32, i8, i64} @llvm.nvvm.test.return.type.i8(i32)
diff --git a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll
index 2efa46c04116f..95fb9c9c30157 100644
--- a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll
+++ b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll
@@ -1,33 +1,33 @@
 ; RUN: llvm-as < %s -o /dev/null
-; Test cases for int_nvvm_test_anytype intrinsic - VALID combinations
+; Test cases for int_nvvm_test_type intrinsic - VALID combinations
 
-define i32 @test_arg0_i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i16.i16.i32.p0.i64.i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+define i32 @test_arg0_i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i16.i16.i32.p0.i32.i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
   ret i32 %result
 }
 
-define i32 @test_arg0_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+define i32 @test_arg0_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
   ret i32 %result
 }
 
-define i32 @test_arg2_anyint(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, i16 %a5)
+define i32 @test_arg2_anyint(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
   ret i32 %result
 }
 
-define i32 @test_arg3_shared_ptr(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i64 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p3.i64.i16(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i64 %a4, i16 %a5)
+define i32 @test_arg3_shared_ptr(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i32 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p3.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i32 %a4, i16 %a5)
   ret i32 %result
 }
 
-define i32 @test_arg4_double(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.f64.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, i16 %a5)
+define i32 @invalid_arg4_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i16 %a4, i16 %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i16.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i16 %a4, i16 %a5)
   ret i32 %result
 }
 
-define i32 @test_arg5_v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <4 x i32> %a5) {
-  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <4 x i32> %a5)
+define i32 @test_arg5_v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, <4 x i32> %a5) {
+  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, <4 x i32> %a5)
   ret i32 %result
 }
 
@@ -36,10 +36,10 @@ define {i32, i32, i64} @test_return_type_valid(i32 %arg) {
   ret {i32, i32, i64} %result
 }
 
-declare i32 @llvm.nvvm.test.anytype.i16.i16.i32.p0.i64.i16(i16, i16, i32, ptr, i64, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.i16(i32, i32, i32, ptr, i64, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.f32.p0.i64.i16(i32, i32, i32, ptr, i64, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p3.i64.i16(i32, i32, i32, ptr addrspace(3), i64, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.f64.i16(i32, i32, i32, ptr, double, i16)
-declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v4i32(i32, i32, i32, ptr, i64, <4 x i32>)
+declare i32 @llvm.nvvm.test.type.i16.i16.i32.p0.i32.i16(i16, i16, i32, ptr, i32, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.i16(i32, i32, i32, ptr, i32, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.f32.p0.i32.i16(i32, i32, float, ptr, i32, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.i32.p3.i32.i16(i32, i32, i32, ptr addrspace(3), i32, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i16.i16(i32, i32, i32, ptr, i16, i16)
+declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.v4i32(i32, i32, i32, ptr, i32, <4 x i32>)
 declare {i32, i32, i64} @llvm.nvvm.test.return.type.i32(i32)
diff --git a/llvm/test/TableGen/overloaded-intrinsic-constraints.td b/llvm/test/TableGen/overloaded-intrinsic-constraints.td
new file mode 100644
index 0000000000000..b6f04ded18bb5
--- /dev/null
+++ b/llvm/test/TableGen/overloaded-intrinsic-constraints.td
@@ -0,0 +1,43 @@
+// RUN: llvm-tblgen -gen-intrinsic-enums -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS | FileCheck %s --check-prefix=CHECK-ENUM
+// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS | FileCheck %s --check-prefix=CHECK-IMPL
+
+include "llvm/IR/Intrinsics.td"
+
+// Test AnyTypeOf constraints for overloaded intrinsics.
+def int_anytypeof_multi : Intrinsic<
+  [llvm_i32_ty],
+  [
+    AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>,
+    AnyTypeOf<[llvm_anyint_ty, llvm_float_ty, llvm_double_ty]>
+  ],
+  [IntrNoMem]
+>;
+
+// Test mixed AnyTypeOf + NoneTypeOf.
+def int_mixed_constraints : Intrinsic<
+  [llvm_i32_ty],
+  [
+    AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>,
+    NoneTypeOf<[llvm_i8_ty]>
+  ],
+  [IntrNoMem]
+>;
+
+// Test NoneTypeOf on return type.
+def int_nonetypeof_return : Intrinsic<
+  [NoneTypeOf<[llvm_i8_ty, llvm_double_ty]>],
+  [llvm_i32_ty],
+  [IntrNoMem]
+>;
+
+// Verify enum generation.
+// CHECK-ENUM: anytypeof_multi = {{[0-9]+}}, // llvm.anytypeof.multi
+// CHECK-ENUM: mixed_constraints{{.*}}// llvm.mixed.constraints
+// CHECK-ENUM: nonetypeof_return{{.*}}// llvm.nonetypeof.return
+
+// Verify encoding table generation.
+// CHECK-IMPL: static constexpr unsigned char IIT_LongEncodingTable[] = {
+// CHECK-IMPL-NEXT: /* 0 */ 4, 15, 0, 93, 2, 3, 4, 15, 8, 94, 1, 2, 0,
+// CHECK-IMPL-NEXT: /* 13 */ 15, 0, 94, 2, 2, 8, 4, 0,
+// CHECK-IMPL-NEXT: /* 21 */ 4, 15, 0, 93, 2, 3, 4, 15, 8, 93, 3, 15, 9, 7, 8, 0,
+// CHECK-IMPL-NEXT: 255

>From f3866416b589429e00610ad9f8d9db35deee5c42 Mon Sep 17 00:00:00 2001
From: Dharuni R Acharya <dharuniracharya at gmail.com>
Date: Mon, 26 Jan 2026 08:44:53 +0000
Subject: [PATCH 4/5] Address Comments

---
 llvm/include/llvm/IR/Intrinsics.h             |  29 +-
 llvm/include/llvm/IR/Intrinsics.td            |  18 -
 llvm/include/llvm/IR/IntrinsicsNVVM.td        |   6 +-
 llvm/lib/IR/Intrinsics.cpp                    | 315 +++---------------
 llvm/lib/IR/Verifier.cpp                      |  12 +-
 .../NVPTX/anytypeof_constraints_invalid.ll    |  42 +--
 .../NVPTX/anytypeof_constraints_valid.ll      |  38 +--
 .../overloaded-intrinsic-constraints.td       |  23 +-
 8 files changed, 114 insertions(+), 369 deletions(-)

diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index dd782a6b5b895..70e94c4d1d6ff 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -183,7 +183,6 @@ namespace Intrinsic {
       AArch64Svcount,
       ArgumentTypeConstraint, // For AnyTypeOf - marks constrained argument
                               // types.
-      ArgumentTypeExclusion,  // For NoneTypeOf - marks excluded argument types.
     } Kind;
 
     union {
@@ -241,12 +240,6 @@ namespace Intrinsic {
       return Argument_NumConstraints;
     }
 
-    // For ArgumentTypeExclusion: get number of excluded types.
-    unsigned getArgumentNumExclusions() const {
-      assert(Kind == ArgumentTypeExclusion);
-      return Argument_NumConstraints;
-    }
-
     static IITDescriptor get(IITDescriptorKind K, unsigned Field) {
       IITDescriptor Result = { K, { Field } };
       return Result;
@@ -283,9 +276,12 @@ namespace Intrinsic {
   ///
   /// Returns false if the given type matches with the constraints, true
   /// otherwise.
-  LLVM_ABI MatchIntrinsicTypesResult
-  matchIntrinsicSignature(FunctionType *FTy, ArrayRef<IITDescriptor> &Infos,
-                          SmallVectorImpl<Type *> &ArgTys);
+  ///
+  /// If ErrMsg is non-null, detailed diagnostic message is produced
+  /// on type constraint violations.
+  LLVM_ABI MatchIntrinsicTypesResult matchIntrinsicSignature(
+      FunctionType *FTy, ArrayRef<IITDescriptor> &Infos,
+      SmallVectorImpl<Type *> &ArgTys, std::string *ErrMsg = nullptr);
 
   /// Verify if the intrinsic has variable arguments. This method is intended to
   /// be called after all the fixed arguments have been matched first.
@@ -294,22 +290,23 @@ namespace Intrinsic {
   LLVM_ABI bool matchIntrinsicVarArg(bool isVarArg,
                                      ArrayRef<IITDescriptor> &Infos);
 
-  /// Verify type constraints for AnyTypeOf constrained intrinsics.
-  LLVM_ABI bool verifyIntrinsicTypeConstraints(ID id, FunctionType *FTy,
-                                               std::string &ErrMsg);
-
   /// Gets the type arguments of an intrinsic call by matching type contraints
   /// specified by the .td file. The overloaded types are pushed into the
   /// AgTys vector.
   ///
   /// Returns false if the given ID and function type combination is not a
   /// valid intrinsic call.
+  ///
+  /// If ErrMsg is non-null, detailed diagnostic message is produced
+  /// on type constraint violations.
   LLVM_ABI bool getIntrinsicSignature(Intrinsic::ID, FunctionType *FT,
-                                      SmallVectorImpl<Type *> &ArgTys);
+                                      SmallVectorImpl<Type *> &ArgTys,
+                                      std::string *ErrMsg = nullptr);
 
   /// Same as previous, but accepts a Function instead of ID and FunctionType.
   LLVM_ABI bool getIntrinsicSignature(Function *F,
-                                      SmallVectorImpl<Type *> &ArgTys);
+                                      SmallVectorImpl<Type *> &ArgTys,
+                                      std::string *ErrMsg = nullptr);
 
   // Checks if the intrinsic name matches with its signature and if not
   // returns the declaration with the same signature and remangled name.
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 0f02a77b5323e..028b65c267ab7 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -374,7 +374,6 @@ def IIT_V2048 : IIT_Vec<2048, 52>;
 def IIT_V4096 : IIT_Vec<4096, 53>;
 // Constrained type encoding for overloaded intrinsics.
 def IIT_ANYTYPE : IIT_Base<93>;
-def IIT_NONETYPE : IIT_Base<94>;
 }
 
 defvar IIT_all_FixedTypes = !filter(iit, IIT_all,
@@ -468,23 +467,6 @@ class AnyTypeOf<list<LLVMType> allowed_types> : LLVMAnyType<Any> {
   );
 }
 
-// NoneTypeOf: Exclude specific types from overloaded type (inverse of AnyTypeOf).
-// Encoding follows the pattern: [IIT_ARG, EncAny, IIT_NONETYPE, count, type_sigs...].
-class NoneTypeOf<list<LLVMType> excluded_types> : LLVMAnyType<Any> {
-  list<LLVMType> ExcludedTypes = excluded_types;
-  
-  // Validation: specifying maximal 255 number of excluded types.
-  assert !le(!size(excluded_types), 255),
-         "NoneTypeOf cannot exceed 255 excluded types";
-  
-  let Sig = !listconcat(
-    [IIT_ARG.Number, EncAnyType<ArgCode>.ret],
-    [IIT_NONETYPE.Number, !size(excluded_types)],
-    !foldl([]<int>, excluded_types, accum, ty,
-      !listconcat(accum, ty.Sig))
-  );
-}
-
 // Match the type of another intrinsic parameter.  Number is an index into the
 // list of overloaded types for the intrinsic, excluding all the fixed types.
 // The Number value must refer to a previously listed type.  For example:
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index d0bb6b5232071..a3ae44ba29177 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -3387,9 +3387,9 @@ def int_nvvm_tensormap_replace_fill_mode :
                            ImmArgPrinter<"printTensormapFillMode">]>]>;
 
 // Test intrinsic - TODO: Add the feature to existing intrinsics and remove these test intrinsics.
-// IIT_LongEncodingTable entry:  /* 16662 */ 4, 15, 0, 93, 2, 3, 4, 15, 7, 15, 8, 93, 2, 15, 9, 7, 15, 16, 93, 2, 14, 24, 3, 15, 24, 94, 2, 5, 8, 15, 32, 93, 3, 3, 10, 4, 10, 7, 0,
-def int_nvvm_test_type : Intrinsic<[llvm_i32_ty],
-   [AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, LLVMMatchType<0>, AnyTypeOf<[llvm_anyint_ty, llvm_float_ty]>, AnyTypeOf<[llvm_ptr_ty, llvm_shared_ptr_ty]>, NoneTypeOf<[llvm_i64_ty, llvm_double_ty]>, AnyTypeOf<[llvm_i16_ty, llvm_v4i32_ty, llvm_v4f32_ty]>],
+// IIT_LongEncodingTable entry:  /* 16662 */ 4, 15, 0, 93, 2, 3, 4, 15, 7, 15, 8, 93, 2, 15, 9, 7, 15, 16, 93, 2, 14, 24, 3, 15, 24, 93, 2, 5, 8, 15, 32, 93, 2, 24, 1, 9, 5, 0,
+def int_nvvm_test_anytype : Intrinsic<[llvm_i32_ty],
+   [AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, LLVMMatchType<0>, AnyTypeOf<[llvm_anyint_ty, llvm_float_ty]>, AnyTypeOf<[llvm_ptr_ty, llvm_shared_ptr_ty]>, AnyTypeOf<[llvm_i64_ty, llvm_double_ty]>, AnyTypeOf<[llvm_global_ptr_ty, llvm_v2i64_ty]>],
    [IntrNoMem]>;
 
 // IIT_LongEncodingTable entry:  /* 15435 */ 21, 1, 4, 15, 0, 93, 2, 3, 4, 5, 4, 0,
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 91720067e3a41..f271077eb68b9 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -366,23 +366,10 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
       return;
     }
 
-    if (NextElt < Infos.size() && Infos[NextElt] == IIT_NONETYPE) {
-      NextElt++;
-
-      unsigned NumTypes = Infos[NextElt++];
-      OutputTable.push_back(
-          IITDescriptor::get(IITDescriptor::ArgumentTypeExclusion, NumTypes));
-
-      for (unsigned i = 0; i < NumTypes; ++i)
-        DecodeIITType(NextElt, Infos, Info, OutputTable);
-      return;
-    }
     return;
   }
   case IIT_ANYTYPE:
     llvm_unreachable("IIT_ANYTYPE must follow IIT_ARG");
-  case IIT_NONETYPE:
-    llvm_unreachable("IIT_NONETYPE must follow IIT_ARG");
   case IIT_EXTEND_ARG: {
     unsigned ArgInfo = (NextElt == Infos.size() ? 0 : Infos[NextElt++]);
     OutputTable.push_back(
@@ -601,9 +588,6 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
   case IITDescriptor::ArgumentTypeConstraint:
     llvm_unreachable(
         "ArgumentTypeConstraint should not appear in DecodeFixedType");
-  case IITDescriptor::ArgumentTypeExclusion:
-    llvm_unreachable(
-        "ArgumentTypeExclusion should not appear in DecodeFixedType");
   }
   llvm_unreachable("unhandled");
 }
@@ -625,15 +609,6 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
       (void)DecodeFixedType(TableRef, Tys, Context);
   }
 
-  if (!TableRef.empty() &&
-      TableRef[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
-    unsigned NumExclusions = TableRef[0].getArgumentNumExclusions();
-    TableRef = TableRef.slice(1);
-
-    for (unsigned i = 0; i < NumExclusions; ++i)
-      (void)DecodeFixedType(TableRef, Tys, Context);
-  }
-
   SmallVector<Type *, 8> ArgTys;
   while (!TableRef.empty()) {
     ArgTys.push_back(DecodeFixedType(TableRef, Tys, Context));
@@ -646,15 +621,6 @@ FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
       for (unsigned i = 0; i < NumConstraints; ++i)
         (void)DecodeFixedType(TableRef, Tys, Context);
     }
-
-    if (!TableRef.empty() &&
-        TableRef[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
-      unsigned NumExclusions = TableRef[0].getArgumentNumExclusions();
-      TableRef = TableRef.slice(1);
-
-      for (unsigned i = 0; i < NumExclusions; ++i)
-        (void)DecodeFixedType(TableRef, Tys, Context);
-    }
   }
 
   // DecodeFixedType returns Void for IITDescriptor::Void and
@@ -943,14 +909,6 @@ skipDescriptorsForSingleType(ArrayRef<Intrinsic::IITDescriptor> &Infos) {
       for (unsigned i = 0; i < NumConstraints; ++i)
         Count += skipDescriptorsForSingleType(Infos);
     }
-    if (!Infos.empty() &&
-        Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
-      unsigned NumExclusions = Infos[0].getArgumentNumExclusions();
-      Count++;
-      Infos = Infos.slice(1);
-      for (unsigned i = 0; i < NumExclusions; ++i)
-        Count += skipDescriptorsForSingleType(Infos);
-    }
     break;
 
   default:
@@ -959,6 +917,16 @@ skipDescriptorsForSingleType(ArrayRef<Intrinsic::IITDescriptor> &Infos) {
   return Count;
 }
 
+// Forward declarations for constraint validation helpers.
+static std::string typeToString(Type *Ty);
+static bool
+verifyTypeAgainstConstraints(Type *Ty, unsigned NumConstraints,
+                             ArrayRef<Intrinsic::IITDescriptor> &Infos);
+static bool
+validateAndConsumeConstraint(Type *Ty,
+                             ArrayRef<Intrinsic::IITDescriptor> &Infos,
+                             const Twine &Constraint, std::string &ErrMsg);
+
 using DeferredIntrinsicMatchPair =
     std::pair<Type *, ArrayRef<Intrinsic::IITDescriptor>>;
 
@@ -966,7 +934,7 @@ static bool
 matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
                    SmallVectorImpl<Type *> &ArgTys,
                    SmallVectorImpl<DeferredIntrinsicMatchPair> &DeferredChecks,
-                   bool IsDeferredCheck) {
+                   bool IsDeferredCheck, std::string *ErrMsg = nullptr) {
   using namespace Intrinsic;
 
   // If we ran out of descriptors, there are too many arguments.
@@ -1020,7 +988,7 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
     VectorType *VT = dyn_cast<VectorType>(Ty);
     return !VT || VT->getElementCount() != D.Vector_Width ||
            matchIntrinsicType(VT->getElementType(), Infos, ArgTys,
-                              DeferredChecks, IsDeferredCheck);
+                              DeferredChecks, IsDeferredCheck, ErrMsg);
   }
   case IITDescriptor::Pointer: {
     PointerType *PT = dyn_cast<PointerType>(Ty);
@@ -1035,7 +1003,7 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
 
     for (unsigned i = 0, e = D.Struct_NumElements; i != e; ++i)
       if (matchIntrinsicType(ST->getElementType(i), Infos, ArgTys,
-                             DeferredChecks, IsDeferredCheck))
+                             DeferredChecks, IsDeferredCheck, ErrMsg))
         return true;
     return false;
   }
@@ -1079,24 +1047,18 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
 
     if (!Infos.empty() &&
         Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
-      unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
-      Infos = Infos.slice(1);
-
-      for (unsigned i = 0; i < NumConstraints; ++i)
-        skipDescriptorsForSingleType(Infos);
-
-      return false;
-    }
-
-    if (!Infos.empty() &&
-        Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
-      unsigned NumExclusions = Infos[0].getArgumentNumExclusions();
-      Infos = Infos.slice(1);
-
-      for (unsigned i = 0; i < NumExclusions; ++i)
-        skipDescriptorsForSingleType(Infos);
-
-      return false;
+      if (ErrMsg) {
+        if (!validateAndConsumeConstraint(Ty, Infos,
+                                          Twine("Overloaded Argument ") +
+                                              Twine(D.getArgumentNumber()),
+                                          *ErrMsg))
+          return true;
+      } else {
+        unsigned NumConstraints = Infos[0].getArgumentNumConstraints();
+        Infos = Infos.slice(1);
+        for (unsigned i = 0; i < NumConstraints; ++i)
+          skipDescriptorsForSingleType(Infos);
+      }
     }
 
     return false;
@@ -1157,7 +1119,7 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
       EltTy = ThisArgType->getElementType();
     }
     return matchIntrinsicType(EltTy, Infos, ArgTys, DeferredChecks,
-                              IsDeferredCheck);
+                              IsDeferredCheck, ErrMsg);
   }
   case IITDescriptor::VecOfAnyPtrsToElt: {
     unsigned RefArgNumber = D.getRefArgNumber();
@@ -1218,32 +1180,28 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
   case IITDescriptor::ArgumentTypeConstraint:
     llvm_unreachable(
         "ArgumentTypeConstraint should be handled in Argument case");
-  case IITDescriptor::ArgumentTypeExclusion:
-    llvm_unreachable(
-        "ArgumentTypeExclusion should be handled in Argument case");
   }
   llvm_unreachable("unhandled");
 }
 
-Intrinsic::MatchIntrinsicTypesResult
-Intrinsic::matchIntrinsicSignature(FunctionType *FTy,
-                                   ArrayRef<Intrinsic::IITDescriptor> &Infos,
-                                   SmallVectorImpl<Type *> &ArgTys) {
+Intrinsic::MatchIntrinsicTypesResult Intrinsic::matchIntrinsicSignature(
+    FunctionType *FTy, ArrayRef<Intrinsic::IITDescriptor> &Infos,
+    SmallVectorImpl<Type *> &ArgTys, std::string *ErrMsg) {
   SmallVector<DeferredIntrinsicMatchPair, 2> DeferredChecks;
   if (matchIntrinsicType(FTy->getReturnType(), Infos, ArgTys, DeferredChecks,
-                         false))
+                         false, ErrMsg))
     return MatchIntrinsicTypes_NoMatchRet;
 
   unsigned NumDeferredReturnChecks = DeferredChecks.size();
 
   for (auto *Ty : FTy->params())
-    if (matchIntrinsicType(Ty, Infos, ArgTys, DeferredChecks, false))
+    if (matchIntrinsicType(Ty, Infos, ArgTys, DeferredChecks, false, ErrMsg))
       return MatchIntrinsicTypes_NoMatchArg;
 
   for (unsigned I = 0, E = DeferredChecks.size(); I != E; ++I) {
     DeferredIntrinsicMatchPair &Check = DeferredChecks[I];
     if (matchIntrinsicType(Check.first, Check.second, ArgTys, DeferredChecks,
-                           true))
+                           true, ErrMsg))
       return I < NumDeferredReturnChecks ? MatchIntrinsicTypes_NoMatchRet
                                          : MatchIntrinsicTypes_NoMatchArg;
   }
@@ -1285,207 +1243,30 @@ static std::string typeToString(Type *Ty) {
   return Str;
 }
 
-enum class ConstraintKind {
-  Allowed,
-  Excluded,
-};
-
+// Validate and consume an AnyTypeOf constraint if present
+// at the current position.
 static bool
-checkAndConsumeConstraintBlock(Type *Ty, ConstraintKind Kind,
-                               ArrayRef<Intrinsic::IITDescriptor> &Infos,
-                               const Twine &Constraint, std::string &ErrMsg) {
+validateAndConsumeConstraint(Type *Ty,
+                             ArrayRef<Intrinsic::IITDescriptor> &Infos,
+                             const Twine &Constraint, std::string &ErrMsg) {
   using namespace Intrinsic;
 
-  unsigned Count = Kind == ConstraintKind::Allowed
-                       ? Infos.front().getArgumentNumConstraints()
-                       : Infos.front().getArgumentNumExclusions();
+  if (Infos.empty() || Infos[0].Kind != IITDescriptor::ArgumentTypeConstraint)
+    return true;
+
+  unsigned Count = Infos.front().getArgumentNumConstraints();
   Infos = Infos.slice(1);
 
   bool Matches = verifyTypeAgainstConstraints(Ty, Count, Infos);
-  bool Violates = Kind == ConstraintKind::Allowed ? !Matches : Matches;
-  if (!Violates)
+  if (Matches)
     return true;
 
   ErrMsg = (Constraint + " type '" + typeToString(Ty) + "'" +
-            (Kind == ConstraintKind::Allowed ? " not in allowed types"
-                                             : " is in excluded types"))
+            " not in allowed types")
                .str();
   return false;
 }
 
-// Verify the Struct return types.
-static bool
-verifyIntrinsicStructOutputTypes(Type *RetTy,
-                                 ArrayRef<Intrinsic::IITDescriptor> &Infos,
-                                 std::string &ErrMsg) {
-  using namespace Intrinsic;
-
-  auto *STy = dyn_cast<StructType>(RetTy);
-  if (!STy) {
-    skipDescriptorsForSingleType(Infos);
-    return false;
-  }
-
-  if (Infos.empty() || Infos[0].Kind != IITDescriptor::Struct) {
-    ErrMsg = "Return type struct encoding is malformed";
-    return false;
-  }
-
-  unsigned NumElements = Infos[0].Struct_NumElements;
-  Infos = Infos.slice(1);
-
-  for (unsigned ElemIdx = 0; ElemIdx < NumElements; ++ElemIdx) {
-    if (Infos.empty())
-      break;
-
-    if (Infos[0].Kind == IITDescriptor::Argument) {
-      Infos = Infos.slice(1);
-
-      Type *ElemTy = STy->getElementType(ElemIdx);
-
-      if (!Infos.empty() &&
-          Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
-        if (!checkAndConsumeConstraintBlock(
-                ElemTy, ConstraintKind::Allowed, Infos,
-                Twine("Return type struct element ") + Twine(ElemIdx), ErrMsg))
-          return false;
-      } else if (!Infos.empty() &&
-                 Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
-        if (!checkAndConsumeConstraintBlock(
-                ElemTy, ConstraintKind::Excluded, Infos,
-                Twine("Return type struct element ") + Twine(ElemIdx), ErrMsg))
-          return false;
-      }
-    } else
-      skipDescriptorsForSingleType(Infos);
-  }
-
-  return true;
-}
-
-// Verify the non struct return types.
-static bool
-verifyIntrinsicNonStructOutputTypes(Type *RetTy,
-                                    ArrayRef<Intrinsic::IITDescriptor> &Infos,
-                                    std::string &ErrMsg) {
-  using namespace Intrinsic;
-
-  if (Infos.empty())
-    return true;
-
-  if (Infos[0].Kind != IITDescriptor::Argument) {
-    skipDescriptorsForSingleType(Infos);
-    return true;
-  }
-
-  Infos = Infos.slice(1);
-
-  if (!Infos.empty() &&
-      Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
-    if (!checkAndConsumeConstraintBlock(RetTy, ConstraintKind::Allowed, Infos,
-                                        "Return type", ErrMsg))
-      return false;
-  } else if (!Infos.empty() &&
-             Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
-    if (!checkAndConsumeConstraintBlock(RetTy, ConstraintKind::Excluded, Infos,
-                                        "Return type", ErrMsg))
-      return false;
-  }
-
-  return true;
-}
-
-// Verify the return types.
-static bool
-verifyIntrinsicOutputTypes(Intrinsic::ID id, FunctionType *FTy,
-                           ArrayRef<Intrinsic::IITDescriptor> &Infos,
-                           std::string &ErrMsg) {
-
-  Type *RetTy = FTy->getReturnType();
-  if (RetTy->isStructTy())
-    return verifyIntrinsicStructOutputTypes(RetTy, Infos, ErrMsg);
-
-  return verifyIntrinsicNonStructOutputTypes(RetTy, Infos, ErrMsg);
-}
-
-// Verify the input parameters.
-static bool verifyIntrinsicInputTypes(Intrinsic::ID id, FunctionType *FTy,
-                                      ArrayRef<Intrinsic::IITDescriptor> &Infos,
-                                      std::string &ErrMsg) {
-  using namespace Intrinsic;
-
-  SmallVector<Type *, 4> ArgTys;
-
-  for (unsigned ParamIdx = 0; ParamIdx < FTy->getNumParams(); ++ParamIdx) {
-    if (Infos.empty())
-      break;
-
-    Type *ParamTy = FTy->getParamType(ParamIdx);
-
-    if (Infos[0].Kind == IITDescriptor::Argument) {
-      unsigned ArgNum = Infos[0].getArgumentNumber();
-      Infos = Infos.slice(1);
-
-      if (!Infos.empty() &&
-          Infos[0].Kind == IITDescriptor::ArgumentTypeConstraint) {
-        if (!checkAndConsumeConstraintBlock(
-                ParamTy, ConstraintKind::Allowed, Infos,
-                Twine("Parameter ") + Twine(ParamIdx), ErrMsg))
-          return false;
-        if (ArgNum == ArgTys.size())
-          ArgTys.push_back(ParamTy);
-      } else if (!Infos.empty() &&
-                 Infos[0].Kind == IITDescriptor::ArgumentTypeExclusion) {
-        if (!checkAndConsumeConstraintBlock(
-                ParamTy, ConstraintKind::Excluded, Infos,
-                Twine("Parameter ") + Twine(ParamIdx), ErrMsg))
-          return false;
-        if (ArgNum == ArgTys.size())
-          ArgTys.push_back(ParamTy);
-      }
-    } else
-      skipDescriptorsForSingleType(Infos);
-  }
-
-  return true;
-}
-
-bool Intrinsic::verifyIntrinsicTypeConstraints(ID id, FunctionType *FTy,
-                                               std::string &ErrMsg) {
-  if (id == 0 || id >= Intrinsic::num_intrinsics)
-    return true;
-
-  if (!isOverloaded(id))
-    return true;
-
-  SmallVector<IITDescriptor, 8> Table;
-  getIntrinsicInfoTableEntries(id, Table);
-  if (Table.empty())
-    return true;
-
-  ArrayRef<IITDescriptor> Infos = Table;
-
-  // if there are no constraint descriptors, skip verification.
-  bool HasConstraints = false;
-  for (const auto &D : Infos) {
-    if (D.Kind == IITDescriptor::ArgumentTypeConstraint ||
-        D.Kind == IITDescriptor::ArgumentTypeExclusion) {
-      HasConstraints = true;
-      break;
-    }
-  }
-  if (!HasConstraints)
-    return true;
-
-  if (!verifyIntrinsicOutputTypes(id, FTy, Infos, ErrMsg))
-    return false;
-
-  if (!verifyIntrinsicInputTypes(id, FTy, Infos, ErrMsg))
-    return false;
-
-  return true;
-}
-
 bool Intrinsic::matchIntrinsicVarArg(
     bool isVarArg, ArrayRef<Intrinsic::IITDescriptor> &Infos) {
   // If there are no descriptors left, then it can't be a vararg.
@@ -1506,7 +1287,8 @@ bool Intrinsic::matchIntrinsicVarArg(
 }
 
 bool Intrinsic::getIntrinsicSignature(Intrinsic::ID ID, FunctionType *FT,
-                                      SmallVectorImpl<Type *> &ArgTys) {
+                                      SmallVectorImpl<Type *> &ArgTys,
+                                      std::string *ErrMsg) {
   if (!ID)
     return false;
 
@@ -1514,7 +1296,7 @@ bool Intrinsic::getIntrinsicSignature(Intrinsic::ID ID, FunctionType *FT,
   getIntrinsicInfoTableEntries(ID, Table);
   ArrayRef<Intrinsic::IITDescriptor> TableRef = Table;
 
-  if (Intrinsic::matchIntrinsicSignature(FT, TableRef, ArgTys) !=
+  if (Intrinsic::matchIntrinsicSignature(FT, TableRef, ArgTys, ErrMsg) !=
       Intrinsic::MatchIntrinsicTypesResult::MatchIntrinsicTypes_Match) {
     return false;
   }
@@ -1524,9 +1306,10 @@ bool Intrinsic::getIntrinsicSignature(Intrinsic::ID ID, FunctionType *FT,
 }
 
 bool Intrinsic::getIntrinsicSignature(Function *F,
-                                      SmallVectorImpl<Type *> &ArgTys) {
+                                      SmallVectorImpl<Type *> &ArgTys,
+                                      std::string *ErrMsg) {
   return getIntrinsicSignature(F->getIntrinsicID(), F->getFunctionType(),
-                               ArgTys);
+                               ArgTys, ErrMsg);
 }
 
 std::optional<Function *> Intrinsic::remangleIntrinsicFunction(Function *F) {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index 301a57b680d7b..630f55942c34b 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -3293,10 +3293,14 @@ void Verifier::visitFunction(const Function &F) {
   // Verify AnyTypeOf type constraints for intrinsic declarations.
   if (F.isIntrinsic()) {
     std::string ConstraintErrMsg;
-    if (!Intrinsic::verifyIntrinsicTypeConstraints(
-            F.getIntrinsicID(), F.getFunctionType(), ConstraintErrMsg))
-      CheckFailed("Intrinsic declaration '" + F.getName().str() +
-                  "' violates type constraint: " + ConstraintErrMsg);
+    SmallVector<Type *, 4> ArgTys;
+    if (!Intrinsic::getIntrinsicSignature(F.getIntrinsicID(),
+                                          F.getFunctionType(), ArgTys,
+                                          &ConstraintErrMsg)) {
+      if (!ConstraintErrMsg.empty())
+        CheckFailed("Intrinsic declaration '" + F.getName().str() +
+                    "' violates type constraint: " + ConstraintErrMsg);
+    }
   }
 
   auto *N = F.getSubprogram();
diff --git a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
index faf97a1875dab..6029c7d3373b4 100644
--- a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
+++ b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_invalid.ll
@@ -1,39 +1,39 @@
 ; RUN: not llvm-as < %s -o /dev/null
-; Test cases for int_nvvm_test_type intrinsic - INVALID combinations
+; Test cases for int_nvvm_test_anytype intrinsic - INVALID combinations
 
 ; arg0 must be i16 or i32, not i8
-define i32 @invalid_arg0_i8(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i8.i8.i32.p0.i32.i16(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
+define i32 @invalid_arg0_i8(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i8.i8.i32.p0.i64.p1(i8 %a0, i8 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5)
   ret i32 %result
 }
 
 ; arg1 must match arg0 (i16), not i32
-define i32 @invalid_arg1_mismatch_i16_i32(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i16.i32.i32.p0.i32.i16(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
+define i32 @invalid_arg1_mismatch_i16_i32(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i16.i32.i32.p0.i64.p1(i16 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5)
   ret i32 %result
 }
 
 ; arg2 must be anyint or float, not double
-define i32 @invalid_arg2_double(i32 %a0, i32 %a1, double %a2, ptr %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.f64.p0.i32.i16(i32 %a0, i32 %a1, double %a2, ptr %a3, i32 %a4, i16 %a5)
+define i32 @invalid_arg2_double(i32 %a0, i32 %a1, double %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.f64.p0.i64.p1(i32 %a0, i32 %a1, double %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5)
   ret i32 %result
 }
 
 ; arg3 must be ptr or ptr addrspace(3), not ptr addrspace(1) (global)
-define i32 @invalid_arg3_ptr_as1_wrong(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p1.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i32 %a4, i16 %a5)
+define i32 @invalid_arg3_ptr_as1_wrong(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i64 %a4, <2 x i64> %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p1.i64.v2i64(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(1) %a3, i64 %a4, <2 x i64> %a5)
   ret i32 %result
 }
 
-; arg4 must not be i64 or double
-define i32 @test_arg4_double(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.f64.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, i16 %a5)
+; arg4 must be i64 or double, not i32
+define i32 @invalid_arg4_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, ptr addrspace(1) %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i32.p1(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, ptr addrspace(1) %a5)
   ret i32 %result
 }
 
-; arg5 must be i16, <4 x i32>, or <4 x f32>, not <2 x i32>
-define i32 @invalid_arg5_v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, <2 x i32> %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, <2 x i32> %a5)
+; arg5 must be ptr addrspace(1) or <2 x i64>, not <2 x i32>
+define i32 @invalid_arg5_v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <2 x i32> %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v2i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <2 x i32> %a5)
   ret i32 %result
 }
 
@@ -42,10 +42,10 @@ define {i32, i8, i64} @invalid_return_type_i8(i32 %arg) {
   ret {i32, i8, i64} %result
 }
 
-declare i32 @llvm.nvvm.test.type.i8.i8.i32.p0.i32.i16(i8, i8, i32, ptr, i32, i16)
-declare i32 @llvm.nvvm.test.type.i16.i32.i32.p0.i32.i16(i16, i32, i32, ptr, i32, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.f64.p0.i32.i16(i32, i32, double, ptr, i32, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.i32.p1.i32.i16(i32, i32, i32, ptr addrspace(1), i32, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.f64.i16(i32, i32, i32, ptr, double, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.v2i32(i32, i32, i32, ptr, i32, <2 x i32>)
+declare i32 @llvm.nvvm.test.anytype.i8.i8.i32.p0.i64.p1(i8, i8, i32, ptr, i64, ptr addrspace(1))
+declare i32 @llvm.nvvm.test.anytype.i16.i32.i32.p0.i64.p1(i16, i32, i32, ptr, i64, ptr addrspace(1))
+declare i32 @llvm.nvvm.test.anytype.i32.i32.f64.p0.i64.p1(i32, i32, double, ptr, i64, ptr addrspace(1))
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p1.i64.v2i64(i32, i32, i32, ptr addrspace(1), i64, <2 x i64>)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i32.p1(i32, i32, i32, ptr, i32, ptr addrspace(1))
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v2i32(i32, i32, i32, ptr, i64, <2 x i32>)
 declare {i32, i8, i64} @llvm.nvvm.test.return.type.i8(i32)
diff --git a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll
index 95fb9c9c30157..58d1642894ee1 100644
--- a/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll
+++ b/llvm/test/CodeGen/NVPTX/anytypeof_constraints_valid.ll
@@ -1,33 +1,33 @@
 ; RUN: llvm-as < %s -o /dev/null
-; Test cases for int_nvvm_test_type intrinsic - VALID combinations
+; Test cases for int_nvvm_test_anytype intrinsic - VALID combinations
 
-define i32 @test_arg0_i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i16.i16.i32.p0.i32.i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
+define i32 @test_arg0_i16(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i16.i16.i32.p0.i64.p1(i16 %a0, i16 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5)
   ret i32 %result
 }
 
-define i32 @test_arg0_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
+define i32 @test_arg0_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.p1(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5)
   ret i32 %result
 }
 
-define i32 @test_arg2_anyint(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, i16 %a5)
+define i32 @test_arg2_anyint(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.p1(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, ptr addrspace(1) %a5)
   ret i32 %result
 }
 
-define i32 @test_arg3_shared_ptr(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i32 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p3.i32.i16(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i32 %a4, i16 %a5)
+define i32 @test_arg3_shared_ptr(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i64 %a4, <2 x i64> %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p3.i64.v2i64(i32 %a0, i32 %a1, i32 %a2, ptr addrspace(3) %a3, i64 %a4, <2 x i64> %a5)
   ret i32 %result
 }
 
-define i32 @invalid_arg4_i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i16 %a4, i16 %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i16.i16(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i16 %a4, i16 %a5)
+define i32 @test_arg4_double(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, ptr addrspace(1) %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.f64.p1(i32 %a0, i32 %a1, i32 %a2, ptr %a3, double %a4, ptr addrspace(1) %a5)
   ret i32 %result
 }
 
-define i32 @test_arg5_v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, <4 x i32> %a5) {
-  %result = call i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i32 %a4, <4 x i32> %a5)
+define i32 @test_arg5_v4i32(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <2 x i64> %a5) {
+  %result = call i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v2i64(i32 %a0, i32 %a1, i32 %a2, ptr %a3, i64 %a4, <2 x i64> %a5)
   ret i32 %result
 }
 
@@ -36,10 +36,10 @@ define {i32, i32, i64} @test_return_type_valid(i32 %arg) {
   ret {i32, i32, i64} %result
 }
 
-declare i32 @llvm.nvvm.test.type.i16.i16.i32.p0.i32.i16(i16, i16, i32, ptr, i32, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.i16(i32, i32, i32, ptr, i32, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.f32.p0.i32.i16(i32, i32, float, ptr, i32, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.i32.p3.i32.i16(i32, i32, i32, ptr addrspace(3), i32, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i16.i16(i32, i32, i32, ptr, i16, i16)
-declare i32 @llvm.nvvm.test.type.i32.i32.i32.p0.i32.v4i32(i32, i32, i32, ptr, i32, <4 x i32>)
+declare i32 @llvm.nvvm.test.anytype.i16.i16.i32.p0.i64.p1(i16, i16, i32, ptr, i64, ptr addrspace(1))
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.p1(i32, i32, i32, ptr, i64, ptr addrspace(1))
+declare i32 @llvm.nvvm.test.anytype.i32.i32.f32.p0.i64.p1(i32, i32, i32, ptr, i64, ptr addrspace(1))
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p3.i64.v2i64(i32, i32, i32, ptr addrspace(3), i64, <2 x i64>)
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.f64.p1(i32, i32, i32, ptr, double, ptr addrspace(1))
+declare i32 @llvm.nvvm.test.anytype.i32.i32.i32.p0.i64.v2i64(i32, i32, i32, ptr, i64, <2 x i64>)
 declare {i32, i32, i64} @llvm.nvvm.test.return.type.i32(i32)
diff --git a/llvm/test/TableGen/overloaded-intrinsic-constraints.td b/llvm/test/TableGen/overloaded-intrinsic-constraints.td
index b6f04ded18bb5..f50c2d3958542 100644
--- a/llvm/test/TableGen/overloaded-intrinsic-constraints.td
+++ b/llvm/test/TableGen/overloaded-intrinsic-constraints.td
@@ -13,31 +13,10 @@ def int_anytypeof_multi : Intrinsic<
   [IntrNoMem]
 >;
 
-// Test mixed AnyTypeOf + NoneTypeOf.
-def int_mixed_constraints : Intrinsic<
-  [llvm_i32_ty],
-  [
-    AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>,
-    NoneTypeOf<[llvm_i8_ty]>
-  ],
-  [IntrNoMem]
->;
-
-// Test NoneTypeOf on return type.
-def int_nonetypeof_return : Intrinsic<
-  [NoneTypeOf<[llvm_i8_ty, llvm_double_ty]>],
-  [llvm_i32_ty],
-  [IntrNoMem]
->;
-
 // Verify enum generation.
 // CHECK-ENUM: anytypeof_multi = {{[0-9]+}}, // llvm.anytypeof.multi
-// CHECK-ENUM: mixed_constraints{{.*}}// llvm.mixed.constraints
-// CHECK-ENUM: nonetypeof_return{{.*}}// llvm.nonetypeof.return
 
 // Verify encoding table generation.
 // CHECK-IMPL: static constexpr unsigned char IIT_LongEncodingTable[] = {
-// CHECK-IMPL-NEXT: /* 0 */ 4, 15, 0, 93, 2, 3, 4, 15, 8, 94, 1, 2, 0,
-// CHECK-IMPL-NEXT: /* 13 */ 15, 0, 94, 2, 2, 8, 4, 0,
-// CHECK-IMPL-NEXT: /* 21 */ 4, 15, 0, 93, 2, 3, 4, 15, 8, 93, 3, 15, 9, 7, 8, 0,
+// CHECK-IMPL-NEXT: /* 0 */ 4, 15, 0, 93, 2, 3, 4, 15, 8, 93, 3, 15, 9, 7, 8, 0,
 // CHECK-IMPL-NEXT: 255

>From 3c769291519b6187844cc7cfae0bc012898f570c Mon Sep 17 00:00:00 2001
From: Dharuni R Acharya <dharuniracharya at gmail.com>
Date: Sun, 8 Feb 2026 06:27:51 +0000
Subject: [PATCH 5/5] Address comments

---
 llvm/include/llvm/IR/Intrinsics.td                     | 4 ++--
 llvm/include/llvm/IR/IntrinsicsNVVM.td                 | 4 ++--
 llvm/test/TableGen/overloaded-intrinsic-constraints.td | 2 +-
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index 028b65c267ab7..88fb78e23f6c6 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -373,7 +373,7 @@ def IIT_V10 : IIT_Vec<10, 51>;
 def IIT_V2048 : IIT_Vec<2048, 52>;
 def IIT_V4096 : IIT_Vec<4096, 53>;
 // Constrained type encoding for overloaded intrinsics.
-def IIT_ANYTYPE : IIT_Base<93>;
+def IIT_ANYTYPE : IIT_Base<54>;
 }
 
 defvar IIT_all_FixedTypes = !filter(iit, IIT_all,
@@ -455,7 +455,7 @@ class LLVMAnyPointerType : LLVMAnyType<pAny> {
 class AnyTypeOf<list<LLVMType> allowed_types> : LLVMAnyType<Any> {
   list<LLVMType> AllowedTypes = allowed_types;
   
-  // Validation: specifying maximal 255 number of allowed types.
+  // Limit to 255 allowed types since it is encoded as a single byte.
   assert !le(!size(allowed_types), 255),
          "AnyTypeOf cannot exceed 255 allowed types";
   
diff --git a/llvm/include/llvm/IR/IntrinsicsNVVM.td b/llvm/include/llvm/IR/IntrinsicsNVVM.td
index a3ae44ba29177..edb40c68d9bdf 100644
--- a/llvm/include/llvm/IR/IntrinsicsNVVM.td
+++ b/llvm/include/llvm/IR/IntrinsicsNVVM.td
@@ -3387,12 +3387,12 @@ def int_nvvm_tensormap_replace_fill_mode :
                            ImmArgPrinter<"printTensormapFillMode">]>]>;
 
 // Test intrinsic - TODO: Add the feature to existing intrinsics and remove these test intrinsics.
-// IIT_LongEncodingTable entry:  /* 16662 */ 4, 15, 0, 93, 2, 3, 4, 15, 7, 15, 8, 93, 2, 15, 9, 7, 15, 16, 93, 2, 14, 24, 3, 15, 24, 93, 2, 5, 8, 15, 32, 93, 2, 24, 1, 9, 5, 0,
+// IIT_LongEncodingTable entry:  /* 16662 */ 4, 15, 0, 54, 2, 3, 4, 15, 7, 15, 8, 54, 2, 15, 9, 7, 15, 16, 54, 2, 14, 24, 3, 15, 24, 54, 2, 5, 8, 15, 32, 54, 2, 24, 1, 9, 5, 0,
 def int_nvvm_test_anytype : Intrinsic<[llvm_i32_ty],
    [AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, LLVMMatchType<0>, AnyTypeOf<[llvm_anyint_ty, llvm_float_ty]>, AnyTypeOf<[llvm_ptr_ty, llvm_shared_ptr_ty]>, AnyTypeOf<[llvm_i64_ty, llvm_double_ty]>, AnyTypeOf<[llvm_global_ptr_ty, llvm_v2i64_ty]>],
    [IntrNoMem]>;
 
-// IIT_LongEncodingTable entry:  /* 15435 */ 21, 1, 4, 15, 0, 93, 2, 3, 4, 5, 4, 0,
+// IIT_LongEncodingTable entry:  /* 15435 */ 21, 1, 4, 15, 0, 54, 2, 3, 4, 5, 4, 0,
 def int_nvvm_test_return_type : Intrinsic<[llvm_i32_ty, AnyTypeOf<[llvm_i16_ty, llvm_i32_ty]>, llvm_i64_ty],
 [llvm_i32_ty],
 [IntrNoMem]>;
diff --git a/llvm/test/TableGen/overloaded-intrinsic-constraints.td b/llvm/test/TableGen/overloaded-intrinsic-constraints.td
index f50c2d3958542..78776b29769cc 100644
--- a/llvm/test/TableGen/overloaded-intrinsic-constraints.td
+++ b/llvm/test/TableGen/overloaded-intrinsic-constraints.td
@@ -18,5 +18,5 @@ def int_anytypeof_multi : Intrinsic<
 
 // Verify encoding table generation.
 // CHECK-IMPL: static constexpr unsigned char IIT_LongEncodingTable[] = {
-// CHECK-IMPL-NEXT: /* 0 */ 4, 15, 0, 93, 2, 3, 4, 15, 8, 93, 3, 15, 9, 7, 8, 0,
+// CHECK-IMPL-NEXT: /* 0 */ 4, 15, 0, 54, 2, 3, 4, 15, 8, 54, 3, 15, 9, 7, 8, 0,
 // CHECK-IMPL-NEXT: 255



More information about the llvm-commits mailing list