[Mlir-commits] [mlir] [mlir][acc] Fold present() clauses on device values (PR #212815)

Ivan R. Ivanov llvmlistbot at llvm.org
Mon Aug 10 05:13:04 PDT 2026


https://github.com/ivanradanov updated https://github.com/llvm/llvm-project/pull/212815

>From 864da47ea2e8924bb8ddfccb526b6438e889c15f Mon Sep 17 00:00:00 2001
From: Ivan Radanov Ivanov <iivanov at nvidia.com>
Date: Wed, 29 Jul 2026 08:55:34 -0700
Subject: [PATCH 1/4] [mlir][acc] Fold present() clauses on device values

The compiler must emit acc.device_ptr mapping for device values. An
existing present clause prevents that. A present on a device value
always holds, so fold it away to allow implicit data handling generate
device_ptr mapping.
---
 .../OpenACC/Transforms/ACCImplicitData.cpp    | 57 +++++++++++++++----
 .../Dialect/OpenACC/acc-implicit-data.mlir    | 46 +++++++++++++++
 2 files changed, 92 insertions(+), 11 deletions(-)

diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
index 628454905b488..d031d9a7f35a3 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
@@ -215,6 +215,7 @@
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include <type_traits>
 
@@ -702,6 +703,35 @@ static void insertInSortedOrder(SmallVector<Value> &sortedDataClauseOperands,
   }
 }
 
+/// A present() clause on a device value always holds. Erase it to allow the
+/// implicit data to generate an acc.deviceptr for it.
+template <typename OpT>
+static void foldPresentDeviceValue(OpT computeConstructOp) {
+  SmallVector<Value> remainingOperands;
+  SmallVector<acc::PresentOp> toErase;
+  for (Value var : computeConstructOp.getDataClauseOperands()) {
+    if (auto presentOp =
+            dyn_cast_if_present<acc::PresentOp>(var.getDefiningOp())) {
+      if (acc::isDeviceValue(presentOp.getVar())) {
+        toErase.push_back(presentOp);
+        continue;
+      }
+    }
+    remainingOperands.push_back(var);
+  }
+  if (toErase.empty())
+    return;
+
+  computeConstructOp.getDataClauseOperandsMutable().assign(remainingOperands);
+  for (acc::PresentOp presentOp : toErase) {
+    Operation *exitOp = findDataExitOp(presentOp);
+    assert(exitOp && exitOp->getNumResults() == 0);
+    presentOp.getAccVar().replaceAllUsesWith(presentOp.getVar());
+    exitOp->erase();
+    presentOp->erase();
+  }
+}
+
 template <typename OpT>
 void ACCImplicitData::generateImplicitDataOps(
     ModuleOp &module, OpT computeConstructOp,
@@ -790,19 +820,24 @@ void ACCImplicitData::runOnOperation() {
 
   acc::OpenACCSupport &accSupport = getAnalysis<acc::OpenACCSupport>();
 
+  SmallVector<Operation *> computeConstructOps;
   module.walk([&](Operation *op) {
-    if (isa<ACC_COMPUTE_CONSTRUCT_OPS, acc::KernelEnvironmentOp>(op)) {
-      assert(op->getNumRegions() == 1 && "must have 1 region");
-
-      auto defaultClause = acc::getDefaultAttr(op);
-      llvm::TypeSwitch<Operation *, void>(op)
-          .Case<ACC_COMPUTE_CONSTRUCT_OPS, acc::KernelEnvironmentOp>(
-              [&](auto op) {
-                generateImplicitDataOps(module, op, defaultClause, accSupport);
-              })
-          .Default([&](Operation *) {});
-    }
+    if (isa<ACC_COMPUTE_CONSTRUCT_OPS, acc::KernelEnvironmentOp>(op))
+      computeConstructOps.push_back(op);
   });
+
+  for (Operation *op : computeConstructOps) {
+    assert(op->getNumRegions() == 1 && "must have 1 region");
+
+    auto defaultClause = acc::getDefaultAttr(op);
+    llvm::TypeSwitch<Operation *, void>(op)
+        .Case<ACC_COMPUTE_CONSTRUCT_OPS, acc::KernelEnvironmentOp>(
+            [&](auto op) {
+              foldPresentDeviceValue(op);
+              generateImplicitDataOps(module, op, defaultClause, accSupport);
+            })
+        .Default([&](Operation *) {});
+  }
 }
 
 } // namespace
