[llvm] [LLVM][AutoUpgrade] Support default args on overloaded intrinsics (PR #217859)

Dharuni R Acharya via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 9 04:05:55 PDT 2026


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

>From 7acb3eef17aa7eb6682165d4bd1aab8c9c308148 Mon Sep 17 00:00:00 2001
From: DharuniRAcharya <dharunira at nvidia.com>
Date: Fri, 14 Aug 2026 04:58:08 +0000
Subject: [PATCH 1/5] [LLVM][Auto-Upgrade] Support default args on overloaded
 intrinsics and undeclared multi-call upgrades

This patch extends intrinsic DefaultValue auto-upgrade to overloaded intrinsics and to calls that omit an explicit declare.

Multiple undeclared calls can leave uniquified temps; this patch recovers the intrinsic via prefix matching in upgradeIntrinsicWithDefaultArgs,
then validate the partial signature before filling default ImmArgs.

Signed-off-by: DharuniRAcharya <dharunira at nvidia.com>
---
 llvm/include/llvm/IR/Intrinsics.h            |  8 ++++
 llvm/lib/IR/Intrinsics.cpp                   | 39 +++++++++++++++++---
 llvm/test/TableGen/intrinsic-default-args.td | 25 +++++++++++--
 3 files changed, 63 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 86b6f9caa9078..7cf28682c83e1 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -309,6 +309,14 @@ LLVM_ABI bool isSignatureValid(Function *F,
                                SmallVectorImpl<Type *> &OverloadTys,
                                raw_ostream &OS = nulls());
 
+/// Same as previous, but \p FT may omit exactly \p NumMissingTrailingParams
+/// trailing parameters. The omitted parameters must have concrete integer type
+/// so that all overload types can be resolved from the provided signature.
+LLVM_ABI bool isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
+                               SmallVectorImpl<Type *> &OverloadTys,
+                               unsigned NumMissingTrailingParams,
+                               raw_ostream &OS = nulls());
+
 // Checks if the intrinsic name matches with its signature and if not
 // returns the declaration with the same signature and remangled name.
 // An existing GlobalValue with the wanted name but with a wrong prototype
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 82b5bff1b9dec..2362ad450a468 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -43,7 +43,8 @@ static bool isSignatureValid(FunctionType *FTy,
                              ArrayRef<Intrinsic::IITDescriptor> &Infos,
                              unsigned NumArgs, bool IsVarArg,
                              SmallVectorImpl<Type *> &OverloadTys,
-                             raw_ostream &OS);
+                             raw_ostream &OS,
+                             unsigned NumMissingTrailingParams = 0);
 
 /// Table of string intrinsic names indexed by enum value.
 #define GET_INTRINSIC_NAME_TABLE
@@ -1338,13 +1339,18 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
 /// \p IsVarArg. The overloaded types for the intrinsic are pushed to the
 /// \p OverloadTys vector.
 ///
+/// If \p NumMissingTrailingParams is non-zero, \p FTy may omit exactly that
+/// many trailing parameters. Omitted parameters must have concrete integer
+/// types and therefore cannot contribute an unresolved overload type.
+///
 /// If the type is not valid, returns false and prints an error message to
 /// \p OS.
 static bool isSignatureValid(FunctionType *FTy,
                              ArrayRef<Intrinsic::IITDescriptor> &Infos,
                              unsigned NumArgs, bool IsVarArg,
                              SmallVectorImpl<Type *> &OverloadTys,
-                             raw_ostream &OS) {
+                             raw_ostream &OS,
+                             unsigned NumMissingTrailingParams) {
   SmallVector<DeferredIntrinsicMatchInfo, 2> DeferredChecks;
 
   assert(!Infos.empty() && "Table consistency error");
@@ -1357,9 +1363,10 @@ static bool isSignatureValid(FunctionType *FTy,
                          DeferredChecks, false, OS))
     return false;
 
