CIRCT 22.0.0git
Loading...
Searching...
No Matches
FIRRTLInstanceInfo.cpp
Go to the documentation of this file.
1//===- FIRRTLInstanceInfo.cpp - Instance info analysis ----------*- 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// This file defines the InstanceInfo analysis. This is an analysis that
10// depends on the InstanceGraph analysis, but provides additional information
11// about FIRRTL operations. This is useful if you find yourself needing to
12// selectively iterate over parts of the design.
13//
14//===----------------------------------------------------------------------===//
15
20#include "circt/Support/Debug.h"
22#include "llvm/ADT/PostOrderIterator.h"
23#include "llvm/Support/Debug.h"
24
25#ifndef NDEBUG
26#include "llvm/ADT/DepthFirstIterator.h"
27#endif
28
29#define DEBUG_TYPE "firrtl-analysis-instanceinfo"
30
31using namespace circt;
32using namespace firrtl;
33
35
36bool InstanceInfo::LatticeValue::isConstant() const { return kind == Constant; }
37
38bool InstanceInfo::LatticeValue::isMixed() const { return kind == Mixed; }
39
42 return value;
43}
44
46 kind = Constant;
47 value = constant;
48}
49
51
53 if (kind > that.kind)
54 return;
55
56 if (kind < that.kind) {
57 kind = that.kind;
58 value = that.value;
59 return;
60 }
61
62 if (isConstant() && getConstant() != that.value)
63 kind = Mixed;
64}
65
67 LatticeValue latticeValue;
68 latticeValue.markConstant(value);
69 mergeIn(latticeValue);
70}
71
73 if (isUnknown() || isMixed())
74 return *this;
75
76 auto invert = LatticeValue();
77 invert.markConstant(!getConstant());
78 return invert;
79}
80
81InstanceInfo::InstanceInfo(Operation *op, mlir::AnalysisManager &am) {
82 auto &iGraph = am.getAnalysis<InstanceGraph>();
83
84 // Setup circuit attributes based on presence of annotations.
85 circuitAttributes.effectiveDut = iGraph.getTopLevelNode()->getModule();
86 for (auto *node : iGraph) {
87 auto moduleOp = node->getModule();
88 AnnotationSet annotations(moduleOp);
89 if (annotations.hasAnnotation(dutAnnoClass)) {
90 circuitAttributes.dut = moduleOp;
92 }
93 }
94
95 // Setup boundary conditions for any modules without users.
96 for (auto *node : iGraph) {
97 if (!node->noUses())
98 continue;
99
100 auto moduleOp = node->getModule();
101 ModuleAttributes &attributes = moduleAttributes[moduleOp];
102
103 attributes.underDut.mergeIn(isDut(moduleOp));
104 attributes.inDesign.mergeIn(isDut(moduleOp));
105 attributes.inEffectiveDesign.mergeIn(isEffectiveDut(moduleOp) || !hasDut());
106 attributes.underLayer.mergeIn(false);
107 }
108
109 // Visit modules in reverse post-order (visit parents before children) to
110 // merge parent attributes and per-instance attributes into children.
111 iGraph.walkInversePostOrder([&](auto &modIt) {
112 auto moduleOp = modIt.getModule();
113 ModuleAttributes &attributes = moduleAttributes[moduleOp];
114
115 AnnotationSet annotations(moduleOp);
116 auto isDut = annotations.hasAnnotation(dutAnnoClass);
117 auto isGCCompanion = annotations.hasAnnotation(companionAnnoClass);
118
119 if (isDut) {
120 attributes.underDut.markConstant(true);
121 attributes.inDesign.markConstant(true);
122 attributes.inEffectiveDesign.markConstant(true);
123 }
124
125 if (isGCCompanion) {
126 attributes.inDesign.mergeIn(false);
127 attributes.inEffectiveDesign.mergeIn(false);
128 attributes.underLayer.mergeIn(true);
129 }
130
131 // Merge in values based on the instantiations of this module.
132 for (auto *useIt : modIt.uses()) {
133 auto parentOp = useIt->getParent()->getModule();
134 auto parentAttrs = moduleAttributes.find(parentOp)->getSecond();
135
136 // Update underDut.
137 if (!isDut)
138 attributes.underDut.mergeIn(parentAttrs.underDut);
139
140 // Update underLayer.
141 bool underLayer = false;
142 if (auto instanceOp = useIt->template getInstance<InstanceOp>()) {
143 if (instanceOp.getLowerToBind() || instanceOp.getDoNotPrint() ||
144 instanceOp->template getParentOfType<LayerBlockOp>() ||
145 instanceOp->template getParentOfType<sv::IfDefOp>())
146 underLayer = true;
147 }
148
149 if (!isGCCompanion) {
150 if (underLayer)
151 attributes.underLayer.mergeIn(true);
152 else
153 attributes.underLayer.mergeIn(parentAttrs.underLayer);
154 }
155
156 // Update inDesign and inEffectiveDesign.
157 if (underLayer) {
158 attributes.inDesign.mergeIn(false);
159 attributes.inEffectiveDesign.mergeIn(false);
160 } else if (!isDut && !isGCCompanion) {
161 attributes.inDesign.mergeIn(parentAttrs.inDesign);
162 attributes.inEffectiveDesign.mergeIn(parentAttrs.inEffectiveDesign);
163 }
164 }
165 });
166
167 LLVM_DEBUG({
168 mlir::OpPrintingFlags flags;
169 flags.skipRegions();
170 debugHeader("FIRRTL InstanceInfo Analysis")
171 << "\n"
172 << llvm::indent(2) << "circuit attributes:\n"
173 << llvm::indent(4) << "hasDut: " << (hasDut() ? "true" : "false")
174 << "\n"
175 << llvm::indent(4) << "dut: ";
176 if (auto dut = circuitAttributes.dut)
177 dut->print(llvm::dbgs(), flags);
178 else
179 llvm::dbgs() << "null";
180 llvm::dbgs() << "\n" << llvm::indent(4) << "effectiveDut: ";
181 circuitAttributes.effectiveDut->print(llvm::dbgs(), flags);
182 llvm::dbgs() << "\n" << llvm::indent(2) << "module attributes:\n";
183 iGraph.walkInversePostOrder([&](auto &modIt) {
184 auto moduleOp = modIt.getModule();
185 auto attributes = moduleAttributes[moduleOp];
186 llvm::dbgs().indent(4)
187 << "- module: " << moduleOp.getModuleName() << "\n"
188 << llvm::indent(6)
189 << "isDut: " << (isDut(moduleOp) ? "true" : "false") << "\n"
190 << llvm::indent(6)
191 << "isEffectiveDue: " << (isEffectiveDut(moduleOp) ? "true" : "false")
192 << "\n"
193 << llvm::indent(6) << "underDut: " << attributes.underDut << "\n"
194 << llvm::indent(6) << "underLayer: " << attributes.underLayer << "\n"
195 << llvm::indent(6) << "inDesign: " << attributes.inDesign << "\n"
196 << llvm::indent(6)
197 << "inEffectiveDesign: " << attributes.inEffectiveDesign << "\n";
198 });
199 });
200}
201
203InstanceInfo::getModuleAttributes(igraph::ModuleOpInterface op) {
204 return moduleAttributes.find(op)->getSecond();
205}
206
208
209bool InstanceInfo::isDut(igraph::ModuleOpInterface op) {
210 if (hasDut())
211 return op == circuitAttributes.dut;
212 return false;
213}
214
215bool InstanceInfo::isEffectiveDut(igraph::ModuleOpInterface op) {
216 if (hasDut())
217 return isDut(op);
218 return op == circuitAttributes.effectiveDut;
219}
220
221igraph::ModuleOpInterface InstanceInfo::getDut() {
222 return circuitAttributes.dut;
223}
224
225igraph::ModuleOpInterface InstanceInfo::getEffectiveDut() {
227}
228
229bool InstanceInfo::anyInstanceUnderDut(igraph::ModuleOpInterface op) {
230 auto underDut = getModuleAttributes(op).underDut;
231 return underDut.isMixed() || allInstancesUnderDut(op);
232}
233
234bool InstanceInfo::allInstancesUnderDut(igraph::ModuleOpInterface op) {
235 auto underDut = getModuleAttributes(op).underDut;
236 return underDut.isConstant() && underDut.getConstant();
237}
238
239bool InstanceInfo::anyInstanceUnderEffectiveDut(igraph::ModuleOpInterface op) {
240 return !hasDut() || anyInstanceUnderDut(op);
241}
242
243bool InstanceInfo::allInstancesUnderEffectiveDut(igraph::ModuleOpInterface op) {
244 return !hasDut() || allInstancesUnderDut(op);
245}
246
247bool InstanceInfo::anyInstanceUnderLayer(igraph::ModuleOpInterface op) {
248 auto underLayer = getModuleAttributes(op).underLayer;
249 return underLayer.isMixed() || allInstancesUnderLayer(op);
250}
251
252bool InstanceInfo::allInstancesUnderLayer(igraph::ModuleOpInterface op) {
253 auto underLayer = getModuleAttributes(op).underLayer;
254 return underLayer.isConstant() && underLayer.getConstant();
255}
256
257bool InstanceInfo::anyInstanceInDesign(igraph::ModuleOpInterface op) {
258 auto inDesign = getModuleAttributes(op).inDesign;
259 return inDesign.isMixed() || allInstancesInDesign(op);
260}
261
262bool InstanceInfo::allInstancesInDesign(igraph::ModuleOpInterface op) {
263 auto inDesign = getModuleAttributes(op).inDesign;
264 return inDesign.isConstant() && inDesign.getConstant();
265}
266
267bool InstanceInfo::anyInstanceInEffectiveDesign(igraph::ModuleOpInterface op) {
268 auto inEffectiveDesign = getModuleAttributes(op).inEffectiveDesign;
269 return inEffectiveDesign.isMixed() || allInstancesInEffectiveDesign(op);
270}
271
272bool InstanceInfo::allInstancesInEffectiveDesign(igraph::ModuleOpInterface op) {
273 auto inEffectiveDesign = getModuleAttributes(op).inEffectiveDesign;
274 return inEffectiveDesign.isConstant() && inEffectiveDesign.getConstant();
275}
assert(baseType &&"element must be base type")
static std::optional< APSInt > getConstant(Attribute operand)
Determine the value of a constant operand for the sake of constant folding.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool hasAnnotation(StringRef className) const
Return true if we have an annotation with the specified class name.
This graph tracks modules and where they are instantiated.
A lattice value to record the value of a property.
LatticeValue operator!()
Invert the lattice value.
void mergeIn(LatticeValue that)
Merge attributes from another LatticeValue into this one.
bool value
The value of the property if kind is Constant.
Kind kind
Whether or not the property holds.
bool getConstant() const
Return the value. This should only be used if the kind is Constant.
void markMixed()
Set this LatticeValue to mixed.
bool isConstant() const
Return true if the kind is Constant.
bool isUnknown() const
Return true if the kind is Unknown.
void markConstant(bool constant)
Set this LatticeValue to a constant.
bool isMixed() const
Return true if the kind is Mixed.
bool allInstancesUnderLayer(igraph::ModuleOpInterface op)
Return true if all instances of this module are under (or transitively under) layer blocks.
igraph::ModuleOpInterface getDut()
Return the design-under-test if one is defined for the circuit, otherwise return null.
bool isEffectiveDut(igraph::ModuleOpInterface op)
Return true if this module is the design-under-test and the circuit has a design-under-test.
CircuitAttributes circuitAttributes
Stores circuit-level attributes.
bool hasDut()
Return true if this circuit has a design-under-test.
bool allInstancesInEffectiveDesign(igraph::ModuleOpInterface op)
Return true if all instances of this module are within (or transitively withiin) the effective design...
bool isDut(igraph::ModuleOpInterface op)
Return true if this module is the design-under-test.
bool anyInstanceUnderDut(igraph::ModuleOpInterface op)
Return true if at least one instance of this module is under (or transitively under) the design-under...
bool anyInstanceUnderEffectiveDut(igraph::ModuleOpInterface op)
Return true if at least one instance is under (or transitively under) the effective design-under-test...
bool allInstancesUnderEffectiveDut(igraph::ModuleOpInterface op)
Return true if all instances are under (or transitively under) the effective design-under-test.
DenseMap< Operation *, ModuleAttributes > moduleAttributes
Internal mapping of operations to module attributes.
igraph::ModuleOpInterface getEffectiveDut()
Return the "effective" design-under-test.
InstanceInfo(Operation *op, mlir::AnalysisManager &am)
bool allInstancesUnderDut(igraph::ModuleOpInterface op)
Return true if all instances of this module are under (or transitively under) the design-under-test.
const ModuleAttributes & getModuleAttributes(igraph::ModuleOpInterface op)
Return the module attributes associated with a module.
bool anyInstanceInEffectiveDesign(igraph::ModuleOpInterface op)
Return true if any instance of this module is within (or transitively within) the effective design.
bool allInstancesInDesign(igraph::ModuleOpInterface op)
Return true if all instances of this module are within (or transitively withiin) the design.
bool anyInstanceUnderLayer(igraph::ModuleOpInterface op)
Return true if at least one instance of this module is under (or transitively under) a layer.
bool anyInstanceInDesign(igraph::ModuleOpInterface op)
Return true if any instance of this module is within (or transitively within) the design.
bool isConstant(Operation *op)
Return true if the specified operation has a constant value.
constexpr const char * dutAnnoClass
constexpr const char * companionAnnoClass
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::raw_ostream & debugHeader(const llvm::Twine &str, unsigned width=80)
Write a "header"-like string to the debug stream with a certain width.
Definition Debug.cpp:17
igraph::ModuleOpInterface dut
The design-under-test if one is defined.
igraph::ModuleOpInterface effectiveDut
The design-under-test if one is defined or the top module.
InstanceInfo::LatticeValue inDesign
Indicates if this module is instantiated in the design.
InstanceInfo::LatticeValue underDut
Indicates if this module is instantiated under the design-under-test.
InstanceInfo::LatticeValue inEffectiveDesign
Indicates if this modules is instantiated in the effective design.
InstanceInfo::LatticeValue underLayer
Indicates if this module is instantiated under a layer.