MLIR 24.0.0git
SparsificationAndBufferizationPass.cpp
Go to the documentation of this file.
1//===- SparsificationAndBufferizationPass.cpp - Tensor to Memref Lowering -===//
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
10
28
29using namespace mlir;
30
31namespace mlir {
32
33#define GEN_PASS_DEF_SPARSIFICATIONANDBUFFERIZATION
34#include "mlir/Dialect/SparseTensor/Transforms/Passes.h.inc"
35
36namespace sparse_tensor {
37
38/// Return `true` if one of the given types is a sparse tensor type.
39static bool containsSparseTensor(TypeRange types) {
40 for (Type t : types)
41 if (isa<TensorType>(t) && getSparseTensorEncoding(t))
42 return true;
43 return false;
44}
45
46/// A pass that lowers tensor ops to memref ops, regardless of whether they are
47/// dense or sparse.
48///
49/// One-Shot Analysis is used to detect RaW conflicts and to insert buffer
50/// copies of the tensor level (`insertTensorCopies`). Afterwards, the lowering
51/// of tensor ops to memref ops follows a different code path depending on
52/// whether the op is sparse or dense:
53///
54/// * Sparse tensor ops are lowered through Sparsification and follow-up pass
55/// that lowers sparse_tensor dialect ops.
56/// * Dense tensor ops are lowered through BufferizableOpInterface
57/// implementations.
60 SparsificationAndBufferizationPass> {
61public:
62 // Bufferization, sparsification, and sparse storage options.
64 const bufferization::OneShotBufferizationOptions &bufferizationOptions,
65 const SparsificationOptions &sparsificationOptions,
66 bool createSparseDeallocs, bool enableRuntimeLibrary,
67 bool enableBufferInitialization)
68 : bufferizationOptions(bufferizationOptions),
69 sparsificationOptions(sparsificationOptions),
70 createSparseDeallocs(createSparseDeallocs),
71 enableBufferInitialization(enableBufferInitialization) {
72 this->enableRuntimeLibrary = enableRuntimeLibrary;
73 }
74 // Private pass options and visible pass options.
76 const bufferization::OneShotBufferizationOptions &bufferizationOptions,
77 const SparsificationOptions &sparsificationOptions,
78 bool createSparseDeallocs, bool enableRuntimeLibrary,
79 bool enableBufferInitialization, unsigned vl, bool vla, bool index32,
80 bool gpu, SparseEmitStrategy emitStrategy,
81 SparseParallelizationStrategy parallelizationStrategy)
82 : bufferizationOptions(bufferizationOptions),
83 sparsificationOptions(sparsificationOptions),
84 createSparseDeallocs(createSparseDeallocs),
85 enableBufferInitialization(enableBufferInitialization) {
86 // Set the visible pass options explicitly.
87 this->enableRuntimeLibrary = enableRuntimeLibrary;
88 vectorLength = vl;
90 enableSIMDIndex32 = index32;
92 sparseEmitStrategy = emitStrategy;
93 parallelization = parallelizationStrategy;
94 }
95
96 /// Bufferize all dense ops. This assumes that no further analysis is needed
97 /// and that all required buffer copies were already inserted by
98 /// `insertTensorCopies` in the form of `bufferization.alloc_tensor` ops.
99 LogicalResult runDenseBufferization() {
101 bufferizationOptions;
102 // Skip all sparse ops.
103 updatedOptions.opFilter.denyOperation([&](Operation *op) {
106 return true;
107 if (auto funcOp = dyn_cast<func::FuncOp>(op)) {
108 FunctionType funcType = funcOp.getFunctionType();
109 if (containsSparseTensor(funcType.getInputs()) ||
110 containsSparseTensor(funcType.getResults()))
111 return true;
112 }
113 return false;
114 });
115
116 bufferization::BufferizationState bufferizationState;
117
118 if (failed(bufferization::bufferizeModuleOp(getOperation(), updatedOptions,
119 bufferizationState)))
120 return failure();
121
123 return success();
124 }
125
126 void runOnOperation() override {
127 // Overrides the default emit strategy using user-provided value.
128 this->sparsificationOptions.sparseEmitStrategy = sparseEmitStrategy;
129
130 // Overrides the default parallelization strategy using user-provided value.
131 this->sparsificationOptions.parallelizationStrategy = parallelization;
132
133 // Keep sparsification and sparse storage lowering on the same runtime path.
134 this->sparsificationOptions.enableRuntimeLibrary = enableRuntimeLibrary;
135
136 // Run enabling transformations.
137 {
138 OpPassManager pm("builtin.module");
140 pm.addNestedPass<func::FuncOp>(
142 if (failed(runPipeline(pm, getOperation())))
143 return signalPassFailure();
144 }
145
146 // Insert tensor copies. This step runs One-Shot Analysis (which analyzes
147 // SSA use-def chains of tensor IR) and decides where buffer copies are
148 // needed and where buffers can be written to in-place. These decisions are
149 // materialized in the IR in the form of `bufferization.alloc_tensor` ops.
150 //
151 // Note: All following steps in this pass must be careful not to modify the
152 // structure of the IR (i.e., tensor use-def chains), as that could
153 // invalidate the results of the analysis. From now on, only small and
154 // localized rewrites are allowed, such as replacing a tensor op with its
155 // memref equivalent.
156 bufferization::BufferizationState bufferizationState;
157
159 getOperation(), bufferizationOptions, bufferizationState)))
160 return signalPassFailure();
161
162 // Option `testAnalysisOnly` is a debug/testing flag. If set, the results of
163 // OneShotAnalysis are added to the IR via attributes. In that case, do not
164 // continue with the remaining pipeline.
165 if (bufferizationOptions.testAnalysisOnly)
166 return;
167
168 // Bufferize all sparse ops. No further analysis is needed. All required
169 // buffer copies were already inserted by `insertTensorCopies` in the form
170 // of `bufferization.alloc_tensor` ops.
171 {
172 OpPassManager pm("builtin.module");
173 if (enableGPULibgen)
176 pm.addPass(createSparsificationPass(sparsificationOptions));
177 if (sparsificationOptions.sparseEmitStrategy ==
181 }
182
185 /*enableConvert=*/true));
186 pm.addPass(
188 pm.addNestedPass<func::FuncOp>(createLowerForeachToSCFPass());
190 if (vectorLength > 0) {
193 }
196 } else {
197 pm.addPass(createSparseTensorCodegenPass(createSparseDeallocs,
198 enableBufferInitialization));
199 pm.addPass(createSparseBufferRewritePass(enableBufferInitialization));
200 }
201 if (failed(runPipeline(pm, getOperation())))
202 return signalPassFailure();
203 }
204
205 // Bufferize all dense ops.
206 if (failed(runDenseBufferization()))
208 }
209
210private:
212 SparsificationOptions sparsificationOptions;
213 bool createSparseDeallocs;
214 bool enableBufferInitialization;
215};
216
217} // namespace sparse_tensor
218} // namespace mlir
219
222 using namespace mlir::bufferization;
224 options.bufferizeFunctionBoundaries = true;
225 options.setFunctionBoundaryTypeConversion(LayoutMapOption::IdentityLayoutMap);
226 options.unknownTypeConverterFn = [](TensorLikeType tensorType,
227 Attribute memorySpace,
229 return cast<bufferization::BufferLikeType>(
230 getMemRefTypeWithStaticIdentityLayout(cast<TensorType>(tensorType),
231 memorySpace));
232 };
233 if (analysisOnly) {
234 options.testAnalysisOnly = true;
235 options.printConflicts = true;
236 }
237 // Since this mini-pipeline may be used in alternative pipelines (viz.
238 // different from the default "sparsifier" pipeline) where unknown ops
239 // are handled by alternative bufferization methods that are downstream
240 // of this mini-pipeline, we allow unknown ops by default (failure to
241 // bufferize is eventually apparent by failing to convert to LLVM IR).
242 options.allowUnknownOps = true;
243 return options;
244}
245
247 SparsificationOptions sparseOptions;
248 return std::make_unique<
250 getBufferizationOptionsForSparsification(/*analysisOnly=*/false),
251 sparseOptions,
252 /*createSparseDeallocs=*/false,
253 /*enableRuntimeLibrary=*/false,
254 /*enableBufferInitialization=*/false);
255}
256
258 const bufferization::OneShotBufferizationOptions &bufferizationOptions,
259 const SparsificationOptions &sparsificationOptions,
260 bool createSparseDeallocs, bool enableRuntimeLibrary,
261 bool enableBufferInitialization, unsigned vectorLength,
262 bool enableVLAVectorization, bool enableSIMDIndex32, bool enableGPULibgen,
263 SparseEmitStrategy emitStrategy,
264 SparseParallelizationStrategy parallelizationStrategy) {
265 return std::make_unique<
267 bufferizationOptions, sparsificationOptions, createSparseDeallocs,
268 enableRuntimeLibrary, enableBufferInitialization, vectorLength,
269 enableVLAVectorization, enableSIMDIndex32, enableGPULibgen, emitStrategy,
270 parallelizationStrategy);
271}
return success()
static llvm::ManagedStatic< PassManagerOptions > options
Attributes are known-constant values of operations.
Definition Attributes.h:25
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition Pass.cpp:393
void addNestedPass(std::unique_ptr< Pass > pass)
Add the given pass to a nested pass manager for the given operation kind OpT.
Operation is the basic unit of execution within MLIR.
Definition Operation.h:87
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:403
result_range getResults()
Definition Operation.h:440
LogicalResult runPipeline(OpPassManager &pipeline, Operation *op)
Schedule an arbitrary pass pipeline on the provided operation.
Definition Pass.h:208
friend class OpPassManager
Allow access to 'clone'.
Definition Pass.h:335
void signalPassFailure()
Signal that some invariant was broken when running.
Definition Pass.h:226
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:40
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition Types.h:74
A pass that lowers tensor ops to memref ops, regardless of whether they are dense or sparse.
SparsificationAndBufferizationPass(const bufferization::OneShotBufferizationOptions &bufferizationOptions, const SparsificationOptions &sparsificationOptions, bool createSparseDeallocs, bool enableRuntimeLibrary, bool enableBufferInitialization, unsigned vl, bool vla, bool index32, bool gpu, SparseEmitStrategy emitStrategy, SparseParallelizationStrategy parallelizationStrategy)
void runOnOperation() override
The polymorphic API that runs the pass over the currently held operation.
SparsificationAndBufferizationPass(const bufferization::OneShotBufferizationOptions &bufferizationOptions, const SparsificationOptions &sparsificationOptions, bool createSparseDeallocs, bool enableRuntimeLibrary, bool enableBufferInitialization)
llvm::LogicalResult bufferizeModuleOp(Operation *moduleOp, const OneShotBufferizationOptions &options, BufferizationState &state, BufferizationStatistics *statistics=nullptr)
Bufferize an ops nested ops that implement BufferizableOpInterface.
void removeBufferizationAttributesInModule(Operation *moduleOp)
Remove bufferization attributes on every FuncOp arguments in the SymbolTable op.
LogicalResult insertTensorCopies(Operation *op, const OneShotBufferizationOptions &options, const BufferizationState &bufferizationState, BufferizationStatistics *statistics=nullptr)
Resolve RaW and other conflicts by inserting bufferization.alloc_tensor ops.
std::unique_ptr<::mlir::Pass > createEmptyTensorToAllocTensorPass()
static bool containsSparseTensor(TypeRange types)
Return true if one of the given types is a sparse tensor type.
SparseTensorEncodingAttr getSparseTensorEncoding(Type type)
Convenience method to get a sparse encoding attribute from a type.
Include the generated interface declarations.
std::unique_ptr< Pass > createSparseVectorizationPass()
std::unique_ptr< Pass > createLowerSparseOpsToForeachPass()
std::unique_ptr< Pass > createSparseTensorCodegenPass()
std::unique_ptr< Pass > createSparseGPUCodegenPass()
std::unique_ptr< Pass > createSparseSpaceCollapsePass()
bufferization::OneShotBufferizationOptions getBufferizationOptionsForSparsification(bool analysisOnly)
std::unique_ptr< Pass > createSparseReinterpretMapPass()
std::unique_ptr< Pass > createSparseTensorConversionPass()
std::unique_ptr< Pass > createSparseBufferRewritePass()
std::unique_ptr< Pass > createSparsificationAndBufferizationPass()
SparseParallelizationStrategy
Defines a parallelization strategy.
Definition Passes.h:36
SparseEmitStrategy
Defines a scope for reinterpret map pass.
Definition Passes.h:52
std::unique_ptr< Pass > createPreSparsificationRewritePass()
std::unique_ptr< Pass > createLowerForeachToSCFPass()
std::unique_ptr<::mlir::Pass > createLoopInvariantCodeMotionPass()
std::unique_ptr< Pass > createLowerSparseIterationToSCFPass()
std::unique_ptr< Pass > createStageSparseOperationsPass()
std::unique_ptr< Pass > createSparsificationPass()
Options for the Sparsification pass.
Definition Passes.h:110
Options for analysis-enabled bufferization.