[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