[Mlir-commits] [llvm] [mlir] [MLIR][LLVM][Intrinsics] Add new MLIR and LLVM APIs to automatically resolve overload types (PR #168188)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Sat Nov 15 00:41:06 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-ir

Author: Rajat Bajpai (rajatbajpai)

<details>
<summary>Changes</summary>

Currently, the `getOrInsertDeclaration` API requires callers to explicitly provide overload types for overloaded intrinsics, placing a significant burden on callers who must determine whether overload types are needed. This typically results in conditional logic at each call site to check if the intrinsic is overloaded and manually match the intrinsic signature.

This patch introduces a new `getOrInsertDeclaration` overload that automatically deduces overload types from the provided return type and argument types. The new API uses `Intrinsic::matchIntrinsicSignature` internally to resolve overloaded types, eliminating the need for callers to perform manual overload detection.

This patch introduces two levels of convenience APIs to eliminate manual overload detection:

1. A new `getOrInsertDeclaration` overload that automatically deduces overload types from return and argument types
2. A new `createIntrinsicCall` overload at MLIR level that leverages the above to provide a simple, type-based intrinsic call interface

Key changes:
- Added `Intrinsic::getOrInsertDeclaration(Module*, ID, Type *RetTy, ArrayRef<Type*> ArgTys)` overload that automatically resolves overloaded intrinsics by internally using `matchIntrinsicSignature`. For non-overloaded intrinsics, it delegates to the existing API.
- Refactored `Intrinsics.cpp` to extract a common helper function `getOrInsertIntrinsicDeclarationImpl` to reduce code duplication between the two `getOrInsertDeclaration` overloads.
- Added `createIntrinsicCall(IRBuilderBase&, Intrinsic::ID, Type *retTy, ArrayRef<Value*> args)` overload in ModuleTranslation that provides a simple interface by delegating overload resolution to the new LLVM API.
- Simplified NVVM_PrefetchOp implementation by removing all conditional logic for handling overloaded intrinsics.

---
Full diff: https://github.com/llvm/llvm-project/pull/168188.diff


5 Files Affected:

- (modified) llvm/include/llvm/IR/Intrinsics.h (+15) 
- (modified) llvm/lib/IR/Intrinsics.cpp (+41-9) 
- (modified) mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td (+1-6) 
- (modified) mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h (+9) 
- (modified) mlir/lib/Target/LLVMIR/ModuleTranslation.cpp (+15) 


``````````diff
diff --git a/llvm/include/llvm/IR/Intrinsics.h b/llvm/include/llvm/IR/Intrinsics.h
index 9577d0141f168..ffcc4677830ca 100644
--- a/llvm/include/llvm/IR/Intrinsics.h
+++ b/llvm/include/llvm/IR/Intrinsics.h
@@ -104,6 +104,21 @@ namespace Intrinsic {
   LLVM_ABI Function *getOrInsertDeclaration(Module *M, ID id,
                                             ArrayRef<Type *> Tys = {});
 
+  /// Look up the Function declaration of the intrinsic \p IID in the Module
+  /// \p M. If it does not exist, add a declaration and return it. Otherwise,
+  /// return the existing declaration.
+  ///
+  /// This overload automatically resolves overloaded intrinsics based on the
+  /// provided return type and argument types. For non-overloaded intrinsics,
+  /// the return type and argument types are ignored.
+  ///
+  /// \param M - The module to get or insert the intrinsic declaration.
+  /// \param IID - The intrinsic ID.
+  /// \param RetTy - The return type of the intrinsic.
+  /// \param ArgTys - The argument types of the intrinsic.
+  LLVM_ABI Function *getOrInsertDeclaration(Module *M, ID IID, Type *RetTy,
+                                            ArrayRef<Type *> ArgTys);
+
   /// Look up the Function declaration of the intrinsic \p id in the Module
   /// \p M and return it if it exists. Otherwise, return nullptr. This version
   /// supports non-overloaded intrinsics.
diff --git a/llvm/lib/IR/Intrinsics.cpp b/llvm/lib/IR/Intrinsics.cpp
index 526800e217399..61c83be82a917 100644
--- a/llvm/lib/IR/Intrinsics.cpp
+++ b/llvm/lib/IR/Intrinsics.cpp
@@ -720,14 +720,14 @@ Intrinsic::ID Intrinsic::lookupIntrinsicID(StringRef Name) {
 #include "llvm/IR/IntrinsicImpl.inc"
 #undef GET_INTRINSIC_ATTRIBUTES
 
-Function *Intrinsic::getOrInsertDeclaration(Module *M, ID id,
-                                            ArrayRef<Type *> Tys) {
-  // There can never be multiple globals with the same name of different types,
-  // because intrinsics must be a specific type.
-  auto *FT = getType(M->getContext(), id, Tys);
+static Function *getOrInsertIntrinsicDeclarationImpl(Module *M,
+                                                     Intrinsic::ID id,
+                                                     ArrayRef<Type *> Tys,
+                                                     FunctionType *FT) {
   Function *F = cast<Function>(
-      M->getOrInsertFunction(
-           Tys.empty() ? getName(id) : getName(id, Tys, M, FT), FT)
+      M->getOrInsertFunction(Tys.empty() ? Intrinsic::getName(id)
+                                         : Intrinsic::getName(id, Tys, M, FT),
+                             FT)
           .getCallee());
   if (F->getFunctionType() == FT)
     return F;
@@ -739,11 +739,43 @@ Function *Intrinsic::getOrInsertDeclaration(Module *M, ID id,
   // invalid declaration will get upgraded later.
   F->setName(F->getName() + ".invalid");
   return cast<Function>(
-      M->getOrInsertFunction(
-           Tys.empty() ? getName(id) : getName(id, Tys, M, FT), FT)
+      M->getOrInsertFunction(Tys.empty() ? Intrinsic::getName(id)
+                                         : Intrinsic::getName(id, Tys, M, FT),
+                             FT)
           .getCallee());
 }
 
+Function *Intrinsic::getOrInsertDeclaration(Module *M, ID id,
+                                            ArrayRef<Type *> Tys) {
+  // There can never be multiple globals with the same name of different types,
+  // because intrinsics must be a specific type.
+  FunctionType *FT = getType(M->getContext(), id, Tys);
+  return getOrInsertIntrinsicDeclarationImpl(M, id, Tys, FT);
+}
+
+Function *Intrinsic::getOrInsertDeclaration(Module *M, ID IID, Type *RetTy,
+                                            ArrayRef<Type *> ArgTys) {
+  // If the intrinsic is not overloaded, use the non-overloaded version.
+  if (!Intrinsic::isOverloaded(IID))
+    return getOrInsertDeclaration(M, IID);
+
+  // Get the intrinsic signature metadata.
+  SmallVector<Intrinsic::IITDescriptor, 8> Table;
+  getIntrinsicInfoTableEntries(IID, Table);
+  ArrayRef<Intrinsic::IITDescriptor> TableRef = Table;
+
+  FunctionType *FTy = FunctionType::get(RetTy, ArgTys, /*isVarArg=*/false);
+
+  // Automatically determine the overloaded types.
+  SmallVector<Type *, 4> OverloadTys;
+  [[maybe_unused]] Intrinsic::MatchIntrinsicTypesResult Res =
+      matchIntrinsicSignature(FTy, TableRef, OverloadTys);
+  assert(Res == Intrinsic::MatchIntrinsicTypes_Match && TableRef.empty() &&
+         "intrinsic signature mismatch");
+
+  return getOrInsertIntrinsicDeclarationImpl(M, IID, OverloadTys, FTy);
+}
+
 Function *Intrinsic::getDeclarationIfExists(const Module *M, ID id) {
   return M->getFunction(getName(id));
 }
diff --git a/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td b/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
index 995ade5c9b033..5747021be189c 100644
--- a/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
+++ b/mlir/include/mlir/Dialect/LLVMIR/NVVMOps.td
@@ -3176,12 +3176,7 @@ def NVVM_PrefetchOp : NVVM_Op<"prefetch",
   let llvmBuilder = [{
     auto [id, args] = NVVM::PrefetchOp::getIntrinsicIDAndArgs(op,
                                           moduleTranslation, builder);
-
-    if(op.getTensormap())
-      // Overloaded intrinsic
-      createIntrinsicCall(builder, id, args, {args[0]->getType()});
-    else
-      createIntrinsicCall(builder, id, args);
+    createIntrinsicCall(builder, id, builder.getVoidTy(), args);
   }];
 }
 
diff --git a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
index eb7dfa7637e52..039ac8e2e1911 100644
--- a/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
+++ b/mlir/include/mlir/Target/LLVMIR/ModuleTranslation.h
@@ -512,6 +512,15 @@ llvm::CallInst *createIntrinsicCall(llvm::IRBuilderBase &builder,
                                     ArrayRef<llvm::Value *> args = {},
                                     ArrayRef<llvm::Type *> tys = {});
 
+/// Creates a call to an LLVM IR intrinsic function with the given return type
+/// and arguments. If the intrinsic is overloaded, the function signature will
+/// be automatically resolved based on the provided return type and argument
+/// types.
+llvm::CallInst *createIntrinsicCall(llvm::IRBuilderBase &builder,
+                                    llvm::Intrinsic::ID intrinsic,
+                                    llvm::Type *retTy,
+                                    ArrayRef<llvm::Value *> args);
+
 /// Creates a call to a LLVM IR intrinsic defined by LLVM_IntrOpBase. This
 /// resolves the overloads, and maps mixed MLIR value and attribute arguments to
 /// LLVM values.
diff --git a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
index 64e3c5f085bb3..e48e841dae18a 100644
--- a/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
+++ b/mlir/lib/Target/LLVMIR/ModuleTranslation.cpp
@@ -898,6 +898,21 @@ llvm::CallInst *mlir::LLVM::detail::createIntrinsicCall(
   return builder.CreateCall(fn, args);
 }
 
+llvm::CallInst *mlir::LLVM::detail::createIntrinsicCall(
+    llvm::IRBuilderBase &builder, llvm::Intrinsic::ID intrinsic,
+    llvm::Type *retTy, ArrayRef<llvm::Value *> args) {
+  llvm::Module *module = builder.GetInsertBlock()->getModule();
+
+  SmallVector<llvm::Type *> argTys;
+  argTys.reserve(args.size());
+  for (llvm::Value *arg : args)
+    argTys.push_back(arg->getType());
+
+  llvm::Function *fn =
+      llvm::Intrinsic::getOrInsertDeclaration(module, intrinsic, retTy, argTys);
+  return builder.CreateCall(fn, args);
+}
+
 llvm::CallInst *mlir::LLVM::detail::createIntrinsicCall(
     llvm::IRBuilderBase &builder, ModuleTranslation &moduleTranslation,
     Operation *intrOp, llvm::Intrinsic::ID intrinsic, unsigned numResults,

``````````

</details>


https://github.com/llvm/llvm-project/pull/168188


More information about the Mlir-commits mailing list