[Mlir-commits] [mlir] [OpenACC] add isEffectivelySerial() to acc.parallel and acc.kernels (PR #209192)

Scott Manley llvmlistbot at llvm.org
Mon Jul 13 07:29:53 PDT 2026


https://github.com/rscottmanley updated https://github.com/llvm/llvm-project/pull/209192

>From fd4c12a15c2a009640dc88cdb0e5a44c6008e013 Mon Sep 17 00:00:00 2001
From: Scott Manley <scmanley at nvidia.com>
Date: Mon, 13 Jul 2026 07:13:39 -0700
Subject: [PATCH 1/3] [OpenACC] add isEffectivelySerial() to acc.parallel and
 acc.kernels

Mirror the isEffectivelySerial() function in acc.compute_region to
acc.parallel and acc.kernel so this check is unified anywhere it needs
to be used. Should be NFC
---
 .../mlir/Dialect/OpenACC/OpenACCOps.td        |  6 +++
 mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp     | 35 ++++++++++++++++
 .../OpenACC/Transforms/ACCComputeLowering.cpp | 41 ++-----------------
 3 files changed, 44 insertions(+), 38 deletions(-)

diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index 30298767c0f3e..db2f0e0605db5 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -1842,6 +1842,9 @@ def OpenACC_ParallelOp
     /// clause for the given device_type.
     bool hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType);
 
+    /// Check whether num_gangs, num_workers, and vector_length are all 1.
+    bool isEffectivelySerial();
+
     /// Return true if the op has the wait attribute for the
     /// mlir::acc::DeviceType::None device_type.
     bool hasWaitOnly();
@@ -2173,6 +2176,9 @@ def OpenACC_KernelsOp
     /// clause for the given device_type.
     bool hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType);
 
+    /// Check whether num_gangs, num_workers, and vector_length are all 1.
+    bool isEffectivelySerial();
+
     /// Return true if the op has the wait attribute for the
     /// mlir::acc::DeviceType::None device_type.
     bool hasWaitOnly();
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
index 7de59058ead0d..3b168b7631db8 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
@@ -14,6 +14,7 @@
 //
 //===----------------------------------------------------------------------===//
 
+#include "mlir/Dialect/Arith/IR/Arith.h"
 #include "mlir/Dialect/GPU/IR/GPUDialect.h"
 #include "mlir/Dialect/OpenACC/OpenACC.h"
 #include "mlir/Dialect/Utils/StaticValueUtils.h"
@@ -571,6 +572,40 @@ ComputeRegionOp::wireHoistedValueThroughIns(Value value) {
   return arg;
 }
 
