[Mlir-commits] [mlir] [mlir][python] Add bindings for OpenACC dialect (PR #163620)

Asher Mancinelli llvmlistbot at llvm.org
Wed Oct 15 14:15:32 PDT 2025


https://github.com/ashermancinelli updated https://github.com/llvm/llvm-project/pull/163620

>From 3c4f715415b73fa06bb2878ee9b8d3efe6b0e398 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Wed, 15 Oct 2025 10:48:42 -0700
Subject: [PATCH 1/4] [mlir][python] Add bindings for OpenACC dialect

---
 mlir/python/CMakeLists.txt              |  9 +++++++++
 mlir/python/mlir/dialects/OpenACCOps.td | 14 ++++++++++++++
 mlir/python/mlir/dialects/openacc.py    |  6 ++++++
 mlir/test/python/dialects/openacc.py    | 19 +++++++++++++++++++
 4 files changed, 48 insertions(+)
 create mode 100644 mlir/python/mlir/dialects/OpenACCOps.td
 create mode 100644 mlir/python/mlir/dialects/openacc.py
 create mode 100644 mlir/test/python/dialects/openacc.py

diff --git a/mlir/python/CMakeLists.txt b/mlir/python/CMakeLists.txt
index 9f5246de6bda0..c643d32e22174 100644
--- a/mlir/python/CMakeLists.txt
+++ b/mlir/python/CMakeLists.txt
@@ -134,6 +134,15 @@ declare_mlir_dialect_python_bindings(
     dialects/func.py
   DIALECT_NAME func)
 
+declare_mlir_dialect_python_bindings(
+  ADD_TO_PARENT MLIRPythonSources.Dialects
+  ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mlir"
+  TD_FILE dialects/OpenACCOps.td
+  SOURCES
+    dialects/openacc.py
+  DIALECT_NAME acc
+  DEPENDS acc_common_td)
+
 declare_mlir_dialect_python_bindings(
   ADD_TO_PARENT MLIRPythonSources.Dialects
   ROOT_DIR "${CMAKE_CURRENT_SOURCE_DIR}/mlir"
diff --git a/mlir/python/mlir/dialects/OpenACCOps.td b/mlir/python/mlir/dialects/OpenACCOps.td
new file mode 100644
index 0000000000000..69a3002e73b81
--- /dev/null
+++ b/mlir/python/mlir/dialects/OpenACCOps.td
@@ -0,0 +1,14 @@
+//===-- OpenACCOps.td - Entry point for OpenACCOps bind ------------*- tablegen -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef PYTHON_BINDINGS_OPENACC_OPS
+#define PYTHON_BINDINGS_OPENACC_OPS
+
+include "mlir/Dialect/OpenACC/OpenACCOps.td"
+
+#endif
diff --git a/mlir/python/mlir/dialects/openacc.py b/mlir/python/mlir/dialects/openacc.py
new file mode 100644
index 0000000000000..e06830a9c48f3
--- /dev/null
+++ b/mlir/python/mlir/dialects/openacc.py
@@ -0,0 +1,6 @@
+#  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
+
+from ._acc_ops_gen import *
+
diff --git a/mlir/test/python/dialects/openacc.py b/mlir/test/python/dialects/openacc.py
new file mode 100644
index 0000000000000..3e67c3deab75d
--- /dev/null
+++ b/mlir/test/python/dialects/openacc.py
@@ -0,0 +1,19 @@
+from mlir.ir import *
+from mlir.dialects import openacc
+
+def run(f):
+    print("\nTEST:", f.__name__)
+    with Context(), Location.unknown():
+        f()
+    return f
+
+ at run
+def testOpenACCKernel():
+    module = Module.create()
+    with InsertionPoint(module.body):
+        openacc.KernelOp(
+            openacc.KernelType.parallel,
+            openacc.KernelModifier.seq,
+            openacc.KernelModifier.seq,
+        )
+    print(module)

>From 9b99be31db4c3a347caff06838900160df6ed862 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Wed, 15 Oct 2025 12:38:36 -0700
Subject: [PATCH 2/4] Add tests

---
 mlir/test/python/dialects/openacc.py | 135 +++++++++++++++++++++++++--
 1 file changed, 127 insertions(+), 8 deletions(-)

diff --git a/mlir/test/python/dialects/openacc.py b/mlir/test/python/dialects/openacc.py
index 3e67c3deab75d..bd607febe21cc 100644
--- a/mlir/test/python/dialects/openacc.py
+++ b/mlir/test/python/dialects/openacc.py
@@ -1,19 +1,138 @@
-from mlir.ir import *
-from mlir.dialects import openacc
+# RUN: python %s | FileCheck %s
+from mlir.ir import (
+    Context,
+    FunctionType,
+    Location,
+    Module,
+    InsertionPoint,
+    IntegerType,
+    IndexType,
+    MemRefType,
+    F32Type,
+    Block,
+    ArrayAttr,
+    Attribute,
+    UnitAttr,
+    StringAttr,
+    DenseI32ArrayAttr,
+    ShapedType,
+)
+from mlir.dialects import openacc, func, arith, memref
+
 
 def run(f):
-    print("\nTEST:", f.__name__)
+    print("\n// TEST:", f.__name__)
     with Context(), Location.unknown():
         f()
     return f
 
+
 @run
-def testOpenACCKernel():
+def testManualReconstructedKernel():
     module = Module.create()
+
+    # Add required module attributes
+    module.operation.attributes["dlti.dl_spec"] = Attribute.parse("#dlti.dl_spec<>")
+    module.operation.attributes["gpu.container_module"] = UnitAttr.get()
+
+    i32 = IntegerType.get_signless(32)
+    i64 = IntegerType.get_signless(64)
+    f32 = F32Type.get()
+    dynamic = ShapedType.get_dynamic_size()
+    memref_f32_1d_any = MemRefType.get([dynamic], f32)
+
     with InsertionPoint(module.body):
-        openacc.KernelOp(
-            openacc.KernelType.parallel,
-            openacc.KernelModifier.seq,
-            openacc.KernelModifier.seq,
+        function_type = FunctionType.get(
+            [memref_f32_1d_any, memref_f32_1d_any, i64], []
         )
+        f = func.FuncOp(
+            type=function_type,
+            name="memcpy_idiom",
+        )
+        f.attributes["sym_visibility"] = StringAttr.get("public")
+
+    with InsertionPoint(f.add_entry_block()):
+        c1024 = arith.ConstantOp(i32, 1024)
+        c128 = arith.ConstantOp(i32, 128)
+
+        parallel_op = openacc.ParallelOp(
+            asyncOperands=[],
+            waitOperands=[],
+            numGangs=[c1024],
+            numWorkers=[],
+            vectorLength=[c128],
+            reductionOperands=[],
+            privateOperands=[],
+            firstprivateOperands=[],
+            dataClauseOperands=[],
+        )
+
+        # Set required device_type and segment attributes to satisfy verifier
+        acc_device_none = ArrayAttr.get([Attribute.parse("#acc.device_type<none>")])
+        parallel_op.numGangsDeviceType = acc_device_none
+        parallel_op.numGangsSegments = DenseI32ArrayAttr.get([1])
+        parallel_op.vectorLengthDeviceType = acc_device_none
+
+        parallel_block = Block.create_at_start(parent=parallel_op.region, arg_types=[])
+
+        with InsertionPoint(parallel_block):
+            c0 = arith.ConstantOp(i64, 0)
+            c1 = arith.ConstantOp(i64, 1)
+
+            loop_op = openacc.LoopOp(
+                results_=[],
+                lowerbound=[c0],
+                upperbound=[f.arguments[2]],
+                step=[c1],
+                gangOperands=[],
+                workerNumOperands=[],
+                vectorOperands=[],
+                tileOperands=[],
+                cacheOperands=[],
+                privateOperands=[],
+                reductionOperands=[],
+                firstprivateOperands=[],
+            )
+
+            # Set loop attributes: gang and independent on device_type<none>
+            acc_device_none = ArrayAttr.get([Attribute.parse("#acc.device_type<none>")])
+            loop_op.gang = acc_device_none
+            loop_op.independent = acc_device_none
+
+            loop_block = Block.create_at_start(parent=loop_op.region, arg_types=[i64])
+
+            with InsertionPoint(loop_block):
+                idx0 = arith.index_cast(
+                    out=IndexType.get(), in_=loop_block.arguments[0]
+                )
+                val = memref.load(memref=f.arguments[1], indices=[idx0])
+                idx1 = arith.index_cast(
+                    out=IndexType.get(), in_=loop_block.arguments[0]
+                )
+                memref.store(value=val, memref=f.arguments[0], indices=[idx1])
+                openacc.YieldOp([])
+
+            openacc.YieldOp([])
+
+        func.ReturnOp([])
+
     print(module)
+
+    # CHECK-LABEL:   func.func public @memcpy_idiom
+    # CHECK-SAME:    (%[[ARG0:.*]]: memref<?xf32>, %[[ARG1:.*]]: memref<?xf32>, %[[ARG2:.*]]: i64) {
+    # CHECK:           %[[CONSTANT_0:.*]] = arith.constant 1024 : i32
+    # CHECK:           %[[CONSTANT_1:.*]] = arith.constant 128 : i32
+    # CHECK:           acc.parallel num_gangs({%[[CONSTANT_0]] : i32}) vector_length(%[[CONSTANT_1]] : i32) {
+    # CHECK:             %[[CONSTANT_2:.*]] = arith.constant 0 : i64
+    # CHECK:             %[[CONSTANT_3:.*]] = arith.constant 1 : i64
+    # CHECK:             acc.loop gang control(%[[VAL_0:.*]] : i64) = (%[[CONSTANT_2]] : i64) to (%[[ARG2]] : i64)  step (%[[CONSTANT_3]] : i64) {
+    # CHECK:               %[[INDEX_CAST_0:.*]] = arith.index_cast %[[VAL_0]] : i64 to index
+    # CHECK:               %[[LOAD_0:.*]] = memref.load %[[ARG1]][%[[INDEX_CAST_0]]] : memref<?xf32>
+    # CHECK:               %[[INDEX_CAST_1:.*]] = arith.index_cast %[[VAL_0]] : i64 to index
+    # CHECK:               memref.store %[[LOAD_0]], %[[ARG0]][%[[INDEX_CAST_1]]] : memref<?xf32>
+    # CHECK:               acc.yield
+    # CHECK:             }
+    # CHECK:             acc.yield
+    # CHECK:           }
+    # CHECK:           return
+    # CHECK:         }

>From 3a58184392f044f98102c4cfd1c8dcb388204372 Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Wed, 15 Oct 2025 12:46:36 -0700
Subject: [PATCH 3/4] Format

---
 mlir/python/mlir/dialects/openacc.py | 1 -
 1 file changed, 1 deletion(-)

diff --git a/mlir/python/mlir/dialects/openacc.py b/mlir/python/mlir/dialects/openacc.py
index e06830a9c48f3..057f71aed20a6 100644
--- a/mlir/python/mlir/dialects/openacc.py
+++ b/mlir/python/mlir/dialects/openacc.py
@@ -3,4 +3,3 @@
 #  SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 
 from ._acc_ops_gen import *
-

>From 3d3912c723b8473a9d14932e694b381c7fc12cbb Mon Sep 17 00:00:00 2001
From: Asher Mancinelli <ashermancinelli at gmail.com>
Date: Wed, 15 Oct 2025 14:15:13 -0700
Subject: [PATCH 4/4] Clean up test

---
 mlir/test/python/dialects/openacc.py | 26 ++++++++------------------
 1 file changed, 8 insertions(+), 18 deletions(-)

diff --git a/mlir/test/python/dialects/openacc.py b/mlir/test/python/dialects/openacc.py
index bd607febe21cc..0b41a46ce9b47 100644
--- a/mlir/test/python/dialects/openacc.py
+++ b/mlir/test/python/dialects/openacc.py
@@ -31,10 +31,6 @@ def run(f):
 def testManualReconstructedKernel():
     module = Module.create()
 
-    # Add required module attributes
-    module.operation.attributes["dlti.dl_spec"] = Attribute.parse("#dlti.dl_spec<>")
-    module.operation.attributes["gpu.container_module"] = UnitAttr.get()
-
     i32 = IntegerType.get_signless(32)
     i64 = IntegerType.get_signless(64)
     f32 = F32Type.get()
@@ -102,14 +98,9 @@ def testManualReconstructedKernel():
             loop_block = Block.create_at_start(parent=loop_op.region, arg_types=[i64])
 
             with InsertionPoint(loop_block):
-                idx0 = arith.index_cast(
-                    out=IndexType.get(), in_=loop_block.arguments[0]
-                )
-                val = memref.load(memref=f.arguments[1], indices=[idx0])
-                idx1 = arith.index_cast(
-                    out=IndexType.get(), in_=loop_block.arguments[0]
-                )
-                memref.store(value=val, memref=f.arguments[0], indices=[idx1])
+                idx = arith.index_cast(out=IndexType.get(), in_=loop_block.arguments[0])
+                val = memref.load(memref=f.arguments[1], indices=[idx])
+                memref.store(value=val, memref=f.arguments[0], indices=[idx])
                 openacc.YieldOp([])
 
             openacc.YieldOp([])
@@ -118,8 +109,8 @@ def testManualReconstructedKernel():
 
     print(module)
 
-    # CHECK-LABEL:   func.func public @memcpy_idiom
-    # CHECK-SAME:    (%[[ARG0:.*]]: memref<?xf32>, %[[ARG1:.*]]: memref<?xf32>, %[[ARG2:.*]]: i64) {
+    # CHECK-LABEL:   func.func public @memcpy_idiom(
+    # CHECK-SAME:      %[[ARG0:.*]]: memref<?xf32>, %[[ARG1:.*]]: memref<?xf32>, %[[ARG2:.*]]: i64) {
     # CHECK:           %[[CONSTANT_0:.*]] = arith.constant 1024 : i32
     # CHECK:           %[[CONSTANT_1:.*]] = arith.constant 128 : i32
     # CHECK:           acc.parallel num_gangs({%[[CONSTANT_0]] : i32}) vector_length(%[[CONSTANT_1]] : i32) {
@@ -127,11 +118,10 @@ def testManualReconstructedKernel():
     # CHECK:             %[[CONSTANT_3:.*]] = arith.constant 1 : i64
     # CHECK:             acc.loop gang control(%[[VAL_0:.*]] : i64) = (%[[CONSTANT_2]] : i64) to (%[[ARG2]] : i64)  step (%[[CONSTANT_3]] : i64) {
     # CHECK:               %[[INDEX_CAST_0:.*]] = arith.index_cast %[[VAL_0]] : i64 to index
-    # CHECK:               %[[LOAD_0:.*]] = memref.load %[[ARG1]][%[[INDEX_CAST_0]]] : memref<?xf32>
-    # CHECK:               %[[INDEX_CAST_1:.*]] = arith.index_cast %[[VAL_0]] : i64 to index
-    # CHECK:               memref.store %[[LOAD_0]], %[[ARG0]][%[[INDEX_CAST_1]]] : memref<?xf32>
+    # CHECK:               %[[LOAD_0:.*]] = memref.load %[[ARG1]]{{\[}}%[[INDEX_CAST_0]]] : memref<?xf32>
+    # CHECK:               memref.store %[[LOAD_0]], %[[ARG0]]{{\[}}%[[INDEX_CAST_0]]] : memref<?xf32>
     # CHECK:               acc.yield
-    # CHECK:             }
+    # CHECK:             } attributes {independent = [#acc.device_type<none>]}
     # CHECK:             acc.yield
     # CHECK:           }
     # CHECK:           return



More information about the Mlir-commits mailing list