CIRCT  20.0.0git
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 
23 namespace circt {
24 namespace firrtl {
25 #define GEN_PASS_DEF_INNERSYMBOLDCE
26 #include "circt/Dialect/FIRRTL/Passes.h.inc"
27 } // namespace firrtl
28 } // namespace circt
29 
30 using namespace mlir;
31 using namespace circt;
32 using namespace firrtl;
33 using 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.
40 static void dropSymbol(const InnerSymTarget &target) {
41  assert(target);
42  assert(InnerSymbolTable::getInnerSymbol(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 
62 private:
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.
71 void InnerSymbolDCEPass::findInnerRefs(Attribute attr) {
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.
80 void 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.
96 void InnerSymbolDCEPass::removeInnerSyms(FModuleLike mod) {
97  auto moduleName = mod.getModuleNameAttr();
98 
99  // Walk inner symbols, removing any not referenced.
100  InnerSymbolTable::walkSymbols(
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 
139 std::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.
Operation * getOp() const
Return the target's base operation. For ports, this is the module.
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.
std::unique_ptr< mlir::Pass > createInnerSymbolDCEPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
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