40 #include "mlir/IR/Attributes.h"
41 #include "mlir/IR/ImplicitLocOpBuilder.h"
42 #include "mlir/Pass/Pass.h"
43 #include "mlir/Support/FileUtilities.h"
44 #include "llvm/ADT/SmallPtrSet.h"
45 #include "llvm/Support/Debug.h"
46 #include "llvm/Support/MemoryBuffer.h"
47 #include "llvm/Support/Path.h"
49 #define DEBUG_TYPE "firrtl-extract-instances"
53 #define GEN_PASS_DEF_EXTRACTINSTANCES
54 #include "circt/Dialect/FIRRTL/Passes.h.inc"
58 using namespace circt;
59 using namespace firrtl;
60 using hw::InnerRefAttr;
68 struct ExtractionInfo {
70 StringRef traceFilename;
74 StringRef wrapperModule;
80 struct ExtractInstancesPass
81 :
public circt::firrtl::impl::ExtractInstancesBase<ExtractInstancesPass> {
82 void runOnOperation()
override;
84 void collectAnno(InstanceOp inst,
Annotation anno);
85 void extractInstances();
86 void groupInstances();
87 void createTraceFiles(ClassOp &sifiveMetadata);
91 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
92 return moduleNamespaces.try_emplace(module, module).first->second;
99 [&](FModuleLike mod) -> hw::InnerSymbolNamespace & {
100 return getModuleNamespace(mod);
105 hw::HierPathOp cloneWithNewNameAndPath(hw::HierPathOp pathOp,
106 ArrayRef<Attribute> newPath) {
107 OpBuilder builder(pathOp);
108 auto newPathOp = builder.cloneWithoutRegions(pathOp);
109 newPathOp.setSymNameAttr(builder.getStringAttr(
110 circuitNamespace.newName(newPathOp.getSymName())));
111 newPathOp.setNamepathAttr(builder.getArrayAttr(newPath));
116 emit::FileOp getOrCreateFile(StringRef fileName) {
117 auto [it, inserted] = files.try_emplace(fileName, emit::FileOp{});
119 auto builder = ImplicitLocOpBuilder::atBlockEnd(
121 it->second = builder.create<emit::FileOp>(fileName);
126 bool anythingChanged;
132 SymbolTable *symbolTable =
nullptr;
136 DenseMap<Operation *, SmallVector<Annotation, 1>> annotatedModules;
140 StringRef dutPrefix =
"";
143 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractionWorklist;
146 DenseMap<StringRef, emit::FileOp> files;
152 DenseMap<Operation *, SmallVector<InnerRefAttr>> extractionPaths;
156 DenseMap<Operation *, StringAttr> originalInstanceParents;
160 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractedInstances;
163 DenseMap<Operation *, SmallString<16>> instPrefices;
168 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
170 ClassOp extractMetadataClass, schemaClass;
171 const unsigned prefixNameFieldId = 0, pathFieldId = 2, fileNameFieldId = 4;
174 DenseMap<InnerRefAttr, InstanceOp> innerRefToInstances;
179 void ExtractInstancesPass::runOnOperation() {
180 circuitOp = getOperation();
181 anythingChanged =
false;
183 annotatedModules.clear();
185 extractionWorklist.clear();
187 extractionPaths.clear();
188 originalInstanceParents.clear();
189 extractedInstances.clear();
190 instPrefices.clear();
191 moduleNamespaces.clear();
192 circuitNamespace.clear();
193 circuitNamespace.add(circuitOp);
194 innerRefToInstances.clear();
195 extractMetadataClass = {};
200 instanceGraph = &getAnalysis<InstanceGraph>();
201 instanceInfo = &getAnalysis<InstanceInfo>();
202 symbolTable = &getAnalysis<SymbolTable>();
205 return signalPassFailure();
210 return signalPassFailure();
215 return signalPassFailure();
217 ClassOp sifiveMetadata =
218 dyn_cast_or_null<ClassOp>(symbolTable->lookup(
"SiFive_Metadata"));
221 createTraceFiles(sifiveMetadata);
223 return signalPassFailure();
226 LLVM_DEBUG(llvm::dbgs() <<
"\n");
227 if (!anythingChanged)
228 markAllAnalysesPreserved();
237 void ExtractInstancesPass::collectAnnos() {
238 CircuitOp circuit = getOperation();
241 StringRef clkgateFileName;
242 StringRef clkgateWrapperModule;
246 LLVM_DEBUG(llvm::dbgs()
247 <<
"Clock gate extraction config: " << anno.
getDict() <<
"\n");
248 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
249 auto groupAttr = anno.
getMember<StringAttr>(
"group");
251 circuit.emitError(
"missing `filename` attribute in `")
252 << anno.
getClass() <<
"` annotation";
257 if (!clkgateFileName.empty()) {
258 circuit.emitError(
"multiple `")
259 << anno.getClass() <<
"` annotations on circuit";
264 clkgateFileName = filenameAttr.getValue();
266 clkgateWrapperModule = groupAttr.getValue();
271 StringRef memoryFileName;
272 StringRef memoryWrapperModule;
276 LLVM_DEBUG(llvm::dbgs()
277 <<
"Memory extraction config: " << anno.
getDict() <<
"\n");
278 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
279 auto groupAttr = anno.
getMember<StringAttr>(
"group");
281 circuit.emitError(
"missing `filename` attribute in `")
282 << anno.
getClass() <<
"` annotation";
287 if (!memoryFileName.empty()) {
288 circuit.emitError(
"multiple `")
289 << anno.getClass() <<
"` annotations on circuit";
294 memoryFileName = filenameAttr.getValue();
296 memoryWrapperModule = groupAttr.getValue();
302 for (
auto module : circuit.getOps<FModuleLike>()) {
305 LLVM_DEBUG(llvm::dbgs()
306 <<
"Marking DUT `" << module.getModuleName() <<
"`\n");
307 if (auto prefix = anno.getMember<StringAttr>(
"prefix"))
313 LLVM_DEBUG(llvm::dbgs() <<
"Annotated module `" << module.getModuleName()
314 <<
"`:\n " << anno.
getDict() <<
"\n");
315 annotatedModules[module].push_back(anno);
321 circuit.walk([&](InstanceOp inst) {
322 SmallVector<Annotation, 1> instAnnos;
323 Operation *module = inst.getReferencedModule(*instanceGraph);
326 auto it = annotatedModules.find(module);
327 if (it != annotatedModules.end())
328 instAnnos.append(it->second);
334 LLVM_DEBUG(llvm::dbgs() <<
"Annotated instance `" << inst.getName()
335 <<
"`:\n " << anno.
getDict() <<
"\n");
336 instAnnos.push_back(anno);
341 if (instAnnos.empty())
345 if (instAnnos.size() > 1) {
346 auto d = inst.emitError(
"multiple extraction annotations on instance `")
347 << inst.getName() <<
"`";
348 d.attachNote(inst.getLoc()) <<
"instance has the following annotations, "
349 "but at most one is allowed:";
350 for (
auto anno : instAnnos)
351 d.attachNote(inst.getLoc()) << anno.
getDict();
357 collectAnno(inst, instAnnos[0]);
364 if (!clkgateFileName.empty()) {
365 auto clkgateDefNameAttr =
StringAttr::get(&getContext(),
"EICG_wrapper");
366 for (
auto module : circuit.getOps<FExtModuleOp>()) {
367 if (module.getDefnameAttr() != clkgateDefNameAttr)
369 LLVM_DEBUG(llvm::dbgs()
370 <<
"Clock gate `" << module.getModuleName() <<
"`\n");
371 if (!instanceInfo->anyInstanceInDesign(module)) {
372 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
377 info.traceFilename = clkgateFileName;
378 info.prefix =
"clock_gate";
379 info.wrapperModule = clkgateWrapperModule;
380 info.stopAtDUT = !info.wrapperModule.empty();
381 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
382 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
383 LLVM_DEBUG(llvm::dbgs()
385 << inst->getParentOfType<FModuleLike>().getModuleName()
386 <<
"." << inst.getName() <<
"`\n");
387 extractionWorklist.push_back({inst, info});
396 if (!memoryFileName.empty()) {
400 getOrCreateFile(memoryFileName);
402 for (
auto module : circuit.getOps<FMemModuleOp>()) {
403 LLVM_DEBUG(llvm::dbgs() <<
"Memory `" << module.getModuleName() <<
"`\n");
404 if (!instanceInfo->anyInstanceInDesign(module)) {
405 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
410 info.traceFilename = memoryFileName;
411 info.prefix =
"mem_wiring";
412 info.wrapperModule = memoryWrapperModule;
413 info.stopAtDUT = !info.wrapperModule.empty();
414 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
415 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
416 LLVM_DEBUG(llvm::dbgs()
418 << inst->getParentOfType<FModuleLike>().getModuleName()
419 <<
"." << inst.getName() <<
"`\n");
420 extractionWorklist.push_back({inst, info});
429 void ExtractInstancesPass::collectAnno(InstanceOp inst,
Annotation anno) {
430 LLVM_DEBUG(llvm::dbgs() <<
"Processing instance `" << inst.getName() <<
"` "
433 auto getStringOrError = [&](StringRef member) {
434 auto attr = anno.
getMember<StringAttr>(member);
436 inst.emitError(
"missing `")
437 << member <<
"` attribute in `" << anno.
getClass() <<
"` annotation";
444 auto filename = getStringOrError(
"filename");
445 auto prefix = getStringOrError(
"prefix");
446 auto dest = anno.
getMember<StringAttr>(
"dest");
451 info.traceFilename = filename;
452 info.prefix = prefix;
453 info.wrapperModule = (dest ? dest.getValue() :
"");
458 info.stopAtDUT = !info.wrapperModule.empty();
460 extractionWorklist.push_back({inst, info});
470 unsigned nlaLen = nla.getNamepath().size();
472 auto parentName = cast<FModuleOp>(inst->getParentOp()).getModuleNameAttr();
473 for (
unsigned nlaIdx = 0; nlaIdx < nlaLen; ++nlaIdx) {
474 auto refPart = nla.refPart(nlaIdx);
475 if (nla.modPart(nlaIdx) == parentName && (!refPart || refPart == instName))
484 void ExtractInstancesPass::extractInstances() {
487 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
489 DenseMap<StringRef, unsigned> prefixUniqueIDs;
491 SmallPtrSet<Operation *, 4> nlasToRemove;
493 auto &nlaTable = getAnalysis<NLATable>();
496 for (
auto &[inst, info] : extractionWorklist)
497 originalInstanceParents[inst] =
498 inst->getParentOfType<FModuleLike>().getModuleNameAttr();
500 while (!extractionWorklist.empty()) {
503 std::tie(inst, info) = extractionWorklist.pop_back_val();
505 auto parent = inst->getParentOfType<FModuleOp>();
514 if (!info.prefix.empty()) {
515 auto &prefixSlot = instPrefices[inst];
516 if (prefixSlot.empty()) {
517 auto idx = prefixUniqueIDs[info.prefix]++;
518 (Twine(info.prefix) +
"_" + Twine(idx)).
toVector(prefixSlot);
527 if (inst->getParentOfType<LayerBlockOp>() ||
528 !instanceInfo->anyInstanceInDesign(parent) ||
529 instanceGraph->lookup(parent)->noUses() ||
530 (info.stopAtDUT && instanceInfo->isDut(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);
611 if (newParentInst.getInnerSymAttr())
612 innerRefToInstances[
getInnerRefTo(newParentInst)] = newParentInst;
615 for (
unsigned portIdx = 0; portIdx < numParentPorts; ++portIdx)
616 oldParentInst.getResult(portIdx).replaceAllUsesWith(
617 newParentInst.getResult(portIdx));
621 auto newInst = inst.cloneAndInsertPorts({});
628 getModuleNamespace(newParent).newName(instSym.getValue());
629 if (newName != instSym.getValue())
630 newInst.setInnerSymAttr(
635 ImplicitLocOpBuilder builder(inst.getLoc(), newParentInst);
636 builder.setInsertionPointAfter(newParentInst);
637 builder.insert(newInst);
638 if (newParentInst.getInnerSymAttr())
640 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
641 auto dst = newInst.getResult(portIdx);
642 auto src = newParentInst.getResult(numParentPorts + portIdx);
645 builder.create<MatchingConnectOp>(dst, src);
654 auto oldPrefix = instPrefices.find(inst);
655 if (oldPrefix != instPrefices.end()) {
656 LLVM_DEBUG(llvm::dbgs()
657 <<
" - Reusing prefix `" << oldPrefix->second <<
"`\n");
658 auto newPrefix = std::move(oldPrefix->second);
659 instPrefices.erase(oldPrefix);
660 instPrefices.insert({newInst, newPrefix});
664 extractionPaths.try_emplace(newInst);
665 auto &extractionPath = (extractionPaths[newInst] = extractionPaths[inst]);
667 innerRefToInstances[instInnerRef] = newParentInst;
668 extractionPath.push_back(instInnerRef);
669 originalInstanceParents.try_emplace(newInst);
670 originalInstanceParents[newInst] = originalInstanceParents[inst];
673 SmallVector<Annotation> newInstNonlocalAnnos;
676 for (
auto nla : sortedInstanceNLAs) {
677 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
681 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
682 nla.getNamepath().end());
691 if (nlaIdx >= nlaPath.size()) {
692 LLVM_DEBUG(llvm::dbgs() <<
" - Instance no longer in path\n");
695 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
702 auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx - 1]);
704 !(innerRef.getModule() == newParent.getModuleNameAttr() &&
706 LLVM_DEBUG(llvm::dbgs()
707 <<
" - Ignored since NLA parent " << innerRef
708 <<
" does not pass through extraction parent\n");
726 LLVM_DEBUG(llvm::dbgs() <<
" - Re-rooting " << nlaPath[0] <<
"\n");
727 assert(isa<InnerRefAttr>(nlaPath[0]) &&
728 "head of hierpath must be an InnerRefAttr");
732 if (instParentNode->hasOneUse()) {
737 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
738 for (
auto anno : instNonlocalAnnos.lookup(nla))
739 newInstNonlocalAnnos.push_back(anno);
740 nlaTable.addNLA(nla);
741 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
745 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
746 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
749 newInstNonlocalAnnos.push_back(anno);
752 nlaTable.addNLA(newNla);
753 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
763 inst.emitWarning(
"extraction of instance `")
764 << inst.getInstanceName()
765 <<
"` could break non-local annotations rooted at `"
766 << parent.getModuleName() <<
"`";
777 if (nlaPath.size() == 2) {
778 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
780 newInstNonlocalAnnos.push_back(anno);
781 LLVM_DEBUG(llvm::dbgs() <<
" - Converted to local "
785 nlasToRemove.insert(nla);
793 StringAttr parentName =
794 cast<InnerRefAttr>(nlaPath[nlaIdx - 1]).getModule();
796 if (isa<InnerRefAttr>(nlaPath[nlaIdx]))
800 LLVM_DEBUG(llvm::dbgs()
801 <<
" - Replacing " << nlaPath[nlaIdx - 1] <<
" and "
802 << nlaPath[nlaIdx] <<
" with " << newRef <<
"\n");
803 nlaPath[nlaIdx] = newRef;
804 nlaPath.erase(nlaPath.begin() + nlaIdx - 1);
806 if (isa<FlatSymbolRefAttr>(newRef)) {
811 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
812 nlaTable.addNLA(newNla);
813 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
814 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
817 newInstNonlocalAnnos.push_back(anno);
820 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
821 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
822 for (
auto anno : instNonlocalAnnos.lookup(nla))
823 newInstNonlocalAnnos.push_back(anno);
831 newInstAnnos.addAnnotations(newInstNonlocalAnnos);
832 newInstAnnos.applyToOperation(newInst);
836 extractionWorklist.push_back({newInst, info});
837 LLVM_DEBUG(llvm::dbgs() <<
" - Updated to " << newInst <<
"\n");
840 instanceGraph->replaceInstance(oldParentInst, newParentInst);
841 oldParentInst.erase();
846 nlaTable.removeNLAsfromModule(instanceNLAs, parent.getNameAttr());
854 for (Operation *op : nlasToRemove) {
855 LLVM_DEBUG(llvm::dbgs() <<
"Removing obsolete " << *op <<
"\n");
863 void ExtractInstancesPass::groupInstances() {
868 llvm::MapVector<std::pair<Operation *, StringRef>, SmallVector<InstanceOp>>
870 for (
auto &[inst, info] : extractedInstances) {
871 if (!info.wrapperModule.empty())
872 instsByWrapper[{inst->getParentOfType<FModuleOp>(), info.wrapperModule}]
875 if (instsByWrapper.empty())
877 LLVM_DEBUG(llvm::dbgs() <<
"\nGrouping instances into wrappers\n");
880 SmallVector<PortInfo> ports;
881 auto &nlaTable = getAnalysis<NLATable>();
883 for (
auto &[parentAndWrapperName, insts] : instsByWrapper) {
884 auto [parentOp, wrapperName] = parentAndWrapperName;
885 auto parent = cast<FModuleOp>(parentOp);
886 LLVM_DEBUG(llvm::dbgs() <<
"- Wrapper `" << wrapperName <<
"` in `"
887 << parent.getModuleName() <<
"` with "
888 << insts.size() <<
" instances\n");
889 OpBuilder builder(parentOp);
892 auto wrapperModuleName = builder.getStringAttr(
893 circuitNamespace.newName(dutPrefix + wrapperName));
894 auto wrapperInstName =
895 builder.getStringAttr(getModuleNamespace(parent).newName(wrapperName));
902 for (
auto inst : insts) {
904 StringRef prefix(instPrefices[inst]);
905 unsigned portNum = inst.getNumResults();
906 for (
unsigned portIdx = 0; portIdx < portNum; ++portIdx) {
907 auto name = inst.getPortNameStr(portIdx);
908 auto nameAttr = builder.getStringAttr(
909 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
911 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
912 inst.getPortDirection(portIdx)};
913 port.
loc = inst.getResult(portIdx).getLoc();
914 ports.push_back(port);
918 DenseSet<hw::HierPathOp> instNlas;
920 nlaTable.getInstanceNLAs(inst, instNlas);
924 for (
auto anno : instAnnos) {
925 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
928 hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr());
930 instNlas.insert(nla);
932 for (
auto nla : instNlas) {
933 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
937 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
938 nla.getNamepath().end());
940 assert(nlaIdx < nlaPath.size() &&
"instance not found in its own NLA");
941 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
948 if (
auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx]))
952 LLVM_DEBUG(llvm::dbgs() <<
" - Expanding " << nlaPath[nlaIdx]
953 <<
" to (" << ref1 <<
", " << ref2 <<
")\n");
954 nlaPath[nlaIdx] = ref1;
955 nlaPath.insert(nlaPath.begin() + nlaIdx + 1, ref2);
959 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
960 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
962 nlaTable.addNLAtoModule(nla, wrapperModuleName);
967 auto wrapper = builder.create<FModuleOp>(
968 builder.getUnknownLoc(), wrapperModuleName,
970 SymbolTable::setSymbolVisibility(wrapper, SymbolTable::Visibility::Private);
975 builder.setInsertionPointToStart(parent.getBodyBlock());
976 auto wrapperInst = builder.create<InstanceOp>(
977 wrapper.getLoc(), wrapper, wrapperName, NameKindEnum::DroppableName,
978 ArrayRef<Attribute>{},
979 ArrayRef<Attribute>{},
false,
981 unsigned portIdx = 0;
982 for (
auto inst : insts)
983 for (
auto result : inst.getResults())
984 result.replaceAllUsesWith(wrapperInst.getResult(portIdx++));
989 builder.setInsertionPointToStart(wrapper.getBodyBlock());
990 for (
auto inst : insts) {
992 builder.insert(inst);
993 for (
auto result : inst.getResults()) {
995 Value src = wrapper.getArgument(portIdx);
998 builder.create<MatchingConnectOp>(result.getLoc(), dst, src);
1008 void ExtractInstancesPass::createTraceFiles(ClassOp &sifiveMetadataClass) {
1009 LLVM_DEBUG(llvm::dbgs() <<
"\nGenerating trace files\n");
1012 llvm::MapVector<StringRef, SmallVector<InstanceOp>> instsByTraceFile;
1013 for (
auto &[inst, info] : extractedInstances)
1014 if (!info.traceFilename.empty())
1015 instsByTraceFile[info.traceFilename].push_back(inst);
1018 SmallVector<Attribute> symbols;
1020 if (sifiveMetadataClass && !extractMetadataClass)
1023 auto addPortsToClass = [&](ArrayRef<std::pair<Value, Twine>> objFields,
1025 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1026 classOp.getLoc(), classOp.getBodyBlock());
1027 auto portIndex = classOp.getNumPorts();
1028 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
1029 for (
auto [index, port] : enumerate(objFields)) {
1031 auto obj = port.first;
1032 newPorts.emplace_back(
1034 PortInfo(builderOM.getStringAttr(port.second + Twine(portIndex)),
1037 classOp.getBodyBlock()->addArgument(obj.getType(), obj.getLoc());
1038 builderOM.create<PropAssignOp>(blockarg, obj);
1040 classOp.insertPorts(newPorts);
1044 SmallVector<std::pair<Value, Twine>> classFields;
1045 for (
auto &[fileName, insts] : instsByTraceFile) {
1046 LLVM_DEBUG(llvm::dbgs() <<
"- " << fileName <<
"\n");
1048 llvm::raw_string_ostream os(buffer);
1050 symbolIndices.clear();
1052 auto addSymbol = [&](Attribute symbol) {
1054 auto it = symbolIndices.find(symbol);
1055 if (it != symbolIndices.end()) {
1058 id = symbols.size();
1059 symbols.push_back(symbol);
1060 symbolIndices.insert({symbol,
id});
1062 os <<
"{{" <<
id <<
"}}";
1065 auto file = getOrCreateFile(fileName);
1066 auto builder = OpBuilder::atBlockEnd(file.getBody());
1067 for (
auto inst : insts) {
1068 StringRef prefix(instPrefices[inst]);
1069 if (prefix.empty()) {
1070 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1071 <<
"` since it has no extraction prefix\n");
1074 ArrayRef<InnerRefAttr> path(extractionPaths[inst]);
1076 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1077 <<
"` since it has not been moved\n");
1080 LLVM_DEBUG(llvm::dbgs()
1081 <<
" - " << prefix <<
": " << inst.getName() <<
"\n");
1082 os << prefix <<
" -> ";
1084 if (sifiveMetadataClass) {
1086 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1087 inst.getLoc(), extractMetadataClass.getBodyBlock());
1088 auto prefixName = builderOM.create<StringConstantOp>(prefix);
1089 auto object = builderOM.create<ObjectOp>(schemaClass, prefix);
1091 builderOM.create<ObjectSubfieldOp>(object, prefixNameFieldId);
1092 builderOM.create<PropAssignOp>(fPrefix, prefixName);
1094 auto targetInstance = innerRefToInstances[path.front()];
1095 SmallVector<Attribute> pathOpAttr(llvm::reverse(path));
1096 auto nla = pathCache.getOpFor(
1099 auto pathOp =
createPathRef(targetInstance, nla, builderOM);
1100 auto fPath = builderOM.create<ObjectSubfieldOp>(object, pathFieldId);
1101 builderOM.create<PropAssignOp>(fPath, pathOp);
1103 builderOM.create<ObjectSubfieldOp>(object, fileNameFieldId);
1105 builderOM.create<StringConstantOp>(builder.getStringAttr(fileName));
1106 builderOM.create<PropAssignOp>(fFile, fileNameOp);
1109 classFields.emplace_back(
object, prefix +
"_field");
1114 while (!path.empty() &&
1115 !instanceInfo->anyInstanceInDesign(cast<igraph::ModuleOpInterface>(
1116 symbolTable->lookup(path.back().getModule())))) {
1117 LLVM_DEBUG(llvm::dbgs()
1118 <<
" - Dropping non-DUT segment " << path.back() <<
"\n");
1119 path = path.drop_back();
1125 ? originalInstanceParents[inst]
1126 : path.back().getModule()));
1127 for (
auto sym : llvm::reverse(path)) {
1138 builder.create<sv::VerbatimOp>(builder.getUnknownLoc(), buffer,
1139 ValueRange{}, builder.getArrayAttr(symbols));
1141 if (!classFields.empty()) {
1142 addPortsToClass(classFields, extractMetadataClass);
1146 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1147 sifiveMetadataClass->getLoc(), sifiveMetadataClass.getBodyBlock());
1148 SmallVector<std::pair<Value, Twine>> classFields = {
1149 {builderOM.create<ObjectOp>(
1150 extractMetadataClass,
1151 builderOM.getStringAttr(
"extract_instances_metadata")),
1152 "extractedInstances_field"}};
1154 addPortsToClass(classFields, sifiveMetadataClass);
1155 auto *node = instanceGraph->lookup(sifiveMetadataClass);
1156 assert(node && node->hasOneUse());
1157 ObjectOp metadataObj =
1158 dyn_cast_or_null<ObjectOp>((*node->usesBegin())->getInstance());
1160 "expected the class to be instantiated by an object op");
1161 builderOM.setInsertionPoint(metadataObj);
1163 builderOM.create<ObjectOp>(sifiveMetadataClass, metadataObj.getName());
1164 metadataObj->replaceAllUsesWith(newObj);
1165 metadataObj->remove();
1169 void ExtractInstancesPass::createSchema() {
1171 auto *context = circuitOp->getContext();
1173 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1174 unknownLoc, circuitOp.getBodyBlock());
1175 mlir::Type portsType[] = {
1180 StringRef portFields[] = {
"name",
"path",
"filename"};
1182 schemaClass = builderOM.create<ClassOp>(
"ExtractInstancesSchema", portFields,
1186 SmallVector<PortInfo> mports;
1187 extractMetadataClass = builderOM.create<ClassOp>(
1188 builderOM.getStringAttr(
"ExtractInstancesMetadata"), mports);
1195 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
PathOp createPathRef(Operation *op, hw::HierPathOp nla, mlir::ImplicitLocOpBuilder &builderOM)
Add the tracker annotation to the op and get a PathOp to the op.
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.
A cache of existing HierPathOps, mostly used to facilitate HierPathOp reuse.
This holds the name and type that describes the module's ports.