#include "mlir/Dialect/SparseTensor/Transforms/Passes.h"
#include "mlir/Dialect/Affine/IR/AffineOps.h"
#include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h"
#include "mlir/Dialect/Bufferization/IR/Bufferization.h"
#include "mlir/Dialect/Bufferization/Transforms/Bufferize.h"
#include "mlir/Dialect/Bufferization/Transforms/OneShotAnalysis.h"
#include "mlir/Dialect/Bufferization/Transforms/OneShotModuleBufferize.h"
#include "mlir/Dialect/Bufferization/Transforms/Passes.h"
#include "mlir/Dialect/Bufferization/Transforms/Transforms.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
#include "mlir/Dialect/GPU/IR/GPUDialect.h"
#include "mlir/Dialect/LLVMIR/LLVMDialect.h"
#include "mlir/Dialect/Linalg/IR/Linalg.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/Dialect/SCF/IR/SCF.h"
#include "mlir/Dialect/SparseTensor/IR/SparseTensor.h"
#include "mlir/Dialect/SparseTensor/Transforms/Passes.h"
#include "mlir/Dialect/Vector/IR/VectorOps.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Transforms/Passes.h"
using namespace mlir;
namespace mlir {
#define GEN_PASS_DEF_SPARSIFICATIONANDBUFFERIZATION
#include "mlir/Dialect/SparseTensor/Transforms/Passes.h.inc"
namespace sparse_tensor {
static bool containsSparseTensor(TypeRange types) {
for (Type t : types)
if (isa<TensorType>(t) && getSparseTensorEncoding(t))
return true;
return false;
}
class SparsificationAndBufferizationPass
: public impl::SparsificationAndBufferizationBase<
SparsificationAndBufferizationPass> {
public:
SparsificationAndBufferizationPass(
const bufferization::OneShotBufferizationOptions &bufferizationOptions,
const SparsificationOptions &sparsificationOptions,
bool createSparseDeallocs, bool enableRuntimeLibrary,
bool enableBufferInitialization)
: bufferizationOptions(bufferizationOptions),
sparsificationOptions(sparsificationOptions),
createSparseDeallocs(createSparseDeallocs),
enableRuntimeLibrary(enableRuntimeLibrary),
enableBufferInitialization(enableBufferInitialization) {}
SparsificationAndBufferizationPass(
const bufferization::OneShotBufferizationOptions &bufferizationOptions,
const SparsificationOptions &sparsificationOptions,
bool createSparseDeallocs, bool enableRuntimeLibrary,
bool enableBufferInitialization, unsigned vl, bool vla, bool index32,
bool gpu, SparseEmitStrategy emitStrategy)
: bufferizationOptions(bufferizationOptions),
sparsificationOptions(sparsificationOptions),
createSparseDeallocs(createSparseDeallocs),
enableRuntimeLibrary(enableRuntimeLibrary),
enableBufferInitialization(enableBufferInitialization) {
vectorLength = vl;
enableVLAVectorization = vla;
enableSIMDIndex32 = index32;
enableGPULibgen = gpu;
sparseEmitStrategy = emitStrategy;
}
LogicalResult runDenseBufferization() {
bufferization::OneShotBufferizationOptions updatedOptions =
bufferizationOptions;
updatedOptions.opFilter.denyOperation([&](Operation *op) {
if (containsSparseTensor(TypeRange(op->getResults())) ||
containsSparseTensor(TypeRange(op->getOperands())))
return true;
if (auto funcOp = dyn_cast<func::FuncOp>(op)) {
FunctionType funcType = funcOp.getFunctionType();
if (containsSparseTensor(funcType.getInputs()) ||
containsSparseTensor(funcType.getResults()))
return true;
}
return false;
});
if (failed(bufferization::bufferizeModuleOp(cast<ModuleOp>(getOperation()),
updatedOptions)))
return failure();
bufferization::removeBufferizationAttributesInModule(getOperation());
return success();
}
void runOnOperation() override {
this->sparsificationOptions.sparseEmitStrategy = sparseEmitStrategy;
{
OpPassManager pm("builtin.module");
pm.addPass(createPreSparsificationRewritePass());
pm.addNestedPass<func::FuncOp>(
bufferization::createEmptyTensorToAllocTensorPass());
if (failed(runPipeline(pm, getOperation())))
return signalPassFailure();
}
if (failed(bufferization::insertTensorCopies(getOperation(),
bufferizationOptions)))
return signalPassFailure();
if (bufferizationOptions.testAnalysisOnly)
return;
{
OpPassManager pm("builtin.module");
if (enableGPULibgen)
pm.addPass(createSparseGPUCodegenPass(0, enableRuntimeLibrary));
pm.addPass(createSparseReinterpretMapPass(ReinterpretMapScope::kAll));
pm.addPass(createSparsificationPass(sparsificationOptions));
if (sparsificationOptions.sparseEmitStrategy ==
SparseEmitStrategy::kSparseIterator) {
pm.addNestedPass<func::FuncOp>(createSparseSpaceCollapsePass());
pm.addNestedPass<func::FuncOp>(createLowerSparseIterationToSCFPass());
}
pm.addNestedPass<func::FuncOp>(createStageSparseOperationsPass());
pm.addPass(createLowerSparseOpsToForeachPass(enableRuntimeLibrary,
true));
pm.addPass(
createSparseReinterpretMapPass(ReinterpretMapScope::kExceptGeneric));
pm.addNestedPass<func::FuncOp>(createLowerForeachToSCFPass());
pm.addPass(mlir::createLoopInvariantCodeMotionPass());
if (vectorLength > 0) {
pm.addPass(createSparseVectorizationPass(
vectorLength, enableVLAVectorization, enableSIMDIndex32));
}
if (enableRuntimeLibrary) {
pm.addPass(createSparseTensorConversionPass());
} else {
pm.addPass(createSparseTensorCodegenPass(createSparseDeallocs,
enableBufferInitialization));
pm.addPass(createSparseBufferRewritePass(enableBufferInitialization));
}
if (failed(runPipeline(pm, getOperation())))
return signalPassFailure();
}
if (failed(runDenseBufferization()))
signalPassFailure();
}
private:
bufferization::OneShotBufferizationOptions bufferizationOptions;
SparsificationOptions sparsificationOptions;
bool createSparseDeallocs;
bool enableRuntimeLibrary;
bool enableBufferInitialization;
};
}
}
mlir::bufferization::OneShotBufferizationOptions
mlir::getBufferizationOptionsForSparsification(bool analysisOnly) {
using namespace mlir::bufferization;
OneShotBufferizationOptions options;
options.bufferizeFunctionBoundaries = true;
options.setFunctionBoundaryTypeConversion(LayoutMapOption::IdentityLayoutMap);
options.unknownTypeConverterFn = [](Value value, Attribute memorySpace,
const BufferizationOptions &options) {
return getMemRefTypeWithStaticIdentityLayout(
cast<TensorType>(value.getType()), memorySpace);
};
if (analysisOnly) {
options.testAnalysisOnly = true;
options.printConflicts = true;
}
options.allowUnknownOps = true;
return options;
}
std::unique_ptr<mlir::Pass> mlir::createSparsificationAndBufferizationPass() {
SparsificationOptions sparseOptions;
return std::make_unique<
mlir::sparse_tensor::SparsificationAndBufferizationPass>(
getBufferizationOptionsForSparsification(false),
sparseOptions,
false,
false,
false);
}
std::unique_ptr<mlir::Pass> mlir::createSparsificationAndBufferizationPass(
const bufferization::OneShotBufferizationOptions &bufferizationOptions,
const SparsificationOptions &sparsificationOptions,
bool createSparseDeallocs, bool enableRuntimeLibrary,
bool enableBufferInitialization, unsigned vectorLength,
bool enableVLAVectorization, bool enableSIMDIndex32, bool enableGPULibgen,
SparseEmitStrategy emitStrategy) {
return std::make_unique<
mlir::sparse_tensor::SparsificationAndBufferizationPass>(
bufferizationOptions, sparsificationOptions, createSparseDeallocs,
enableRuntimeLibrary, enableBufferInitialization, vectorLength,
enableVLAVectorization, enableSIMDIndex32, enableGPULibgen, emitStrategy);
}