CIRCT 20.0.0git
Loading...
Searching...
No Matches
InnerSymbolDCE.cpp
Go to the documentation of this file.
1//===- InnerSymbolDCE.cpp - Delete Unused Inner Symbols----------*- C++ -*-===//
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// This pass removes inner symbols which have no uses.
9//
10//===----------------------------------------------------------------------===//
11
16#include "mlir/IR/BuiltinOps.h"
17#include "mlir/IR/Threading.h"
18#include "mlir/Pass/Pass.h"
19#include "llvm/Support/Debug.h"
20
21#define DEBUG_TYPE "firrtl-inner-symbol-dce"
22
23namespace circt {
24namespace firrtl {
25#define GEN_PASS_DEF_INNERSYMBOLDCE
26#include "circt/Dialect/FIRRTL/Passes.h.inc"
27} // namespace firrtl
28} // namespace circt
29
30using namespace mlir;
31using namespace circt;
32using namespace firrtl;
33using namespace hw;
34
35/// Drop the specified symbol.
36/// Belongs in InnerSymbolTable, need to move port symbols accessors
37/// into HW(ModuleLike) or perhaps a new inner-symbol interface that
38/// dialects can optionally elect to use on their "ModuleLike"s.
39/// For now, since InnerSymbolDCE is FIRRTL-only, define this here.
40static void dropSymbol(const InnerSymTarget &target) {
41 assert(target);
43
44 if (target.isPort()) {
45 auto mod = cast<FModuleLike>(target.getOp());
46 assert(target.getPort() < mod.getNumPorts());
47 auto base = mod.getPortSymbolAttr(target.getPort());
48 cast<firrtl::FModuleLike>(*mod).setPortSymbolAttr(
49 target.getPort(), base.erase(target.getField()));
50 return;
51 }
52
53 auto symOp = cast<InnerSymbolOpInterface>(target.getOp());
54 auto base = symOp.getInnerSymAttr();
55 symOp.setInnerSymbolAttr(base.erase(target.getField()));
56}
57
59 : public circt::firrtl::impl::InnerSymbolDCEBase<InnerSymbolDCEPass> {
60 void runOnOperation() override;
61
62private:
63 void findInnerRefs(Attribute attr);
64 void insertInnerRef(InnerRefAttr innerRef);
65 void removeInnerSyms(FModuleLike mod);
66
67 DenseSet<std::pair<StringAttr, StringAttr>> innerRefs;
68};
69
70/// Find all InnerRefAttrs inside a given Attribute.
72 // Check if this Attribute or any sub-Attributes are InnerRefAttrs.
73 attr.walk([&](Attribute subAttr) {
74 if (auto innerRef = dyn_cast<InnerRefAttr>(subAttr))
75 insertInnerRef(innerRef);
76 });
77}
78
79/// Add an InnerRefAttr to the set of all InnerRefAttrs.
80void InnerSymbolDCEPass::insertInnerRef(InnerRefAttr innerRef) {
81 StringAttr moduleName = innerRef.getModule();
82 StringAttr symName = innerRef.getName();
83
84 // Track total inner refs found.
85 ++numInnerRefsFound;
86
87 auto [iter, inserted] = innerRefs.insert({moduleName, symName});
88 if (!inserted)
89 return;
90
91 LLVM_DEBUG(llvm::dbgs() << DEBUG_TYPE << ": found reference to " << moduleName
92 << "::" << symName << '\n';);
93}
94
95/// Remove all dead inner symbols from the specified module.
97 auto moduleName = mod.getModuleNameAttr();
98
99 // Walk inner symbols, removing any not referenced.
101 mod, [&](StringAttr name, const InnerSymTarget &target) {
102 ++numInnerSymbolsFound;
103
104 // Check if the name is referenced by any InnerRef.
105 if (innerRefs.contains({moduleName, name}))
106 return;
107
108 dropSymbol(target);
109 ++numInnerSymbolsRemoved;
110
111 LLVM_DEBUG(llvm::dbgs() << DEBUG_TYPE << ": removed " << moduleName
112 << "::" << name << '\n';);
113 });
114}
115
117 // Run on the top-level ModuleOp to include any VerbatimOps that aren't
118 // wrapped in a CircuitOp.
119 ModuleOp topModule = getOperation();
120
121 // Traverse the entire IR once.
122 SmallVector<FModuleLike> modules;
123 topModule.walk([&](Operation *op) {
124 // Find all InnerRefAttrs.
125 for (NamedAttribute namedAttr : op->getAttrs())
126 findInnerRefs(namedAttr.getValue());
127
128 // Collect all FModuleLike operations.
129 if (auto mod = dyn_cast<FModuleLike>(op))
130 modules.push_back(mod);
131 });
132
133 // Traverse all FModuleOps in parallel, removing any InnerSymAttrs that are
134 // dead code.
135 parallelForEach(&getContext(), modules,
136 [&](FModuleLike mod) { removeInnerSyms(mod); });
137}
138
139std::unique_ptr<mlir::Pass> circt::firrtl::createInnerSymbolDCEPass() {
140 return std::make_unique<InnerSymbolDCEPass>();
141}
assert(baseType &&"element must be base type")
static void dropSymbol(const InnerSymTarget &target)
Drop the specified symbol.
#define DEBUG_TYPE
The target of an inner symbol, the entity the symbol is a handle for.
auto getField() const
Return the target's fieldID.
auto getPort() const
Return the target's port, if valid. Check "isPort()".
bool isPort() const
Return if this targets a port.
Operation * getOp() const
Return the target's base operation. For ports, this is the module.
static StringAttr getInnerSymbol(Operation *op)
Get InnerSymbol for an operation.
static RetTy walkSymbols(Operation *op, FuncTy &&callback)
Walk the given IST operation and invoke the callback for all encountered inner symbols.
std::unique_ptr< mlir::Pass > createInnerSymbolDCEPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
void removeInnerSyms(FModuleLike mod)
Remove all dead inner symbols from the specified module.
void findInnerRefs(Attribute attr)
Find all InnerRefAttrs inside a given Attribute.
void runOnOperation() override
void insertInnerRef(InnerRefAttr innerRef)
Add an InnerRefAttr to the set of all InnerRefAttrs.
DenseSet< std::pair< StringAttr, StringAttr > > innerRefs