Skip to content

Commit e07a7fd

Browse files
[mlir][bufferization] Move ModuleBufferization to bufferization dialect
* Move Module Bufferization to the bufferization dialect. The implementation is split into `OneShotModuleBufferize.cpp` and `FuncBufferizableOpInterfaceImpl.cpp`, so that the external model implementation can be easily moved to the func dialect in the future. * Split and clean up test cases. A few test cases are still remaining in Linalg and will be updated separately. * `linalg.inplaceable` is renamed to `bufferization.writable` to accurately reflect its current usage. * Attributes and their verifiers are moved from the Linalg dialect to the Bufferization dialect. * Expand documentation. * Add a new flag to One-Shot Bufferize to allow for function boundary bufferization. Differential Revision: https://reviews.llvm.org/D122229
1 parent 3e1d2c3 commit e07a7fd

33 files changed

+1620
-1487
lines changed

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

Lines changed: 3 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -326,17 +326,12 @@ def BufferizableOpInterface : OpInterface<"BufferizableOpInterface"> {
326326
&& !bufferizableOp.getAliasingOpResult(opOperand, state).empty();
327327
}
328328

329-
// TODO: The following two attributes should belong to the tensor dialect.
330-
// The corresponding verifier should also be in the tensor dialect.
329+
// TODO: This attribute is deprecated. Use `bufferization.writable` or add
330+
// a new attribute in a different dialect.
331331
/// Attribute name used to mark region arguments that can be bufferized
332332
/// in-place during one-shot bufferization.
333333
constexpr const static ::llvm::StringLiteral
334-
kInplaceableAttrName = "linalg.inplaceable";
335-
336-
/// Attribute name used to mark the bufferization layout for region
337-
/// arguments during one-shot bufferization.
338-
constexpr const static ::llvm::StringLiteral
339-
kBufferLayoutAttrName = "linalg.buffer_layout";
334+
kInplaceableAttrName = "linalg.inplaceable";
340335
}];
341336
}
342337

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,19 @@ def Bufferization_Dialect : Dialect {
2626
deallocation](/docs/BufferDeallocationInternals/).
2727
}];
2828
let dependentDialects = ["memref::MemRefDialect", "tensor::TensorDialect"];
29+
30+
let extraClassDeclaration = [{
31+
/// An attribute that can override writability of buffers of tensor function
32+
/// arguments during One-Shot Module Bufferize.
33+
constexpr const static ::llvm::StringLiteral
34+
kWritableAttrName = "bufferization.writable";
35+
36+
/// Attribute name used to mark the bufferization layout for region
37+
/// arguments during One-Shot Module Bufferize.
38+
constexpr const static ::llvm::StringLiteral
39+
kBufferLayoutAttrName = "bufferization.buffer_layout";
40+
}];
41+
let hasOperationAttrVerify = 1;
2942
}
3043

