CIRCT  18.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 
12 #include "PassDetails.h"
15 #include "mlir/IR/BuiltinOps.h"
16 #include "mlir/IR/Threading.h"
17 #include "llvm/Support/Debug.h"
18 
19 #define DEBUG_TYPE "firrtl-inner-symbol-dce"
20 
21 using namespace mlir;
22 using namespace circt;
23 using namespace firrtl;
24 using namespace hw;
25 
26 /// Drop the specified symbol.
27 /// Belongs in InnerSymbolTable, need to move port symbols accessors
28 /// into HW(ModuleLike) or perhaps a new inner-symbol interface that
29 /// dialects can optionally elect to use on their "ModuleLike"s.
30 /// For now, since InnerSymbolDCE is FIRRTL-only, define this here.
31 static void dropSymbol(const InnerSymTarget &target) {
32  assert(target);
33  assert(InnerSymbolTable::getInnerSymbol(target));
34 
35  if (target.isPort()) {
36  auto mod = cast<FModuleLike>(target.getOp());
37  assert(target.getPort() < mod.getNumPorts());
38  auto base = mod.getPortSymbolAttr(target.getPort());
39  cast<firrtl::FModuleLike>(*mod).setPortSymbolsAttr(
40  target.getPort(), base.erase(target.getField()));
41  return;
42  }
43 
44  auto symOp = cast<InnerSymbolOpInterface>(target.getOp());
45  auto base = symOp.getInnerSymAttr();
46  symOp.setInnerSymbolAttr(base.erase(target.getField()));
47 }
48 
49 struct InnerSymbolDCEPass : public InnerSymbolDCEBase<InnerSymbolDCEPass> {
50  void runOnOperation() override;
51 
52 private:
53  void findInnerRefs(Attribute attr);
54  void insertInnerRef(InnerRefAttr innerRef);
55  void removeInnerSyms(FModuleLike mod);
56 
57  DenseSet<std::pair<StringAttr, StringAttr>> innerRefs;
58 };
59 
60 /// Find all InnerRefAttrs inside a given Attribute.
61 void InnerSymbolDCEPass::findInnerRefs(Attribute attr) {
62  // Check if this Attribute or any sub-Attributes are InnerRefAttrs.
63  attr.walk([&](Attribute subAttr) {
64  if (auto innerRef = dyn_cast<InnerRefAttr>(subAttr))
65  insertInnerRef(innerRef);
66  });
67 }
68 
69 /// Add an InnerRefAttr to the set of all InnerRefAttrs.
70 void InnerSymbolDCEPass::insertInnerRef(InnerRefAttr innerRef) {
71  StringAttr moduleName = innerRef.getModule();
72  StringAttr symName = innerRef.getName();
73 
74  // Track total inner refs found.
75  ++numInnerRefsFound;
76 
77  auto [iter, inserted] = innerRefs.insert({moduleName, symName});
78  if (!inserted)
79  return;
80 
81  LLVM_DEBUG(llvm::dbgs() << DEBUG_TYPE << ": found reference to " << moduleName
82  << "::" << symName << '\n';);
83 }
84 
85 /// Remove all dead inner symbols from the specified module.
86 void InnerSymbolDCEPass::removeInnerSyms(FModuleLike mod) {
87  auto moduleName = mod.getModuleNameAttr();
88 
89  // Walk inner symbols, removing any not referenced.
90  InnerSymbolTable::walkSymbols(
91  mod, [&](StringAttr name, const InnerSymTarget &target) {
92  ++numInnerSymbolsFound;
93 
94  // Check if the name is referenced by any InnerRef.
95  if (innerRefs.contains({moduleName, name}))
96  return;
97 
98  dropSymbol(target);
99  ++numInnerSymbolsRemoved;
100 
101  LLVM_DEBUG(llvm::dbgs() << DEBUG_TYPE << ": removed " << moduleName
102  << "::" << name << '\n';);
103  });
104 }
105 
107  // Run on the top-level ModuleOp to include any VerbatimOps that aren't
108  // wrapped in a CircuitOp.
109  ModuleOp topModule = getOperation();
110 
111  // Traverse the entire IR once.
112  SmallVector<FModuleLike> modules;
113  topModule.walk([&](Operation *op) {
114  // Find all InnerRefAttrs.
115  for (NamedAttribute namedAttr : op->getAttrs())
116  findInnerRefs(namedAttr.getValue());
117 
118  // Collect all FModuleLike operations.
119  if (auto mod = dyn_cast<FModuleLike>(op))
120  modules.push_back(mod);
121  });
122 
123  // Traverse all FModuleOps in parallel, removing any InnerSymAttrs that are
124  // dead code.
125  parallelForEach(&getContext(), modules,
126  [&](FModuleLike mod) { removeInnerSyms(mod); });
127 }
128 
129 std::unique_ptr<mlir::Pass> circt::firrtl::createInnerSymbolDCEPass() {
130  return std::make_unique<InnerSymbolDCEPass>();
131 }
assert(baseType &&"element must be base type")
static void dropSymbol(const InnerSymTarget &target)
Drop the specified symbol.
#define DEBUG_TYPE
std::unique_ptr< mlir::Pass > createInnerSymbolDCEPass()
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
Definition: DebugAnalysis.h:21
Definition: hw.py:1
mlir::raw_indented_ostream & dbgs()
Definition: Utility.h:28
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