14 #include "mlir/IR/IRMapping.h"
15 #include "mlir/Pass/Pass.h"
16 #include "mlir/Transforms/InliningUtils.h"
17 #include "llvm/ADT/PostOrderIterator.h"
18 #include "llvm/Support/Debug.h"
20 #define DEBUG_TYPE "arc-inline-modules"
24 #define GEN_PASS_DEF_INLINEMODULES
25 #include "circt/Dialect/Arc/ArcPasses.h.inc"
29 using namespace circt;
32 using namespace igraph;
33 using mlir::InlinerInterface;
36 struct InlineModulesPass
37 :
public arc::impl::InlineModulesBase<InlineModulesPass> {
38 void runOnOperation()
override;
44 struct PrefixingInliner :
public InlinerInterface {
46 PrefixingInliner(MLIRContext *context, StringRef prefix)
47 : InlinerInterface(context), prefix(prefix) {}
49 bool isLegalToInline(Region *dest, Region *src,
bool wouldBeCloned,
50 IRMapping &valueMapping)
const override {
53 bool isLegalToInline(Operation *op, Region *dest,
bool wouldBeCloned,
54 IRMapping &valueMapping)
const override {
57 void handleTerminator(Operation *op,
58 ArrayRef<Value> valuesToRepl)
const override {
59 assert(isa<hw::OutputOp>(op));
60 for (
auto [from, to] : llvm::zip(valuesToRepl, op->getOperands()))
61 from.replaceAllUsesWith(to);
64 void processInlinedBlocks(
65 iterator_range<Region::iterator> inlinedBlocks)
override {
66 for (Block &block : inlinedBlocks)
67 block.walk([&](Operation *op) { updateNames(op); });
71 if (attr.getValue().empty())
73 return StringAttr::get(attr.getContext(), prefix +
"/" + attr.getValue());
76 void updateNames(Operation *op)
const {
77 if (
auto name = op->getAttrOfType<StringAttr>(
"name"))
79 if (
auto name = op->getAttrOfType<StringAttr>(
"instanceName"))
81 if (
auto namesAttr = op->getAttrOfType<ArrayAttr>(
"names")) {
82 SmallVector<Attribute> names(namesAttr.getValue().begin(),
83 namesAttr.getValue().end());
84 for (
auto &name : names)
85 if (
auto nameStr = name.dyn_cast<StringAttr>())
87 op->setAttr(
"names",
ArrayAttr::get(namesAttr.getContext(), names));
93 void InlineModulesPass::runOnOperation() {
94 auto &instanceGraph = getAnalysis<hw::InstanceGraph>();
95 DenseSet<Operation *> handled;
99 for (
auto *startNode : instanceGraph) {
100 if (handled.count(startNode->getModule().getOperation()))
107 if (!handled.insert(node->getModule().getOperation()).second)
110 unsigned numUsesLeft = node->getNumUses();
111 if (numUsesLeft == 0)
114 for (
auto *instRecord : node->uses()) {
117 dyn_cast_or_null<HWModuleOp>(node->getModule().getOperation());
118 if (!module || !module.isPrivate())
122 auto inst = dyn_cast_or_null<InstanceOp>(
123 instRecord->getInstance().getOperation());
127 bool isLastModuleUse = --numUsesLeft == 0;
129 PrefixingInliner inliner(&getContext(), inst.getInstanceName());
130 if (failed(mlir::inlineRegion(inliner, &module.getBody(), inst,
131 inst.getOperands(), inst.getResults(),
132 std::nullopt, !isLastModuleUse))) {
133 inst.emitError(
"failed to inline '")
134 << module.getModuleName() <<
"' into instance '"
135 << inst.getInstanceName() <<
"'";
136 return signalPassFailure();
148 return std::make_unique<InlineModulesPass>();
assert(baseType &&"element must be base type")
static void updateName(PatternRewriter &rewriter, Operation *op, StringAttr name)
Set the name of an op based on the best of two names: The current name, and the name passed in.
This is a Node in the InstanceGraph.
std::unique_ptr< mlir::Pass > createInlineModulesPass()
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...