MLIR 23.0.0git
InlinerPass.cpp
Go to the documentation of this file.
1//===- InlinerPass.cpp - Pass to inline function calls --------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file implements a basic inlining algorithm that operates bottom up over
10// the Strongly Connect Components(SCCs) of the CallGraph. This enables a more
11// incremental propagation of inlining decisions from the leafs to the roots of
12// the callgraph.
13//
14//===----------------------------------------------------------------------===//
15
17
21#include "llvm/Support/DebugLog.h"
22
23namespace mlir {
24#define GEN_PASS_DEF_INLINERPASS
25#include "mlir/Transforms/Passes.h.inc"
26} // namespace mlir
27
28#define DEBUG_TYPE "inliner-pass"
29
30using namespace mlir;
31
32/// This function implements the inliner optimization pipeline.
36
37//===----------------------------------------------------------------------===//
38// InlinerPass
39//===----------------------------------------------------------------------===//
40
41namespace {
42class InlinerPass : public impl::InlinerPassBase<InlinerPass> {
43public:
44 using impl::InlinerPassBase<InlinerPass>::InlinerPassBase;
45 InlinerPass();
46 InlinerPass(const InlinerPass &) = default;
47 InlinerPass(std::function<void(OpPassManager &)> defaultPipeline);
48 InlinerPass(std::function<void(OpPassManager &)> defaultPipeline,
49 llvm::StringMap<OpPassManager> opPipelines);
50 void runOnOperation() override;
51
52 /// A callback provided to the inliner driver to execute
53 /// the specified pass pipeline on the given operation
54 /// within the context of the current inliner pass,
55 /// which is passed as the first argument.
56 /// runPipeline API is protected within the Pass class,
57 /// so this helper is required to call it from the foreign
58 /// inliner driver.
59 static LogicalResult runPipelineHelper(Pass &pass, OpPassManager &pipeline,
60 Operation *op) {
61 return mlir::cast<InlinerPass>(pass).runPipeline(pipeline, op);
62 }
63
64private:
65 /// Attempt to initialize the options of this pass from the given string.
66 /// Derived classes may override this method to hook into the point at which
67 /// options are initialized, but should generally always invoke this base
68 /// class variant.
69 LogicalResult initializeOptions(
70 StringRef options,
71 function_ref<LogicalResult(const Twine &)> errorHandler) override;
72
73 /// Inliner configuration parameters created from the pass options.
74 InlinerConfig config;
75};
76} // namespace
77
78InlinerPass::InlinerPass() : InlinerPass(defaultInlinerOptPipeline) {}
79
80InlinerPass::InlinerPass(
81 std::function<void(OpPassManager &)> defaultPipelineArg)
82 : InlinerPass(std::move(defaultPipelineArg),
83 llvm::StringMap<OpPassManager>{}) {}
84
85InlinerPass::InlinerPass(std::function<void(OpPassManager &)> defaultPipeline,
86 llvm::StringMap<OpPassManager> opPipelines)
87 : config(std::move(defaultPipeline), maxInliningIterations) {
88 if (opPipelines.empty())
89 return;
90
91 // Update the option for the op specific optimization pipelines.
92 for (auto &it : opPipelines)
93 opPipelineList.addValue(it.second);
94 config.setOpPipelines(std::move(opPipelines));
95}
96
97// Return true if the inlining ratio does not exceed the threshold.
98static bool isProfitableToInline(const Inliner::ResolvedCall &resolvedCall,
99 unsigned inliningThreshold) {
100 // Return early, ratio <= 0U will always be false.
101 if (inliningThreshold == 0U)
102 return false;
103 // Return early, ratio <= -1U will always be true.
104 if (inliningThreshold == -1U)
105 return true;
106
107 Region *callerRegion = resolvedCall.sourceNode->getCallableRegion();
108 Region *calleeRegion = resolvedCall.targetNode->getCallableRegion();
109
110 assert(calleeRegion && callerRegion && "unexpected external node");
111
112 auto countOps = [](Region *region) {
113 unsigned count = 0;
114 region->walk([&](Operation *) { ++count; });
115 return count;
116 };
117
118 unsigned callerOps = countOps(callerRegion);
119
120 // Always inline empty callees (if it is possible at all).
121 if (callerOps == 0)
122 return true;
123
124 unsigned ratio = countOps(calleeRegion) * 100 / callerOps;
125 LDBG() << "Callee / caller operation ratio (max: " << inliningThreshold
126 << "%): " << ratio << "%";
127 return ratio <= inliningThreshold;
128}
129
130void InlinerPass::runOnOperation() {
131 CallGraph &cg = getAnalysis<CallGraph>();
132
133 // The inliner should only be run on operations that define a symbol table,
134 // as the callgraph will need to resolve references.
135 Operation *op = getOperation();
136 if (!op->hasTrait<OpTrait::SymbolTable>()) {
137 op->emitOpError() << " was scheduled to run under the inliner, but does "
138 "not define a symbol table";
139 return signalPassFailure();
140 }
141
142 // By default, assume that any inlining is profitable.
143 auto profitabilityCb = [this](const Inliner::ResolvedCall &call) {
144 return isProfitableToInline(call, inliningThreshold);
145 };
146
147 // Get an instance of the inliner.
148 Inliner inliner(op, cg, *this, getAnalysisManager(), runPipelineHelper,
149 config, profitabilityCb);
150
151 // Run the inlining.
152 if (failed(inliner.doInlining()))
153 signalPassFailure();
154}
155
156LogicalResult InlinerPass::initializeOptions(
157 StringRef options,
158 function_ref<LogicalResult(const Twine &)> errorHandler) {
159 if (failed(Pass::initializeOptions(options, errorHandler)))
160 return failure();
161
162 // Initialize the pipeline builder for operations without the dedicated
163 // optimization pipeline in opPipelineList to use the option string.
164 // TODO: Use a generic pass manager for the pre-inline pipeline, and remove
165 // this.
166 if (!defaultPipelineStr.empty()) {
167 std::string defaultPipelineCopy = defaultPipelineStr;
168 config.setDefaultPipeline([=](OpPassManager &pm) {
169 (void)parsePassPipeline(defaultPipelineCopy, pm);
170 });
171 } else if (defaultPipelineStr.getNumOccurrences()) {
172 config.setDefaultPipeline(nullptr);
173 }
174
175 // Initialize the op specific pass pipelines.
176 llvm::StringMap<OpPassManager> pipelines;
177 for (OpPassManager pipeline : opPipelineList)
178 if (!pipeline.empty())
179 pipelines.try_emplace(pipeline.getOpAnchorName(), pipeline);
180 config.setOpPipelines(std::move(pipelines));
181
182 config.setMaxInliningIterations(maxInliningIterations);
183
184 return success();
185}
186
187std::unique_ptr<Pass>
188mlir::createInlinerPass(llvm::StringMap<OpPassManager> opPipelines) {
189 return std::make_unique<InlinerPass>(defaultInlinerOptPipeline,
190 std::move(opPipelines));
191}
192std::unique_ptr<Pass> mlir::createInlinerPass(
193 llvm::StringMap<OpPassManager> opPipelines,
194 std::function<void(OpPassManager &)> defaultPipelineBuilder) {
195 return std::make_unique<InlinerPass>(std::move(defaultPipelineBuilder),
196 std::move(opPipelines));
197}
for(Operation *op :ops)
return success()
static void defaultInlinerOptPipeline(OpPassManager &pm)
This function implements the inliner optimization pipeline.
static bool isProfitableToInline(const Inliner::ResolvedCall &resolvedCall, unsigned inliningThreshold)
static llvm::ManagedStatic< PassManagerOptions > options
Region * getCallableRegion() const
Returns the callable region this node represents.
Definition CallGraph.cpp:36
void setMaxInliningIterations(unsigned max)
Definition Inliner.h:54
void setOpPipelines(OpPipelinesTy pipelines)
Definition Inliner.h:51
void setDefaultPipeline(DefaultPipelineTy pipeline)
Definition Inliner.h:48
This class represents a pass manager that runs passes on either a specific operation type,...
Definition PassManager.h:46
void addPass(std::unique_ptr< Pass > pass)
Add the given pass to this pass manager.
Definition Pass.cpp:392
Operation is the basic unit of execution within MLIR.
Definition Operation.h:88
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition Operation.h:778
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
virtual LogicalResult initializeOptions(StringRef options, function_ref< LogicalResult(const Twine &)> errorHandler)
Attempt to initialize the options of this pass from the given string.
Definition Pass.cpp:65
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition Region.h:26
The OpAsmOpInterface, see OpAsmInterface.td for more details.
Definition CallGraph.h:229
detail::InFlightRemark failed(Location loc, RemarkOpts opts)
Report an optimization remark that failed.
Definition Remarks.h:717
Include the generated interface declarations.
std::unique_ptr< Pass > createInlinerPass(llvm::StringMap< OpPassManager > opPipelines)
Creates an instance of the inliner pass, and use the provided pass managers when optimizing callable ...
std::unique_ptr< Pass > createCanonicalizerPass(const GreedyRewriteConfig &config, ArrayRef< std::string > disabledPatterns={}, ArrayRef< std::string > enabledPatterns={})
Creates an instance of the Canonicalizer pass with the specified config.
LogicalResult parsePassPipeline(StringRef pipeline, OpPassManager &pm, raw_ostream &errorStream=llvm::errs())
Parse the textual representation of a pass pipeline, adding the result to 'pm' on success.
llvm::function_ref< Fn > function_ref
Definition LLVM.h:144
This struct represents a resolved call to a given callgraph node.
Definition Inliner.h:109
CallGraphNode * sourceNode
Definition Inliner.h:114
CallGraphNode * targetNode
Definition Inliner.h:114