CIRCT  20.0.0git
OwningModuleCache.h
Go to the documentation of this file.
1 //===- OwningModuleCache.h - Memoized cache of owning modules ---*- 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 
9 #ifndef CIRCT_DIALECT_FIRRTL_OWNINGMODULECACHE_H
10 #define CIRCT_DIALECT_FIRRTL_OWNINGMODULECACHE_H
11 
14 
15 namespace circt {
16 namespace firrtl {
17 
18 /// This implements an analysis to determine which module owns a given path
19 /// operation. The owning module of a path is a module which contains the
20 /// path op, or instantiates it through children classes. A path operation
21 /// is generally only allowed to have a single owning module, and must target
22 /// an entity underneath that module's hierarchy.
24 
27 
28  /// Return this operation's owning module. If there is none or more than
29  /// one, this returns null.
30  FModuleOp lookup(ClassOp classOp) {
31  auto op = classOp;
32 
33  auto [it, inserted] = cache.try_emplace(op);
34  if (!inserted)
35  return it->second;
36 
37  // Slow path.
38  struct StackElement {
39  StackElement(InstanceGraphNode *node)
40  : current(node->getModule()), it(node->usesBegin()),
41  end(node->usesEnd()) {}
42  bool first = true;
43  FModuleOp owner = nullptr;
44  Operation *current;
47  };
48 
49  auto combine = [](FModuleOp current, FModuleOp parent, bool first) {
50  if (first)
51  current = parent;
52  else if (current != parent)
53  current = nullptr;
54  return current;
55  };
56 
57  auto *node = instanceGraph.lookup(op);
58  SmallVector<StackElement> stack;
59 
60  stack.emplace_back(node);
61 
62  auto returning = false;
63  FModuleOp result = nullptr;
64  while (!stack.empty()) {
65 
66  auto &elt = stack.back();
67  auto &it = elt.it;
68  auto &end = elt.end;
69 
70  if (returning) {
71  elt.owner = combine(elt.owner, result, elt.first);
72  elt.first = false;
73  returning = false;
74  }
75 
76  // Try to get each child.
77  while (true) {
78  if (it == end) {
79  // Set up to return the result.
80  returning = true;
81  result = elt.owner;
82  // Cache the result.
83  cache[elt.current] = elt.owner;
84  stack.pop_back();
85  break;
86  }
87 
88  auto *parentNode = (*it)->getParent();
89  auto parent = parentNode->getModule();
90 
91  // Advance past the current element.
92  ++it;
93 
94  if (auto parentModule = dyn_cast<FModuleOp>(parent.getOperation())) {
95  elt.owner = combine(elt.owner, parentModule, elt.first);
96  elt.first = false;
97  continue;
98  }
99  auto [pIt, pInserted] = cache.try_emplace(parent);
100  if (!pInserted) {
101  elt.owner = combine(elt.owner, pIt->second, elt.first);
102  elt.first = false;
103  continue;
104  }
105 
106  // Set it up to iterate the child.
107  stack.emplace_back(parentNode);
108  returning = false;
109  result = nullptr;
110  break;
111  }
112  }
113 
114  assert(returning && "must be returning a result");
115  return result;
116  }
117 
118  /// Return this operation's owning module. If there is none or more than
119  /// one, this returns null.
120  FModuleOp lookup(Operation *op) {
121  while (op) {
122  if (auto module = dyn_cast<FModuleOp>(op))
123  return module;
124  if (auto classOp = dyn_cast<ClassOp>(op))
125  return lookup(classOp);
126  op = op->getParentOp();
127  }
128  return nullptr;
129  }
130 
131 private:
132  DenseMap<Operation *, FModuleOp> cache;
134 };
135 
136 } // namespace firrtl
137 } // namespace circt
138 
139 #endif // CIRCT_DIALECT_FIRRTL_OWNINGMODULECACHE_H
assert(baseType &&"element must be base type")
This graph tracks modules and where they are instantiated.
This is a Node in the InstanceGraph.
auto getModule()
Get the module that this node is tracking.
UseIterator usesBegin()
Iterate the instance records which instantiate this module.
InstanceGraphNode * lookup(ModuleOpInterface op)
Look up an InstanceGraphNode for a module.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
This implements an analysis to determine which module owns a given path operation.
DenseMap< Operation *, FModuleOp > cache
FModuleOp lookup(ClassOp classOp)
Return this operation's owning module.
OwningModuleCache(InstanceGraph &instanceGraph)
FModuleOp lookup(Operation *op)
Return this operation's owning module.