[Mlir-commits] [mlir] f9c2117 - [acc] Add an API to make private recipes out of firstprivate recipes (#170588)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Dec 4 14:08:38 PST 2025
Author: Susan Tan (ス-ザン タン)
Date: 2025-12-04T17:08:34-05:00
New Revision: f9c2117b860e4b56f37be3c7c5f736065139eb12
URL: https://github.com/llvm/llvm-project/commit/f9c2117b860e4b56f37be3c7c5f736065139eb12
DIFF: https://github.com/llvm/llvm-project/commit/f9c2117b860e4b56f37be3c7c5f736065139eb12.diff
LOG: [acc] Add an API to make private recipes out of firstprivate recipes (#170588)
In cases of optimizations promoting firstprivate to private, this API
would be useful.
Added:
mlir/test/Dialect/OpenACC/recipe-populate-private-from-firstprivate.mlir
Modified:
mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
mlir/test/lib/Dialect/OpenACC/TestRecipePopulate.cpp
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 7a727bd7fb838..e968c2b151f5a 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -1394,6 +1394,19 @@ 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 useful in cases where we promote private variables to firstprivate by analysis
+ /// This function reuses the init region from a firstprivate recipe when building a private
+ /// recipe. Callers thus must ensure that this is semantically valid for the language
+ /// lowering (e.g. that private does not perform extra default initialization
+ /// that firstprivate intentionally omits, such as for C++ classes or Fortran
+ /// derived types with default initialization).
+ 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 029b1eee8e93d..7b91393c0314f 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,28 @@ 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
+ IRMapping mapping;
+ firstprivRecipe.getInitRegion().cloneInto(&recipe.getInitRegion(), mapping);
+
+ // Clone destroy region if the firstprivate.recipe has one.
+ if (!firstprivRecipe.getDestroyRegion().empty()) {
+ IRMapping mapping;
+ firstprivRecipe.getDestroyRegion().cloneInto(&recipe.getDestroyRegion(),
+ mapping);
+ }
+ 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..154d44e31d027
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/recipe-populate-private-from-firstprivate.mlir
@@ -0,0 +1,38 @@
+// 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. For a simple scalar
+// alloca-backed memref, only an init region is expected (no destroy).
+// 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_from_firstprivate() {
+ %0 = memref.alloca() {test.var = "scalar"} : memref<f32>
+ return
+}
+
+// -----
+
+// Verify that destroy regions are also present when creating a private recipe
+// from a firstprivate recipe that requires dynamic deallocation.
+// CHECK: acc.private.recipe @private_from_firstprivate_dynamic_d2 : memref<?x?xf32> init {
+// CHECK: ^bb0(%[[ARG:.*]]: memref<?x?xf32>):
+// CHECK: %[[C0:.*]] = arith.constant 0 : index
+// CHECK: %[[DIM0:.*]] = memref.dim %[[ARG]], %[[C0]] : memref<?x?xf32>
+// CHECK: %[[C1:.*]] = arith.constant 1 : index
+// CHECK: %[[DIM1:.*]] = memref.dim %[[ARG]], %[[C1]] : memref<?x?xf32>
+// CHECK: %[[ALLOC:.*]] = memref.alloc(%[[DIM0]], %[[DIM1]]) {acc.var_name = #acc.var_name<"dynamic_d2">} : memref<?x?xf32>
+// CHECK: acc.yield %[[ALLOC]] : memref<?x?xf32>
+// CHECK: } destroy {
+// CHECK: ^bb0(%{{.*}}: memref<?x?xf32>, %[[VAL:.*]]: memref<?x?xf32>):
+// CHECK: memref.dealloc %[[VAL]] : memref<?x?xf32>
+// CHECK: acc.terminator
+// CHECK: }
+
+func.func @test_dynamic_from_firstprivate(%arg0: index, %arg1: index) {
+ %0 = memref.alloc(%arg0, %arg1) {test.var = "dynamic_d2"} : memref<?x?xf32>
+ 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;
+ }
}
}
}
More information about the Mlir-commits
mailing list