Program Listing for File ConvertToEmitC.cpp
↰ Return to documentation for file (lib/Conversion/ConvertToEmitC/ConvertToEmitC.cpp)
#include "laksa-mlir/Conversion/ConvertToEmitC/ConvertToEmitC.h"
#include "laksa-mlir/Conversion/ReshapedCopyToLoops/ReshapedCopyToLoops.h"
#include "mlir/Conversion/AffineToStandard/AffineToStandard.h"
#include "mlir/Conversion/ConvertToEmitC/ConvertToEmitCPass.h"
#include "mlir/Conversion/ReconcileUnrealizedCasts/ReconcileUnrealizedCasts.h"
#include "mlir/Dialect/Arith/Transforms/Passes.h"
#include "mlir/Dialect/Bufferization/Transforms/Passes.h"
#include "mlir/Dialect/Linalg/Passes.h"
#include "mlir/Dialect/MemRef/Transforms/Passes.h"
#include "mlir/Pass/PassManager.h"
#include "mlir/Pass/PassRegistry.h"
#include <mlir/Transforms/Passes.h>
using namespace mlir;
namespace {
struct ConvertToEmitCPipelineOptions
: public PassPipelineOptions<ConvertToEmitCPipelineOptions> {
Option<uint32_t> maxAllocSizeInBytes{
*this,
"max-alloc-size-in-bytes",
llvm::cl::desc(
"Maximal size in bytes of a heap allocation that is "
"promoted to the stack. EmitC has no lowering for "
"memref.alloc, so anything above this limit makes the "
"conversion fail."),
llvm::cl::init(100000000)};
};
} // namespace
void mlir::laksa::addConvertToEmitCPasses(
OpPassManager &pm,
uint32_t maxAllocSizeInBytes)
{
// Bufferize with identity layout maps: EmitC has no notion of a strided
// memref, so the function boundaries must come out as plain arrays.
bufferization::OneShotBufferizePassOptions bufferizeOptions;
bufferizeOptions.bufferizeFunctionBoundaries = true;
bufferizeOptions.functionBoundaryTypeConversion =
bufferization::LayoutMapOption::IdentityLayoutMap;
// MemRefToEmitC rejects memref.global/memref.alloc carrying an alignment
// attribute, so do not let bufferization attach one.
bufferizeOptions.bufferAlignment = 0;
pm.addPass(bufferization::createOneShotBufferizePass(bufferizeOptions));
// A memref-returning function has no C equivalent; turn the result into an
// out-parameter instead. Public functions are opted in explicitly, as the
// entry point is the one that matters here.
bufferization::BufferResultsToOutParamsPassOptions outParamsOptions;
outParamsOptions.modifyPublicFunctions = true;
outParamsOptions.hoistStaticAllocs = true;
pm.addPass(
bufferization::createBufferResultsToOutParamsPass(outParamsOptions));
pm.addPass(createConvertLinalgToLoopsPass());
// Fold the reshapes bufferization left behind into the loads and stores
// that consume them.
pm.addPass(memref::createFoldMemRefAliasOpsPass());
pm.addPass(createConvertReshapedCopyToLoopsPass());
pm.addPass(memref::createExpandStridedMetadataPass());
pm.addPass(createLowerAffinePass());
pm.addPass(createCSEPass());
pm.addPass(createCanonicalizerPass());
// Whatever allocation survived out-param hoisting has to become a stack
// array, the only kind of buffer EmitC can express.
bufferization::PromoteBuffersToStackPassOptions promoteOptions;
promoteOptions.maxAllocSizeInBytes = maxAllocSizeInBytes;
pm.nest("func.func")
.addPass(
bufferization::createPromoteBuffersToStackPass(promoteOptions));
// ArithToEmitC has no pattern for the min/max ops; expand them into the
// cmpi/select pairs it does handle.
pm.addPass(arith::createArithExpandOpsPass());
pm.addPass(createConvertToEmitC());
pm.addPass(createReconcileUnrealizedCastsPass());
}
void mlir::laksa::registerConvertToEmitCPipelines()
{
PassPipelineRegistration<ConvertToEmitCPipelineOptions>(
"convert-to-laksa-emitc",
"Convert everything to the upstream emitc dialect",
[](OpPassManager &pm, const ConvertToEmitCPipelineOptions &options) {
addConvertToEmitCPasses(pm, options.maxAllocSizeInBytes);
});
}