[Mlir-commits] [mlir] [mlir][GPU] Refactor GPUOps lowering (PR #188905)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Mar 26 21:07:47 PDT 2026


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir-gpu

Author: Hocky Yudhiono (hockyy)

<details>
<summary>Changes</summary>

Refactors `gpu.func` to `llvm.func` lowering to reuse the same discardable-attribute path as `func.func` to `llvm.func`, moves that shared logic into LLVMCommon, and keeps GPU-specific metadata explicit.



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


6 Files Affected:

- (added) mlir/include/mlir/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.h (+39) 
- (modified) mlir/lib/Conversion/FuncToLLVM/FuncToLLVM.cpp (+3-50) 
- (modified) mlir/lib/Conversion/GPUCommon/GPUOpsLowering.cpp (+73-59) 
- (modified) mlir/lib/Conversion/GPUCommon/GPUOpsLowering.h (+7) 
- (modified) mlir/lib/Conversion/LLVMCommon/CMakeLists.txt (+1) 
- (added) mlir/lib/Conversion/LLVMCommon/LowerFunctionAttrsToLLVM.cpp (+56) 


``````````diff
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;
+}

``````````

</details>


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


More information about the Mlir-commits mailing list