[Mlir-commits] [mlir] [acc] Add an API to make private recipe out of firstprivate recipes (PR #170588)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Dec 3 16:55:17 PST 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-openacc
@llvm/pr-subscribers-mlir-openacc
Author: Susan Tan (ス-ザン タン) (SusanTan)
<details>
<summary>Changes</summary>
In cases of optimizations promoting firstprivate to private, this API would be useful.
---
Full diff: https://github.com/llvm/llvm-project/pull/170588.diff
4 Files Affected:
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+9)
- (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+33)
- (added) mlir/test/Dialect/OpenACC/recipe-populate-private-from-firstprivate.mlir (+17)
- (modified) mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp (+23)
``````````diff
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index fcfe959709f09..ada77479ce4a3 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -1394,6 +1394,15 @@ def OpenACC_PrivateRecipeOp
::mlir::Type varType,
::llvm::StringRef varName = "",
::mlir::ValueRange bounds = {});
+
+ /// Creates a PrivateRecipeOp using the same variable type as an existing
+ /// FirstprivateRecipeOp. This is a convenience wrapper that forwards to
+ /// the type-based createAndPopulate overload.
+ static std::optional<PrivateRecipeOp> createAndPopulate(
+ ::mlir::OpBuilder &builder,
+ ::mlir::Location loc,
+ ::llvm::StringRef recipeName,
+ ::mlir::acc::FirstprivateRecipeOp firstprivRecipe);
}];
}
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index 9235f89b7969a..9f4f587a387f4 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -15,6 +15,7 @@
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/DialectImplementation.h"
+#include "mlir/IR/IRMapping.h"
#include "mlir/IR/Matchers.h"
#include "mlir/IR/OpImplementation.h"
#include "mlir/IR/SymbolTable.h"
@@ -1449,6 +1450,38 @@ PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
return recipe;
}
+std::optional<PrivateRecipeOp>
+PrivateRecipeOp::createAndPopulate(OpBuilder &builder, Location loc,
+ StringRef recipeName,
+ FirstprivateRecipeOp firstprivRecipe) {
+ // Create the private.recipe op with the same type as the firstprivate.recipe.
+ OpBuilder::InsertionGuard guard(builder);
+ auto varType = firstprivRecipe.getType();
+ auto recipe = PrivateRecipeOp::create(builder, loc, recipeName, varType);
+
+ // Clone the init region: same argument list (original + bounds...), same
+ // body, same yield value. This matches PrivateRecipeOp's expected init
+ // signature.
+ {
+ IRMapping mapping;
+ firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
+ }
+
+ // Clone destroy region if the firstprivate.recipe has one. The destroy region
+ // signatures (original, privatized, bounds...) are compatible between the
+ // two.
+ if (!firstprivRecipe.getDestroyRegion().empty()) {
+ IRMapping mapping;
+ firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
+ mapping);
+ }
+
+ // The copy region from firstprivate is intentionally ignored: private recipes
+ // only have init + optional destroy.
+
+ return recipe;
+}
+
//===----------------------------------------------------------------------===//
// FirstprivateRecipeOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/OpenACC/recipe-populate-private-from-firstprivate.mlir b/mlir/test/Dialect/OpenACC/recipe-populate-private-from-firstprivate.mlir
new file mode 100644
index 0000000000000..a315a7b4b5b3e
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/recipe-populate-private-from-firstprivate.mlir
@@ -0,0 +1,17 @@
+// RUN: mlir-opt %s --split-input-file --pass-pipeline="builtin.module(test-acc-recipe-populate{recipe-type=private_from_firstprivate})" | FileCheck %s
+
+// Verify that we can create a private recipe using the convenience overload
+// that takes an existing firstprivate recipe as input.
+// CHECK: acc.firstprivate.recipe @first_firstprivate_scalar : memref<f32> init
+// CHECK: acc.private.recipe @private_from_firstprivate_scalar : memref<f32> init {
+// CHECK: ^bb0(%{{.*}}: memref<f32>):
+// CHECK: %[[ALLOC:.*]] = memref.alloca() {acc.var_name = #acc.var_name<"scalar">} : memref<f32>
+// CHECK: acc.yield %[[ALLOC]] : memref<f32>
+// CHECK: }
+
+func.func @test_scalar() {
+ %0 = memref.alloca() {test.var = "scalar"} : memref<f32>
+ return
+}
+
+
diff --git a/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp b/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp
index 35f092c2188a6..2506ca4fc39ce 100644
--- a/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp
+++ b/mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp
@@ -93,6 +93,29 @@ void TestRecipePopulatePass::runOnOperation() {
if (!recipe) {
op->emitError("Failed to create firstprivate recipe for ") << varName;
}
+ } else if (recipeType == "private_from_firstprivate") {
+ // First create a firstprivate recipe, then use it to drive creation of a
+ // matching private recipe via the convenience overload. Give each recipe
+ // a stable, predictable name so tests can check both.
+ std::string firstprivName = "first_firstprivate_" + varName;
+ std::string privName = "private_from_firstprivate_" + varName;
+
+ auto firstpriv = FirstprivateRecipeOp::createAndPopulate(
+ builder, loc, firstprivName, var.getType(), varName, bounds);
+
+ if (!firstpriv) {
+ op->emitError("Failed to create firstprivate recipe for ") << varName;
+ return;
+ }
+
+ auto priv = PrivateRecipeOp::createAndPopulate(builder, loc, privName,
+ *firstpriv);
+
+ if (!priv) {
+ op->emitError(
+ "Failed to create private recipe (from firstprivate) for ")
+ << varName;
+ }
}
}
}
``````````
</details>
https://github.com/llvm/llvm-project/pull/170588
More information about the Mlir-commits
mailing list