From 94201c35f371f43b45eadafdaa3698d1688a985e Mon Sep 17 00:00:00 2001 From: Rahul Joshi Date: Thu, 30 Apr 2026 09:09:56 -0700 Subject: [PATCH] [LLVM][Intrinsics] Add validation for vararg intrinsics (#193777) Add validation for use of `llvm_vararg_ty` in intrinsic type signature. --- llvm/include/llvm/IR/Intrinsics.h | 4 +-- .../TableGen/intrinsic-varargs-validation.td | 35 +++++++++++++++++++ llvm/test/TableGen/intrinsic-varargs.td | 1 + .../TableGen/Basic/CodeGenIntrinsics.cpp | 17 ++++++--- 4 files changed, 51 insertions(+), 6 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 954c704169e5..1efddd09b08f 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 &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/test/TableGen/intrinsic-varargs-validation.td b/llvm/test/TableGen/intrinsic-varargs-validation.td new file mode 100644 index 000000000000..70231747e85e --- /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: cannot use llvm_vararg_ty as a return type +def int_test: Intrinsic<[llvm_vararg_ty], []>; +#endif // TEST0 + +#ifdef TEST1 +// 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: 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: 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: 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/test/TableGen/intrinsic-varargs.td b/llvm/test/TableGen/intrinsic-varargs.td index f94e1d0d6750..498647cc54ed 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]>; diff --git a/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp b/llvm/utils/TableGen/Basic/CodeGenIntrinsics.cpp index 6239082d35be..af70f216d538 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");