3144
#endif // BUFFERIZATION_BASE
Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
//===- BufferizableOpInterfaceImpl.h - Impl. of BufferizableOpInterface ---===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef MLIR_BUFFERIZATION_TRANSFORMS_FUNCBUFFERIZABLEOPINTERFACEIMPL_H
10+
#define MLIR_BUFFERIZATION_TRANSFORMS_FUNCBUFFERIZABLEOPINTERFACEIMPL_H
11+
12+
#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
13+
14+
namespace mlir {
15+
class DialectRegistry;
16+
17+
namespace func {
18+
class FuncOp;
19+
} // namespace func
20+
21+
namespace bufferization {
22+
namespace func_ext {
23+
/// The state of analysis of a FuncOp.
24+
enum class FuncOpAnalysisState { NotAnalyzed, InProgress, Analyzed };
25+
26+
using func::FuncOp;
27+
28+
/// Extra analysis state that is required for bufferization of function
29+
/// boundaries.
30+
struct FuncAnalysisState : public DialectAnalysisState {
31+
// Note: Function arguments and/or function return values may disappear during
32+
// bufferization. Functions and their CallOps are analyzed and bufferized
33+
// separately. To ensure that a CallOp analysis/bufferization can access an
34+
// already bufferized function's analysis results, we store bbArg/return value
35+
// indices instead of BlockArguments/OpOperand pointers.
36+
37+
/// A set of block argument indices.
38+
using BbArgIndexSet = DenseSet<int64_t>;
39+
40+
/// A mapping of indices to indices.
41+
using IndexMapping = DenseMap<int64_t, int64_t>;
42+
43+
/// A mapping of indices to a list of indices.
44+
using IndexToIndexListMapping = DenseMap<int64_t, SmallVector<int64_t>>;
45+
46+
/// A mapping of ReturnOp OpOperand indices to equivalent FuncOp BBArg
47+
/// indices.
48+
DenseMap<FuncOp, IndexMapping> equivalentFuncArgs;
49+
50+
/// A mapping of ReturnOp OpOperand indices to aliasing FuncOp BBArg indices.
51+
DenseMap<FuncOp, IndexToIndexListMapping> aliasingFuncArgs;
52+
53+
/// A mapping of FuncOp BBArg indices to aliasing ReturnOp OpOperand indices.
54+
DenseMap<FuncOp, IndexToIndexListMapping> aliasingReturnVals;
55+
56+
/// A set of all read BlockArguments of FuncOps.
57+
DenseMap<FuncOp, BbArgIndexSet> readBbArgs;
58+
59+
/// A set of all written-to BlockArguments of FuncOps.
60+
DenseMap<FuncOp, BbArgIndexSet> writtenBbArgs;
61+
62+
/// Keep track of which FuncOps are fully analyzed or currently being
63+
/// analyzed.
64+
DenseMap<FuncOp, FuncOpAnalysisState> analyzedFuncOps;
65+
66+
/// This function is called right before analyzing the given FuncOp. It
67+
/// initializes the data structures for the FuncOp in this state object.
68+
void startFunctionAnalysis(FuncOp funcOp);
69+
};
70+
71+
void registerBufferizableOpInterfaceExternalModels(DialectRegistry &registry);
72+
} // namespace func_ext
73+
} // namespace bufferization
74+
} // namespace mlir
75+
76+
#endif // MLIR_BUFFERIZATION_TRANSFORMS_FUNCBUFFERIZABLEOPINTERFACEIMPL_H
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//===- OneShotModuleBufferize.h - Bufferization across Func. Boundaries ---===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#ifndef MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_ONESHOTMODULEBUFFERIZE_H
10+
#define MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_ONESHOTMODULEBUFFERIZE_H
11+
12+
namespace mlir {
13+
14+
struct LogicalResult;
15+
class ModuleOp;
16+
17+
namespace bufferization {
18+
struct OneShotBufferizationOptions;
19+
20+
/// Run One-Shot Module Bufferization on the given module. Performs a simple
21+
/// function call analysis to determine which function arguments are
22+
/// inplaceable. Then analyzes and bufferizes FuncOps one-by-one with One-Shot
23+
/// Bufferize.
24+
LogicalResult
25+
runOneShotModuleBufferize(ModuleOp moduleOp,
26+
bufferization::OneShotBufferizationOptions options);
27+
28+
} // namespace bufferization
29+
} // namespace mlir
30+
31+
#endif // MLIR_DIALECT_BUFFERIZATION_TRANSFORMS_ONESHOTMODULEBUFFERIZE_H

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

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,34 @@ def OneShotBufferize : Pass<"one-shot-bufferize", "ModuleOp"> {
200200
prints analysis results and explains why an OpOperand was decided to
201201
bufferize out-of-place. This is useful for understanding why One-Shot
202202
Bufferize chose to insert a certain buffer copy.
203+
204+
`bufferize-function-boundaries` is an experimental flag for bufferizing
205+
`FuncOp`, `ReturnOp` and `CallOp`. This feature is still under development
206+
and supports only simple cases at the moment. In particular:
207+
208+
* Recursive or circular function call graphs are not supported.
209+
* If a newly allocated buffer is returned from a function (with
210+
`allow-return-allocs`), the buffer will never be deallocated and leak.
211+
Such IR needs special handling, e.g., allocation hoisting or reference
212+
counting.
213+
* External functions (without bodies) that return a tensor are not
214+
supported.
215+
* Function with multiple blocks or multiple ReturnOps are not supported.
216+
217+
One-Shot Bufferize implements the following contract around function calls:
218+
The buffer of function arguments is always writable (unless annotated with
219+
`bufferization.writable = false`). A buffer copy may be inserted at the call
220+
site where necessary. Alias sets and equivalence info is propagated through
221+
function calls. Whenever a function is bufferized, all other functions that
222+
are being called were already analyzed and bufferized, so exact alias and
223+
equivalence information is available. This is why recursive function calls
224+
are not yet supported.
225+
226+
One-Shot Bufferize gathers additional information during the analysis phase
227+
when function boundary bufferization is activated. E.g., whether a function
228+
argument is read/written and which returned values are aliasing/equivalent.
229+
For debugging purposes, such information can be printed with
230+
`test-analysis-only`.
203231
}];
204232
let options = [
205233
Option<"allowReturnAllocs", "allow-return-allocs", "bool",
@@ -211,6 +239,9 @@ def OneShotBufferize : Pass<"one-shot-bufferize", "ModuleOp"> {
211239
Option<"analysisFuzzerSeed", "analysis-fuzzer-seed", "unsigned",
212240
/*default=*/"0",
213241
"Test only: Analyze ops in random order with a given seed (fuzzer)">,
242+
Option<"bufferizeFunctionBoundaries", "bufferize-function-boundaries",
243+
"bool", /*default=*/"0",
244+
"Bufferize function boundaries (experimental).">,
214245
Option<"createDeallocs", "create-deallocs", "bool", /*default=*/"true",
215246
"Specify if buffers should be deallocated. For compatibility with "
216247
"core bufferization passes.">,

mlir/include/mlir/Dialect/Linalg/CMakeLists.txt

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
add_subdirectory(ComprehensiveBufferize)
21
add_subdirectory(IR)
32

43
set(LLVM_TARGET_DEFINITIONS Passes.td)

mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/CMakeLists.txt

Lines changed: 0 additions & 2 deletions
This file was deleted.

mlir/include/mlir/Dialect/Linalg/ComprehensiveBufferize/ModuleBufferization.h

Lines changed: 0 additions & 43 deletions
This file was deleted.

mlir/include/mlir/InitAllDialects.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "mlir/Dialect/ArmSVE/ArmSVEDialect.h"
2323
#include "mlir/Dialect/Async/IR/Async.h"
2424
#include "mlir/Dialect/Bufferization/IR/Bufferization.h"
25+
#include "mlir/Dialect/Bufferization/Transforms/FuncBufferizableOpInterfaceImpl.h"
2526
#include "mlir/Dialect/Complex/IR/Complex.h"
2627
#include "mlir/Dialect/ControlFlow/IR/ControlFlow.h"
2728
#include "mlir/Dialect/DLTI/DLTI.h"
@@ -46,6 +47,7 @@
4647
#include "mlir/Dialect/SCF/SCF.h"
4748
#include "mlir/Dialect/SPIRV/IR/SPIRVDialect.h"
4849
#include "mlir/Dialect/Shape/IR/Shape.h"
50+
#include "mlir/Dialect/Shape/Transforms/BufferizableOpInterfaceImpl.h"
4951
#include "mlir/Dialect/SparseTensor/IR/SparseTensor.h"
5052
#include "mlir/Dialect/Tensor/IR/Tensor.h"
5153
#include "mlir/Dialect/Tensor/IR/TensorInferTypeOpInterfaceImpl.h"
@@ -100,8 +102,11 @@ inline void registerAllDialects(DialectRegistry &registry) {
100102
x86vector::X86VectorDialect>();
101103
// clang-format on
102104
arith::registerBufferizableOpInterfaceExternalModels(registry);
105+
bufferization::func_ext::registerBufferizableOpInterfaceExternalModels(
106+
registry);
103107
linalg::registerBufferizableOpInterfaceExternalModels(registry);
104108
scf::registerBufferizableOpInterfaceExternalModels(registry);
109+
shape::registerBufferizableOpInterfaceExternalModels(registry);
105110
tensor::registerBufferizableOpInterfaceExternalModels(registry);
106111
tensor::registerInferTypeOpInterfaceExternalModels(registry);
107112
tensor::registerTilingOpInterfaceExternalModels(registry);

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

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -33,11 +33,6 @@ namespace bufferization {
3333
using namespace mlir;
3434
using namespace bufferization;
3535

36-
/// Attribute name used to mark the bufferization layout for region
37-
/// arguments during linalg comprehensive bufferization.
38-
constexpr const ::llvm::StringLiteral
39-
bufferization::BufferizableOpInterface::kBufferLayoutAttrName;
40-
4136
/// Attribute name used to mark region arguments that can be bufferized
4237
/// in-place during linalg comprehensive bufferization.
4338
constexpr const ::llvm::StringLiteral

0 commit comments

Comments
 (0)