[Mlir-commits] [mlir] 85e7860 - [mlir][acc] Make getDominatingDataClauses an OpenACC utility (#170549)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Dec 5 09:31:30 PST 2025


Author: nvptm
Date: 2025-12-05T09:31:26-08:00
New Revision: 85e7860319844308372ef7eea22ba88295989f5f

URL: https://github.com/llvm/llvm-project/commit/85e7860319844308372ef7eea22ba88295989f5f
DIFF: https://github.com/llvm/llvm-project/commit/85e7860319844308372ef7eea22ba88295989f5f.diff

LOG: [mlir][acc] Make getDominatingDataClauses an OpenACC utility (#170549)

Moving getDominatingDataClauses to OpenACCUtils allows reuse.

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h
    mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
    mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp
    mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h
index 2852e0917c3fb..e9ce9b3a36aba 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h
@@ -10,8 +10,11 @@
 #define MLIR_DIALECT_OPENACC_OPENACCUTILS_H_
 
 #include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "llvm/ADT/SmallVector.h"
 
 namespace mlir {
+class DominanceInfo;
+class PostDominanceInfo;
 namespace acc {
 
 /// Used to obtain the enclosing compute construct operation that contains
@@ -62,6 +65,22 @@ mlir::Value getBaseEntity(mlir::Value val);
 bool isValidSymbolUse(mlir::Operation *user, mlir::SymbolRefAttr symbol,
                       mlir::Operation **definingOpPtr = nullptr);
 
+/// Collects all data clauses that dominate the compute construct.
+/// This includes data clauses from:
+/// - The compute construct itself
+/// - Enclosing data constructs
+/// - Applicable declare directives (those that dominate and post-dominate)
+/// This is used to determine if a variable is already covered by an existing
+/// data clause.
+/// \param computeConstructOp The compute construct operation
+/// \param domInfo Dominance information
+/// \param postDomInfo Post-dominance information
+/// \return Vector of data clause values that dominate the compute construct
+llvm::SmallVector<mlir::Value>
+getDominatingDataClauses(mlir::Operation *computeConstructOp,
+                         mlir::DominanceInfo &domInfo,
+                         mlir::PostDominanceInfo &postDomInfo);
+
 } // namespace acc
 } // namespace mlir
 

diff  --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
index 8bdde7c9691bf..67cdf100a7a48 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCImplicitData.cpp
@@ -237,11 +237,6 @@ class ACCImplicitData : public acc::impl::ACCImplicitDataBase<ACCImplicitData> {
   void runOnOperation() override;
 
 private:
-  /// Collects all data clauses that dominate the compute construct.
-  /// Needed to determine if a variable is already covered by an existing data
-  /// clause.
-  SmallVector<Value> getDominatingDataClauses(Operation *computeConstructOp);
-
   /// Looks through the `dominatingDataClauses` to find the original data clause
   /// op for an alias. Returns nullptr if no original data clause op is found.
   template <typename OpT>
@@ -300,62 +295,6 @@ static bool isCandidateForImplicitData(Value val, Region &accRegion) {
   return true;
 }
 
-SmallVector<Value>
-ACCImplicitData::getDominatingDataClauses(Operation *computeConstructOp) {
-  llvm::SmallSetVector<Value, 8> dominatingDataClauses;
-
-  llvm::TypeSwitch<Operation *>(computeConstructOp)
-      .Case<acc::ParallelOp, acc::KernelsOp, acc::SerialOp>([&](auto op) {
-        for (auto dataClause : op.getDataClauseOperands()) {
-          dominatingDataClauses.insert(dataClause);
-        }
-      })
-      .Default([](Operation *) {});
-
-  // Collect the data clauses from enclosing data constructs.
-  Operation *currParentOp = computeConstructOp->getParentOp();
-  while (currParentOp) {
-    if (isa<acc::DataOp>(currParentOp)) {
-      for (auto dataClause :
-           dyn_cast<acc::DataOp>(currParentOp).getDataClauseOperands()) {
-        dominatingDataClauses.insert(dataClause);
-      }
-    }
-    currParentOp = currParentOp->getParentOp();
-  }
-
-  // Find the enclosing function/subroutine
-  auto funcOp = computeConstructOp->getParentOfType<FunctionOpInterface>();
-  if (!funcOp)
-    return dominatingDataClauses.takeVector();
-
-  // Walk the function to find `acc.declare_enter`/`acc.declare_exit` pairs that
-  // dominate and post-dominate the compute construct and add their data
-  // clauses to the list.
-  auto &domInfo = this->getAnalysis<DominanceInfo>();
-  auto &postDomInfo = this->getAnalysis<PostDominanceInfo>();
-  funcOp->walk([&](acc::DeclareEnterOp declareEnterOp) {
-    if (domInfo.dominates(declareEnterOp.getOperation(), computeConstructOp)) {
-      // Collect all `acc.declare_exit` ops for this token.
-      SmallVector<acc::DeclareExitOp> exits;
-      for (auto *user : declareEnterOp.getToken().getUsers())
-        if (auto declareExit = dyn_cast<acc::DeclareExitOp>(user))
-          exits.push_back(declareExit);
-
-      // Only add clauses if every `acc.declare_exit` op post-dominates the
-      // compute construct.
-      if (!exits.empty() && llvm::all_of(exits, [&](acc::DeclareExitOp exitOp) {
-            return postDomInfo.postDominates(exitOp, computeConstructOp);
-          })) {
-        for (auto dataClause : declareEnterOp.getDataClauseOperands())
-          dominatingDataClauses.insert(dataClause);
-      }
-    }
-  });
-
-  return dominatingDataClauses.takeVector();
-}
-
 template <typename OpT>
 Operation *ACCImplicitData::getOriginalDataClauseOpForAlias(
     Value var, OpBuilder &builder, OpT computeConstructOp,
@@ -775,7 +714,10 @@ void ACCImplicitData::generateImplicitDataOps(
     LLVM_DEBUG(llvm::dbgs() << "== Generating clauses for ==\n"
                             << computeConstructOp << "\n");
   }
-  auto dominatingDataClauses = getDominatingDataClauses(computeConstructOp);
+  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,

diff  --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp
index aebc248e02ea0..7f27b4495045f 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp
@@ -9,9 +9,11 @@
 #include "mlir/Dialect/OpenACC/OpenACCUtils.h"
 
 #include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/IR/Dominance.h"
 #include "mlir/IR/SymbolTable.h"
 #include "mlir/Interfaces/FunctionInterfaces.h"
 #include "mlir/Interfaces/ViewLikeInterface.h"
+#include "llvm/ADT/SetVector.h"
 #include "llvm/ADT/TypeSwitch.h"
 #include "llvm/IR/Intrinsics.h"
 #include "llvm/Support/Casting.h"
@@ -205,3 +207,62 @@ bool mlir::acc::isValidSymbolUse(mlir::Operation *user,
   bool hasDeclare = definingOp->hasAttr(mlir::acc::getDeclareAttrName());
   return hasDeclare;
 }
+
+llvm::SmallVector<mlir::Value>
+mlir::acc::getDominatingDataClauses(mlir::Operation *computeConstructOp,
+                                    mlir::DominanceInfo &domInfo,
+                                    mlir::PostDominanceInfo &postDomInfo) {
+  llvm::SmallSetVector<mlir::Value, 8> dominatingDataClauses;
+
+  llvm::TypeSwitch<mlir::Operation *>(computeConstructOp)
+      .Case<mlir::acc::ParallelOp, mlir::acc::KernelsOp, mlir::acc::SerialOp>(
+          [&](auto op) {
+            for (auto dataClause : op.getDataClauseOperands()) {
+              dominatingDataClauses.insert(dataClause);
+            }
+          })
+      .Default([](mlir::Operation *) {});
+
+  // Collect the data clauses from enclosing data constructs.
+  mlir::Operation *currParentOp = computeConstructOp->getParentOp();
+  while (currParentOp) {
+    if (mlir::isa<mlir::acc::DataOp>(currParentOp)) {
+      for (auto dataClause : mlir::dyn_cast<mlir::acc::DataOp>(currParentOp)
+                                 .getDataClauseOperands()) {
+        dominatingDataClauses.insert(dataClause);
+      }
+    }
+    currParentOp = currParentOp->getParentOp();
+  }
+
+  // Find the enclosing function/subroutine
+  auto funcOp =
+      computeConstructOp->getParentOfType<mlir::FunctionOpInterface>();
+  if (!funcOp)
+    return dominatingDataClauses.takeVector();
+
+  // Walk the function to find `acc.declare_enter`/`acc.declare_exit` pairs that
+  // dominate and post-dominate the compute construct and add their data
+  // clauses to the list.
+  funcOp->walk([&](mlir::acc::DeclareEnterOp declareEnterOp) {
+    if (domInfo.dominates(declareEnterOp.getOperation(), computeConstructOp)) {
+      // Collect all `acc.declare_exit` ops for this token.
+      llvm::SmallVector<mlir::acc::DeclareExitOp> exits;
+      for (auto *user : declareEnterOp.getToken().getUsers())
+        if (auto declareExit = mlir::dyn_cast<mlir::acc::DeclareExitOp>(user))
+          exits.push_back(declareExit);
+
+      // Only add clauses if every `acc.declare_exit` op post-dominates the
+      // compute construct.
+      if (!exits.empty() &&
+          llvm::all_of(exits, [&](mlir::acc::DeclareExitOp exitOp) {
+            return postDomInfo.postDominates(exitOp, computeConstructOp);
+          })) {
+        for (auto dataClause : declareEnterOp.getDataClauseOperands())
+          dominatingDataClauses.insert(dataClause);
+      }
+    }
+  });
+
+  return dominatingDataClauses.takeVector();
+}

diff  --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp
index 8b1f532bbe5c0..60d87326c0e9b 100644
--- a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp
@@ -913,3 +913,457 @@ TEST_F(OpenACCUtilsTest, isValidSymbolUseNullDefiningOpPtr) {
 
   EXPECT_TRUE(result);
 }
+
+//===----------------------------------------------------------------------===//
+// getDominatingDataClauses Tests
+//===----------------------------------------------------------------------===//
+
+TEST_F(OpenACCUtilsTest, getDominatingDataClausesFromComputeConstruct) {
+  // Create a module to hold a function
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  Block *moduleBlock = module->getBody();
+
+  OpBuilder::InsertionGuard guard(b);
+  b.setInsertionPointToStart(moduleBlock);
+
+  // Create a function
+  auto funcType = b.getFunctionType({}, {});
+  OwningOpRef<func::FuncOp> funcOp =
+      func::FuncOp::create(b, loc, "test_func", funcType);
+  Block *funcBlock = funcOp->addEntryBlock();
+
+  b.setInsertionPointToStart(funcBlock);
+
+  // Create a memref for the data clause
+  auto memrefTy = MemRefType::get({10}, b.getI32Type());
+  OwningOpRef<memref::AllocaOp> allocOp =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr =
+      cast<TypedValue<PointerLikeType>>(allocOp->getResult());
+
+  // Create a copyin op to represent a data clause
+  OwningOpRef<CopyinOp> copyinOp =
+      CopyinOp::create(b, loc, varPtr, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"test_var");
+
+  // Create a parallel op
+  OwningOpRef<ParallelOp> parallelOp =
+      ParallelOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands
+  parallelOp->getDataClauseOperandsMutable().append(copyinOp->getAccVar());
+
+  // Create dominance info
+  DominanceInfo domInfo(funcOp.get());
+  PostDominanceInfo postDomInfo(funcOp.get());
+
+  // Get dominating data clauses
+  auto dataClauses =
+      getDominatingDataClauses(parallelOp.get(), domInfo, postDomInfo);
+
+  // Should contain the copyin from the parallel op
+  EXPECT_EQ(dataClauses.size(), 1ul);
+  EXPECT_EQ(dataClauses[0], copyinOp->getAccVar());
+}
+
+TEST_F(OpenACCUtilsTest, getDominatingDataClausesFromEnclosingDataOp) {
+  // Create a module to hold a function
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  Block *moduleBlock = module->getBody();
+
+  OpBuilder::InsertionGuard guard(b);
+  b.setInsertionPointToStart(moduleBlock);
+
+  // Create a function
+  auto funcType = b.getFunctionType({}, {});
+  OwningOpRef<func::FuncOp> funcOp =
+      func::FuncOp::create(b, loc, "test_func", funcType);
+  Block *funcBlock = funcOp->addEntryBlock();
+
+  b.setInsertionPointToStart(funcBlock);
+
+  // Create a memref for the data clause
+  auto memrefTy = MemRefType::get({10}, b.getI32Type());
+  OwningOpRef<memref::AllocaOp> allocOp =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr =
+      cast<TypedValue<PointerLikeType>>(allocOp->getResult());
+
+  // Create a copyin op for the data construct
+  OwningOpRef<CopyinOp> copyinOp =
+      CopyinOp::create(b, loc, varPtr, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"test_var");
+
+  // Create a data op
+  OwningOpRef<DataOp> dataOp =
+      DataOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands
+  dataOp->getDataClauseOperandsMutable().append(copyinOp->getAccVar());
+
+  Region &dataRegion = dataOp->getRegion();
+  Block *dataBlock = &dataRegion.emplaceBlock();
+
+  b.setInsertionPointToStart(dataBlock);
+
+  // Create a parallel op inside the data region (no data clauses on parallel)
+  OwningOpRef<ParallelOp> parallelOp =
+      ParallelOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Create dominance info
+  DominanceInfo domInfo(funcOp.get());
+  PostDominanceInfo postDomInfo(funcOp.get());
+
+  // Get dominating data clauses
+  auto dataClauses =
+      getDominatingDataClauses(parallelOp.get(), domInfo, postDomInfo);
+
+  // Should contain the copyin from the enclosing data op
+  EXPECT_EQ(dataClauses.size(), 1ul);
+  EXPECT_EQ(dataClauses[0], copyinOp->getAccVar());
+}
+
+TEST_F(OpenACCUtilsTest, getDominatingDataClausesFromComputeAndEnclosingData) {
+  // Create a module to hold a function
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  Block *moduleBlock = module->getBody();
+
+  OpBuilder::InsertionGuard guard(b);
+  b.setInsertionPointToStart(moduleBlock);
+
+  // Create a function
+  auto funcType = b.getFunctionType({}, {});
+  OwningOpRef<func::FuncOp> funcOp =
+      func::FuncOp::create(b, loc, "test_func", funcType);
+  Block *funcBlock = funcOp->addEntryBlock();
+
+  b.setInsertionPointToStart(funcBlock);
+
+  // Create two memrefs for 
diff erent data clauses
+  auto memrefTy = MemRefType::get({10}, b.getI32Type());
+  OwningOpRef<memref::AllocaOp> allocOp1 =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr1 =
+      cast<TypedValue<PointerLikeType>>(allocOp1->getResult());
+
+  OwningOpRef<memref::AllocaOp> allocOp2 =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr2 =
+      cast<TypedValue<PointerLikeType>>(allocOp2->getResult());
+
+  // Create copyin ops
+  OwningOpRef<CopyinOp> copyinOp1 =
+      CopyinOp::create(b, loc, varPtr1, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"var1");
+  OwningOpRef<CopyinOp> copyinOp2 =
+      CopyinOp::create(b, loc, varPtr2, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"var2");
+
+  // Create a data op
+  OwningOpRef<DataOp> dataOp =
+      DataOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands for data op
+  dataOp->getDataClauseOperandsMutable().append(copyinOp1->getAccVar());
+
+  Region &dataRegion = dataOp->getRegion();
+  Block *dataBlock = &dataRegion.emplaceBlock();
+
+  b.setInsertionPointToStart(dataBlock);
+
+  // Create a parallel op inside the data region
+  OwningOpRef<ParallelOp> parallelOp =
+      ParallelOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands for parallel op
+  parallelOp->getDataClauseOperandsMutable().append(copyinOp2->getAccVar());
+
+  // Create dominance info
+  DominanceInfo domInfo(funcOp.get());
+  PostDominanceInfo postDomInfo(funcOp.get());
+
+  // Get dominating data clauses
+  auto dataClauses =
+      getDominatingDataClauses(parallelOp.get(), domInfo, postDomInfo);
+
+  // Should contain both copyins (from data op and parallel op)
+  EXPECT_EQ(dataClauses.size(), 2ul);
+  // Note: Order might not be guaranteed, so check both are present
+  EXPECT_TRUE(llvm::is_contained(dataClauses, copyinOp1->getAccVar()));
+  EXPECT_TRUE(llvm::is_contained(dataClauses, copyinOp2->getAccVar()));
+}
+
+TEST_F(OpenACCUtilsTest, getDominatingDataClausesWithDeclareDirectives) {
+  // Create a module to hold a function
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  Block *moduleBlock = module->getBody();
+
+  OpBuilder::InsertionGuard guard(b);
+  b.setInsertionPointToStart(moduleBlock);
+
+  // Create a function
+  auto funcType = b.getFunctionType({}, {});
+  OwningOpRef<func::FuncOp> funcOp =
+      func::FuncOp::create(b, loc, "test_func", funcType);
+  Block *funcBlock = funcOp->addEntryBlock();
+
+  b.setInsertionPointToStart(funcBlock);
+
+  // Create a memref for the declare directive
+  auto memrefTy = MemRefType::get({10}, b.getI32Type());
+  OwningOpRef<memref::AllocaOp> allocOp =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr =
+      cast<TypedValue<PointerLikeType>>(allocOp->getResult());
+
+  // Create a copyin op for declare
+  OwningOpRef<CopyinOp> copyinOp =
+      CopyinOp::create(b, loc, varPtr, /*structured=*/false, /*implicit=*/false,
+                       /*name=*/"declare_var");
+
+  // Create a declare_enter op
+  OwningOpRef<DeclareEnterOp> declareEnterOp = DeclareEnterOp::create(
+      b, loc, TypeRange{b.getType<acc::DeclareTokenType>()},
+      ValueRange{copyinOp->getAccVar()});
+
+  // Create a parallel op
+  OwningOpRef<ParallelOp> parallelOp =
+      ParallelOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Create a declare_exit op that post-dominates the parallel
+  OwningOpRef<DeclareExitOp> declareExitOp = DeclareExitOp::create(
+      b, loc, declareEnterOp->getToken(), ValueRange{copyinOp->getAccVar()});
+
+  // Add a return to complete the function
+  OwningOpRef<func::ReturnOp> returnOp = func::ReturnOp::create(b, loc);
+
+  // Create dominance info
+  DominanceInfo domInfo(funcOp.get());
+  PostDominanceInfo postDomInfo(funcOp.get());
+
+  // Get dominating data clauses
+  auto dataClauses =
+      getDominatingDataClauses(parallelOp.get(), domInfo, postDomInfo);
+
+  // Should contain the copyin from the declare directive
+  EXPECT_EQ(dataClauses.size(), 1ul);
+  EXPECT_EQ(dataClauses[0], copyinOp->getAccVar());
+}
+
+TEST_F(OpenACCUtilsTest, getDominatingDataClausesMultipleDataConstructs) {
+  // Create a module to hold a function
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  Block *moduleBlock = module->getBody();
+
+  OpBuilder::InsertionGuard guard(b);
+  b.setInsertionPointToStart(moduleBlock);
+
+  // Create a function
+  auto funcType = b.getFunctionType({}, {});
+  OwningOpRef<func::FuncOp> funcOp =
+      func::FuncOp::create(b, loc, "test_func", funcType);
+  Block *funcBlock = funcOp->addEntryBlock();
+
+  b.setInsertionPointToStart(funcBlock);
+
+  // Create three memrefs
+  auto memrefTy = MemRefType::get({10}, b.getI32Type());
+  OwningOpRef<memref::AllocaOp> allocOp1 =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr1 =
+      cast<TypedValue<PointerLikeType>>(allocOp1->getResult());
+
+  OwningOpRef<memref::AllocaOp> allocOp2 =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr2 =
+      cast<TypedValue<PointerLikeType>>(allocOp2->getResult());
+
+  OwningOpRef<memref::AllocaOp> allocOp3 =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr3 =
+      cast<TypedValue<PointerLikeType>>(allocOp3->getResult());
+
+  // Create copyin ops
+  OwningOpRef<CopyinOp> copyinOp1 =
+      CopyinOp::create(b, loc, varPtr1, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"var1");
+  OwningOpRef<CopyinOp> copyinOp2 =
+      CopyinOp::create(b, loc, varPtr2, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"var2");
+  OwningOpRef<CopyinOp> copyinOp3 =
+      CopyinOp::create(b, loc, varPtr3, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"var3");
+
+  // Create outer data op
+  OwningOpRef<DataOp> outerDataOp =
+      DataOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands for outer data op
+  outerDataOp->getDataClauseOperandsMutable().append(copyinOp1->getAccVar());
+
+  Region &outerDataRegion = outerDataOp->getRegion();
+  Block *outerDataBlock = &outerDataRegion.emplaceBlock();
+
+  b.setInsertionPointToStart(outerDataBlock);
+
+  // Create inner data op
+  OwningOpRef<DataOp> innerDataOp =
+      DataOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands for inner data op
+  innerDataOp->getDataClauseOperandsMutable().append(copyinOp2->getAccVar());
+
+  Region &innerDataRegion = innerDataOp->getRegion();
+  Block *innerDataBlock = &innerDataRegion.emplaceBlock();
+
+  b.setInsertionPointToStart(innerDataBlock);
+
+  // Create a parallel op
+  OwningOpRef<ParallelOp> parallelOp =
+      ParallelOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands for parallel op
+  parallelOp->getDataClauseOperandsMutable().append(copyinOp3->getAccVar());
+
+  // Create dominance info
+  DominanceInfo domInfo(funcOp.get());
+  PostDominanceInfo postDomInfo(funcOp.get());
+
+  // Get dominating data clauses
+  auto dataClauses =
+      getDominatingDataClauses(parallelOp.get(), domInfo, postDomInfo);
+
+  // Should contain all three copyins
+  EXPECT_EQ(dataClauses.size(), 3ul);
+  EXPECT_TRUE(llvm::is_contained(dataClauses, copyinOp1->getAccVar()));
+  EXPECT_TRUE(llvm::is_contained(dataClauses, copyinOp2->getAccVar()));
+  EXPECT_TRUE(llvm::is_contained(dataClauses, copyinOp3->getAccVar()));
+}
+
+TEST_F(OpenACCUtilsTest, getDominatingDataClausesKernelsOp) {
+  // Test with KernelsOp instead of ParallelOp
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  Block *moduleBlock = module->getBody();
+
+  OpBuilder::InsertionGuard guard(b);
+  b.setInsertionPointToStart(moduleBlock);
+
+  // Create a function
+  auto funcType = b.getFunctionType({}, {});
+  OwningOpRef<func::FuncOp> funcOp =
+      func::FuncOp::create(b, loc, "test_func", funcType);
+  Block *funcBlock = funcOp->addEntryBlock();
+
+  b.setInsertionPointToStart(funcBlock);
+
+  // Create a memref
+  auto memrefTy = MemRefType::get({10}, b.getI32Type());
+  OwningOpRef<memref::AllocaOp> allocOp =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr =
+      cast<TypedValue<PointerLikeType>>(allocOp->getResult());
+
+  // Create a copyin op
+  OwningOpRef<CopyinOp> copyinOp =
+      CopyinOp::create(b, loc, varPtr, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"test_var");
+
+  // Create a kernels op
+  OwningOpRef<KernelsOp> kernelsOp =
+      KernelsOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands
+  kernelsOp->getDataClauseOperandsMutable().append(copyinOp->getAccVar());
+
+  // Create dominance info
+  DominanceInfo domInfo(funcOp.get());
+  PostDominanceInfo postDomInfo(funcOp.get());
+
+  // Get dominating data clauses
+  auto dataClauses =
+      getDominatingDataClauses(kernelsOp.get(), domInfo, postDomInfo);
+
+  // Should contain the copyin from the kernels op
+  EXPECT_EQ(dataClauses.size(), 1ul);
+  EXPECT_EQ(dataClauses[0], copyinOp->getAccVar());
+}
+
+TEST_F(OpenACCUtilsTest, getDominatingDataClausesSerialOp) {
+  // Test with SerialOp
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  Block *moduleBlock = module->getBody();
+
+  OpBuilder::InsertionGuard guard(b);
+  b.setInsertionPointToStart(moduleBlock);
+
+  // Create a function
+  auto funcType = b.getFunctionType({}, {});
+  OwningOpRef<func::FuncOp> funcOp =
+      func::FuncOp::create(b, loc, "test_func", funcType);
+  Block *funcBlock = funcOp->addEntryBlock();
+
+  b.setInsertionPointToStart(funcBlock);
+
+  // Create a memref
+  auto memrefTy = MemRefType::get({10}, b.getI32Type());
+  OwningOpRef<memref::AllocaOp> allocOp =
+      memref::AllocaOp::create(b, loc, memrefTy);
+  TypedValue<PointerLikeType> varPtr =
+      cast<TypedValue<PointerLikeType>>(allocOp->getResult());
+
+  // Create a copyin op
+  OwningOpRef<CopyinOp> copyinOp =
+      CopyinOp::create(b, loc, varPtr, /*structured=*/true, /*implicit=*/false,
+                       /*name=*/"test_var");
+
+  // Create a serial op
+  OwningOpRef<SerialOp> serialOp =
+      SerialOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Set the data clause operands
+  serialOp->getDataClauseOperandsMutable().append(copyinOp->getAccVar());
+
+  // Create dominance info
+  DominanceInfo domInfo(funcOp.get());
+  PostDominanceInfo postDomInfo(funcOp.get());
+
+  // Get dominating data clauses
+  auto dataClauses =
+      getDominatingDataClauses(serialOp.get(), domInfo, postDomInfo);
+
+  // Should contain the copyin from the serial op
+  EXPECT_EQ(dataClauses.size(), 1ul);
+  EXPECT_EQ(dataClauses[0], copyinOp->getAccVar());
+}
+
+TEST_F(OpenACCUtilsTest, getDominatingDataClausesEmpty) {
+  // Test with no data clauses at all
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  Block *moduleBlock = module->getBody();
+
+  OpBuilder::InsertionGuard guard(b);
+  b.setInsertionPointToStart(moduleBlock);
+
+  // Create a function
+  auto funcType = b.getFunctionType({}, {});
+  OwningOpRef<func::FuncOp> funcOp =
+      func::FuncOp::create(b, loc, "test_func", funcType);
+  Block *funcBlock = funcOp->addEntryBlock();
+
+  b.setInsertionPointToStart(funcBlock);
+
+  // Create a parallel op with no data clauses
+  OwningOpRef<ParallelOp> parallelOp =
+      ParallelOp::create(b, loc, TypeRange{}, ValueRange{});
+
+  // Create dominance info
+  DominanceInfo domInfo(funcOp.get());
+  PostDominanceInfo postDomInfo(funcOp.get());
+
+  // Get dominating data clauses
+  auto dataClauses =
+      getDominatingDataClauses(parallelOp.get(), domInfo, postDomInfo);
+
+  // Should be empty
+  EXPECT_EQ(dataClauses.size(), 0ul);
+}


        


More information about the Mlir-commits mailing list