mirror of https://github.com/llvm/circt.git
[FIRRTL] Convert CheckLayers to use InstanceInfo (#7635)
Change the `CheckLayers` pass to use the `InstanceInfo` analysis. This new analysis makes the error checking trivial. However, the error reporting is still somewhat tedious. Signed-off-by: Schuyler Eldridge <schuyler.eldridge@sifive.com>
This commit is contained in:
parent
bc2951d75b
commit
f85865eea9
|
@ -6,10 +6,13 @@
|
|||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "circt/Analysis/FIRRTLInstanceInfo.h"
|
||||
#include "circt/Dialect/FIRRTL/FIRRTLInstanceGraph.h"
|
||||
#include "circt/Dialect/FIRRTL/FIRRTLOps.h"
|
||||
#include "circt/Dialect/FIRRTL/Passes.h"
|
||||
#include "circt/Support/InstanceGraphInterface.h"
|
||||
#include "mlir/Pass/Pass.h"
|
||||
#include "llvm/ADT/DepthFirstIterator.h"
|
||||
#include "llvm/ADT/PostOrderIterator.h"
|
||||
|
||||
namespace circt {
|
||||
|
@ -25,72 +28,56 @@ using namespace mlir;
|
|||
|
||||
namespace {
|
||||
class CheckLayers {
|
||||
CheckLayers(InstanceGraph &instanceGraph) : instanceGraph(instanceGraph) {}
|
||||
|
||||
/// Walk the LayerBlock and report any illegal instantiation found within.
|
||||
void run(LayerBlockOp layerBlock) {
|
||||
layerBlock.getBody()->walk([&](FInstanceLike instance) {
|
||||
auto moduleName = instance.getReferencedModuleNameAttr();
|
||||
auto *targetModule =
|
||||
instanceGraph.lookup(moduleName)->getModule<Operation *>();
|
||||
auto childLayerBlock = layerBlocks.lookup(targetModule);
|
||||
if (childLayerBlock) {
|
||||
auto diag = emitError(instance.getLoc())
|
||||
<< "cannot instantiate " << moduleName
|
||||
<< " under a layerblock, because " << moduleName
|
||||
<< " contains a layerblock";
|
||||
diag.attachNote(childLayerBlock.getLoc()) << "layerblock here";
|
||||
error = true;
|
||||
}
|
||||
});
|
||||
}
|
||||
CheckLayers(InstanceGraph &instanceGraph, InstanceInfo &instanceInfo)
|
||||
: iGraph(instanceGraph), iInfo(instanceInfo) {}
|
||||
|
||||
/// Walk a module, reporting any illegal instantation of layers under layers,
|
||||
/// and record if this module contains any layerblocks.
|
||||
void run(FModuleOp moduleOp) {
|
||||
// If this module directly contains a layerblock, or instantiates another
|
||||
// module with a layerblock, then this will point to the layerblock. We use
|
||||
// this for error reporting. We keep track of only the first layerblock
|
||||
// found.
|
||||
LayerBlockOp firstLayerblock = nullptr;
|
||||
moduleOp.getBodyBlock()->walk<WalkOrder::PreOrder>([&](Operation *op) {
|
||||
// If we are instantiating a module, check if it contains a layerblock. If
|
||||
// it does, mark this target layerblock as our layerblock.
|
||||
if (auto instance = dyn_cast<FInstanceLike>(op)) {
|
||||
// If this is the first layer block in this module, record it.
|
||||
if (!firstLayerblock) {
|
||||
auto moduleName = instance.getReferencedModuleNameAttr();
|
||||
auto *targetModule =
|
||||
instanceGraph.lookup(moduleName)->getModule().getOperation();
|
||||
firstLayerblock = layerBlocks.lookup(targetModule);
|
||||
}
|
||||
return WalkResult::advance();
|
||||
}
|
||||
if (auto layerBlock = dyn_cast<LayerBlockOp>(op)) {
|
||||
// If this is the first layer block in this module, record it.
|
||||
if (!firstLayerblock)
|
||||
firstLayerblock = layerBlock;
|
||||
// Process the layerblock.
|
||||
run(layerBlock);
|
||||
// Don't recurse on elements of the layerblock. If an instance within
|
||||
// did contain a layerblock, then an error would have been reported for
|
||||
// it already.
|
||||
return WalkResult::skip();
|
||||
}
|
||||
// Do nothing for all other operations.
|
||||
return WalkResult::advance();
|
||||
// No instance is under a layer block. No further examination is necessary.
|
||||
if (!iInfo.anyInstanceUnderLayer(moduleOp))
|
||||
return;
|
||||
|
||||
// The module is under a layer block. Verify that it has no layer blocks.
|
||||
LayerBlockOp layerBlockOp;
|
||||
moduleOp.getBodyBlock()->walk([&](LayerBlockOp op) {
|
||||
layerBlockOp = op;
|
||||
return WalkResult::interrupt();
|
||||
});
|
||||
// If this module contained a layerblock, then record it.
|
||||
if (firstLayerblock)
|
||||
layerBlocks.try_emplace(moduleOp, firstLayerblock);
|
||||
if (!layerBlockOp)
|
||||
return;
|
||||
|
||||
// The module contains layer blocks and is instantiated under a layer block.
|
||||
// Walk up the instance hierarchy to find the first instance which is
|
||||
// directly under a layer block.
|
||||
error = true;
|
||||
for (auto *node : llvm::inverse_depth_first(iGraph.lookup(moduleOp))) {
|
||||
auto modOp = node->getModule();
|
||||
if (previousErrors.contains(node) || !iInfo.anyInstanceUnderLayer(modOp))
|
||||
continue;
|
||||
for (auto *instNode : node->uses()) {
|
||||
auto instanceOp = instNode->getInstance();
|
||||
if (instanceOp->getParentOfType<LayerBlockOp>()) {
|
||||
auto moduleName = modOp.getModuleNameAttr();
|
||||
auto diag = emitError(instanceOp.getLoc())
|
||||
<< "cannot instantiate " << moduleName
|
||||
<< " under a layerblock, because " << moduleName
|
||||
<< " contains a layerblock";
|
||||
diag.attachNote(layerBlockOp->getLoc()) << "layerblock here";
|
||||
previousErrors.insert(node);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
static LogicalResult run(InstanceGraph &instanceGraph) {
|
||||
CheckLayers checkLayers(instanceGraph);
|
||||
static LogicalResult run(InstanceGraph &instanceGraph,
|
||||
InstanceInfo &instanceInfo) {
|
||||
CheckLayers checkLayers(instanceGraph, instanceInfo);
|
||||
DenseSet<InstanceGraphNode *> visited;
|
||||
for (auto *root : instanceGraph) {
|
||||
for (auto *node : llvm::post_order_ext(root, visited)) {
|
||||
for (auto *node : llvm::inverse_post_order_ext(root, visited)) {
|
||||
if (auto moduleOp = dyn_cast<FModuleOp>(node->getModule<Operation *>()))
|
||||
checkLayers.run(moduleOp);
|
||||
}
|
||||
|
@ -99,10 +86,15 @@ public:
|
|||
}
|
||||
|
||||
private:
|
||||
InstanceGraph &instanceGraph;
|
||||
/// A mapping from a module to the first layerblock that it contains,
|
||||
/// transitively through instances.
|
||||
DenseMap<Operation *, LayerBlockOp> layerBlocks;
|
||||
/// Pre-populated analyses
|
||||
InstanceGraph &iGraph;
|
||||
InstanceInfo &iInfo;
|
||||
|
||||
/// This records modules for which we have already generated errors when doing
|
||||
/// a top-down walk.
|
||||
DenseSet<const InstanceGraphNode *> previousErrors;
|
||||
|
||||
/// Indicates if this checker found an error.
|
||||
bool error = false;
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
@ -111,7 +103,8 @@ class CheckLayersPass
|
|||
: public circt::firrtl::impl::CheckLayersBase<CheckLayersPass> {
|
||||
public:
|
||||
void runOnOperation() override {
|
||||
if (failed(CheckLayers::run(getAnalysis<InstanceGraph>())))
|
||||
if (failed(CheckLayers::run(getAnalysis<InstanceGraph>(),
|
||||
getAnalysis<InstanceInfo>())))
|
||||
return signalPassFailure();
|
||||
markAllAnalysesPreserved();
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue