[Mlir-commits] [mlir] [OpenACC] Add pass `ACCEmitRemarksPrivate`. (PR #205824)

Moazin K. llvmlistbot at llvm.org
Thu Jun 25 07:25:07 PDT 2026


https://github.com/moazin created https://github.com/llvm/llvm-project/pull/205824

The pass emits remarks describing `acc.firstprivate` and `acc.private` associated with OpenACC compute and loop constructs.

Assisted-by: Claude Code

>From e071a1828e9dd9ccfb66971f71758e97be6b4b15 Mon Sep 17 00:00:00 2001
From: Moazin Khatti <mkhatti at nvidia.com>
Date: Wed, 24 Jun 2026 16:46:52 -0700
Subject: [PATCH] [OpenACC] Add pass `ACCEmitRemarksPrivate`.

The pass emits remarks describing `acc.firstprivate` and `acc.private`
associated with OpenACC compute and loop constructs.

Assisted-by: Claude Code
---
 .../mlir/Dialect/OpenACC/Transforms/Passes.td |  14 +++
 .../Transforms/ACCEmitRemarksPrivate.cpp      |  99 +++++++++++++++
 .../Dialect/OpenACC/Transforms/CMakeLists.txt |   1 +
 .../OpenACC/acc-emit-remarks-private.mlir     | 119 ++++++++++++++++++
 4 files changed, 233 insertions(+)
 create mode 100644 mlir/lib/Dialect/OpenACC/Transforms/ACCEmitRemarksPrivate.cpp
 create mode 100644 mlir/test/Dialect/OpenACC/acc-emit-remarks-private.mlir

diff --git a/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td b/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td
index e35e38adceb02..b52dee12d390a 100644
--- a/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/OpenACC/Transforms/Passes.td
@@ -193,6 +193,20 @@ def ACCEmitRemarksLoop : Pass<"acc-emit-remarks-loop", "mlir::func::FuncOp"> {
   ];
 }
 
+def ACCEmitRemarksPrivate
+    : Pass<"acc-emit-remarks-private", "mlir::func::FuncOp"> {
+  let summary = "Emit OpenACC private and firstprivate remarks";
+  let description = [{
+    This pass emits optimization remarks describing the private and firstprivate
+    variables associated with OpenACC compute and loop constructs.
+
+    The pass walks compute constructs and `acc.loop` operations and, for each,
+    reports the implicit and explicit `private` and `firstprivate` variables it
+    carries.
+  }];
+  let dependentDialects = ["mlir::acc::OpenACCDialect"];
+}
+
 def ACCLoopTiling : Pass<"acc-loop-tiling", "mlir::func::FuncOp"> {
   let summary = "Tile OpenACC loops with tile clauses";
   let description = [{
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCEmitRemarksPrivate.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCEmitRemarksPrivate.cpp
new file mode 100644
index 0000000000000..119ee9cecd77a
--- /dev/null
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCEmitRemarksPrivate.cpp
@@ -0,0 +1,99 @@
+//===- ACCEmitRemarksPrivate.cpp - Emit OpenACC privatization remarks ----===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass emits remarks describing the private and firstprivate variables
+// associated with OpenACC compute and loop constructs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/OpenACC/Analysis/OpenACCSupport.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenACC/Transforms/Passes.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/ADT/TypeSwitch.h"
+
+namespace mlir {
+namespace acc {
+#define GEN_PASS_DEF_ACCEMITREMARKSPRIVATE
+#include "mlir/Dialect/OpenACC/Transforms/Passes.h.inc"
+} // namespace acc
+} // namespace mlir
+
+#define DEBUG_TYPE "acc-emit-remarks-private"
+
+using namespace mlir;
+
+namespace {
+
+template <typename OpTy>
+static void reportPrivatization(Operation *accOp, ValueRange operands,
+                                acc::OpenACCSupport &accSupport,
+                                StringRef clause) {
+  SmallVector<std::string> implicitNames;
+  SmallVector<std::string> explicitNames;
+  for (Value operand : operands) {
+    auto op = cast<OpTy>(operand.getDefiningOp());
+    std::string varName = accSupport.getVariableName(op.getAccVar());
+    (op.getImplicit() ? implicitNames : explicitNames)
+        .push_back(varName.empty() ? "<unknown>" : varName);
+  }
+
+  if (!implicitNames.empty())
+    accSupport.emitRemark(
+        accOp,
+        [clause, names = std::move(implicitNames)]() {
+          return (Twine("Generating implicit ") + clause + "(" +
+                  llvm::join(names, ",") + ")")
+              .str();
+        },
+        DEBUG_TYPE);
+
+  if (!explicitNames.empty())
+    accSupport.emitRemark(
+        accOp,
+        [clause, names = std::move(explicitNames)]() {
+          return (Twine("Generating ") + clause + "(" + llvm::join(names, ",") +
+                  ")")
+              .str();
+        },
+        DEBUG_TYPE);
+}
+
+template <typename OpTy>
+static void emitRemarksForACCOp(OpTy accOp, acc::OpenACCSupport &accSupport) {
+  reportPrivatization<acc::FirstprivateOp>(
+      accOp, accOp.getFirstprivateOperands(), accSupport, "firstprivate");
+  reportPrivatization<acc::PrivateOp>(accOp, accOp.getPrivateOperands(),
+                                      accSupport, "private");
+}
+
+class ACCEmitRemarksPrivate
+    : public acc::impl::ACCEmitRemarksPrivateBase<ACCEmitRemarksPrivate> {
+public:
+  using ACCEmitRemarksPrivateBase<
+      ACCEmitRemarksPrivate>::ACCEmitRemarksPrivateBase;
+
+  void runOnOperation() override {
+    func::FuncOp func = getOperation();
+
+    auto cachedAnalysis = getCachedParentAnalysis<acc::OpenACCSupport>();
+    acc::OpenACCSupport &accSupport =
+        cachedAnalysis ? cachedAnalysis->get()
+                       : getAnalysis<acc::OpenACCSupport>();
+
+    func.walk([&](Operation *op) {
+      TypeSwitch<Operation *>(op).Case<ACC_COMPUTE_CONSTRUCT_AND_LOOP_OPS>(
+        [&](auto constructOp) { emitRemarksForACCOp(constructOp, accSupport); }
+      );
+    });
+  }
+};
+
+} // namespace
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/CMakeLists.txt b/mlir/lib/Dialect/OpenACC/Transforms/CMakeLists.txt
index 2ae3571673469..d977028c283e6 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/CMakeLists.txt
+++ b/mlir/lib/Dialect/OpenACC/Transforms/CMakeLists.txt
@@ -5,6 +5,7 @@ add_mlir_dialect_library(MLIROpenACCTransforms
   ACCRoutineToGPUFunc.cpp
   ACCDeclareGPUModuleInsertion.cpp
   ACCEmitRemarksLoop.cpp
+  ACCEmitRemarksPrivate.cpp
   ACCIfClauseLowering.cpp
   ACCImplicitData.cpp
   ACCRecipeMaterialization.cpp
diff --git a/mlir/test/Dialect/OpenACC/acc-emit-remarks-private.mlir b/mlir/test/Dialect/OpenACC/acc-emit-remarks-private.mlir
new file mode 100644
index 0000000000000..b388ad51208a2
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/acc-emit-remarks-private.mlir
@@ -0,0 +1,119 @@
+// RUN: mlir-opt %s -acc-emit-remarks-private --remarks-filter="(open)?acc.*" 2>&1 | FileCheck %s
+
+// CHECK: remark: [Passed] openacc | Category:acc-emit-remarks-private | Function=firstpriv_implicit | Remark="Generating implicit firstprivate(t)"
+// CHECK: remark: [Passed] openacc | Category:acc-emit-remarks-private | Function=firstpriv_explicit | Remark="Generating firstprivate(t)"
+// CHECK: remark: [Passed] openacc | Category:acc-emit-remarks-private | Function=private_loop_implicit | Remark="Generating implicit private(x)"
+// CHECK: remark: [Passed] openacc | Category:acc-emit-remarks-private | Function=private_loop_unknown | Remark="Generating implicit private(<unknown>)"
+// CHECK: remark: [Passed] openacc | Category:acc-emit-remarks-private | Function=private_explicit | Remark="Generating private(x)"
+// CHECK: remark: [Passed] openacc | Category:acc-emit-remarks-private | Function=multi_private_implicit | Remark="Generating implicit private(a,b)"
+
+acc.firstprivate.recipe @firstprivatization_memref_i32 : memref<i32> init {
+^bb0(%arg0: memref<i32>):
+  %0 = memref.alloca() : memref<i32>
+  acc.yield %0 : memref<i32>
+} copy {
+^bb0(%arg0: memref<i32>, %arg1: memref<i32>):
+  %0 = memref.load %arg0[] : memref<i32>
+  memref.store %0, %arg1[] : memref<i32>
+  acc.terminator
+} destroy {
+^bb0(%arg0: memref<i32>, %arg1: memref<i32>):
+  memref.dealloc %arg1 : memref<i32>
+  acc.terminator
+}
+
+acc.private.recipe @privatization_memref_i64 : memref<i64> init {
+^bb0(%arg0: memref<i64>):
+  %0 = memref.alloca() : memref<i64>
+  acc.yield %0 : memref<i64>
+} destroy {
+^bb0(%arg0: memref<i64>, %arg1: memref<i64>):
+  memref.dealloc %arg1 : memref<i64>
+  acc.terminator
+}
+
+// CHECK-LABEL: func.func @firstpriv_implicit
+// CHECK: acc.firstprivate
+// CHECK: acc.parallel firstprivate
+func.func @firstpriv_implicit() {
+  %c1336 = arith.constant 1336 : i32
+  %alloc = memref.alloca() : memref<i32>
+  memref.store %c1336, %alloc[] : memref<i32>
+  %fp = acc.firstprivate varPtr(%alloc : memref<i32>) recipe(@firstprivatization_memref_i32) -> memref<i32> {implicit = true, name = "t"}
+  acc.parallel firstprivate(%fp : memref<i32>) {
+    %c1 = arith.constant 1 : i32
+    %v = memref.load %fp[] : memref<i32>
+    %add = arith.addi %v, %c1 : i32
+    memref.store %add, %fp[] : memref<i32>
+    acc.yield
+  }
+  return
+}
+
+// CHECK-LABEL: func.func @firstpriv_explicit
+func.func @firstpriv_explicit() {
+  %c1336 = arith.constant 1336 : i32
+  %alloc = memref.alloca() : memref<i32>
+  memref.store %c1336, %alloc[] : memref<i32>
+  %fp = acc.firstprivate varPtr(%alloc : memref<i32>) recipe(@firstprivatization_memref_i32) -> memref<i32> {name = "t"}
+  acc.parallel firstprivate(%fp : memref<i32>) {
+    %c1 = arith.constant 1 : i32
+    %v = memref.load %fp[] : memref<i32>
+    %add = arith.addi %v, %c1 : i32
+    memref.store %add, %fp[] : memref<i32>
+    acc.yield
+  }
+  return
+}
+
+// CHECK-LABEL: func.func @private_loop_implicit
+func.func @private_loop_implicit(%arg0 : memref<i64>) {
+  %c16 = arith.constant 16 : index
+  %c1 = arith.constant 1 : index
+  %priv = acc.private varPtr(%arg0 : memref<i64>) recipe(@privatization_memref_i64) -> memref<i64> {implicit = true, name = "x"}
+  acc.loop private(%priv : memref<i64>) control(%siv : index) = (%c1 : index) to (%c16 : index) step (%c1 : index) {
+    %iv_i64 = arith.index_cast %siv : index to i64
+    memref.store %iv_i64, %priv[] : memref<i64>
+    acc.yield
+  } attributes {independent = [#acc.device_type<none>]}
+  return
+}
+
+// CHECK-LABEL: func.func @private_loop_unknown
+func.func @private_loop_unknown(%arg0 : memref<i64>) {
+  %c16 = arith.constant 16 : index
+  %c1 = arith.constant 1 : index
+  %priv = acc.private varPtr(%arg0 : memref<i64>) recipe(@privatization_memref_i64) -> memref<i64> {implicit = true, name = ""}
+  acc.loop private(%priv : memref<i64>) control(%siv : index) = (%c1 : index) to (%c16 : index) step (%c1 : index) {
+    %iv_i64 = arith.index_cast %siv : index to i64
+    memref.store %iv_i64, %priv[] : memref<i64>
+    acc.yield
+  } attributes {independent = [#acc.device_type<none>]}
+  return
+}
+
+// CHECK-LABEL: func.func @private_explicit
+func.func @private_explicit(%arg0 : memref<i64>) {
+  %c16 = arith.constant 16 : index
+  %c1 = arith.constant 1 : index
+  %priv = acc.private varPtr(%arg0 : memref<i64>) recipe(@privatization_memref_i64) -> memref<i64> {name = "x"}
+  acc.parallel private(%priv : memref<i64>) {
+    acc.loop control(%siv : index) = (%c1 : index) to (%c16 : index) step (%c1 : index) {
+      %iv_i64 = arith.index_cast %siv : index to i64
+      memref.store %iv_i64, %priv[] : memref<i64>
+      acc.yield
+    } attributes {independent = [#acc.device_type<none>]}
+    acc.yield
+  }
+  return
+}
+
+// CHECK-LABEL: func.func @multi_private_implicit
+func.func @multi_private_implicit(%arg0 : memref<i64>, %arg1 : memref<i64>) {
+  %privA = acc.private varPtr(%arg0 : memref<i64>) recipe(@privatization_memref_i64) -> memref<i64> {implicit = true, name = "a"}
+  %privB = acc.private varPtr(%arg1 : memref<i64>) recipe(@privatization_memref_i64) -> memref<i64> {implicit = true, name = "b"}
+  acc.parallel private(%privA, %privB : memref<i64>, memref<i64>) {
+    acc.yield
+  }
+  return
+}



More information about the Mlir-commits mailing list