12#include "mlir/Dialect/Func/IR/FuncOps.h"
13#include "mlir/IR/SymbolTable.h"
14#include "mlir/IR/Threading.h"
15#include "mlir/IR/Visitors.h"
16#include "mlir/Interfaces/CallInterfaces.h"
17#include "mlir/Pass/Pass.h"
18#include "mlir/Transforms/Inliner.h"
19#include "mlir/Transforms/InliningUtils.h"
20#include "llvm/Support/Debug.h"
22#define DEBUG_TYPE "llhd-inline-calls"
26#define GEN_PASS_DEF_INLINECALLSPASS
27#include "circt/Dialect/LLHD/Transforms/LLHDPasses.h.inc"
34using llvm::SmallSetVector;
40struct FunctionInliner :
public InlinerInterface {
41 using InlinerInterface::InlinerInterface;
43 bool isLegalToInline(Operation *call, Operation *callable,
44 bool wouldBeCloned)
const override {
46 if (!isa<func::FuncOp>(callable))
50 if (!mayHaveSSADominance(*call->getParentRegion()))
55 bool isLegalToInline(Region *dest, Region *src,
bool wouldBeCloned,
56 IRMapping &valueMapping)
const override {
60 bool isLegalToInline(Operation *op, Region *dest,
bool wouldBeCloned,
61 IRMapping &valueMapping)
const override {
65 bool shouldAnalyzeRecursively(Operation *op)
const override {
return false; }
70 :
public llhd::impl::InlineCallsPassBase<InlineCallsPass> {
71 using CallStack = SmallSetVector<func::FuncOp, 8>;
72 void runOnOperation()
override;
73 LogicalResult runOnRegion(Region ®ion,
const SymbolTable &symbolTable,
74 CallStack &callStack);
78void InlineCallsPass::runOnOperation() {
79 auto &symbolTable = getAnalysis<SymbolTable>();
80 if (failed(failableParallelForEach(
81 &getContext(), getOperation().getOps<hw::HWModuleOp>(),
84 return runOnRegion(module.getBody(), symbolTable, callStack);
89LogicalResult InlineCallsPass::runOnRegion(Region ®ion,
90 const SymbolTable &symbolTable,
91 CallStack &callStack) {
92 FunctionInliner inliner(&getContext());
94 SmallVector<Operation *> callsToErase;
95 SmallVector<std::pair<Operation *, func::FuncOp>> inlineEndMarkers;
101 for (
auto &block : region) {
102 for (
auto &op : block) {
104 if (!inlineEndMarkers.empty() && inlineEndMarkers.back().first == &op) {
105 assert(inlineEndMarkers.back().second == callStack.back());
106 LLVM_DEBUG(llvm::dbgs()
108 << inlineEndMarkers.back().second.getSymName() <<
"\n");
109 inlineEndMarkers.pop_back();
110 callStack.pop_back();
114 for (
auto &nestedRegion : op.getRegions())
115 if (failed(runOnRegion(nestedRegion, symbolTable, callStack)))
119 auto callOp = dyn_cast<func::CallOp>(op);
124 auto symbol = callOp.getCalleeAttr();
125 auto calledOp = symbolTable.lookup(symbol.getAttr());
126 auto funcOp = dyn_cast<func::FuncOp>(calledOp);
128 auto d = callOp.emitError(
"function call cannot be inlined: call "
129 "target is not a regular function");
130 d.attachNote(calledOp->getLoc()) <<
"call target defined here";
136 if (!callStack.insert(funcOp))
137 return callOp.emitError(
"recursive function call cannot be inlined");
138 inlineEndMarkers.push_back({op.getNextNode(), funcOp});
144 LLVM_DEBUG(llvm::dbgs() <<
"- Inlining " << callOp <<
"\n");
145 if (failed(inlineCall(inliner, config.getCloneCallback(), callOp, funcOp,
146 funcOp.getCallableRegion())))
147 return callOp.emitError(
"function call cannot be inlined");
148 callsToErase.push_back(callOp);
154 for (
auto *callOp : callsToErase)
assert(baseType &&"element must be base type")
Signals that an operations regions are procedural.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.