MLIR 22.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 // Private pass options only.
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 enableRuntimeLibrary(enableRuntimeLibrary),
72 enableBufferInitialization(enableBufferInitialization) {}
73 // Private pass options and visible pass options.
75 const bufferization::OneShotBufferizationOptions &bufferizationOptions,
76 const SparsificationOptions &sparsificationOptions,
77 bool createSparseDeallocs, bool enableRuntimeLibrary,
78 bool enableBufferInitialization, unsigned vl, bool vla, bool index32,
79 bool gpu, SparseEmitStrategy emitStrategy,
80 SparseParallelizationStrategy parallelizationStrategy)
81 : bufferizationOptions(bufferizationOptions),
82 sparsificationOptions(sparsificationOptions),
83 createSparseDeallocs(createSparseDeallocs),
84 enableRuntimeLibrary(enableRuntimeLibrary),
85 enableBufferInitialization(enableBufferInitialization) {
86 // Set the visible pass options explicitly.
87 vectorLength = vl;
89 enableSIMDIndex32 = index32;
91 sparseEmitStrategy = emitStrategy;
92 parallelization = parallelizationStrategy;
93 }
94
95 /// Bufferize all dense ops. This assumes that no further analysis is needed
96 /// and that all required buffer copies were already inserted by
97 /// `insertTensorCopies` in the form of `bufferization.alloc_tensor` ops.
98 LogicalResult runDenseBufferization() {
100 bufferizationOptions;
101 // Skip all sparse ops.
102 updatedOptions.opFilter.denyOperation([&](Operation *op) {
105 return true;
106 if (auto funcOp = dyn_cast<func::FuncOp>(op)) {
107 FunctionType funcType = funcOp.getFunctionType();
108 if (containsSparseTensor(funcType.getInputs()) ||
109 containsSparseTensor(funcType.getResults()))
110 return true;
111 }
112 return false;
113 });
114
115 bufferization::BufferizationState bufferizationState;
116
117 if (failed(bufferization::bufferizeModuleOp(getOperation(), updatedOptions,
118 bufferizationState)))
119 return failure();
120
122 return success();
123 }
124
125 void runOnOperation() override {
126 // Overrides the default emit strategy using user-provided value.
127 this->sparsificationOptions.sparseEmitStrategy = sparseEmitStrategy;
128
129 // Overrides the default parallelization strategy using user-provided value.
130 this->sparsificationOptions.parallelizationStrategy = parallelization;
131
132 // Run enabling transformations.
133 {
134 OpPassManager pm("builtin.module");
136 pm.addNestedPass<func::FuncOp>(
138 if (failed(runPipeline(pm, getOperation())))
139 return signalPassFailure();
140 }
141
142 // Insert tensor copies. This step runs One-Shot Analysis (which analyzes
143 // SSA use-def chains of tensor IR) and decides where buffer copies are
144 // needed and where buffers can be written to in-place. These decisions are
145 // materialized in the IR in the form of `bufferization.alloc_tensor` ops.
146 //
147 // Note: All following steps in this pass must be careful not to modify the
148 // structure of the IR (i.e., tensor use-def chains), as that could
149 // invalidate the results of the analysis. From now on, only small and
150 // localized rewrites are allowed, such as replacing a tensor op with its
151 // memref equivalent.
152 bufferization::BufferizationState bufferizationState;
153
155 getOperation(), bufferizationOptions, bufferizationState)))
156 return signalPassFailure();
157
158 // Option `testAnalysisOnly` is a debug/testing flag. If set, the results of
159 // OneShotAnalysis are added to the IR via attributes. In that case, do not
160 // continue with the remaining pipeline.
161 if (bufferizationOptions.testAnalysisOnly)
162 return;
163
164 // Bufferize all sparse ops. No further analysis is needed. All required
165 // buffer copies were already inserted by `insertTensorCopies` in the form
166 // of `bufferization.alloc_tensor` ops.
167 {
168 OpPassManager pm("builtin.module");
169 if (enableGPULibgen)
170 pm.addPass(createSparseGPUCodegenPass(0, enableRuntimeLibrary));
172 pm.addPass(createSparsificationPass(sparsificationOptions));
173 if (sparsificationOptions.sparseEmitStrategy ==
177 }
178
180 pm.addPass(createLowerSparseOpsToForeachPass(enableRuntimeLibrary,
181 /*enableConvert=*/true));
182 pm.addPass(
184 pm.addNestedPass<func::FuncOp>(createLowerForeachToSCFPass());
186 if (vectorLength > 0) {
189 }
190 if (enableRuntimeLibrary) {
192 } else {
193 pm.addPass(createSparseTensorCodegenPass(createSparseDeallocs,
194 enableBufferInitialization));
195 pm.addPass(createSparseBufferRewritePass(enableBufferInitialization));
196 }
197 if (failed(runPipeline(pm, getOperation())))
198 return signalPassFailure();
199 }
200
201 // Bufferize all dense ops.
202 if (failed(runDenseBufferization()))
204 }
205
206private:
208 SparsificationOptions sparsificationOptions;
209 bool createSparseDeallocs;
210 bool enableRuntimeLibrary;
211 bool enableBufferInitialization;
212};
213
214} // namespace sparse_tensor
215} // namespace mlir
216
219 using namespace mlir::bufferization;
221 options.bufferizeFunctionBoundaries = true;
222 options.setFunctionBoundaryTypeConversion(LayoutMapOption::IdentityLayoutMap);
223 options.unknownTypeConverterFn = [](TensorType tensorType,
224 Attribute memorySpace,
226 return getMemRefTypeWithStaticIdentityLayout(tensorType, memorySpace);
227 };
228 if (analysisOnly) {
229 options.testAnalysisOnly = true;
230 options.printConflicts = true;
231 }
232 // Since this mini-pipeline may be used in alternative pipelines (viz.
233 // different from the default "sparsifier" pipeline) where unknown ops
234 // are handled by alternative bufferization methods that are downstream
235 // of this mini-pipeline, we allow unknown ops by default (failure to
236 // bufferize is eventually apparent by failing to convert to LLVM IR).
237 options.allowUnknownOps = true;
238 return options;
239}
240
242 SparsificationOptions sparseOptions;
243 return std::make_unique<
245 getBufferizationOptionsForSparsification(/*analysisOnly=*/false),
246 sparseOptions,
247 /*createSparseDeallocs=*/false,
248 /*enableRuntimeLibrary=*/false,
249 /*enableBufferInitialization=*/false);
250}
251
253 const bufferization::OneShotBufferizationOptions &bufferizationOptions,
254 const SparsificationOptions &sparsificationOptions,
255 bool createSparseDeallocs, bool enableRuntimeLibrary,
256 bool enableBufferInitialization, unsigned vectorLength,
257 bool enableVLAVectorization, bool enableSIMDIndex32, bool enableGPULibgen,
258 SparseEmitStrategy emitStrategy,
259 SparseParallelizationStrategy parallelizationStrategy) {
260 return std::make_unique<
262 bufferizationOptions, sparsificationOptions, createSparseDeallocs,
263 enableRuntimeLibrary, enableBufferInitialization, vectorLength,
264 enableVLAVectorization, enableSIMDIndex32, enableGPULibgen, emitStrategy,
265 parallelizationStrategy);
266}
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:392
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:88
operand_range getOperands()
Returns an iterator on the underlying Value's.
Definition Operation.h:378
result_range getResults()
Definition Operation.h:415
LogicalResult runPipeline(OpPassManager &pipeline, Operation *op)
Schedule an arbitrary pass pipeline on the provided operation.
Definition Pass.h:200
friend class OpPassManager
Allow access to 'clone'.
Definition Pass.h:327
void signalPassFailure()
Signal that some invariant was broken when running.
Definition Pass.h:218
Tensor types represent multi-dimensional arrays, and have two variants: RankedTensorType and Unranked...
This class provides an abstraction over the various different ranges of value types.
Definition TypeRange.h:37
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()
std::unique_ptr< Pass > createLoopInvariantCodeMotionPass()
Creates a loop invariant code motion pass that hoists loop invariant instructions out of the loop.
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< Pass > createLowerSparseIterationToSCFPass()
std::unique_ptr< Pass > createStageSparseOperationsPass()
std::unique_ptr< Pass > createSparsificationPass()
Options for the Sparsification pass.
Definition Passes.h:109
Options for analysis-enabled bufferization.