-  if (FTy->getNumParams() != NumArgs) {
+  unsigned ProvidedArgs = FTy->getNumParams();
+  if (ProvidedArgs + NumMissingTrailingParams != NumArgs) {
     OS << "intrinsic has incorrect number of args. Expected " << NumArgs
-       << ", but got " << FTy->getNumParams();
+       << ", but got " << ProvidedArgs;
     return false;
   }
 
@@ -1378,6 +1385,19 @@ static bool isSignatureValid(FunctionType *FTy,
       return false;
   }
 
+  if (NumMissingTrailingParams) {
+    // Default arguments are materialized as ConstantInt values, requiring one
+    // concrete integer descriptor per omitted parameter.
+    if (Infos.size() != NumMissingTrailingParams ||
+        llvm::any_of(Infos, [](Intrinsic::IITDescriptor D) {
+          return D.Kind != Intrinsic::IITDescriptor::Integer;
+        })) {
+      OS << "intrinsic has unresolved trailing argument types!";
+      return false;
+    }
+    Infos = {};
+  }
+
   if (!Infos.empty()) {
     OS << "intrinsic has too few arguments!";
     return false;
@@ -1404,13 +1424,22 @@ bool Intrinsic::hasStructReturnType(ID id) {
 bool Intrinsic::isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
                                  SmallVectorImpl<Type *> &OverloadTys,
                                  raw_ostream &OS) {
+  return isSignatureValid(ID, FT, OverloadTys,
+                          /*NumMissingTrailingParams=*/0, OS);
+}
+
+bool Intrinsic::isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
+                                 SmallVectorImpl<Type *> &OverloadTys,
+                                 unsigned NumMissingTrailingParams,
+                                 raw_ostream &OS) {
   if (!ID)
     return false;
 
   SmallVector<Intrinsic::IITDescriptor, 8> Table;
   auto [TableRef, NumArgs, IsVarArg] = getIntrinsicInfoTableEntries(ID, Table);
 
-  return ::isSignatureValid(FT, TableRef, NumArgs, IsVarArg, OverloadTys, OS);
+  return ::isSignatureValid(FT, TableRef, NumArgs, IsVarArg, OverloadTys, OS,
+                            NumMissingTrailingParams);
 }
 
 bool Intrinsic::isSignatureValid(Function *F,
diff --git a/llvm/test/TableGen/intrinsic-default-args.td b/llvm/test/TableGen/intrinsic-default-args.td
index e372a870880e7..1afffc964360b 100644
--- a/llvm/test/TableGen/intrinsic-default-args.td
+++ b/llvm/test/TableGen/intrinsic-default-args.td
@@ -6,7 +6,7 @@
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_NEGATIVE 2>&1 | FileCheck %s --check-prefix=ERR-NEGATIVE
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_RANGE 2>&1 | FileCheck %s --check-prefix=ERR-RANGE
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_NONINT 2>&1 | FileCheck %s --check-prefix=ERR-NONINT
-// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_OVERLOADED 2>&1 | FileCheck %s --check-prefix=ERR-OVERLOADED
+// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DTEST_OVERLOADED | FileCheck %s --check-prefix=OVERLOADED
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_GAP 2>&1 | FileCheck %s --check-prefix=ERR-GAP
 
 include "llvm/IR/Intrinsics.td"
@@ -77,12 +77,29 @@ def int_test_nonint :
               [ImmArg<ArgIndex<1>, DefaultValue<1>>]>;
 #endif
 
-// A default on an overloaded intrinsic is rejected (not yet supported).
-#ifdef ERROR_OVERLOADED
-// ERR-OVERLOADED: error: default argument values are not supported for overloaded intrinsics
+#ifdef TEST_OVERLOADED
 def int_test_overloaded :
     Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty],
               [ImmArg<ArgIndex<1>, DefaultValue<5>>]>;
+
+def int_test_overloaded_two_defaults :
+    Intrinsic<[llvm_anyint_ty],
+              [LLVMMatchType<0>, llvm_i1_ty, llvm_i32_ty],
+              [ImmArg<ArgIndex<1>, DefaultValue<0>>,
+               ImmArg<ArgIndex<2>, DefaultValue<7>>]>;
+
+def int_test_overloaded_ptr :
+    Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i32_ty],
+              [ImmArg<ArgIndex<1>, DefaultValue<1>>]>;
+
+// Header (1 << 32) | 1 = 4294967297 for single trailing defaults.
+// Header (2 << 32) | 1 = 8589934593 for two trailing defaults.
+// OVERLOADED:      static constexpr uint64_t DefaultArgValuesTable[] = {
+// OVERLOADED-NEXT:   0, // offset 0: sentinel for intrinsics without defaults
+// OVERLOADED-DAG: {{.*}}4294967297,{{.*}}5,{{.*}}0,
+// OVERLOADED-DAG: {{.*}}8589934593,{{.*}}0,{{.*}}7,{{.*}}0,
+// OVERLOADED-DAG: {{.*}}4294967297,{{.*}}1,{{.*}}0,
+// OVERLOADED: Intrinsic::getAllDefaultArgValues(ID IID) {
 #endif
 
 // Defaults must form a contiguous trailing block.

