[Mlir-commits] [mlir] [MLIR] Account for named attributes without dialect prefixes in `FuncToLLVM` lowering pass (PR #182987)
Ayokunle Amodu
llvmlistbot at llvm.org
Mon Feb 23 19:12:16 PST 2026
https://github.com/ayokunle321 created https://github.com/llvm/llvm-project/pull/182987
Fixes https://github.com/llvm/llvm-project/issues/181464.
Explanation of the issue:
In `convertFuncOpToLLVMFuncOp`, the function `filterFuncAttributes` is called to remove named attributes already handled by the `FuncOp`'s build function. This is done so that the `FuncOp`'s list of named attributes does not have duplicates when trying to create a sorted dictionary out of it. In the crash-inducing test below, the named attribute `linkage` slips through the filter because it does not have its dialect prefix, i.e., it is defined as `linkage` and not `llvm.linkage` (the pass was designed to handle only dialect-prefixed attributes, but MLIR does not enforce dialect prefixed attributes). Due to this, an assert that checks for duplicates in the attribute list fails.
Minimal IR:
```
module {
func.func @host() attributes {linkage = #llvm.linkage<internal>} {
return
}
}
```
This patch updates the `FuncToLLVM` lowering pass to account for attribute names without dialect prefixes.
@matthias-springer I know the fix is funky 😔, please bare with me. Open to suggestions for a better workaround.
>From 46fa4abe8bd4902988c19e3ecf5564966606a095 Mon Sep 17 00:00:00 2001
From: Ayokunle Amodu <ayokunle321 at gmail.com>
Date: Mon, 23 Feb 2026 19:34:28 -0700
Subject: [PATCH] fix handling of attribute names
---
mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp | 29 ++++++++++++++-----
1 file changed, 22 insertions(+), 7 deletions(-)
diff --git a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
index 2220f61ed8a07..d0b33bae6d0a5 100644
--- a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
+++ b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
@@ -52,10 +52,15 @@ static constexpr StringRef varargsAttrName = "func.varargs";
static constexpr StringRef linkageAttrName = "llvm.linkage";
static constexpr StringRef barePtrAttrName = "llvm.bareptr";
+static constexpr StringRef varargsAttrNameNoPrefix = "varargs";
+static constexpr StringRef linkageAttrNameNoPrefix = "linkage";
+static constexpr StringRef barePtrAttrNameNoPrefix = "bareptr";
+
/// Return `true` if the `op` should use bare pointer calling convention.
static bool shouldUseBarePtrCallConv(Operation *op,
const LLVMTypeConverter *typeConverter) {
- return (op && op->hasAttr(barePtrAttrName)) ||
+ return (op && (op->hasAttr(barePtrAttrName) ||
+ op->hasAttr(barePtrAttrNameNoPrefix))) ||
typeConverter->getOptions().useBarePtrCallConv;
}
@@ -65,7 +70,9 @@ static void filterFuncAttributes(FunctionOpInterface func,
SmallVectorImpl<NamedAttribute> &result) {
for (const NamedAttribute &attr : func->getDiscardableAttrs()) {
if (attr.getName() == linkageAttrName ||
+ attr.getName() == linkageAttrNameNoPrefix ||
attr.getName() == varargsAttrName ||
+ attr.getName() == varargsAttrNameNoPrefix ||
attr.getName() == LLVM::LLVMDialect::getReadnoneAttrName())
continue;
result.push_back(attr);
@@ -299,7 +306,10 @@ FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
// Convert the original function arguments. They are converted using the
// LLVMTypeConverter provided to this legalization pattern.
- auto varargsAttr = funcOp->getAttrOfType<BoolAttr>(varargsAttrName);
+ auto varargsAttr =
+ funcOp->getAttrOfType<BoolAttr>(varargsAttrName)
+ ? funcOp->getAttrOfType<BoolAttr>(varargsAttrName)
+ : funcOp->getAttrOfType<BoolAttr>(varargsAttrNameNoPrefix);
// Gather `llvm.byval` and `llvm.byref` arguments whose type convertion was
// overriden with an LLVM pointer type for later processing.
SmallVector<std::optional<NamedAttribute>> byValRefNonPtrAttrs;
@@ -323,9 +333,12 @@ FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
// Create an LLVM function, use external linkage by default until MLIR
// functions have linkage.
LLVM::Linkage linkage = LLVM::Linkage::External;
- if (funcOp->hasAttr(linkageAttrName)) {
- auto attr =
- dyn_cast<mlir::LLVM::LinkageAttr>(funcOp->getAttr(linkageAttrName));
+ if (funcOp->hasAttr(linkageAttrName) ||
+ funcOp->hasAttr(linkageAttrNameNoPrefix)) {
+ auto attr = dyn_cast_or_null<mlir::LLVM::LinkageAttr>(
+ funcOp->getAttr(linkageAttrName)
+ ? funcOp->getAttr(linkageAttrName)
+ : funcOp->getAttr(linkageAttrNameNoPrefix));
if (!attr) {
funcOp->emitError() << "Contains " << linkageAttrName
<< " attribute not of type LLVM::LinkageAttr";
@@ -651,13 +664,15 @@ class CallOpLowering : public CallOpInterfaceLowering<func::CallOp> {
Operation *callee =
symbolTables->lookupNearestSymbolFrom(callOp, callOp.getCalleeAttr());
useBarePtrCallConv =
- callee != nullptr && callee->hasAttr(barePtrAttrName);
+ callee != nullptr && (callee->hasAttr(barePtrAttrName) ||
+ callee->hasAttr(barePtrAttrNameNoPrefix));
} else {
// Warning: This is a linear lookup.
Operation *callee =
SymbolTable::lookupNearestSymbolFrom(callOp, callOp.getCalleeAttr());
useBarePtrCallConv =
- callee != nullptr && callee->hasAttr(barePtrAttrName);
+ callee != nullptr && (callee->hasAttr(barePtrAttrName) ||
+ callee->hasAttr(barePtrAttrNameNoPrefix));
}
return matchAndRewriteImpl(callOp, adaptor, rewriter, useBarePtrCallConv);
}
More information about the Mlir-commits
mailing list