29 #include "mlir/IR/Attributes.h"
30 #include "mlir/IR/ImplicitLocOpBuilder.h"
31 #include "mlir/Pass/Pass.h"
32 #include "mlir/Support/FileUtilities.h"
33 #include "llvm/ADT/SmallPtrSet.h"
34 #include "llvm/Support/Debug.h"
35 #include "llvm/Support/MemoryBuffer.h"
36 #include "llvm/Support/Path.h"
38 #define DEBUG_TYPE "firrtl-extract-instances"
42 #define GEN_PASS_DEF_EXTRACTINSTANCES
43 #include "circt/Dialect/FIRRTL/Passes.h.inc"
47 using namespace circt;
48 using namespace firrtl;
49 using hw::InnerRefAttr;
57 struct ExtractionInfo {
59 StringRef traceFilename;
63 StringRef wrapperModule;
69 struct ExtractInstancesPass
70 :
public circt::firrtl::impl::ExtractInstancesBase<ExtractInstancesPass> {
71 void runOnOperation()
override;
73 void collectAnno(InstanceOp inst,
Annotation anno);
74 void extractInstances();
75 void groupInstances();
76 void createTraceFiles();
79 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
80 return moduleNamespaces.try_emplace(module, module).first->second;
87 [&](FModuleLike mod) -> hw::InnerSymbolNamespace & {
88 return getModuleNamespace(mod);
93 hw::HierPathOp cloneWithNewNameAndPath(hw::HierPathOp pathOp,
94 ArrayRef<Attribute> newPath) {
95 OpBuilder builder(pathOp);
96 auto newPathOp = builder.cloneWithoutRegions(pathOp);
97 newPathOp.setSymNameAttr(builder.getStringAttr(
98 circuitNamespace.newName(newPathOp.getSymName())));
99 newPathOp.setNamepathAttr(builder.getArrayAttr(newPath));
104 emit::FileOp getOrCreateFile(StringRef fileName) {
105 auto [it, inserted] = files.try_emplace(fileName, emit::FileOp{});
107 auto builder = ImplicitLocOpBuilder::atBlockEnd(
109 it->second = builder.create<emit::FileOp>(fileName);
114 bool anythingChanged;
121 DenseMap<Operation *, SmallVector<Annotation, 1>> annotatedModules;
125 DenseSet<Operation *> dutRootModules;
128 DenseSet<Operation *> dutModules;
130 DenseSet<Attribute> dutModuleNames;
133 StringRef dutPrefix =
"";
136 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractionWorklist;
139 DenseMap<StringRef, emit::FileOp> files;
145 DenseMap<Operation *, SmallVector<InnerRefAttr>> extractionPaths;
149 DenseMap<Operation *, StringAttr> originalInstanceParents;
153 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractedInstances;
156 DenseMap<Operation *, SmallString<16>> instPrefices;
161 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
166 void ExtractInstancesPass::runOnOperation() {
167 CircuitOp circuitOp = getOperation();
168 anythingChanged =
false;
170 annotatedModules.clear();
171 dutRootModules.clear();
173 dutModuleNames.clear();
175 extractionWorklist.clear();
177 extractionPaths.clear();
178 originalInstanceParents.clear();
179 extractedInstances.clear();
180 instPrefices.clear();
181 moduleNamespaces.clear();
182 circuitNamespace.clear();
183 circuitNamespace.add(circuitOp);
187 instanceGraph = &getAnalysis<InstanceGraph>();
190 return signalPassFailure();
195 return signalPassFailure();
200 return signalPassFailure();
205 return signalPassFailure();
208 LLVM_DEBUG(llvm::dbgs() <<
"\n");
209 if (!anythingChanged)
210 markAllAnalysesPreserved();
219 void ExtractInstancesPass::collectAnnos() {
220 CircuitOp circuit = getOperation();
223 StringRef clkgateFileName;
224 StringRef clkgateWrapperModule;
228 LLVM_DEBUG(llvm::dbgs()
229 <<
"Clock gate extraction config: " << anno.
getDict() <<
"\n");
230 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
231 auto groupAttr = anno.
getMember<StringAttr>(
"group");
233 circuit.emitError(
"missing `filename` attribute in `")
234 << anno.
getClass() <<
"` annotation";
239 if (!clkgateFileName.empty()) {
240 circuit.emitError(
"multiple `")
241 << anno.getClass() <<
"` annotations on circuit";
246 clkgateFileName = filenameAttr.getValue();
248 clkgateWrapperModule = groupAttr.getValue();
253 StringRef memoryFileName;
254 StringRef memoryWrapperModule;
258 LLVM_DEBUG(llvm::dbgs()
259 <<
"Memory extraction config: " << anno.
getDict() <<
"\n");
260 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
261 auto groupAttr = anno.
getMember<StringAttr>(
"group");
263 circuit.emitError(
"missing `filename` attribute in `")
264 << anno.
getClass() <<
"` annotation";
269 if (!memoryFileName.empty()) {
270 circuit.emitError(
"multiple `")
271 << anno.getClass() <<
"` annotations on circuit";
276 memoryFileName = filenameAttr.getValue();
278 memoryWrapperModule = groupAttr.getValue();
284 for (
auto module : circuit.getOps<FModuleLike>()) {
287 LLVM_DEBUG(llvm::dbgs()
288 <<
"Marking DUT `" << module.getModuleName() <<
"`\n");
289 dutRootModules.insert(module);
290 dutModules.insert(module);
291 if (auto prefix = anno.getMember<StringAttr>(
"prefix"))
297 LLVM_DEBUG(llvm::dbgs() <<
"Annotated module `" << module.getModuleName()
298 <<
"`:\n " << anno.
getDict() <<
"\n");
299 annotatedModules[module].push_back(anno);
305 circuit.walk([&](InstanceOp inst) {
306 SmallVector<Annotation, 1> instAnnos;
307 Operation *module = inst.getReferencedModule(*instanceGraph);
310 auto it = annotatedModules.find(module);
311 if (it != annotatedModules.end())
312 instAnnos.append(it->second);
318 LLVM_DEBUG(llvm::dbgs() <<
"Annotated instance `" << inst.getName()
319 <<
"`:\n " << anno.
getDict() <<
"\n");
320 instAnnos.push_back(anno);
325 if (instAnnos.empty())
329 if (instAnnos.size() > 1) {
330 auto d = inst.emitError(
"multiple extraction annotations on instance `")
331 << inst.getName() <<
"`";
332 d.attachNote(inst.getLoc()) <<
"instance has the following annotations, "
333 "but at most one is allowed:";
334 for (
auto anno : instAnnos)
335 d.attachNote(inst.getLoc()) << anno.
getDict();
341 collectAnno(inst, instAnnos[0]);
345 LLVM_DEBUG(llvm::dbgs() <<
"Marking DUT hierarchy\n");
346 SmallVector<InstanceGraphNode *> worklist;
347 for (Operation *op : dutModules)
349 instanceGraph->lookup(cast<igraph::ModuleOpInterface>(op)));
350 while (!worklist.empty()) {
351 auto *module = worklist.pop_back_val();
352 dutModuleNames.insert(module->getModule().getModuleNameAttr());
353 LLVM_DEBUG(llvm::dbgs()
354 <<
"- " << module->getModule().getModuleName() <<
"\n");
355 for (
auto *instRecord : *module) {
356 auto *target = instRecord->getTarget();
357 if (dutModules.insert(target->getModule()).second)
358 worklist.push_back(target);
366 if (!clkgateFileName.empty()) {
367 auto clkgateDefNameAttr =
StringAttr::get(&getContext(),
"EICG_wrapper");
368 for (
auto module : circuit.getOps<FExtModuleOp>()) {
369 if (module.getDefnameAttr() != clkgateDefNameAttr)
371 LLVM_DEBUG(llvm::dbgs()
372 <<
"Clock gate `" << module.getModuleName() <<
"`\n");
373 if (!dutModules.contains(module)) {
374 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
379 info.traceFilename = clkgateFileName;
380 info.prefix =
"clock_gate";
381 info.wrapperModule = clkgateWrapperModule;
382 info.stopAtDUT = !info.wrapperModule.empty();
383 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
384 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
385 LLVM_DEBUG(llvm::dbgs()
387 << inst->getParentOfType<FModuleLike>().getModuleName()
388 <<
"." << inst.getName() <<
"`\n");
389 extractionWorklist.push_back({inst, info});
398 if (!memoryFileName.empty()) {
402 getOrCreateFile(memoryFileName);
404 for (
auto module : circuit.getOps<FMemModuleOp>()) {
405 LLVM_DEBUG(llvm::dbgs() <<
"Memory `" << module.getModuleName() <<
"`\n");
406 if (!dutModules.contains(module)) {
407 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
412 info.traceFilename = memoryFileName;
413 info.prefix =
"mem_wiring";
414 info.wrapperModule = memoryWrapperModule;
415 info.stopAtDUT = !info.wrapperModule.empty();
416 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
417 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
418 LLVM_DEBUG(llvm::dbgs()
420 << inst->getParentOfType<FModuleLike>().getModuleName()
421 <<
"." << inst.getName() <<
"`\n");
422 extractionWorklist.push_back({inst, info});
431 void ExtractInstancesPass::collectAnno(InstanceOp inst,
Annotation anno) {
432 LLVM_DEBUG(llvm::dbgs() <<
"Processing instance `" << inst.getName() <<
"` "
435 auto getStringOrError = [&](StringRef member) {
436 auto attr = anno.
getMember<StringAttr>(member);
438 inst.emitError(
"missing `")
439 << member <<
"` attribute in `" << anno.
getClass() <<
"` annotation";
446 auto filename = getStringOrError(
"filename");
447 auto prefix = getStringOrError(
"prefix");
448 auto dest = anno.
getMember<StringAttr>(
"dest");
453 info.traceFilename = filename;
454 info.prefix = prefix;
455 info.wrapperModule = (dest ? dest.getValue() :
"");
460 info.stopAtDUT = !info.wrapperModule.empty();
462 extractionWorklist.push_back({inst, info});
472 unsigned nlaLen = nla.getNamepath().size();
474 auto parentName = cast<FModuleOp>(inst->getParentOp()).getModuleNameAttr();
475 for (
unsigned nlaIdx = 0; nlaIdx < nlaLen; ++nlaIdx) {
476 auto refPart = nla.refPart(nlaIdx);
477 if (nla.modPart(nlaIdx) == parentName && (!refPart || refPart == instName))
486 void ExtractInstancesPass::extractInstances() {
489 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
491 DenseMap<StringRef, unsigned> prefixUniqueIDs;
493 SmallPtrSet<Operation *, 4> nlasToRemove;
495 auto &nlaTable = getAnalysis<NLATable>();
498 for (
auto &[inst, info] : extractionWorklist)
499 originalInstanceParents[inst] =
500 inst->getParentOfType<FModuleLike>().getModuleNameAttr();
502 while (!extractionWorklist.empty()) {
505 std::tie(inst, info) = extractionWorklist.pop_back_val();
506 auto parent = inst->getParentOfType<FModuleOp>();
515 if (!info.prefix.empty()) {
516 auto &prefixSlot = instPrefices[inst];
517 if (prefixSlot.empty()) {
518 auto idx = prefixUniqueIDs[info.prefix]++;
519 (Twine(info.prefix) +
"_" + Twine(idx)).
toVector(prefixSlot);
528 if (!dutModules.contains(parent) ||
529 instanceGraph->lookup(parent)->noUses() ||
530 (info.stopAtDUT && dutRootModules.contains(parent))) {
531 LLVM_DEBUG(llvm::dbgs() <<
"\nNo need to further move " << inst <<
"\n");
532 extractedInstances.push_back({inst, info});
536 llvm::dbgs() <<
"\nMoving ";
538 llvm::dbgs() <<
"`" << prefix <<
"` ";
539 llvm::dbgs() << inst <<
"\n";
544 unsigned numParentPorts = parent.getNumPorts();
545 unsigned numInstPorts = inst.getNumResults();
547 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
550 auto name = inst.getPortNameStr(portIdx);
553 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
556 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
558 newPort.loc = inst.getResult(portIdx).getLoc();
559 newPorts.push_back({numParentPorts, newPort});
560 LLVM_DEBUG(llvm::dbgs()
561 <<
"- Adding port " << newPort.direction <<
" "
562 << newPort.name.getValue() <<
": " << newPort.type <<
"\n");
564 parent.insertPorts(newPorts);
565 anythingChanged =
true;
569 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
570 inst.getResult(portIdx).replaceAllUsesWith(
571 parent.getArgument(numParentPorts + portIdx));
573 assert(inst.use_empty() &&
"instance ports should have been detached");
574 DenseSet<hw::HierPathOp> instanceNLAs;
577 nlaTable.getInstanceNLAs(inst, instanceNLAs);
580 DenseMap<hw::HierPathOp, SmallVector<Annotation>> instNonlocalAnnos;
583 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
587 if (hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr())) {
588 instNonlocalAnnos[nla].push_back(anno);
589 instanceNLAs.insert(nla);
596 SmallVector<hw::HierPathOp> sortedInstanceNLAs(instanceNLAs.begin(),
598 llvm::sort(sortedInstanceNLAs,
599 [](
auto a,
auto b) {
return a.getSymName() < b.getSymName(); });
604 auto *instParentNode =
605 instanceGraph->lookup(cast<igraph::ModuleOpInterface>(*parent));
606 for (
auto *instRecord : instParentNode->uses()) {
607 auto oldParentInst = cast<InstanceOp>(*instRecord->getInstance());
608 auto newParent = oldParentInst->getParentOfType<FModuleLike>();
609 LLVM_DEBUG(llvm::dbgs() <<
"- Updating " << oldParentInst <<
"\n");
610 auto newParentInst = oldParentInst.cloneAndInsertPorts(newPorts);
613 for (
unsigned portIdx = 0; portIdx < numParentPorts; ++portIdx)
614 oldParentInst.getResult(portIdx).replaceAllUsesWith(
615 newParentInst.getResult(portIdx));
619 auto newInst = inst.cloneAndInsertPorts({});
626 getModuleNamespace(newParent).newName(instSym.getValue());
627 if (newName != instSym.getValue())
628 newInst.setInnerSymAttr(
633 ImplicitLocOpBuilder builder(inst.getLoc(), newParentInst);
634 builder.setInsertionPointAfter(newParentInst);
635 builder.insert(newInst);
636 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
637 auto dst = newInst.getResult(portIdx);
638 auto src = newParentInst.getResult(numParentPorts + portIdx);
641 builder.create<MatchingConnectOp>(dst, src);
650 auto oldPrefix = instPrefices.find(inst);
651 if (oldPrefix != instPrefices.end()) {
652 LLVM_DEBUG(llvm::dbgs()
653 <<
" - Reusing prefix `" << oldPrefix->second <<
"`\n");
654 auto newPrefix = std::move(oldPrefix->second);
655 instPrefices.erase(oldPrefix);
656 instPrefices.insert({newInst, newPrefix});
660 extractionPaths.try_emplace(newInst);
661 auto &extractionPath = (extractionPaths[newInst] = extractionPaths[inst]);
663 originalInstanceParents.try_emplace(newInst);
664 originalInstanceParents[newInst] = originalInstanceParents[inst];
667 SmallVector<Annotation> newInstNonlocalAnnos;
670 for (
auto nla : sortedInstanceNLAs) {
671 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
675 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
676 nla.getNamepath().end());
685 if (nlaIdx >= nlaPath.size()) {
686 LLVM_DEBUG(llvm::dbgs() <<
" - Instance no longer in path\n");
689 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
696 auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx - 1]);
698 !(innerRef.getModule() == newParent.getModuleNameAttr() &&
700 LLVM_DEBUG(llvm::dbgs()
701 <<
" - Ignored since NLA parent " << innerRef
702 <<
" does not pass through extraction parent\n");
720 LLVM_DEBUG(llvm::dbgs() <<
" - Re-rooting " << nlaPath[0] <<
"\n");
721 assert(isa<InnerRefAttr>(nlaPath[0]) &&
722 "head of hierpath must be an InnerRefAttr");
726 if (instParentNode->hasOneUse()) {
731 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
732 for (
auto anno : instNonlocalAnnos.lookup(nla))
733 newInstNonlocalAnnos.push_back(anno);
734 nlaTable.addNLA(nla);
735 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
739 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
740 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
743 newInstNonlocalAnnos.push_back(anno);
746 nlaTable.addNLA(newNla);
747 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
757 inst.emitWarning(
"extraction of instance `")
758 << inst.getInstanceName()
759 <<
"` could break non-local annotations rooted at `"
760 << parent.getModuleName() <<
"`";
771 if (nlaPath.size() == 2) {
772 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
774 newInstNonlocalAnnos.push_back(anno);
775 LLVM_DEBUG(llvm::dbgs() <<
" - Converted to local "
779 nlasToRemove.insert(nla);
787 StringAttr parentName =
788 cast<InnerRefAttr>(nlaPath[nlaIdx - 1]).getModule();
790 if (isa<InnerRefAttr>(nlaPath[nlaIdx]))
794 LLVM_DEBUG(llvm::dbgs()
795 <<
" - Replacing " << nlaPath[nlaIdx - 1] <<
" and "
796 << nlaPath[nlaIdx] <<
" with " << newRef <<
"\n");
797 nlaPath[nlaIdx] = newRef;
798 nlaPath.erase(nlaPath.begin() + nlaIdx - 1);
800 if (isa<FlatSymbolRefAttr>(newRef)) {
805 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
806 nlaTable.addNLA(newNla);
807 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
808 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
811 newInstNonlocalAnnos.push_back(anno);
814 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
815 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
816 for (
auto anno : instNonlocalAnnos.lookup(nla))
817 newInstNonlocalAnnos.push_back(anno);
825 newInstAnnos.addAnnotations(newInstNonlocalAnnos);
826 newInstAnnos.applyToOperation(newInst);
830 extractionWorklist.push_back({newInst, info});
831 LLVM_DEBUG(llvm::dbgs() <<
" - Updated to " << newInst <<
"\n");
834 instanceGraph->replaceInstance(oldParentInst, newParentInst);
835 oldParentInst.erase();
840 nlaTable.removeNLAsfromModule(instanceNLAs, parent.getNameAttr());
848 for (Operation *op : nlasToRemove) {
849 LLVM_DEBUG(llvm::dbgs() <<
"Removing obsolete " << *op <<
"\n");
857 void ExtractInstancesPass::groupInstances() {
862 llvm::MapVector<std::pair<Operation *, StringRef>, SmallVector<InstanceOp>>
864 for (
auto &[inst, info] : extractedInstances) {
865 if (!info.wrapperModule.empty())
866 instsByWrapper[{inst->getParentOfType<FModuleOp>(), info.wrapperModule}]
869 if (instsByWrapper.empty())
871 LLVM_DEBUG(llvm::dbgs() <<
"\nGrouping instances into wrappers\n");
874 SmallVector<PortInfo> ports;
875 auto &nlaTable = getAnalysis<NLATable>();
877 for (
auto &[parentAndWrapperName, insts] : instsByWrapper) {
878 auto [parentOp, wrapperName] = parentAndWrapperName;
879 auto parent = cast<FModuleOp>(parentOp);
880 LLVM_DEBUG(llvm::dbgs() <<
"- Wrapper `" << wrapperName <<
"` in `"
881 << parent.getModuleName() <<
"` with "
882 << insts.size() <<
" instances\n");
883 OpBuilder builder(parentOp);
886 auto wrapperModuleName = builder.getStringAttr(
887 circuitNamespace.newName(dutPrefix + wrapperName));
888 auto wrapperInstName =
889 builder.getStringAttr(getModuleNamespace(parent).newName(wrapperName));
896 for (
auto inst : insts) {
898 StringRef prefix(instPrefices[inst]);
899 unsigned portNum = inst.getNumResults();
900 for (
unsigned portIdx = 0; portIdx < portNum; ++portIdx) {
901 auto name = inst.getPortNameStr(portIdx);
902 auto nameAttr = builder.getStringAttr(
903 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
905 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
906 inst.getPortDirection(portIdx)};
907 port.
loc = inst.getResult(portIdx).getLoc();
908 ports.push_back(port);
912 DenseSet<hw::HierPathOp> instNlas;
914 nlaTable.getInstanceNLAs(inst, instNlas);
918 for (
auto anno : instAnnos) {
919 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
922 hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr());
924 instNlas.insert(nla);
926 for (
auto nla : instNlas) {
927 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
931 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
932 nla.getNamepath().end());
934 assert(nlaIdx < nlaPath.size() &&
"instance not found in its own NLA");
935 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
942 if (
auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx]))
946 LLVM_DEBUG(llvm::dbgs() <<
" - Expanding " << nlaPath[nlaIdx]
947 <<
" to (" << ref1 <<
", " << ref2 <<
")\n");
948 nlaPath[nlaIdx] = ref1;
949 nlaPath.insert(nlaPath.begin() + nlaIdx + 1, ref2);
953 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
954 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
956 nlaTable.addNLAtoModule(nla, wrapperModuleName);
961 auto wrapper = builder.create<FModuleOp>(
962 builder.getUnknownLoc(), wrapperModuleName,
964 SymbolTable::setSymbolVisibility(wrapper, SymbolTable::Visibility::Private);
969 builder.setInsertionPointToStart(parent.getBodyBlock());
970 auto wrapperInst = builder.create<InstanceOp>(
971 wrapper.getLoc(), wrapper, wrapperName, NameKindEnum::DroppableName,
972 ArrayRef<Attribute>{},
973 ArrayRef<Attribute>{},
false,
975 unsigned portIdx = 0;
976 for (
auto inst : insts)
977 for (
auto result : inst.getResults())
978 result.replaceAllUsesWith(wrapperInst.getResult(portIdx++));
983 builder.setInsertionPointToStart(wrapper.getBodyBlock());
984 for (
auto inst : insts) {
986 builder.insert(inst);
987 for (
auto result : inst.getResults()) {
989 Value src = wrapper.getArgument(portIdx);
992 builder.create<MatchingConnectOp>(result.getLoc(), dst, src);
1002 void ExtractInstancesPass::createTraceFiles() {
1003 LLVM_DEBUG(llvm::dbgs() <<
"\nGenerating trace files\n");
1007 for (
auto &[inst, info] : extractedInstances)
1008 if (!info.traceFilename.empty())
1009 instsByTraceFile[info.traceFilename].push_back(inst);
1012 SmallVector<Attribute> symbols;
1015 for (
auto &[fileName, insts] : instsByTraceFile) {
1016 LLVM_DEBUG(llvm::dbgs() <<
"- " << fileName <<
"\n");
1018 llvm::raw_string_ostream os(buffer);
1020 symbolIndices.clear();
1022 auto addSymbol = [&](Attribute symbol) {
1024 auto it = symbolIndices.find(symbol);
1025 if (it != symbolIndices.end()) {
1028 id = symbols.size();
1029 symbols.push_back(symbol);
1030 symbolIndices.insert({symbol,
id});
1032 os <<
"{{" <<
id <<
"}}";
1035 auto file = getOrCreateFile(fileName);
1036 auto builder = OpBuilder::atBlockEnd(file.getBody());
1037 for (
auto inst : insts) {
1038 StringRef prefix(instPrefices[inst]);
1039 if (prefix.empty()) {
1040 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1041 <<
"` since it has no extraction prefix\n");
1044 ArrayRef<InnerRefAttr> path(extractionPaths[inst]);
1046 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1047 <<
"` since it has not been moved\n");
1050 LLVM_DEBUG(llvm::dbgs()
1051 <<
" - " << prefix <<
": " << inst.getName() <<
"\n");
1052 os << prefix <<
" -> ";
1057 while (!path.empty() &&
1058 !dutModuleNames.contains(path.back().getModule())) {
1059 LLVM_DEBUG(llvm::dbgs()
1060 <<
" - Dropping non-DUT segment " << path.back() <<
"\n");
1061 path = path.drop_back();
1067 ? originalInstanceParents[inst]
1068 : path.back().getModule()));
1069 for (
auto sym : llvm::reverse(path)) {
1080 builder.create<sv::VerbatimOp>(builder.getUnknownLoc(), buffer,
1081 ValueRange{}, builder.getArrayAttr(symbols));
1090 return std::make_unique<ExtractInstancesPass>();
assert(baseType &&"element must be base type")
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Block * getBodyBlock(FModuleLike mod)
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.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
The namespace of a CircuitOp, generally inhabited by modules.
This holds the name and type that describes the module's ports.