.. _program_listing_file_lib_Conversion_ConvertToEmitC_ConvertToEmitC.cpp: Program Listing for File ConvertToEmitC.cpp =========================================== |exhale_lsh| :ref:`Return to documentation for file ` (``lib/Conversion/ConvertToEmitC/ConvertToEmitC.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: 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 using namespace mlir; namespace { struct ConvertToEmitCPipelineOptions : public PassPipelineOptions { Option 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( "convert-to-laksa-emitc", "Convert everything to the upstream emitc dialect", [](OpPassManager &pm, const ConvertToEmitCPipelineOptions &options) { addConvertToEmitCPasses(pm, options.maxAllocSizeInBytes); }); }