Skip to content

Commit 1647897

Browse files
committed
[mlir][bufferization] Add OwnershipBasedBufferDeallocation pass option to forbid clones
Adds a pass option to the `ownership-based-buffer-deallocation` pass to forbid insertion of clone operations. This is necessary to support IR that does not have the property that every buffer write dominates every buffer read to the same buffer. Instead of silently producing invalid IR, the pass would then emit an error. This is a restriction in the old `buffer-deallocation` pass, but the new function boundary ABI was not enforced in this old pass. Having this option allows easier migration from the old to the new deallocation pass because enabling this option allows the new deallocation pass to fix IR that does not adhere to the function boundary ABI (in some situations).
1 parent 6bf043e commit 1647897

File tree

17 files changed

+305
-104
lines changed

17 files changed

+305
-104
lines changed

mlir/include/mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,14 @@ struct DeallocationOptions {
9696
// pass the ownership of MemRef values instead of adhering to the function
9797
// boundary ABI.
9898
bool privateFuncDynamicOwnership = false;
99+
100+
// Allows the pass to insert `bufferization.clone` operations. This is useful
101+
// for supporting IR that does not adhere to the function boundary ABI
102+
// initially (excl. external functions) and to support operations with results
103+
// with 'Unknown' ownership. However, it requires that all buffer writes
104+
// dominate all buffer reads (i.e., only enable this option if your IR is
105+
// guaranteed to have this property).
106+
bool allowCloning = false;
99107
};
100108

101109
/// This class collects all the state that we need to perform the buffer
@@ -142,8 +150,9 @@ class DeallocationState {
142150
/// a new SSA value, returned as the first element of the pair, which has
143151
/// 'Unique' ownership and can be used instead of the passed Value with the
144152
/// the ownership indicator returned as the second element of the pair.
145-
std::pair<Value, Value>
146-
getMemrefWithUniqueOwnership(OpBuilder &builder, Value memref, Block *block);
153+
FailureOr<std::pair<Value, Value>>
154+
getMemrefWithUniqueOwnership(const DeallocationOptions &options,
155+
OpBuilder &builder, Value memref, Block *block);
147156

148157
/// Given two basic blocks and the values passed via block arguments to the
149158
/// destination block, compute the list of MemRefs that have to be retained in

mlir/include/mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.td

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ def BufferDeallocationOpInterface :
5656
method (which is especially important if operations are created that
5757
cannot be easily canonicalized away anymore).
5858
}],
59-
/*retType=*/"std::pair<Value, Value>",
59+
/*retType=*/"FailureOr<std::pair<Value, Value>>",
6060
/*methodName=*/"materializeUniqueOwnershipForMemref",
6161
/*args=*/(ins "DeallocationState &":$state,
6262
"const DeallocationOptions &":$options,
@@ -65,7 +65,7 @@ def BufferDeallocationOpInterface :
6565
/*methodBody=*/[{}],
6666
/*defaultImplementation=*/[{
6767
return state.getMemrefWithUniqueOwnership(
68-
builder, memref, memref.getParentBlock());
68+
options, builder, memref, memref.getParentBlock());
6969
}]>,
7070
];
7171
}

mlir/include/mlir/Dialect/Bufferization/Pipelines/Passes.h

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
namespace mlir {
1919
namespace bufferization {
20+
struct DeallocationOptions;
2021

2122
/// Options for the buffer deallocation pipeline.
2223
struct BufferDeallocationPipelineOptions
@@ -28,6 +29,22 @@ struct BufferDeallocationPipelineOptions
2829
"dynamically pass ownership of memrefs to callees. This can enable "
2930
"earlier deallocations."),
3031
llvm::cl::init(false)};
32+
PassOptions::Option<bool> allowCloning{
33+
*this, "allow-cloning",
34+
llvm::cl::desc(
35+
"Allows the pass to insert `bufferization.clone` operations. This is "
36+
"useful for supporting IR that does not adhere to the function "
37+
"boundary ABI initially (excl. external functions) and to support "
38+
"operations with results with 'Unknown' ownership. However, it "
39+
"requires that all buffer writes dominate all buffer reads (i.e., "
40+
"only enable this option if your IR is guaranteed to have this "
41+
"property)."),
42+
llvm::cl::init(false)};
43+
44+
/// Convert this BufferDeallocationPipelineOptions struct to a
45+
/// DeallocationOptions struct to be passed to the
46+
/// OwnershipBasedBufferDeallocationPass.
47+
DeallocationOptions asDeallocationOptions() const;
3148
};
3249

