//===- Inliner.h - Inliner pass utilities -----------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This header file declares utility structures for the inliner pass. // //===----------------------------------------------------------------------===// #ifndef MLIR_TRANSFORMS_INLINER_H #define MLIR_TRANSFORMS_INLINER_H #include "mlir/Analysis/CallGraph.h" #include "mlir/Interfaces/CallInterfaces.h" #include "mlir/Pass/AnalysisManager.h" #include "mlir/Pass/PassManager.h" #include "mlir/Transforms/InliningUtils.h" #include "llvm/ADT/StringMap.h" namespace mlir { class OpPassManager; class Operation; class InlinerConfig { public: using DefaultPipelineTy = std::function; using OpPipelinesTy = llvm::StringMap; InlinerConfig() = default; InlinerConfig(DefaultPipelineTy defaultPipeline, unsigned maxInliningIterations) : defaultPipeline(std::move(defaultPipeline)), maxInliningIterations(maxInliningIterations) {} const DefaultPipelineTy &getDefaultPipeline() const { return defaultPipeline; } const OpPipelinesTy &getOpPipelines() const { return opPipelines; } unsigned getMaxInliningIterations() const { return maxInliningIterations; } const InlinerInterface::CloneCallbackTy &getCloneCallback() const { return cloneCallback; } bool getCanHandleMultipleBlocks() const { return canHandleMultipleBlocks; } void setDefaultPipeline(DefaultPipelineTy pipeline) { defaultPipeline = std::move(pipeline); } void setOpPipelines(OpPipelinesTy pipelines) { opPipelines = std::move(pipelines); } void setMaxInliningIterations(unsigned max) { maxInliningIterations = max; } void setCloneCallback(InlinerInterface::CloneCallbackTy callback) { cloneCallback = std::move(callback); } void setCanHandleMultipleBlocks(bool value = true) { canHandleMultipleBlocks = value; } private: /// An optional function that constructs an optimization pipeline for /// a given operation. This optimization pipeline is applied /// only to those callable operations that do not have dedicated /// optimization pipeline in opPipelines (based on the operation name). DefaultPipelineTy defaultPipeline; /// A map of operation names to pass pipelines to use when optimizing /// callable operations of these types. This provides a specialized pipeline /// instead of the one produced by defaultPipeline. OpPipelinesTy opPipelines; /// For SCC-based inlining algorithms, specifies maximum number of iterations /// when inlining within an SCC. unsigned maxInliningIterations{0}; /// Callback for cloning operations during inlining InlinerInterface::CloneCallbackTy cloneCallback = [](OpBuilder &builder, Region *src, Block *inlineBlock, Block *postInsertBlock, IRMapping &mapper, bool shouldCloneInlinedRegion) { // Check to see if the region is being cloned, or moved inline. In // either case, move the new blocks after the 'insertBlock' to improve // IR readability. Region *insertRegion = inlineBlock->getParent(); if (shouldCloneInlinedRegion) src->cloneInto(insertRegion, postInsertBlock->getIterator(), mapper); else insertRegion->getBlocks().splice(postInsertBlock->getIterator(), src->getBlocks(), src->begin(), src->end()); }; /// Determine if the inliner can inline a function containing multiple /// blocks into a region that requires a single block. By default, it is /// not allowed. If it is true, cloneCallback should perform the extra /// transformation. see the example in /// mlir/test/lib/Transforms/TestInliningCallback.cpp bool canHandleMultipleBlocks{false}; }; /// This is an implementation of the inliner /// that operates bottom up over the Strongly Connected Components(SCCs) /// of the CallGraph. This enables a more incremental propagation /// of inlining decisions from the leafs to the roots of the callgraph. class Inliner { public: /// This struct represents a resolved call to a given callgraph node. Given /// that the call does not actually contain a direct reference to the /// Region(CallGraphNode) that it is dispatching to, we need to resolve them /// explicitly. struct ResolvedCall { ResolvedCall(CallOpInterface call, CallGraphNode *sourceNode, CallGraphNode *targetNode) : call(call), sourceNode(sourceNode), targetNode(targetNode) {} CallOpInterface call; CallGraphNode *sourceNode, *targetNode; }; using RunPipelineHelperTy = std::function; /// Type of the callback answering if it is profitable /// to inline a callable operation at a call site. /// It might be the case that the ResolvedCall does not provide /// enough context to make the profitability decision, so /// this hook's interface might need to be extended in future. using ProfitabilityCallbackTy = std::function; Inliner(Operation *op, CallGraph &cg, Pass &pass, AnalysisManager am, RunPipelineHelperTy runPipelineHelper, const InlinerConfig &config, ProfitabilityCallbackTy isProfitableToInline) : op(op), cg(cg), pass(pass), am(am), runPipelineHelper(std::move(runPipelineHelper)), config(config), isProfitableToInline(std::move(isProfitableToInline)) {} Inliner(Inliner &) = delete; void operator=(const Inliner &) = delete; /// Perform inlining on a OpTrait::SymbolTable operation. LogicalResult doInlining(); private: /// An OpTrait::SymbolTable operation to run the inlining on. Operation *op; /// A CallGraph analysis for the given operation. CallGraph &cg; /// A reference to the pass using this inliner. Pass &pass; /// Analysis manager for the given operation instance. AnalysisManager am; /// A callback for running a nested pass pipeline on the operation /// contained within the main operation. const RunPipelineHelperTy runPipelineHelper; /// The inliner configuration parameters. const InlinerConfig &config; /// Returns true, if it is profitable to inline the callable operation /// at the call site. ProfitabilityCallbackTy isProfitableToInline; /// Forward declaration of the class providing the actual implementation. class Impl; }; } // namespace mlir #endif // MLIR_TRANSFORMS_INLINER_H