+/// Strip index_cast operations from a value before checking for a constant.
+static Value stripIndexCasts(Value val) {
+  while (auto castOp = val.getDefiningOp<arith::IndexCastOp>())
+    val = castOp.getIn();
+  return val;
+}
+
+template <typename ComputeOpT>
+static bool isGangWorkerVectorAllOne(ComputeOpT op) {
+  auto numGangs = op.getNumGangsValues();
+  if (numGangs.empty())
+    return false;
+  for (Value gangSize : numGangs) {
+    if (!isConstantIntValue(stripIndexCasts(gangSize), 1))
+      return false;
+  }
+  Value numWorkers = op.getNumWorkersValue();
+  if (!numWorkers)
+    return false;
+  Value vectorLength = op.getVectorLengthValue();
+  if (!vectorLength)
+    return false;
+  return isConstantIntValue(stripIndexCasts(numWorkers), 1) &&
+         isConstantIntValue(stripIndexCasts(vectorLength), 1);
+}
+
+bool ParallelOp::isEffectivelySerial() {
+  return isGangWorkerVectorAllOne(*this);
+}
+
+bool KernelsOp::isEffectivelySerial() {
+  return isGangWorkerVectorAllOne(*this);
+}
+
 bool ComputeRegionOp::isEffectivelySerial() {
   auto *ctx = getContext();
 
diff --git a/mlir/lib/Dialect/OpenACC/Transforms/ACCComputeLowering.cpp b/mlir/lib/Dialect/OpenACC/Transforms/ACCComputeLowering.cpp
index b3d54d2e05697..a275a794c9fd5 100644
--- a/mlir/lib/Dialect/OpenACC/Transforms/ACCComputeLowering.cpp
+++ b/mlir/lib/Dialect/OpenACC/Transforms/ACCComputeLowering.cpp
@@ -78,41 +78,6 @@ namespace {
 // Helper functions
 //===----------------------------------------------------------------------===//
 
-/// Strip index_cast operations from a value before checking for a constant.
-static Value stripIndexCasts(Value val) {
-  while (auto castOp = val.getDefiningOp<arith::IndexCastOp>())
-    val = castOp.getIn();
-  return val;
-}
-
-template <typename ComputeOpT>
-static bool isGangWorkerVectorAllOne(ComputeOpT op) {
-  auto numGangs = op.getNumGangsValues();
-  if (numGangs.empty())
-    return false;
-  for (Value gangSize : numGangs) {
-    if (!isConstantIntValue(stripIndexCasts(gangSize), 1))
-      return false;
-  }
-  Value numWorkers = op.getNumWorkersValue();
-  if (!numWorkers)
-    return false;
-  Value vectorLength = op.getVectorLengthValue();
-  if (!vectorLength)
-    return false;
-  return isConstantIntValue(stripIndexCasts(numWorkers), 1) &&
-         isConstantIntValue(stripIndexCasts(vectorLength), 1);
-}
-
-/// A compute construct is "effectively serial" when it specifies
-/// num_gangs(1), num_workers(1), and vector_length(1). This is because
-/// these are the only parallelism dimensions expressible from OpenACC spec
-/// point-of-view and is consistent with how `serial` semantics are defined.
-template <typename ComputeOpT>
-static bool isEffectivelySerial(ComputeOpT op) {
-  return isGangWorkerVectorAllOne(op);
-}
-
 static bool isOpInComputeRegion(Operation *op) {
   Region *region = op->getBlock()->getParent();
   return getEnclosingComputeOp(*region) != nullptr;
@@ -120,9 +85,9 @@ static bool isOpInComputeRegion(Operation *op) {
 
 static bool isOpInSerialRegion(Operation *op) {
   if (auto parallelOp = op->getParentOfType<ParallelOp>())
-    return isEffectivelySerial(parallelOp);
+    return parallelOp.isEffectivelySerial();
   if (auto kernelsOp = op->getParentOfType<KernelsOp>())
-    return isEffectivelySerial(kernelsOp);
+    return kernelsOp.isEffectivelySerial();
   if (op->getParentOfType<SerialOp>())
     return true;
   if (auto computeRegion = op->getParentOfType<ComputeRegionOp>())
@@ -230,7 +195,7 @@ assignKnownLaunchArgs(ComputeConstructT computeOp, DeviceType deviceType,
     return {ParWidthOp::create(rewriter, loc, Value(), policy.seqDim(ctx))};
   } else if constexpr (llvm::is_one_of<ComputeConstructT, ParallelOp,
                                        KernelsOp>::value) {
-    if (isEffectivelySerial(computeOp))
+    if (computeOp.isEffectivelySerial())
       return {ParWidthOp::create(rewriter, loc, Value(), policy.seqDim(ctx))};
 
     deviceType = getParDimsDeviceType(computeOp, deviceType);

>From db3c29b6b0fd8452eebbab0c273d69668d9a7d1e Mon Sep 17 00:00:00 2001
From: Scott Manley <scmanley at nvidia.com>
Date: Mon, 13 Jul 2026 07:21:28 -0700
Subject: [PATCH 2/3] move strip index casts to lambda

---
 mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
index 3b168b7631db8..8cb2be720c29e 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
@@ -572,15 +572,15 @@ ComputeRegionOp::wireHoistedValueThroughIns(Value value) {
   return arg;
 }
 
-/// Strip index_cast operations from a value before checking for a constant.
-static Value stripIndexCasts(Value val) {
-  while (auto castOp = val.getDefiningOp<arith::IndexCastOp>())
-    val = castOp.getIn();
-  return val;
-}
-
 template <typename ComputeOpT>
 static bool isGangWorkerVectorAllOne(ComputeOpT op) {
+  // Strip index_cast operations from a value before checking for a constant.
+  auto stripIndexCasts = [](Value val) -> Value {
+    while (auto castOp = val.getDefiningOp<arith::IndexCastOp>())
+      val = castOp.getIn();
+    return val;
+  };
+
   auto numGangs = op.getNumGangsValues();
   if (numGangs.empty())
     return false;

>From 0cc933527e3865a07a046be1a98156e46134e593 Mon Sep 17 00:00:00 2001
From: Scott Manley <scmanley at nvidia.com>
Date: Mon, 13 Jul 2026 07:29:17 -0700
Subject: [PATCH 3/3] move isGangWorkerVectorAllOne into OpenACC.h

---
 mlir/include/mlir/Dialect/OpenACC/OpenACC.h | 26 ++++++++++++++++
 mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp     |  8 +++++
 mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp   | 34 ---------------------
 3 files changed, 34 insertions(+), 34 deletions(-)

diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
index 650f6f780273f..4abc3971f12c0 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
@@ -238,6 +238,32 @@ struct CurrentDeviceIdResource
   bool isAddressable() const override { return false; }
 };
 
+template <typename ComputeOpT>
+static bool isGangWorkerVectorAllOne(ComputeOpT op) {
+  // Strip index_cast operations from a value before checking for a constant.
+  auto stripIndexCasts = [](Value val) -> Value {
+    while (auto castOp = val.getDefiningOp<arith::IndexCastOp>())
+      val = castOp.getIn();
+    return val;
+  };
+
+  auto numGangs = op.getNumGangsValues();
+  if (numGangs.empty())
+    return false;
+  for (Value gangSize : numGangs) {
+    if (!isConstantIntValue(stripIndexCasts(gangSize), 1))
+      return false;
+  }
+  Value numWorkers = op.getNumWorkersValue();
+  if (!numWorkers)
+    return false;
+  Value vectorLength = op.getVectorLengthValue();
+  if (!vectorLength)
+    return false;
+  return isConstantIntValue(stripIndexCasts(numWorkers), 1) &&
+         isConstantIntValue(stripIndexCasts(vectorLength), 1);
+}
+
 } // namespace acc
 } // namespace mlir
 
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index d793645e49eca..0205afc1dfedb 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -2234,6 +2234,10 @@ bool acc::ParallelOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
       getVectorLength(), deviceType);
 }
 
+bool acc::ParallelOp::isEffectivelySerial() {
+  return isGangWorkerVectorAllOne(*this);
+}
+
 bool acc::ParallelOp::hasWaitOnly() {
   return hasWaitOnly(mlir::acc::DeviceType::None);
 }
@@ -3107,6 +3111,10 @@ bool acc::KernelsOp::hasAnyGangWorkerVector(mlir::acc::DeviceType deviceType) {
       getVectorLength(), deviceType);
 }
 
+bool acc::KernelsOp::isEffectivelySerial() {
+  return isGangWorkerVectorAllOne(*this);
+}
+
 bool acc::KernelsOp::hasWaitOnly() {
   return hasWaitOnly(mlir::acc::DeviceType::None);
 }
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
index 8cb2be720c29e..4f112b4002427 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACCCG.cpp
@@ -572,40 +572,6 @@ ComputeRegionOp::wireHoistedValueThroughIns(Value value) {
   return arg;
 }
 
-template <typename ComputeOpT>
-static bool isGangWorkerVectorAllOne(ComputeOpT op) {
-  // Strip index_cast operations from a value before checking for a constant.
-  auto stripIndexCasts = [](Value val) -> Value {
-    while (auto castOp = val.getDefiningOp<arith::IndexCastOp>())
-      val = castOp.getIn();
-    return val;
-  };
-
-  auto numGangs = op.getNumGangsValues();
-  if (numGangs.empty())
-    return false;
-  for (Value gangSize : numGangs) {
-    if (!isConstantIntValue(stripIndexCasts(gangSize), 1))
-      return false;
-  }
-  Value numWorkers = op.getNumWorkersValue();
-  if (!numWorkers)
-    return false;
-  Value vectorLength = op.getVectorLengthValue();
-  if (!vectorLength)
-    return false;
-  return isConstantIntValue(stripIndexCasts(numWorkers), 1) &&
-         isConstantIntValue(stripIndexCasts(vectorLength), 1);
-}
-
-bool ParallelOp::isEffectivelySerial() {
-  return isGangWorkerVectorAllOne(*this);
-}
-
-bool KernelsOp::isEffectivelySerial() {
-  return isGangWorkerVectorAllOne(*this);
-}
-
 bool ComputeRegionOp::isEffectivelySerial() {
   auto *ctx = getContext();
 



More information about the Mlir-commits mailing list