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"
54using namespace firrtl;
55using hw::InnerRefAttr;
63struct ExtractionInfo {
65 StringRef traceFilename;
69 StringRef wrapperModule;
75struct 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);
87 return moduleNamespaces.try_emplace(module, module).first->second;
93 return ::getInnerRefTo(op,
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(
115 UnknownLoc::get(&getContext()), getOperation().
getBodyBlock());
116 it->second = emit::FileOp::create(builder, 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 *, std::pair<SmallString<16>, StringAttr>>
160 DenseMap<Operation *, hw::InnerSymbolNamespace> moduleNamespaces;
162 ClassOp extractMetadataClass, schemaClass;
163 const unsigned prefixNameFieldId = 0, pathFieldId = 2, fileNameFieldId = 4,
167 DenseMap<InnerRefAttr, InstanceOp> innerRefToInstances;
168 Type stringType, pathType;
178void ExtractInstancesPass::runOnOperation() {
179 circuitOp = getOperation();
180 anythingChanged =
false;
182 annotatedModules.clear();
183 extractionWorklist.clear();
185 extractionPaths.clear();
186 originalInstanceParents.clear();
187 extractedInstances.clear();
188 instPrefixNamesPair.clear();
189 moduleNamespaces.clear();
190 circuitNamespace.clear();
191 circuitNamespace.add(circuitOp);
192 innerRefToInstances.clear();
193 extractMetadataClass = {};
195 auto *context = circuitOp->getContext();
196 stringType = StringType::get(context);
197 pathType = PathType::get(context);
202 instanceGraph = &getAnalysis<InstanceGraph>();
203 instanceInfo = &getAnalysis<InstanceInfo>();
204 symbolTable = &getAnalysis<SymbolTable>();
207 return signalPassFailure();
212 return signalPassFailure();
217 return signalPassFailure();
219 ClassOp sifiveMetadata =
220 dyn_cast_or_null<ClassOp>(symbolTable->lookup(
"SiFive_Metadata"));
223 createTraceFiles(sifiveMetadata);
225 return signalPassFailure();
228 LLVM_DEBUG(llvm::dbgs() <<
"\n");
229 if (!anythingChanged)
230 markAllAnalysesPreserved();
239void ExtractInstancesPass::collectAnnos() {
240 CircuitOp circuit = getOperation();
254 if (
auto moveDutAnnoAttr = anno.
getMember<BoolAttr>(
"moveDut"))
255 moveDut = moveDutAnnoAttr.getValue();
260 StringRef clkgateFileName;
261 StringRef clkgateWrapperModule;
265 LLVM_DEBUG(llvm::dbgs()
266 <<
"Clock gate extraction config: " << anno.
getDict() <<
"\n");
267 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
268 auto groupAttr = anno.
getMember<StringAttr>(
"group");
270 circuit.emitError(
"missing `filename` attribute in `")
271 << anno.
getClass() <<
"` annotation";
276 if (!clkgateFileName.empty()) {
277 circuit.emitError(
"multiple `")
278 << anno.
getClass() <<
"` annotations on circuit";
283 clkgateFileName = filenameAttr.getValue();
285 clkgateWrapperModule = groupAttr.getValue();
290 StringRef memoryFileName;
291 StringRef memoryWrapperModule;
295 LLVM_DEBUG(llvm::dbgs()
296 <<
"Memory extraction config: " << anno.
getDict() <<
"\n");
297 auto filenameAttr = anno.
getMember<StringAttr>(
"filename");
298 auto groupAttr = anno.
getMember<StringAttr>(
"group");
300 circuit.emitError(
"missing `filename` attribute in `")
301 << anno.
getClass() <<
"` annotation";
306 if (!memoryFileName.empty()) {
307 circuit.emitError(
"multiple `")
308 << anno.
getClass() <<
"` annotations on circuit";
313 memoryFileName = filenameAttr.getValue();
315 memoryWrapperModule = groupAttr.getValue();
321 for (
auto module : circuit.getOps<FModuleLike>()) {
325 LLVM_DEBUG(llvm::dbgs() <<
"Annotated module `" << module.getModuleName()
326 <<
"`:\n " << anno.
getDict() <<
"\n");
327 annotatedModules[module].push_back(anno);
333 circuit.walk([&](InstanceOp inst) {
334 SmallVector<Annotation, 1> instAnnos;
335 Operation *
module = inst.getReferencedModule(*instanceGraph);
338 auto it = annotatedModules.find(module);
339 if (it != annotatedModules.end())
340 instAnnos.append(it->second);
346 LLVM_DEBUG(llvm::dbgs() <<
"Annotated instance `" << inst.getName()
347 <<
"`:\n " << anno.
getDict() <<
"\n");
348 instAnnos.push_back(anno);
353 if (instAnnos.empty())
357 if (instAnnos.size() > 1) {
358 auto d = inst.emitError(
"multiple extraction annotations on instance `")
359 << inst.getName() <<
"`";
360 d.attachNote(inst.getLoc()) <<
"instance has the following annotations, "
361 "but at most one is allowed:";
362 for (
auto anno : instAnnos)
363 d.attachNote(inst.
getLoc()) << anno.getDict();
369 collectAnno(inst, instAnnos[0]);
378 if (!clkgateFileName.empty()) {
379 for (
auto module : circuit.getOps<FExtModuleOp>()) {
380 if (!module.getDefnameAttr().getValue().ends_with(
"EICG_wrapper"))
382 LLVM_DEBUG(llvm::dbgs()
383 <<
"Clock gate `" << module.getModuleName() <<
"`\n");
384 if (!instanceInfo->anyInstanceInDesign(module)) {
385 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
390 info.traceFilename = clkgateFileName;
391 info.prefix =
"clock_gate";
392 info.wrapperModule = clkgateWrapperModule;
393 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
394 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
395 LLVM_DEBUG(llvm::dbgs()
397 << inst->getParentOfType<FModuleLike>().getModuleName()
398 <<
"." << inst.getName() <<
"`\n");
399 extractionWorklist.push_back({inst,
info});
408 if (!memoryFileName.empty()) {
412 getOrCreateFile(memoryFileName);
414 for (
auto module : circuit.getOps<FMemModuleOp>()) {
415 LLVM_DEBUG(llvm::dbgs() <<
"Memory `" << module.getModuleName() <<
"`\n");
416 if (!instanceInfo->anyInstanceInDesign(module)) {
417 LLVM_DEBUG(llvm::dbgs() <<
"- Ignored (outside DUT)\n");
422 info.traceFilename = memoryFileName;
423 info.prefix =
"mem_wiring";
424 info.wrapperModule = memoryWrapperModule;
425 for (
auto *instRecord : instanceGraph->lookup(module)->uses()) {
426 if (
auto inst = dyn_cast<InstanceOp>(*instRecord->getInstance())) {
427 LLVM_DEBUG(llvm::dbgs()
429 << inst->getParentOfType<FModuleLike>().getModuleName()
430 <<
"." << inst.getName() <<
"`\n");
431 extractionWorklist.push_back({inst,
info});
440void ExtractInstancesPass::collectAnno(InstanceOp inst,
Annotation anno) {
441 LLVM_DEBUG(llvm::dbgs() <<
"Processing instance `" << inst.getName() <<
"` "
444 auto getStringOrError = [&](StringRef member) {
445 auto attr = anno.
getMember<StringAttr>(member);
447 inst.emitError(
"missing `")
448 << member <<
"` attribute in `" << anno.
getClass() <<
"` annotation";
455 auto filename = getStringOrError(
"filename");
456 auto prefix = getStringOrError(
"prefix");
457 auto dest = anno.
getMember<StringAttr>(
"dest");
462 info.traceFilename = filename;
463 info.prefix = prefix;
464 info.wrapperModule = (dest ? dest.getValue() :
"");
470 extractionWorklist.push_back({inst,
info});
480 unsigned nlaLen = nla.getNamepath().size();
482 auto parentName = cast<FModuleOp>(inst->getParentOp()).getModuleNameAttr();
483 for (
unsigned nlaIdx = 0; nlaIdx < nlaLen; ++nlaIdx) {
484 auto refPart = nla.refPart(nlaIdx);
485 if (nla.modPart(nlaIdx) == parentName && (!refPart || refPart == instName))
494void ExtractInstancesPass::extractInstances() {
497 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
499 DenseMap<StringRef, unsigned> prefixUniqueIDs;
501 SmallPtrSet<Operation *, 4> nlasToRemove;
503 auto &nlaTable = getAnalysis<NLATable>();
506 for (
auto &[inst, info] : extractionWorklist)
507 originalInstanceParents[inst] =
508 inst->getParentOfType<FModuleLike>().getModuleNameAttr();
510 while (!extractionWorklist.empty()) {
513 std::tie(inst, info) = extractionWorklist.pop_back_val();
515 auto parent = inst->getParentOfType<FModuleOp>();
524 auto &instPrefixEntry = instPrefixNamesPair[inst];
525 instPrefixEntry.second = inst.getInstanceNameAttr();
526 if (!
info.prefix.empty()) {
527 auto &prefixSlot = instPrefixEntry.first;
528 if (prefixSlot.empty()) {
529 auto idx = prefixUniqueIDs[
info.prefix]++;
530 (Twine(
info.prefix) +
"_" + Twine(idx)).
toVector(prefixSlot);
537 bool stopAtDUT = !moveDut && !
info.wrapperModule.empty();
543 if (inst->getParentOfType<LayerBlockOp>() ||
544 !instanceInfo->anyInstanceInDesign(parent) ||
545 instanceGraph->lookup(parent)->noUses() ||
546 (stopAtDUT && instanceInfo->isDut(parent))) {
547 LLVM_DEBUG(llvm::dbgs() <<
"\nNo need to further move " << inst <<
"\n");
548 extractedInstances.push_back({inst,
info});
552 llvm::dbgs() <<
"\nMoving ";
554 llvm::dbgs() <<
"`" << prefix <<
"` ";
555 llvm::dbgs() << inst <<
"\n";
560 unsigned numParentPorts = parent.getNumPorts();
561 unsigned numInstPorts = inst.getNumResults();
563 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
566 auto name = inst.getPortName(portIdx);
567 auto nameAttr = StringAttr::get(
569 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
572 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
574 newPort.
loc = inst.getResult(portIdx).getLoc();
575 newPorts.push_back({numParentPorts, newPort});
576 LLVM_DEBUG(llvm::dbgs()
577 <<
"- Adding port " << newPort.direction <<
" "
578 << newPort.name.getValue() <<
": " << newPort.type <<
"\n");
580 parent.insertPorts(newPorts);
581 anythingChanged =
true;
585 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
586 inst.getResult(portIdx).replaceAllUsesWith(
587 parent.getArgument(numParentPorts + portIdx));
589 assert(inst.use_empty() &&
"instance ports should have been detached");
590 DenseSet<hw::HierPathOp> instanceNLAs;
593 nlaTable.getInstanceNLAs(inst, instanceNLAs);
596 DenseMap<hw::HierPathOp, SmallVector<Annotation>> instNonlocalAnnos;
599 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
603 if (hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr())) {
604 instNonlocalAnnos[nla].push_back(anno);
605 instanceNLAs.insert(nla);
612 SmallVector<hw::HierPathOp> sortedInstanceNLAs(instanceNLAs.begin(),
614 llvm::sort(sortedInstanceNLAs,
615 [](
auto a,
auto b) {
return a.getSymName() < b.getSymName(); });
620 auto *instParentNode =
621 instanceGraph->lookup(cast<igraph::ModuleOpInterface>(*parent));
622 for (
auto *instRecord : instParentNode->uses()) {
623 auto oldParentInst = cast<InstanceOp>(*instRecord->getInstance());
624 auto newParent = oldParentInst->getParentOfType<FModuleLike>();
625 LLVM_DEBUG(llvm::dbgs() <<
"- Updating " << oldParentInst <<
"\n");
627 oldParentInst.cloneWithInsertedPortsAndReplaceUses(newPorts);
628 if (newParentInst.getInnerSymAttr())
629 innerRefToInstances[
getInnerRefTo(newParentInst)] = newParentInst;
631 auto newInst = cast<InstanceOp>(inst->clone());
637 getModuleNamespace(newParent).newName(instSym.getValue());
638 if (newName != instSym.getValue())
639 newInst.setInnerSymAttr(
640 hw::InnerSymAttr::get(StringAttr::get(&getContext(), newName)));
644 ImplicitLocOpBuilder builder(inst.getLoc(), newParentInst);
645 builder.setInsertionPointAfter(newParentInst);
646 builder.insert(newInst);
647 if (newParentInst.getInnerSymAttr())
649 for (
unsigned portIdx = 0; portIdx < numInstPorts; ++portIdx) {
650 auto dst = newInst.getResult(portIdx);
651 auto src = newParentInst.getResult(numParentPorts + portIdx);
652 if (newPorts[portIdx].second.direction == Direction::In)
654 MatchingConnectOp::create(builder, dst, src);
663 auto oldPrefix = instPrefixNamesPair.find(inst);
664 if (oldPrefix != instPrefixNamesPair.end()) {
665 LLVM_DEBUG(llvm::dbgs() <<
" - Reusing prefix `"
666 << oldPrefix->second.first <<
"`\n");
667 auto newPrefix = std::move(oldPrefix->second);
668 instPrefixNamesPair.erase(oldPrefix);
669 instPrefixNamesPair.insert({newInst, newPrefix});
673 extractionPaths.try_emplace(newInst);
674 auto &extractionPath = (extractionPaths[newInst] = extractionPaths[inst]);
676 innerRefToInstances[instInnerRef] = newParentInst;
677 extractionPath.push_back(instInnerRef);
678 originalInstanceParents.try_emplace(newInst);
679 originalInstanceParents[newInst] = originalInstanceParents[inst];
682 SmallVector<Annotation> newInstNonlocalAnnos;
685 for (
auto nla : sortedInstanceNLAs) {
686 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
690 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
691 nla.getNamepath().end());
700 if (nlaIdx >= nlaPath.size()) {
701 LLVM_DEBUG(llvm::dbgs() <<
" - Instance no longer in path\n");
704 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
711 auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx - 1]);
713 !(innerRef.getModule() == newParent.getModuleNameAttr() &&
715 LLVM_DEBUG(llvm::dbgs()
716 <<
" - Ignored since NLA parent " << innerRef
717 <<
" does not pass through extraction parent\n");
735 LLVM_DEBUG(llvm::dbgs() <<
" - Re-rooting " << nlaPath[0] <<
"\n");
736 assert(isa<InnerRefAttr>(nlaPath[0]) &&
737 "head of hierpath must be an InnerRefAttr");
738 nlaPath[0] = InnerRefAttr::get(newParent.getModuleNameAttr(),
741 if (instParentNode->hasOneUse()) {
746 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
747 for (
auto anno : instNonlocalAnnos.lookup(nla))
748 newInstNonlocalAnnos.push_back(anno);
749 nlaTable.addNLA(nla);
750 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
754 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
755 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
757 FlatSymbolRefAttr::get(newNla.getSymNameAttr()));
758 newInstNonlocalAnnos.push_back(anno);
761 nlaTable.addNLA(newNla);
762 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
772 inst.emitWarning(
"extraction of instance `")
773 << inst.getInstanceName()
774 <<
"` could break non-local annotations rooted at `"
775 << parent.getModuleName() <<
"`";
786 if (nlaPath.size() == 2) {
787 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
789 newInstNonlocalAnnos.push_back(anno);
790 LLVM_DEBUG(llvm::dbgs() <<
" - Converted to local "
794 nlasToRemove.insert(nla);
802 StringAttr parentName =
803 cast<InnerRefAttr>(nlaPath[nlaIdx - 1]).getModule();
805 if (isa<InnerRefAttr>(nlaPath[nlaIdx]))
808 newRef = FlatSymbolRefAttr::get(parentName);
809 LLVM_DEBUG(llvm::dbgs()
810 <<
" - Replacing " << nlaPath[nlaIdx - 1] <<
" and "
811 << nlaPath[nlaIdx] <<
" with " << newRef <<
"\n");
812 nlaPath[nlaIdx] = newRef;
813 nlaPath.erase(nlaPath.begin() + nlaIdx - 1);
815 if (isa<FlatSymbolRefAttr>(newRef)) {
820 auto newNla = cloneWithNewNameAndPath(nla, nlaPath);
821 nlaTable.addNLA(newNla);
822 LLVM_DEBUG(llvm::dbgs() <<
" - Created " << newNla <<
"\n");
823 for (
auto anno : instNonlocalAnnos.lookup(nla)) {
825 FlatSymbolRefAttr::get(newNla.getSymNameAttr()));
826 newInstNonlocalAnnos.push_back(anno);
829 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
830 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
831 for (
auto anno : instNonlocalAnnos.lookup(nla))
832 newInstNonlocalAnnos.push_back(anno);
840 newInstAnnos.addAnnotations(newInstNonlocalAnnos);
841 newInstAnnos.applyToOperation(newInst);
845 extractionWorklist.push_back({newInst,
info});
846 LLVM_DEBUG(llvm::dbgs() <<
" - Updated to " << newInst <<
"\n");
849 instanceGraph->replaceInstance(oldParentInst, newParentInst);
850 oldParentInst.erase();
855 nlaTable.removeNLAsfromModule(instanceNLAs, parent.getNameAttr());
863 for (Operation *op : nlasToRemove) {
864 LLVM_DEBUG(llvm::dbgs() <<
"Removing obsolete " << *op <<
"\n");
872void ExtractInstancesPass::groupInstances() {
877 llvm::MapVector<std::pair<Operation *, StringRef>, SmallVector<InstanceOp>>
879 for (
auto &[inst, info] : extractedInstances) {
880 if (!
info.wrapperModule.empty())
881 instsByWrapper[{inst->getParentOfType<FModuleOp>(),
info.wrapperModule}]
884 if (instsByWrapper.empty())
886 LLVM_DEBUG(llvm::dbgs() <<
"\nGrouping instances into wrappers\n");
889 SmallVector<PortInfo> ports;
890 auto &nlaTable = getAnalysis<NLATable>();
892 for (
auto &[parentAndWrapperName, insts] : instsByWrapper) {
893 auto [parentOp, wrapperName] = parentAndWrapperName;
894 auto parent = cast<FModuleOp>(parentOp);
895 LLVM_DEBUG(llvm::dbgs() <<
"- Wrapper `" << wrapperName <<
"` in `"
896 << parent.getModuleName() <<
"` with "
897 << insts.size() <<
" instances\n");
898 OpBuilder builder(parentOp);
901 auto wrapperModuleName =
902 builder.getStringAttr(circuitNamespace.newName(wrapperName));
903 auto wrapperInstName =
904 builder.getStringAttr(getModuleNamespace(parent).newName(wrapperName));
911 for (
auto inst : insts) {
913 StringRef prefix(instPrefixNamesPair[inst].first);
914 unsigned portNum = inst.getNumResults();
915 for (
unsigned portIdx = 0; portIdx < portNum; ++portIdx) {
916 auto name = inst.getPortName(portIdx);
917 auto nameAttr = builder.getStringAttr(
918 prefix.empty() ? Twine(name) : Twine(prefix) +
"_" + name);
920 type_cast<FIRRTLType>(inst.getResult(portIdx).getType()),
921 inst.getPortDirection(portIdx)};
922 port.
loc = inst.getResult(portIdx).getLoc();
923 ports.push_back(port);
927 DenseSet<hw::HierPathOp> instNlas;
929 nlaTable.getInstanceNLAs(inst, instNlas);
933 for (
auto anno : instAnnos) {
934 auto nlaName = anno.
getMember<FlatSymbolRefAttr>(
"circt.nonlocal");
937 hw::HierPathOp nla = nlaTable.getNLA(nlaName.getAttr());
939 instNlas.insert(nla);
941 for (
auto nla : instNlas) {
942 LLVM_DEBUG(llvm::dbgs() <<
" - Updating " << nla <<
"\n");
946 SmallVector<Attribute> nlaPath(nla.getNamepath().begin(),
947 nla.getNamepath().end());
949 assert(nlaIdx < nlaPath.size() &&
"instance not found in its own NLA");
950 LLVM_DEBUG(llvm::dbgs() <<
" - Position " << nlaIdx <<
"\n");
955 InnerRefAttr::get(parent.getModuleNameAttr(), wrapperInstName);
957 if (
auto innerRef = dyn_cast<InnerRefAttr>(nlaPath[nlaIdx]))
958 ref2 = InnerRefAttr::get(wrapperModuleName, innerRef.getName());
960 ref2 = FlatSymbolRefAttr::get(wrapperModuleName);
961 LLVM_DEBUG(llvm::dbgs() <<
" - Expanding " << nlaPath[nlaIdx]
962 <<
" to (" << ref1 <<
", " << ref2 <<
")\n");
963 nlaPath[nlaIdx] = ref1;
964 nlaPath.insert(nlaPath.begin() + nlaIdx + 1, ref2);
968 nla.setNamepathAttr(builder.getArrayAttr(nlaPath));
969 LLVM_DEBUG(llvm::dbgs() <<
" - Modified to " << nla <<
"\n");
971 nlaTable.addNLAtoModule(nla, wrapperModuleName);
976 auto wrapper = FModuleOp::create(
977 builder, builder.getUnknownLoc(), wrapperModuleName,
978 ConventionAttr::get(builder.getContext(), Convention::Internal), ports);
979 SymbolTable::setSymbolVisibility(wrapper, SymbolTable::Visibility::Private);
984 builder.setInsertionPointToStart(parent.getBodyBlock());
985 auto wrapperInst = InstanceOp::create(
986 builder, wrapper.getLoc(), wrapper, wrapperName,
987 NameKindEnum::DroppableName, ArrayRef<Attribute>{},
988 ArrayRef<Attribute>{},
false,
989 false, hw::InnerSymAttr::get(wrapperInstName));
990 unsigned portIdx = 0;
991 for (
auto inst : insts)
992 for (auto result : inst.getResults())
993 result.replaceAllUsesWith(wrapperInst.getResult(portIdx++));
998 builder.setInsertionPointToStart(wrapper.getBodyBlock());
999 for (
auto inst : insts) {
1001 builder.insert(inst);
1002 for (
auto result : inst.getResults()) {
1004 Value src = wrapper.getArgument(portIdx);
1005 if (ports[portIdx].direction == Direction::Out)
1006 std::swap(dst, src);
1007 MatchingConnectOp::create(builder, result.getLoc(), dst, src);
1017void ExtractInstancesPass::createTraceFiles(ClassOp &sifiveMetadataClass) {
1018 LLVM_DEBUG(llvm::dbgs() <<
"\nGenerating trace files\n");
1021 llvm::MapVector<StringRef, SmallVector<InstanceOp>> instsByTraceFile;
1022 for (
auto &[inst, info] : extractedInstances)
1024 instsByTraceFile[
info.traceFilename].push_back(inst);
1027 SmallVector<Attribute> symbols;
1029 if (sifiveMetadataClass && !extractMetadataClass)
1032 auto addPortsToClass = [&](ArrayRef<std::pair<Value, Twine>> objFields,
1034 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1035 classOp.getLoc(), classOp.getBodyBlock());
1036 auto portIndex = classOp.getNumPorts();
1037 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
1038 for (
auto [index, port] : enumerate(objFields)) {
1040 auto obj = port.first;
1041 newPorts.emplace_back(
1043 PortInfo(builderOM.getStringAttr(port.second + Twine(portIndex)),
1044 obj.getType(), Direction::Out));
1046 classOp.getBodyBlock()->addArgument(obj.getType(), obj.getLoc());
1047 PropAssignOp::create(builderOM, blockarg, obj);
1049 classOp.insertPorts(newPorts);
1053 SmallVector<std::pair<Value, Twine>> classFields;
1054 for (
auto &[fileName, insts] : instsByTraceFile) {
1055 LLVM_DEBUG(llvm::dbgs() <<
"- " << fileName <<
"\n");
1057 llvm::raw_string_ostream os(buffer);
1059 symbolIndices.clear();
1061 auto addSymbol = [&](Attribute symbol) {
1063 auto it = symbolIndices.find(symbol);
1064 if (it != symbolIndices.end()) {
1067 id = symbols.size();
1068 symbols.push_back(symbol);
1069 symbolIndices.insert({symbol,
id});
1071 os <<
"{{" <<
id <<
"}}";
1074 auto file = getOrCreateFile(fileName);
1075 auto builder = OpBuilder::atBlockEnd(file.getBody());
1076 for (
auto inst : insts) {
1077 StringRef prefix(instPrefixNamesPair[inst].first);
1078 StringAttr origInstName(instPrefixNamesPair[inst].second);
1079 if (prefix.empty()) {
1080 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1081 <<
"` since it has no extraction prefix\n");
1084 ArrayRef<InnerRefAttr> path(extractionPaths[inst]);
1086 LLVM_DEBUG(llvm::dbgs() <<
" - Skipping `" << inst.getName()
1087 <<
"` since it has not been moved\n");
1090 LLVM_DEBUG(llvm::dbgs()
1091 <<
" - " << prefix <<
": " << inst.getName() <<
"\n");
1092 os << prefix <<
" -> ";
1094 if (sifiveMetadataClass) {
1096 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1097 inst.getLoc(), extractMetadataClass.getBodyBlock());
1098 auto prefixName = StringConstantOp::create(builderOM, prefix);
1099 auto object = ObjectOp::create(builderOM, schemaClass, prefix);
1101 ObjectSubfieldOp::create(builderOM,
object, prefixNameFieldId);
1102 PropAssignOp::create(builderOM, fPrefix, prefixName);
1104 auto targetInstance = innerRefToInstances[path.front()];
1105 SmallVector<Attribute> pathOpAttr(llvm::reverse(path));
1106 auto nla = pathCache.getOpFor(
1107 ArrayAttr::get(circuitOp->getContext(), pathOpAttr));
1109 auto pathOp =
createPathRef(targetInstance, nla, builderOM);
1110 auto fPath = ObjectSubfieldOp::create(builderOM,
object, pathFieldId);
1111 PropAssignOp::create(builderOM, fPath, pathOp);
1113 ObjectSubfieldOp::create(builderOM,
object, fileNameFieldId);
1114 auto fileNameOp = StringConstantOp::create(
1115 builderOM, builder.getStringAttr(fileName));
1116 PropAssignOp::create(builderOM, fFile, fileNameOp);
1119 ObjectSubfieldOp::create(builderOM,
object, instNameFieldId);
1120 auto instNameOp = StringConstantOp::create(builderOM, origInstName);
1121 PropAssignOp::create(builderOM, finstName, instNameOp);
1124 classFields.emplace_back(
object, prefix +
"_field");
1129 while (!path.empty() &&
1130 !instanceInfo->anyInstanceInDesign(cast<igraph::ModuleOpInterface>(
1131 symbolTable->lookup(path.back().getModule())))) {
1132 LLVM_DEBUG(llvm::dbgs()
1133 <<
" - Dropping non-DUT segment " << path.back() <<
"\n");
1134 path = path.drop_back();
1139 addSymbol(FlatSymbolRefAttr::get(path.empty()
1140 ? originalInstanceParents[inst]
1141 : path.back().getModule()));
1142 for (
auto sym :
llvm::reverse(path)) {
1146 os <<
"." << origInstName.getValue();
1154 sv::VerbatimOp::create(builder, builder.getUnknownLoc(), buffer,
1155 ValueRange{}, builder.getArrayAttr(symbols));
1157 if (!classFields.empty()) {
1158 addPortsToClass(classFields, extractMetadataClass);
1162 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1163 sifiveMetadataClass->getLoc(), sifiveMetadataClass.getBodyBlock());
1164 SmallVector<std::pair<Value, Twine>> classFields = {
1166 builderOM, extractMetadataClass,
1167 builderOM.getStringAttr(
"extract_instances_metadata")),
1168 "extractedInstances_field"}};
1170 addPortsToClass(classFields, sifiveMetadataClass);
1171 auto *node = instanceGraph->lookup(sifiveMetadataClass);
1172 assert(node && node->hasOneUse());
1173 ObjectOp metadataObj = (*node->usesBegin())->getInstance<ObjectOp>();
1175 "expected the class to be instantiated by an object op");
1176 builderOM.setInsertionPoint(metadataObj);
1178 ObjectOp::create(builderOM, sifiveMetadataClass, metadataObj.getName());
1179 metadataObj->replaceAllUsesWith(newObj);
1180 metadataObj->remove();
1184void ExtractInstancesPass::createSchema() {
1186 auto *context = circuitOp->getContext();
1187 auto unknownLoc = mlir::UnknownLoc::get(context);
1188 auto builderOM = mlir::ImplicitLocOpBuilder::atBlockEnd(
1189 unknownLoc, circuitOp.getBodyBlock());
1190 mlir::Type portsType[] = {
1196 StringRef portFields[] = {
"name",
"path",
"filename",
"inst_name"};
1198 schemaClass = ClassOp::create(builderOM,
"ExtractInstancesSchema", portFields,
1202 SmallVector<PortInfo> mports;
1203 extractMetadataClass = ClassOp::create(
1204 builderOM, builderOM.getStringAttr(
"ExtractInstancesMetadata"), mports);
assert(baseType &&"element must be base type")
static std::vector< mlir::Value > toVector(mlir::ValueRange range)
static Location getLoc(DefSlot slot)
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
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 flip(Direction direction)
Flip a port direction.
constexpr const char * injectDUTHierarchyAnnoClass
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 * 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.
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.