>From d5f04458ab5df8fe6b4ee5d74aaf03b9d8e4f93b Mon Sep 17 00:00:00 2001
From: DharuniRAcharya <dharunira at nvidia.com>
Date: Thu, 20 Aug 2026 10:48:27 +0000
Subject: [PATCH 2/5] Address comments

---
 llvm/include/llvm/IR/Intrinsics.h            |  8 ----
 llvm/lib/IR/AutoUpgrade.cpp                  |  2 -
 llvm/lib/IR/Intrinsics.cpp                   | 39 +++-----------------
 llvm/test/TableGen/intrinsic-default-args.td | 25 ++-----------
 4 files changed, 9 insertions(+), 65 deletions(-)

diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 7cf28682c83e1..86b6f9caa9078 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -309,14 +309,6 @@ LLVM_ABI bool isSignatureValid(Function *F,
                                SmallVectorImpl<Type *> &OverloadTys,
                                raw_ostream &OS = nulls());
 
-/// Same as previous, but \p FT may omit exactly \p NumMissingTrailingParams
-/// trailing parameters. The omitted parameters must have concrete integer type
-/// so that all overload types can be resolved from the provided signature.
-LLVM_ABI bool isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
-                               SmallVectorImpl<Type *> &OverloadTys,
-                               unsigned NumMissingTrailingParams,
-                               raw_ostream &OS = nulls());
-
 // Checks if the intrinsic name matches with its signature and if not
 // returns the declaration with the same signature and remangled name.
 // An existing GlobalValue with the wanted name but with a wrong prototype
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 530ee5b7b6047..a16b52d3af1d9 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -5634,13 +5634,11 @@ static bool upgradeIntrinsicCallWithDefaultArgs(CallBase *CI, Function *NewFn,
            "missing argument outside the default range");
     Type *ParamTy = NewFT->getParamType(Idx);
 
-    // Only integer types are supported (i1, i8, i16, i32, i64).
     if (!ParamTy->isIntegerTy())
       return false;
     NewArgs.push_back(ConstantInt::get(ParamTy, Defaults[Idx - FirstDefault]));
   }
 
-  // Preserve operand bundles by creating the call with them.
   SmallVector<OperandBundleDef, 1> OpBundles;
   CI->getOperandBundlesAsDefs(OpBundles);
   CallInst *NewCall = Builder.CreateCall(NewFn, NewArgs, OpBundles);
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 2362ad450a468..82b5bff1b9dec 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -43,8 +43,7 @@ static bool isSignatureValid(FunctionType *FTy,
                              ArrayRef<Intrinsic::IITDescriptor> &Infos,
                              unsigned NumArgs, bool IsVarArg,
                              SmallVectorImpl<Type *> &OverloadTys,
-                             raw_ostream &OS,
-                             unsigned NumMissingTrailingParams = 0);
+                             raw_ostream &OS);
 
 /// Table of string intrinsic names indexed by enum value.
 #define GET_INTRINSIC_NAME_TABLE
@@ -1339,18 +1338,13 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
 /// \p IsVarArg. The overloaded types for the intrinsic are pushed to the
 /// \p OverloadTys vector.
 ///
