[Mlir-commits] [mlir] [mlir][openacc] Report private arrays placed in local memory (PR #224398)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Thu Sep 17 12:56:36 PDT 2026
llvmorg-github-actions[bot] wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-openacc
Author: Yian Su (yiansu)
<details>
<summary>Changes</summary>
ACCCGToGPU reports private arrays it places in GPU shared memory, but says nothing when a private array is given per-thread stack storage. Collect those names too and emit a matching remark, so -Minfo output accounts for every private array placement.
Rank-0 privatizations are skipped: a private scalar is a register candidate rather than local memory.
---
Full diff: https://github.com/llvm/llvm-project/pull/224398.diff
2 Files Affected:
- (modified) mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp (+35)
- (added) mlir/test/Dialect/OpenACC/acc-cg-to-gpu-private-local-memory-remark.mlir (+58)
``````````diff
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp
index b9d634e059a01..96f974a488c3c 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCCGToGPU.cpp
@@ -529,6 +529,12 @@ class ACCCGToGPULowering {
/// Reserve \p bytes from the shared-memory budget.
bool tryAllocateSharedMemory(int64_t bytes);
+ /// Record the array behind \p privateLocal as per-thread local memory for
+ /// the closing remark. Rank-0 privatizations are skipped: a scalar is a
+ /// register candidate, not local memory.
+ void recordLocalMemPrivate(acc::PrivateLocalOp privateLocal,
+ MemRefType baseTy);
+
/// Element size in bytes for \p elementType .
int64_t getElementSizeInBytes(Location loc, Type elementType) const;
@@ -701,6 +707,7 @@ class ACCCGToGPULowering {
acc::DefaultACCToGPUMappingPolicy defaultPolicy;
SharedMemoryBudget sharedMemBudget;
SmallVector<std::string> sharedMemPrivateVarNames;
+ SmallVector<std::string> localMemPrivateVarNames;
llvm::SmallVector<Operation *, 4> deferredBarrierSeqLoops;
Value getThreadId(Location loc, gpu::Dimension dim) {
@@ -865,6 +872,20 @@ bool ACCCGToGPULowering::tryAllocateSharedMemory(int64_t bytes) {
return sharedMemBudget.tryAllocate(bytes);
}
+void ACCCGToGPULowering::recordLocalMemPrivate(acc::PrivateLocalOp privateLocal,
+ MemRefType baseTy) {
+ if (baseTy.getRank() == 0)
+ return;
+ std::string varName =
+ privateLocal ? accSupport.getVariableName(privateLocal.getResult())
+ : std::string();
+ if (varName.empty())
+ varName = "(*)";
+ // The same variable reaches this point once per acc.private_local it has.
+ if (!llvm::is_contained(localMemPrivateVarNames, varName))
+ localMemPrivateVarNames.push_back(varName);
+}
+
FailureOr<arith::AtomicRMWKind>
ACCCGToGPULowering::getReductionKind(acc::ReductionOperator redOp, Type type,
Location loc) {
@@ -1250,6 +1271,14 @@ LogicalResult ACCCGToGPULowering::rewrite() {
if (hasFailed)
return failure();
+ if (!localMemPrivateVarNames.empty()) {
+ accSupport.emitRemark(computeRegion, [&]() {
+ return (llvm::Twine("Local memory used for ") +
+ llvm::join(localMemPrivateVarNames, ","))
+ .str();
+ });
+ }
+
if (!sharedMemPrivateVarNames.empty()) {
accSupport.emitRemark(computeRegion, [&]() {
return (llvm::Twine("GPU shared memory used for ") +
@@ -2578,6 +2607,8 @@ Value ACCCGToGPULowering::processPrivatize(acc::PrivatizeOp privatize) {
}
Operation *privatizeUser = getOnlyUser(tracked);
assert(privatizeUser && "expected PrivateLocalOp user for privatize");
+ acc::PrivateLocalOp privateLocalUser =
+ dyn_cast<acc::PrivateLocalOp>(privatizeUser);
std::pair<SmallVector<mlir::acc::GPUParallelDimAttr>,
SmallVector<mlir::acc::GPUParallelDimAttr>>
@@ -2609,6 +2640,7 @@ Value ACCCGToGPULowering::processPrivatize(acc::PrivatizeOp privatize) {
if (threadXActive &&
canUseStackAlloca(baseTy, loc, options.maxThreadPrivateStack)) {
auto alloca = memref::AllocaOp::create(rewriter, loc, baseTy);
+ recordLocalMemPrivate(privateLocalUser, baseTy);
mapping.map(privatize.getResult(), alloca.getResult());
return alloca.getResult();
}
@@ -2667,6 +2699,7 @@ Value ACCCGToGPULowering::processPrivatize(acc::PrivatizeOp privatize) {
// Static sizes: use alloca (stack allocation)
auto alloca =
memref::AllocaOp::create(rewriter, privatize->getLoc(), baseTy);
+ recordLocalMemPrivate(privateLocalUser, baseTy);
mapping.map(privatize.getResult(), alloca.getResult());
return alloca.getResult();
}
@@ -2853,6 +2886,7 @@ void ACCCGToGPULowering::processPrivateLocal(
(arrayAccum && storageHasThreadX(privateLocal, computeRegion))) &&
canUseStackAlloca(baseTy, loc, options.maxThreadPrivateStack)) {
Value alloca = memref::AllocaOp::create(rewriter, loc, baseTy);
+ recordLocalMemPrivate(privateLocal, baseTy);
if (arrayAccum) {
FailureOr<arith::AtomicRMWKind> kind = getReductionKind(
arrayAccum.getReductionOperator(), baseTy.getElementType(), loc);
@@ -2943,6 +2977,7 @@ void ACCCGToGPULowering::processPrivateLocal(
(arrayAccum && storageHasThreadX(privateLocal, computeRegion))) &&
canUseStackAlloca(baseTy, loc, options.maxThreadPrivateStack)) {
Value alloca = memref::AllocaOp::create(rewriter, loc, baseTy);
+ recordLocalMemPrivate(privateLocal, baseTy);
if (arrayAccum) {
FailureOr<arith::AtomicRMWKind> kind = getReductionKind(
arrayAccum.getReductionOperator(), baseTy.getElementType(), loc);
diff --git a/mlir/test/Dialect/OpenACC/acc-cg-to-gpu-private-local-memory-remark.mlir b/mlir/test/Dialect/OpenACC/acc-cg-to-gpu-private-local-memory-remark.mlir
new file mode 100644
index 0000000000000..b69cf304d7fec
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/acc-cg-to-gpu-private-local-memory-remark.mlir
@@ -0,0 +1,58 @@
+// RUN: mlir-opt %s --pass-pipeline="builtin.module(func.func(acc-cg-to-gpu))" \
+// RUN: --remarks-filter="(open)?acc.*" 2>&1 | FileCheck %s
+
+// CHECK: Function=one_array | Remark="Local memory used for buf"
+func.func @one_array() {
+ %c0 = arith.constant 0 : index
+ %c1 = arith.constant 1 : i32
+ %priv = acc.privatize par_dims(#acc<par_dims[thread_x]>)
+ : () -> !acc.private_type<memref<4xi32>>
+
+ acc.compute_region ins(%priv_in = %priv) : (!acc.private_type<memref<4xi32>>) {
+ %c0_k = arith.constant 0 : index
+ %c1_k = arith.constant 1 : i32
+ %local = acc.private_local %priv_in {acc.var_name = #acc.var_name<"buf">}
+ : (!acc.private_type<memref<4xi32>>) -> memref<4xi32>
+ memref.store %c1_k, %local[%c0_k] : memref<4xi32>
+ acc.yield
+ } <{origin = "acc.parallel"}>
+ return
+}
+
+// CHECK: Function=two_arrays | Remark="Local memory used for a,b"
+func.func @two_arrays() {
+ %priv_a = acc.privatize par_dims(#acc<par_dims[thread_x]>)
+ : () -> !acc.private_type<memref<4xi32>>
+ %priv_b = acc.privatize par_dims(#acc<par_dims[thread_x]>)
+ : () -> !acc.private_type<memref<8xi32>>
+
+ acc.compute_region ins(%a_in = %priv_a, %b_in = %priv_b)
+ : (!acc.private_type<memref<4xi32>>, !acc.private_type<memref<8xi32>>) {
+ %c0_k = arith.constant 0 : index
+ %c1_k = arith.constant 1 : i32
+ %a = acc.private_local %a_in {acc.var_name = #acc.var_name<"a">}
+ : (!acc.private_type<memref<4xi32>>) -> memref<4xi32>
+ %b = acc.private_local %b_in {acc.var_name = #acc.var_name<"b">}
+ : (!acc.private_type<memref<8xi32>>) -> memref<8xi32>
+ memref.store %c1_k, %a[%c0_k] : memref<4xi32>
+ memref.store %c1_k, %b[%c0_k] : memref<8xi32>
+ acc.yield
+ } <{origin = "acc.parallel"}>
+ return
+}
+
+// CHECK: Function=scalar
+// CHECK-NOT: Local memory used for
+func.func @scalar() {
+ %priv = acc.privatize par_dims(#acc<par_dims[thread_x]>)
+ : () -> !acc.private_type<memref<i32>>
+
+ acc.compute_region ins(%priv_in = %priv) : (!acc.private_type<memref<i32>>) {
+ %c1_k = arith.constant 1 : i32
+ %local = acc.private_local %priv_in {acc.var_name = #acc.var_name<"s">}
+ : (!acc.private_type<memref<i32>>) -> memref<i32>
+ memref.store %c1_k, %local[] : memref<i32>
+ acc.yield
+ } <{origin = "acc.parallel"}>
+ return
+}
``````````
</details>
https://github.com/llvm/llvm-project/pull/224398
More information about the Mlir-commits
mailing list