CIRCT 20.0.0git
Loading...
Searching...
No Matches
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
17namespace circt {
18namespace firrtl {
19#define GEN_PASS_DEF_CHECKLAYERS
20#include "circt/Dialect/FIRRTL/Passes.h.inc"
21} // namespace firrtl
22} // namespace circt
23
24using namespace circt;
25using namespace firrtl;
26using namespace mlir;
27
28namespace {
29class 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
108public:
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
122private:
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> {
140public:
141 void runOnOperation() override {
142 if (failed(CheckLayers::run(getAnalysis<InstanceGraph>(),
143 getAnalysis<InstanceInfo>())))
144 return signalPassFailure();
145 markAllAnalysesPreserved();
146 }
147};
148
149std::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.
int run(Type[Generator] generator=CppGenerator, cmdline_args=sys.argv)
Definition codegen.py:121