-/// If \p NumMissingTrailingParams is non-zero, \p FTy may omit exactly that
-/// many trailing parameters. Omitted parameters must have concrete integer
-/// types and therefore cannot contribute an unresolved overload type.
-///
 /// If the type is not valid, returns false and prints an error message to
 /// \p OS.
 static bool isSignatureValid(FunctionType *FTy,
                              ArrayRef<Intrinsic::IITDescriptor> &Infos,
                              unsigned NumArgs, bool IsVarArg,
                              SmallVectorImpl<Type *> &OverloadTys,
-                             raw_ostream &OS,
-                             unsigned NumMissingTrailingParams) {
+                             raw_ostream &OS) {
   SmallVector<DeferredIntrinsicMatchInfo, 2> DeferredChecks;
 
   assert(!Infos.empty() && "Table consistency error");
@@ -1363,10 +1357,9 @@ static bool isSignatureValid(FunctionType *FTy,
                          DeferredChecks, false, OS))
     return false;
 
-  unsigned ProvidedArgs = FTy->getNumParams();
-  if (ProvidedArgs + NumMissingTrailingParams != NumArgs) {
+  if (FTy->getNumParams() != NumArgs) {
     OS << "intrinsic has incorrect number of args. Expected " << NumArgs
-       << ", but got " << ProvidedArgs;
+       << ", but got " << FTy->getNumParams();
     return false;
   }
 
@@ -1385,19 +1378,6 @@ static bool isSignatureValid(FunctionType *FTy,
       return false;
   }
 
-  if (NumMissingTrailingParams) {
-    // Default arguments are materialized as ConstantInt values, requiring one
-    // concrete integer descriptor per omitted parameter.
-    if (Infos.size() != NumMissingTrailingParams ||
-        llvm::any_of(Infos, [](Intrinsic::IITDescriptor D) {
-          return D.Kind != Intrinsic::IITDescriptor::Integer;
-        })) {
-      OS << "intrinsic has unresolved trailing argument types!";
-      return false;
-    }
-    Infos = {};
-  }
-
   if (!Infos.empty()) {
     OS << "intrinsic has too few arguments!";
     return false;
@@ -1424,22 +1404,13 @@ bool Intrinsic::hasStructReturnType(ID id) {
 bool Intrinsic::isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
                                  SmallVectorImpl<Type *> &OverloadTys,
                                  raw_ostream &OS) {
-  return isSignatureValid(ID, FT, OverloadTys,
-                          /*NumMissingTrailingParams=*/0, OS);
-}
-
-bool Intrinsic::isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
-                                 SmallVectorImpl<Type *> &OverloadTys,
-                                 unsigned NumMissingTrailingParams,
-                                 raw_ostream &OS) {
   if (!ID)
     return false;
 
   SmallVector<Intrinsic::IITDescriptor, 8> Table;
   auto [TableRef, NumArgs, IsVarArg] = getIntrinsicInfoTableEntries(ID, Table);
 
-  return ::isSignatureValid(FT, TableRef, NumArgs, IsVarArg, OverloadTys, OS,
-                            NumMissingTrailingParams);
+  return ::isSignatureValid(FT, TableRef, NumArgs, IsVarArg, OverloadTys, OS);
 }
 
 bool Intrinsic::isSignatureValid(Function *F,
diff --git a/llvm/test/TableGen/intrinsic-default-args.td b/llvm/test/TableGen/intrinsic-default-args.td
index 1afffc964360b..e372a870880e7 100644
--- a/llvm/test/TableGen/intrinsic-default-args.td
+++ b/llvm/test/TableGen/intrinsic-default-args.td
@@ -6,7 +6,7 @@
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_NEGATIVE 2>&1 | FileCheck %s --check-prefix=ERR-NEGATIVE
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_RANGE 2>&1 | FileCheck %s --check-prefix=ERR-RANGE
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_NONINT 2>&1 | FileCheck %s --check-prefix=ERR-NONINT
-// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DTEST_OVERLOADED | FileCheck %s --check-prefix=OVERLOADED
+// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_OVERLOADED 2>&1 | FileCheck %s --check-prefix=ERR-OVERLOADED
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_GAP 2>&1 | FileCheck %s --check-prefix=ERR-GAP
 
 include "llvm/IR/Intrinsics.td"
@@ -77,29 +77,12 @@ def int_test_nonint :
               [ImmArg<ArgIndex<1>, DefaultValue<1>>]>;
 #endif
 
-#ifdef TEST_OVERLOADED
+// A default on an overloaded intrinsic is rejected (not yet supported).
+#ifdef ERROR_OVERLOADED
+// ERR-OVERLOADED: error: default argument values are not supported for overloaded intrinsics
 def int_test_overloaded :
     Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty],
               [ImmArg<ArgIndex<1>, DefaultValue<5>>]>;
-
-def int_test_overloaded_two_defaults :
-    Intrinsic<[llvm_anyint_ty],
-              [LLVMMatchType<0>, llvm_i1_ty, llvm_i32_ty],
-              [ImmArg<ArgIndex<1>, DefaultValue<0>>,
-               ImmArg<ArgIndex<2>, DefaultValue<7>>]>;
-
-def int_test_overloaded_ptr :
-    Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i32_ty],
-              [ImmArg<ArgIndex<1>, DefaultValue<1>>]>;
-
-// Header (1 << 32) | 1 = 4294967297 for single trailing defaults.
-// Header (2 << 32) | 1 = 8589934593 for two trailing defaults.
-// OVERLOADED:      static constexpr uint64_t DefaultArgValuesTable[] = {
-// OVERLOADED-NEXT:   0, // offset 0: sentinel for intrinsics without defaults
-// OVERLOADED-DAG: {{.*}}4294967297,{{.*}}5,{{.*}}0,
-// OVERLOADED-DAG: {{.*}}8589934593,{{.*}}0,{{.*}}7,{{.*}}0,
-// OVERLOADED-DAG: {{.*}}4294967297,{{.*}}1,{{.*}}0,
-// OVERLOADED: Intrinsic::getAllDefaultArgValues(ID IID) {
 #endif
 
 // Defaults must form a contiguous trailing block.

