This is just code refactoring done as a preparation for adding MLIR inliner cost model hook(s). Related discussion: https://discourse.llvm.org/t/inliner-cost-model/2992 The logic of SCC-based MLIR inliner is separated into the Inliner implementation. The MLIR inliner pass becomes, well, just a pass that invokes the SCC-based MLIR inliner.
156 lines
5.7 KiB
C++
156 lines
5.7 KiB
C++
//===- InlinerPass.cpp - Pass to inline function calls --------------------===//
|
|
//
|
|
// 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 file implements a basic inlining algorithm that operates bottom up over
|
|
// the Strongly Connect Components(SCCs) of the CallGraph. This enables a more
|
|
// incremental propagation of inlining decisions from the leafs to the roots of
|
|
// the callgraph.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "mlir/Transforms/Passes.h"
|
|
|
|
#include "mlir/Analysis/CallGraph.h"
|
|
#include "mlir/Pass/PassManager.h"
|
|
#include "mlir/Transforms/Inliner.h"
|
|
|
|
namespace mlir {
|
|
#define GEN_PASS_DEF_INLINER
|
|
#include "mlir/Transforms/Passes.h.inc"
|
|
} // namespace mlir
|
|
|
|
using namespace mlir;
|
|
|
|
/// This function implements the inliner optimization pipeline.
|
|
static void defaultInlinerOptPipeline(OpPassManager &pm) {
|
|
pm.addPass(createCanonicalizerPass());
|
|
}
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
// InlinerPass
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
namespace {
|
|
class InlinerPass : public impl::InlinerBase<InlinerPass> {
|
|
public:
|
|
InlinerPass();
|
|
InlinerPass(const InlinerPass &) = default;
|
|
InlinerPass(std::function<void(OpPassManager &)> defaultPipeline);
|
|
InlinerPass(std::function<void(OpPassManager &)> defaultPipeline,
|
|
llvm::StringMap<OpPassManager> opPipelines);
|
|
void runOnOperation() override;
|
|
|
|
/// A callback provided to the inliner driver to execute
|
|
/// the specified pass pipeline on the given operation
|
|
/// within the context of the current inliner pass,
|
|
/// which is passed as the first argument.
|
|
/// runPipeline API is protected within the Pass class,
|
|
/// so this helper is required to call it from the foreign
|
|
/// inliner driver.
|
|
static LogicalResult runPipelineHelper(Pass &pass, OpPassManager &pipeline,
|
|
Operation *op) {
|
|
return mlir::cast<InlinerPass>(pass).runPipeline(pipeline, op);
|
|
}
|
|
|
|
private:
|
|
/// Attempt to initialize the options of this pass from the given string.
|
|
/// Derived classes may override this method to hook into the point at which
|
|
/// options are initialized, but should generally always invoke this base
|
|
/// class variant.
|
|
LogicalResult initializeOptions(StringRef options) override;
|
|
|
|
/// Inliner configuration parameters created from the pass options.
|
|
InlinerConfig config;
|
|
};
|
|
} // namespace
|
|
|
|
InlinerPass::InlinerPass() : InlinerPass(defaultInlinerOptPipeline) {}
|
|
|
|
InlinerPass::InlinerPass(
|
|
std::function<void(OpPassManager &)> defaultPipelineArg)
|
|
: InlinerPass(std::move(defaultPipelineArg),
|
|
llvm::StringMap<OpPassManager>{}) {}
|
|
|
|
InlinerPass::InlinerPass(std::function<void(OpPassManager &)> defaultPipeline,
|
|
llvm::StringMap<OpPassManager> opPipelines)
|
|
: config(std::move(defaultPipeline), maxInliningIterations) {
|
|
if (opPipelines.empty())
|
|
return;
|
|
|
|
// Update the option for the op specific optimization pipelines.
|
|
for (auto &it : opPipelines)
|
|
opPipelineList.addValue(it.second);
|
|
config.setOpPipelines(std::move(opPipelines));
|
|
}
|
|
|
|
void InlinerPass::runOnOperation() {
|
|
CallGraph &cg = getAnalysis<CallGraph>();
|
|
|
|
// The inliner should only be run on operations that define a symbol table,
|
|
// as the callgraph will need to resolve references.
|
|
Operation *op = getOperation();
|
|
if (!op->hasTrait<OpTrait::SymbolTable>()) {
|
|
op->emitOpError() << " was scheduled to run under the inliner, but does "
|
|
"not define a symbol table";
|
|
return signalPassFailure();
|
|
}
|
|
|
|
// Get an instance of the inliner.
|
|
Inliner inliner(op, cg, *this, getAnalysisManager(), runPipelineHelper,
|
|
config);
|
|
|
|
// Run the inlining.
|
|
if (failed(inliner.doInlining()))
|
|
signalPassFailure();
|
|
return;
|
|
}
|
|
|
|
LogicalResult InlinerPass::initializeOptions(StringRef options) {
|
|
if (failed(Pass::initializeOptions(options)))
|
|
return failure();
|
|
|
|
// Initialize the pipeline builder for operations without the dedicated
|
|
// optimization pipeline in opPipelineList to use the option string.
|
|
// TODO: Use a generic pass manager for the pre-inline pipeline, and remove
|
|
// this.
|
|
if (!defaultPipelineStr.empty()) {
|
|
std::string defaultPipelineCopy = defaultPipelineStr;
|
|
config.setDefaultPipeline([=](OpPassManager &pm) {
|
|
(void)parsePassPipeline(defaultPipelineCopy, pm);
|
|
});
|
|
} else if (defaultPipelineStr.getNumOccurrences()) {
|
|
config.setDefaultPipeline(nullptr);
|
|
}
|
|
|
|
// Initialize the op specific pass pipelines.
|
|
llvm::StringMap<OpPassManager> pipelines;
|
|
for (OpPassManager pipeline : opPipelineList)
|
|
if (!pipeline.empty())
|
|
pipelines.try_emplace(pipeline.getOpAnchorName(), pipeline);
|
|
config.setOpPipelines(std::move(pipelines));
|
|
|
|
config.setMaxInliningIterations(maxInliningIterations);
|
|
|
|
return success();
|
|
}
|
|
|
|
std::unique_ptr<Pass> mlir::createInlinerPass() {
|
|
return std::make_unique<InlinerPass>();
|
|
}
|
|
std::unique_ptr<Pass>
|
|
mlir::createInlinerPass(llvm::StringMap<OpPassManager> opPipelines) {
|
|
return std::make_unique<InlinerPass>(defaultInlinerOptPipeline,
|
|
std::move(opPipelines));
|
|
}
|
|
std::unique_ptr<Pass> mlir::createInlinerPass(
|
|
llvm::StringMap<OpPassManager> opPipelines,
|
|
std::function<void(OpPassManager &)> defaultPipelineBuilder) {
|
|
return std::make_unique<InlinerPass>(std::move(defaultPipelineBuilder),
|
|
std::move(opPipelines));
|
|
}
|