29 #include "mlir/IR/Attributes.h"
30 #include "mlir/IR/ImplicitLocOpBuilder.h"
31 #include "mlir/Support/FileUtilities.h"
32 #include "llvm/ADT/SmallPtrSet.h"
33 #include "llvm/Support/Debug.h"
34 #include "llvm/Support/MemoryBuffer.h"
35 #include "llvm/Support/Path.h"
37 #define DEBUG_TYPE "firrtl-extract-instances"
39 using namespace circt;
40 using namespace firrtl;
41 using hw::InnerRefAttr;
49 struct ExtractionInfo {
51 StringRef traceFilename;
55 StringRef wrapperModule;
61 struct ExtractInstancesPass
62 :
public ExtractInstancesBase<ExtractInstancesPass> {
63 void runOnOperation()
override;
65 void collectAnno(InstanceOp inst,
Annotation anno);
66 void extractInstances();
67 void groupInstances();
68 void createTraceFiles();
71 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
72 return moduleNamespaces.try_emplace(module, module).first->second;
79 [&](FModuleLike mod) -> hw::InnerSymbolNamespace & {
80 return getModuleNamespace(mod);
85 hw::HierPathOp cloneWithNewNameAndPath(hw::HierPathOp pathOp,
86 ArrayRef<Attribute> newPath) {
88 auto newPathOp =
builder.cloneWithoutRegions(pathOp);
89 newPathOp.setSymNameAttr(
builder.getStringAttr(
90 circuitNamespace.newName(newPathOp.getSymName())));
91 newPathOp.setNamepathAttr(
builder.getArrayAttr(newPath));
96 emit::FileOp getOrCreateFile(StringRef fileName) {
97 auto [it, inserted] = files.try_emplace(fileName, emit::FileOp{});
99 auto builder = ImplicitLocOpBuilder::atBlockEnd(
101 it->second =
builder.create<emit::FileOp>(fileName);
106 bool anythingChanged;
113 DenseMap<Operation *, SmallVector<Annotation, 1>> annotatedModules;
117 DenseSet<Operation *> dutRootModules;
120 DenseSet<Operation *> dutModules;
122 DenseSet<Attribute> dutModuleNames;
125 StringRef dutPrefix =
"";
128 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractionWorklist;
131 DenseMap<StringRef, emit::FileOp> files;
137 DenseMap<Operation *, SmallVector<InnerRefAttr>> extractionPaths;
141 DenseMap<Operation *, StringAttr> originalInstanceParents;
145 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractedInstances;
148 DenseMap<Operation *, SmallString<16>> instPrefices;
153 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
158 void ExtractInstancesPass::runOnOperation() {
159 CircuitOp circuitOp = getOperation();
160 anythingChanged =
false;
162 annotatedModules.clear();
163 dutRootModules.clear();
165 dutModuleNames.clear();
167 extractionWorklist.clear();
169 extractionPaths.clear();
170 originalInstanceParents.clear();
171 extractedInstances.clear();
172 instPrefices.clear();
173 moduleNamespaces.clear();
174 circuitNamespace.clear();
175 circuitNamespace.add(circuitOp);
179 instanceGraph = &getAnalysis<InstanceGraph>();
182 return signalPassFailure();
187 return signalPassFailure();
192 return signalPassFailure();
197 return signalPassFailure();
200 LLVM_DEBUG(llvm::dbgs() <<
"\n");
201 if (!anythingChanged)
202 markAllAnalysesPreserved();
211 void ExtractInstancesPass::collectAnnos() {
212 CircuitOp circuit = getOperation();
215 StringRef clkgateFileName;
216 StringRef clkgateWrapperModule;
220 LLVM_DEBUG(llvm::dbgs()
221 <<
"Clock gate extraction config: " << anno.
getDict() <<
"\n");
222 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
223 auto groupAttr = anno.
getMember<StringAttr>(
"group");
225 circuit.emitError(
"missing `filename` attribute in `")
226 << anno.
getClass() <<
"` annotation";
231 if (!clkgateFileName.empty()) {
232 circuit.emitError(
"multiple `")
233 << anno.getClass() <<
"` annotations on circuit";
238 clkgateFileName = filenameAttr.getValue();
240 clkgateWrapperModule = groupAttr.getValue();
245 StringRef memoryFileName;
246 StringRef memoryWrapperModule;
250 LLVM_DEBUG(llvm::dbgs()
251 <<
"Memory extraction config: " << anno.
getDict() <<
"\n");
252 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
253 auto groupAttr = anno.
getMember<StringAttr>(
"group");
255 circuit.emitError(
"missing `filename` attribute in `")
256 << anno.
getClass() <<
"` annotation";
261 if (!memoryFileName.empty()) {
262 circuit.emitError(
"multiple `")
263 << anno.getClass() <<
"` annotations on circuit";
268 memoryFileName = filenameAttr.getValue();
270 memoryWrapperModule = groupAttr.getValue();
276 for (
auto module : circuit.getOps<FModuleLike>()) {
279 LLVM_DEBUG(llvm::dbgs()
280 <<
"Marking DUT `" << module.getModuleName() <<
"`\n");
281 dutRootModules.insert(module);
282 dutModules.insert(module);
283 if (auto prefix = anno.getMember<StringAttr>(
"prefix"))
289 LLVM_DEBUG(llvm::dbgs() <<
"Annotated module `" << module.getModuleName()
290 <<
"`:\n " << anno.
getDict() <<
"\n");
291 annotatedModules[module].push_back(anno);
297 circuit.walk([&](InstanceOp inst) {
298 SmallVector<Annotation, 1> instAnnos;
299 Operation *module = inst.getReferencedModule(*instanceGraph);
302 auto it = annotatedModules.find(module);
303 if (it != annotatedModules.end())
304 instAnnos.append(it->second);
310 LLVM_DEBUG(llvm::dbgs() <<
"Annotated instance `" << inst.getName()
311 <<
"`:\n " << anno.
getDict() <<
"\n");
312 instAnnos.push_back(anno);
317 if (instAnnos.empty())
321 if (instAnnos.size() > 1) {
322 auto d = inst.emitError(
"multiple extraction annotations on instance `")
323 << inst.getName() <<
"`";
324 d.attachNote(inst.getLoc()) <<
"instance has the following annotations, "
325 "but at most one is allowed:";
326 for (
auto anno : instAnnos)
327 d.attachNote(inst.getLoc()) << anno.
getDict();
333 collectAnno(inst, instAnnos[0]);
337 LLVM_DEBUG(llvm::dbgs() <<
"Marking DUT hierarchy\n");
338 SmallVector<InstanceGraphNode *> worklist;
339 for (Operation *op : dutModules)
341 instanceGraph->lookup(cast<igraph::ModuleOpInterface>(op)));
342 while (!worklist.empty()) {
343 auto *module = worklist.pop_back_val();
344 dutModuleNames.insert(module->getModule().getModuleNameAttr());
345 LLVM_DEBUG(llvm::dbgs()
346 <<
"- " << module->getModule().getModuleName() <<
"\n");
347 for (
auto *instRecord : *module) {
348 auto *target = instRecord->getTarget();
349 if (dutModules.insert(target->getModule()).second)
350 worklist.push_back(target);
358 if (!clkgateFileName.empty()) {
359 auto clkgateDefNameAttr =
StringAttr::get(&getContext(),
"EICG_wrapper");
360 for (
auto module : circuit.getOps<FExtModuleOp>()) {
361 if (module.getDefnameAttr() != clkgateDefNameAttr)
363 LLVM_DEBUG(llvm::dbgs()
364 <<
"Clock gate `" << module.getModuleName() <<
"`\n");
365 if (!dutModules.contains(module)) {
366 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
371 info.traceFilename = clkgateFileName;
372 info.prefix =
"clock_gate";
373 info.wrapperModule = clkgateWrapperModule;
374 info.stopAtDUT = !info.wrapperModule.empty();
375 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
376 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
377 LLVM_DEBUG(llvm::dbgs()
379 << inst->getParentOfType<FModuleLike>().getModuleName()
380 <<
"." << inst.getName() <<
"`\n");
381 extractionWorklist.push_back({inst, info});
390 if (!memoryFileName.empty()) {
394 getOrCreateFile(memoryFileName);
396 for (
auto module : circuit.getOps<FMemModuleOp>()) {
397 LLVM_DEBUG(llvm::dbgs() <<
"Memory `" << module.getModuleName() <<
"`\n");
398 if (!dutModules.contains(module)) {
399 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
404 info.traceFilename = memoryFileName;
405 info.prefix =
"mem_wiring";
406 info.wrapperModule = memoryWrapperModule;
407 info.stopAtDUT = !info.wrapperModule.empty();
408 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
409 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
410 LLVM_DEBUG(llvm::dbgs()
412 << inst->getParentOfType<FModuleLike>().getModuleName()
413 <<
"." << inst.getName() <<
"`\n");
414 extractionWorklist.push_back({inst, info});
423 void ExtractInstancesPass::collectAnno(InstanceOp inst,
Annotation anno) {
424 LLVM_DEBUG(llvm::dbgs() <<
"Processing instance `" << inst.getName() <<
"` "
427 auto getStringOrError = [&](StringRef member) {
428 auto attr = anno.
getMember<StringAttr>(member);
430 inst.emitError(
"missing `")
431 << member <<
"` attribute in `" << anno.
getClass() <<
"` annotation";
438 auto filename = getStringOrError(
"filename");
439 auto prefix = getStringOrError(
"prefix");
440 auto dest = anno.
getMember<StringAttr>(
"dest");
445 info.traceFilename = filename;
446 info.prefix = prefix;
447 info.wrapperModule = (dest ? dest.getValue() :
"");
452 info.stopAtDUT = !info.wrapperModule.empty();
454 extractionWorklist.push_back({inst, info});
464 unsigned nlaLen = nla.getNamepath().size();
466 auto parentName = cast<FModuleOp>(inst->getParentOp()).getModuleNameAttr();
467 for (
unsigned nlaIdx = 0; nlaIdx < nlaLen; ++nlaIdx) {
468 auto refPart = nla.refPart(nlaIdx);
469 if (nla.modPart(nlaIdx) == parentName && (!refPart || refPart == instName))
478 void ExtractInstancesPass::extractInstances() {
481 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
483 DenseMap<StringRef, unsigned> prefixUniqueIDs;
485 SmallPtrSet<Operation *, 4> nlasToRemove;
487 auto &nlaTable = getAnalysis<NLATable>();
490 for (
auto &[inst, info] : extractionWorklist)
491 originalInstanceParents[inst] =
492 inst->getParentOfType<FModuleLike>().getModuleNameAttr();
494 while (!extractionWorklist.empty()) {
497 std::tie(inst, info) = extractionWorklist.pop_back_val();
498 auto parent = inst->getParentOfType<FModuleOp>();
507 if (!info.prefix.empty()) {
508 auto &prefixSlot = instPrefices[inst];
509 if (prefixSlot.empty()) {
510 auto idx = prefixUniqueIDs[info.prefix]++;
511 (Twine(info.prefix) +
"_" + Twine(idx)).
toVector(prefixSlot);
520 if (!dutModules.contains(parent) ||
521 instanceGraph->lookup(parent)->noUses() ||
522 (info.stopAtDUT && dutRootModules.contains(parent))) {
523 LLVM_DEBUG(llvm::dbgs() <<
"\nNo need to further move " << inst <<
"\n");
524 extractedInstances.push_back({inst, info});
528 llvm::dbgs() <<
"\nMoving ";
530 llvm::dbgs() <<
"`" << prefix <<
"` ";
531 llvm::dbgs() << inst <<
"\n";
536 unsigned numParentPorts = parent.getNumPorts();
537 unsigned numInstPorts = inst.getNumResults();
539 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
542 auto name = inst.getPortNameStr(portIdx);
545 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
548 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
550 newPort.loc = inst.getResult(portIdx).getLoc();
551 newPorts.push_back({numParentPorts, newPort});
552 LLVM_DEBUG(llvm::dbgs()
553 <<
"- Adding port " << newPort.direction <<
" "
554 << newPort.name.getValue() <<
": " << newPort.type <<
"\n");
556 parent.insertPorts(newPorts);
557 anythingChanged =
true;
561 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
562 inst.getResult(portIdx).replaceAllUsesWith(
563 parent.getArgument(numParentPorts + portIdx));
565 assert(inst.use_empty() &&
"instance ports should have been detached");
566 DenseSet<hw::HierPathOp> instanceNLAs;
569 nlaTable.getInstanceNLAs(inst, instanceNLAs);
572 DenseMap<hw::HierPathOp, SmallVector<Annotation>> instNonlocalAnnos;
575 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
579 if (hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr())) {
580 instNonlocalAnnos[nla].push_back(anno);
581 instanceNLAs.insert(nla);
588 SmallVector<hw::HierPathOp> sortedInstanceNLAs(instanceNLAs.begin(),
590 llvm::sort(sortedInstanceNLAs,
591 [](
auto a,
auto b) {
return a.getSymName() < b.getSymName(); });
596 auto *instParentNode =
597 instanceGraph->lookup(cast<igraph::ModuleOpInterface>(*parent));
598 for (
auto *instRecord : instParentNode->uses()) {
599 auto oldParentInst = cast<InstanceOp>(*instRecord->getInstance());
600 auto newParent = oldParentInst->getParentOfType<FModuleLike>();
601 LLVM_DEBUG(llvm::dbgs() <<
"- Updating " << oldParentInst <<
"\n");
602 auto newParentInst = oldParentInst.cloneAndInsertPorts(newPorts);
605 for (
unsigned portIdx = 0; portIdx < numParentPorts; ++portIdx)
606 oldParentInst.getResult(portIdx).replaceAllUsesWith(
607 newParentInst.getResult(portIdx));
611 auto newInst = inst.cloneAndInsertPorts({});
618 getModuleNamespace(newParent).newName(instSym.getValue());
619 if (newName != instSym.getValue())
620 newInst.setInnerSymAttr(
625 ImplicitLocOpBuilder
builder(inst.getLoc(), newParentInst);
626 builder.setInsertionPointAfter(newParentInst);
628 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
629 auto dst = newInst.getResult(portIdx);
630 auto src = newParentInst.getResult(numParentPorts + portIdx);
633 builder.create<StrictConnectOp>(dst, src);
642 auto oldPrefix = instPrefices.find(inst);
643 if (oldPrefix != instPrefices.end()) {
644 LLVM_DEBUG(llvm::dbgs()
645 <<
" - Reusing prefix `" << oldPrefix->second <<
"`\n");
646 auto newPrefix = std::move(oldPrefix->second);
647 instPrefices.erase(oldPrefix);
648 instPrefices.insert({newInst, newPrefix});
652 extractionPaths.try_emplace(newInst);
653 auto &extractionPath = (extractionPaths[newInst] = extractionPaths[inst]);
655 originalInstanceParents.try_emplace(newInst);
656 originalInstanceParents[newInst] = originalInstanceParents[inst];
659 SmallVector<Annotation> newInstNonlocalAnnos;
662 for (
auto nla : sortedInstanceNLAs) {
663 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
667 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
668 nla.getNamepath().end());
677 if (nlaIdx >= nlaPath.size()) {
678 LLVM_DEBUG(llvm::dbgs() <<
" - Instance no longer in path\n");
681 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
688 auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx - 1]);
690 !(innerRef.getModule() == newParent.getModuleNameAttr() &&
692 LLVM_DEBUG(llvm::dbgs()
693 <<
" - Ignored since NLA parent " << innerRef
694 <<
" does not pass through extraction parent\n");
712 LLVM_DEBUG(llvm::dbgs() <<
" - Re-rooting " << nlaPath[0] <<
"\n");
713 assert(isa<InnerRefAttr>(nlaPath[0]) &&
714 "head of hierpath must be an InnerRefAttr");
718 if (instParentNode->hasOneUse()) {
723 nla.setNamepathAttr(
builder.getArrayAttr(nlaPath));
724 for (
auto anno : instNonlocalAnnos.lookup(nla))
725 newInstNonlocalAnnos.push_back(anno);
726 nlaTable.addNLA(nla);
727 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
731 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
732 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
735 newInstNonlocalAnnos.push_back(anno);
738 nlaTable.addNLA(newNla);
739 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
749 inst.emitWarning(
"extraction of instance `")
750 << inst.getInstanceName()
751 <<
"` could break non-local annotations rooted at `"
752 << parent.getModuleName() <<
"`";
763 if (nlaPath.size() == 2) {
764 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
766 newInstNonlocalAnnos.push_back(anno);
767 LLVM_DEBUG(llvm::dbgs() <<
" - Converted to local "
771 nlasToRemove.insert(nla);
779 StringAttr parentName =
780 cast<InnerRefAttr>(nlaPath[nlaIdx - 1]).getModule();
782 if (isa<InnerRefAttr>(nlaPath[nlaIdx]))
786 LLVM_DEBUG(llvm::dbgs()
787 <<
" - Replacing " << nlaPath[nlaIdx - 1] <<
" and "
788 << nlaPath[nlaIdx] <<
" with " << newRef <<
"\n");
789 nlaPath[nlaIdx] = newRef;
790 nlaPath.erase(nlaPath.begin() + nlaIdx - 1);
792 if (isa<FlatSymbolRefAttr>(newRef)) {
797 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
798 nlaTable.addNLA(newNla);
799 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
800 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
803 newInstNonlocalAnnos.push_back(anno);
806 nla.setNamepathAttr(
builder.getArrayAttr(nlaPath));
807 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
808 for (
auto anno : instNonlocalAnnos.lookup(nla))
809 newInstNonlocalAnnos.push_back(anno);
817 newInstAnnos.addAnnotations(newInstNonlocalAnnos);
818 newInstAnnos.applyToOperation(newInst);
822 extractionWorklist.push_back({newInst, info});
823 LLVM_DEBUG(llvm::dbgs() <<
" - Updated to " << newInst <<
"\n");
826 instanceGraph->replaceInstance(oldParentInst, newParentInst);
827 oldParentInst.erase();
832 nlaTable.removeNLAsfromModule(instanceNLAs, parent.getNameAttr());
840 for (Operation *op : nlasToRemove) {
841 LLVM_DEBUG(llvm::dbgs() <<
"Removing obsolete " << *op <<
"\n");
849 void ExtractInstancesPass::groupInstances() {
854 llvm::MapVector<std::pair<Operation *, StringRef>, SmallVector<InstanceOp>>
856 for (
auto &[inst, info] : extractedInstances) {
857 if (!info.wrapperModule.empty())
858 instsByWrapper[{inst->getParentOfType<FModuleOp>(), info.wrapperModule}]
861 if (instsByWrapper.empty())
863 LLVM_DEBUG(llvm::dbgs() <<
"\nGrouping instances into wrappers\n");
866 SmallVector<PortInfo> ports;
867 auto &nlaTable = getAnalysis<NLATable>();
869 for (
auto &[parentAndWrapperName, insts] : instsByWrapper) {
870 auto [parentOp, wrapperName] = parentAndWrapperName;
871 auto parent = cast<FModuleOp>(parentOp);
872 LLVM_DEBUG(llvm::dbgs() <<
"- Wrapper `" << wrapperName <<
"` in `"
873 << parent.getModuleName() <<
"` with "
874 << insts.size() <<
" instances\n");
878 auto wrapperModuleName =
builder.getStringAttr(
879 circuitNamespace.newName(dutPrefix + wrapperName));
880 auto wrapperInstName =
881 builder.getStringAttr(getModuleNamespace(parent).newName(wrapperName));
888 for (
auto inst : insts) {
890 StringRef prefix(instPrefices[inst]);
891 unsigned portNum = inst.getNumResults();
892 for (
unsigned portIdx = 0; portIdx < portNum; ++portIdx) {
893 auto name = inst.getPortNameStr(portIdx);
894 auto nameAttr =
builder.getStringAttr(
895 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
897 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
898 inst.getPortDirection(portIdx)};
899 port.
loc = inst.getResult(portIdx).getLoc();
900 ports.push_back(port);
904 DenseSet<hw::HierPathOp> instNlas;
906 nlaTable.getInstanceNLAs(inst, instNlas);
910 for (
auto anno : instAnnos) {
911 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
914 hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr());
916 instNlas.insert(nla);
918 for (
auto nla : instNlas) {
919 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
923 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
924 nla.getNamepath().end());
926 assert(nlaIdx < nlaPath.size() &&
"instance not found in its own NLA");
927 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
934 if (
auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx]))
938 LLVM_DEBUG(llvm::dbgs() <<
" - Expanding " << nlaPath[nlaIdx]
939 <<
" to (" << ref1 <<
", " << ref2 <<
")\n");
940 nlaPath[nlaIdx] = ref1;
941 nlaPath.insert(nlaPath.begin() + nlaIdx + 1, ref2);
945 nla.setNamepathAttr(
builder.getArrayAttr(nlaPath));
946 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
948 nlaTable.addNLAtoModule(nla, wrapperModuleName);
953 auto wrapper =
builder.create<FModuleOp>(
954 builder.getUnknownLoc(), wrapperModuleName,
956 SymbolTable::setSymbolVisibility(wrapper, SymbolTable::Visibility::Private);
961 builder.setInsertionPointToStart(parent.getBodyBlock());
962 auto wrapperInst =
builder.create<InstanceOp>(
963 wrapper.getLoc(), wrapper, wrapperName, NameKindEnum::DroppableName,
964 ArrayRef<Attribute>{},
965 ArrayRef<Attribute>{},
false,
967 unsigned portIdx = 0;
968 for (
auto inst : insts)
969 for (
auto result : inst.getResults())
970 result.replaceAllUsesWith(wrapperInst.getResult(portIdx++));
975 builder.setInsertionPointToStart(wrapper.getBodyBlock());
976 for (
auto inst : insts) {
979 for (
auto result : inst.getResults()) {
981 Value src = wrapper.getArgument(portIdx);
984 builder.create<StrictConnectOp>(result.getLoc(), dst, src);
994 void ExtractInstancesPass::createTraceFiles() {
995 LLVM_DEBUG(llvm::dbgs() <<
"\nGenerating trace files\n");
999 for (
auto &[inst, info] : extractedInstances)
1000 if (!info.traceFilename.empty())
1001 instsByTraceFile[info.traceFilename].push_back(inst);
1004 SmallVector<Attribute> symbols;
1007 for (
auto &[fileName, insts] : instsByTraceFile) {
1008 LLVM_DEBUG(llvm::dbgs() <<
"- " << fileName <<
"\n");
1010 llvm::raw_string_ostream os(buffer);
1012 symbolIndices.clear();
1014 auto addSymbol = [&](Attribute symbol) {
1016 auto it = symbolIndices.find(symbol);
1017 if (it != symbolIndices.end()) {
1020 id = symbols.size();
1021 symbols.push_back(symbol);
1022 symbolIndices.insert({symbol,
id});
1024 os <<
"{{" <<
id <<
"}}";
1027 auto file = getOrCreateFile(fileName);
1028 auto builder = OpBuilder::atBlockEnd(file.getBody());
1029 for (
auto inst : insts) {
1030 StringRef prefix(instPrefices[inst]);
1031 if (prefix.empty()) {
1032 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1033 <<
"` since it has no extraction prefix\n");
1036 ArrayRef<InnerRefAttr> path(extractionPaths[inst]);
1038 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1039 <<
"` since it has not been moved\n");
1042 LLVM_DEBUG(llvm::dbgs()
1043 <<
" - " << prefix <<
": " << inst.getName() <<
"\n");
1044 os << prefix <<
" -> ";
1049 while (!path.empty() &&
1050 !dutModuleNames.contains(path.back().getModule())) {
1051 LLVM_DEBUG(llvm::dbgs()
1052 <<
" - Dropping non-DUT segment " << path.back() <<
"\n");
1053 path = path.drop_back();
1059 ? originalInstanceParents[inst]
1060 : path.back().getModule()));
1061 for (
auto sym : llvm::reverse(path)) {
1073 ValueRange{},
builder.getArrayAttr(symbols));
1082 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.
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.