[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