[Mlir-commits] [mlir] [mlir][acc] Add operation for private handle to memref (PR #201603)

Razvan Lupusoru llvmlistbot at llvm.org
Thu Jun 4 07:50:11 PDT 2026


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

This MR introduces a new operation `acc.unwrap_private` for creating a pointer-like view of the `acc.private_type` handle. This operation will be used when materializing `acc.private_local` into the memory view needed to access the allocated private memory. This new operation is just a simple cast and thus it gets ViewLikeOpInterface attached to it.

Additionally, `acc.private_type` is now treated as a pointer-like type to ease conversions to other pointer-like types via PointerLikeType::genCast.

>From 883a17d7232724e001d0ec5ca310c3e362f3d81c Mon Sep 17 00:00:00 2001
From: Razvan Lupusoru <rlupusoru at nvidia.com>
Date: Thu, 4 Jun 2026 07:45:06 -0700
Subject: [PATCH] [mlir][acc] Add operation for private handle to memref

This MR introduces a new operation `acc.unwrap_private`
for creating a pointer-like view of the `acc.private_type`
handle. This operation will be used when materializing
`acc.private_local` into the memory view needed to access
the allocated private memory. This new operation is
just a simple cast and thus it gets ViewLikeOpInterface
attached to it.

Additionally, `acc.private_type` is now treated as a
pointer-like type to ease conversions to other pointer-like
types via PointerLikeType::genCast.
---
 mlir/include/mlir/Dialect/OpenACC/OpenACC.h   |  1 +
 .../mlir/Dialect/OpenACC/OpenACCCGOps.td      | 23 ++++++++++++++++
 mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp       | 18 +++++++++++++
 .../Dialect/OpenACC/ops-cg-privatization.mlir | 27 +++++++++++++++++++
 .../OpenACC/OpenACCTypeInterfacesTest.cpp     | 21 +++++++++++++++
 5 files changed, 90 insertions(+)

diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
index 682e8ff9784c8..d5cd04949c751 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
@@ -32,6 +32,7 @@
 #include "mlir/Interfaces/ControlFlowInterfaces.h"
 #include "mlir/Interfaces/LoopLikeInterface.h"
 #include "mlir/Interfaces/SideEffectInterfaces.h"
+#include "mlir/Interfaces/ViewLikeInterface.h"
 #include <variant>
 
 #define GET_TYPEDEF_CLASSES
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
index 9bca3b36c9785..13969f9fc9c65 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCCGOps.td
@@ -17,6 +17,7 @@
 #define OPENACC_CG_OPS
 
 include "mlir/Interfaces/InferTypeOpInterface.td"
+include "mlir/Interfaces/ViewLikeInterface.td"
 
 // This file is intended to be included from OpenACCOps.td, which provides
 // the necessary includes and definitions. The operations defined here use
@@ -253,6 +254,28 @@ def OpenACC_PrivatizeOp : OpenACC_Op<"privatize", []> {
   ];
 }
 
+//===----------------------------------------------------------------------===//
+// acc.unwrap_private
+//===----------------------------------------------------------------------===//
+
+def OpenACC_UnwrapPrivateOp
+    : OpenACC_Op<"unwrap_private",
+                 [NoMemoryEffect, AlwaysSpeculatable, ViewLikeOpInterface]> {
+  let summary = "Unwrap acc.private_type handle to pointer-like storage";
+  let description = [{
+    Converts a privatization handle (`acc.private_type<T>`) to a pointer-like
+    view of the underlying private storage.
+  }];
+  let arguments = (ins OpenACC_PrivateType:$handle);
+  let results = (outs OpenACC_PointerLikeType:$result);
+  let assemblyFormat = [{
+    $handle attr-dict `:` qualified(type($handle)) `to` type($result)
+  }];
+  let extraClassDeclaration = [{
+    ::mlir::Value getViewSource() { return getHandle(); }
+  }];
+}
+
 //===----------------------------------------------------------------------===//
 // acc.private_local
 //===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index f5ad1867086b6..ec8bac765ed33 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -346,6 +346,23 @@ struct LLVMPointerPointerLikeModel
   }
 };
 
