CIRCT  20.0.0git
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 
30 using namespace circt;
31 using namespace firrtl;
32 
34 
35 bool InstanceInfo::LatticeValue::isConstant() const { return kind == Constant; }
36 
37 bool InstanceInfo::LatticeValue::isMixed() const { return kind == Mixed; }
38 
40  assert(isConstant());
41  return value;
42 }
43 
45  kind = Constant;
46  value = constant;
47 }
48 
49 void InstanceInfo::LatticeValue::markMixed() { kind = Mixed; }
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 
80 InstanceInfo::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  auto instanceOp = useIt->getInstance();
144  bool underLayer = (isa<InstanceOp>(instanceOp) &&
145  cast<InstanceOp>(instanceOp).getLowerToBind()) ||
146  instanceOp->getParentOfType<LayerBlockOp>();
147  if (!isGCCompanion) {
148  if (underLayer)
149  attributes.underLayer.mergeIn(true);
150  else
151  attributes.underLayer.mergeIn(parentAttrs.underLayer);
152  }
153 
154  // Update inDesign and inEffectiveDesign.
155  if (underLayer) {
156  attributes.inDesign.mergeIn(false);
157  attributes.inEffectiveDesign.mergeIn(false);
158  } else if (!isDut && !isGCCompanion) {
159  attributes.inDesign.mergeIn(parentAttrs.inDesign);
160  attributes.inEffectiveDesign.mergeIn(parentAttrs.inEffectiveDesign);
161  }
162  }
163  }
164  }
165 
166  LLVM_DEBUG({
167  mlir::OpPrintingFlags flags;
168  flags.skipRegions();
169  debugHeader("FIRRTL InstanceInfo Analysis")
170  << "\n"
171  << llvm::indent(2) << "circuit attributes:\n"
172  << llvm::indent(4) << "hasDut: " << (hasDut() ? "true" : "false")
173  << "\n"
174  << llvm::indent(4) << "dut: ";
175  if (auto dut = circuitAttributes.dut)
176  dut->print(llvm::dbgs(), flags);
177  else
178  llvm::dbgs() << "null";
179  llvm::dbgs() << "\n" << llvm::indent(4) << "effectiveDut: ";
180  circuitAttributes.effectiveDut->print(llvm::dbgs(), flags);
181  llvm::dbgs() << "\n" << llvm::indent(2) << "module attributes:\n";
182  visited.clear();
183  for (auto *root : iGraph) {
184  for (auto *modIt : llvm::inverse_post_order_ext(root, visited)) {
185  visited.insert(modIt);
186  auto moduleOp = modIt->getModule();
187  auto attributes = moduleAttributes[moduleOp];
188  llvm::dbgs().indent(4)
189  << "- module: " << moduleOp.getModuleName() << "\n"
190  << llvm::indent(6)
191  << "isDut: " << (isDut(moduleOp) ? "true" : "false") << "\n"
192  << llvm::indent(6) << "isEffectiveDue: "
193  << (isEffectiveDut(moduleOp) ? "true" : "false") << "\n"
194  << llvm::indent(6) << "underDut: " << attributes.underDut << "\n"
195  << llvm::indent(6) << "underLayer: " << attributes.underLayer
196  << "\n"
197  << llvm::indent(6) << "inDesign: " << attributes.inDesign << "\n"
198  << llvm::indent(6)
199  << "inEffectiveDesign: " << attributes.inEffectiveDesign << "\n";
200  }
201  }
202  });
203 }
204 
206 InstanceInfo::getModuleAttributes(igraph::ModuleOpInterface op) {
207  return moduleAttributes.find(op)->getSecond();
208 }
209 
211 
212 bool InstanceInfo::isDut(igraph::ModuleOpInterface op) {
213  if (hasDut())
214  return op == circuitAttributes.dut;
215  return false;
216 }
217 
218 bool InstanceInfo::isEffectiveDut(igraph::ModuleOpInterface op) {
219  if (hasDut())
220  return isDut(op);
221  return op == circuitAttributes.effectiveDut;
222 }
223 
224 igraph::ModuleOpInterface InstanceInfo::getDut() {
225  return circuitAttributes.dut;
226 }
227 
228 igraph::ModuleOpInterface InstanceInfo::getEffectiveDut() {
230 }
231 
232 bool InstanceInfo::anyInstanceUnderDut(igraph::ModuleOpInterface op) {
233  auto underDut = getModuleAttributes(op).underDut;
234  return underDut.isMixed() || allInstancesUnderDut(op);
235 }
236 
237 bool InstanceInfo::allInstancesUnderDut(igraph::ModuleOpInterface op) {
238  auto underDut = getModuleAttributes(op).underDut;
239  return underDut.isConstant() && underDut.getConstant();
240 }
241 
242 bool InstanceInfo::anyInstanceUnderEffectiveDut(igraph::ModuleOpInterface op) {
243  return !hasDut() || anyInstanceUnderDut(op);
244 }
245 
246 bool InstanceInfo::allInstancesUnderEffectiveDut(igraph::ModuleOpInterface op) {
247  return !hasDut() || allInstancesUnderDut(op);
248 }
249 
250 bool InstanceInfo::anyInstanceUnderLayer(igraph::ModuleOpInterface op) {
251  auto underLayer = getModuleAttributes(op).underLayer;
252  return underLayer.isMixed() || allInstancesUnderLayer(op);
253 }
254 
255 bool InstanceInfo::allInstancesUnderLayer(igraph::ModuleOpInterface op) {
256  auto underLayer = getModuleAttributes(op).underLayer;
257  return underLayer.isConstant() && underLayer.getConstant();
258 }
259 
260 bool InstanceInfo::anyInstanceInDesign(igraph::ModuleOpInterface op) {
261  auto inDesign = getModuleAttributes(op).inDesign;
262  return inDesign.isMixed() || allInstancesInDesign(op);
263 }
264 
265 bool InstanceInfo::allInstancesInDesign(igraph::ModuleOpInterface op) {
266  auto inDesign = getModuleAttributes(op).inDesign;
267  return inDesign.isConstant() && inDesign.getConstant();
268 }
269 
270 bool InstanceInfo::anyInstanceInEffectiveDesign(igraph::ModuleOpInterface op) {
271  auto inEffectiveDesign = getModuleAttributes(op).inEffectiveDesign;
272  return inEffectiveDesign.isMixed() || allInstancesInEffectiveDesign(op);
273 }
274 
275 bool InstanceInfo::allInstancesInEffectiveDesign(igraph::ModuleOpInterface op) {
276  auto inEffectiveDesign = getModuleAttributes(op).inEffectiveDesign;
277  return inEffectiveDesign.isConstant() && inEffectiveDesign.getConstant();
278 }
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.
Definition: FIRRTLOps.cpp:4588
constexpr const char * dutAnnoClass
constexpr const char * companionAnnoClass
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
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.