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 = dyn_cast<FModuleLike>(
209 *instanceGraph->getReferencedModule(instanceOp));
215 if (
auto *extModule = dyn_cast_or_null<FExtModuleOp>(&target)) {
220 if (!isDataTap && !isMemTap)
225 recordPrefix(prefixMap, target.getModuleName(), prefix);
230 target.getModuleName());
235 StringAttr oldModName = instanceOp.getModuleNameAttr().getAttr();
238 if (
auto nla = anno.
getMember(
"circt.nonlocal")) {
239 auto nlaName = cast<FlatSymbolRefAttr>(nla).getAttr();
240 nlaTable->updateModuleInNLA(nlaName, oldModName, newTarget);
244 DenseSet<hw::HierPathOp> instNLAs;
245 nlaTable->getInstanceNLAs(instanceOp, instNLAs);
246 for (
auto nla : instNLAs)
247 nlaTable->updateModuleInNLA(nla, oldModName, newTarget);
251 replacer.replaceElementsIn(op);
258 void PrefixModulesPass::renameModule(FModuleOp module) {
262 auto innerPrefix = prefixInfo.prefix;
268 auto oldName = module.getName().str();
269 std::string moduleName =
270 (prefixInfo.inclusive ? innerPrefix + oldName : oldName).str();
272 auto &prefixes = prefixMap[module.getName()];
278 if (prefixes.empty())
279 prefixes.push_back(
"");
281 auto &firstPrefix = prefixes.front();
283 auto fixNLAsRootedAt = [&](StringAttr oldModName, StringAttr newModuleName) {
284 DenseSet<hw::HierPathOp> nlas;
285 nlaTable->getNLAsInModule(oldModName, nlas);
287 if (n.root() == oldModName)
288 nlaTable->updateModuleInNLA(n, oldModName, newModuleName);
293 builder.setInsertionPointAfter(module);
294 auto oldModName = module.getNameAttr();
295 for (
auto &outerPrefix : llvm::drop_begin(prefixes)) {
296 auto moduleClone = cast<FModuleOp>(
builder.clone(*module));
297 std::string newModName = outerPrefix + moduleName;
298 auto newModNameAttr =
StringAttr::get(module.getContext(), newModName);
299 moduleClone.setName(newModNameAttr);
302 nlaTable->addModule(moduleClone);
303 fixNLAsRootedAt(oldModName, newModNameAttr);
305 renameModuleBody((outerPrefix + innerPrefix).str(), oldName, moduleClone);
308 auto prefixFull = (firstPrefix + innerPrefix).str();
309 auto newModuleName = firstPrefix + moduleName;
310 auto newModuleNameAttr =
StringAttr::get(module.getContext(), newModuleName);
314 module.setName(newModuleNameAttr);
315 nlaTable->addModule(module);
316 fixNLAsRootedAt(oldModName, newModuleNameAttr);
317 renameModuleBody(prefixFull, oldName, module);
320 SmallVector<Annotation, 1> newAnnotations;
321 annotations.removeAnnotations([&](
Annotation anno) {
323 anno.setMember(
"prefix", builder.getStringAttr(prefixFull));
324 newAnnotations.push_back(anno);
331 interfacePrefixMap[anno.
getMember<IntegerAttr>(
"id")] = prefixFull;
336 if (!newAnnotations.empty()) {
337 annotations.addAnnotations(newAnnotations);
338 annotations.applyToOperation(module);
350 void PrefixModulesPass::renameExtModule(FExtModuleOp extModule) {
352 auto &prefixes = prefixMap[extModule.getName()];
353 if (prefixes.empty())
357 builder.setInsertionPointAfter(extModule);
362 auto applyPrefixToNameAndDefName = [&](FExtModuleOp &extModule,
364 extModule.setName((prefix + extModule.getName()).str());
365 if (
auto defname = extModule.getDefname())
366 extModule->setAttr(
"defname",
builder.getStringAttr(prefix + *defname));
370 for (
auto &prefix : llvm::drop_begin(prefixes)) {
371 auto duplicate = cast<FExtModuleOp>(
builder.clone(*extModule));
372 applyPrefixToNameAndDefName(duplicate, prefix);
376 applyPrefixToNameAndDefName(extModule, prefixes.front());
380 void PrefixModulesPass::renameMemModule(FMemModuleOp memModule) {
382 auto &prefixes = prefixMap[memModule.getName()];
383 if (prefixes.empty())
387 builder.setInsertionPointAfter(memModule);
390 auto originalName = memModule.getName();
391 for (
auto &prefix : llvm::drop_begin(prefixes)) {
392 auto duplicate = cast<FMemModuleOp>(
builder.clone(*memModule));
393 duplicate.setName((prefix + originalName).str());
394 removeDeadAnnotations(duplicate.getNameAttr(), duplicate);
398 memModule.setName((prefixes.front() + originalName).str());
399 removeDeadAnnotations(memModule.getNameAttr(), memModule);
407 void PrefixModulesPass::prefixGrandCentralInterfaces() {
409 if (interfacePrefixMap.empty())
412 auto circuit = getOperation();
415 SmallVector<Attribute> newCircuitAnnotations;
421 if (
auto id = anno.
getMember<IntegerAttr>(
"id"))
422 prefix = interfacePrefixMap[id];
426 if (prefix.empty()) {
427 newCircuitAnnotations.push_back(anno.
getDict());
434 NamedAttrList newAnno(anno.
getDict().getValue());
435 newAnno.append(
"prefix",
builder.getStringAttr(prefix));
436 newCircuitAnnotations.push_back(
437 DictionaryAttr::getWithSorted(
builder.getContext(), newAnno));
445 void PrefixModulesPass::runOnOperation() {
446 auto *context = &getContext();
447 instanceGraph = &getAnalysis<InstanceGraph>();
448 nlaTable = &getAnalysis<NLATable>();
449 auto circuitOp = getOperation();
452 auto mainModule = instanceGraph->getTopLevelModule();
454 if (!prefix.empty()) {
455 auto oldModName = mainModule.getModuleNameAttr();
456 auto newMainModuleName =
458 circuitOp.setNameAttr(newMainModuleName);
461 nlaTable->renameModule(oldModName, newMainModuleName);
462 for (
auto n : nlaTable->lookup(oldModName))
463 if (n.root() == oldModName)
464 nlaTable->updateModuleInNLA(n, oldModName, newMainModuleName);
469 DenseSet<InstanceGraphNode *> visited;
470 for (
auto *current : *instanceGraph) {
471 for (
auto &node : llvm::inverse_post_order_ext(current, visited)) {
472 if (
auto module = dyn_cast<FModuleOp>(*node->getModule()))
473 renameModule(module);
474 if (
auto extModule = dyn_cast<FExtModuleOp>(*node->getModule()))
475 renameExtModule(extModule);
476 if (
auto memModule = dyn_cast<FMemModuleOp>(*node->getModule()))
477 renameMemModule(memModule);
482 prefixGrandCentralInterfaces();
485 interfacePrefixMap.clear();
486 if (!anythingChanged)
487 markAllAnalysesPreserved();
491 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()
This file defines an intermediate representation for circuits acting as an abstraction for constraint...