3350
//===----------------------------------------------------------------------===//

mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.h

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
#ifndef MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_PASSES_H
22
#define MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_PASSES_H
33

4+
#include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h"
45
#include "mlir/Pass/Pass.h"
56

67
namespace mlir {
@@ -31,7 +32,7 @@ std::unique_ptr<Pass> createBufferDeallocationPass();
3132
/// Creates an instance of the OwnershipBasedBufferDeallocation pass to free all
3233
/// allocated buffers.
3334
std::unique_ptr<Pass> createOwnershipBasedBufferDeallocationPass(
34-
bool privateFuncDynamicOwnership = false);
35+
const DeallocationOptions &options = DeallocationOptions());
3536

3637
/// Creates a pass that optimizes `bufferization.dealloc` operations. For
3738
/// example, it reduces the number of alias checks needed at runtime using
@@ -134,8 +135,9 @@ func::FuncOp buildDeallocationLibraryFunction(OpBuilder &builder, Location loc,
134135
LogicalResult deallocateBuffers(Operation *op);
135136

136137
/// Run ownership basedbuffer deallocation.
137-
LogicalResult deallocateBuffersOwnershipBased(FunctionOpInterface op,
138-
bool privateFuncDynamicOwnership);
138+
LogicalResult deallocateBuffersOwnershipBased(
139+
FunctionOpInterface op,
140+
const DeallocationOptions &options = DeallocationOptions());
139141

140142
/// Creates a pass that moves allocations upwards to reduce the number of
141143
/// required copies that are inserted during the BufferDeallocation pass.

mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -223,6 +223,14 @@ def OwnershipBasedBufferDeallocation : Pass<
223223
"Allows to add additional arguments to private functions to "
224224
"dynamically pass ownership of memrefs to callees. This can enable "
225225
"earlier deallocations.">,
226+
Option<"allowCloning", "allow-cloning", "bool", /*default=*/"false",
227+
"Allows the pass to insert `bufferization.clone` operations. This "
228+
"is useful for supporting IR that does not adhere to the function "
229+
"boundary ABI initially (excl. external functions) and to support "
230+
"operations with results with 'Unknown' ownership. However, it "
231+
"requires that all buffer writes dominate all buffer reads (i.e., "
232+
"only enable this option if your IR is guaranteed to have this "
233+
"property).">,
226234
];
227235
let constructor = "mlir::bufferization::createOwnershipBasedBufferDeallocationPass()";
228236

mlir/lib/Dialect/Arith/Transforms/BufferDeallocationOpInterfaceImpl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ struct SelectOpInterface
5353
return op; // nothing to do
5454
}
5555

56-
std::pair<Value, Value>
56+
FailureOr<std::pair<Value, Value>>
5757
materializeUniqueOwnershipForMemref(Operation *op, DeallocationState &state,
5858
const DeallocationOptions &options,
5959
OpBuilder &builder, Value value) const {
@@ -64,14 +64,14 @@ struct SelectOpInterface
6464
Block *block = value.getParentBlock();
6565
if (!state.getOwnership(selectOp.getTrueValue(), block).isUnique() ||
6666
!state.getOwnership(selectOp.getFalseValue(), block).isUnique())
67-
return state.getMemrefWithUniqueOwnership(builder, value,
67+
return state.getMemrefWithUniqueOwnership(options, builder, value,
6868
value.getParentBlock());
6969

7070
Value ownership = builder.create<arith::SelectOp>(
7171
op->getLoc(), selectOp.getCondition(),
7272
state.getOwnership(selectOp.getTrueValue(), block).getIndicator(),
7373
state.getOwnership(selectOp.getFalseValue(), block).getIndicator());
74-
return {selectOp.getResult(), ownership};
74+
return std::make_pair(selectOp.getResult(), ownership);
7575
}
7676
};
7777

mlir/lib/Dialect/Bufferization/IR/BufferDeallocationOpInterface.cpp

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -132,16 +132,21 @@ void DeallocationState::getLiveMemrefsIn(Block *block,
132132
memrefs.append(liveMemrefs);
133133
}
134134

135-
std::pair<Value, Value>
136-
DeallocationState::getMemrefWithUniqueOwnership(OpBuilder &builder,
137-
Value memref, Block *block) {
135+
FailureOr<std::pair<Value, Value>>
136+
DeallocationState::getMemrefWithUniqueOwnership(
137+
const DeallocationOptions &options, OpBuilder &builder, Value memref,
138+
Block *block) {
138139
auto iter = ownershipMap.find({memref, block});
139140
assert(iter != ownershipMap.end() &&
140141
"Value must already have been registered in the ownership map");
141142

142143
Ownership ownership = iter->second;
143144
if (ownership.isUnique())
144-
return {memref, ownership.getIndicator()};
145+
return std::make_pair(memref, ownership.getIndicator());
146+
147+
if (!options.allowCloning)
148+
return emitError(memref.getLoc(),
149+
"MemRef value does not have valid ownership");
145150

146151
// Instead of inserting a clone operation we could also insert a dealloc
147152
// operation earlier in the block and use the updated ownerships returned by
@@ -155,7 +160,7 @@ DeallocationState::getMemrefWithUniqueOwnership(OpBuilder &builder,
155160
Value newMemref = cloneOp.getResult();
156161
updateOwnership(newMemref, condition);
157162
memrefsToDeallocatePerBlock[newMemref.getParentBlock()].push_back(newMemref);
158-
return {newMemref, condition};
163+
return std::make_pair(newMemref, condition);
159164
}
160165

161166
void DeallocationState::getMemrefsToRetain(

mlir/lib/Dialect/Bufferization/Pipelines/BufferizationPipelines.cpp

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,35 @@
88

99
#include "mlir/Dialect/Bufferization/Pipelines/Passes.h"
1010

11+
#include "mlir/Dialect/Bufferization/IR/BufferDeallocationOpInterface.h"
1112
#include "mlir/Dialect/Bufferization/Transforms/Passes.h"
1213
#include "mlir/Dialect/Func/IR/FuncOps.h"
1314
#include "mlir/Dialect/MemRef/Transforms/Passes.h"
1415
#include "mlir/Pass/PassManager.h"
1516
#include "mlir/Transforms/Passes.h"
1617

18+
using namespace mlir;
19+
using namespace bufferization;
20+
1721
//===----------------------------------------------------------------------===//
1822
// Pipeline implementation.
1923
//===----------------------------------------------------------------------===//
2024

25+
DeallocationOptions
26+
BufferDeallocationPipelineOptions::asDeallocationOptions() const {
27+
DeallocationOptions opts;
28+
opts.privateFuncDynamicOwnership = privateFunctionDynamicOwnership.getValue();
29+
opts.allowCloning = allowCloning.getValue();
30+
return opts;
31+
}
32+
2133
void mlir::bufferization::buildBufferDeallocationPipeline(
2234
OpPassManager &pm, const BufferDeallocationPipelineOptions &options) {
2335
pm.addNestedPass<func::FuncOp>(
2436
memref::createExpandReallocPass(/*emitDeallocs=*/false));
2537
pm.addNestedPass<func::FuncOp>(createCanonicalizerPass());
2638
pm.addNestedPass<func::FuncOp>(createOwnershipBasedBufferDeallocationPass(
27-
options.privateFunctionDynamicOwnership.getValue()));
39+
options.asDeallocationOptions()));
2840
pm.addNestedPass<func::FuncOp>(createCanonicalizerPass());
2941
pm.addNestedPass<func::FuncOp>(createBufferDeallocationSimplificationPass());
3042
pm.addPass(createLowerDeallocationsPass());

mlir/lib/Dialect/Bufferization/Pipelines/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ add_mlir_dialect_library(MLIRBufferizationPipelines
55
${MLIR_MAIN_INCLUDE_DIR}/mlir/Dialect/Bufferization
66

77
LINK_LIBS PUBLIC
8+
MLIRBufferizationDialect
89
MLIRBufferizationTransforms
910
MLIRMemRefTransforms
1011
MLIRFuncDialect

0 commit comments

Comments
 (0)