diff --git a/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir b/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
index 3b6b5e1ade5e0..6551b20100005 100644
--- a/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
+++ b/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
@@ -287,3 +287,49 @@ func.func @test_declare_deviceptr_arg_in_parallel(%arg0: memref<?xi8>) {
 // CHECK: acc.declare_exit token(%[[TOKEN]]) dataOperands(%[[DEVPTR]] : memref<10xf32>)
 // CHECK-NOT: acc.copyin
 // CHECK-NOT: acc.copyout
+
+// -----
+
+// Fold an explicit present of device data: drop present/delete and rewrite
+// region uses; subsequent implicit mapping should emit deviceptr.
+func.func @test_fold_present_device_value() {
+  %alloc = memref.alloca() : memref<10xf32, #gpu.address_space<global>>
+  %present = acc.present varPtr(%alloc : memref<10xf32, #gpu.address_space<global>>) -> memref<10xf32, #gpu.address_space<global>> {name = "a"}
+  acc.parallel dataOperands(%present : memref<10xf32, #gpu.address_space<global>>) {
+    %c0 = arith.constant 0 : index
+    %load = memref.load %present[%c0] : memref<10xf32, #gpu.address_space<global>>
+    acc.yield
+  }
+  acc.delete accPtr(%present : memref<10xf32, #gpu.address_space<global>>) {dataClause = #acc<data_clause acc_present>, name = "a"}
+  return
+}
+
+// CHECK-LABEL: func.func @test_fold_present_device_value
+// CHECK: %[[ALLOC:.*]] = memref.alloca() : memref<10xf32, #gpu.address_space<global>>
+// CHECK: %[[DEVPTR:.*]] = acc.deviceptr varPtr(%[[ALLOC]] : memref<10xf32, #gpu.address_space<global>>) -> memref<10xf32, #gpu.address_space<global>> {implicit = true, name = ""}
+// CHECK: acc.parallel dataOperands(%[[DEVPTR]] : memref<10xf32, #gpu.address_space<global>>) {
+// CHECK: memref.load %[[DEVPTR]][{{.*}}] : memref<10xf32, #gpu.address_space<global>>
+// CHECK-NOT: acc.present
+// CHECK-NOT: acc.delete
+
+// -----
+
+// Present of host data must not be folded away.
+func.func @test_present_host_not_folded() {
+  %alloc = memref.alloca() : memref<10xf32>
+  %present = acc.present varPtr(%alloc : memref<10xf32>) -> memref<10xf32> {name = "a"}
+  acc.parallel dataOperands(%present : memref<10xf32>) {
+    %c0 = arith.constant 0 : index
+    %load = memref.load %present[%c0] : memref<10xf32>
+    acc.yield
+  }
+  acc.delete accPtr(%present : memref<10xf32>) {dataClause = #acc<data_clause acc_present>, name = "a"}
+  return
+}
+
+// CHECK-LABEL: func.func @test_present_host_not_folded
+// CHECK: %[[ALLOC:.*]] = memref.alloca() : memref<10xf32>
+// CHECK: %[[PRESENT:.*]] = acc.present varPtr(%[[ALLOC]] : memref<10xf32>) -> memref<10xf32> {name = "a"}
+// CHECK: acc.parallel dataOperands(%[[PRESENT]] : memref<10xf32>) {
+// CHECK: memref.load %[[PRESENT]][{{.*}}] : memref<10xf32>
+// CHECK: acc.delete accPtr(%[[PRESENT]] : memref<10xf32>) {dataClause = #acc<data_clause acc_present>, name = "a"}

>From 5034ecefcaa3a26b30df2431a8b3cc940051a222 Mon Sep 17 00:00:00 2001
From: Ivan Radanov Ivanov <iivanov at nvidia.com>
Date: Fri, 31 Jul 2026 10:59:16 -0700
Subject: [PATCH 2/4] fix

---
 .../OpenACC/Transforms/ACCImplicitData.cpp    | 60 +++++++++++++++----
 .../Dialect/OpenACC/acc-implicit-data.mlir    | 31 ++++++++++
 2 files changed, 80 insertions(+), 11 deletions(-)

diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
index d031d9a7f35a3..693460f2e4173 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
@@ -212,6 +212,7 @@
 #include "mlir/Interfaces/FunctionInterfaces.h"
 #include "mlir/Interfaces/ViewLikeInterface.h"
 #include "mlir/Transforms/RegionUtils.h"
+#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/TypeSwitch.h"
@@ -259,7 +260,8 @@ class ACCImplicitData : public acc::impl::ACCImplicitDataBase<ACCImplicitData> {
   void
   generateImplicitDataOps(ModuleOp &module, OpT computeConstructOp,
                           std::optional<acc::ClauseDefaultValue> &defaultClause,
-                          acc::OpenACCSupport &accSupport);
+                          acc::OpenACCSupport &accSupport,
+                          SmallVector<Value> &dominatingDataClauses);
 
   /// Generates a private recipe for a variable.
   acc::PrivateRecipeOp generatePrivateRecipe(ModuleOp &module, Value var,
@@ -703,16 +705,44 @@ static void insertInSortedOrder(SmallVector<Value> &sortedDataClauseOperands,
   }
 }
 
+static bool isCoveredByEnclosingDataClause(Value var,
+                                           ArrayRef<Value> enclosingDataClauses,
+                                           AliasAnalysis &aliasAnalysis) {
+  for (Value clause : enclosingDataClauses) {
+    Operation *entryOp = clause.getDefiningOp();
+    if (!entryOp)
+      continue;
+    if (isa<acc::CopyinOp, acc::CreateOp, acc::PresentOp, acc::NoCreateOp>(
+            entryOp) &&
+        aliasAnalysis.alias(acc::getVar(entryOp), var).isMust())
+      return true;
+  }
+  return false;
+}
+
 /// A present() clause on a device value always holds. Erase it to allow the
-/// implicit data to generate an acc.deviceptr for it.
+/// implicit data to generate an acc.deviceptr for it, except if a dominating
+/// data clause mapped it to the device (valid for cuda `managed` allocations).
 template <typename OpT>
-static void foldPresentDeviceValue(OpT computeConstructOp) {
+static void foldPresentDeviceValue(OpT computeConstructOp,
+                                   SmallVector<Value> &dominatingDataClauses,
+                                   AliasAnalysis &aliasAnalysis) {
+  llvm::DenseSet<Value> ownClauses(
+      computeConstructOp.getDataClauseOperands().begin(),
+      computeConstructOp.getDataClauseOperands().end());
+  SmallVector<Value> enclosingClauses;
+  for (Value v : dominatingDataClauses)
+    if (!ownClauses.count(v))
+      enclosingClauses.push_back(v);
+
   SmallVector<Value> remainingOperands;
   SmallVector<acc::PresentOp> toErase;
   for (Value var : computeConstructOp.getDataClauseOperands()) {
     if (auto presentOp =
             dyn_cast_if_present<acc::PresentOp>(var.getDefiningOp())) {
-      if (acc::isDeviceValue(presentOp.getVar())) {
+      if (acc::isDeviceValue(presentOp.getVar()) &&
+          !isCoveredByEnclosingDataClause(presentOp.getVar(), enclosingClauses,
+                                          aliasAnalysis)) {
         toErase.push_back(presentOp);
         continue;
       }
@@ -722,6 +752,12 @@ static void foldPresentDeviceValue(OpT computeConstructOp) {
   if (toErase.empty())
     return;
 
+  llvm::DenseSet<Value> foldedAccVars;
+  for (acc::PresentOp presentOp : toErase)
+    foldedAccVars.insert(presentOp.getAccVar());
+  llvm::erase_if(dominatingDataClauses,
+                 [&](Value v) { return foldedAccVars.count(v); });
+
   computeConstructOp.getDataClauseOperandsMutable().assign(remainingOperands);
   for (acc::PresentOp presentOp : toErase) {
     Operation *exitOp = findDataExitOp(presentOp);
@@ -736,7 +772,8 @@ template <typename OpT>
 void ACCImplicitData::generateImplicitDataOps(
     ModuleOp &module, OpT computeConstructOp,
     std::optional<acc::ClauseDefaultValue> &defaultClause,
-    acc::OpenACCSupport &accSupport) {
+    acc::OpenACCSupport &accSupport,
+    SmallVector<Value> &dominatingDataClauses) {
   // Implicit data attributes are only applied if "[t]here is no default(none)
   // clause visible at the compute construct", unless ignoreDefaultNone is set.
   if (!ignoreDefaultNone && defaultClause.has_value() &&
@@ -768,10 +805,6 @@ void ACCImplicitData::generateImplicitDataOps(
     LLVM_DEBUG(llvm::dbgs() << "== Generating clauses for ==\n"
                             << computeConstructOp << "\n");
   }
-  auto &domInfo = this->getAnalysis<DominanceInfo>();
-  auto &postDomInfo = this->getAnalysis<PostDominanceInfo>();
-  auto dominatingDataClauses =
-      acc::getDominatingDataClauses(computeConstructOp, domInfo, postDomInfo);
   for (auto var : candidateVars) {
     auto newDataClauseOp = generateDataClauseOpForCandidate(
         var, module, builder, computeConstructOp, dominatingDataClauses,
@@ -833,8 +866,13 @@ void ACCImplicitData::runOnOperation() {
     llvm::TypeSwitch<Operation *, void>(op)
         .Case<ACC_COMPUTE_CONSTRUCT_OPS, acc::KernelEnvironmentOp>(
             [&](auto op) {
-              foldPresentDeviceValue(op);
-              generateImplicitDataOps(module, op, defaultClause, accSupport);
+              auto dominatingDataClauses = acc::getDominatingDataClauses(
+                  op, getAnalysis<DominanceInfo>(),
+                  getAnalysis<PostDominanceInfo>());
+              foldPresentDeviceValue(op, dominatingDataClauses,
+                                     getAnalysis<AliasAnalysis>());
+              generateImplicitDataOps(module, op, defaultClause, accSupport,
+                                      dominatingDataClauses);
             })
         .Default([&](Operation *) {});
   }
diff --git a/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir b/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
index 6551b20100005..b8477893c34c7 100644
--- a/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
+++ b/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
@@ -333,3 +333,34 @@ func.func @test_present_host_not_folded() {
 // CHECK: acc.parallel dataOperands(%[[PRESENT]] : memref<10xf32>) {
 // CHECK: memref.load %[[PRESENT]][{{.*}}] : memref<10xf32>
 // CHECK: acc.delete accPtr(%[[PRESENT]] : memref<10xf32>) {dataClause = #acc<data_clause acc_present>, name = "a"}
+
+// -----
+
+// Present of device data that is already covered by an enclosing acc.data
+// clause must NOT be folded
+func.func @test_present_device_inside_data_region_not_folded() {
+  %alloc = memref.alloca() : memref<10xf32, #gpu.address_space<global>>
+  %copy = acc.copyin varPtr(%alloc : memref<10xf32, #gpu.address_space<global>>) -> memref<10xf32, #gpu.address_space<global>> {name = "a"}
+  acc.data dataOperands(%copy : memref<10xf32, #gpu.address_space<global>>) {
+    %present = acc.present varPtr(%alloc : memref<10xf32, #gpu.address_space<global>>) -> memref<10xf32, #gpu.address_space<global>> {name = "a"}
+    acc.parallel dataOperands(%present : memref<10xf32, #gpu.address_space<global>>) {
+      %c0 = arith.constant 0 : index
+      %load = memref.load %present[%c0] : memref<10xf32, #gpu.address_space<global>>
+      acc.yield
+    }
+    acc.delete accPtr(%present : memref<10xf32, #gpu.address_space<global>>) {dataClause = #acc<data_clause acc_present>, name = "a"}
+    acc.terminator
+  }
+  acc.copyout accPtr(%copy : memref<10xf32, #gpu.address_space<global>>) to varPtr(%alloc : memref<10xf32, #gpu.address_space<global>>) {name = "a"}
+  return
+}
+
+// CHECK-LABEL: func.func @test_present_device_inside_data_region_not_folded
+// CHECK: %[[ALLOC:.*]] = memref.alloca() : memref<10xf32, #gpu.address_space<global>>
+// CHECK: %[[COPY:.*]] = acc.copyin varPtr(%[[ALLOC]] : memref<10xf32, #gpu.address_space<global>>)
+// CHECK: acc.data dataOperands(%[[COPY]] : memref<10xf32, #gpu.address_space<global>>)
+// CHECK: %[[PRESENT:.*]] = acc.present varPtr(%[[ALLOC]] : memref<10xf32, #gpu.address_space<global>>) -> memref<10xf32, #gpu.address_space<global>> {name = "a"}
+// CHECK: acc.parallel dataOperands(%[[PRESENT]] : memref<10xf32, #gpu.address_space<global>>)
+// CHECK: memref.load %[[PRESENT]][{{.*}}] : memref<10xf32, #gpu.address_space<global>>
+// CHECK: acc.delete accPtr(%[[PRESENT]] : memref<10xf32, #gpu.address_space<global>>) {dataClause = #acc<data_clause acc_present>, name = "a"}
+// CHECK-NOT: acc.deviceptr

>From ead75465c79459bea5207e250c8fc13fe0be517c Mon Sep 17 00:00:00 2001
From: Ivan Radanov Ivanov <iivanov at nvidia.com>
Date: Wed, 5 Aug 2026 14:13:44 -0700
Subject: [PATCH 3/4] Revert "fix"

This reverts commit 69f28b7a1691b23cdceff36836e4e6a35eb405ec.
---
 .../OpenACC/Transforms/ACCImplicitData.cpp    | 60 ++++---------------
 .../Dialect/OpenACC/acc-implicit-data.mlir    | 31 ----------
 2 files changed, 11 insertions(+), 80 deletions(-)

diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
index 693460f2e4173..d031d9a7f35a3 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
@@ -212,7 +212,6 @@
 #include "mlir/Interfaces/FunctionInterfaces.h"
 #include "mlir/Interfaces/ViewLikeInterface.h"
 #include "mlir/Transforms/RegionUtils.h"
-#include "llvm/ADT/DenseSet.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallVector.h"
 #include "llvm/ADT/TypeSwitch.h"
@@ -260,8 +259,7 @@ class ACCImplicitData : public acc::impl::ACCImplicitDataBase<ACCImplicitData> {
   void
   generateImplicitDataOps(ModuleOp &module, OpT computeConstructOp,
                           std::optional<acc::ClauseDefaultValue> &defaultClause,
-                          acc::OpenACCSupport &accSupport,
-                          SmallVector<Value> &dominatingDataClauses);
+                          acc::OpenACCSupport &accSupport);
 
   /// Generates a private recipe for a variable.
   acc::PrivateRecipeOp generatePrivateRecipe(ModuleOp &module, Value var,
@@ -705,44 +703,16 @@ static void insertInSortedOrder(SmallVector<Value> &sortedDataClauseOperands,
   }
 }
 
-static bool isCoveredByEnclosingDataClause(Value var,
-                                           ArrayRef<Value> enclosingDataClauses,
-                                           AliasAnalysis &aliasAnalysis) {
-  for (Value clause : enclosingDataClauses) {
-    Operation *entryOp = clause.getDefiningOp();
-    if (!entryOp)
-      continue;
-    if (isa<acc::CopyinOp, acc::CreateOp, acc::PresentOp, acc::NoCreateOp>(
-            entryOp) &&
-        aliasAnalysis.alias(acc::getVar(entryOp), var).isMust())
-      return true;
-  }
-  return false;
-}
-
 /// A present() clause on a device value always holds. Erase it to allow the
-/// implicit data to generate an acc.deviceptr for it, except if a dominating
-/// data clause mapped it to the device (valid for cuda `managed` allocations).
+/// implicit data to generate an acc.deviceptr for it.
 template <typename OpT>
-static void foldPresentDeviceValue(OpT computeConstructOp,
-                                   SmallVector<Value> &dominatingDataClauses,
-                                   AliasAnalysis &aliasAnalysis) {
-  llvm::DenseSet<Value> ownClauses(
-      computeConstructOp.getDataClauseOperands().begin(),
-      computeConstructOp.getDataClauseOperands().end());
-  SmallVector<Value> enclosingClauses;
-  for (Value v : dominatingDataClauses)
-    if (!ownClauses.count(v))
-      enclosingClauses.push_back(v);
-
+static void foldPresentDeviceValue(OpT computeConstructOp) {
   SmallVector<Value> remainingOperands;
   SmallVector<acc::PresentOp> toErase;
   for (Value var : computeConstructOp.getDataClauseOperands()) {
     if (auto presentOp =
             dyn_cast_if_present<acc::PresentOp>(var.getDefiningOp())) {
-      if (acc::isDeviceValue(presentOp.getVar()) &&
-          !isCoveredByEnclosingDataClause(presentOp.getVar(), enclosingClauses,
-                                          aliasAnalysis)) {
+      if (acc::isDeviceValue(presentOp.getVar())) {
         toErase.push_back(presentOp);
         continue;
       }
@@ -752,12 +722,6 @@ static void foldPresentDeviceValue(OpT computeConstructOp,
   if (toErase.empty())
     return;
 
-  llvm::DenseSet<Value> foldedAccVars;
-  for (acc::PresentOp presentOp : toErase)
-    foldedAccVars.insert(presentOp.getAccVar());
-  llvm::erase_if(dominatingDataClauses,
-                 [&](Value v) { return foldedAccVars.count(v); });
-
   computeConstructOp.getDataClauseOperandsMutable().assign(remainingOperands);
   for (acc::PresentOp presentOp : toErase) {
     Operation *exitOp = findDataExitOp(presentOp);
@@ -772,8 +736,7 @@ template <typename OpT>
 void ACCImplicitData::generateImplicitDataOps(
     ModuleOp &module, OpT computeConstructOp,
     std::optional<acc::ClauseDefaultValue> &defaultClause,
-    acc::OpenACCSupport &accSupport,
-    SmallVector<Value> &dominatingDataClauses) {
+    acc::OpenACCSupport &accSupport) {
   // Implicit data attributes are only applied if "[t]here is no default(none)
   // clause visible at the compute construct", unless ignoreDefaultNone is set.
   if (!ignoreDefaultNone && defaultClause.has_value() &&
@@ -805,6 +768,10 @@ void ACCImplicitData::generateImplicitDataOps(
     LLVM_DEBUG(llvm::dbgs() << "== Generating clauses for ==\n"
                             << computeConstructOp << "\n");
   }
+  auto &domInfo = this->getAnalysis<DominanceInfo>();
+  auto &postDomInfo = this->getAnalysis<PostDominanceInfo>();
+  auto dominatingDataClauses =
+      acc::getDominatingDataClauses(computeConstructOp, domInfo, postDomInfo);
   for (auto var : candidateVars) {
     auto newDataClauseOp = generateDataClauseOpForCandidate(
         var, module, builder, computeConstructOp, dominatingDataClauses,
@@ -866,13 +833,8 @@ void ACCImplicitData::runOnOperation() {
     llvm::TypeSwitch<Operation *, void>(op)
         .Case<ACC_COMPUTE_CONSTRUCT_OPS, acc::KernelEnvironmentOp>(
             [&](auto op) {
-              auto dominatingDataClauses = acc::getDominatingDataClauses(
-                  op, getAnalysis<DominanceInfo>(),
-                  getAnalysis<PostDominanceInfo>());
-              foldPresentDeviceValue(op, dominatingDataClauses,
-                                     getAnalysis<AliasAnalysis>());
-              generateImplicitDataOps(module, op, defaultClause, accSupport,
-                                      dominatingDataClauses);
+              foldPresentDeviceValue(op);
+              generateImplicitDataOps(module, op, defaultClause, accSupport);
             })
         .Default([&](Operation *) {});
   }
diff --git a/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir b/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
index b8477893c34c7..6551b20100005 100644
--- a/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
+++ b/mlir/test/Dialect/OpenACC/acc-implicit-data.mlir
@@ -333,34 +333,3 @@ func.func @test_present_host_not_folded() {
 // CHECK: acc.parallel dataOperands(%[[PRESENT]] : memref<10xf32>) {
 // CHECK: memref.load %[[PRESENT]][{{.*}}] : memref<10xf32>
 // CHECK: acc.delete accPtr(%[[PRESENT]] : memref<10xf32>) {dataClause = #acc<data_clause acc_present>, name = "a"}
-
-// -----
-
-// Present of device data that is already covered by an enclosing acc.data
-// clause must NOT be folded
-func.func @test_present_device_inside_data_region_not_folded() {
-  %alloc = memref.alloca() : memref<10xf32, #gpu.address_space<global>>
-  %copy = acc.copyin varPtr(%alloc : memref<10xf32, #gpu.address_space<global>>) -> memref<10xf32, #gpu.address_space<global>> {name = "a"}
-  acc.data dataOperands(%copy : memref<10xf32, #gpu.address_space<global>>) {
-    %present = acc.present varPtr(%alloc : memref<10xf32, #gpu.address_space<global>>) -> memref<10xf32, #gpu.address_space<global>> {name = "a"}
-    acc.parallel dataOperands(%present : memref<10xf32, #gpu.address_space<global>>) {
-      %c0 = arith.constant 0 : index
-      %load = memref.load %present[%c0] : memref<10xf32, #gpu.address_space<global>>
-      acc.yield
-    }
-    acc.delete accPtr(%present : memref<10xf32, #gpu.address_space<global>>) {dataClause = #acc<data_clause acc_present>, name = "a"}
-    acc.terminator
-  }
-  acc.copyout accPtr(%copy : memref<10xf32, #gpu.address_space<global>>) to varPtr(%alloc : memref<10xf32, #gpu.address_space<global>>) {name = "a"}
-  return
-}
-
-// CHECK-LABEL: func.func @test_present_device_inside_data_region_not_folded
-// CHECK: %[[ALLOC:.*]] = memref.alloca() : memref<10xf32, #gpu.address_space<global>>
-// CHECK: %[[COPY:.*]] = acc.copyin varPtr(%[[ALLOC]] : memref<10xf32, #gpu.address_space<global>>)
-// CHECK: acc.data dataOperands(%[[COPY]] : memref<10xf32, #gpu.address_space<global>>)
-// CHECK: %[[PRESENT:.*]] = acc.present varPtr(%[[ALLOC]] : memref<10xf32, #gpu.address_space<global>>) -> memref<10xf32, #gpu.address_space<global>> {name = "a"}
-// CHECK: acc.parallel dataOperands(%[[PRESENT]] : memref<10xf32, #gpu.address_space<global>>)
-// CHECK: memref.load %[[PRESENT]][{{.*}}] : memref<10xf32, #gpu.address_space<global>>
-// CHECK: acc.delete accPtr(%[[PRESENT]] : memref<10xf32, #gpu.address_space<global>>) {dataClause = #acc<data_clause acc_present>, name = "a"}
-// CHECK-NOT: acc.deviceptr

>From 9db08f38e8ca6274b4443d5a8a4a0e25efe306fb Mon Sep 17 00:00:00 2001
From: Ivan Radanov Ivanov <iivanov at nvidia.com>
Date: Mon, 10 Aug 2026 05:04:11 -0700
Subject: [PATCH 4/4] reorder devicevalue check

---
 .../OpenACC/Transforms/ACCImplicitData.cpp    | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
index d031d9a7f35a3..5aae7dfef7d58 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
@@ -458,15 +458,6 @@ Operation *ACCImplicitData::generateDataClauseOpForCandidate(
       typeCategory, acc::VariableTypeCategory::aggregate);
   Location loc = computeConstructOp->getLoc();
 
-  if (acc::isDeviceValue(var)) {
-    // If the variable is device data, use deviceptr clause.
-    LLVM_DEBUG(llvm::dbgs() << "Using deviceptr clause because variable is "
-                               "device data\n");
-    return acc::DevicePtrOp::create(builder, loc, var,
-                                    /*structured=*/true, /*implicit=*/true,
-                                    accSupport.getVariableName(var));
-  }
-
   Operation *op = nullptr;
   op = getOriginalDataClauseOpForAlias(var, builder, computeConstructOp,
                                        dominatingDataClauses);
@@ -491,6 +482,16 @@ Operation *ACCImplicitData::generateDataClauseOpForCandidate(
                                   acc::getBounds(op));
   }
 
+  if (acc::isDeviceValue(var)) {
+    // Variable is device data with no existing dominating mapping: use
+    // deviceptr clause.
+    LLVM_DEBUG(llvm::dbgs() << "Using deviceptr clause because variable is "
+                               "device data\n");
+    return acc::DevicePtrOp::create(builder, loc, var,
+                                    /*structured=*/true, /*implicit=*/true,
+                                    accSupport.getVariableName(var));
+  }
+
   if (isScalar) {
     if (enableImplicitReductionCopy &&
         acc::isOnlyUsedByReductionClauses(var,



More information about the Mlir-commits mailing list