[Mlir-commits] [mlir] [mlir][gpu] Make launch_func op use SymbolUserOpInterface (PR #173277)
lonely eagle
llvmlistbot at llvm.org
Sat Feb 28 02:55:55 PST 2026
https://github.com/linuxlonelyeagle updated https://github.com/llvm/llvm-project/pull/173277
>From 6ecf071db0189d3c849d80d3c4a16b5730b252b8 Mon Sep 17 00:00:00 2001
From: linuxlonelyeagle <2020382038 at qq.com>
Date: Thu, 18 Dec 2025 05:20:23 +0000
Subject: [PATCH 1/3] make launch_func use SymbolUserOpInterface.
---
mlir/include/mlir/Dialect/GPU/IR/GPUOps.td | 3 +-
mlir/lib/Dialect/GPU/IR/GPUDialect.cpp | 156 +++++++++++----------
2 files changed, 81 insertions(+), 78 deletions(-)
diff --git a/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td b/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
index 6b0fd1ed9080e..9174384333417 100644
--- a/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
+++ b/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
@@ -619,7 +619,8 @@ def LaunchIndx : AnyTypeOf<[Index, I32, I64]>;
def GPU_LaunchFuncOp :GPU_Op<"launch_func", [
GPU_AsyncOpInterface, AttrSizedOperandSegments,
AllTypesMatch<["gridSizeX", "gridSizeY", "gridSizeZ", "blockSizeX",
- "blockSizeY", "blockSizeZ"]>]>,
+ "blockSizeY", "blockSizeZ"]>,
+ DeclareOpInterfaceMethods<SymbolUserOpInterface>]>,
Arguments<(ins Variadic<GPU_AsyncToken>:$asyncDependencies,
SymbolRefAttr:$kernel,
LaunchIndx:$gridSizeX,
diff --git a/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp b/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
index a66a83b7e3ca1..6d3f3f1b9dda4 100644
--- a/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
+++ b/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
@@ -408,83 +408,7 @@ LogicalResult GPUDialect::verifyOperationAttribute(Operation *op,
return op->emitError("expected '")
<< getContainerModuleAttrName() << "' attribute to be attached to '"
<< ModuleOp::getOperationName() << '\'';
-
- auto walkResult = module.walk([&module](LaunchFuncOp launchOp) -> WalkResult {
- // Ignore launches that are nested more or less deep than functions in the
- // module we are currently checking.
- if (!launchOp->getParentOp() ||
- launchOp->getParentOp()->getParentOp() != module)
- return success();
-
- // Ignore launch ops with missing attributes here. The errors will be
- // reported by the verifiers of those ops.
- if (!launchOp->getAttrOfType<SymbolRefAttr>(
- LaunchFuncOp::getKernelAttrName(launchOp->getName())))
- return success();
-
- // Check that `launch_func` refers to a well-formed GPU kernel container.
- StringAttr kernelContainerName = launchOp.getKernelModuleName();
- Operation *kernelContainer = module.lookupSymbol(kernelContainerName);
- if (!kernelContainer)
- return launchOp.emitOpError()
- << "kernel container '" << kernelContainerName.getValue()
- << "' is undefined";
-
- // If the container is a GPU binary op return success.
- if (isa<BinaryOp>(kernelContainer))
- return success();
-
- auto kernelModule = dyn_cast<GPUModuleOp>(kernelContainer);
- if (!kernelModule)
- return launchOp.emitOpError()
- << "kernel module '" << kernelContainerName.getValue()
- << "' is undefined";
-
- // Check that `launch_func` refers to a well-formed kernel function.
- Operation *kernelFunc = module.lookupSymbol(launchOp.getKernelAttr());
- if (!kernelFunc)
- return launchOp.emitOpError("kernel function '")
- << launchOp.getKernel() << "' is undefined";
- auto kernelConvertedFunction = dyn_cast<FunctionOpInterface>(kernelFunc);
- if (!kernelConvertedFunction) {
- InFlightDiagnostic diag = launchOp.emitOpError()
- << "referenced kernel '" << launchOp.getKernel()
- << "' is not a function";
- diag.attachNote(kernelFunc->getLoc()) << "see the kernel definition here";
- return diag;
- }
-
- if (!kernelFunc->getAttrOfType<mlir::UnitAttr>(
- GPUDialect::getKernelFuncAttrName()))
- return launchOp.emitOpError("kernel function is missing the '")
- << GPUDialect::getKernelFuncAttrName() << "' attribute";
-
- // TODO: If the kernel isn't a GPU function (which happens during separate
- // compilation), do not check type correspondence as it would require the
- // verifier to be aware of the type conversion.
- auto kernelGPUFunction = dyn_cast<gpu::GPUFuncOp>(kernelFunc);
- if (!kernelGPUFunction)
- return success();
-
- unsigned actualNumArguments = launchOp.getNumKernelOperands();
- unsigned expectedNumArguments = kernelGPUFunction.getNumArguments();
- if (expectedNumArguments != actualNumArguments)
- return launchOp.emitOpError("got ")
- << actualNumArguments << " kernel operands but expected "
- << expectedNumArguments;
-
- auto functionType = kernelGPUFunction.getFunctionType();
- for (unsigned i = 0; i < expectedNumArguments; ++i) {
- if (launchOp.getKernelOperand(i).getType() != functionType.getInput(i)) {
- return launchOp.emitOpError("type of function argument ")
- << i << " does not match";
- }
- }
-
- return success();
- });
-
- return walkResult.wasInterrupted() ? failure() : success();
+ return success();
}
/// Parses an optional list of async operands with an optional leading keyword.
@@ -1396,6 +1320,84 @@ LogicalResult LaunchFuncOp::verify() {
return success();
}
+LogicalResult
+LaunchFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
+ LaunchFuncOp launchOp = *this;
+ ModuleOp module = (*this)->getParentOfType<ModuleOp>();
+ // Ignore launches that are nested more or less deep than functions in the
+ // module we are currently checking.
+ if (!launchOp->getParentOp() ||
+ launchOp->getParentOp()->getParentOp() != module)
+ return success();
+
+ // Ignore launch ops with missing attributes here. The errors will be
+ // reported by the verifiers of those ops.
+ if (!launchOp->getAttrOfType<SymbolRefAttr>(
+ LaunchFuncOp::getKernelAttrName(launchOp->getName())))
+ return success();
+
+ // Check that `launch_func` refers to a well-formed GPU kernel container.
+ StringAttr kernelContainerName = launchOp.getKernelModuleName();
+ Operation *kernelContainer = module.lookupSymbol(kernelContainerName);
+ if (!kernelContainer)
+ return launchOp.emitOpError()
+ << "kernel container '" << kernelContainerName.getValue()
+ << "' is undefined";
+
+ // If the container is a GPU binary op return success.
+ if (isa<BinaryOp>(kernelContainer))
+ return success();
+
+ auto kernelModule = dyn_cast<GPUModuleOp>(kernelContainer);
+ if (!kernelModule)
+ return launchOp.emitOpError()
+ << "kernel module '" << kernelContainerName.getValue()
+ << "' is undefined";
+
+ // Check that `launch_func` refers to a well-formed kernel function.
+ Operation *kernelFunc = module.lookupSymbol(launchOp.getKernelAttr());
+ if (!kernelFunc)
+ return launchOp.emitOpError("kernel function '")
+ << launchOp.getKernel() << "' is undefined";
+ auto kernelConvertedFunction = dyn_cast<FunctionOpInterface>(kernelFunc);
+ if (!kernelConvertedFunction) {
+ InFlightDiagnostic diag = launchOp.emitOpError()
+ << "referenced kernel '" << launchOp.getKernel()
+ << "' is not a function";
+ diag.attachNote(kernelFunc->getLoc()) << "see the kernel definition here";
+ return diag;
+ }
+
+ if (!kernelFunc->getAttrOfType<mlir::UnitAttr>(
+ GPUDialect::getKernelFuncAttrName()))
+ return launchOp.emitOpError("kernel function is missing the '")
+ << GPUDialect::getKernelFuncAttrName() << "' attribute";
+
+ // TODO: If the kernel isn't a GPU function (which happens during separate
+ // compilation), do not check type correspondence as it would require the
+ // verifier to be aware of the type conversion.
+ auto kernelGPUFunction = dyn_cast<gpu::GPUFuncOp>(kernelFunc);
+ if (!kernelGPUFunction)
+ return success();
+
+ unsigned actualNumArguments = launchOp.getNumKernelOperands();
+ unsigned expectedNumArguments = kernelGPUFunction.getNumArguments();
+ if (expectedNumArguments != actualNumArguments)
+ return launchOp.emitOpError("got ")
+ << actualNumArguments << " kernel operands but expected "
+ << expectedNumArguments;
+
+ auto functionType = kernelGPUFunction.getFunctionType();
+ for (unsigned i = 0; i < expectedNumArguments; ++i) {
+ if (launchOp.getKernelOperand(i).getType() != functionType.getInput(i)) {
+ return launchOp.emitOpError("type of function argument ")
+ << i << " does not match";
+ }
+ }
+
+ return success();
+}
+
static ParseResult
parseLaunchDimType(OpAsmParser &parser, Type &dimTy,
std::optional<OpAsmParser::UnresolvedOperand> clusterValue,
>From fd9b43a50e412855324652580c2d408a35d49c50 Mon Sep 17 00:00:00 2001
From: linuxlonelyeagle <2020382038 at qq.com>
Date: Mon, 22 Dec 2025 16:08:33 +0000
Subject: [PATCH 2/3] use clang-format and fix test.
---
mlir/include/mlir/Dialect/GPU/IR/GPUOps.td | 4 ++--
mlir/lib/Dialect/GPU/IR/GPUDialect.cpp | 6 ++++--
mlir/test/Dialect/GPU/invalid.mlir | 4 ++--
3 files changed, 8 insertions(+), 6 deletions(-)
diff --git a/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td b/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
index 9174384333417..b5a9e3413ddfd 100644
--- a/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
+++ b/mlir/include/mlir/Dialect/GPU/IR/GPUOps.td
@@ -618,9 +618,9 @@ def LaunchIndx : AnyTypeOf<[Index, I32, I64]>;
def GPU_LaunchFuncOp :GPU_Op<"launch_func", [
GPU_AsyncOpInterface, AttrSizedOperandSegments,
+ DeclareOpInterfaceMethods<SymbolUserOpInterface>,
AllTypesMatch<["gridSizeX", "gridSizeY", "gridSizeZ", "blockSizeX",
- "blockSizeY", "blockSizeZ"]>,
- DeclareOpInterfaceMethods<SymbolUserOpInterface>]>,
+ "blockSizeY", "blockSizeZ"]>]>,
Arguments<(ins Variadic<GPU_AsyncToken>:$asyncDependencies,
SymbolRefAttr:$kernel,
LaunchIndx:$gridSizeX,
diff --git a/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp b/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
index 6d3f3f1b9dda4..8eada213e6033 100644
--- a/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
+++ b/mlir/lib/Dialect/GPU/IR/GPUDialect.cpp
@@ -1338,7 +1338,8 @@ LaunchFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
// Check that `launch_func` refers to a well-formed GPU kernel container.
StringAttr kernelContainerName = launchOp.getKernelModuleName();
- Operation *kernelContainer = module.lookupSymbol(kernelContainerName);
+ Operation *kernelContainer =
+ symbolTable.lookupNearestSymbolFrom(module, kernelContainerName);
if (!kernelContainer)
return launchOp.emitOpError()
<< "kernel container '" << kernelContainerName.getValue()
@@ -1355,7 +1356,8 @@ LaunchFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {
<< "' is undefined";
// Check that `launch_func` refers to a well-formed kernel function.
- Operation *kernelFunc = module.lookupSymbol(launchOp.getKernelAttr());
+ Operation *kernelFunc =
+ symbolTable.lookupNearestSymbolFrom(module, launchOp.getKernelAttr());
if (!kernelFunc)
return launchOp.emitOpError("kernel function '")
<< launchOp.getKernel() << "' is undefined";
diff --git a/mlir/test/Dialect/GPU/invalid.mlir b/mlir/test/Dialect/GPU/invalid.mlir
index 20fe50469e0e4..1fbfcb92ad709 100644
--- a/mlir/test/Dialect/GPU/invalid.mlir
+++ b/mlir/test/Dialect/GPU/invalid.mlir
@@ -191,14 +191,14 @@ module attributes {gpu.container_module} {
// -----
module attributes {gpu.container_module} {
- module @kernels {
+ gpu.module @kernels_container {
gpu.func @kernel_1(%arg1 : !llvm.ptr) kernel {
gpu.return
}
}
func.func @launch_func_missing_kernel_attr(%sz : index, %arg : !llvm.ptr) {
- // expected-error at +1 {{kernel module 'kernels' is undefined}}
+ // expected-error at +1 {{kernel container 'kernels' is undefined}}
gpu.launch_func @kernels::@kernel_1 blocks in (%sz, %sz, %sz) threads in (%sz, %sz, %sz) args(%arg : !llvm.ptr)
return
}
>From b517e4a561a6da1e2a77940cce7ecee3d7d444d1 Mon Sep 17 00:00:00 2001
From: linuxlonelyeagle <2020382038 at qq.com>
Date: Sat, 28 Feb 2026 10:55:38 +0000
Subject: [PATCH 3/3] update test.
---
mlir/test/Dialect/GPU/invalid.mlir | 16 ++++++++++++++++
1 file changed, 16 insertions(+)
diff --git a/mlir/test/Dialect/GPU/invalid.mlir b/mlir/test/Dialect/GPU/invalid.mlir
index 1fbfcb92ad709..b8e160ad8fdd9 100644
--- a/mlir/test/Dialect/GPU/invalid.mlir
+++ b/mlir/test/Dialect/GPU/invalid.mlir
@@ -206,6 +206,22 @@ module attributes {gpu.container_module} {
// -----
+module attributes {gpu.container_module} {
+ module @kernels {
+ // expected-error at +1 {{'gpu.func' op expects parent op 'gpu.module'}}
+ gpu.func @kernel_1(%arg1 : !llvm.ptr) kernel {
+ gpu.return
+ }
+ }
+
+ func.func @launch_func_missing_kernel_attr(%sz : index, %arg : !llvm.ptr) {
+ gpu.launch_func @kernels::@kernel_1 blocks in (%sz, %sz, %sz) threads in (%sz, %sz, %sz) args(%arg : !llvm.ptr)
+ return
+ }
+}
+
+// -----
+
module attributes {gpu.container_module} {
gpu.module @kernels {
gpu.func @kernel_1(%arg1 : !llvm.ptr) {
More information about the Mlir-commits
mailing list