[Mlir-commits] [mlir] [acc] Expand OpenACCSupport to provide getRecipeName and emitNYI (PR #165628)

Razvan Lupusoru llvmlistbot at llvm.org
Wed Oct 29 14:49:51 PDT 2025


https://github.com/razvanlupusoru created https://github.com/llvm/llvm-project/pull/165628

Extends OpenACCSupport utilities to include recipe name generation and error reporting for unsupported features, providing foundation for variable privatization handling.

Changes:
- Add RecipeKind enum (private, firstprivate, reduction) for APIs that request a specific kind of recipe
- Add getRecipeName() API to OpenACCSupport and OpenACCUtils that generates recipe names from types (e.g., "privatization_memref_5x10xf32_")
- Add emitNYI() API to OpenACCSupport for graceful handling of not-yet-implemented cases
- Generalize MemRefPointerLikeModel template to support UnrankedMemRefType
- Add unit tests and integration tests for new APIs

>From add0d0584a22ca57a2992c6dece0a7f280f68a27 Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Wed, 29 Oct 2025 14:48:32 -0700
Subject: [PATCH] [acc] Expand OpenACCSupport to provide getRecipeName and
 emitNYI

Extends OpenACCSupport utilities to include recipe name
generation and error reporting for unsupported features,
providing foundation for variable privatization handling.

Changes:
- Add RecipeKind enum (private, firstprivate, reduction) for
  APIs that request a specific kind of recipe
- Add getRecipeName() API to OpenACCSupport and OpenACCUtils
  that generates recipe names from types (e.g.,
  "privatization_memref_5x10xf32_")
- Add emitNYI() API to OpenACCSupport for graceful handling
  of not-yet-implemented cases
- Generalize MemRefPointerLikeModel template to support
  UnrankedMemRefType
- Add unit tests and integration tests for new APIs
---
 .../Dialect/OpenACC/Analysis/OpenACCSupport.h | 36 ++++++++
 .../mlir/Dialect/OpenACC/OpenACCOps.td        | 20 +++++
 .../mlir/Dialect/OpenACC/OpenACCUtils.h       |  8 ++
 .../OpenACC/Analysis/OpenACCSupport.cpp       | 20 +++++
 mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp       | 13 +--
 .../Dialect/OpenACC/Utils/OpenACCUtils.cpp    | 39 +++++++++
 .../OpenACC/support-analysis-recipename.mlir  | 78 +++++++++++++++++
 .../OpenACC/support-analysis-unsupported.mlir | 18 ++++
 .../Dialect/OpenACC/TestOpenACCSupport.cpp    | 22 +++++
 .../Dialect/OpenACC/OpenACCUtilsTest.cpp      | 85 +++++++++++++++++++
 10 files changed, 334 insertions(+), 5 deletions(-)
 create mode 100644 mlir/test/Dialect/OpenACC/support-analysis-recipename.mlir
 create mode 100644 mlir/test/Dialect/OpenACC/support-analysis-unsupported.mlir

diff --git a/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h b/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
index 0833462ea0509..d9b2646b753f3 100644
--- a/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
+++ b/mlir/include/mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h
@@ -58,6 +58,9 @@
 namespace mlir {
 namespace acc {
 
+// Forward declaration for RecipeKind enum
+enum class RecipeKind : uint32_t;
+
 namespace detail {
 /// This class contains internal trait classes used by OpenACCSupport.
 /// It follows the Concept-Model pattern used throughout MLIR (e.g., in
@@ -69,6 +72,13 @@ struct OpenACCSupportTraits {
 
     /// Get the variable name for a given MLIR value.
     virtual std::string getVariableName(Value v) = 0;
+
+    /// Get the recipe name for a given kind, type and value.
+    virtual std::string getRecipeName(RecipeKind kind, Type type,
+                                      Value var) = 0;
+
+    // Used to report a case that is not supported by the implementation.
+    virtual InFlightDiagnostic emitNYI(Location loc, const Twine &message) = 0;
   };
 
   /// This class wraps a concrete OpenACCSupport implementation and forwards
@@ -84,6 +94,14 @@ struct OpenACCSupportTraits {
       return impl.getVariableName(v);
     }
 
+    std::string getRecipeName(RecipeKind kind, Type type, Value var) final {
+      return impl.getRecipeName(kind, type, var);
+    }
+
+    InFlightDiagnostic emitNYI(Location loc, const Twine &message) final {
+      return impl.emitNYI(loc, message);
+    }
+
   private:
     ImplT impl;
   };
@@ -118,6 +136,24 @@ class OpenACCSupport {
   /// \return The variable name, or an empty string if unavailable.
   std::string getVariableName(Value v);
 
+  /// Get the recipe name for a given type and value.
+  ///
+  /// \param kind The kind of recipe to get the name for.
+  /// \param type The type to get the recipe name for. Can be null if the
+  ///        var is provided instead.
+  /// \param var The MLIR value to get the recipe name for. Can be null if
+  ///        the type is provided instead.
+  /// \return The recipe name, or an empty string if not available.
+  std::string getRecipeName(RecipeKind kind, Type type, Value var);
+
+  /// Report a case that is not yet supported by the implementation.
+  ///
+  /// \param loc The location to report the unsupported case at.
+  /// \param message The message to report.
+  /// \return An in-flight diagnostic object that can be used to report the
+  ///         unsupported case.
+  InFlightDiagnostic emitNYI(Location loc, const Twine &message);
+
   /// Signal that this analysis should always be preserved so that
   /// underlying implementation registration is not lost.
   bool isInvalidated(const AnalysisManager::PreservedAnalyses &pa) {
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index a18c18af8a753..2f4517ddfe754 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -152,6 +152,26 @@ def OpenACC_LoopParMode : I32EnumAttr<
   let genSpecializedAttr = 0;
 }
 
+def OpenACC_PrivateRecipe : I32EnumAttrCase<"private_recipe", 0>;
+def OpenACC_FirstprivateRecipe : I32EnumAttrCase<"firstprivate_recipe", 1>;
+def OpenACC_ReductionRecipe : I32EnumAttrCase<"reduction_recipe", 2>;
+
+def OpenACC_RecipeKind : I32EnumAttr<
+    "RecipeKind",
+    "Encodes the options for kinds of recipes availabie in acc dialect",
+    [
+      OpenACC_PrivateRecipe, OpenACC_FirstprivateRecipe,
+      OpenACC_ReductionRecipe]> {
+  let cppNamespace = "::mlir::acc";
+  let genSpecializedAttr = 0;
+}
+
+def OpenACC_RecipeKindAttr : EnumAttr<OpenACC_Dialect,
+                                             OpenACC_RecipeKind,
+                                             "recipe_kind"> {
+  let assemblyFormat = [{ ```<` $value `>` }];
+}
+
 // Type used in operation below.
 def IntOrIndex : AnyTypeOf<[AnyInteger, Index]>;
 
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h
index 0ee88c6f47b67..98a30c8d9530a 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCUtils.h
@@ -43,6 +43,14 @@ mlir::acc::VariableTypeCategory getTypeCategory(mlir::Value var);
 /// empty string if no name is found.
 std::string getVariableName(mlir::Value v);
 
+/// Get the recipe name for a given kind, type and value.
+///
+/// \param kind The kind of recipe to get the name for.
+/// \param type The type to get the recipe name for. Can be null if the
+///        var is provided instead.
+/// \return The recipe name, or an empty string if not available.
+std::string getRecipeName(mlir::acc::RecipeKind kind, mlir::Type type);
+
 } // namespace acc
 } // namespace mlir
 
diff --git a/mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp b/mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp
index f6b4534794eaf..78d0e9ab6369c 100644
--- a/mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp
+++ b/mlir/lib/Dialect/OpenACC/Analysis/OpenACCSupport.cpp
@@ -22,5 +22,25 @@ std::string OpenACCSupport::getVariableName(Value v) {
   return acc::getVariableName(v);
 }
 
+std::string OpenACCSupport::getRecipeName(RecipeKind kind, Type type,
+                                          Value var) {
+  if (impl)
+    return impl->getRecipeName(kind, type, var);
+  // The default implementation assumes that only type matters
+  // and the actual instance of variable is not relevant.
+  auto recipeName = acc::getRecipeName(kind, type);
+  if (recipeName.empty())
+    emitNYI(var ? var.getLoc() : UnknownLoc::get(type.getContext()),
+            "variable privatization (incomplete recipe name handling)");
+  return recipeName;
+}
+
+InFlightDiagnostic OpenACCSupport::emitNYI(Location loc,
+                                                   const Twine &message) {
+  if (impl)
+    return impl->emitNYI(loc, message);
+  return mlir::emitError(loc, "not yet implemented: " + message);
+}
+
 } // namespace acc
 } // namespace mlir
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index ca46629919dba..35eba724a9059 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -50,11 +50,11 @@ static void attachVarNameAttr(Operation *op, OpBuilder &builder,
   }
 }
 
