-
Notifications
You must be signed in to change notification settings - Fork 14.3k
[mlir][bufferization] Add "bottom-up from terminators" analysis heuristic #83964
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[mlir][bufferization] Add "bottom-up from terminators" analysis heuristic #83964
Conversation
@llvm/pr-subscribers-mlir-tensor @llvm/pr-subscribers-mlir Author: Matthias Springer (matthias-springer) ChangesOne-Shot Bufferize currently does not support loops where a yielded value bufferizes to a buffer that is different from the buffer of the region iter_arg. In such a case, the bufferization fails with an error such as:
One common reason for non-equivalent buffers is that an op on the path from the region iter_arg to the terminator bufferizes out-of-place. Ops that are analyzed earlier are more likely to bufferize in-place. This commit adds a new heuristic that gives preference to ops that are reachable on the reverse SSA use-def chain from a region terminator and are within the parent region of the terminator. This is expected to work better than the existing heuristics for loops where an iter_arg is written to multiple times within a loop, but only one write is fed into the terminator. Current users of One-Shot Bufferize are not affected by this change. "Bottom-up" is still the default heuristic. Users can switch to the new heuristic manually. This commit also turns the "fuzzer" pass option into a heuristic, cleaning up the code a bit. Patch is 31.75 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/83964.diff 17 Files Affected:
diff --git a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
index d8cfeee2466360..b639eedd0f050c 100644
--- a/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
+++ b/mlir/include/mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h
@@ -356,10 +356,6 @@ struct BufferizationOptions {
DefaultMemorySpaceFn defaultMemorySpaceFn =
[](TensorType t) -> std::optional<Attribute> { return Attribute(); };
- /// Seed for the analysis fuzzer. If set to `0`, the fuzzer is deactivated.
- /// Should be used only with `testAnalysisOnly = true`.
- unsigned analysisFuzzerSeed = 0;
-
/// If set to `true`, the analysis is skipped. A buffer is copied before every
/// write. This flag cannot be used together with `testAnalysisOnly = true`.
bool copyBeforeWrite = false;
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h b/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
index a29af853eb21ba..d50a3042aeeacf 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h
@@ -24,7 +24,12 @@ class OneShotAnalysisState;
/// Options for analysis-enabled bufferization.
struct OneShotBufferizationOptions : public BufferizationOptions {
- enum class AnalysisHeuristic { BottomUp, TopDown };
+ enum class AnalysisHeuristic {
+ BottomUp,
+ TopDown,
+ BottomUpFromTerminators,
+ Fuzzer
+ };
OneShotBufferizationOptions() = default;
@@ -42,6 +47,11 @@ struct OneShotBufferizationOptions : public BufferizationOptions {
/// Specify the functions that should not be analyzed. copyBeforeWrite will be
/// set to true when bufferizing them.
llvm::ArrayRef<std::string> noAnalysisFuncFilter;
+
+ /// Seed for the analysis fuzzer. Used only if the heuristic is set to
+ /// `AnalysisHeuristic::Fuzzer`. The fuzzer should be used only with
+ /// `testAnalysisOnly = true`.
+ unsigned analysisFuzzerSeed = 0;
};
/// State for analysis-enabled bufferization. This class keeps track of alias
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
index e01f36b8daa18d..32787b3f08224f 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
@@ -454,6 +454,24 @@ def OneShotBufferize : Pass<"one-shot-bufferize", "ModuleOp"> {
argument is read/written and which returned values are aliasing/equivalent.
For debugging purposes, such information can be printed with
`test-analysis-only`.
+
+ The order in which ops are analyzed is important. The analysis is greedy and
+ ops that are analyzed earlier are more likely to bufferize in-place. The
+ heuristic can be set with `analysis-heuristic`. At the moment, the following
+ heuristics are available:
+
+ * `bottom-up` (default): Analyze ops from bottom to top.
+ * `top-down`: Analyze ops from top to bottom.
+ * `fuzzer`: Randomize the ordering of ops with `analysis-fuzzer-seed`.
+ * `bottom-up-from-terminators`: Traverse the reverse use-def chains of
+ tensor IR, starting from region branch terminators (bottom-up). Nested
+ regions are traversed before enclosing regions. Analyze the traversed ops
+ first, then analyze the remaining ops bottom-up. This heuristic is useful
+ for bufferizing loop constructs. One-Shot Bufferize currently supports
+ only such IR where yielded tensor values bufferize to equivalent region
+ iter_args, and first analyzing all ops on the path from the "yielding" op
+ to the beginning of the loop body makes it more likely for the region
+ iter_args and yielded values to bufferize to equivalent buffers.
}];
let options = [
Option<"allowReturnAllocsFromLoops", "allow-return-allocs-from-loops",
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
index 6a0ad66549965a..e807c329b71a47 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/Bufferize.cpp
@@ -182,6 +182,11 @@ parseHeuristicOption(const std::string &s) {
return OneShotBufferizationOptions::AnalysisHeuristic::BottomUp;
if (s == "top-down")
return OneShotBufferizationOptions::AnalysisHeuristic::TopDown;
+ if (s == "bottom-up-from-terminators")
+ return OneShotBufferizationOptions::AnalysisHeuristic::
+ BottomUpFromTerminators;
+ if (s == "fuzzer")
+ return OneShotBufferizationOptions::AnalysisHeuristic::Fuzzer;
llvm_unreachable("invalid analysisheuristic option");
}
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp b/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
index fba9cd87306381..00f657ca5d9aac 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/OneShotAnalysis.cpp
@@ -51,6 +51,7 @@
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/IR/AsmState.h"
#include "mlir/IR/Dominance.h"
+#include "mlir/IR/Iterators.h"
#include "mlir/IR/Operation.h"
#include "mlir/IR/TypeUtilities.h"
#include "mlir/Interfaces/ControlFlowInterfaces.h"
@@ -1094,41 +1095,98 @@ static void equivalenceAnalysis(Operation *op, OneShotAnalysisState &state) {
equivalenceAnalysis(ops, state);
}
-LogicalResult OneShotAnalysisState::analyzeOp(Operation *op,
- const DominanceInfo &domInfo) {
- // Collect ops so we can build our own reverse traversal.
- SmallVector<Operation *> ops;
- op->walk([&](Operation *op) {
- // No tensors => no buffers.
- if (!hasTensorSemantics(op))
+/// "Bottom-up from terminators" heuristic.
+static SmallVector<Operation *>
+bottomUpFromTerminatorsHeuristic(Operation *op,
+ const OneShotAnalysisState &state) {
+ SetVector<Operation *> traversedOps;
+
+ // Find region terminators.
+ op->walk<WalkOrder::PostOrder>([&](RegionBranchTerminatorOpInterface term) {
+ if (!traversedOps.insert(term))
return;
- ops.push_back(op);
+ // Follow the reverse SSA use-def chain from each yielded value as long as
+ // we stay within the same region.
+ SmallVector<OpResult> worklist;
+ for (Value v : term->getOperands()) {
+ if (!isa<TensorType>(v.getType()))
+ continue;
+ auto opResult = dyn_cast<OpResult>(v);
+ if (!opResult)
+ continue;
+ worklist.push_back(opResult);
+ }
+ while (!worklist.empty()) {
+ OpResult opResult = worklist.pop_back_val();
+ Operation *defOp = opResult.getDefiningOp();
+ if (!traversedOps.insert(defOp))
+ continue;
+ if (!term->getParentRegion()->findAncestorOpInRegion(*defOp))
+ continue;
+ AliasingOpOperandList aliases = state.getAliasingOpOperands(opResult);
+ for (auto alias : aliases) {
+ Value v = alias.opOperand->get();
+ if (!isa<TensorType>(v.getType()))
+ continue;
+ auto opResult = dyn_cast<OpResult>(v);
+ if (!opResult)
+ continue;
+ worklist.push_back(opResult);
+ }
+ }
});
- if (getOptions().analysisFuzzerSeed) {
- // This is a fuzzer. For testing purposes only. Randomize the order in which
- // operations are analyzed. The bufferization quality is likely worse, but
- // we want to make sure that no assertions are triggered anywhere.
- std::mt19937 g(getOptions().analysisFuzzerSeed);
- llvm::shuffle(ops.begin(), ops.end(), g);
- }
+ // Analyze traversed ops, then all remaining ops.
+ SmallVector<Operation *> result(traversedOps.begin(), traversedOps.end());
+ op->walk<WalkOrder::PostOrder, ReverseIterator>([&](Operation *op) {
+ if (!traversedOps.contains(op) && hasTensorSemantics(op))
+ result.push_back(op);
+ });
+ return result;
+}
+LogicalResult OneShotAnalysisState::analyzeOp(Operation *op,
+ const DominanceInfo &domInfo) {
OneShotBufferizationOptions::AnalysisHeuristic heuristic =
getOptions().analysisHeuristic;
- if (heuristic == OneShotBufferizationOptions::AnalysisHeuristic::BottomUp) {
- // Default: Walk ops in reverse for better interference analysis.
- for (Operation *op : reverse(ops))
- if (failed(analyzeSingleOp(op, domInfo)))
- return failure();
- } else if (heuristic ==
- OneShotBufferizationOptions::AnalysisHeuristic::TopDown) {
- for (Operation *op : ops)
- if (failed(analyzeSingleOp(op, domInfo)))
- return failure();
+
+ SmallVector<Operation *> orderedOps;
+ if (heuristic ==
+ OneShotBufferizationOptions::AnalysisHeuristic::BottomUpFromTerminators) {
+ orderedOps = bottomUpFromTerminatorsHeuristic(op, *this);
} else {
- llvm_unreachable("unsupported heuristic");
+ op->walk([&](Operation *op) {
+ // No tensors => no buffers.
+ if (!hasTensorSemantics(op))
+ return;
+ orderedOps.push_back(op);
+ });
+ if (heuristic == OneShotBufferizationOptions::AnalysisHeuristic::BottomUp) {
+ // Default: Walk ops in reverse for better interference analysis.
+ std::reverse(orderedOps.begin(), orderedOps.end());
+ } else if (heuristic ==
+ OneShotBufferizationOptions::AnalysisHeuristic::TopDown) {
+ // Ops are already sorted top-down in `orderedOps`.
+ } else if (heuristic ==
+ OneShotBufferizationOptions::AnalysisHeuristic::Fuzzer) {
+ assert(getOptions().analysisFuzzerSeed &&
+ "expected that fuzzer seed it set");
+ // This is a fuzzer. For testing purposes only. Randomize the order in
+ // which operations are analyzed. The bufferization quality is likely
+ // worse, but we want to make sure that no assertions are triggered
+ // anywhere.
+ std::mt19937 g(getOptions().analysisFuzzerSeed);
+ llvm::shuffle(orderedOps.begin(), orderedOps.end(), g);
+ } else {
+ llvm_unreachable("unsupported heuristic");
+ }
}
+ // Analyze ops in the computed order.
+ for (Operation *op : orderedOps)
+ if (failed(analyzeSingleOp(op, domInfo)))
+ return failure();
+
equivalenceAnalysis(op, *this);
return success();
}
diff --git a/mlir/test/Dialect/Arith/one-shot-bufferize.mlir b/mlir/test/Dialect/Arith/one-shot-bufferize.mlir
index 174bf2fc8e4bc7..f6bdca7f4d9e56 100644
--- a/mlir/test/Dialect/Arith/one-shot-bufferize.mlir
+++ b/mlir/test/Dialect/Arith/one-shot-bufferize.mlir
@@ -1,9 +1,9 @@
// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries" -split-input-file | FileCheck %s
// Run fuzzer with different seeds.
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=23 bufferize-function-boundaries" -split-input-file -o /dev/null
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=59 bufferize-function-boundaries" -split-input-file -o /dev/null
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=91 bufferize-function-boundaries" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=23 bufferize-function-boundaries" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=59 bufferize-function-boundaries" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=91 bufferize-function-boundaries" -split-input-file -o /dev/null
// Test bufferization using memref types that have no layout map.
// RUN: mlir-opt %s -one-shot-bufferize="unknown-type-conversion=identity-layout-map function-boundary-type-conversion=identity-layout-map bufferize-function-boundaries" -split-input-file -o /dev/null
diff --git a/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-allow-return-allocs.mlir b/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-allow-return-allocs.mlir
index e4375950d33637..8f0170b17381a4 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-allow-return-allocs.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-allow-return-allocs.mlir
@@ -1,9 +1,9 @@
// RUN: mlir-opt %s -one-shot-bufferize="allow-unknown-ops" -canonicalize -split-input-file | FileCheck %s
// Run fuzzer with different seeds.
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=23" -split-input-file -o /dev/null
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=59" -split-input-file -o /dev/null
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=91" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=23" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=59" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=91" -split-input-file -o /dev/null
// CHECK-LABEL: func @buffer_not_deallocated(
// CHECK-SAME: %[[t:.*]]: tensor<?xf32>
diff --git a/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-analysis-bottom-up-from-terminators.mlir b/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-analysis-bottom-up-from-terminators.mlir
new file mode 100644
index 00000000000000..1b75edc4c157fc
--- /dev/null
+++ b/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-analysis-bottom-up-from-terminators.mlir
@@ -0,0 +1,36 @@
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=bottom-up-from-terminators" -split-input-file | FileCheck %s
+
+// CHECK-LABEL: func @simple_test(
+func.func @simple_test(%lb: index, %ub: index, %step: index, %f1: f32, %f2: f32) -> (tensor<5xf32>, tensor<5xf32>) {
+ %c0 = arith.constant 0 : index
+ %p = arith.constant 0.0 : f32
+
+ // Make sure that ops that feed into region terminators bufferize in-place
+ // (if possible).
+ // Note: This test case fails to bufferize with a "top-down" or "bottom-up"
+ // heuristic.
+
+ %0 = tensor.empty() : tensor<5xf32>
+ %1 = scf.for %iv = %lb to %ub step %step iter_args(%t = %0) -> (tensor<5xf32>) {
+ // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "false"]}
+ %2 = linalg.fill ins(%f1 : f32) outs(%t : tensor<5xf32>) -> tensor<5xf32>
+ // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}
+ %3 = linalg.fill ins(%f2 : f32) outs(%t : tensor<5xf32>) -> tensor<5xf32>
+ %4 = vector.transfer_read %2[%c0], %p : tensor<5xf32>, vector<5xf32>
+ vector.print %4 : vector<5xf32>
+ scf.yield %3 : tensor<5xf32>
+ }
+
+ %5 = tensor.empty() : tensor<5xf32>
+ %6 = scf.for %iv = %lb to %ub step %step iter_args(%t = %0) -> (tensor<5xf32>) {
+ // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "true"]}
+ %7 = linalg.fill ins(%f1 : f32) outs(%t : tensor<5xf32>) -> tensor<5xf32>
+ // CHECK: linalg.fill {__inplace_operands_attr__ = ["none", "false"]}
+ %8 = linalg.fill ins(%f2 : f32) outs(%t : tensor<5xf32>) -> tensor<5xf32>
+ %9 = vector.transfer_read %8[%c0], %p : tensor<5xf32>, vector<5xf32>
+ vector.print %9 : vector<5xf32>
+ scf.yield %7 : tensor<5xf32>
+ }
+
+ return %1, %6 : tensor<5xf32>, tensor<5xf32>
+}
diff --git a/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-partial.mlir b/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-partial.mlir
index 2c5f2083f58908..9380c81ce235cd 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-partial.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize-partial.mlir
@@ -4,9 +4,9 @@
// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="allow-unknown-ops unknown-type-conversion=identity-layout-map" -split-input-file | FileCheck %s --check-prefix=CHECK-NO-LAYOUT-MAP
// Run fuzzer with different seeds.
-// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=23" -split-input-file -o /dev/null
-// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=59" -split-input-file -o /dev/null
-// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=91" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=23" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=59" -split-input-file -o /dev/null
+// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=91" -split-input-file -o /dev/null
// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="dialect-filter=tensor,bufferization allow-unknown-ops" -canonicalize -split-input-file | FileCheck %s --check-prefix=CHECK-TENSOR
// RUN: mlir-opt %s -allow-unregistered-dialect -one-shot-bufferize="dialect-filter=scf,bufferization allow-unknown-ops" -canonicalize -split-input-file | FileCheck %s --check-prefix=CHECK-SCF
diff --git a/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize.mlir b/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize.mlir
index 611b67e198c000..0ed3a9f077ce0e 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/one-shot-bufferize.mlir
@@ -1,9 +1,9 @@
// RUN: mlir-opt %s -one-shot-bufferize="allow-unknown-ops" -verify-diagnostics -split-input-file | FileCheck %s
// Run fuzzer with different seeds.
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=23" -verify-diagnostics -split-input-file -o /dev/null
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=59" -verify-diagnostics -split-input-file -o /dev/null
-// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-fuzzer-seed=91" -verify-diagnostics -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=23" -verify-diagnostics -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=59" -verify-diagnostics -split-input-file -o /dev/null
+// RUN: mlir-opt %s -one-shot-bufferize="test-analysis-only analysis-heuristic=fuzzer analysis-fuzzer-seed=91" -verify-diagnostics -split-input-file -o /dev/null
// Run with top-down analysis.
// RUN: mlir-opt %s -one-shot-bufferize="allow-unknown-ops analysis-heuristic=top-down" -verify-diagnostics -split-input-file | FileCheck %s --check-prefix=CHECK-TOP-DOWN-ANALYSIS
diff --git a/mlir/test/Dialect/Bufferization/Transforms/one-shot-module-bufferize-allow-return-allocs.mlir b/mlir/test/Dialect/Bufferization/Transforms/one-shot-module-bufferize-allow-return-allocs.mlir
index 9319ac61d928eb..c58b153d438caf 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/one-shot-module-bufferize-allow-return-allocs.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/one-shot-module-bufferize-allow-return-allocs.mlir
@@ -2,9 +2,9 @@
// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 " -split-input-file | FileCheck %s --check-prefix=NO-DROP
// Run fuzzer with different seeds.
-// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 test-analysis-only analysis-fuzzer-seed=23" -split-input-file -o /dev/null
-// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 test-analysis-only analysis-fuzzer-seed=59" -split-input-file -o /dev/null
-// RUN: mlir-opt %s -one-shot-bufferize="bufferize-function-boundaries=1 test-analysis-only analysis-fuzzer-seed=91" -split-input-file -o /dev/null
...
[truncated]
|
…stic One-Shot Bufferize currently does not support loops where a yielded value bufferizes to a buffer that is different from the buffer of the region iter_arg. In such a case, the bufferization fails with an error such as: ``` Yield operand #0 is not equivalent to the corresponding iter bbArg scf.yield %0 : tensor<5xf32> ``` One common reason for non-equivalent buffers is that an op on the path from the region iter_arg to the terminator bufferizes out-of-place. Ops that are analyzed earlier are more likely to bufferize in-place. This commit adds a new heuristic that gives preference to ops that are reachable on the reverse SSA use-def chain from a region terminator and are within the parent region of the terminator. This is expected to work better than the existing heuristics for loops where an iter_arg is written to multiple times within a loop, but only one write is fed into the terminator. Current users of One-Shot Bufferize are not affected by this change. "Bottom-up" is still the default heuristic. Users can switch to the new heuristic manually. This commit also turns the "fuzzer" pass option into a heuristic, cleaning up the code a bit.
7248f4e
to
b16301f
Compare
…stic (llvm#83964) One-Shot Bufferize currently does not support loops where a yielded value bufferizes to a buffer that is different from the buffer of the region iter_arg. In such a case, the bufferization fails with an error such as: ``` Yield operand #0 is not equivalent to the corresponding iter bbArg scf.yield %0 : tensor<5xf32> ``` One common reason for non-equivalent buffers is that an op on the path from the region iter_arg to the terminator bufferizes out-of-place. Ops that are analyzed earlier are more likely to bufferize in-place. This commit adds a new heuristic that gives preference to ops that are reachable on the reverse SSA use-def chain from a region terminator and are within the parent region of the terminator. This is expected to work better than the existing heuristics for loops where an iter_arg is written to multiple times within a loop, but only one write is fed into the terminator. Current users of One-Shot Bufferize are not affected by this change. "Bottom-up" is still the default heuristic. Users can switch to the new heuristic manually. This commit also turns the "fuzzer" pass option into a heuristic, cleaning up the code a bit.
One-Shot Bufferize currently does not support loops where a yielded value bufferizes to a buffer that is different from the buffer of the region iter_arg. In such a case, the bufferization fails with an error such as:
One common reason for non-equivalent buffers is that an op on the path from the region iter_arg to the terminator bufferizes out-of-place. Ops that are analyzed earlier are more likely to bufferize in-place.
This commit adds a new heuristic that gives preference to ops that are reachable on the reverse SSA use-def chain from a region terminator and are within the parent region of the terminator. This is expected to work better than the existing heuristics for loops where an iter_arg is written to multiple times within a loop, but only one write is fed into the terminator.
Current users of One-Shot Bufferize are not affected by this change. "Bottom-up" is still the default heuristic. Users can switch to the new heuristic manually.
This commit also turns the "fuzzer" pass option into a heuristic, cleaning up the code a bit.