CIRCT 24.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.
auto getModule()
Get the module that this node is tracking.
UseIterator usesBegin()
Iterate the instance records which instantiate this module.
igraph::InstanceGraphNode InstanceGraphNode
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
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.