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.
59 : public impl::SparsificationAndBufferizationBase<
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;
88 enableVLAVectorization = vla;
89 enableSIMDIndex32 = index32;
90 enableGPULibgen = gpu;
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>(
137 bufferization::createEmptyTensorToAllocTensorPass());
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) {
188 vectorLength, enableVLAVectorization, enableSIMDIndex32));
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()))
203 signalPassFailure();
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
This class represents a pass manager that runs passes on either a specific operation type,...
Definition PassManager.h:46
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
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)
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.
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.