[Mlir-commits] [mlir] [mlir][GPU] Refactor GPUOps lowering (PR #188905)
Hocky Yudhiono
llvmlistbot at llvm.org
Sun Mar 29 19:43:19 PDT 2026
https://github.com/hockyy updated https://github.com/llvm/llvm-project/pull/188905
>From a1a6996cc6dcc4b909f20cc508b063f9f3b83b39 Mon Sep 17 00:00:00 2001
From: Hocky Yudhiono <hocky.yudhiono at gmail.com>
Date: Fri, 27 Mar 2026 12:04:27 +0800
Subject: [PATCH] [mlir][GPU] Refactor GPUOps lowering
---
.../LLVMCommon/LowerFunctionAttrsToLLVM.h | 39 ++++++
mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp | 53 +------
.../Conversion/GPUCommon/GPUOpsLowering.cpp | 132 ++++++++++--------
.../lib/Conversion/GPUCommon/GPUOpsLowering.h | 7 +
mlir/lib/Conversion/LLVMCommon/CMakeLists.txt | 1 +
.../LLVMCommon/LowerFunctionAttrsToLLVM.cpp | 56 ++++++++
6 files changed, 179 insertions(+), 109 deletions(-)
create mode 100644 mlir/include/mlir/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.h
create mode 100644 mlir/lib/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.cpp
diff --git a/mlir/include/mlir/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.h b/mlir/include/mlir/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.h
new file mode 100644
index 0000000000000..f12f9d2c90e2e
--- /dev/null
+++ b/mlir/include/mlir/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.h
@@ -0,0 +1,39 @@
+//===- LowerFunctionAttrsToLLVM.h - Lower func attrs to llvm.func - C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Shared helpers for lowering discardable attributes on any FunctionOpInterface
+// (e.g. func.func, gpu.func) into llvm.func properties and discardables.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CONVERSION_LLVMCOMMON_LOWERFUNCTIONATTRSTOLLVM_H
+#define MLIR_CONVERSION_LLVMCOMMON_LOWERFUNCTIONATTRSTOLLVM_H
+
+#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
+#include "mlir/IR/OperationSupport.h"
+#include "mlir/Interfaces/FunctionInterfaces.h"
+
+namespace mlir {
+
+/// Result of lowering discardable attributes from a `FunctionOpInterface` to
+/// what `llvm.func` expects: typed inherent properties plus remaining
+/// discardable attributes.
+struct LowerLLVMFuncAttrs {
+ LLVM::LLVMFuncOp::Properties properties;
+ NamedAttrList discardableAttrs;
+};
+
+/// Lower discardable attributes on `func`, splitting `llvm.*` inherent
+/// properties from other attributes to forward to `llvm.func`. Returns
+/// failure if an `llvm.*` property bundle is invalid for `llvm.func`.
+FailureOr<LowerLLVMFuncAttrs>
+lowerDiscardableAttrsForLLVMFunc(FunctionOpInterface func);
+
+} // namespace mlir
+
+#endif // MLIR_CONVERSION_LLVMCOMMON_LOWERFUNCTIONATTRSTOLLVM_H
diff --git a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
index 88abc4400c9b7..bd7bc47217bdc 100644
--- a/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
+++ b/mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp
@@ -19,6 +19,7 @@
#include "mlir/Conversion/ConvertToLLVM/ToLLVMInterface.h"
#include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
#include "mlir/Conversion/LLVMCommon/ConversionTarget.h"
+#include "mlir/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.h"
#include "mlir/Conversion/LLVMCommon/Pattern.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/LLVMIR/FunctionCallUtils.h"
@@ -77,55 +78,6 @@ static void filterFuncAttributes(FunctionOpInterface func,
}
}
-/// Add custom lowered funcOp to llvm.func attributes here.
-struct LoweredFuncAttrs {
- LLVM::LLVMFuncOp::Properties properties;
- NamedAttrList discardableAttrs;
-};
-
-/// Lower discardable function attributes on `func.func` to attributes expected
-/// by `llvm.func`.
-static FailureOr<LoweredFuncAttrs>
-lowerFuncAttributes(FunctionOpInterface func) {
- MLIRContext *ctx = func->getContext();
- LoweredFuncAttrs lowered;
-
- llvm::SmallDenseSet<StringRef> odsAttrNames(
- LLVM::LLVMFuncOp::getAttributeNames().begin(),
- LLVM::LLVMFuncOp::getAttributeNames().end());
-
- NamedAttrList inherentAttrs;
-
- for (const NamedAttribute &attr : func->getDiscardableAttrs()) {
- StringRef attrName = attr.getName().strref();
-
- if (odsAttrNames.contains(attrName)) {
- LDBG() << "LLVM specific attributes: " << attrName
- << "should use llvm.* prefix, discarding it";
- continue;
- }
-
- StringRef inherent = attrName;
- if (inherent.consume_front("llvm.") && odsAttrNames.contains(inherent))
- inherentAttrs.set(inherent, attr.getValue()); // collect inherent attrs
- else
- lowered.discardableAttrs.push_back(attr);
- }
-
- // Convert collected inherent attrs into typed properties.
- if (!inherentAttrs.empty()) {
- DictionaryAttr dict = inherentAttrs.getDictionary(ctx);
- auto emitError = [&] {
- return func.emitOpError("invalid llvm.func property");
- };
- if (failed(LLVM::LLVMFuncOp::setPropertiesFromAttr(lowered.properties, dict,
- emitError))) {
- return failure();
- }
- }
- return lowered;
-}
-
static void buildLLVMFuncProperties(PatternRewriter &rewriter,
FunctionOpInterface srcFunc,
Type llvmFuncType,
@@ -385,7 +337,8 @@ FailureOr<LLVM::LLVMFuncOp> mlir::convertFuncOpToLLVMFuncOp(
return funcOp.emitError("C interface for variadic functions is not "
"supported yet.");
- FailureOr<LoweredFuncAttrs> loweredAttrs = lowerFuncAttributes(funcOp);
+ FailureOr<LowerLLVMFuncAttrs> loweredAttrs =
+ lowerDiscardableAttrsForLLVMFunc(funcOp);
if (failed(loweredAttrs))
return rewriter.notifyMatchFailure(funcOp,
"failed to lower func attributes");
diff --git a/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp b/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp
index 6a705ebab7aa4..771cf0abd3c0e 100644
--- a/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp
+++ b/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp
@@ -14,6 +14,7 @@
#include "mlir/IR/Attributes.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/SymbolTable.h"
#include "llvm/ADT/SmallVectorExtras.h"
#include "llvm/ADT/StringSet.h"
#include "llvm/Support/FormatVariadic.h"
@@ -74,6 +75,69 @@ LLVM::GlobalOp mlir::getOrCreateStringConstant(OpBuilder &b, Location loc,
name, attr, alignment, addrSpace);
}
+FailureOr<LowerLLVMFuncAttrs> GPUFuncOpLowering::buildLoweredGPULLVMFuncAttrs(
+ gpu::GPUFuncOp gpuFuncOp, Type llvmFuncType, OpBuilder &rewriter) const {
+ FailureOr<LowerLLVMFuncAttrs> loweredAttrs =
+ lowerDiscardableAttrsForLLVMFunc(gpuFuncOp);
+ if (failed(loweredAttrs))
+ return failure();
+
+ // TODO: How do we refactor this to be deny list?
+ NamedAttrList &discardable = loweredAttrs->discardableAttrs;
+ discardable.erase(gpu::GPUFuncOp::getNumWorkgroupAttributionsAttrName());
+ discardable.erase(SymbolTable::getSymbolAttrName());
+ discardable.erase(gpuFuncOp.getFunctionTypeAttrName());
+ discardable.erase(gpuFuncOp.getArgAttrsAttrName());
+ discardable.erase(gpuFuncOp.getResAttrsAttrName());
+ discardable.erase(gpuFuncOp.getWorkgroupAttribAttrsAttrName());
+ discardable.erase(gpuFuncOp.getPrivateAttribAttrsAttrName());
+ discardable.erase(gpuFuncOp.getKnownBlockSizeAttrName());
+ discardable.erase(gpuFuncOp.getKnownGridSizeAttrName());
+ discardable.erase(gpuFuncOp.getKnownClusterSizeAttrName());
+
+ MLIRContext *ctx = rewriter.getContext();
+ LLVM::LLVMFuncOp::Properties &props = loweredAttrs->properties;
+ props.sym_name = rewriter.getStringAttr(gpuFuncOp.getName());
+ props.function_type = TypeAttr::get(llvmFuncType);
+ props.setCConv(LLVM::CConvAttr::get(ctx, gpuFuncOp.isKernel()
+ ? kernelCallingConvention
+ : nonKernelCallingConvention));
+
+ DenseI32ArrayAttr knownBlockSize = gpuFuncOp.getKnownBlockSizeAttr();
+ DenseI32ArrayAttr knownGridSize = gpuFuncOp.getKnownGridSizeAttr();
+ DenseI32ArrayAttr knownClusterSize = gpuFuncOp.getKnownClusterSizeAttr();
+ // Ensure we don't lose information if the function is lowered before its
+ // surrounding context.
+ auto *gpuDialect = cast<gpu::GPUDialect>(gpuFuncOp->getDialect());
+ if (knownBlockSize)
+ loweredAttrs->discardableAttrs.append(
+ gpuDialect->getKnownBlockSizeAttrHelper().getName(), knownBlockSize);
+ if (knownGridSize)
+ loweredAttrs->discardableAttrs.append(
+ gpuDialect->getKnownGridSizeAttrHelper().getName(), knownGridSize);
+ if (knownClusterSize)
+ loweredAttrs->discardableAttrs.append(
+ gpuDialect->getKnownClusterSizeAttrHelper().getName(),
+ knownClusterSize);
+
+ // Add a dialect specific kernel attribute in addition to GPU kernel
+ // attribute. The former is necessary for further translation while the
+ // latter is expected by gpu.launch_func.
+ if (gpuFuncOp.isKernel()) {
+ if (kernelAttributeName)
+ loweredAttrs->discardableAttrs.append(kernelAttributeName,
+ rewriter.getUnitAttr());
+ if (kernelBlockSizeAttributeName && knownBlockSize)
+ loweredAttrs->discardableAttrs.append(kernelBlockSizeAttributeName,
+ knownBlockSize);
+ if (kernelClusterSizeAttributeName && knownClusterSize)
+ loweredAttrs->discardableAttrs.append(kernelClusterSizeAttributeName,
+ knownClusterSize);
+ }
+
+ return loweredAttrs;
+}
+
LogicalResult
GPUFuncOpLowering::matchAndRewrite(gpu::GPUFuncOp gpuFuncOp, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const {
@@ -174,67 +238,17 @@ GPUFuncOpLowering::matchAndRewrite(gpu::GPUFuncOp gpuFuncOp, OpAdaptor adaptor,
});
}
- // Create the new function operation. Only copy those attributes that are
- // not specific to function modeling.
- SmallVector<NamedAttribute, 4> attributes;
- ArrayAttr argAttrs;
- for (const auto &attr : gpuFuncOp->getAttrs()) {
- if (attr.getName() == SymbolTable::getSymbolAttrName() ||
- attr.getName() == gpuFuncOp.getFunctionTypeAttrName() ||
- attr.getName() ==
- gpu::GPUFuncOp::getNumWorkgroupAttributionsAttrName() ||
- attr.getName() == gpuFuncOp.getWorkgroupAttribAttrsAttrName() ||
- attr.getName() == gpuFuncOp.getPrivateAttribAttrsAttrName() ||
- attr.getName() == gpuFuncOp.getKnownBlockSizeAttrName() ||
- attr.getName() == gpuFuncOp.getKnownGridSizeAttrName() ||
- attr.getName() == gpuFuncOp.getKnownClusterSizeAttrName())
- continue;
- if (attr.getName() == gpuFuncOp.getArgAttrsAttrName()) {
- argAttrs = gpuFuncOp.getArgAttrsAttr();
- continue;
- }
- attributes.push_back(attr);
- }
+ ArrayAttr argAttrs = gpuFuncOp.getArgAttrsAttr();
- DenseI32ArrayAttr knownBlockSize = gpuFuncOp.getKnownBlockSizeAttr();
- DenseI32ArrayAttr knownGridSize = gpuFuncOp.getKnownGridSizeAttr();
- DenseI32ArrayAttr knownClusterSize = gpuFuncOp.getKnownClusterSizeAttr();
- // Ensure we don't lose information if the function is lowered before its
- // surrounding context.
- auto *gpuDialect = cast<gpu::GPUDialect>(gpuFuncOp->getDialect());
- if (knownBlockSize)
- attributes.emplace_back(gpuDialect->getKnownBlockSizeAttrHelper().getName(),
- knownBlockSize);
- if (knownGridSize)
- attributes.emplace_back(gpuDialect->getKnownGridSizeAttrHelper().getName(),
- knownGridSize);
- if (knownClusterSize)
- attributes.emplace_back(
- gpuDialect->getKnownClusterSizeAttrHelper().getName(),
- knownClusterSize);
+ FailureOr<LowerLLVMFuncAttrs> loweredAttrs =
+ buildLoweredGPULLVMFuncAttrs(gpuFuncOp, funcType, rewriter);
+ if (failed(loweredAttrs))
+ return rewriter.notifyMatchFailure(gpuFuncOp,
+ "failed to lower func attributes");
- // Add a dialect specific kernel attribute in addition to GPU kernel
- // attribute. The former is necessary for further translation while the
- // latter is expected by gpu.launch_func.
- if (gpuFuncOp.isKernel()) {
- if (kernelAttributeName)
- attributes.emplace_back(kernelAttributeName, rewriter.getUnitAttr());
- // Set the dialect-specific block size attribute if there is one.
- if (kernelBlockSizeAttributeName && knownBlockSize) {
- attributes.emplace_back(kernelBlockSizeAttributeName, knownBlockSize);
- }
- // Set the dialect-specific cluster size attribute if there is one.
- if (kernelClusterSizeAttributeName && knownClusterSize) {
- attributes.emplace_back(kernelClusterSizeAttributeName, knownClusterSize);
- }
- }
- LLVM::CConv callingConvention = gpuFuncOp.isKernel()
- ? kernelCallingConvention
- : nonKernelCallingConvention;
- auto llvmFuncOp = LLVM::LLVMFuncOp::create(
- rewriter, gpuFuncOp.getLoc(), gpuFuncOp.getName(), funcType,
- LLVM::Linkage::External, /*dsoLocal=*/false, callingConvention,
- /*comdat=*/nullptr, attributes);
+ auto llvmFuncOp = LLVM::LLVMFuncOp::create(rewriter, gpuFuncOp.getLoc(),
+ loweredAttrs->properties,
+ loweredAttrs->discardableAttrs);
{
// Insert operations that correspond to converted workgroup and private
diff --git a/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.h b/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.h
index a3b2e04c35313..7aa1d8da233a4 100644
--- a/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.h
+++ b/mlir/lib/Conversion/GPUCommon/GPUOpsLowering.h
@@ -8,6 +8,7 @@
#ifndef MLIR_CONVERSION_GPUCOMMON_GPUOPSLOWERING_H_
#define MLIR_CONVERSION_GPUCOMMON_GPUOPSLOWERING_H_
+#include "mlir/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.h"
#include "mlir/Conversion/LLVMCommon/Pattern.h"
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
#include "mlir/Dialect/LLVMIR/LLVMAttrs.h"
@@ -106,6 +107,12 @@ struct GPUFuncOpLowering : ConvertOpToLLVMPattern<gpu::GPUFuncOp> {
matchAndRewrite(gpu::GPUFuncOp gpuFuncOp, OpAdaptor adaptor,
ConversionPatternRewriter &rewriter) const override;
+ /// Lower discardable attrs like `func` lowering, then set `llvm.func`
+ /// properties and append GPU / target-specific discardable metadata.
+ FailureOr<LowerLLVMFuncAttrs>
+ buildLoweredGPULLVMFuncAttrs(gpu::GPUFuncOp gpuFuncOp, Type llvmFuncType,
+ OpBuilder &rewriter) const;
+
private:
/// The address space to use for `alloca`s in private memory.
unsigned allocaAddrSpace;
diff --git a/mlir/lib/Conversion/LLVMCommon/CMakeLists.txt b/mlir/lib/Conversion/LLVMCommon/CMakeLists.txt
index 568d9339aaabc..77f5013764d96 100644
--- a/mlir/lib/Conversion/LLVMCommon/CMakeLists.txt
+++ b/mlir/lib/Conversion/LLVMCommon/CMakeLists.txt
@@ -1,5 +1,6 @@
add_mlir_conversion_library(MLIRLLVMCommonConversion
ConversionTarget.cpp
+ LowerFunctionAttrsToLLVM.cpp
LoweringOptions.cpp
MemRefBuilder.cpp
Pattern.cpp
diff --git a/mlir/lib/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.cpp b/mlir/lib/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.cpp
new file mode 100644
index 0000000000000..eee7a96b369fd
--- /dev/null
+++ b/mlir/lib/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.cpp
@@ -0,0 +1,56 @@
+//===- LowerFunctionAttrsToLLVM.cpp - Lower func attrs to llvm.func -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/Support/DebugLog.h"
+
+using namespace mlir;
+
+#define DEBUG_TYPE "lower-function-attrs-to-llvm"
+
+FailureOr<LowerLLVMFuncAttrs>
+mlir::lowerDiscardableAttrsForLLVMFunc(FunctionOpInterface func) {
+ MLIRContext *ctx = func->getContext();
+ LowerLLVMFuncAttrs lowered;
+
+ llvm::SmallDenseSet<StringRef> odsAttrNames(
+ LLVM::LLVMFuncOp::getAttributeNames().begin(),
+ LLVM::LLVMFuncOp::getAttributeNames().end());
+
+ NamedAttrList inherentAttrs;
+
+ for (const NamedAttribute &attr : func->getDiscardableAttrs()) {
+ StringRef attrName = attr.getName().strref();
+
+ if (odsAttrNames.contains(attrName)) {
+ LDBG() << "LLVM specific attributes: " << attrName
+ << "should use llvm.* prefix, discarding it";
+ continue;
+ }
+
+ StringRef inherent = attrName;
+ if (inherent.consume_front("llvm.") && odsAttrNames.contains(inherent))
+ inherentAttrs.set(inherent, attr.getValue()); // collect inherent attrs
+ else
+ lowered.discardableAttrs.push_back(attr);
+ }
+
+ // Convert collected inherent attrs into typed properties.
+ if (!inherentAttrs.empty()) {
+ DictionaryAttr dict = inherentAttrs.getDictionary(ctx);
+ auto emitError = [&] {
+ return func.emitOpError("invalid llvm.func property");
+ };
+ if (failed(LLVM::LLVMFuncOp::setPropertiesFromAttr(lowered.properties, dict,
+ emitError))) {
+ return failure();
+ }
+ }
+ return lowered;
+}
More information about the Mlir-commits
mailing list