28 #include "mlir/IR/Attributes.h"
29 #include "mlir/IR/ImplicitLocOpBuilder.h"
30 #include "mlir/Support/FileUtilities.h"
31 #include "llvm/ADT/SmallPtrSet.h"
32 #include "llvm/Support/Debug.h"
33 #include "llvm/Support/MemoryBuffer.h"
34 #include "llvm/Support/Path.h"
36 #define DEBUG_TYPE "firrtl-extract-instances"
38 using namespace circt;
39 using namespace firrtl;
40 using hw::InnerRefAttr;
48 struct ExtractionInfo {
50 StringRef traceFilename;
54 StringRef wrapperModule;
60 struct ExtractInstancesPass
61 :
public ExtractInstancesBase<ExtractInstancesPass> {
62 void runOnOperation()
override;
64 void collectAnno(InstanceOp inst,
Annotation anno);
65 void extractInstances();
66 void groupInstances();
67 void createTraceFiles();
70 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
71 return moduleNamespaces.try_emplace(module, module).first->second;
78 [&](FModuleLike mod) -> hw::InnerSymbolNamespace & {
79 return getModuleNamespace(mod);
84 hw::HierPathOp cloneWithNewNameAndPath(hw::HierPathOp pathOp,
85 ArrayRef<Attribute> newPath) {
87 auto newPathOp =
builder.cloneWithoutRegions(pathOp);
88 newPathOp.setSymNameAttr(
builder.getStringAttr(
89 circuitNamespace.newName(newPathOp.getSymName())));
90 newPathOp.setNamepathAttr(
builder.getArrayAttr(newPath));
101 DenseMap<Operation *, SmallVector<Annotation, 1>> annotatedModules;
105 DenseSet<Operation *> dutRootModules;
108 DenseSet<Operation *> dutModules;
110 DenseSet<Attribute> dutModuleNames;
113 StringRef dutPrefix =
"";
116 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractionWorklist;
122 DenseMap<Operation *, SmallVector<InnerRefAttr>> extractionPaths;
126 DenseMap<Operation *, StringAttr> originalInstanceParents;
130 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractedInstances;
133 DenseMap<Operation *, SmallString<16>> instPrefices;
138 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
143 void ExtractInstancesPass::runOnOperation() {
144 CircuitOp circuitOp = getOperation();
145 anythingChanged =
false;
147 annotatedModules.clear();
148 dutRootModules.clear();
150 extractionWorklist.clear();
151 extractionPaths.clear();
152 originalInstanceParents.clear();
153 extractedInstances.clear();
154 instPrefices.clear();
155 moduleNamespaces.clear();
156 circuitNamespace.clear();
157 circuitNamespace.add(circuitOp);
161 instanceGraph = &getAnalysis<InstanceGraph>();
164 return signalPassFailure();
169 return signalPassFailure();
174 return signalPassFailure();
179 return signalPassFailure();
183 if (!anythingChanged)
184 markAllAnalysesPreserved();
193 void ExtractInstancesPass::collectAnnos() {
194 CircuitOp circuit = getOperation();
197 StringRef clkgateFileName;
198 StringRef clkgateWrapperModule;
203 <<
"Clock gate extraction config: " << anno.
getDict() <<
"\n");
204 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
205 auto groupAttr = anno.
getMember<StringAttr>(
"group");
207 circuit.emitError(
"missing `filename` attribute in `")
208 << anno.
getClass() <<
"` annotation";
213 if (!clkgateFileName.empty()) {
214 circuit.emitError(
"multiple `")
215 << anno.getClass() <<
"` annotations on circuit";
220 clkgateFileName = filenameAttr.getValue();
222 clkgateWrapperModule = groupAttr.getValue();
227 StringRef memoryFileName;
228 StringRef memoryWrapperModule;
233 <<
"Memory extraction config: " << anno.
getDict() <<
"\n");
234 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
235 auto groupAttr = anno.
getMember<StringAttr>(
"group");
237 circuit.emitError(
"missing `filename` attribute in `")
238 << anno.
getClass() <<
"` annotation";
243 if (!memoryFileName.empty()) {
244 circuit.emitError(
"multiple `")
245 << anno.getClass() <<
"` annotations on circuit";
250 memoryFileName = filenameAttr.getValue();
252 memoryWrapperModule = groupAttr.getValue();
258 for (
auto module : circuit.getOps<FModuleLike>()) {
261 LLVM_DEBUG(llvm::dbgs()
262 <<
"Marking DUT `" << module.getModuleName() <<
"`\n");
263 dutRootModules.insert(module);
264 dutModules.insert(module);
265 if (auto prefix = anno.getMember<StringAttr>(
"prefix"))
271 LLVM_DEBUG(
llvm::dbgs() <<
"Annotated module `" << module.getModuleName()
272 <<
"`:\n " << anno.
getDict() <<
"\n");
273 annotatedModules[module].push_back(anno);
279 circuit.walk([&](InstanceOp inst) {
280 SmallVector<Annotation, 1> instAnnos;
281 Operation *module = instanceGraph->getReferencedModule(inst);
284 auto it = annotatedModules.find(module);
285 if (it != annotatedModules.end())
286 instAnnos.append(it->second);
292 LLVM_DEBUG(
llvm::dbgs() <<
"Annotated instance `" << inst.getName()
293 <<
"`:\n " << anno.
getDict() <<
"\n");
294 instAnnos.push_back(anno);
299 if (instAnnos.empty())
303 if (instAnnos.size() > 1) {
304 auto d = inst.emitError(
"multiple extraction annotations on instance `")
305 << inst.getName() <<
"`";
306 d.attachNote(inst.getLoc()) <<
"instance has the following annotations, "
307 "but at most one is allowed:";
308 for (
auto anno : instAnnos)
309 d.attachNote(inst.getLoc()) << anno.
getDict();
315 collectAnno(inst, instAnnos[0]);
319 LLVM_DEBUG(
llvm::dbgs() <<
"Marking DUT hierarchy\n");
320 SmallVector<InstanceGraphNode *> worklist;
321 for (Operation *op : dutModules)
323 instanceGraph->lookup(cast<igraph::ModuleOpInterface>(op)));
324 while (!worklist.empty()) {
325 auto *module = worklist.pop_back_val();
326 dutModuleNames.insert(module->getModule().getModuleNameAttr());
328 <<
"- " << module->getModule().getModuleName() <<
"\n");
329 for (
auto *instRecord : *module) {
330 auto *target = instRecord->getTarget();
331 if (dutModules.insert(target->getModule()).second)
332 worklist.push_back(target);
340 if (!clkgateFileName.empty()) {
341 auto clkgateDefNameAttr =
StringAttr::get(&getContext(),
"EICG_wrapper");
342 for (
auto module : circuit.getOps<FExtModuleOp>()) {
343 if (module.getDefnameAttr() != clkgateDefNameAttr)
346 <<
"Clock gate `" << module.getModuleName() <<
"`\n");
347 if (!dutModules.contains(module)) {
348 LLVM_DEBUG(
llvm::dbgs() <<
"- Ignored (outside DUT)\n");
353 info.traceFilename = clkgateFileName;
354 info.prefix =
"clock_gate";
355 info.wrapperModule = clkgateWrapperModule;
356 info.stopAtDUT = !info.wrapperModule.empty();
357 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
358 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
361 << inst->getParentOfType<FModuleLike>().getModuleName()
362 <<
"." << inst.getName() <<
"`\n");
363 extractionWorklist.push_back({inst, info});
372 if (!memoryFileName.empty()) {
377 auto *context = circuit.getContext();
379 circuit.getBodyBlock());
380 builder.create<sv::VerbatimOp>(
"")->setAttr(
382 hw::OutputFileAttr::getFromFilename(context, memoryFileName,
385 for (
auto module : circuit.getOps<FMemModuleOp>()) {
386 LLVM_DEBUG(
llvm::dbgs() <<
"Memory `" << module.getModuleName() <<
"`\n");
387 if (!dutModules.contains(module)) {
388 LLVM_DEBUG(
llvm::dbgs() <<
"- Ignored (outside DUT)\n");
393 info.traceFilename = memoryFileName;
394 info.prefix =
"mem_wiring";
395 info.wrapperModule = memoryWrapperModule;
396 info.stopAtDUT = !info.wrapperModule.empty();
397 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
398 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
401 << inst->getParentOfType<FModuleLike>().getModuleName()
402 <<
"." << inst.getName() <<
"`\n");
403 extractionWorklist.push_back({inst, info});
412 void ExtractInstancesPass::collectAnno(InstanceOp inst,
Annotation anno) {
413 LLVM_DEBUG(
llvm::dbgs() <<
"Processing instance `" << inst.getName() <<
"` "
416 auto getStringOrError = [&](StringRef member) {
417 auto attr = anno.
getMember<StringAttr>(member);
419 inst.emitError(
"missing `")
420 << member <<
"` attribute in `" << anno.
getClass() <<
"` annotation";
427 auto filename = getStringOrError(
"filename");
428 auto prefix = getStringOrError(
"prefix");
429 auto dest = anno.
getMember<StringAttr>(
"dest");
434 info.traceFilename = filename;
435 info.prefix = prefix;
436 info.wrapperModule = (dest ? dest.getValue() :
"");
441 info.stopAtDUT = !info.wrapperModule.empty();
443 extractionWorklist.push_back({inst, info});
453 unsigned nlaLen = nla.getNamepath().size();
455 auto parentName = cast<FModuleOp>(inst->getParentOp()).getModuleNameAttr();
456 for (
unsigned nlaIdx = 0; nlaIdx < nlaLen; ++nlaIdx) {
457 auto refPart = nla.refPart(nlaIdx);
458 if (nla.modPart(nlaIdx) == parentName && (!refPart || refPart == instName))
467 void ExtractInstancesPass::extractInstances() {
470 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
472 DenseMap<StringRef, unsigned> prefixUniqueIDs;
474 SmallPtrSet<Operation *, 4> nlasToRemove;
476 auto &nlaTable = getAnalysis<NLATable>();
479 for (
auto &[inst, info] : extractionWorklist)
480 originalInstanceParents[inst] =
481 inst->getParentOfType<FModuleLike>().getModuleNameAttr();
483 while (!extractionWorklist.empty()) {
486 std::tie(inst, info) = extractionWorklist.pop_back_val();
487 auto parent = inst->getParentOfType<FModuleOp>();
496 if (!info.prefix.empty()) {
497 auto &prefixSlot = instPrefices[inst];
498 if (prefixSlot.empty()) {
499 auto idx = prefixUniqueIDs[info.prefix]++;
500 (Twine(info.prefix) +
"_" + Twine(idx)).
toVector(prefixSlot);
509 if (!dutModules.contains(parent) ||
510 instanceGraph->lookup(parent)->noUses() ||
511 (info.stopAtDUT && dutRootModules.contains(parent))) {
512 LLVM_DEBUG(
llvm::dbgs() <<
"\nNo need to further move " << inst <<
"\n");
513 extractedInstances.push_back({inst, info});
525 unsigned numParentPorts = parent.getNumPorts();
526 unsigned numInstPorts = inst.getNumResults();
528 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
531 auto name = inst.getPortNameStr(portIdx);
534 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
537 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
539 newPort.loc = inst.getResult(portIdx).getLoc();
540 newPorts.push_back({numParentPorts, newPort});
542 <<
"- Adding port " << newPort.direction <<
" "
543 << newPort.name.getValue() <<
": " << newPort.type <<
"\n");
545 parent.insertPorts(newPorts);
546 anythingChanged =
true;
550 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
551 inst.getResult(portIdx).replaceAllUsesWith(
552 parent.getArgument(numParentPorts + portIdx));
554 assert(inst.use_empty() &&
"instance ports should have been detached");
555 DenseSet<hw::HierPathOp> instanceNLAs;
558 nlaTable.getInstanceNLAs(inst, instanceNLAs);
561 DenseMap<hw::HierPathOp, SmallVector<Annotation>> instNonlocalAnnos;
564 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
568 if (hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr())) {
569 instNonlocalAnnos[nla].push_back(anno);
570 instanceNLAs.insert(nla);
577 SmallVector<hw::HierPathOp> sortedInstanceNLAs(instanceNLAs.begin(),
579 llvm::sort(sortedInstanceNLAs,
580 [](
auto a,
auto b) {
return a.getSymName() < b.getSymName(); });
585 auto *instParentNode =
586 instanceGraph->lookup(cast<igraph::ModuleOpInterface>(*parent));
587 for (
auto *instRecord : instParentNode->uses()) {
588 auto oldParentInst = cast<InstanceOp>(*instRecord->getInstance());
589 auto newParent = oldParentInst->getParentOfType<FModuleLike>();
590 LLVM_DEBUG(
llvm::dbgs() <<
"- Updating " << oldParentInst <<
"\n");
591 auto newParentInst = oldParentInst.cloneAndInsertPorts(newPorts);
594 for (
unsigned portIdx = 0; portIdx < numParentPorts; ++portIdx)
595 oldParentInst.getResult(portIdx).replaceAllUsesWith(
596 newParentInst.getResult(portIdx));
600 auto newInst = inst.cloneAndInsertPorts({});
607 getModuleNamespace(newParent).newName(instSym.getValue());
608 if (newName != instSym.getValue())
609 newInst.setInnerSymAttr(
614 ImplicitLocOpBuilder
builder(inst.getLoc(), newParentInst);
615 builder.setInsertionPointAfter(newParentInst);
617 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
618 auto dst = newInst.getResult(portIdx);
619 auto src = newParentInst.getResult(numParentPorts + portIdx);
622 builder.create<StrictConnectOp>(dst, src);
631 auto oldPrefix = instPrefices.find(inst);
632 if (oldPrefix != instPrefices.end()) {
634 <<
" - Reusing prefix `" << oldPrefix->second <<
"`\n");
635 auto newPrefix = std::move(oldPrefix->second);
636 instPrefices.erase(oldPrefix);
637 instPrefices.insert({newInst, newPrefix});
641 extractionPaths.try_emplace(newInst);
642 auto &extractionPath = (extractionPaths[newInst] = extractionPaths[inst]);
644 originalInstanceParents.try_emplace(newInst);
645 originalInstanceParents[newInst] = originalInstanceParents[inst];
648 SmallVector<Annotation> newInstNonlocalAnnos;
651 for (
auto nla : sortedInstanceNLAs) {
652 LLVM_DEBUG(
llvm::dbgs() <<
" - Updating " << nla <<
"\n");
656 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
657 nla.getNamepath().end());
666 if (nlaIdx >= nlaPath.size()) {
667 LLVM_DEBUG(
llvm::dbgs() <<
" - Instance no longer in path\n");
670 LLVM_DEBUG(
llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
677 auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx - 1]);
679 !(innerRef.getModule() == newParent.getModuleNameAttr() &&
682 <<
" - Ignored since NLA parent " << innerRef
683 <<
" does not pass through extraction parent\n");
701 LLVM_DEBUG(
llvm::dbgs() <<
" - Re-rooting " << nlaPath[0] <<
"\n");
702 assert(isa<InnerRefAttr>(nlaPath[0]) &&
703 "head of hierpath must be an InnerRefAttr");
707 if (instParentNode->hasOneUse()) {
712 nla.setNamepathAttr(
builder.getArrayAttr(nlaPath));
713 for (
auto anno : instNonlocalAnnos.lookup(nla))
714 newInstNonlocalAnnos.push_back(anno);
715 nlaTable.addNLA(nla);
716 LLVM_DEBUG(
llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
720 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
721 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
724 newInstNonlocalAnnos.push_back(anno);
727 nlaTable.addNLA(newNla);
728 LLVM_DEBUG(
llvm::dbgs() <<
" - Created " << newNla <<
"\n");
738 inst.emitWarning(
"extraction of instance `")
739 << inst.getInstanceName()
740 <<
"` could break non-local annotations rooted at `"
741 << parent.getModuleName() <<
"`";
752 if (nlaPath.size() == 2) {
753 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
755 newInstNonlocalAnnos.push_back(anno);
756 LLVM_DEBUG(
llvm::dbgs() <<
" - Converted to local "
760 nlasToRemove.insert(nla);
768 StringAttr parentName =
769 cast<InnerRefAttr>(nlaPath[nlaIdx - 1]).getModule();
771 if (isa<InnerRefAttr>(nlaPath[nlaIdx]))
776 <<
" - Replacing " << nlaPath[nlaIdx - 1] <<
" and "
777 << nlaPath[nlaIdx] <<
" with " << newRef <<
"\n");
778 nlaPath[nlaIdx] = newRef;
779 nlaPath.erase(nlaPath.begin() + nlaIdx - 1);
781 if (isa<FlatSymbolRefAttr>(newRef)) {
786 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
787 nlaTable.addNLA(newNla);
788 LLVM_DEBUG(
llvm::dbgs() <<
" - Created " << newNla <<
"\n");
789 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
792 newInstNonlocalAnnos.push_back(anno);
795 nla.setNamepathAttr(
builder.getArrayAttr(nlaPath));
796 LLVM_DEBUG(
llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
797 for (
auto anno : instNonlocalAnnos.lookup(nla))
798 newInstNonlocalAnnos.push_back(anno);
806 newInstAnnos.addAnnotations(newInstNonlocalAnnos);
807 newInstAnnos.applyToOperation(newInst);
811 extractionWorklist.push_back({newInst, info});
812 LLVM_DEBUG(
llvm::dbgs() <<
" - Updated to " << newInst <<
"\n");
815 instanceGraph->replaceInstance(oldParentInst, newParentInst);
816 oldParentInst.erase();
821 nlaTable.removeNLAsfromModule(instanceNLAs, parent.getNameAttr());
829 for (Operation *op : nlasToRemove) {
830 LLVM_DEBUG(
llvm::dbgs() <<
"Removing obsolete " << *op <<
"\n");
838 void ExtractInstancesPass::groupInstances() {
843 llvm::MapVector<std::pair<Operation *, StringRef>, SmallVector<InstanceOp>>
845 for (
auto &[inst, info] : extractedInstances) {
846 if (!info.wrapperModule.empty())
847 instsByWrapper[{inst->getParentOfType<FModuleOp>(), info.wrapperModule}]
850 if (instsByWrapper.empty())
852 LLVM_DEBUG(
llvm::dbgs() <<
"\nGrouping instances into wrappers\n");
855 SmallVector<PortInfo> ports;
856 auto &nlaTable = getAnalysis<NLATable>();
858 for (
auto &[parentAndWrapperName, insts] : instsByWrapper) {
859 auto [parentOp, wrapperName] = parentAndWrapperName;
860 auto parent = cast<FModuleOp>(parentOp);
861 LLVM_DEBUG(
llvm::dbgs() <<
"- Wrapper `" << wrapperName <<
"` in `"
862 << parent.getModuleName() <<
"` with "
863 << insts.size() <<
" instances\n");
867 auto wrapperModuleName =
builder.getStringAttr(
868 circuitNamespace.newName(dutPrefix + wrapperName));
869 auto wrapperInstName =
870 builder.getStringAttr(getModuleNamespace(parent).newName(wrapperName));
877 for (
auto inst : insts) {
879 StringRef prefix(instPrefices[inst]);
880 unsigned portNum = inst.getNumResults();
881 for (
unsigned portIdx = 0; portIdx < portNum; ++portIdx) {
882 auto name = inst.getPortNameStr(portIdx);
883 auto nameAttr =
builder.getStringAttr(
884 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
886 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
887 inst.getPortDirection(portIdx)};
888 port.
loc = inst.getResult(portIdx).getLoc();
889 ports.push_back(port);
893 DenseSet<hw::HierPathOp> instNlas;
895 nlaTable.getInstanceNLAs(inst, instNlas);
899 for (
auto anno : instAnnos) {
900 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
903 hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr());
905 instNlas.insert(nla);
907 for (
auto nla : instNlas) {
908 LLVM_DEBUG(
llvm::dbgs() <<
" - Updating " << nla <<
"\n");
912 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
913 nla.getNamepath().end());
915 assert(nlaIdx < nlaPath.size() &&
"instance not found in its own NLA");
916 LLVM_DEBUG(
llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
923 if (
auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx]))
927 LLVM_DEBUG(
llvm::dbgs() <<
" - Expanding " << nlaPath[nlaIdx]
928 <<
" to (" << ref1 <<
", " << ref2 <<
")\n");
929 nlaPath[nlaIdx] = ref1;
930 nlaPath.insert(nlaPath.begin() + nlaIdx + 1, ref2);
934 nla.setNamepathAttr(
builder.getArrayAttr(nlaPath));
935 LLVM_DEBUG(
llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
937 nlaTable.addNLAtoModule(nla, wrapperModuleName);
942 auto wrapper =
builder.create<FModuleOp>(
943 builder.getUnknownLoc(), wrapperModuleName,
945 SymbolTable::setSymbolVisibility(wrapper, SymbolTable::Visibility::Private);
950 builder.setInsertionPointToStart(parent.getBodyBlock());
951 auto wrapperInst =
builder.create<InstanceOp>(
952 wrapper.getLoc(), wrapper, wrapperName, NameKindEnum::DroppableName,
953 ArrayRef<Attribute>{},
954 ArrayRef<Attribute>{},
false,
956 unsigned portIdx = 0;
957 for (
auto inst : insts)
958 for (
auto result : inst.getResults())
959 result.replaceAllUsesWith(wrapperInst.getResult(portIdx++));
964 builder.setInsertionPointToStart(wrapper.getBodyBlock());
965 for (
auto inst : insts) {
968 for (
auto result : inst.getResults()) {
970 Value src = wrapper.getArgument(portIdx);
973 builder.create<StrictConnectOp>(result.getLoc(), dst, src);
983 void ExtractInstancesPass::createTraceFiles() {
984 LLVM_DEBUG(
llvm::dbgs() <<
"\nGenerating trace files\n");
985 auto builder = OpBuilder::atBlockEnd(getOperation().getBodyBlock());
989 for (
auto &[inst, info] : extractedInstances)
990 if (!info.traceFilename.empty())
991 instsByTraceFile[info.traceFilename].push_back(inst);
994 SmallVector<Attribute> symbols;
997 for (
auto &[fileName, insts] : instsByTraceFile) {
998 LLVM_DEBUG(
llvm::dbgs() <<
"- " << fileName <<
"\n");
1000 llvm::raw_string_ostream os(buffer);
1002 symbolIndices.clear();
1004 auto addSymbol = [&](Attribute symbol) {
1006 auto it = symbolIndices.find(symbol);
1007 if (it != symbolIndices.end()) {
1010 id = symbols.size();
1011 symbols.push_back(symbol);
1012 symbolIndices.insert({symbol,
id});
1014 os <<
"{{" <<
id <<
"}}";
1017 for (
auto inst : insts) {
1018 StringRef prefix(instPrefices[inst]);
1019 if (prefix.empty()) {
1020 LLVM_DEBUG(
llvm::dbgs() <<
" - Skipping `" << inst.getName()
1021 <<
"` since it has no extraction prefix\n");
1024 ArrayRef<InnerRefAttr> path(extractionPaths[inst]);
1026 LLVM_DEBUG(
llvm::dbgs() <<
" - Skipping `" << inst.getName()
1027 <<
"` since it has not been moved\n");
1031 <<
" - " << prefix <<
": " << inst.getName() <<
"\n");
1032 os << prefix <<
" -> ";
1037 while (!path.empty() &&
1038 !dutModuleNames.contains(path.back().getModule())) {
1040 <<
" - Dropping non-DUT segment " << path.back() <<
"\n");
1041 path = path.drop_back();
1047 ? originalInstanceParents[inst]
1048 : path.back().getModule()));
1049 for (
auto sym : llvm::reverse(path)) {
1060 auto verbatimOp =
builder.create<sv::VerbatimOp>(
1061 builder.getUnknownLoc(), buffer, ValueRange{},
1062 builder.getArrayAttr(symbols));
1063 auto fileAttr = hw::OutputFileAttr::getFromFilename(
1064 builder.getContext(), fileName,
true);
1065 verbatimOp->setAttr(
"output_file", fileAttr);
1074 return std::make_unique<ExtractInstancesPass>();
assert(baseType &&"element must be base type")
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
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.
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.
void setMember(StringAttr name, Attribute value)
Add or set a member of the annotation to a value.
void removeMember(StringAttr name)
Remove 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.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
Direction flip(Direction direction)
Flip a port direction.
constexpr const char * extractBlackBoxAnnoClass
constexpr const char * dutAnnoClass
constexpr const char * extractSeqMemsAnnoClass
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
std::unique_ptr< mlir::Pass > createExtractInstancesPass()
constexpr const char * extractClockGatesAnnoClass
StringAttr getInnerSymName(Operation *op)
Return the StringAttr for the inner_sym name, if it exists.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & dbgs()
The namespace of a CircuitOp, generally inhabited by modules.
This holds the name and type that describes the module's ports.