.. _program_listing_file_lib_Conversion_FuncToDFG_FuncToDFG.cpp: Program Listing for File FuncToDFG.cpp ====================================== |exhale_lsh| :ref:`Return to documentation for file ` (``lib/Conversion/FuncToDFG/FuncToDFG.cpp``) .. |exhale_lsh| unicode:: U+021B0 .. UPWARDS ARROW WITH TIP LEFTWARDS .. code-block:: cpp #include "laksa-mlir/Conversion/FuncToDFG/FuncToDFG.h" #include "laksa-mlir/Dialect/DFG/IR/DFG.h" #include "laksa-mlir/Dialect/DFG/IR/DFGOps.h" #include "laksa-mlir/IR/LaksaAttributes.h" #include "mlir/Dialect/Func/IR/FuncOps.h" #include "mlir/IR/BuiltinDialect.h" #include "mlir/IR/IRMapping.h" #include "mlir/IR/PatternMatch.h" #include #include #include #include #define DEBUG_TYPE "func-to-dfg" #define LAKSA_DEBUG(X) \ LLVM_DEBUG(llvm::dbgs() << "[func-to-dfg] "; X; llvm::dbgs() << "\n") namespace mlir { #define GEN_PASS_DEF_CONVERTFUNCTODFG #include "laksa-mlir/Conversion/Passes.h.inc" } // namespace mlir using namespace mlir; using namespace mlir::dfg; namespace { struct NodeFuncToOperator : OpConversionPattern { NodeFuncToOperator(TypeConverter &typeConverter, MLIRContext* context) : OpConversionPattern( typeConverter, context, /*benefit=*/1) {}; LogicalResult matchAndRewrite( func::FuncOp op, func::FuncOpAdaptor, ConversionPatternRewriter &rewriter) const override { if (op->hasAttr(laksa::kRootAttrName)) return failure(); LAKSA_DEBUG( llvm::dbgs() << "Found node function @" << op.getSymName() << " at " << op.getLoc()); rewriter.replaceOpWithNewOp( op, op.getSymName(), op.getFunctionType(), [&](OpBuilder &operatorBuilder, Location operatorLoc, ValueRange operatorBlkArgs) { IRMapping mapper; for (auto [oldArg, newArg] : llvm::zip(op.getBody().getArguments(), operatorBlkArgs)) mapper.map(oldArg, newArg); for (auto &opFunc : op.getBody().getOps()) { if (auto retOp = dyn_cast(&opFunc)) { SmallVector outputs; for (auto operand : retOp.getOperands()) outputs.push_back(mapper.lookup(operand)); OutputOp::create(operatorBuilder, operatorLoc, outputs); LAKSA_DEBUG( llvm::dbgs() << "Replace return function to operator's output."); } else { operatorBuilder.clone(opFunc, mapper); } } }); LAKSA_DEBUG( llvm::dbgs() << "Replace the node function with operator operation."); return success(); } }; struct GraphFuncToRegion : OpConversionPattern { GraphFuncToRegion( TypeConverter &typeConverter, MLIRContext* context, DenseMap &returnValueToOutputPortMap) : OpConversionPattern( typeConverter, context, /*benefit=*/2), returnValueToOutputPortMap(returnValueToOutputPortMap) {}; LogicalResult matchAndRewrite( func::FuncOp op, func::FuncOpAdaptor, ConversionPatternRewriter &rewriter) const override { if (!op->hasAttr(laksa::kRootAttrName)) return failure(); LAKSA_DEBUG( llvm::dbgs() << "Found graph function @" << op.getSymName() << " at " << op.getLoc()); auto regionOp = rewriter.replaceOpWithNewOp( op, op.getSymName(), op.getFunctionType(), [&](OpBuilder &operatorBuilder, Location, ValueRange operatorBlkArgs) { IRMapping mapper; for (auto [oldArg, newArg] : llvm::zip(op.getBody().getArguments(), operatorBlkArgs)) mapper.map(oldArg, newArg); unsigned numInputs = op.getFunctionType().getNumInputs(); for (auto &opFunc : op.getBody().getOps()) { if (auto retOp = dyn_cast(&opFunc)) { for (auto [idx, operand] : llvm::enumerate(retOp.getOperands())) returnValueToOutputPortMap.insert( {mapper.lookup(operand), operatorBlkArgs[numInputs + idx]}); LAKSA_DEBUG( llvm::dbgs() << "Saved return values and erase " "return operation."); } else { operatorBuilder.clone(opFunc, mapper); } } }); regionOp->setAttr( laksa::kRootAttrName, UnitAttr::get(rewriter.getContext())); LAKSA_DEBUG( llvm::dbgs() << "Replace the graph function with region operation."); return success(); } private: DenseMap &returnValueToOutputPortMap; }; struct CallToInstantiate : OpConversionPattern { CallToInstantiate( TypeConverter &typeConverter, MLIRContext* context, DenseMap &returnValueToOutputPortMap, DenseMap &callResultChannelMap) : OpConversionPattern(typeConverter, context), returnValueToOutputPortMap(returnValueToOutputPortMap), callResultChannelMap(callResultChannelMap) {}; LogicalResult matchAndRewrite( func::CallOp op, func::CallOpAdaptor, ConversionPatternRewriter &rewriter) const override { auto loc = op.getLoc(); auto nodeName = op.getCallee(); SmallVector inputs, outputs; for (auto operand : op.getOperands()) { if (isa(operand)) { inputs.push_back(operand); LAKSA_DEBUG( llvm::dbgs() << "Found input value as block argument."); } else { auto it = callResultChannelMap.find(operand); if (it == callResultChannelMap.end()) return rewriter.notifyMatchFailure( loc, "Cannot find channel port map."); inputs.push_back(it->second); LAKSA_DEBUG( llvm::dbgs() << "Use channel's input port as input."); } } for (auto result : op.getResults()) { auto it = returnValueToOutputPortMap.find(result); if (it != returnValueToOutputPortMap.end()) { outputs.push_back(it->second); LAKSA_DEBUG(llvm::dbgs() << "Found return value to output."); } else { auto newChannel = ChannelOp::create(rewriter, loc, result.getType()); callResultChannelMap.insert( {result, newChannel.getOutputPort()}); outputs.push_back(newChannel.getInputPort()); LAKSA_DEBUG( llvm::dbgs() << "Created ChannelOp for call result."); } } InstantiateOp::create(rewriter, loc, nodeName, inputs, outputs); LAKSA_DEBUG(llvm::dbgs() << "Created InstantiateOp to replace CallOp."); rewriter.eraseOp(op); return success(); } private: DenseMap &returnValueToOutputPortMap; DenseMap &callResultChannelMap; }; } // namespace void mlir::populateFuncToDFGConversionPatterns( TypeConverter &typeConverter, RewritePatternSet &patterns, DenseMap &returnValueToOutputPortMap, DenseMap &callResultChannelMap) { patterns.add(typeConverter, patterns.getContext()); patterns.add( typeConverter, patterns.getContext(), returnValueToOutputPortMap); patterns.add( typeConverter, patterns.getContext(), returnValueToOutputPortMap, callResultChannelMap); } namespace { struct ConvertFuncToDFGPass : public impl::ConvertFuncToDFGBase { void runOnOperation() final; }; } // namespace void ConvertFuncToDFGPass::runOnOperation() { ConversionTarget target(getContext()); RewritePatternSet patterns(&getContext()); TypeConverter converter; converter.addConversion([&](Type type) { return type; }); DenseMap returnValueToOutputPortMap; DenseMap callResultChannelMap; populateFuncToDFGConversionPatterns( converter, patterns, returnValueToOutputPortMap, callResultChannelMap); target.addLegalDialect(); target.addIllegalDialect(); target.markUnknownOpDynamicallyLegal([](Operation*) { return true; }); if (failed(applyPartialConversion( getOperation(), target, std::move(patterns)))) { signalPassFailure(); } } std::unique_ptr mlir::createConvertFuncToDFGPass() { return std::make_unique(); }