1313#include  " circt/Dialect/FIRRTL/FIRRTLInstanceGraph.h" 
1414#include  " circt/Dialect/FIRRTL/FIRRTLOps.h" 
1515#include  " circt/Dialect/FIRRTL/Passes.h" 
16+ #include  " circt/Dialect/HW/HWOps.h" 
1617#include  " circt/Support/Debug.h" 
1718#include  " mlir/IR/Dominance.h" 
1819#include  " mlir/IR/Threading.h" 
@@ -34,6 +35,9 @@ using namespace circt;
3435using  namespace  firrtl ; 
3536using  namespace  mlir ; 
3637
38+ static  constexpr  llvm::StringLiteral
39+     kExtMemoryEffectNLAAttrName (" circt.layerSink.externalMemoryEffect" 
40+ 
3741// ===----------------------------------------------------------------------===//
3842//  Helpers
3943// ===----------------------------------------------------------------------===//
@@ -87,7 +91,10 @@ static bool cloneable(Operation *op) {
8791namespace  {
8892class  EffectInfo  {
8993public: 
90-   EffectInfo (CircuitOp circuit, InstanceGraph &instanceGraph) {
94+   EffectInfo (CircuitOp circuit, InstanceGraph &instanceGraph,
95+              DenseSet<StringAttr> explicitEffectfulModules)
96+       : explicitEffectfulModules(std::move(explicitEffectfulModules)) {
97+     DenseSet<InstanceGraphNode *> visited;
9198    instanceGraph.walkPostOrder (
9299        [&](auto  &node) { update (node.getModule ().getOperation ()); });
93100  }
@@ -111,6 +118,7 @@ class EffectInfo {
111118  }
112119
113120private: 
121+   DenseSet<StringAttr> explicitEffectfulModules;
114122  // / Record whether the module contains any effectful ops.
115123  void  update (FModuleOp moduleOp) {
116124    moduleOp.getBodyBlock ()->walk ([&](Operation *op) {
@@ -130,6 +138,14 @@ class EffectInfo {
130138      if  (!annos.empty ())
131139        return  markEffectful (moduleOp);
132140
141+     if  (explicitEffectfulModules.contains (moduleOp.getModuleNameAttr ()))
142+       return  markEffectful (moduleOp);
143+ 
144+     //  Treat generated memory modules as effectful since they model stateful
145+     //  hardware even though they have no body.
146+     if  (isa<FMemModuleOp>(moduleOp.getOperation ()))
147+       return  markEffectful (moduleOp);
148+ 
133149    for  (auto  annos : moduleOp.getPortAnnotations ())
134150      if  (!cast<ArrayAttr>(annos).empty ())
135151        return  markEffectful (moduleOp);
@@ -486,7 +502,19 @@ void LayerSinkPass::runOnOperation() {
486502                 << " \n " 
487503                 << " Circuit: '" getName () << " '\n " 
488504  auto  &instanceGraph = getAnalysis<InstanceGraph>();
489-   EffectInfo effectInfo (circuit, instanceGraph);
505+ 
506+   DenseSet<StringAttr> explicitEffectModules;
507+   SmallVector<hw::HierPathOp, 4 > effectNLAs;
508+   for  (auto  nla : circuit.getOps <hw::HierPathOp>()) {
509+     if  (!nla->hasAttr (kExtMemoryEffectNLAAttrName ))
510+       continue ;
511+     if  (auto  leaf = nla.leafMod ())
512+       explicitEffectModules.insert (leaf);
513+     effectNLAs.push_back (nla);
514+   }
515+ 
516+   EffectInfo effectInfo (circuit, instanceGraph,
517+                         std::move (explicitEffectModules));
490518
491519  std::atomic<bool > changed (false );
492520  parallelForEach (&getContext (), circuit.getOps <FModuleOp>(),
@@ -495,6 +523,9 @@ void LayerSinkPass::runOnOperation() {
495523                      changed = true ;
496524                  });
497525
526+   for  (auto  nla : effectNLAs)
527+     nla.erase ();
528+ 
498529  if  (!changed)
499530    markAllAnalysesPreserved ();
500531  else 
0 commit comments