>From a5a740c8048e1e995fcea00cd2404ef35b5631bf Mon Sep 17 00:00:00 2001
From: DharuniRAcharya <dharunira at nvidia.com>
Date: Fri, 21 Aug 2026 05:58:18 +0000
Subject: [PATCH 3/5] Address comments

---
 llvm/lib/IR/AutoUpgrade.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index a16b52d3af1d9..530ee5b7b6047 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -5634,11 +5634,13 @@ static bool upgradeIntrinsicCallWithDefaultArgs(CallBase *CI, Function *NewFn,
            "missing argument outside the default range");
     Type *ParamTy = NewFT->getParamType(Idx);
 
+    // Only integer types are supported (i1, i8, i16, i32, i64).
     if (!ParamTy->isIntegerTy())
       return false;
     NewArgs.push_back(ConstantInt::get(ParamTy, Defaults[Idx - FirstDefault]));
   }
 
+  // Preserve operand bundles by creating the call with them.
   SmallVector<OperandBundleDef, 1> OpBundles;
   CI->getOperandBundlesAsDefs(OpBundles);
   CallInst *NewCall = Builder.CreateCall(NewFn, NewArgs, OpBundles);

>From d5f6f3a2ea944c22043d59a53c55f7f109ab50c5 Mon Sep 17 00:00:00 2001
From: DharuniRAcharya <dharunira at nvidia.com>
Date: Fri, 21 Aug 2026 09:17:53 +0000
Subject: [PATCH 4/5] [LLVM][Auto-Upgrade] Support default args on overloaded
 intrinsics

This patch extends intrinsic DefaultValue auto-upgrade to overloaded intrinsics.

Signed-off-by: DharuniRAcharya <dharunira at nvidia.com>
---
 llvm/include/llvm/IR/Intrinsics.h            |  8 ++++
 llvm/lib/IR/AutoUpgrade.cpp                  |  2 +-
 llvm/lib/IR/Intrinsics.cpp                   | 39 +++++++++++++++++---
 llvm/test/TableGen/intrinsic-default-args.td | 25 +++++++++++--
 4 files changed, 64 insertions(+), 10 deletions(-)

diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 86b6f9caa9078..7cf28682c83e1 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -309,6 +309,14 @@ LLVM_ABI bool isSignatureValid(Function *F,
                                SmallVectorImpl<Type *> &OverloadTys,
                                raw_ostream &OS = nulls());
 
+/// Same as previous, but \p FT may omit exactly \p NumMissingTrailingParams
+/// trailing parameters. The omitted parameters must have concrete integer type
+/// so that all overload types can be resolved from the provided signature.
+LLVM_ABI bool isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
+                               SmallVectorImpl<Type *> &OverloadTys,
+                               unsigned NumMissingTrailingParams,
+                               raw_ostream &OS = nulls());
+
 // Checks if the intrinsic name matches with its signature and if not
 // returns the declaration with the same signature and remangled name.
 // An existing GlobalValue with the wanted name but with a wrong prototype
diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 530ee5b7b6047..133dbb16d536e 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -1634,7 +1634,7 @@ static bool upgradeIntrinsicWithDefaultArgs(Function *F, Function *&NewFn) {
     return false;
 
   rename(F);
-  NewFn = Intrinsic::getOrInsertDeclaration(F->getParent(), IID);
+  NewFn = Intrinsic::getOrInsertDeclaration(F->getParent(), IID, OverloadTys);
   assert(NewFn->arg_size() == FullArgCount &&
          "total number of default args does not match intrinsic signature");
   return true;
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 82b5bff1b9dec..2362ad450a468 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -43,7 +43,8 @@ static bool isSignatureValid(FunctionType *FTy,
                              ArrayRef<Intrinsic::IITDescriptor> &Infos,
                              unsigned NumArgs, bool IsVarArg,
                              SmallVectorImpl<Type *> &OverloadTys,
-                             raw_ostream &OS);
+                             raw_ostream &OS,
+                             unsigned NumMissingTrailingParams = 0);
 
 /// Table of string intrinsic names indexed by enum value.
 #define GET_INTRINSIC_NAME_TABLE
@@ -1338,13 +1339,18 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
 /// \p IsVarArg. The overloaded types for the intrinsic are pushed to the
 /// \p OverloadTys vector.
 ///
+/// If \p NumMissingTrailingParams is non-zero, \p FTy may omit exactly that
+/// many trailing parameters. Omitted parameters must have concrete integer
+/// types and therefore cannot contribute an unresolved overload type.
+///
 /// If the type is not valid, returns false and prints an error message to
 /// \p OS.
 static bool isSignatureValid(FunctionType *FTy,
                              ArrayRef<Intrinsic::IITDescriptor> &Infos,
                              unsigned NumArgs, bool IsVarArg,
                              SmallVectorImpl<Type *> &OverloadTys,
-                             raw_ostream &OS) {
+                             raw_ostream &OS,
+                             unsigned NumMissingTrailingParams) {
   SmallVector<DeferredIntrinsicMatchInfo, 2> DeferredChecks;
 
   assert(!Infos.empty() && "Table consistency error");
@@ -1357,9 +1363,10 @@ static bool isSignatureValid(FunctionType *FTy,
                          DeferredChecks, false, OS))
     return false;
 
