20#include <mlir/IR/BuiltinOps.h>
21#include <mlir/IR/SymbolTable.h>
22#include <mlir/Transforms/InliningUtils.h>
24#include <llvm/ADT/DenseSet.h>
25#include <llvm/ADT/SCCIterator.h>
26#include <llvm/ADT/SmallVector.h>
27#include <llvm/Support/Debug.h>
30#define GEN_PASS_DEF_INLINEFREEFUNCTIONSPASS
34#define DEBUG_TYPE "llzk-inline-free-functions"
45static bool isInlinableFreeFunction(
FuncDefOp func, ModuleOp root) {
46 return func->getParentOp() == root;
52static bool isInlinableCallSite(
CallOp call, ModuleOp root) {
53 return call->getParentOfType<
FuncDefOp>() && call->getParentOfType<ModuleOp>() == root;
60static llvm::DenseSet<Operation *> collectRecursiveFunctions(
const llzk::CallGraph &cg) {
61 llvm::DenseSet<Operation *> recursive;
62 for (
auto scc = llvm::scc_begin(&cg); !scc.isAtEnd(); ++scc) {
63 if (scc->size() == 1 && !scc.hasCycle()) {
67 if (!node->isExternal()) {
68 recursive.insert(node->getCalledFunction().getOperation());
78 CallOp call, ModuleOp root, SymbolTableCollection &tables,
79 const llvm::DenseSet<Operation *> &skippedCallees
86 if (!isInlinableFreeFunction(callee, root) || callee.isExternal() ||
87 skippedCallees.contains(callee)) {
94struct FreeFunctionCall {
101static SmallVector<FreeFunctionCall> collectFreeFunctionCalls(
102 ModuleOp
mod, SymbolTableCollection &tables,
const llvm::DenseSet<Operation *> &skippedCallees
104 SmallVector<FreeFunctionCall> calls;
106 if (!isInlinableCallSite(call,
mod)) {
109 if (
FuncDefOp callee = resolveFreeCallee(call,
mod, tables, skippedCallees)) {
110 calls.push_back({call, callee});
119static SmallVector<FuncDefOp> collectUnusedHelpers(ModuleOp
mod) {
121 SmallVector<FuncDefOp> unusedFunctions;
123 if (func.isExternal()) {
128 unusedFunctions.push_back(func);
131 return unusedFunctions;
135 using Base = InlineFreeFunctionsPassBase<PassImpl>;
138 void runOnOperation()
override {
139 ModuleOp
mod = getOperation();
140 SymbolTableCollection tables;
141 InlinerInterface inliner(&getContext());
144 llvm::DenseSet<Operation *> skippedCallees =
145 collectRecursiveFunctions(getAnalysis<CallGraphAnalysis>().getCallGraph());
147 inlineCalls(
mod, tables, inliner, skippedCallees);
148 removeUnusedFunctions(
mod);
158 ModuleOp
mod, SymbolTableCollection &tables, InlinerInterface &inliner,
159 llvm::DenseSet<Operation *> &skippedCallees
161 SmallVector<FreeFunctionCall> callsToInline =
162 collectFreeFunctionCalls(
mod, tables, skippedCallees);
163 while (!callsToInline.empty()) {
165 llvm::dbgs() <<
"[" DEBUG_TYPE "] round found " << callsToInline.size()
166 <<
" free-function call site(s) to inline\n";
169 for (
auto [call, callee] : callsToInline) {
170 if (skippedCallees.contains(callee)) {
173 if (failed(inlineCall(inliner, call, callee, callee.getCallableRegion(),
true))) {
174 call.emitWarning(
"failed to inline free function call; skipping this callee");
175 skippedCallees.insert(callee);
181 callsToInline = collectFreeFunctionCalls(
mod, tables, skippedCallees);
187 void removeUnusedFunctions(ModuleOp
mod) {
188 SmallVector<FuncDefOp> toErase = collectUnusedHelpers(
mod);
189 while (!toErase.empty()) {
193 toErase = collectUnusedHelpers(
mod);
This is a simple port of the mlir::CallGraphNode with llzk::CallGraph as a friend class,...
This is a port of mlir::CallGraph that has been adapted to use the custom symbol lookup helpers (see ...
bool hasPredecessor() const
Return true if this node has any predecessors.
Builds a graph structure representing the relationships between symbols and their uses.
const SymbolUseGraphNode * lookupNode(mlir::ModuleOp pathRoot, mlir::SymbolRefAttr path) const
Return the existing node for the symbol reference relative to the given module, else nullptr.
::mlir::FailureOr<::llzk::SymbolLookupResult<::llzk::function::FuncDefOp > > getCalleeTarget(::mlir::SymbolTableCollection &tables)
Resolve and return the target FuncDefOp for this CallOp.
ExpressionValue mod(const llvm::SMTSolverRef &solver, const ExpressionValue &lhs, const ExpressionValue &rhs)