From 04fb49d086d968754cd5eff1a1254d1e85d08acb Mon Sep 17 00:00:00 2001 From: Prithayan Barua Date: Sun, 24 Oct 2021 01:11:17 -0400 Subject: [PATCH] [FIRRTL] Update NLA during prefix module pass (#2030) This change updates the `NonLocalAnchor` symbol reference to modules that are renamed in prefix module pass. The `nla` op contains reference to module symbols, which might be left invalid after module renaming. For example, `firrtl.nla @nla_2 [@Top, @Aardvark, @Zebra] ["test", "test1", "Zebra"]` There can be multiple copies of any module created after the prefix module pass. The `firrtl.nla` renaming is context sensitive and depends on the instance op, which is anchored to the `nla`. This renaming is also based on the assumption, that the modules in the `firrtl.nla` begin with the top level module. Otherwise, the `firrtl.nla` might be ambiguous if multiple clones of the first module is created. --- .../FIRRTL/Transforms/PrefixModules.cpp | 54 +++++++++++++++++-- test/Dialect/FIRRTL/prefix-modules.mlir | 46 ++++++++++++++++ 2 files changed, 97 insertions(+), 3 deletions(-) diff --git a/lib/Dialect/FIRRTL/Transforms/PrefixModules.cpp b/lib/Dialect/FIRRTL/Transforms/PrefixModules.cpp index a661087d5b6f..e1da3fc62e14 100644 --- a/lib/Dialect/FIRRTL/Transforms/PrefixModules.cpp +++ b/lib/Dialect/FIRRTL/Transforms/PrefixModules.cpp @@ -108,6 +108,9 @@ class PrefixModulesPass : public PrefixModulesBase { /// Cached instance graph analysis. InstanceGraph *instanceGraph = nullptr; + /// Map of symbol name to NonLocalAnchor op. + llvm::StringMap nlaMap; + /// Boolean keeping track of any name changes. bool anythingChanged = false; }; @@ -135,13 +138,40 @@ void PrefixModulesPass::renameModuleBody(std::string prefix, FModuleOp module) { // Skip this rename if the instance is an external module. if (!target) return; - // Record that we must prefix the target module with the current prefix. recordPrefix(prefixMap, target.getName(), prefix); // Fixup this instance op to use the prefixed module name. Note that the // referenced FModuleOp will be renamed later. auto newTarget = (prefix + getPrefix(target) + target.getName()).str(); + AnnotationSet instAnnos(instanceOp); + // If the instance has NonLocalAnchor, then update its module name also. + // There can be multiple NonLocalAnchors attached to the instance op. + + for (Annotation anno : instAnnos) { + if (anno.isClass("circt.nonlocal")) + if (auto nla = anno.getMember("circt.nonlocal")) { + auto nlaName = nla.cast().getValue(); + auto f = nlaMap.find(nlaName); + if (f == nlaMap.end()) + instanceOp.emitError("cannot find NonLocalAnchor :" + nlaName); + else { + auto nlaOp = dyn_cast(f->second); + // Iterate over the modules of the NonLocalAnchor op, and update + // it. + SmallVector newMods; + for (auto oldMod : nlaOp.modpath()) { + if (instanceOp.moduleNameAttr() == + oldMod.cast()) + newMods.push_back(FlatSymbolRefAttr::get(context, newTarget)); + else + newMods.push_back(oldMod.cast()); + } + nlaOp->setAttr("modpath", ArrayAttr::get(context, newMods)); + } + } + } + instanceOp.moduleNameAttr(FlatSymbolRefAttr::get(context, newTarget)); } }); @@ -231,11 +261,29 @@ void PrefixModulesPass::runOnOperation() { instanceGraph = &getAnalysis(); auto circuitOp = getOperation(); + // Record all the NLA ops in the circt. + for (auto nla : circuitOp.body().getOps()) + nlaMap[nla.sym_name()] = nla; + // If the main module is prefixed, we have to update the CircuitOp. auto mainModule = instanceGraph->getTopLevelModule(); auto prefix = getPrefix(mainModule); - if (!prefix.empty()) - circuitOp.nameAttr(StringAttr::get(context, prefix + circuitOp.name())); + if (!prefix.empty()) { + auto newMainModuleName = ((prefix + circuitOp.name()).str()); + circuitOp.nameAttr(StringAttr::get(context, newMainModuleName)); + // Now update all the NLAs that have the top level module symbol. + for (auto &n : nlaMap) { + auto nla = cast(n.second); + auto oldMods = nla.modpath(); + if (oldMods.empty()) + continue; + SmallVector newMods(oldMods.begin(), oldMods.end()); + if (nla.modpath()[0].cast().getValue().equals( + mainModule.moduleName())) + newMods[0] = FlatSymbolRefAttr::get(context, newMainModuleName); + nla->setAttr("modpath", ArrayAttr::get(context, newMods)); + } + } // Walk all Modules in a top-down order. For each module, look at the list of // required prefixes to be applied. diff --git a/test/Dialect/FIRRTL/prefix-modules.mlir b/test/Dialect/FIRRTL/prefix-modules.mlir index 50c9d803a18c..716b733557ce 100644 --- a/test/Dialect/FIRRTL/prefix-modules.mlir +++ b/test/Dialect/FIRRTL/prefix-modules.mlir @@ -187,3 +187,49 @@ firrtl.circuit "GCTInterfacePrefix" firrtl.instance dut @DUT() } } + +// CHECK: firrtl.circuit "T_NLATop" +firrtl.circuit "NLATop" { + + firrtl.nla @nla [@NLATop, @Aardvark, @Zebra] ["test", "test", "Zebra"] + firrtl.nla @nla_1 [@NLATop, @Aardvark, @Zebra] ["test", "test_1", "Zebra"] + // CHECK: firrtl.nla @nla [@T_NLATop, @T_Aardvark, @T_A_Z_Zebra] ["test", "test", "Zebra"] + // CHECK: firrtl.nla @nla_1 [@T_NLATop, @T_Aardvark, @T_A_Z_Zebra] ["test", "test_1", "Zebra"] + // CHECK: firrtl.module @T_NLATop + firrtl.module @NLATop() + attributes {annotations = [{ + class = "sifive.enterprise.firrtl.NestedPrefixModulesAnnotation", + prefix = "T_", + inclusive = true + }]} { + + // CHECK: firrtl.instance test {annotations = [{circt.nonlocal = @nla, class = "circt.nonlocal"}, {circt.nonlocal = @nla_1, class = "circt.nonlocal"}]} @T_Aardvark() + firrtl.instance test {annotations = [{circt.nonlocal = @nla, class = "circt.nonlocal"}, {circt.nonlocal = @nla_1, class = "circt.nonlocal"} ]}@Aardvark() + + // CHECK: firrtl.instance test2 @T_Z_Zebra() + firrtl.instance test2 @Zebra() + } + + // CHECK: firrtl.module @T_Aardvark + firrtl.module @Aardvark() + attributes {annotations = [{ + class = "sifive.enterprise.firrtl.NestedPrefixModulesAnnotation", + prefix = "A_", + inclusive = false + }]} { + + // CHECK: firrtl.instance test {annotations = [{circt.nonlocal = @nla, class = "circt.nonlocal"}]} @T_A_Z_Zebra() + firrtl.instance test {annotations = [{circt.nonlocal = @nla, class = "circt.nonlocal"}]}@Zebra() + firrtl.instance test1 {annotations = [{circt.nonlocal = @nla_1, class = "circt.nonlocal"}]}@Zebra() + } + + // CHECK: firrtl.module @T_Z_Zebra + // CHECK: firrtl.module @T_A_Z_Zebra + firrtl.module @Zebra() + attributes {annotations = [{ + class = "sifive.enterprise.firrtl.NestedPrefixModulesAnnotation", + prefix = "Z_", + inclusive = true + }]} { + } +}