-  if (FTy->getNumParams() != NumArgs) {
+  unsigned ProvidedArgs = FTy->getNumParams();
+  if (ProvidedArgs + NumMissingTrailingParams != NumArgs) {
     OS << "intrinsic has incorrect number of args. Expected " << NumArgs
-       << ", but got " << FTy->getNumParams();
+       << ", but got " << ProvidedArgs;
     return false;
   }
 
@@ -1378,6 +1385,19 @@ static bool isSignatureValid(FunctionType *FTy,
       return false;
   }
 
+  if (NumMissingTrailingParams) {
+    // Default arguments are materialized as ConstantInt values, requiring one
+    // concrete integer descriptor per omitted parameter.
+    if (Infos.size() != NumMissingTrailingParams ||
+        llvm::any_of(Infos, [](Intrinsic::IITDescriptor D) {
+          return D.Kind != Intrinsic::IITDescriptor::Integer;
+        })) {
+      OS << "intrinsic has unresolved trailing argument types!";
+      return false;
+    }
+    Infos = {};
+  }
+
   if (!Infos.empty()) {
     OS << "intrinsic has too few arguments!";
     return false;
@@ -1404,13 +1424,22 @@ bool Intrinsic::hasStructReturnType(ID id) {
 bool Intrinsic::isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
                                  SmallVectorImpl<Type *> &OverloadTys,
                                  raw_ostream &OS) {
+  return isSignatureValid(ID, FT, OverloadTys,
+                          /*NumMissingTrailingParams=*/0, OS);
+}
+
+bool Intrinsic::isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
+                                 SmallVectorImpl<Type *> &OverloadTys,
+                                 unsigned NumMissingTrailingParams,
+                                 raw_ostream &OS) {
   if (!ID)
     return false;
 
   SmallVector<Intrinsic::IITDescriptor, 8> Table;
   auto [TableRef, NumArgs, IsVarArg] = getIntrinsicInfoTableEntries(ID, Table);
 
-  return ::isSignatureValid(FT, TableRef, NumArgs, IsVarArg, OverloadTys, OS);
+  return ::isSignatureValid(FT, TableRef, NumArgs, IsVarArg, OverloadTys, OS,
+                            NumMissingTrailingParams);
 }
 
 bool Intrinsic::isSignatureValid(Function *F,
diff --git a/llvm/test/TableGen/intrinsic-default-args.td b/llvm/test/TableGen/intrinsic-default-args.td
index e372a870880e7..1afffc964360b 100644
--- a/llvm/test/TableGen/intrinsic-default-args.td
+++ b/llvm/test/TableGen/intrinsic-default-args.td
@@ -6,7 +6,7 @@
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_NEGATIVE 2>&1 | FileCheck %s --check-prefix=ERR-NEGATIVE
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_RANGE 2>&1 | FileCheck %s --check-prefix=ERR-RANGE
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_NONINT 2>&1 | FileCheck %s --check-prefix=ERR-NONINT
-// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_OVERLOADED 2>&1 | FileCheck %s --check-prefix=ERR-OVERLOADED
+// RUN: llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DTEST_OVERLOADED | FileCheck %s --check-prefix=OVERLOADED
 // RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST_INTRINSICS_SUPPRESS_DEFS -DERROR_GAP 2>&1 | FileCheck %s --check-prefix=ERR-GAP
 
 include "llvm/IR/Intrinsics.td"
@@ -77,12 +77,29 @@ def int_test_nonint :
               [ImmArg<ArgIndex<1>, DefaultValue<1>>]>;
 #endif
 
-// A default on an overloaded intrinsic is rejected (not yet supported).
-#ifdef ERROR_OVERLOADED
-// ERR-OVERLOADED: error: default argument values are not supported for overloaded intrinsics
+#ifdef TEST_OVERLOADED
 def int_test_overloaded :
     Intrinsic<[llvm_anyint_ty], [llvm_anyint_ty, llvm_i32_ty],
               [ImmArg<ArgIndex<1>, DefaultValue<5>>]>;
+
+def int_test_overloaded_two_defaults :
+    Intrinsic<[llvm_anyint_ty],
+              [LLVMMatchType<0>, llvm_i1_ty, llvm_i32_ty],
+              [ImmArg<ArgIndex<1>, DefaultValue<0>>,
+               ImmArg<ArgIndex<2>, DefaultValue<7>>]>;
+
+def int_test_overloaded_ptr :
+    Intrinsic<[llvm_anyptr_ty], [LLVMMatchType<0>, llvm_i32_ty],
+              [ImmArg<ArgIndex<1>, DefaultValue<1>>]>;
+
+// Header (1 << 32) | 1 = 4294967297 for single trailing defaults.
+// Header (2 << 32) | 1 = 8589934593 for two trailing defaults.
+// OVERLOADED:      static constexpr uint64_t DefaultArgValuesTable[] = {
+// OVERLOADED-NEXT:   0, // offset 0: sentinel for intrinsics without defaults
+// OVERLOADED-DAG: {{.*}}4294967297,{{.*}}5,{{.*}}0,
+// OVERLOADED-DAG: {{.*}}8589934593,{{.*}}0,{{.*}}7,{{.*}}0,
+// OVERLOADED-DAG: {{.*}}4294967297,{{.*}}1,{{.*}}0,
+// OVERLOADED: Intrinsic::getAllDefaultArgValues(ID IID) {
 #endif
 
 // Defaults must form a contiguous trailing block.

>From 74323726e52ecc94840b4cee68d022b6ee3d713e Mon Sep 17 00:00:00 2001
From: DharuniRAcharya <dharunira at nvidia.com>
Date: Wed, 9 Sep 2026 11:05:31 +0000
Subject: [PATCH 5/5] Resolve merge conflicts

---
 llvm/lib/IR/AutoUpgrade.cpp                     | 17 +++++++++++------
 llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp |  8 --------
 2 files changed, 11 insertions(+), 14 deletions(-)

diff --git a/llvm/lib/IR/AutoUpgrade.cpp b/llvm/lib/IR/AutoUpgrade.cpp
index 133dbb16d536e..18c11adfbb7d8 100644
--- a/llvm/lib/IR/AutoUpgrade.cpp
+++ b/llvm/lib/IR/AutoUpgrade.cpp
@@ -1608,28 +1608,33 @@ static bool convertIntrinsicValidType(StringRef Name,
   return false;
 }
 
-static unsigned getFullArgCountForDefaultArgUpgrade(Function *F,
-                                                    Intrinsic::ID IID) {
+static unsigned
+getFullArgCountForDefaultArgUpgrade(Function *F, Intrinsic::ID IID,
+                                    SmallVectorImpl<Type *> &OverloadTys) {
   auto [FirstDefault, Defaults] = Intrinsic::getAllDefaultArgValues(IID);
   if (Defaults.empty())
     return 0;
 
-  if (Intrinsic::isOverloaded(IID))
-    return 0;
-
   unsigned FullArgCount = FirstDefault + Defaults.size();
 
   // Only trailing default arguments can be missing.
   if (F->arg_size() < FirstDefault || F->arg_size() >= FullArgCount)
     return 0;
 
+  unsigned NumMissingTrailingParams = FullArgCount - F->arg_size();
+  if (!Intrinsic::isSignatureValid(IID, F->getFunctionType(), OverloadTys,
+                                   NumMissingTrailingParams))
+    return 0;
+
   return FullArgCount;
 }
 
 static bool upgradeIntrinsicWithDefaultArgs(Function *F, Function *&NewFn) {
   Intrinsic::ID IID = F->getIntrinsicID();
+  SmallVector<Type *, 4> OverloadTys;
 
-  unsigned FullArgCount = getFullArgCountForDefaultArgUpgrade(F, IID);
+  unsigned FullArgCount =
+      getFullArgCountForDefaultArgUpgrade(F, IID, OverloadTys);
   if (FullArgCount == 0)
     return false;
 
diff --git a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp
index 1d12235c87a24..b497c4dcd7806 100644
--- a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp
+++ b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp
@@ -427,14 +427,6 @@ CodeGenIntrinsic::CodeGenIntrinsic(const Record *R,
           TheDef->getLoc(),
           formatv("RangeSet requires ImmArg for argument {}", RangeSet.ArgNo));
 
-  if (isOverloaded &&
-      llvm::any_of(ParamDefaultValues, [](const std::optional<uint64_t> &DV) {
-        return DV.has_value();
-      }))
-    PrintFatalError(TheDef->getLoc(),
-                    "default argument values are not supported for "
-                    "overloaded intrinsics");
-
   unsigned NumParams = IS.ParamTys.size();
   bool SeenDefault = false;
   for (unsigned i = 0; i < NumParams; ++i) {



More information about the llvm-commits mailing list