Loading [MathJax]/extensions/tex2jax.js
CIRCT 21.0.0git
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
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
19#include "circt/Support/Debug.h"
21#include "llvm/ADT/PostOrderIterator.h"
22#include "llvm/Support/Debug.h"
23
24#ifndef NDEBUG
25#include "llvm/ADT/DepthFirstIterator.h"
26#endif
27
28#define DEBUG_TYPE "firrtl-analysis-instanceinfo"
29
30using namespace circt;
31using namespace firrtl;
32
34
35bool InstanceInfo::LatticeValue::isConstant() const { return kind == Constant; }
36
37bool InstanceInfo::LatticeValue::isMixed() const { return kind == Mixed; }
38
41 return value;
42}
43
45 kind = Constant;
46 value = constant;
47}
48
50
52 if (kind > that.kind)
53 return;
54
55 if (kind < that.kind) {
56 kind = that.kind;
57 value = that.value;
58 return;
59 }
60
61 if (isConstant() && getConstant() != that.value)
62 kind = Mixed;
63}
64
66 LatticeValue latticeValue;
67 latticeValue.markConstant(value);
68 mergeIn(latticeValue);
69}
70
72 if (isUnknown() || isMixed())
73 return *this;
74
75 auto invert = LatticeValue();
76 invert.markConstant(!getConstant());
77 return invert;
78}
79
80InstanceInfo::InstanceInfo(Operation *op, mlir::AnalysisManager &am) {
81 auto &iGraph = am.getAnalysis<InstanceGraph>();
82
83 // Setup circuit attributes based on presence of annotations.
84 circuitAttributes.effectiveDut = iGraph.getTopLevelNode()->getModule();
85 for (auto *node : iGraph) {
86 auto moduleOp = node->getModule();
87 AnnotationSet annotations(moduleOp);
88 if (annotations.hasAnnotation(dutAnnoClass)) {
89 circuitAttributes.dut = moduleOp;
91 }
92 }
93
94 // Setup boundary conditions for any modules without users.
95 for (auto *node : iGraph) {
96 if (!node->noUses())
97 continue;
98
99 auto moduleOp = node->getModule();
100 ModuleAttributes &attributes = moduleAttributes[moduleOp];
101
102 attributes.underDut.mergeIn(isDut(moduleOp));
103 attributes.inDesign.mergeIn(isDut(moduleOp));
104 attributes.inEffectiveDesign.mergeIn(isEffectiveDut(moduleOp) || !hasDut());
105 attributes.underLayer.mergeIn(false);
106 }
107
108 // Visit modules in reverse post-order (visit parents before children) to
109 // merge parent attributes and per-instance attributes into children.
110 DenseSet<InstanceGraphNode *> visited;
111 for (auto *root : iGraph) {
112 for (auto *modIt : llvm::inverse_post_order_ext(root, visited)) {
113 visited.insert(modIt);
114 auto moduleOp = modIt->getModule();
115 ModuleAttributes &attributes = moduleAttributes[moduleOp];
116
117 AnnotationSet annotations(moduleOp);
118 auto isDut = annotations.hasAnnotation(dutAnnoClass);
119 auto isGCCompanion = annotations.hasAnnotation(companionAnnoClass);
120
121 if (isDut) {
122 attributes.underDut.markConstant(true);
123 attributes.inDesign.markConstant(true);
124 attributes.inEffectiveDesign.markConstant(true);
125 }
126
127 if (isGCCompanion) {
128 attributes.inDesign.mergeIn(false);
129 attributes.inEffectiveDesign.mergeIn(false);
130 attributes.underLayer.mergeIn(true);
131 }
132
133 // Merge in values based on the instantiations of this module.
134 for (auto *useIt : modIt->uses()) {
135 auto parentOp = useIt->getParent()->getModule();
136 auto parentAttrs = moduleAttributes.find(parentOp)->getSecond();
137
138 // Update underDut.
139 if (!isDut)
140 attributes.underDut.mergeIn(parentAttrs.underDut);
141
142 // Update underLayer.
143 bool underLayer = false;
144 if (auto instanceOp = useIt->getInstance<InstanceOp>()) {
145 if (instanceOp.getLowerToBind() || instanceOp.getDoNotPrint() ||
146 instanceOp->getParentOfType<LayerBlockOp>())
147 underLayer = true;
148 }
149
150 if (!isGCCompanion) {
151 if (underLayer)
152 attributes.underLayer.mergeIn(true);
153 else
154 attributes.underLayer.mergeIn(parentAttrs.underLayer);
155 }
156
157 // Update inDesign and inEffectiveDesign.
158 if (underLayer) {
159 attributes.inDesign.mergeIn(false);
160 attributes.inEffectiveDesign.mergeIn(false);
161 } else if (!isDut && !isGCCompanion) {
162 attributes.inDesign.mergeIn(parentAttrs.inDesign);
163 attributes.inEffectiveDesign.mergeIn(parentAttrs.inEffectiveDesign);
164 }
165 }
166 }
167 }
168
169 LLVM_DEBUG({
170 mlir::OpPrintingFlags flags;
171 flags.skipRegions();
172 debugHeader("FIRRTL InstanceInfo Analysis")
173 << "\n"
174 << llvm::indent(2) << "circuit attributes:\n"
175 << llvm::indent(4) << "hasDut: " << (hasDut() ? "true" : "false")
176 << "\n"
177 << llvm::indent(4) << "dut: ";
178 if (auto dut = circuitAttributes.dut)
179 dut->print(llvm::dbgs(), flags);
180 else
181 llvm::dbgs() << "null";
182 llvm::dbgs() << "\n" << llvm::indent(4) << "effectiveDut: ";
183 circuitAttributes.effectiveDut->print(llvm::dbgs(), flags);
184 llvm::dbgs() << "\n" << llvm::indent(2) << "module attributes:\n";
185 visited.clear();
186 for (auto *root : iGraph) {
187 for (auto *modIt : llvm::inverse_post_order_ext(root, visited)) {
188 visited.insert(modIt);
189 auto moduleOp = modIt->getModule();
190 auto attributes = moduleAttributes[moduleOp];
191 llvm::dbgs().indent(4)
192 << "- module: " << moduleOp.getModuleName() << "\n"
193 << llvm::indent(6)
194 << "isDut: " << (isDut(moduleOp) ? "true" : "false") << "\n"
195 << llvm::indent(6) << "isEffectiveDue: "
196 << (isEffectiveDut(moduleOp) ? "true" : "false") << "\n"
197 << llvm::indent(6) << "underDut: " << attributes.underDut << "\n"
198 << llvm::indent(6) << "underLayer: " << attributes.underLayer
199 << "\n"
200 << llvm::indent(6) << "inDesign: " << attributes.inDesign << "\n"
201 << llvm::indent(6)
202 << "inEffectiveDesign: " << attributes.inEffectiveDesign << "\n";
203 }
204 }
205 });
206}
207
209InstanceInfo::getModuleAttributes(igraph::ModuleOpInterface op) {
210 return moduleAttributes.find(op)->getSecond();
211}
212
214
215bool InstanceInfo::isDut(igraph::ModuleOpInterface op) {
216 if (hasDut())
217 return op == circuitAttributes.dut;
218 return false;
219}
220
221bool InstanceInfo::isEffectiveDut(igraph::ModuleOpInterface op) {
222 if (hasDut())
223 return isDut(op);
224 return op == circuitAttributes.effectiveDut;
225}
226
227igraph::ModuleOpInterface InstanceInfo::getDut() {
228 return circuitAttributes.dut;
229}
230
231igraph::ModuleOpInterface InstanceInfo::getEffectiveDut() {
233}
234
235bool InstanceInfo::anyInstanceUnderDut(igraph::ModuleOpInterface op) {
236 auto underDut = getModuleAttributes(op).underDut;
237 return underDut.isMixed() || allInstancesUnderDut(op);
238}
239
240bool InstanceInfo::allInstancesUnderDut(igraph::ModuleOpInterface op) {
241 auto underDut = getModuleAttributes(op).underDut;
242 return underDut.isConstant() && underDut.getConstant();
243}
244
245bool InstanceInfo::anyInstanceUnderEffectiveDut(igraph::ModuleOpInterface op) {
246 return !hasDut() || anyInstanceUnderDut(op);
247}
248
249bool InstanceInfo::allInstancesUnderEffectiveDut(igraph::ModuleOpInterface op) {
250 return !hasDut() || allInstancesUnderDut(op);
251}
252
253bool InstanceInfo::anyInstanceUnderLayer(igraph::ModuleOpInterface op) {
254 auto underLayer = getModuleAttributes(op).underLayer;
255 return underLayer.isMixed() || allInstancesUnderLayer(op);
256}
257
258bool InstanceInfo::allInstancesUnderLayer(igraph::ModuleOpInterface op) {
259 auto underLayer = getModuleAttributes(op).underLayer;
260 return underLayer.isConstant() && underLayer.getConstant();
261}
262
263bool InstanceInfo::anyInstanceInDesign(igraph::ModuleOpInterface op) {
264 auto inDesign = getModuleAttributes(op).inDesign;
265 return inDesign.isMixed() || allInstancesInDesign(op);
266}
267
268bool InstanceInfo::allInstancesInDesign(igraph::ModuleOpInterface op) {
269 auto inDesign = getModuleAttributes(op).inDesign;
270 return inDesign.isConstant() && inDesign.getConstant();
271}
272
273bool InstanceInfo::anyInstanceInEffectiveDesign(igraph::ModuleOpInterface op) {
274 auto inEffectiveDesign = getModuleAttributes(op).inEffectiveDesign;
275 return inEffectiveDesign.isMixed() || allInstancesInEffectiveDesign(op);
276}
277
278bool InstanceInfo::allInstancesInEffectiveDesign(igraph::ModuleOpInterface op) {
279 auto inEffectiveDesign = getModuleAttributes(op).inEffectiveDesign;
280 return inEffectiveDesign.isConstant() && inEffectiveDesign.getConstant();
281}
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(llvm::StringRef str, int width=80)
Write a "header"-like string to the debug stream with a certain width.
Definition Debug.cpp:18
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.