+struct PrivateTypePointerLikeModel
+    : public PointerLikeType::ExternalModel<PrivateTypePointerLikeModel,
+                                            PrivateType> {
+  Type getElementType(Type type) const {
+    return cast<PrivateType>(type).getBaseTy();
+  }
+
+  Value genCast(Type, OpBuilder &builder, Location loc, Value value,
+                Type resultType) const {
+    if (value.getType() == resultType)
+      return value;
+    if (!isa<PointerLikeType>(resultType))
+      return {};
+    return UnwrapPrivateOp::create(builder, loc, resultType, value).getResult();
+  }
+};
+
 struct MemrefAddressOfGlobalModel
     : public AddressOfGlobalOpInterface::ExternalModel<
           MemrefAddressOfGlobalModel, memref::GetGlobalOp> {
@@ -474,6 +491,7 @@ void OpenACCDialect::initialize() {
       MemRefPointerLikeModel<UnrankedMemRefType>>(*getContext());
   LLVM::LLVMPointerType::attachInterface<LLVMPointerPointerLikeModel>(
       *getContext());
+  PrivateType::attachInterface<PrivateTypePointerLikeModel>(*getContext());
 
   // Attach operation interfaces
   memref::GetGlobalOp::attachInterface<MemrefAddressOfGlobalModel>(
diff --git a/mlir/test/Dialect/OpenACC/ops-cg-privatization.mlir b/mlir/test/Dialect/OpenACC/ops-cg-privatization.mlir
index 206466e94abd7..2b0af1527a984 100644
--- a/mlir/test/Dialect/OpenACC/ops-cg-privatization.mlir
+++ b/mlir/test/Dialect/OpenACC/ops-cg-privatization.mlir
@@ -1,5 +1,7 @@
 // RUN: mlir-opt -split-input-file %s | FileCheck %s --check-prefixes=CHECK
+// Verify the printed output can be parsed.
 // RUN: mlir-opt -split-input-file %s | mlir-opt -split-input-file | FileCheck %s --check-prefixes=CHECK
+// Verify the generic form can be parsed.
 // RUN: mlir-opt -split-input-file -mlir-print-op-generic %s | mlir-opt -split-input-file | FileCheck %s --check-prefixes=CHECK
 
 // -----
@@ -114,3 +116,28 @@ func.func @privatize_inside_compute_region(%data : memref<64xf32>) {
 // CHECK: acc.private_local
 // CHECK: memref.load %{{.*}}[%{{.*}}] : memref<64xf32>
 // CHECK: } {origin = "acc.parallel"}
+
+// -----
+
+// CHECK-LABEL: func @unwrap_private_to_memref
+func.func @unwrap_private_to_memref() {
+  %h = acc.privatize : () -> !acc.private_type<memref<i32>>
+  %m = acc.unwrap_private %h : !acc.private_type<memref<i32>> to memref<i32>
+  %z = arith.constant 0 : i32
+  memref.store %z, %m[] : memref<i32>
+  return
+}
+// CHECK-DAG: %[[H:.*]] = acc.privatize
+// CHECK-SAME: () -> !acc.private_type<memref<i32>>
+// CHECK: %{{.*}} = acc.unwrap_private %[[H]]
+// CHECK-SAME: !acc.private_type<memref<i32>> to memref<i32>
+
+// -----
+
+// CHECK-LABEL: func @unwrap_private_to_byte_memref
+func.func @unwrap_private_to_byte_memref() {
+  %h = acc.privatize : () -> !acc.private_type<memref<f64>>
+  %storage = acc.unwrap_private %h : !acc.private_type<memref<f64>> to memref<?xi8>
+  return
+}
+// CHECK: acc.unwrap_private %{{.*}} : !acc.private_type<memref<f64>> to memref<?xi8>
diff --git a/mlir/unittests/Dialect/OpenACC/OpenACCTypeInterfacesTest.cpp b/mlir/unittests/Dialect/OpenACC/OpenACCTypeInterfacesTest.cpp
index 0d5419203dbbe..573f8c6e902cd 100644
--- a/mlir/unittests/Dialect/OpenACC/OpenACCTypeInterfacesTest.cpp
+++ b/mlir/unittests/Dialect/OpenACC/OpenACCTypeInterfacesTest.cpp
@@ -256,3 +256,24 @@ TEST_F(OpenACCTypeInterfacesTest, PointerLikeGenCastLLVMIntToPtrFromIndex) {
   ASSERT_TRUE(intToPtr);
   EXPECT_TRUE(isa<arith::IndexCastUIOp>(intToPtr.getArg().getDefiningOp()));
 }
+
+TEST_F(OpenACCTypeInterfacesTest, PointerLikeGenCastPrivateTypeToMemref) {
+  Location loc = UnknownLoc::get(&context);
+  OwningOpRef<ModuleOp> module = ModuleOp::create(loc);
+  OpBuilder builder(module->getBodyRegion());
+  func::FuncOp fn = func::FuncOp::create(
+      builder, loc, "cast_private_to_memref", builder.getFunctionType({}, {}));
+  Block *block = fn.addEntryBlock();
+  builder.setInsertionPointToStart(block);
+
+  Type privateTy = PrivateType::get(&context, builder.getI8Type());
+  Type memrefTy = MemRefType::get({ShapedType::kDynamic}, builder.getI8Type());
+  Value handle = UndefOp::create(builder, loc, privateTy);
+  auto ptrLike = cast<PointerLikeType>(privateTy);
+  Value out = ptrLike.genCast(builder, loc, handle, memrefTy);
+  ASSERT_TRUE(out);
+  EXPECT_EQ(out.getType(), memrefTy);
+  auto unwrap = dyn_cast<UnwrapPrivateOp>(out.getDefiningOp());
+  ASSERT_TRUE(unwrap);
+  EXPECT_EQ(unwrap.getHandle(), handle);
+}



More information about the Mlir-commits mailing list