From 8f493874115f37e7066b0d9fe5213ce47d22cf50 Mon Sep 17 00:00:00 2001 From: makslevental Date: Sat, 27 Jun 2026 18:39:48 -0700 Subject: [PATCH] [eudsl-python-extras] Disallow gpu.func external declarations gpu.func requires at least one body block per MLIR semantics, so external declarations (empty bodies) are invalid. Raise ValueError early when gpu.func detects a declaration, instead of letting it fail at verification. --- .../mlir/extras/dialects/gpu.py | 4 ++ .../tests/dialect/test_gpu.py | 48 +++++++++++++++---- 2 files changed, 42 insertions(+), 10 deletions(-) diff --git a/projects/eudsl-python-extras/mlir/extras/dialects/gpu.py b/projects/eudsl-python-extras/mlir/extras/dialects/gpu.py index 7309493e..180f8027 100644 --- a/projects/eudsl-python-extras/mlir/extras/dialects/gpu.py +++ b/projects/eudsl-python-extras/mlir/extras/dialects/gpu.py @@ -463,6 +463,10 @@ def func( ip=ip, ) func_.__name__ = f.__name__ + if func_._is_decl(): + raise ValueError( + "gpu.func does not support external declarations (body must not be empty)" + ) if emit: func_.emit() if emit_grid: diff --git a/projects/eudsl-python-extras/tests/dialect/test_gpu.py b/projects/eudsl-python-extras/tests/dialect/test_gpu.py index d6d5fed4..0cfbb6ce 100644 --- a/projects/eudsl-python-extras/tests/dialect/test_gpu.py +++ b/projects/eudsl-python-extras/tests/dialect/test_gpu.py @@ -1583,10 +1583,6 @@ def main(): ctx.module.operation.verify() -@pytest.mark.xfail( - reason="gpu.func emit inside gpu.module via region_op fails verification; " - "existing test_grid_qualname_and_call works but only with int sizes" -) def test_gpu_func_call_with_value_sizes(ctx: MLIRContext): """Branch 391->390: GPUFunc.__call__ with Value grid/block sizes""" from mlir.extras.dialects.arith import constant @@ -1594,16 +1590,13 @@ def test_gpu_func_call_with_value_sizes(ctx: MLIRContext): set_container_module(ctx.module) - @gpu.func(emit_grid=True) - @canonicalize(using=scf.canonicalizer) + @gpu.func def kernel(a: T.memref(4, 4, T.f32())): - return - - kernel.qualname = "MyModule" + x = a[0, 0] @module("MyModule", ["#nvvm.target"]) def gpu_mod(): - kernel.func.emit() + kernel.emit() mem = memref.alloc([4, 4], T.f32()) gx = constant(1, T.index()) @@ -1617,6 +1610,41 @@ def gpu_mod(): ctx.module.operation.verify() +def test_gpu_func_external_decl_raises(ctx: MLIRContext): + """gpu.func does not support external declarations""" + with pytest.raises( + ValueError, match="gpu.func does not support external declarations" + ): + + @gpu.func + def kernel(a: T.memref(4, 4, T.f32())): ... + + +def test_gpu_func_external_decl_in_gpu_module_raises(): + """gpu.func external decl inside gpu.module also raises""" + from mlir.ir import Context, Location, Module, InsertionPoint + + with Context(): + with Location.unknown(): + module = Module.create() + with InsertionPoint(module.body): + with pytest.raises( + ValueError, + match="gpu.func does not support external declarations", + ): + + class MyModule( + metaclass=GPUModuleMeta, targets=["#nvvm.target"] + ): + + @gpu.func + def kernel(a: T.memref(4, 4, T.f32())): ... + + # GPUModuleMeta.__prepare__ enters an InsertionPoint that + # never exits when the class body raises; pop it manually. + InsertionPoint.current.__exit__(None, None, None) + + def test_launch_with_async_dependencies(ctx: MLIRContext): """Branch 301->303: LaunchOp with explicit async_dependencies""" from mlir.extras.dialects.gpu import launch