[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