[Mlir-commits] [mlir] d6048f5 - [mlir][bufferization] Skip parallel analysis without parallel regions (#227202)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Sep 30 02:12:41 PDT 2026
Author: Ziliang Zhang
Date: 2026-09-30T09:12:34Z
New Revision: d6048f5ff3bdd934508a585a92ba010834981b7c
URL: https://github.com/llvm/llvm-project/commit/d6048f5ff3bdd934508a585a92ba010834981b7c
DIFF: https://github.com/llvm/llvm-project/commit/d6048f5ff3bdd934508a585a92ba010834981b7c.diff
LOG: [mlir][bufferization] Skip parallel analysis without parallel regions (#227202)
One-Shot Bufferize currently runs parallel-region conflict analysis even
when the analyzed IR has no parallel regions. This can repeatedly walk
long reverse use-def chains without being able to find a parallel-region
conflict.
Added:
Modified:
mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
mlir/test/Dialect/SCF/one-shot-bufferize-analysis.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
index 203680796a289..bec14fffec96c 100644
--- a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
+++ b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
@@ -312,10 +312,11 @@ struct BufferizationOptions {
/// bufferized or not.
bool bufferizeFunctionBoundaries = false;
- // Specifies whether to account for parallel regions in RaW analysis. If true,
- // then writes inside of parallel regions that write to buffers defined
- // outside of the parallel region will be given a new buffer.
- bool checkParallelRegions = true;
+ /// Whether the IR may contain a parallel region. When unset, the analysis
+ /// walks the IR to compute it.
+ /// Note: If the IR contains a parallel region, but this flag is set to
+ /// "false", the bufferization may produce incorrect IR.
+ std::optional<bool> mayHaveParallelRegions = std::nullopt;
/// This function controls buffer types on function signatures. Sets
/// `functionArgTypeConverterFn` and `inferFunctionResultLayout` accordingly.
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h b/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
index af5d2bd9a2db4..8b647790d6703 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
@@ -91,6 +91,10 @@ class OneShotAnalysisState : public AnalysisState {
/// the options when set; otherwise computed by walking the IR.
bool mayHaveUnstructuredControlFlow() const { return mayHaveUnstructuredCF; }
+ /// True if the analyzed IR may contain a parallel region. Taken from the
+ /// options when set; otherwise computed by walking the IR.
+ bool mayHaveParallelRegions() const { return mayHaveParallelRegionsFlag; }
+
/// Analyze the given op and its nested ops.
LogicalResult analyzeOp(Operation *op, const DominanceInfo &domInfo);
@@ -267,6 +271,9 @@ class OneShotAnalysisState : public AnalysisState {
/// True if any region has more than one block.
bool mayHaveUnstructuredCF = false;
+ /// True if the analyzed IR may contain a parallel region.
+ bool mayHaveParallelRegionsFlag = false;
+
/// Cached CFG reachability. Defined out-of-line to keep BitVector out of
/// this header.
class CFGReachabilityCache;
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
index b2608fc5b574c..0638b339cf9dc 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
@@ -516,9 +516,9 @@ def OneShotBufferizePass : Pass<"one-shot-bufferize", "ModuleOp"> {
Option<"bufferizeFunctionBoundaries", "bufferize-function-boundaries",
"bool", /*default=*/"0",
"Bufferize function boundaries (experimental).">,
- Option<"checkParallelRegions", "check-parallel-regions", "bool",
+ Option<"mayHaveParallelRegions", "may-have-parallel-regions", "bool",
/*default=*/"true",
- "Account for parallel regions in RaW analysis.">,
+ "Whether the IR may contain parallel regions.">,
Option<"copyBeforeWrite", "copy-before-write", "bool",
/*default=*/"false",
"Skip the analysis. Make a buffer copy on every write.">,
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
index 099f2a9372215..18ae650526d53 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
@@ -97,7 +97,8 @@ struct OneShotBufferizePass
opt.bufferAlignment = bufferAlignment;
opt.testAnalysisOnly = testAnalysisOnly;
opt.bufferizeFunctionBoundaries = bufferizeFunctionBoundaries;
- opt.checkParallelRegions = checkParallelRegions;
+ if (!mayHaveParallelRegions)
+ opt.mayHaveParallelRegions = false;
opt.noAnalysisFuncFilter = noAnalysisFuncFilter;
// Configure type converter.
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp b/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
index 1649a84c41674..e8b3404843217 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
@@ -131,11 +131,32 @@ static bool detectUnstructuredControlFlow(Operation *op) {
return walkRes.wasInterrupted();
}
+/// Return "true" if any allowed op has a parallel region.
+static bool detectParallelRegions(Operation *op,
+ const BufferizationOptions &options) {
+ WalkResult walkRes =
+ op->walk([&](BufferizableOpInterface bufferizableOp) -> WalkResult {
+ if (!options.isOpAllowed(bufferizableOp))
+ return WalkResult::skip();
+ for (Region ®ion : bufferizableOp->getRegions()) {
+ if (bufferizableOp.isParallelRegion(region.getRegionNumber()))
+ return WalkResult::interrupt();
+ }
+ return WalkResult::advance();
+ });
+ return walkRes.wasInterrupted();
+}
+
OneShotAnalysisState::OneShotAnalysisState(
Operation *op, const OneShotBufferizationOptions &options)
: AnalysisState(options, TypeID::get<OneShotAnalysisState>()) {
mayHaveUnstructuredCF = options.mayHaveUnstructuredControlFlow.value_or(
detectUnstructuredControlFlow(op));
+ if (!options.mayHaveParallelRegions.has_value()) {
+ mayHaveParallelRegionsFlag = detectParallelRegions(op, options);
+ } else {
+ mayHaveParallelRegionsFlag = *options.mayHaveParallelRegions;
+ }
// Set up alias sets.
op->walk([&](Operation *op) {
@@ -153,6 +174,7 @@ OneShotAnalysisState::OneShotAnalysisState(
op->walk([&](BufferizableOpInterface bufferizableOp) {
if (!options.isOpAllowed(bufferizableOp))
return WalkResult::skip();
+
for (OpOperand &opOperand : bufferizableOp->getOpOperands())
if (isa<TensorLikeType>(opOperand.get().getType()))
if (bufferizableOp.mustBufferizeInPlace(opOperand, *this))
@@ -841,7 +863,7 @@ hasReadAfterWriteInterference(const DenseSet<OpOperand *> &usesRead,
// Before going through the main RaW analysis, find cases where a buffer must
// be privatized due to parallelism. If the result of a write is never read,
// privatization is not necessary (and large parts of the IR are likely dead).
- if (options.checkParallelRegions && !usesRead.empty()) {
+ if (state.mayHaveParallelRegions() && !usesRead.empty()) {
for (OpOperand *uConflictingWrite : usesWrite) {
// Find the allocation point or last write (definition) of the buffer.
// Note: In contrast to `findDefinitions`, this also returns results of
@@ -858,10 +880,11 @@ hasReadAfterWriteInterference(const DenseSet<OpOperand *> &usesRead,
// The writing op must bufferize out-of-place if the definition is in a
//
diff erent parallel region than this write.
+ Region *writeParallelRegion = getParallelRegion(
+ uConflictingWrite->getOwner()->getParentRegion(), options);
for (Value def : definitionsOrLeaves) {
if (getParallelRegion(def.getParentRegion(), options) !=
- getParallelRegion(uConflictingWrite->getOwner()->getParentRegion(),
- options)) {
+ writeParallelRegion) {
LDBG() << "\n- bufferizes out-of-place due to parallel region:\n"
<< " unConflictingWrite = operand "
<< uConflictingWrite->getOperandNumber() << " of "
diff --git a/mlir/test/Dialect/SCF/one-shot-bufferize-analysis.mlir b/mlir/test/Dialect/SCF/one-shot-bufferize-analysis.mlir
index ed3685514dd0d..3d02f022a3864 100644
--- a/mlir/test/Dialect/SCF/one-shot-bufferize-analysis.mlir
+++ b/mlir/test/Dialect/SCF/one-shot-bufferize-analysis.mlir
@@ -1,5 +1,5 @@
// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only" -split-input-file | FileCheck %s --check-prefixes=CHECK,PARALLEL-CHECK
-// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only check-parallel-regions=false" -split-input-file | FileCheck %s --check-prefixes=CHECK,NO-PARALLEL-CHECK
+// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only may-have-parallel-regions=false" -split-input-file | FileCheck %s --check-prefixes=CHECK,NO-PARALLEL-CHECK
// Run fuzzer with
diff erent seeds.
// RUN: mlir-opt %s -one-shot-bufferize="allow-return-allocs-from-loops bufferize-function-boundaries test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=23" -split-input-file -o /dev/null
More information about the Mlir-commits
mailing list