[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