CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
15namespace circt {
16namespace 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
131private:
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.
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.