[Mlir-commits] [mlir] [mlir][acc] Flag the data region of a structured declare for the runtime (PR #234822)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Oct 22 20:00:55 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir-openacc

Author: Zhen Wang (wangzpgi)

<details>
<summary>Changes</summary>

A structured `acc.declare_enter` / `acc.declare_exit` pair lowers to the same `__tgt_acc_data_begin` / `__tgt_acc_data_end` entry points as `acc.data`, with the region flags set to `None`. The runtime cannot tell the two apart, yet a declare of a device pointer in a local scope has to keep a registration that a plain `deviceptr` mapping does not need.

Add `ACCDataRegionFlags::Declare` and set it on the begin and end calls of a structured declare. Unstructured declares still go through `__tgt_acc_declare`, and the declare-action recipes through `__tgt_acc_mirror_alloc` / `__tgt_acc_mirror_dealloc`, so they are unchanged. A post-dealloc recipe's `data_end` holds no token and keeps `None`.

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


3 Files Affected:

- (modified) mlir/include/mlir/Conversion/OpenACCToLLVM/ACCDataRuntime.h (+3) 
- (modified) mlir/lib/Conversion/OpenACCToLLVM/ACCDataDirectivePatterns.cpp (+17-7) 
- (modified) mlir/test/Conversion/OpenACCToLLVM/declare.mlir (+31-5) 


``````````diff
diff --git a/mlir/include/mlir/Conversion/OpenACCToLLVM/ACCDataRuntime.h b/mlir/include/mlir/Conversion/OpenACCToLLVM/ACCDataRuntime.h
index 8fdb4cb9d3ebc6..c3af08e9d37a5e 100644
--- a/mlir/include/mlir/Conversion/OpenACCToLLVM/ACCDataRuntime.h
+++ b/mlir/include/mlir/Conversion/OpenACCToLLVM/ACCDataRuntime.h
@@ -86,6 +86,9 @@ enum class ACCDataRegionFlags : int64_t {
   None = 0,
   /// The implicit data region of a compute construct.
   Implicit = 1,
+  /// The region of a structured declare directive in a local scope, which
+  /// lasts until that scope ends.
+  Declare = 2,
 };
 
 /// What a data runtime call is asked for besides mapping its operands.
diff --git a/mlir/lib/Conversion/OpenACCToLLVM/ACCDataDirectivePatterns.cpp b/mlir/lib/Conversion/OpenACCToLLVM/ACCDataDirectivePatterns.cpp
index a895a97bb8dac4..a59b81d8acb1f9 100644
--- a/mlir/lib/Conversion/OpenACCToLLVM/ACCDataDirectivePatterns.cpp
+++ b/mlir/lib/Conversion/OpenACCToLLVM/ACCDataDirectivePatterns.cpp
@@ -32,15 +32,18 @@ using namespace mlir::acc;
 
 /// Emits the call to the mapping entry point \p fn for \p mappingOperands, the
 /// data-clause operands of a data construct, paired with their type converted
-/// values in \p convertedOperands.
+/// values in \p convertedOperands. \p regionFlags describe the data region
+/// the call opens or closes.
 static LogicalResult emitDataRuntimeCall(
     Location loc, RuntimeFunction fn, ValueRange mappingOperands,
     ValueRange convertedOperands, ACCDataCallKind callKind,
     ConversionPatternRewriter &rewriter, OpenACCSupport &accSupport,
     Region &globalSymbolRegion, SymbolTable &symbolTable,
-    const ACCRuntimeCallConfig &config, ArrayRef<Value> trailingArguments) {
+    const ACCRuntimeCallConfig &config, ArrayRef<Value> trailingArguments,
+    ACCDataRegionFlags regionFlags = ACCDataRegionFlags::None) {
   ACCDataCallOptions options;
   options.callKind = callKind;
+  options.flags = static_cast<int64_t>(regionFlags);
   return emitACCDataRuntimeCall(
       loc, fn, mappingOperands, convertedOperands, rewriter, accSupport,
       globalSymbolRegion, symbolTable, config, trailingArguments, options);
@@ -192,8 +195,9 @@ using UpdateOpLowering =
                         ACCDataCallKind::DataEnter>;
 
 /// Structured `acc.declare_enter` (token used by a matching exit) maps like
-/// `acc.data` enter. In a declare-action recipe the object the directive
-/// names is allocated by the host, so only the device mirror of it is
+/// `acc.data` enter, with the region flags telling the runtime that a declare
+/// directive opened the region. In a declare-action recipe the object the
+/// directive names is allocated by the host, so only the device mirror of it is
 /// allocated here. An unstructured enter registers the objects it names with
 /// `__tgt_acc_declare`.
 struct DeclareEnterOpLowering : public ConvertOpToLLVMPattern<DeclareEnterOp> {
@@ -224,7 +228,8 @@ struct DeclareEnterOpLowering : public ConvertOpToLLVMPattern<DeclareEnterOp> {
       emitted = emitDataRuntimeCall(
           loc, RuntimeFunction::ACCRTL_tgt_acc_data_begin, mappingOperands,
           convertedOperands, ACCDataCallKind::DataEnter, rewriter, accSupport,
-          globalSymbolRegion, symbolTable, config, {asyncQueue});
+          globalSymbolRegion, symbolTable, config, {asyncQueue},
+          ACCDataRegionFlags::Declare);
     } else {
       Value binaryDescriptor =
           config.createDeclareBinaryDescriptor(loc, rewriter);
@@ -256,7 +261,9 @@ struct DeclareEnterOpLowering : public ConvertOpToLLVMPattern<DeclareEnterOp> {
 
 /// A recipe that runs before the host object is deallocated frees the device
 /// mirror of it, as the mapping is torn down once the host storage is gone.
-/// Every other `acc.declare_exit` ends the mapping with `__tgt_acc_data_end`.
+/// Every other `acc.declare_exit` ends the mapping with `__tgt_acc_data_end`;
+/// a structured exit (one holding the token of its enter) carries the declare
+/// region flag, as its enter did.
 struct DeclareExitOpLowering : public ConvertOpToLLVMPattern<DeclareExitOp> {
   DeclareExitOpLowering(const LLVMTypeConverter &converter,
                         OpenACCSupport &accSupport, Region &globalSymbolRegion,
@@ -283,10 +290,13 @@ struct DeclareExitOpLowering : public ConvertOpToLLVMPattern<DeclareExitOp> {
           convertedOperands, ACCDataCallKind::DataEnter, rewriter, accSupport,
           globalSymbolRegion, symbolTable, config, {});
     } else {
+      ACCDataRegionFlags regionFlags = op.getToken()
+                                           ? ACCDataRegionFlags::Declare
+                                           : ACCDataRegionFlags::None;
       emitted = emitDataRuntimeCall(
           loc, RuntimeFunction::ACCRTL_tgt_acc_data_end, mappingOperands,
           convertedOperands, ACCDataCallKind::DataExit, rewriter, accSupport,
-          globalSymbolRegion, symbolTable, config, {asyncQueue});
+          globalSymbolRegion, symbolTable, config, {asyncQueue}, regionFlags);
     }
     if (failed(emitted))
       return failure();
diff --git a/mlir/test/Conversion/OpenACCToLLVM/declare.mlir b/mlir/test/Conversion/OpenACCToLLVM/declare.mlir
index a25ba4899d86b7..a77e97cbe362b9 100644
--- a/mlir/test/Conversion/OpenACCToLLVM/declare.mlir
+++ b/mlir/test/Conversion/OpenACCToLLVM/declare.mlir
@@ -1,10 +1,13 @@
 // RUN: mlir-opt %s -acc-to-llvm -split-input-file | FileCheck %s
 
 // A structured declare (the enter token is consumed by a matching exit) uses
-// the same begin/end runtime entry points as acc.data.
+// the same begin/end runtime entry points as acc.data, with the declare
+// region flag (2) so the runtime can tell the two apart.
 // CHECK-LABEL: llvm.func @structured_declare
-// CHECK: llvm.call @__tgt_acc_data_begin
-// CHECK: llvm.call @__tgt_acc_data_end
+// CHECK: %[[BEGIN_FLAGS:.*]] = llvm.mlir.constant(2 : i64) : i64
+// CHECK: llvm.call @__tgt_acc_data_begin(%{{[^,]+}}, %[[BEGIN_FLAGS]],
+// CHECK: %[[END_FLAGS:.*]] = llvm.mlir.constant(2 : i64) : i64
+// CHECK: llvm.call @__tgt_acc_data_end(%{{[^,]+}}, %[[END_FLAGS]],
 // CHECK-NOT: acc.declare_enter
 // CHECK-NOT: acc.declare_exit
 func.func @structured_declare(%arg0: !llvm.ptr) {
@@ -19,6 +22,26 @@ func.func @structured_declare(%arg0: !llvm.ptr) {
 
 // -----
 
+// A structured declare whose exit names no objects, as a declare of a device
+// pointer does, still opens its region with the declare flag; there is no
+// end call, as nothing is to be released.
+// CHECK-LABEL: llvm.func @structured_declare_no_exit_operands
+// CHECK: %[[BEGIN_FLAGS:.*]] = llvm.mlir.constant(2 : i64) : i64
+// CHECK: llvm.call @__tgt_acc_data_begin(%{{[^,]+}}, %[[BEGIN_FLAGS]],
+// CHECK-NOT: llvm.call @__tgt_acc_data_end
+// CHECK-NOT: acc.declare_exit
+func.func @structured_declare_no_exit_operands(%arg0: !llvm.ptr) {
+  %size = arith.constant 40 : i64
+  %map = acc.map_info varPtr(%arg0 : !llvm.ptr) varType(f32)
+      size(%size : i64) elementSize(4) name("a")
+      descKind(none) mapFlags(devptr) -> !llvm.ptr
+  %token = acc.declare_enter dataOperands(%map : !llvm.ptr)
+  acc.declare_exit token(%token)
+  return
+}
+
+// -----
+
 // An unstructured declare registers the objects with __tgt_acc_declare. With
 // no target hook installed, its binary descriptor is null.
 // CHECK-LABEL: llvm.func @unstructured_declare
@@ -70,9 +93,12 @@ llvm.func @pre_dealloc_recipe(%arg0: !llvm.ptr) attributes {acc.declare_action =
 // -----
 
 // A recipe that runs after the host object is deallocated releases the
-// mapping of the descriptor, which is still valid storage at that point.
+// mapping of the descriptor, which is still valid storage at that point. The
+// exit holds no token, so the call carries no declare region flag.
 // CHECK-LABEL: llvm.func @post_dealloc_recipe
-// CHECK: llvm.call @__tgt_acc_data_end
+// CHECK: llvm.mlir.addressof @acc.ident
+// CHECK: %[[END_FLAGS:.*]] = llvm.mlir.constant(0 : i64) : i64
+// CHECK: llvm.call @__tgt_acc_data_end(%{{[^,]+}}, %[[END_FLAGS]],
 // CHECK-NOT: llvm.call @__tgt_acc_mirror_dealloc
 llvm.func @post_dealloc_recipe(%arg0: !llvm.ptr) attributes {acc.declare_action = #acc.declare_action<postDealloc = @post_dealloc_recipe>} {
   %size = arith.constant 4 : i64

``````````

</details>


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


More information about the Mlir-commits mailing list