38 #include "mlir/IR/Attributes.h"
39 #include "mlir/IR/ImplicitLocOpBuilder.h"
40 #include "mlir/Pass/Pass.h"
41 #include "mlir/Support/FileUtilities.h"
42 #include "llvm/Support/Debug.h"
44 #define DEBUG_TYPE "firrtl-extract-instances"
48 #define GEN_PASS_DEF_EXTRACTINSTANCES
49 #include "circt/Dialect/FIRRTL/Passes.h.inc"
53 using namespace circt;
54 using namespace firrtl;
55 using hw::InnerRefAttr;
63 struct ExtractionInfo {
65 StringRef traceFilename;
69 StringRef wrapperModule;
75 struct ExtractInstancesPass
76 :
public circt::firrtl::impl::ExtractInstancesBase<ExtractInstancesPass> {
77 void runOnOperation()
override;
79 void collectAnno(InstanceOp inst,
Annotation anno);
80 void extractInstances();
81 void groupInstances();
82 void createTraceFiles(ClassOp &sifiveMetadata);
86 hw::InnerSymbolNamespace &getModuleNamespace(FModuleLike module) {
87 return moduleNamespaces.try_emplace(module, module).first->second;
94 [&](FModuleLike mod) -> hw::InnerSymbolNamespace & {
95 return getModuleNamespace(mod);
100 hw::HierPathOp cloneWithNewNameAndPath(hw::HierPathOp pathOp,
101 ArrayRef<Attribute> newPath) {
102 OpBuilder builder(pathOp);
103 auto newPathOp = builder.cloneWithoutRegions(pathOp);
104 newPathOp.setSymNameAttr(builder.getStringAttr(
105 circuitNamespace.newName(newPathOp.getSymName())));
106 newPathOp.setNamepathAttr(builder.getArrayAttr(newPath));
111 emit::FileOp getOrCreateFile(StringRef fileName) {
112 auto [it, inserted] = files.try_emplace(fileName, emit::FileOp{});
114 auto builder = ImplicitLocOpBuilder::atBlockEnd(
116 it->second = builder.create<emit::FileOp>(fileName);
121 bool anythingChanged;
127 SymbolTable *symbolTable =
nullptr;
131 DenseMap<Operation *, SmallVector<Annotation, 1>> annotatedModules;
134 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractionWorklist;
137 DenseMap<StringRef, emit::FileOp> files;
143 DenseMap<Operation *, SmallVector<InnerRefAttr>> extractionPaths;
147 DenseMap<Operation *, StringAttr> originalInstanceParents;
151 SmallVector<std::pair<InstanceOp, ExtractionInfo>> extractedInstances;
154 DenseMap<Operation *, SmallString<16>> instPrefices;
159 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
161 ClassOp extractMetadataClass, schemaClass;
162 const unsigned prefixNameFieldId = 0, pathFieldId = 2, fileNameFieldId = 4;
165 DenseMap<InnerRefAttr, InstanceOp> innerRefToInstances;
170 void ExtractInstancesPass::runOnOperation() {
171 circuitOp = getOperation();
172 anythingChanged =
false;
174 annotatedModules.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);
184 innerRefToInstances.clear();
185 extractMetadataClass = {};
190 instanceGraph = &getAnalysis<InstanceGraph>();
191 instanceInfo = &getAnalysis<InstanceInfo>();
192 symbolTable = &getAnalysis<SymbolTable>();
195 return signalPassFailure();
200 return signalPassFailure();
205 return signalPassFailure();
207 ClassOp sifiveMetadata =
208 dyn_cast_or_null<ClassOp>(symbolTable->lookup(
"SiFive_Metadata"));
211 createTraceFiles(sifiveMetadata);
213 return signalPassFailure();
216 LLVM_DEBUG(llvm::dbgs() <<
"\n");
217 if (!anythingChanged)
218 markAllAnalysesPreserved();
227 void ExtractInstancesPass::collectAnnos() {
228 CircuitOp circuit = getOperation();
231 StringRef clkgateFileName;
232 StringRef clkgateWrapperModule;
236 LLVM_DEBUG(llvm::dbgs()
237 <<
"Clock gate extraction config: " << anno.
getDict() <<
"\n");
238 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
239 auto groupAttr = anno.
getMember<StringAttr>(
"group");
241 circuit.emitError(
"missing `filename` attribute in `")
242 << anno.
getClass() <<
"` annotation";
247 if (!clkgateFileName.empty()) {
248 circuit.emitError(
"multiple `")
249 << anno.getClass() <<
"` annotations on circuit";
254 clkgateFileName = filenameAttr.getValue();
256 clkgateWrapperModule = groupAttr.getValue();
261 StringRef memoryFileName;
262 StringRef memoryWrapperModule;
266 LLVM_DEBUG(llvm::dbgs()
267 <<
"Memory extraction config: " << anno.
getDict() <<
"\n");
268 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
269 auto groupAttr = anno.
getMember<StringAttr>(
"group");
271 circuit.emitError(
"missing `filename` attribute in `")
272 << anno.
getClass() <<
"` annotation";
277 if (!memoryFileName.empty()) {
278 circuit.emitError(
"multiple `")
279 << anno.getClass() <<
"` annotations on circuit";
284 memoryFileName = filenameAttr.getValue();
286 memoryWrapperModule = groupAttr.getValue();
292 for (
auto module : circuit.getOps<FModuleLike>()) {
295 LLVM_DEBUG(llvm::dbgs()
296 <<
"Marking DUT `" << module.getModuleName() <<
"`\n");
301 LLVM_DEBUG(llvm::dbgs() <<
"Annotated module `" << module.getModuleName()
302 <<
"`:\n " << anno.
getDict() <<
"\n");
303 annotatedModules[module].push_back(anno);
309 circuit.walk([&](InstanceOp inst) {
310 SmallVector<Annotation, 1> instAnnos;
311 Operation *module = inst.getReferencedModule(*instanceGraph);
314 auto it = annotatedModules.find(module);
315 if (it != annotatedModules.end())
316 instAnnos.append(it->second);
322 LLVM_DEBUG(llvm::dbgs() <<
"Annotated instance `" << inst.getName()
323 <<
"`:\n " << anno.
getDict() <<
"\n");
324 instAnnos.push_back(anno);
329 if (instAnnos.empty())
333 if (instAnnos.size() > 1) {
334 auto d = inst.emitError(
"multiple extraction annotations on instance `")
335 << inst.getName() <<
"`";
336 d.attachNote(inst.getLoc()) <<
"instance has the following annotations, "
337 "but at most one is allowed:";
338 for (
auto anno : instAnnos)
339 d.attachNote(inst.getLoc()) << anno.
getDict();
345 collectAnno(inst, instAnnos[0]);
354 if (!clkgateFileName.empty()) {
355 for (
auto module : circuit.getOps<FExtModuleOp>()) {
356 if (!module.getDefnameAttr().getValue().ends_with(
"EICG_wrapper"))
358 LLVM_DEBUG(llvm::dbgs()
359 <<
"Clock gate `" << module.getModuleName() <<
"`\n");
360 if (!instanceInfo->anyInstanceInDesign(module)) {
361 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
366 info.traceFilename = clkgateFileName;
367 info.prefix =
"clock_gate";
368 info.wrapperModule = clkgateWrapperModule;
369 info.stopAtDUT = !info.wrapperModule.empty();
370 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
371 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
372 LLVM_DEBUG(llvm::dbgs()
374 << inst->getParentOfType<FModuleLike>().getModuleName()
375 <<
"." << inst.getName() <<
"`\n");
376 extractionWorklist.push_back({inst, info});
385 if (!memoryFileName.empty()) {
389 getOrCreateFile(memoryFileName);
391 for (
auto module : circuit.getOps<FMemModuleOp>()) {
392 LLVM_DEBUG(llvm::dbgs() <<
"Memory `" << module.getModuleName() <<
"`\n");
393 if (!instanceInfo->anyInstanceInDesign(module)) {
394 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
399 info.traceFilename = memoryFileName;
400 info.prefix =
"mem_wiring";
401 info.wrapperModule = memoryWrapperModule;
402 info.stopAtDUT = !info.wrapperModule.empty();
403 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
404 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
405 LLVM_DEBUG(llvm::dbgs()
407 << inst->getParentOfType<FModuleLike>().getModuleName()
408 <<
"." << inst.getName() <<
"`\n");
409 extractionWorklist.push_back({inst, info});
418 void ExtractInstancesPass::collectAnno(InstanceOp inst,
Annotation anno) {
419 LLVM_DEBUG(llvm::dbgs() <<
"Processing instance `" << inst.getName() <<
"` "
422 auto getStringOrError = [&](StringRef member) {
423 auto attr = anno.
getMember<StringAttr>(member);
425 inst.emitError(
"missing `")
426 << member <<
"` attribute in `" << anno.
getClass() <<
"` annotation";
433 auto filename = getStringOrError(
"filename");
434 auto prefix = getStringOrError(
"prefix");
435 auto dest = anno.
getMember<StringAttr>(
"dest");
440 info.traceFilename = filename;
441 info.prefix = prefix;
442 info.wrapperModule = (dest ? dest.getValue() :
"");
447 info.stopAtDUT = !info.wrapperModule.empty();
449 extractionWorklist.push_back({inst, info});
459 unsigned nlaLen = nla.getNamepath().size();
461 auto parentName = cast<FModuleOp>(inst->getParentOp()).getModuleNameAttr();
462 for (
unsigned nlaIdx = 0; nlaIdx < nlaLen; ++nlaIdx) {
463 auto refPart = nla.refPart(nlaIdx);
464 if (nla.modPart(nlaIdx) == parentName && (!refPart || refPart == instName))
473 void ExtractInstancesPass::extractInstances() {
476 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
478 DenseMap<StringRef, unsigned> prefixUniqueIDs;
480 SmallPtrSet<Operation *, 4> nlasToRemove;
482 auto &nlaTable = getAnalysis<NLATable>();
485 for (
auto &[inst, info] : extractionWorklist)
486 originalInstanceParents[inst] =
487 inst->getParentOfType<FModuleLike>().getModuleNameAttr();
489 while (!extractionWorklist.empty()) {
492 std::tie(inst, info) = extractionWorklist.pop_back_val();
494 auto parent = inst->getParentOfType<FModuleOp>();
503 if (!info.prefix.empty()) {
504 auto &prefixSlot = instPrefices[inst];
505 if (prefixSlot.empty()) {
506 auto idx = prefixUniqueIDs[info.prefix]++;
507 (Twine(info.prefix) +
"_" + Twine(idx)).
toVector(prefixSlot);
516 if (inst->getParentOfType<LayerBlockOp>() ||
517 !instanceInfo->anyInstanceInDesign(parent) ||
518 instanceGraph->lookup(parent)->noUses() ||
519 (info.stopAtDUT && instanceInfo->isDut(parent))) {
520 LLVM_DEBUG(llvm::dbgs() <<
"\nNo need to further move " << inst <<
"\n");
521 extractedInstances.push_back({inst, info});
525 llvm::dbgs() <<
"\nMoving ";
527 llvm::dbgs() <<
"`" << prefix <<
"` ";
528 llvm::dbgs() << inst <<
"\n";
533 unsigned numParentPorts = parent.getNumPorts();
534 unsigned numInstPorts = inst.getNumResults();
536 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
539 auto name = inst.getPortNameStr(portIdx);
542 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
545 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
547 newPort.loc = inst.getResult(portIdx).getLoc();
548 newPorts.push_back({numParentPorts, newPort});
549 LLVM_DEBUG(llvm::dbgs()
550 <<
"- Adding port " << newPort.direction <<
" "
551 << newPort.name.getValue() <<
": " << newPort.type <<
"\n");
553 parent.insertPorts(newPorts);
554 anythingChanged =
true;
558 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
559 inst.getResult(portIdx).replaceAllUsesWith(
560 parent.getArgument(numParentPorts + portIdx));
562 assert(inst.use_empty() &&
"instance ports should have been detached");
563 DenseSet<hw::HierPathOp> instanceNLAs;
566 nlaTable.getInstanceNLAs(inst, instanceNLAs);
569 DenseMap<hw::HierPathOp, SmallVector<Annotation>> instNonlocalAnnos;
572 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
576 if (hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr())) {
577 instNonlocalAnnos[nla].push_back(anno);
578 instanceNLAs.insert(nla);
585 SmallVector<hw::HierPathOp> sortedInstanceNLAs(instanceNLAs.begin(),
587 llvm::sort(sortedInstanceNLAs,
588 [](
auto a,
auto b) {
return a.getSymName() < b.getSymName(); });
593 auto *instParentNode =
594 instanceGraph->lookup(cast<igraph::ModuleOpInterface>(*parent));
595 for (
auto *instRecord : instParentNode->uses()) {
596 auto oldParentInst = cast<InstanceOp>(*instRecord->getInstance());
597 auto newParent = oldParentInst->getParentOfType<FModuleLike>();
598 LLVM_DEBUG(llvm::dbgs() <<
"- Updating " << oldParentInst <<
"\n");
599 auto newParentInst = oldParentInst.cloneAndInsertPorts(newPorts);
600 if (newParentInst.getInnerSymAttr())
601 innerRefToInstances[
getInnerRefTo(newParentInst)] = newParentInst;
604 for (
unsigned portIdx = 0; portIdx < numParentPorts; ++portIdx)
605 oldParentInst.getResult(portIdx).replaceAllUsesWith(
606 newParentInst.getResult(portIdx));
610 auto newInst = inst.cloneAndInsertPorts({});
617 getModuleNamespace(newParent).newName(instSym.getValue());
618 if (newName != instSym.getValue())
619 newInst.setInnerSymAttr(
624 ImplicitLocOpBuilder builder(inst.getLoc(), newParentInst);
625 builder.setInsertionPointAfter(newParentInst);
626 builder.insert(newInst);
627 if (newParentInst.getInnerSymAttr())
629 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
630 auto dst = newInst.getResult(portIdx);
631 auto src = newParentInst.getResult(numParentPorts + portIdx);
634 builder.create<MatchingConnectOp>(dst, src);
643 auto oldPrefix = instPrefices.find(inst);
644 if (oldPrefix != instPrefices.end()) {
645 LLVM_DEBUG(llvm::dbgs()
646 <<
" - Reusing prefix `" << oldPrefix->second <<
"`\n");
647 auto newPrefix = std::move(oldPrefix->second);
648 instPrefices.erase(oldPrefix);
649 instPrefices.insert({newInst, newPrefix});
653 extractionPaths.try_emplace(newInst);
654 auto &extractionPath = (extractionPaths[newInst] = extractionPaths[inst]);
656 innerRefToInstances[instInnerRef] = newParentInst;
657 extractionPath.push_back(instInnerRef);
658 originalInstanceParents.try_emplace(newInst);
659 originalInstanceParents[newInst] = originalInstanceParents[inst];
662 SmallVector<Annotation> newInstNonlocalAnnos;
665 for (
auto nla : sortedInstanceNLAs) {
666 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
670 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
671 nla.getNamepath().end());
680 if (nlaIdx >= nlaPath.size()) {
681 LLVM_DEBUG(llvm::dbgs() <<
" - Instance no longer in path\n");
684 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
691 auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx - 1]);
693 !(innerRef.getModule() == newParent.getModuleNameAttr() &&
695 LLVM_DEBUG(llvm::dbgs()
696 <<
" - Ignored since NLA parent " << innerRef
697 <<
" does not pass through extraction parent\n");
715 LLVM_DEBUG(llvm::dbgs() <<
" - Re-rooting " << nlaPath[0] <<
"\n");
716 assert(isa<InnerRefAttr>(nlaPath[0]) &&
717 "head of hierpath must be an InnerRefAttr");
721 if (instParentNode->hasOneUse()) {
726 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
727 for (
auto anno : instNonlocalAnnos.lookup(nla))
728 newInstNonlocalAnnos.push_back(anno);
729 nlaTable.addNLA(nla);
730 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
734 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
735 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
738 newInstNonlocalAnnos.push_back(anno);
741 nlaTable.addNLA(newNla);
742 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
752 inst.emitWarning(
"extraction of instance `")
753 << inst.getInstanceName()
754 <<
"` could break non-local annotations rooted at `"
755 << parent.getModuleName() <<
"`";
766 if (nlaPath.size() == 2) {
767 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
769 newInstNonlocalAnnos.push_back(anno);
770 LLVM_DEBUG(llvm::dbgs() <<
" - Converted to local "
774 nlasToRemove.insert(nla);
782 StringAttr parentName =
783 cast<InnerRefAttr>(nlaPath[nlaIdx - 1]).getModule();
785 if (isa<InnerRefAttr>(nlaPath[nlaIdx]))
789 LLVM_DEBUG(llvm::dbgs()
790 <<
" - Replacing " << nlaPath[nlaIdx - 1] <<
" and "
791 << nlaPath[nlaIdx] <<
" with " << newRef <<
"\n");
792 nlaPath[nlaIdx] = newRef;
793 nlaPath.erase(nlaPath.begin() + nlaIdx - 1);
795 if (isa<FlatSymbolRefAttr>(newRef)) {
800 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
801 nlaTable.addNLA(newNla);
802 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
803 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
806 newInstNonlocalAnnos.push_back(anno);
809 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
810 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
811 for (
auto anno : instNonlocalAnnos.lookup(nla))
812 newInstNonlocalAnnos.push_back(anno);
820 newInstAnnos.addAnnotations(newInstNonlocalAnnos);
821 newInstAnnos.applyToOperation(newInst);
825 extractionWorklist.push_back({newInst, info});
826 LLVM_DEBUG(llvm::dbgs() <<
" - Updated to " << newInst <<
"\n");
829 instanceGraph->replaceInstance(oldParentInst, newParentInst);
830 oldParentInst.erase();
835 nlaTable.removeNLAsfromModule(instanceNLAs, parent.getNameAttr());
843 for (Operation *op : nlasToRemove) {
844 LLVM_DEBUG(llvm::dbgs() <<
"Removing obsolete " << *op <<
"\n");
852 void ExtractInstancesPass::groupInstances() {
857 llvm::MapVector<std::pair<Operation *, StringRef>, SmallVector<InstanceOp>>
859 for (
auto &[inst, info] : extractedInstances) {
860 if (!info.wrapperModule.empty())
861 instsByWrapper[{inst->getParentOfType<FModuleOp>(), info.wrapperModule}]
864 if (instsByWrapper.empty())
866 LLVM_DEBUG(llvm::dbgs() <<
"\nGrouping instances into wrappers\n");
869 SmallVector<PortInfo> ports;
870 auto &nlaTable = getAnalysis<NLATable>();
872 for (
auto &[parentAndWrapperName, insts] : instsByWrapper) {
873 auto [parentOp, wrapperName] = parentAndWrapperName;
874 auto parent = cast<FModuleOp>(parentOp);
875 LLVM_DEBUG(llvm::dbgs() <<
"- Wrapper `" << wrapperName <<
"` in `"
876 << parent.getModuleName() <<
"` with "
877 << insts.size() <<
" instances\n");
878 OpBuilder builder(parentOp);
881 auto wrapperModuleName =
882 builder.getStringAttr(circuitNamespace.newName(wrapperName));
883 auto wrapperInstName =
884 builder.getStringAttr(getModuleNamespace(parent).newName(wrapperName));
891 for (
auto inst : insts) {
893 StringRef prefix(instPrefices[inst]);
894 unsigned portNum = inst.getNumResults();
895 for (
unsigned portIdx = 0; portIdx < portNum; ++portIdx) {
896 auto name = inst.getPortNameStr(portIdx);
897 auto nameAttr = builder.getStringAttr(
898 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
900 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
901 inst.getPortDirection(portIdx)};
902 port.
loc = inst.getResult(portIdx).getLoc();
903 ports.push_back(port);
907 DenseSet<hw::HierPathOp> instNlas;
909 nlaTable.getInstanceNLAs(inst, instNlas);
913 for (
auto anno : instAnnos) {
914 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
917 hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr());
919 instNlas.insert(nla);
921 for (
auto nla : instNlas) {
922 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
926 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
927 nla.getNamepath().end());
929 assert(nlaIdx < nlaPath.size() &&
"instance not found in its own NLA");
930 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
937 if (
auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx]))
941 LLVM_DEBUG(llvm::dbgs() <<
" - Expanding " << nlaPath[nlaIdx]
942 <<
" to (" << ref1 <<
", " << ref2 <<
")\n");
943 nlaPath[nlaIdx] = ref1;
944 nlaPath.insert(nlaPath.begin() + nlaIdx + 1, ref2);
948 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
949 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
951 nlaTable.addNLAtoModule(nla, wrapperModuleName);
956 auto wrapper = builder.create<FModuleOp>(
957 builder.getUnknownLoc(), wrapperModuleName,
959 SymbolTable::setSymbolVisibility(wrapper, SymbolTable::Visibility::Private);
964 builder.setInsertionPointToStart(parent.getBodyBlock());
965 auto wrapperInst = builder.create<InstanceOp>(
966 wrapper.getLoc(), wrapper, wrapperName, NameKindEnum::DroppableName,
967 ArrayRef<Attribute>{},
968 ArrayRef<Attribute>{},
false,
970 unsigned portIdx = 0;
971 for (
auto inst : insts)
972 for (
auto result : inst.getResults())
973 result.replaceAllUsesWith(wrapperInst.getResult(portIdx++));
978 builder.setInsertionPointToStart(wrapper.getBodyBlock());
979 for (
auto inst : insts) {
981 builder.insert(inst);
982 for (
auto result : inst.getResults()) {
984 Value src = wrapper.getArgument(portIdx);
987 builder.create<MatchingConnectOp>(result.getLoc(), dst, src);
997 void ExtractInstancesPass::createTraceFiles(ClassOp &sifiveMetadataClass) {
998 LLVM_DEBUG(llvm::dbgs() <<
"\nGenerating trace files\n");
1001 llvm::MapVector<StringRef, SmallVector<InstanceOp>> instsByTraceFile;
1002 for (
auto &[inst, info] : extractedInstances)
1003 if (!info.traceFilename.empty())
1004 instsByTraceFile[info.traceFilename].push_back(inst);
1007 SmallVector<Attribute> symbols;
1009 if (sifiveMetadataClass && !extractMetadataClass)
1012 auto addPortsToClass = [&](ArrayRef<std::pair<Value, Twine>> objFields,
1014 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1015 classOp.getLoc(), classOp.getBodyBlock());
1016 auto portIndex = classOp.getNumPorts();
1017 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
1018 for (
auto [index, port] : enumerate(objFields)) {
1020 auto obj = port.first;
1021 newPorts.emplace_back(
1023 PortInfo(builderOM.getStringAttr(port.second + Twine(portIndex)),
1026 classOp.getBodyBlock()->addArgument(obj.getType(), obj.getLoc());
1027 builderOM.create<PropAssignOp>(blockarg, obj);
1029 classOp.insertPorts(newPorts);
1033 SmallVector<std::pair<Value, Twine>> classFields;
1034 for (
auto &[fileName, insts] : instsByTraceFile) {
1035 LLVM_DEBUG(llvm::dbgs() <<
"- " << fileName <<
"\n");
1037 llvm::raw_string_ostream os(buffer);
1039 symbolIndices.clear();
1041 auto addSymbol = [&](Attribute symbol) {
1043 auto it = symbolIndices.find(symbol);
1044 if (it != symbolIndices.end()) {
1047 id = symbols.size();
1048 symbols.push_back(symbol);
1049 symbolIndices.insert({symbol,
id});
1051 os <<
"{{" <<
id <<
"}}";
1054 auto file = getOrCreateFile(fileName);
1055 auto builder = OpBuilder::atBlockEnd(file.getBody());
1056 for (
auto inst : insts) {
1057 StringRef prefix(instPrefices[inst]);
1058 if (prefix.empty()) {
1059 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1060 <<
"` since it has no extraction prefix\n");
1063 ArrayRef<InnerRefAttr> path(extractionPaths[inst]);
1065 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1066 <<
"` since it has not been moved\n");
1069 LLVM_DEBUG(llvm::dbgs()
1070 <<
" - " << prefix <<
": " << inst.getName() <<
"\n");
1071 os << prefix <<
" -> ";
1073 if (sifiveMetadataClass) {
1075 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1076 inst.getLoc(), extractMetadataClass.getBodyBlock());
1077 auto prefixName = builderOM.create<StringConstantOp>(prefix);
1078 auto object = builderOM.create<ObjectOp>(schemaClass, prefix);
1080 builderOM.create<ObjectSubfieldOp>(object, prefixNameFieldId);
1081 builderOM.create<PropAssignOp>(fPrefix, prefixName);
1083 auto targetInstance = innerRefToInstances[path.front()];
1084 SmallVector<Attribute> pathOpAttr(llvm::reverse(path));
1085 auto nla = pathCache.getOpFor(
1088 auto pathOp =
createPathRef(targetInstance, nla, builderOM);
1089 auto fPath = builderOM.create<ObjectSubfieldOp>(object, pathFieldId);
1090 builderOM.create<PropAssignOp>(fPath, pathOp);
1092 builderOM.create<ObjectSubfieldOp>(object, fileNameFieldId);
1094 builderOM.create<StringConstantOp>(builder.getStringAttr(fileName));
1095 builderOM.create<PropAssignOp>(fFile, fileNameOp);
1098 classFields.emplace_back(
object, prefix +
"_field");
1103 while (!path.empty() &&
1104 !instanceInfo->anyInstanceInDesign(cast<igraph::ModuleOpInterface>(
1105 symbolTable->lookup(path.back().getModule())))) {
1106 LLVM_DEBUG(llvm::dbgs()
1107 <<
" - Dropping non-DUT segment " << path.back() <<
"\n");
1108 path = path.drop_back();
1114 ? originalInstanceParents[inst]
1115 : path.back().getModule()));
1116 for (
auto sym : llvm::reverse(path)) {
1127 builder.create<sv::VerbatimOp>(builder.getUnknownLoc(), buffer,
1128 ValueRange{}, builder.getArrayAttr(symbols));
1130 if (!classFields.empty()) {
1131 addPortsToClass(classFields, extractMetadataClass);
1135 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1136 sifiveMetadataClass->getLoc(), sifiveMetadataClass.getBodyBlock());
1137 SmallVector<std::pair<Value, Twine>> classFields = {
1138 {builderOM.create<ObjectOp>(
1139 extractMetadataClass,
1140 builderOM.getStringAttr(
"extract_instances_metadata")),
1141 "extractedInstances_field"}};
1143 addPortsToClass(classFields, sifiveMetadataClass);
1144 auto *node = instanceGraph->lookup(sifiveMetadataClass);
1145 assert(node && node->hasOneUse());
1146 ObjectOp metadataObj =
1147 dyn_cast_or_null<ObjectOp>((*node->usesBegin())->getInstance());
1149 "expected the class to be instantiated by an object op");
1150 builderOM.setInsertionPoint(metadataObj);
1152 builderOM.create<ObjectOp>(sifiveMetadataClass, metadataObj.getName());
1153 metadataObj->replaceAllUsesWith(newObj);
1154 metadataObj->remove();
1158 void ExtractInstancesPass::createSchema() {
1160 auto *context = circuitOp->getContext();
1162 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1163 unknownLoc, circuitOp.getBodyBlock());
1164 mlir::Type portsType[] = {
1169 StringRef portFields[] = {
"name",
"path",
"filename"};
1171 schemaClass = builderOM.create<ClassOp>(
"ExtractInstancesSchema", portFields,
1175 SmallVector<PortInfo> mports;
1176 extractMetadataClass = builderOM.create<ClassOp>(
1177 builderOM.getStringAttr(
"ExtractInstancesMetadata"), mports);
1184 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.