22 #include "mlir/IR/AttrTypeSubElements.h"
23 #include "llvm/ADT/DenseMap.h"
24 #include "llvm/ADT/PostOrderIterator.h"
25 #include "llvm/ADT/StringMap.h"
27 using namespace circt;
28 using namespace firrtl;
34 using PrefixMap = llvm::DenseMap<StringRef, std::vector<std::string>>;
39 auto &modulePrefixes = prefixMap[moduleName];
40 if (llvm::find(modulePrefixes, prefix) == modulePrefixes.end())
41 modulePrefixes.push_back(prefix);
68 StringRef prefix =
"";
69 if (
auto prefixAttr = anno.getMember<StringAttr>(
"prefix"))
70 prefix = prefixAttr.getValue();
73 bool inclusive =
false;
74 if (
auto inclusiveAttr = anno.getMember<BoolAttr>(
"inclusive"))
75 inclusive = inclusiveAttr.getValue();
77 return {prefix, inclusive};
83 if (prefixInfo.inclusive)
84 return prefixInfo.prefix;
94 class PrefixModulesPass :
public PrefixModulesBase<PrefixModulesPass> {
95 void removeDeadAnnotations(StringAttr moduleName, Operation *op);
96 void renameModuleBody(std::string prefix, StringRef oldName,
98 void renameModule(FModuleOp module);
99 void renameExtModule(FExtModuleOp extModule);
100 void renameMemModule(FMemModuleOp memModule);
101 void runOnOperation()
override;
107 void prefixGrandCentralInterfaces();
113 DenseMap<Attribute, std::string> interfacePrefixMap;
122 bool anythingChanged =
false;
129 void PrefixModulesPass::removeDeadAnnotations(StringAttr moduleName,
136 auto canRemoveAnno = [&](
Annotation anno, Operation *op) ->
bool {
137 auto nla = anno.
getMember(
"circt.nonlocal");
140 auto nlaName = cast<FlatSymbolRefAttr>(nla).getAttr();
141 auto nlaOp = nlaTable->getNLA(nlaName);
143 op->emitError(
"cannot find HierPathOp :" + nlaName.getValue());
148 bool isValid =
false;
149 if (isa<InstanceOp>(op))
150 isValid = nlaOp.hasModule(moduleName);
152 isValid = nlaOp.leafMod() == moduleName;
156 op, std::bind(canRemoveAnno, std::placeholders::_2, op));
158 op, std::bind(canRemoveAnno, std::placeholders::_1, op));
163 void PrefixModulesPass::renameModuleBody(std::string prefix, StringRef oldName,
165 auto *context = module.getContext();
171 anythingChanged =
true;
172 StringAttr thisMod = module.getNameAttr();
177 removeDeadAnnotations(thisMod, module);
179 mlir::AttrTypeReplacer replacer;
180 replacer.addReplacement(
181 [&](hw::InnerRefAttr innerRef) -> std::pair<Attribute, WalkResult> {
182 StringAttr moduleName = innerRef.getModule();
183 StringAttr symName = innerRef.getName();
185 StringAttr newTarget;
186 if (moduleName == oldName) {
187 newTarget = module.getNameAttr();
189 auto target = instanceGraph->lookup(moduleName)->getModule();
191 target.getModuleName());
196 module.getBody().walk([&](Operation *op) {
198 removeDeadAnnotations(thisMod, op);
200 if (
auto memOp = dyn_cast<MemOp>(op)) {
201 StringAttr newPrefix;
202 if (
auto oldPrefix = memOp->getAttrOfType<StringAttr>(
"prefix"))
206 memOp->setAttr(
"prefix", newPrefix);
207 }
else if (
auto instanceOp = dyn_cast<InstanceOp>(op)) {
208 auto target = instanceOp.getReferencedModule(*instanceGraph);
214 if (
auto *extModule = dyn_cast_or_null<FExtModuleOp>(&target)) {
219 if (!isDataTap && !isMemTap)
224 recordPrefix(prefixMap, target.getModuleName(), prefix);
229 target.getModuleName());
234 StringAttr oldModName = instanceOp.getModuleNameAttr().getAttr();
237 if (
auto nla = anno.
getMember(
"circt.nonlocal")) {
238 auto nlaName = cast<FlatSymbolRefAttr>(nla).getAttr();
239 nlaTable->updateModuleInNLA(nlaName, oldModName, newTarget);
243 DenseSet<hw::HierPathOp> instNLAs;
244 nlaTable->getInstanceNLAs(instanceOp, instNLAs);
245 for (
auto nla : instNLAs)
246 nlaTable->updateModuleInNLA(nla, oldModName, newTarget);
250 replacer.replaceElementsIn(op);
257 void PrefixModulesPass::renameModule(FModuleOp module) {
261 auto innerPrefix = prefixInfo.prefix;
267 auto oldName = module.getName().str();
268 std::string moduleName =
269 (prefixInfo.inclusive ? innerPrefix + oldName : oldName).str();
271 auto &prefixes = prefixMap[module.getName()];
277 if (prefixes.empty())
278 prefixes.push_back(
"");
280 auto &firstPrefix = prefixes.front();
282 auto fixNLAsRootedAt = [&](StringAttr oldModName, StringAttr newModuleName) {
283 DenseSet<hw::HierPathOp> nlas;
284 nlaTable->getNLAsInModule(oldModName, nlas);
286 if (n.root() == oldModName)
287 nlaTable->updateModuleInNLA(n, oldModName, newModuleName);
292 builder.setInsertionPointAfter(module);
293 auto oldModName = module.getNameAttr();
294 for (
auto &outerPrefix : llvm::drop_begin(prefixes)) {
295 auto moduleClone = cast<FModuleOp>(
builder.clone(*module));
296 std::string newModName = outerPrefix + moduleName;
297 auto newModNameAttr =
StringAttr::get(module.getContext(), newModName);
298 moduleClone.setName(newModNameAttr);
301 nlaTable->addModule(moduleClone);
302 fixNLAsRootedAt(oldModName, newModNameAttr);
304 renameModuleBody((outerPrefix + innerPrefix).str(), oldName, moduleClone);
307 auto prefixFull = (firstPrefix + innerPrefix).str();
308 auto newModuleName = firstPrefix + moduleName;
309 auto newModuleNameAttr =
StringAttr::get(module.getContext(), newModuleName);
313 module.setName(newModuleNameAttr);
314 nlaTable->addModule(module);
315 fixNLAsRootedAt(oldModName, newModuleNameAttr);
316 renameModuleBody(prefixFull, oldName, module);
319 SmallVector<Annotation, 1> newAnnotations;
320 annotations.removeAnnotations([&](
Annotation anno) {
322 anno.setMember(
"prefix", builder.getStringAttr(prefixFull));
323 newAnnotations.push_back(anno);
330 interfacePrefixMap[anno.
getMember<IntegerAttr>(
"id")] = prefixFull;
335 if (!newAnnotations.empty()) {
336 annotations.addAnnotations(newAnnotations);
337 annotations.applyToOperation(module);
349 void PrefixModulesPass::renameExtModule(FExtModuleOp extModule) {
351 auto &prefixes = prefixMap[extModule.getName()];
352 if (prefixes.empty())
356 builder.setInsertionPointAfter(extModule);
361 auto applyPrefixToNameAndDefName = [&](FExtModuleOp &extModule,
363 extModule.setName((prefix + extModule.getName()).str());
364 if (
auto defname = extModule.getDefname())
365 extModule->setAttr(
"defname",
builder.getStringAttr(prefix + *defname));
369 for (
auto &prefix : llvm::drop_begin(prefixes)) {
370 auto duplicate = cast<FExtModuleOp>(
builder.clone(*extModule));
371 applyPrefixToNameAndDefName(duplicate, prefix);
375 applyPrefixToNameAndDefName(extModule, prefixes.front());
379 void PrefixModulesPass::renameMemModule(FMemModuleOp memModule) {
381 auto &prefixes = prefixMap[memModule.getName()];
382 if (prefixes.empty())
386 builder.setInsertionPointAfter(memModule);
389 auto originalName = memModule.getName();
390 for (
auto &prefix : llvm::drop_begin(prefixes)) {
391 auto duplicate = cast<FMemModuleOp>(
builder.clone(*memModule));
392 duplicate.setName((prefix + originalName).str());
393 removeDeadAnnotations(duplicate.getNameAttr(), duplicate);
397 memModule.setName((prefixes.front() + originalName).str());
398 removeDeadAnnotations(memModule.getNameAttr(), memModule);
406 void PrefixModulesPass::prefixGrandCentralInterfaces() {
408 if (interfacePrefixMap.empty())
411 auto circuit = getOperation();
414 SmallVector<Attribute> newCircuitAnnotations;
420 if (
auto id = anno.
getMember<IntegerAttr>(
"id"))
421 prefix = interfacePrefixMap[id];
425 if (prefix.empty()) {
426 newCircuitAnnotations.push_back(anno.
getDict());
433 NamedAttrList newAnno(anno.
getDict().getValue());
434 newAnno.append(
"prefix",
builder.getStringAttr(prefix));
435 newCircuitAnnotations.push_back(
436 DictionaryAttr::getWithSorted(
builder.getContext(), newAnno));
444 void PrefixModulesPass::runOnOperation() {
445 auto *context = &getContext();
446 instanceGraph = &getAnalysis<InstanceGraph>();
447 nlaTable = &getAnalysis<NLATable>();
448 auto circuitOp = getOperation();
451 auto mainModule = instanceGraph->getTopLevelModule();
453 if (!prefix.empty()) {
454 auto oldModName = mainModule.getModuleNameAttr();
455 auto newMainModuleName =
457 circuitOp.setNameAttr(newMainModuleName);
460 nlaTable->renameModule(oldModName, newMainModuleName);
461 for (
auto n : nlaTable->lookup(oldModName))
462 if (n.root() == oldModName)
463 nlaTable->updateModuleInNLA(n, oldModName, newMainModuleName);
468 DenseSet<InstanceGraphNode *> visited;
469 for (
auto *current : *instanceGraph) {
470 for (
auto &node : llvm::inverse_post_order_ext(current, visited)) {
471 if (
auto module = dyn_cast<FModuleOp>(*node->getModule()))
472 renameModule(module);
473 if (
auto extModule = dyn_cast<FExtModuleOp>(*node->getModule()))
474 renameExtModule(extModule);
475 if (
auto memModule = dyn_cast<FMemModuleOp>(*node->getModule()))
476 renameMemModule(memModule);
481 prefixGrandCentralInterfaces();
484 interfacePrefixMap.clear();
485 if (!anythingChanged)
486 markAllAnalysesPreserved();
490 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.