CIRCT  20.0.0git
CheckLayers.cpp
Go to the documentation of this file.
1 //===- CheckLayers.cpp - check layer legality -----------------------------===//
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 
15 #include "llvm/ADT/PostOrderIterator.h"
16 
17 namespace circt {
18 namespace firrtl {
19 #define GEN_PASS_DEF_CHECKLAYERS
20 #include "circt/Dialect/FIRRTL/Passes.h.inc"
21 } // namespace firrtl
22 } // namespace circt
23 
24 using namespace circt;
25 using namespace firrtl;
26 using namespace mlir;
27 
28 namespace {
29 class CheckLayers {
30  CheckLayers(InstanceGraph &instanceGraph, InstanceInfo &instanceInfo)
31  : iGraph(instanceGraph), iInfo(instanceInfo) {}
32 
33  /// Walk a module and record any illegal layerblocks/Grand Central companions
34  /// under layerblocks/Grand Central companions. This function should be run
35  /// on children before parents for accurate reporting.
36  void run(FModuleOp moduleOp) {
37 
38  // The module is _never_ instantiated under a layer. There is nothing to do
39  // because erroneous instantiations are reported when examining the module.
40  // Note: Grand Central companions are under a layer (because InstanceInfo
41  // uses the inclusive definition of "under" to be consistent with how the
42  // design-under-test module is "under" the design).
43  if (!iInfo.anyInstanceUnderLayer(moduleOp))
44  return;
45 
46  // Check if this module has any layerblock ops. If these exist, then these
47  // may be errors.
48  SmallVector<Operation *> layerBlockOps;
49  moduleOp->walk([&](LayerBlockOp layerBlockOp) {
50  layerBlockOps.push_back(layerBlockOp);
51  });
52 
53  bool isGCCompanion =
55 
56  // Both Grand Central copmanions and modules that transitively instantiate
57  // layerblocks/Grand Central companions require analysis of their
58  // instantiation sites. However, if this is a normal module instantiated
59  // under a layer and it contains no layerblocks, then early exit to avoid
60  // unnecessarily examining instantiation sites.
61  if (!isGCCompanion && !transitiveModules.contains(moduleOp) &&
62  layerBlockOps.empty())
63  return;
64 
65  // Record instantiations of this module under layerblocks or modules that
66  // are under layer blocks. Update transitive modules.
67  SmallVector<Operation *> instUnderLayerBlock, instUnderLayerModule;
68  for (auto *instNode : iGraph.lookup(moduleOp)->uses()) {
69  auto *instOp = instNode->getInstance().getOperation();
70  if (instOp->getParentOfType<LayerBlockOp>())
71  instUnderLayerBlock.push_back(instOp);
72  else if (auto parent = instOp->getParentOfType<FModuleOp>();
73  iInfo.anyInstanceUnderLayer(parent)) {
74  transitiveModules.insert(parent);
75  instUnderLayerModule.push_back(instOp);
76  }
77  }
78 
79  // The module _may_ contain no errors if it is a Grand Central companion or
80  // a transitive module. Do a final check to ensure that an error exists.
81  if (layerBlockOps.empty() && instUnderLayerBlock.empty() &&
82  instUnderLayerModule.empty())
83  return;
84 
85  // Record that an error occurred and print out an error message on the
86  // module with notes for more information.
87  error = true;
88  auto diag = moduleOp->emitOpError();
89  if (isGCCompanion)
90  diag
91  << "is a Grand Central companion that either contains layerblocks or";
92 
93  else
94  diag << "either contains layerblocks or";
95  diag << " has at least one instance that is or contains a Grand Central "
96  "companion or layerblocks";
97 
98  for (auto *layerBlockOp : layerBlockOps)
99  diag.attachNote(layerBlockOp->getLoc()) << "illegal layerblock here";
100  for (auto *instUnderLayerBlock : instUnderLayerBlock)
101  diag.attachNote(instUnderLayerBlock->getLoc())
102  << "illegal instantiation under a layerblock here";
103  for (auto *instUnderLayerModule : instUnderLayerModule)
104  diag.attachNote(instUnderLayerModule->getLoc())
105  << "illegal instantiation in a module under a layer here";
106  }
107 
108 public:
109  static LogicalResult run(InstanceGraph &instanceGraph,
110  InstanceInfo &instanceInfo) {
111  CheckLayers checkLayers(instanceGraph, instanceInfo);
112  DenseSet<InstanceGraphNode *> visited;
113  for (auto *root : instanceGraph) {
114  for (auto *node : llvm::post_order_ext(root, visited)) {
115  if (auto moduleOp = dyn_cast<FModuleOp>(node->getModule<Operation *>()))
116  checkLayers.run(moduleOp);
117  }
118  }
119  return failure(checkLayers.error);
120  }
121 
122 private:
123  /// Pre-populated analyses
124  InstanceGraph &iGraph;
125  InstanceInfo &iInfo;
126 
127  /// A module whose instances (transitively) contain layerblocks or Grand
128  /// Central companions. This is used so that every illegal instantiation can
129  /// be reported. This is populated by `run` and requires child modules to be
130  /// visited before parents.
131  DenseSet<Operation *> transitiveModules;
132 
133  /// Indicates if this checker found an error.
134  bool error = false;
135 };
136 } // end anonymous namespace
137 
139  : public circt::firrtl::impl::CheckLayersBase<CheckLayersPass> {
140 public:
141  void runOnOperation() override {
142  if (failed(CheckLayers::run(getAnalysis<InstanceGraph>(),
143  getAnalysis<InstanceInfo>())))
144  return signalPassFailure();
145  markAllAnalysesPreserved();
146  }
147 };
148 
149 std::unique_ptr<Pass> circt::firrtl::createCheckLayers() {
150  return std::make_unique<CheckLayersPass>();
151 }
void runOnOperation() override
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.
std::unique_ptr< mlir::Pass > createCheckLayers()
constexpr const char * companionAnnoClass
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition: DebugAnalysis.h:21
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
Definition: codegen.py:121