[llvm] [LLVM][Intrinsics] Add validation for vararg intrinsics (PR #193777)
Rahul Joshi via llvm-commits
llvm-commits at lists.llvm.org
Thu Apr 30 06:13:33 PDT 2026
https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/193777
>From fb810d2794e9933dea29b05389388baf4cf560df Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 23 Apr 2026 08:27:08 -0700
Subject: [PATCH 1/2] [LLVM][Intrinsics] Add validation for vararg intrinsics
Add additional validation for use of `llvm_vararg_ty` in intrinsic type
signature. Additionally simplify some existing validation to use
`!filter` and short-circuiting `!or, and print the top-level record name
with assert message for better tracebility when an assert fails.
---
llvm/include/llvm/IR/Intrinsics.h | 4 +-
llvm/include/llvm/IR/Intrinsics.td | 41 ++++++++++++++-----
llvm/test/TableGen/intrinsic-arginfo-error.td | 2 +-
...nsic-overload-dependent-type-validation.td | 8 ++--
.../TableGen/intrinsic-varargs-validation.td | 35 ++++++++++++++++
llvm/test/TableGen/intrinsic-varargs.td | 1 +
6 files changed, 74 insertions(+), 17 deletions(-)
create mode 100644 llvm/test/TableGen/intrinsic-varargs-validation.td
diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 954c704169e53..1efddd09b08fd 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -227,7 +227,7 @@ namespace Intrinsic {
}
// OneNthEltsVecArguments uses both a divisor N and a reference argument for
- // the full-width vector to match
+ // the full-width vector to match.
unsigned getVectorDivisor() const {
assert(Kind == OneNthEltsVec);
return OverloadInfo >> 16;
@@ -285,7 +285,7 @@ namespace Intrinsic {
LLVM_ABI bool matchIntrinsicVarArg(bool isVarArg,
ArrayRef<IITDescriptor> &Infos);
- /// Gets the type arguments of an intrinsic call by matching type contraints
+ /// Gets the overload types of an intrinsic call by matching type contraints
/// specified by the .td file. The overloaded types are pushed into the
/// OverloadTys vector.
///
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index afcf21af115a5..baa187219e39d 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -690,7 +690,8 @@ class AssignOverloadIndex<list<bit> IsOverloadedType> {
list<int> ret = !foreach(a, PrefixSum, !if(!ge(a, 0), a, ?));
}
-class TypeInfoGen<list<LLVMType> RetTypes, list<LLVMType> ParamTypes> {
+class TypeInfoGen<string Name, list<LLVMType> RetTypes,
+ list<LLVMType> ParamTypes> {
list<LLVMType> AllTypes = !listconcat(RetTypes, ParamTypes);
// Assign overload index for all overloaded types
@@ -707,19 +708,39 @@ class TypeInfoGen<list<LLVMType> RetTypes, list<LLVMType> ParamTypes> {
// Validate that the overload index referenced by dependent types always
// references an LLVMAnyType type.
- list<int> InvalidOverload = !foreach(ty, AllTypes,
- // an entry in the list will be 1 if its a dependent type and it
- // references another overload type that is not `Any`.
+ list<LLVMType> InvalidOverload = !filter(ty, AllTypes,
+ // A dependent type has an invalid overload index if it references another
+ // overload type that is not `Any`.
!and(
!isa<LLVMDependentType>(ty),
- !if(!ge(!cast<LLVMDependentType>(ty).OverloadIndex, !size(OverloadTypes)),
- 1,
- !not(!isa<LLVMAnyType>(OverloadTypes[!cast<LLVMDependentType>(ty).OverloadIndex]))
+ !or(
+ !if(!ge(!cast<LLVMDependentType>(ty).OverloadIndex, !size(OverloadTypes)), -1, 0),
+ !not(!isa<LLVMAnyType>(
+ OverloadTypes[!cast<LLVMDependentType>(ty).OverloadIndex]))
)
)
);
- assert !eq(!foldl(0, InvalidOverload, a, x, !add(a, x)), 0),
- "dependent types must reference an overload index of an \'llvm_any\' type";
+ assert !empty(InvalidOverload),
+ Name #
+ ": dependent types must reference an overload index of an \'llvm_any\' type";
+
+ // Validate that return types cannot have vararg.
+ assert !empty(!filter(ty, RetTypes, !eq(ty, llvm_vararg_ty))),
+ Name # ": cannot use llvm_vararg_ty as a return type";
+
+ // Validate that param types can have vararg only in the last position.
+ // Create a list of indices for vararg_ty occurrences in the list.
+ list<int> VarArgIndices = !filter(
+ Idx1,
+ !foreach(Idx0, !range(ParamTypes),
+ !if(!eq(ParamTypes[Idx0], llvm_vararg_ty), Idx0, -1)),
+ !ge(Idx1, 0)
+ );
+ assert !le(!size(VarArgIndices), 1),
+ Name # ": cannot use llvm_vararg_ty more than once as a param type";
+ assert !or(!if(!empty(VarArgIndices), -1, 0),
+ !eq(VarArgIndices[0], !sub(!size(ParamTypes), 1))),
+ Name # ": llvm_vararg_ty must be used as the last param type";
list<LLVMType> Types = !foreach(ty, AllTypes,
!if(!isa<LLVMDependentType>(ty),
@@ -768,7 +789,7 @@ class Intrinsic<list<LLVMType> ret_types,
// IntrinsicProperty<1>
bit DisableDefaultAttributes = disable_default_attributes;
- TypeInfoGen TypeInfo = TypeInfoGen<RetTypes, ParamTypes>;
+ TypeInfoGen TypeInfo = TypeInfoGen<NAME, RetTypes, ParamTypes>;
}
// Intrinsic with default attributes (disable_default_attributes = false).
diff --git a/llvm/test/TableGen/intrinsic-arginfo-error.td b/llvm/test/TableGen/intrinsic-arginfo-error.td
index 0a49e73bf5529..f777dbc0539d8 100644
--- a/llvm/test/TableGen/intrinsic-arginfo-error.td
+++ b/llvm/test/TableGen/intrinsic-arginfo-error.td
@@ -2,7 +2,7 @@
include "llvm/IR/Intrinsics.td"
-// CHECK: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
def int_test : DefaultAttrsIntrinsic<
[llvm_anyint_ty],
[llvm_anyint_ty, LLVMMatchType<2>],
diff --git a/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td b/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td
index b7da7f6c0bf87..514363d84cf64 100644
--- a/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td
+++ b/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td
@@ -12,7 +12,7 @@ include "llvm/IR/Intrinsics.td"
#ifdef TEST0
-// CHECK-TEST0: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK-TEST0: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
def int_test: DefaultAttrsIntrinsic<
[ llvm_anyvector_ty], // overload index 0.
[ LLVMVectorOfAnyPointersToElt<0>, // overload index 1.
@@ -28,7 +28,7 @@ def int_test: DefaultAttrsIntrinsic<
#ifdef TEST1
-// CHECK-TEST1: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK-TEST1: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
def int_test: DefaultAttrsIntrinsic<
[ llvm_anyvector_ty], // overload index 0.
[ LLVMVectorOfAnyPointersToElt<0>, // overload index 1.
@@ -44,7 +44,7 @@ def int_test: DefaultAttrsIntrinsic<
#ifdef TEST2
-// CHECK-TEST2: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK-TEST2: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
def int_test: DefaultAttrsIntrinsic<
[ llvm_anyvector_ty], // overload index 0.
[ LLVMVectorOfAnyPointersToElt<0>, // overload index 1.
@@ -60,7 +60,7 @@ def int_test: DefaultAttrsIntrinsic<
#ifdef TEST3
-// CHECK-TEST3: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK-TEST3: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
def int_test: DefaultAttrsIntrinsic<
[ llvm_anyvector_ty], // overload index 0.
[ LLVMVectorOfAnyPointersToElt<0>, // overload index 1.
diff --git a/llvm/test/TableGen/intrinsic-varargs-validation.td b/llvm/test/TableGen/intrinsic-varargs-validation.td
new file mode 100644
index 0000000000000..28ab7bae44368
--- /dev/null
+++ b/llvm/test/TableGen/intrinsic-varargs-validation.td
@@ -0,0 +1,35 @@
+// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST0 2>&1 | FileCheck %s --check-prefix=CHECK-TEST0
+// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST1 2>&1 | FileCheck %s --check-prefix=CHECK-TEST1
+// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST2 2>&1 | FileCheck %s --check-prefix=CHECK-TEST2
+// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST3 2>&1 | FileCheck %s --check-prefix=CHECK-TEST3
+// RUN: not llvm-tblgen -gen-intrinsic-impl -I %p/../../include %s -DTEST4 2>&1 | FileCheck %s --check-prefix=CHECK-TEST4
+
+// This unit test tests whether invalid use of `llvm_vararg_ty` are flagged.
+
+#define TEST_INTRINSICS_SUPPRESS_DEFS
+include "llvm/IR/Intrinsics.td"
+
+#ifdef TEST0
+// CHECK-TEST0: error: assertion failed: int_test: cannot use llvm_vararg_ty as a return type
+def int_test: Intrinsic<[llvm_vararg_ty], []>;
+#endif // TEST0
+
+#ifdef TEST1
+// CHECK-TEST1: error: assertion failed: int_test: cannot use llvm_vararg_ty as a return type
+def int_test: Intrinsic<[llvm_i32_ty, llvm_vararg_ty], []>;
+#endif // TEST1
+
+#ifdef TEST2
+// CHECK-TEST2: error: assertion failed: int_test: llvm_vararg_ty must be used as the last param type
+def int_test: Intrinsic<[], [llvm_i32_ty, llvm_vararg_ty, llvm_i1_ty]>;
+#endif // TEST2
+
+#ifdef TEST3
+// CHECK-TEST3: error: assertion failed: int_test: cannot use llvm_vararg_ty more than once as a param type
+def int_test: Intrinsic<[], [llvm_i32_ty, llvm_vararg_ty, llvm_vararg_ty]>;
+#endif // TEST3
+
+#ifdef TEST4
+// CHECK-TEST4: error: assertion failed: int_test: cannot use llvm_vararg_ty more than once as a param type
+def int_test: Intrinsic<[], [llvm_vararg_ty, llvm_i32_ty, llvm_vararg_ty]>;
+#endif // TEST4
diff --git a/llvm/test/TableGen/intrinsic-varargs.td b/llvm/test/TableGen/intrinsic-varargs.td
index f94e1d0d6750e..498647cc54ed1 100644
--- a/llvm/test/TableGen/intrinsic-varargs.td
+++ b/llvm/test/TableGen/intrinsic-varargs.td
@@ -3,5 +3,6 @@
include "llvm/IR/Intrinsics.td"
+// CHECK-LABEL: IIT_LongEncodingTable
// CHECK: /* 0 */ 0, 26, 0,
def int_foo : Intrinsic<[], [llvm_vararg_ty]>;
>From f73c39210f4099f90d76ff88a8d267934cb48efc Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Thu, 30 Apr 2026 06:05:50 -0700
Subject: [PATCH 2/2] Review feedback
---
llvm/include/llvm/IR/Intrinsics.td | 41 +++++--------------
llvm/test/TableGen/intrinsic-arginfo-error.td | 2 +-
...nsic-overload-dependent-type-validation.td | 8 ++--
.../TableGen/intrinsic-varargs-validation.td | 10 ++---
.../TableGen/Basic/CodeGenIntrinsics.cpp | 17 ++++++--
5 files changed, 33 insertions(+), 45 deletions(-)
diff --git a/llvm/include/llvm/IR/Intrinsics.td b/llvm/include/llvm/IR/Intrinsics.td
index baa187219e39d..afcf21af115a5 100644
--- a/llvm/include/llvm/IR/Intrinsics.td
+++ b/llvm/include/llvm/IR/Intrinsics.td
@@ -690,8 +690,7 @@ class AssignOverloadIndex<list<bit> IsOverloadedType> {
list<int> ret = !foreach(a, PrefixSum, !if(!ge(a, 0), a, ?));
}
-class TypeInfoGen<string Name, list<LLVMType> RetTypes,
- list<LLVMType> ParamTypes> {
+class TypeInfoGen<list<LLVMType> RetTypes, list<LLVMType> ParamTypes> {
list<LLVMType> AllTypes = !listconcat(RetTypes, ParamTypes);
// Assign overload index for all overloaded types
@@ -708,39 +707,19 @@ class TypeInfoGen<string Name, list<LLVMType> RetTypes,
// Validate that the overload index referenced by dependent types always
// references an LLVMAnyType type.
- list<LLVMType> InvalidOverload = !filter(ty, AllTypes,
- // A dependent type has an invalid overload index if it references another
- // overload type that is not `Any`.
+ list<int> InvalidOverload = !foreach(ty, AllTypes,
+ // an entry in the list will be 1 if its a dependent type and it
+ // references another overload type that is not `Any`.
!and(
!isa<LLVMDependentType>(ty),
- !or(
- !if(!ge(!cast<LLVMDependentType>(ty).OverloadIndex, !size(OverloadTypes)), -1, 0),
- !not(!isa<LLVMAnyType>(
- OverloadTypes[!cast<LLVMDependentType>(ty).OverloadIndex]))
+ !if(!ge(!cast<LLVMDependentType>(ty).OverloadIndex, !size(OverloadTypes)),
+ 1,
+ !not(!isa<LLVMAnyType>(OverloadTypes[!cast<LLVMDependentType>(ty).OverloadIndex]))
)
)
);
- assert !empty(InvalidOverload),
- Name #
- ": dependent types must reference an overload index of an \'llvm_any\' type";
-
- // Validate that return types cannot have vararg.
- assert !empty(!filter(ty, RetTypes, !eq(ty, llvm_vararg_ty))),
- Name # ": cannot use llvm_vararg_ty as a return type";
-
- // Validate that param types can have vararg only in the last position.
- // Create a list of indices for vararg_ty occurrences in the list.
- list<int> VarArgIndices = !filter(
- Idx1,
- !foreach(Idx0, !range(ParamTypes),
- !if(!eq(ParamTypes[Idx0], llvm_vararg_ty), Idx0, -1)),
- !ge(Idx1, 0)
- );
- assert !le(!size(VarArgIndices), 1),
- Name # ": cannot use llvm_vararg_ty more than once as a param type";
- assert !or(!if(!empty(VarArgIndices), -1, 0),
- !eq(VarArgIndices[0], !sub(!size(ParamTypes), 1))),
- Name # ": llvm_vararg_ty must be used as the last param type";
+ assert !eq(!foldl(0, InvalidOverload, a, x, !add(a, x)), 0),
+ "dependent types must reference an overload index of an \'llvm_any\' type";
list<LLVMType> Types = !foreach(ty, AllTypes,
!if(!isa<LLVMDependentType>(ty),
@@ -789,7 +768,7 @@ class Intrinsic<list<LLVMType> ret_types,
// IntrinsicProperty<1>
bit DisableDefaultAttributes = disable_default_attributes;
- TypeInfoGen TypeInfo = TypeInfoGen<NAME, RetTypes, ParamTypes>;
+ TypeInfoGen TypeInfo = TypeInfoGen<RetTypes, ParamTypes>;
}
// Intrinsic with default attributes (disable_default_attributes = false).
diff --git a/llvm/test/TableGen/intrinsic-arginfo-error.td b/llvm/test/TableGen/intrinsic-arginfo-error.td
index f777dbc0539d8..0a49e73bf5529 100644
--- a/llvm/test/TableGen/intrinsic-arginfo-error.td
+++ b/llvm/test/TableGen/intrinsic-arginfo-error.td
@@ -2,7 +2,7 @@
include "llvm/IR/Intrinsics.td"
-// CHECK: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
def int_test : DefaultAttrsIntrinsic<
[llvm_anyint_ty],
[llvm_anyint_ty, LLVMMatchType<2>],
diff --git a/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td b/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td
index 514363d84cf64..b7da7f6c0bf87 100644
--- a/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td
+++ b/llvm/test/TableGen/intrinsic-overload-dependent-type-validation.td
@@ -12,7 +12,7 @@ include "llvm/IR/Intrinsics.td"
#ifdef TEST0
-// CHECK-TEST0: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK-TEST0: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
def int_test: DefaultAttrsIntrinsic<
[ llvm_anyvector_ty], // overload index 0.
[ LLVMVectorOfAnyPointersToElt<0>, // overload index 1.
@@ -28,7 +28,7 @@ def int_test: DefaultAttrsIntrinsic<
#ifdef TEST1
-// CHECK-TEST1: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK-TEST1: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
def int_test: DefaultAttrsIntrinsic<
[ llvm_anyvector_ty], // overload index 0.
[ LLVMVectorOfAnyPointersToElt<0>, // overload index 1.
@@ -44,7 +44,7 @@ def int_test: DefaultAttrsIntrinsic<
#ifdef TEST2
-// CHECK-TEST2: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK-TEST2: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
def int_test: DefaultAttrsIntrinsic<
[ llvm_anyvector_ty], // overload index 0.
[ LLVMVectorOfAnyPointersToElt<0>, // overload index 1.
@@ -60,7 +60,7 @@ def int_test: DefaultAttrsIntrinsic<
#ifdef TEST3
-// CHECK-TEST3: error: assertion failed: int_test: dependent types must reference an overload index of an 'llvm_any' type
+// CHECK-TEST3: error: assertion failed: dependent types must reference an overload index of an 'llvm_any' type
def int_test: DefaultAttrsIntrinsic<
[ llvm_anyvector_ty], // overload index 0.
[ LLVMVectorOfAnyPointersToElt<0>, // overload index 1.
diff --git a/llvm/test/TableGen/intrinsic-varargs-validation.td b/llvm/test/TableGen/intrinsic-varargs-validation.td
index 28ab7bae44368..70231747e85e3 100644
--- a/llvm/test/TableGen/intrinsic-varargs-validation.td
+++ b/llvm/test/TableGen/intrinsic-varargs-validation.td
@@ -10,26 +10,26 @@
include "llvm/IR/Intrinsics.td"
#ifdef TEST0
-// CHECK-TEST0: error: assertion failed: int_test: cannot use llvm_vararg_ty as a return type
+// CHECK-TEST0: error: cannot use llvm_vararg_ty as a return type
def int_test: Intrinsic<[llvm_vararg_ty], []>;
#endif // TEST0
#ifdef TEST1
-// CHECK-TEST1: error: assertion failed: int_test: cannot use llvm_vararg_ty as a return type
+// CHECK-TEST1: error: cannot use llvm_vararg_ty as a return type
def int_test: Intrinsic<[llvm_i32_ty, llvm_vararg_ty], []>;
#endif // TEST1
#ifdef TEST2
-// CHECK-TEST2: error: assertion failed: int_test: llvm_vararg_ty must be used as the last param type
+// CHECK-TEST2: error: llvm_vararg_ty can only be the last parameter type
def int_test: Intrinsic<[], [llvm_i32_ty, llvm_vararg_ty, llvm_i1_ty]>;
#endif // TEST2
#ifdef TEST3
-// CHECK-TEST3: error: assertion failed: int_test: cannot use llvm_vararg_ty more than once as a param type
+// CHECK-TEST3: error: llvm_vararg_ty can only be the last parameter type
def int_test: Intrinsic<[], [llvm_i32_ty, llvm_vararg_ty, llvm_vararg_ty]>;
#endif // TEST3
#ifdef TEST4
-// CHECK-TEST4: error: assertion failed: int_test: cannot use llvm_vararg_ty more than once as a param type
+// CHECK-TEST4: error: llvm_vararg_ty can only be the last parameter type
def int_test: Intrinsic<[], [llvm_vararg_ty, llvm_i32_ty, llvm_vararg_ty]>;
#endif // TEST4
diff --git a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp
index 6239082d35bed..af70f216d538a 100644
--- a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp
+++ b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp
@@ -322,11 +322,20 @@ CodeGenIntrinsic::CodeGenIntrinsic(const Record *R,
// Types field is a concatenation of Return types followed by Param types.
unsigned Idx = 0;
- for (; Idx < NumRet; ++Idx)
- IS.RetTys.push_back(TypeList->getElementAsRecord(Idx));
+ for (; Idx < NumRet; ++Idx) {
+ const Record *RetTy = TypeList->getElementAsRecord(Idx);
+ if (RetTy->getName() == "llvm_vararg_ty")
+ PrintFatalError(DefLoc, "cannot use llvm_vararg_ty as a return type");
+ IS.RetTys.push_back(RetTy);
+ }
- for (unsigned E = TypeList->size(); Idx < E; ++Idx)
- IS.ParamTys.push_back(TypeList->getElementAsRecord(Idx));
+ for (unsigned E = TypeList->size(); Idx < E; ++Idx) {
+ const Record *ParamTy = TypeList->getElementAsRecord(Idx);
+ if (Idx != E - 1 && ParamTy->getName() == "llvm_vararg_ty")
+ PrintFatalError(DefLoc,
+ "llvm_vararg_ty can only be the last parameter type");
+ IS.ParamTys.push_back(ParamTy);
+ }
// Parse the intrinsic properties.
const ListInit *PropList = R->getValueAsListInit("IntrProperties");
More information about the llvm-commits
mailing list