+template <typename T>
 struct MemRefPointerLikeModel
-    : public PointerLikeType::ExternalModel<MemRefPointerLikeModel,
-                                            MemRefType> {
+    : public PointerLikeType::ExternalModel<MemRefPointerLikeModel<T>, T> {
   Type getElementType(Type pointer) const {
-    return cast<MemRefType>(pointer).getElementType();
+    return cast<T>(pointer).getElementType();
   }
 
   mlir::acc::VariableTypeCategory
@@ -63,7 +63,7 @@ struct MemRefPointerLikeModel
     if (auto mappableTy = dyn_cast<MappableType>(varType)) {
       return mappableTy.getTypeCategory(varPtr);
     }
-    auto memrefTy = cast<MemRefType>(pointer);
+    auto memrefTy = cast<T>(pointer);
     if (!memrefTy.hasRank()) {
       // This memref is unranked - aka it could have any rank, including a
       // rank of 0 which could mean scalar. For now, return uncategorized.
@@ -296,7 +296,10 @@ void OpenACCDialect::initialize() {
   // By attaching interfaces here, we make the OpenACC dialect dependent on
   // the other dialects. This is probably better than having dialects like LLVM
   // and memref be dependent on OpenACC.
-  MemRefType::attachInterface<MemRefPointerLikeModel>(*getContext());
+  MemRefType::attachInterface<MemRefPointerLikeModel<MemRefType>>(
+      *getContext());
+  UnrankedMemRefType::attachInterface<
+      MemRefPointerLikeModel<UnrankedMemRefType>>(*getContext());
   LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
       *getContext());
 }
diff --git a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp
index 89adda82646e6..660c3138af0ec 100644
--- a/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp
+++ b/mlir/lib/Dialect/OpenACC/Utils/OpenACCUtils.cpp
@@ -11,6 +11,7 @@
 #include "mlir/Dialect/OpenACC/OpenACC.h"
 #include "mlir/Interfaces/ViewLikeInterface.h"
 #include "llvm/ADT/TypeSwitch.h"
+#include "llvm/Support/Casting.h"
 
 mlir::Operation *mlir::acc::getEnclosingComputeOp(mlir::Region &region) {
   mlir::Operation *parentOp = region.getParentOp();
@@ -106,3 +107,41 @@ std::string mlir::acc::getVariableName(mlir::Value v) {
 
   return "";
 }
+
+std::string mlir::acc::getRecipeName(mlir::acc::RecipeKind kind,
+                                     mlir::Type type) {
+  assert(kind == mlir::acc::RecipeKind::private_recipe ||
+         kind == mlir::acc::RecipeKind::firstprivate_recipe ||
+         kind == mlir::acc::RecipeKind::reduction_recipe);
+  if (!llvm::isa<mlir::acc::PointerLikeType, mlir::acc::MappableType>(type))
+    return "";
+
+  std::string recipeName;
+  llvm::raw_string_ostream ss(recipeName);
+  ss << (kind == mlir::acc::RecipeKind::private_recipe ? "privatization_"
+         : kind == mlir::acc::RecipeKind::firstprivate_recipe
+             ? "firstprivatization_"
+             : "reduction_");
+
+  // Print the type using its dialect-defined textual format.
+  type.print(ss);
+  ss.flush();
+
+  // Replace invalid characters (anything that's not a letter, number, or
+  // period) since this needs to be a valid MLIR identifier.
+  for (char &c : recipeName) {
+    if (!std::isalnum(static_cast<unsigned char>(c)) && c != '.' && c != '_') {
+      if (c == '?')
+        c = 'U';
+      else if (c == '*')
+        c = 'Z';
+      else if (c == '(' || c == ')' || c == '[' || c == ']' || c == '{' ||
+               c == '}' || c == '<' || c == '>')
+        c = '_';
+      else
+        c = 'X';
+    }
+  }
+
+  return recipeName;
+}
diff --git a/mlir/test/Dialect/OpenACC/support-analysis-recipename.mlir b/mlir/test/Dialect/OpenACC/support-analysis-recipename.mlir
new file mode 100644
index 0000000000000..8ea53b5d0f4d4
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/support-analysis-recipename.mlir
@@ -0,0 +1,78 @@
+// RUN: mlir-opt %s -split-input-file -test-acc-support | FileCheck %s
+
+// Test private recipe with 2D memref
+func.func @test_private_2d_memref() {
+  // Create a 2D memref
+  %0 = memref.alloca() {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<5x10xf32>
+
+  // CHECK: op=%{{.*}} = memref.alloca() {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<5x10xf32>
+  // CHECK-NEXT: getRecipeName(kind=private_recipe, type=memref<5x10xf32>)="privatization_memref_5x10xf32_"
+
+  return
+}
+
+// -----
+
+// Test firstprivate recipe with 2D memref
+func.func @test_firstprivate_2d_memref() {
+  // Create a 2D memref
+  %0 = memref.alloca() {test.recipe_name = #acc.recipe_kind<firstprivate_recipe>} : memref<8x16xf64>
+
+  // CHECK: op=%{{.*}} = memref.alloca() {test.recipe_name = #acc.recipe_kind<firstprivate_recipe>} : memref<8x16xf64>
+  // CHECK-NEXT: getRecipeName(kind=firstprivate_recipe, type=memref<8x16xf64>)="firstprivatization_memref_8x16xf64_"
+
+  return
+}
+
+// -----
+
+// Test reduction recipe with 2D memref
+func.func @test_reduction_2d_memref() {
+  // Create a 2D memref
+  %0 = memref.alloca() {test.recipe_name = #acc.recipe_kind<reduction_recipe>} : memref<4x8xi32>
+
+  // CHECK: op=%{{.*}} = memref.alloca() {test.recipe_name = #acc.recipe_kind<reduction_recipe>} : memref<4x8xi32>
+  // CHECK-NEXT: getRecipeName(kind=reduction_recipe, type=memref<4x8xi32>)="reduction_memref_4x8xi32_"
+
+  return
+}
+
+// -----
+
+// Test private recipe with dynamic memref
+func.func @test_private_dynamic_memref(%arg0: memref<5x10xi32>) {
+  // Cast to dynamic dimensions
+  %0 = memref.cast %arg0 {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<5x10xi32> to memref<?x10xi32>
+
+  // CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<5x10xi32> to memref<?x10xi32>
+  // CHECK-NEXT: getRecipeName(kind=private_recipe, type=memref<?x10xi32>)="privatization_memref_Ux10xi32_"
+
+  return
+}
+
+// -----
+
+// Test private recipe with scalar memref
+func.func @test_private_scalar_memref() {
+  // Create a scalar memref (no dimensions)
+  %0 = memref.alloca() {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<i32>
+
+  // CHECK: op=%{{.*}} = memref.alloca() {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<i32>
+  // CHECK-NEXT: getRecipeName(kind=private_recipe, type=memref<i32>)="privatization_memref_i32_"
+
+  return
+}
+
+// -----
+
+// Test private recipe with unranked memref
+func.func @test_private_unranked_memref(%arg0: memref<10xi32>) {
+  // Cast to unranked memref
+  %0 = memref.cast %arg0 {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<10xi32> to memref<*xi32>
+
+  // CHECK: op=%{{.*}} = memref.cast %{{.*}} {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<10xi32> to memref<*xi32>
+  // CHECK-NEXT: getRecipeName(kind=private_recipe, type=memref<*xi32>)="privatization_memref_Zxi32_"
+
+  return
+}
+
diff --git a/mlir/test/Dialect/OpenACC/support-analysis-unsupported.mlir b/mlir/test/Dialect/OpenACC/support-analysis-unsupported.mlir
new file mode 100644
index 0000000000000..c4d5b81a1380a
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/support-analysis-unsupported.mlir
@@ -0,0 +1,18 @@
+// RUN: mlir-opt %s --split-input-file -test-acc-support -verify-diagnostics
+
+// Test emitNYI with a simple message
+func.func @test_emit_nyi() {
+  // expected-error @below {{not yet implemented: Unsupported feature in OpenACC}}
+  %0 = memref.alloca() {test.emit_nyi = "Unsupported feature in OpenACC"} : memref<10xi32>
+  return
+}
+
+// -----
+
+// Test recipe name on load operation from scalar memref
+func.func @test_recipe_load_scalar() {
+  %0 = memref.alloca() : memref<i32>
+  // expected-error @below {{not yet implemented: variable privatization (incomplete recipe name handling)}}
+  %1 = memref.load %0[] {test.recipe_name = #acc.recipe_kind<private_recipe>} : memref<i32>
+  return
+}
diff --git a/mlir/test/lib/Dialect/OpenACC/TestOpenACCSupport.cpp b/mlir/test/lib/Dialect/OpenACC/TestOpenACCSupport.cpp
index 8bf984bdc2632..7c8b08489c62e 100644
--- a/mlir/test/lib/Dialect/OpenACC/TestOpenACCSupport.cpp
+++ b/mlir/test/lib/Dialect/OpenACC/TestOpenACCSupport.cpp
@@ -57,6 +57,28 @@ void TestOpenACCSupportPass::runOnOperation() {
                      << "\"\n";
       }
     }
+
+    // Check for test.recipe_name attribute. This is the marker used to identify
+    // the operations that need to be tested for getRecipeName.
+    if (auto recipeAttr =
+            op->getAttrOfType<RecipeKindAttr>("test.recipe_name")) {
+      RecipeKind kind = recipeAttr.getValue();
+      // Get the type from the first result if available
+      if (op->getNumResults() > 0) {
+        Type type = op->getResult(0).getType();
+        std::string recipeName =
+            support.getRecipeName(kind, type, op->getResult(0));
+        llvm::outs() << "op=" << *op
+                     << "\n\tgetRecipeName(kind=" << stringifyRecipeKind(kind)
+                     << ", type=" << type << ")=\"" << recipeName << "\"\n";
+      }
+    }
+
+    // Check for test.emit_nyi attribute. This is the marker used to
+    // test whether the not yet implemented case is reported correctly.
+    if (auto messageAttr = op->getAttrOfType<StringAttr>("test.emit_nyi")) {
+      support.emitNYI(op->getLoc(), messageAttr.getValue());
+    }
   });
 }
 
diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp
index 3fbbcc90a67c9..f1fe53c15a6f5 100644
--- a/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCUtilsTest.cpp
@@ -485,3 +485,88 @@ TEST_F(OpenACCUtilsTest, getVariableNameFromCopyin) {
   std::string varName = getVariableName(copyinOp->getAccVar());
   EXPECT_EQ(varName, name);
 }
+
+//===----------------------------------------------------------------------===//
+// getRecipeName Tests
+//===----------------------------------------------------------------------===//
+
+TEST_F(OpenACCUtilsTest, getRecipeNamePrivateScalarMemref) {
+  // Create a scalar memref type
+  auto scalarMemrefTy = MemRefType::get({}, b.getI32Type());
+
+  // Test private recipe with scalar memref
+  std::string recipeName =
+      getRecipeName(RecipeKind::private_recipe, scalarMemrefTy);
+  EXPECT_EQ(recipeName, "privatization_memref_i32_");
+}
+
+TEST_F(OpenACCUtilsTest, getRecipeNameFirstprivateScalarMemref) {
+  // Create a scalar memref type
+  auto scalarMemrefTy = MemRefType::get({}, b.getF32Type());
+
+  // Test firstprivate recipe with scalar memref
+  std::string recipeName =
+      getRecipeName(RecipeKind::firstprivate_recipe, scalarMemrefTy);
+  EXPECT_EQ(recipeName, "firstprivatization_memref_f32_");
+}
+
+TEST_F(OpenACCUtilsTest, getRecipeNameReductionScalarMemref) {
+  // Create a scalar memref type
+  auto scalarMemrefTy = MemRefType::get({}, b.getI64Type());
+
+  // Test reduction recipe with scalar memref
+  std::string recipeName =
+      getRecipeName(RecipeKind::reduction_recipe, scalarMemrefTy);
+  EXPECT_EQ(recipeName, "reduction_memref_i64_");
+}
+
+TEST_F(OpenACCUtilsTest, getRecipeNamePrivate2DMemref) {
+  // Create a 2D memref type
+  auto memref2DTy = MemRefType::get({5, 10}, b.getF32Type());
+
+  // Test private recipe with 2D memref
+  std::string recipeName =
+      getRecipeName(RecipeKind::private_recipe, memref2DTy);
+  EXPECT_EQ(recipeName, "privatization_memref_5x10xf32_");
+}
+
+TEST_F(OpenACCUtilsTest, getRecipeNameFirstprivate2DMemref) {
+  // Create a 2D memref type
+  auto memref2DTy = MemRefType::get({8, 16}, b.getF64Type());
+
+  // Test firstprivate recipe with 2D memref
+  std::string recipeName =
+      getRecipeName(RecipeKind::firstprivate_recipe, memref2DTy);
+  EXPECT_EQ(recipeName, "firstprivatization_memref_8x16xf64_");
+}
+
+TEST_F(OpenACCUtilsTest, getRecipeNameReduction2DMemref) {
+  // Create a 2D memref type
+  auto memref2DTy = MemRefType::get({4, 8}, b.getI32Type());
+
+  // Test reduction recipe with 2D memref
+  std::string recipeName =
+      getRecipeName(RecipeKind::reduction_recipe, memref2DTy);
+  EXPECT_EQ(recipeName, "reduction_memref_4x8xi32_");
+}
+
+TEST_F(OpenACCUtilsTest, getRecipeNamePrivateDynamicMemref) {
+  // Create a memref with dynamic dimensions
+  auto dynamicMemrefTy =
+      MemRefType::get({ShapedType::kDynamic, 10}, b.getI32Type());
+
+  // Test private recipe with dynamic memref
+  std::string recipeName =
+      getRecipeName(RecipeKind::private_recipe, dynamicMemrefTy);
+  EXPECT_EQ(recipeName, "privatization_memref_Ux10xi32_");
+}
+
+TEST_F(OpenACCUtilsTest, getRecipeNamePrivateUnrankedMemref) {
+  // Create an unranked memref type
+  auto unrankedMemrefTy = UnrankedMemRefType::get(b.getI32Type(), 0);
+
+  // Test private recipe with unranked memref
+  std::string recipeName =
+      getRecipeName(RecipeKind::private_recipe, unrankedMemrefTy);
+  EXPECT_EQ(recipeName, "privatization_memref_Zxi32_");
+}



More information about the Mlir-commits mailing list