CIRCT 23.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 return inst.getLowerToBind() || inst.getDoNotPrint() ||
36 inst->getParentOfType<LayerBlockOp>() ||
37 inst->getParentOfType<sv::IfDefOp>();
38}
39
41
42bool InstanceInfo::LatticeValue::isConstant() const { return kind == Constant; }
43
44bool InstanceInfo::LatticeValue::isMixed() const { return kind == Mixed; }
45
48 return value;
49}
50
52 kind = Constant;
53 value = constant;
54}
55
57
59 if (kind > that.kind)
60 return;
61
62 if (kind < that.kind) {
63 kind = that.kind;
64 value = that.value;
65 return;
66 }
67
68 if (isConstant() && getConstant() != that.value)
69 kind = Mixed;
70}
71
73 LatticeValue latticeValue;
74 latticeValue.markConstant(value);
75 mergeIn(latticeValue);
76}
77
79 if (isUnknown() || isMixed())
80 return *this;
81
82 auto invert = LatticeValue();
83 invert.markConstant(!getConstant());
84 return invert;
85}
86
87InstanceInfo::InstanceInfo(Operation *op, mlir::AnalysisManager &am) {
88 auto &iGraph = am.getAnalysis<InstanceGraph>();
89
90 // Setup circuit attributes based on presence of annotations.
91 circuitAttributes.effectiveDut = iGraph.getTopLevelNode()->getModule();
92 for (auto *node : iGraph) {
93 auto moduleOp = node->getModule();
94 AnnotationSet annotations(moduleOp);
95 if (annotations.hasAnnotation(markDUTAnnoClass)) {
96 circuitAttributes.dut = moduleOp;
98 }
99 }
100
101 // Setup boundary conditions for any modules without users.
102 for (auto *node : iGraph) {
103 if (!node->noUses())
104 continue;
105
106 auto moduleOp = node->getModule();
107 ModuleAttributes &attributes = moduleAttributes[moduleOp];
108
109 attributes.underDut.mergeIn(isDut(moduleOp));
110 attributes.inDesign.mergeIn(isDut(moduleOp));
111 attributes.inEffectiveDesign.mergeIn(isEffectiveDut(moduleOp) || !hasDut());
112 attributes.underLayer.mergeIn(false);
113 attributes.inInstanceChoice.mergeIn(false);
114 }
115
116 // Visit modules in reverse post-order (visit parents before children) to
117 // merge parent attributes and per-instance attributes into children.
118 iGraph.walkInversePostOrder([&](auto &modIt) {
119 auto moduleOp = modIt.getModule();
120 ModuleAttributes &attributes = moduleAttributes[moduleOp];
121
122 AnnotationSet annotations(moduleOp);
123 auto isDut = annotations.hasAnnotation(markDUTAnnoClass);
124 auto isGCCompanion = annotations.hasAnnotation(companionAnnoClass);
125
126 if (isDut) {
127 attributes.underDut.markConstant(true);
128 attributes.inDesign.markConstant(true);
129 attributes.inEffectiveDesign.markConstant(true);
130 }
131
132 if (isGCCompanion) {
133 attributes.inDesign.mergeIn(false);
134 attributes.inEffectiveDesign.mergeIn(false);
135 attributes.underLayer.mergeIn(true);
136 }
137
138 // Merge in values based on the instantiations of this module.
139 for (auto *useIt : modIt.uses()) {
140 auto parentOp = useIt->getParent()->getModule();
141 auto parentAttrs = moduleAttributes.find(parentOp)->getSecond();
142
143 // Update underDut.
144 if (!isDut)
145 attributes.underDut.mergeIn(parentAttrs.underDut);
146
147 // Update underLayer.
148 bool underLayer = false;
149 if (auto instanceOp = useIt->template getInstance<InstanceOp>())
150 underLayer = InstanceInfo::isInstanceUnderLayer(instanceOp);
151
152 // Update inInstanceChoice.
153 if (auto instanceChoiceOp =
154 useIt->template getInstance<InstanceChoiceOp>()) {
155 attributes.inInstanceChoice.mergeIn(true);
156 if (instanceChoiceOp->template getParentOfType<LayerBlockOp>() ||
157 instanceChoiceOp->template getParentOfType<sv::IfDefOp>())
158 underLayer = true;
159 } else
160 attributes.inInstanceChoice.mergeIn(parentAttrs.inInstanceChoice);
161
162 if (!isGCCompanion) {
163 if (underLayer)
164 attributes.underLayer.mergeIn(true);
165 else
166 attributes.underLayer.mergeIn(parentAttrs.underLayer);
167 }
168
169 // Update inDesign and inEffectiveDesign.
170 if (underLayer) {
171 attributes.inDesign.mergeIn(false);
172 attributes.inEffectiveDesign.mergeIn(false);
173 } else if (!isDut && !isGCCompanion) {
174 attributes.inDesign.mergeIn(parentAttrs.inDesign);
175 attributes.inEffectiveDesign.mergeIn(parentAttrs.inEffectiveDesign);
176 }
177 }
178 });
179
180 LLVM_DEBUG({
181 mlir::OpPrintingFlags flags;
182 flags.skipRegions();
183 debugHeader("FIRRTL InstanceInfo Analysis")
184 << "\n"
185 << llvm::indent(2) << "circuit attributes:\n"
186 << llvm::indent(4) << "hasDut: " << (hasDut() ? "true" : "false")
187 << "\n"
188 << llvm::indent(4) << "dut: ";
189 if (auto dut = circuitAttributes.dut)
190 dut->print(llvm::dbgs(), flags);
191 else
192 llvm::dbgs() << "null";
193 llvm::dbgs() << "\n" << llvm::indent(4) << "effectiveDut: ";
194 circuitAttributes.effectiveDut->print(llvm::dbgs(), flags);
195 llvm::dbgs() << "\n" << llvm::indent(2) << "module attributes:\n";
196 iGraph.walkInversePostOrder([&](auto &modIt) {
197 auto moduleOp = modIt.getModule();
198 auto attributes = moduleAttributes[moduleOp];
199 llvm::dbgs().indent(4)
200 << "- module: " << moduleOp.getModuleName() << "\n"
201 << llvm::indent(6)
202 << "isDut: " << (isDut(moduleOp) ? "true" : "false") << "\n"
203 << llvm::indent(6)
204 << "isEffectiveDue: " << (isEffectiveDut(moduleOp) ? "true" : "false")
205 << "\n"
206 << llvm::indent(6) << "underDut: " << attributes.underDut << "\n"
207 << llvm::indent(6) << "underLayer: " << attributes.underLayer << "\n"
208 << llvm::indent(6) << "inDesign: " << attributes.inDesign << "\n"
209 << llvm::indent(6)
210 << "inEffectiveDesign: " << attributes.inEffectiveDesign << "\n"
211 << llvm::indent(6)
212 << "inInstanceChoice: " << attributes.inInstanceChoice << "\n";
213 });
214 });
215}
216
218InstanceInfo::getModuleAttributes(igraph::ModuleOpInterface op) {
219 return moduleAttributes.find(op)->getSecond();
220}
221
223
224bool InstanceInfo::isDut(igraph::ModuleOpInterface op) {
225 if (hasDut())
226 return op == circuitAttributes.dut;
227 return false;
228}
229
230bool InstanceInfo::isEffectiveDut(igraph::ModuleOpInterface op) {
231 if (hasDut())
232 return isDut(op);
233 return op == circuitAttributes.effectiveDut;
234}
235
236igraph::ModuleOpInterface InstanceInfo::getDut() {
237 return circuitAttributes.dut;
238}
239
240igraph::ModuleOpInterface InstanceInfo::getEffectiveDut() {
242}
243
244bool InstanceInfo::anyInstanceUnderDut(igraph::ModuleOpInterface op) {
245 auto underDut = getModuleAttributes(op).underDut;
246 return underDut.isMixed() || allInstancesUnderDut(op);
247}
248
249bool InstanceInfo::allInstancesUnderDut(igraph::ModuleOpInterface op) {
250 auto underDut = getModuleAttributes(op).underDut;
251 return underDut.isConstant() && underDut.getConstant();
252}
253
254bool InstanceInfo::anyInstanceUnderEffectiveDut(igraph::ModuleOpInterface op) {
255 return !hasDut() || anyInstanceUnderDut(op);
256}
257
258bool InstanceInfo::allInstancesUnderEffectiveDut(igraph::ModuleOpInterface op) {
259 return !hasDut() || allInstancesUnderDut(op);
260}
261
262bool InstanceInfo::anyInstanceUnderLayer(igraph::ModuleOpInterface op) {
263 auto underLayer = getModuleAttributes(op).underLayer;
264 return underLayer.isMixed() || allInstancesUnderLayer(op);
265}
266
267bool InstanceInfo::allInstancesUnderLayer(igraph::ModuleOpInterface op) {
268 auto underLayer = getModuleAttributes(op).underLayer;
269 return underLayer.isConstant() && underLayer.getConstant();
270}
271
272bool InstanceInfo::anyInstanceInDesign(igraph::ModuleOpInterface op) {
273 auto inDesign = getModuleAttributes(op).inDesign;
274 return inDesign.isMixed() || allInstancesInDesign(op);
275}
276
277bool InstanceInfo::allInstancesInDesign(igraph::ModuleOpInterface op) {
278 auto inDesign = getModuleAttributes(op).inDesign;
279 return inDesign.isConstant() && inDesign.getConstant();
280}
281
282bool InstanceInfo::anyInstanceInEffectiveDesign(igraph::ModuleOpInterface op) {
283 auto inEffectiveDesign = getModuleAttributes(op).inEffectiveDesign;
284 return inEffectiveDesign.isMixed() || allInstancesInEffectiveDesign(op);
285}
286
287bool InstanceInfo::allInstancesInEffectiveDesign(igraph::ModuleOpInterface op) {
288 auto inEffectiveDesign = getModuleAttributes(op).inEffectiveDesign;
289 return inEffectiveDesign.isConstant() && inEffectiveDesign.getConstant();
290}
291
292bool InstanceInfo::anyInstanceInInstanceChoice(igraph::ModuleOpInterface op) {
293 auto inInstanceChoice = getModuleAttributes(op).inInstanceChoice;
294 return inInstanceChoice.isMixed() ||
295 (inInstanceChoice.isConstant() && inInstanceChoice.getConstant());
296}
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.
static bool isInstanceUnderLayer(InstanceOp inst)
Return true if an instance op should be considered "under a layer" for the purposes of metadata emiss...
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 anyInstanceInInstanceChoice(igraph::ModuleOpInterface op)
Return true if any instance of this module is within (or transitively within) an instance choice.
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.
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 inInstanceChoice
Indicates if this module is instantiated within (or transitively within) an instance choice operation...
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.