[clang] [llvm] [LLVM] Extend `getIntrinsicInfoTableEntries` to return number of args (PR #196563)
Rahul Joshi via cfe-commits
cfe-commits at lists.llvm.org
Fri May 8 10:38:46 PDT 2026
https://github.com/jurahul updated https://github.com/llvm/llvm-project/pull/196563
>From 0c97380df99647df1956ace8ae5dffdf3e8e43b5 Mon Sep 17 00:00:00 2001
From: Rahul Joshi <rjoshi at nvidia.com>
Date: Fri, 8 May 2026 08:58:06 -0700
Subject: [PATCH] [LLVM][Intrinsics] Extend `getIntrinsicInfoTableEntries` to
return num args
---
clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp | 12 +---
llvm/include/llvm/IR/Intrinsics.h | 15 +++--
llvm/lib/IR/Intrinsics.cpp | 79 ++++++++++++-------------
3 files changed, 52 insertions(+), 54 deletions(-)
diff --git a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
index fe932834e9b55..868bca404949b 100644
--- a/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
+++ b/clang/lib/CIR/CodeGen/CIRGenBuiltin.cpp
@@ -955,21 +955,13 @@ static cir::FuncType getIntrinsicType(CIRGenFunction &cgf,
using namespace llvm::Intrinsic;
SmallVector<IITDescriptor, 8> table;
- getIntrinsicInfoTableEntries(id, table);
+ auto [tableRef, _, isVarArg] = getIntrinsicInfoTableEntries(id, table);
- ArrayRef<IITDescriptor> tableRef = table;
mlir::Type resultTy = decodeFixedType(cgf, tableRef, context);
SmallVector<mlir::Type, 8> argTypes;
- bool isVarArg = false;
- while (!tableRef.empty()) {
- IITDescriptor::IITDescriptorKind kind = tableRef.front().Kind;
- if (kind == IITDescriptor::VarArg) {
- isVarArg = true;
- break; // VarArg is last
- }
+ while (!tableRef.empty())
argTypes.push_back(decodeFixedType(cgf, tableRef, context));
- }
// CIR convention: no explicit void return type
if (isa<cir::VoidType>(resultTy))
diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index ae931c7961161..af97285fcee70 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -20,6 +20,7 @@
#include "llvm/Support/TypeSize.h"
#include <optional>
#include <string>
+#include <tuple>
namespace llvm {
@@ -259,10 +260,16 @@ struct IITDescriptor {
/// Returns true if \p id has a struct return type.
LLVM_ABI bool hasStructReturnType(ID id);
-/// Return the IIT table descriptor for the specified intrinsic into an array
-/// of IITDescriptors.
-LLVM_ABI void getIntrinsicInfoTableEntries(ID id,
- SmallVectorImpl<IITDescriptor> &T);
+/// Fill the IIT table descriptor for the intrinsic \p id into an array
+/// of IITDescriptors. Returns a tuple of 3 values:
+/// - ArrayRef for the descriptor table (for convenience).
+/// - Number of arguments.
+/// - if it's a variable argument intrinsic.
+///
+/// Note that for VarArg intrinsics, the last IIT `VarArg` token will be
+/// consumed and not a part of the returned ArrayRef.
+LLVM_ABI std::tuple<ArrayRef<IITDescriptor>, unsigned, bool>
+getIntrinsicInfoTableEntries(ID id, SmallVectorImpl<IITDescriptor> &T);
/// Returns true if \p FT is a valid function type for intrinsic \p ID. If
/// `ID` is an overloaded intrinsic, the overload types are pushed into the
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index ff57d335c9a13..72fbfabd48987 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -38,10 +38,9 @@
using namespace llvm;
// Forward declaration of static functions.
-static bool isIntrinsicVarArg(ArrayRef<Intrinsic::IITDescriptor> &Infos,
- bool Consume);
static bool isSignatureValid(FunctionType *FTy,
ArrayRef<Intrinsic::IITDescriptor> &Infos,
+ bool IsVarArg, unsigned NumArgs,
SmallVectorImpl<Type *> &OverloadTys,
raw_ostream &OS);
@@ -398,6 +397,7 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
unsigned OverloadIndex = Infos[NextElt++];
OutputTable.push_back(
IITDescriptor::get(IITDescriptor::SameVecWidth, OverloadIndex));
+ DecodeIITType(NextElt, Infos, OutputTable);
return;
}
case IIT_VEC_OF_ANYPTRS_TO_ELT: {
@@ -451,8 +451,9 @@ DecodeIITType(unsigned &NextElt, ArrayRef<unsigned char> Infos,
#define GET_INTRINSIC_GENERATOR_GLOBAL
#include "llvm/IR/IntrinsicImpl.inc"
-void Intrinsic::getIntrinsicInfoTableEntries(
- ID id, SmallVectorImpl<IITDescriptor> &T) {
+std::tuple<ArrayRef<Intrinsic::IITDescriptor>, unsigned, bool>
+Intrinsic::getIntrinsicInfoTableEntries(ID id,
+ SmallVectorImpl<IITDescriptor> &T) {
// Note that `FixedEncodingTy` is defined in IntrinsicImpl.inc and can be
// uint16_t or uint32_t based on the the value of `Use16BitFixedEncoding` in
// IntrinsicEmitter.cpp.
@@ -497,8 +498,21 @@ void Intrinsic::getIntrinsicInfoTableEntries(
// Okay, decode the table into the output vector of IITDescriptors.
DecodeIITType(NextElt, IITEntries, T);
- while (IITEntries[NextElt] != IIT_Done)
+ unsigned NumArgs = 0;
+ while (IITEntries[NextElt] != IIT_Done) {
DecodeIITType(NextElt, IITEntries, T);
+ ++NumArgs;
+ }
+
+ ArrayRef<IITDescriptor> TableRef = T;
+
+ bool IsVarArg = false;
+ if (TableRef.back().Kind == Intrinsic::IITDescriptor::VarArg) {
+ IsVarArg = true;
+ TableRef.consume_back();
+ --NumArgs;
+ }
+ return {TableRef, NumArgs, IsVarArg};
}
static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
@@ -511,8 +525,6 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
switch (D.Kind) {
case IITDescriptor::Void:
return Type::getVoidTy(Context);
- case IITDescriptor::VarArg:
- return Type::getVoidTy(Context);
case IITDescriptor::MMX:
return llvm::FixedVectorType::get(llvm::IntegerType::get(Context, 64), 1);
case IITDescriptor::AMX:
@@ -589,6 +601,8 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
assert(VTy && "Expected overload type to be a Vector Type");
return VectorType::getInteger(VTy);
}
+ case IITDescriptor::VarArg:
+ break;
}
llvm_unreachable("unhandled");
}
@@ -596,10 +610,7 @@ static Type *DecodeFixedType(ArrayRef<Intrinsic::IITDescriptor> &Infos,
FunctionType *Intrinsic::getType(LLVMContext &Context, ID id,
ArrayRef<Type *> OverloadTys) {
SmallVector<IITDescriptor, 8> Table;
- getIntrinsicInfoTableEntries(id, Table);
- ArrayRef<IITDescriptor> TableRef = Table;
-
- bool IsVarArg = isIntrinsicVarArg(TableRef, /*Consume=*/true);
+ auto [TableRef, _, IsVarArg] = getIntrinsicInfoTableEntries(id, Table);
Type *ResultTy = DecodeFixedType(TableRef, OverloadTys, Context);
@@ -777,16 +788,13 @@ Function *Intrinsic::getOrInsertDeclaration(Module *M, ID id, Type *RetTy,
// Get the intrinsic signature metadata.
SmallVector<Intrinsic::IITDescriptor, 8> Table;
- getIntrinsicInfoTableEntries(id, Table);
- ArrayRef<Intrinsic::IITDescriptor> TableRef = Table;
- bool IsVarArg = isIntrinsicVarArg(TableRef, /*Consume=*/false);
-
+ auto [TableRef, NumArgs, IsVarArg] = getIntrinsicInfoTableEntries(id, Table);
FunctionType *FTy = FunctionType::get(RetTy, ArgTys, IsVarArg);
// Automatically determine the overloaded types.
SmallVector<Type *, 4> OverloadTys;
- [[maybe_unused]] bool IsValid =
- ::isSignatureValid(FTy, TableRef, OverloadTys, nulls());
+ [[maybe_unused]] bool IsValid = ::isSignatureValid(
+ FTy, TableRef, IsVarArg, NumArgs, OverloadTys, nulls());
assert(IsValid && "intrinsic signature mismatch");
return getOrInsertIntrinsicDeclarationImpl(M, id, OverloadTys, FTy);
}
@@ -859,8 +867,6 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
switch (D.Kind) {
case IITDescriptor::Void:
return !Ty->isVoidTy();
- case IITDescriptor::VarArg:
- return true;
case IITDescriptor::MMX: {
FixedVectorType *VT = dyn_cast<FixedVectorType>(Ty);
return !VT || VT->getNumElements() != 1 ||
@@ -1050,44 +1056,38 @@ matchIntrinsicType(Type *Ty, ArrayRef<Intrinsic::IITDescriptor> &Infos,
return true;
return ThisArgVecTy != VectorType::getInteger(ReferenceType);
}
+ case IITDescriptor::VarArg:
+ break;
}
llvm_unreachable("unhandled");
}
-/// Returns true if the intrinsic is a VarArg intrinsics. If \p Consume is true
-/// the IITDescriptor for the VarArg is consumed and removed from \p Infos, else
-/// it stays unchanged.
-static bool isIntrinsicVarArg(ArrayRef<Intrinsic::IITDescriptor> &Infos,
- bool Consume) {
- if (!Infos.empty() && Infos.back().Kind == Intrinsic::IITDescriptor::VarArg) {
- if (Consume)
- Infos.consume_back();
- return true;
- }
- return false;
-}
-
/// Return true if the function type \p FTy is a valid type signature for the
-/// type constraints specified in the .td file, represented by \p Infos.
-/// The overloaded type for the intrinsic are pushed to the OverloadTys vector.
+/// type constraints specified in the .td file, represented by \p Infos and
+/// \p IsVarArg. The overloaded type for the intrinsic are pushed to the
+/// \p OverloadTys vector.
///
/// 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,
+ bool IsVarArg, unsigned NumArgs,
SmallVectorImpl<Type *> &OverloadTys,
raw_ostream &OS) {
- bool IsVarArg = isIntrinsicVarArg(Infos, /*Consume=*/true);
-
SmallVector<DeferredIntrinsicMatchPair, 2> DeferredChecks;
if (matchIntrinsicType(FTy->getReturnType(), Infos, OverloadTys,
DeferredChecks, false)) {
OS << "intrinsic has incorrect return type!";
return false;
}
-
unsigned NumDeferredReturnChecks = DeferredChecks.size();
+ if (FTy->getNumParams() != NumArgs) {
+ OS << "intrinsic has incorrect number of args. Expected " << NumArgs
+ << ", but got " << FTy->getNumParams();
+ return false;
+ }
+
for (Type *Ty : FTy->params()) {
if (matchIntrinsicType(Ty, Infos, OverloadTys, DeferredChecks, false)) {
OS << "intrinsic has incorrect argument type!";
@@ -1137,10 +1137,9 @@ bool Intrinsic::isSignatureValid(Intrinsic::ID ID, FunctionType *FT,
return false;
SmallVector<Intrinsic::IITDescriptor, 8> Table;
- getIntrinsicInfoTableEntries(ID, Table);
- ArrayRef<Intrinsic::IITDescriptor> TableRef = Table;
+ auto [TableRef, NumArgs, IsVarArg] = getIntrinsicInfoTableEntries(ID, Table);
- return ::isSignatureValid(FT, TableRef, OverloadTys, OS);
+ return ::isSignatureValid(FT, TableRef, IsVarArg, NumArgs, OverloadTys, OS);
}
bool Intrinsic::isSignatureValid(Function *F,
More information about the cfe-commits
mailing list