21 #include "mlir/IR/AttrTypeSubElements.h"
22 #include "mlir/Pass/Pass.h"
23 #include "llvm/ADT/DenseMap.h"
24 #include "llvm/ADT/PostOrderIterator.h"
25 #include "llvm/ADT/StringMap.h"
29 #define GEN_PASS_DEF_PREFIXMODULES
30 #include "circt/Dialect/FIRRTL/Passes.h.inc"
34 using namespace circt;
35 using namespace firrtl;
41 using PrefixMap = llvm::DenseMap<StringRef, std::vector<std::string>>;
46 auto &modulePrefixes = prefixMap[moduleName];
47 if (llvm::find(modulePrefixes, prefix) == modulePrefixes.end())
48 modulePrefixes.push_back(prefix);
75 StringRef prefix =
"";
76 if (
auto prefixAttr = anno.getMember<StringAttr>(
"prefix"))
77 prefix = prefixAttr.getValue();
80 bool inclusive =
false;
81 if (
auto inclusiveAttr = anno.getMember<BoolAttr>(
"inclusive"))
82 inclusive = inclusiveAttr.getValue();
84 return {prefix, inclusive};
90 if (prefixInfo.inclusive)
91 return prefixInfo.prefix;
101 class PrefixModulesPass
102 :
public circt::firrtl::impl::PrefixModulesBase<PrefixModulesPass> {
103 void removeDeadAnnotations(StringAttr moduleName, Operation *op);
104 void renameModuleBody(std::string prefix, StringRef oldName,
106 void renameModule(FModuleOp module);
107 void renameExtModule(FExtModuleOp extModule);
108 void renameMemModule(FMemModuleOp memModule);
109 void runOnOperation()
override;
115 void prefixGrandCentralInterfaces();
121 DenseMap<Attribute, std::string> interfacePrefixMap;
130 bool anythingChanged =
false;
137 void PrefixModulesPass::removeDeadAnnotations(StringAttr moduleName,
144 auto canRemoveAnno = [&](
Annotation anno, Operation *op) ->
bool {
145 auto nla = anno.
getMember(
"circt.nonlocal");
148 auto nlaName = cast<FlatSymbolRefAttr>(nla).getAttr();
149 auto nlaOp = nlaTable->getNLA(nlaName);
151 op->emitError(
"cannot find HierPathOp :" + nlaName.getValue());
156 bool isValid =
false;
157 if (isa<InstanceOp>(op))
158 isValid = nlaOp.hasModule(moduleName);
160 isValid = nlaOp.leafMod() == moduleName;
164 op, std::bind(canRemoveAnno, std::placeholders::_2, op));
166 op, std::bind(canRemoveAnno, std::placeholders::_1, op));
171 void PrefixModulesPass::renameModuleBody(std::string prefix, StringRef oldName,
173 auto *context = module.getContext();
179 anythingChanged =
true;
180 StringAttr thisMod = module.getNameAttr();
185 removeDeadAnnotations(thisMod, module);
187 mlir::AttrTypeReplacer replacer;
188 replacer.addReplacement(
189 [&](hw::InnerRefAttr innerRef) -> std::pair<Attribute, WalkResult> {
190 StringAttr moduleName = innerRef.getModule();
191 StringAttr symName = innerRef.getName();
193 StringAttr newTarget;
194 if (moduleName == oldName) {
195 newTarget = module.getNameAttr();
197 auto target = instanceGraph->lookup(moduleName)->getModule();
199 target.getModuleName());
204 module.getBody().walk([&](Operation *op) {
206 removeDeadAnnotations(thisMod, op);
208 if (
auto memOp = dyn_cast<MemOp>(op)) {
209 StringAttr newPrefix;
210 if (
auto oldPrefix = memOp->getAttrOfType<StringAttr>(
"prefix"))
214 memOp->setAttr(
"prefix", newPrefix);
215 }
else if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
216 auto target = instanceOp.getReferencedModule(*instanceGraph);
222 if (
auto *extModule = dyn_cast_or_null<FExtModuleOp>(&target)) {
227 if (!isDataTap && !isMemTap)
232 recordPrefix(prefixMap, target.getModuleName(), prefix);
237 target.getModuleName());
242 StringAttr oldModName = instanceOp.getModuleNameAttr().getAttr();
245 if (
auto nla = anno.
getMember(
"circt.nonlocal")) {
246 auto nlaName = cast<FlatSymbolRefAttr>(nla).getAttr();
247 nlaTable->updateModuleInNLA(nlaName, oldModName, newTarget);
251 DenseSet<hw::HierPathOp> instNLAs;
252 nlaTable->getInstanceNLAs(instanceOp, instNLAs);
253 for (
auto nla : instNLAs)
254 nlaTable->updateModuleInNLA(nla, oldModName, newTarget);
258 replacer.replaceElementsIn(op);
265 void PrefixModulesPass::renameModule(FModuleOp module) {
269 auto innerPrefix = prefixInfo.prefix;
275 auto oldName = module.getName().str();
276 std::string moduleName =
277 (prefixInfo.inclusive ? innerPrefix + oldName : oldName).str();
279 auto &prefixes = prefixMap[module.getName()];
285 if (prefixes.empty())
286 prefixes.push_back(
"");
288 auto &firstPrefix = prefixes.front();
290 auto fixNLAsRootedAt = [&](StringAttr oldModName, StringAttr newModuleName) {
291 DenseSet<hw::HierPathOp> nlas;
292 nlaTable->getNLAsInModule(oldModName, nlas);
294 if (n.root() == oldModName)
295 nlaTable->updateModuleInNLA(n, oldModName, newModuleName);
299 OpBuilder builder(module);
300 builder.setInsertionPointAfter(module);
301 auto oldModName = module.getNameAttr();
302 for (
auto &outerPrefix : llvm::drop_begin(prefixes)) {
303 auto moduleClone = cast<FModuleOp>(builder.clone(*module));
304 std::string newModName = outerPrefix + moduleName;
305 auto newModNameAttr =
StringAttr::get(module.getContext(), newModName);
306 moduleClone.setName(newModNameAttr);
309 nlaTable->addModule(moduleClone);
310 fixNLAsRootedAt(oldModName, newModNameAttr);
312 renameModuleBody((outerPrefix + innerPrefix).str(), oldName, moduleClone);
315 auto prefixFull = (firstPrefix + innerPrefix).str();
316 auto newModuleName = firstPrefix + moduleName;
317 auto newModuleNameAttr =
StringAttr::get(module.getContext(), newModuleName);
321 module.setName(newModuleNameAttr);
322 nlaTable->addModule(module);
323 fixNLAsRootedAt(oldModName, newModuleNameAttr);
324 renameModuleBody(prefixFull, oldName, module);
327 SmallVector<Annotation, 1> newAnnotations;
328 annotations.removeAnnotations([&](
Annotation anno) {
330 anno.setMember(
"prefix", builder.getStringAttr(prefixFull));
331 newAnnotations.push_back(anno);
338 interfacePrefixMap[anno.
getMember<IntegerAttr>(
"id")] = prefixFull;
343 if (!newAnnotations.empty()) {
344 annotations.addAnnotations(newAnnotations);
345 annotations.applyToOperation(module);
357 void PrefixModulesPass::renameExtModule(FExtModuleOp extModule) {
359 auto &prefixes = prefixMap[extModule.getName()];
360 if (prefixes.empty())
363 OpBuilder builder(extModule);
364 builder.setInsertionPointAfter(extModule);
369 auto applyPrefixToNameAndDefName = [&](FExtModuleOp &extModule,
371 extModule.setName((prefix + extModule.getName()).str());
372 if (
auto defname = extModule.getDefname())
373 extModule->setAttr(
"defname", builder.getStringAttr(prefix + *defname));
377 for (
auto &prefix : llvm::drop_begin(prefixes)) {
378 auto duplicate = cast<FExtModuleOp>(builder.clone(*extModule));
379 applyPrefixToNameAndDefName(duplicate, prefix);
383 applyPrefixToNameAndDefName(extModule, prefixes.front());
387 void PrefixModulesPass::renameMemModule(FMemModuleOp memModule) {
389 auto &prefixes = prefixMap[memModule.getName()];
390 if (prefixes.empty())
393 OpBuilder builder(memModule);
394 builder.setInsertionPointAfter(memModule);
397 auto originalName = memModule.getName();
398 for (
auto &prefix : llvm::drop_begin(prefixes)) {
399 auto duplicate = cast<FMemModuleOp>(builder.clone(*memModule));
400 duplicate.setName((prefix + originalName).str());
401 removeDeadAnnotations(duplicate.getNameAttr(), duplicate);
405 memModule.setName((prefixes.front() + originalName).str());
406 removeDeadAnnotations(memModule.getNameAttr(), memModule);
414 void PrefixModulesPass::prefixGrandCentralInterfaces() {
416 if (interfacePrefixMap.empty())
419 auto circuit = getOperation();
420 OpBuilder builder(circuit);
422 SmallVector<Attribute> newCircuitAnnotations;
428 if (
auto id = anno.
getMember<IntegerAttr>(
"id"))
429 prefix = interfacePrefixMap[id];
433 if (prefix.empty()) {
434 newCircuitAnnotations.push_back(anno.
getDict());
441 NamedAttrList newAnno(anno.
getDict().getValue());
442 newAnno.append(
"prefix", builder.getStringAttr(prefix));
443 newCircuitAnnotations.push_back(
444 DictionaryAttr::getWithSorted(builder.getContext(), newAnno));
452 void PrefixModulesPass::runOnOperation() {
453 auto *context = &getContext();
454 instanceGraph = &getAnalysis<InstanceGraph>();
455 nlaTable = &getAnalysis<NLATable>();
456 auto circuitOp = getOperation();
459 auto mainModule = instanceGraph->getTopLevelModule();
461 if (!prefix.empty()) {
462 auto oldModName = mainModule.getModuleNameAttr();
463 auto newMainModuleName =
465 circuitOp.setNameAttr(newMainModuleName);
468 nlaTable->renameModule(oldModName, newMainModuleName);
469 for (
auto n : nlaTable->lookup(oldModName))
470 if (n.root() == oldModName)
471 nlaTable->updateModuleInNLA(n, oldModName, newMainModuleName);
476 DenseSet<InstanceGraphNode *> visited;
477 for (
auto *current : *instanceGraph) {
478 for (
auto &node : llvm::inverse_post_order_ext(current, visited)) {
479 if (
auto module = dyn_cast<FModuleOp>(*node->getModule()))
480 renameModule(module);
481 else if (
auto extModule = dyn_cast<FExtModuleOp>(*node->getModule()))
482 renameExtModule(extModule);
483 else if (
auto memModule = dyn_cast<FMemModuleOp>(*node->getModule()))
484 renameMemModule(memModule);
489 prefixGrandCentralInterfaces();
492 interfacePrefixMap.clear();
493 if (!anythingChanged)
494 markAllAnalysesPreserved();
498 return std::make_unique<PrefixModulesPass>();
static void recordPrefix(PrefixMap &prefixMap, StringRef moduleName, std::string prefix)
Insert a string into the end of vector if the string is not already present.
llvm::DenseMap< StringRef, std::vector< std::string > > PrefixMap
This maps a FModuleOp to a list of all prefixes that need to be applied.
static PrefixInfo getPrefixInfo(Operation *module)
Get the PrefixInfo for a module from a NestedPrefixModulesAnnotation on a module.
static StringRef getPrefix(Operation *module)
If there is an inclusive prefix attached to the module, return it.
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
bool applyToOperation(Operation *op) const
Store the annotations in this set in an operation's annotations attribute, overwriting any existing a...
bool hasAnnotation(StringRef className) const
Return true if we have an annotation with the specified class name.
static bool removePortAnnotations(Operation *module, llvm::function_ref< bool(unsigned, Annotation)> predicate)
Remove all port annotations from a module or extmodule for which predicate returns true.
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
Annotation getAnnotation(StringRef className) const
If this annotation set has an annotation with the specified class name, return it.
This class provides a read-only projection of an annotation.
DictionaryAttr getDict() const
Get the data dictionary of this attribute.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
StringRef getClass() const
Return the 'class' that this annotation is representing.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
This graph tracks modules and where they are instantiated.
This table tracks nlas and what modules participate in them.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
constexpr const char * augmentedBundleTypeClass
constexpr const char * dutAnnoClass
constexpr const char * dataTapsBlackboxClass
constexpr const char * prefixModulesAnnoClass
constexpr const char * companionAnnoClass
constexpr const char * memTapPortClass
std::unique_ptr< mlir::Pass > createPrefixModulesPass()
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.