323 CircuitOp circuitOp = moduleOp->getParentOfType<CircuitOp>();
324 StringRef circuitName = circuitOp.getName();
330 DenseMap<InstanceOp, FModuleOp> createdInstances;
343 auto result = moduleOp.walk<mlir::WalkOrder::PostOrder>([&](Operation *op) {
345 if (
auto wire = dyn_cast<WireOp>(op)) {
347 return WalkResult::advance();
349 if (
auto sub = dyn_cast<RefSubOp>(op)) {
351 return WalkResult::advance();
353 if (
auto instance = dyn_cast<InstanceOp>(op)) {
354 instance.setLayers({});
355 for (
auto result : instance.getResults())
357 return WalkResult::advance();
359 if (
auto cast = dyn_cast<RefCastOp>(op)) {
361 return WalkResult::advance();
364 auto layerBlock = dyn_cast<LayerBlockOp>(op);
366 return WalkResult::advance();
368 auto layer =
symbolToLayer.lookup(layerBlock.getLayerName());
370 if (layer.getConvention() == LayerConvention::Inline) {
372 return WalkResult::advance();
375 assert(layer.getConvention() == LayerConvention::Bind);
376 Block *body = layerBlock.getBody(0);
377 OpBuilder builder(moduleOp);
381 SmallVector<PortInfo> ports;
384 SmallVector<ConnectInfo> connectValues;
387 auto createInputPort = [&](Value operand, Location loc) {
393 auto type = operand.getType();
394 if (
auto refType = dyn_cast<RefType>(type))
395 type = refType.getType();
397 ports.push_back({builder.getStringAttr(portName), type, Direction::In,
403 Value replacement = body->addArgument(type, loc);
404 if (isa<RefType>(operand.getType())) {
405 OpBuilder::InsertionGuard guard(builder);
406 builder.setInsertionPointToStart(body);
407 replacement = builder.create<RefSendOp>(loc, replacement);
409 operand.replaceUsesWithIf(replacement, [&](OpOperand &use) {
410 auto *user = use.getOwner();
411 if (!layerBlock->isAncestor(user))
413 if (
auto connectLike = dyn_cast<FConnectLike>(user)) {
414 if (use.getOperandNumber() == 0)
420 connectValues.push_back({operand, ConnectKind::NonRef});
426 auto getPortLoc = [&](Value port) -> Location {
427 Location loc = UnknownLoc::get(port.getContext());
428 if (
auto *destOp = port.getDefiningOp())
429 if (
auto instOp = dyn_cast<InstanceOp>(destOp)) {
430 auto modOpIt = createdInstances.find(instOp);
431 if (modOpIt != createdInstances.end()) {
432 auto portNum = cast<OpResult>(port).getResultNumber();
433 loc = modOpIt->getSecond().getPortLocation(portNum);
441 auto createOutputPort = [&](Value dest, Value src) {
442 auto loc = getPortLoc(dest);
443 auto portNum = ports.size();
447 if (
auto oldRef = dyn_cast<RefType>(dest.getType()))
450 refType = RefType::get(
451 type_cast<FIRRTLBaseType>(dest.getType()).getPassiveType(),
454 ports.push_back({builder.getStringAttr(portName), refType, Direction::Out,
456 Value replacement = body->addArgument(refType, loc);
457 if (isa<RefType>(dest.getType())) {
458 dest.replaceUsesWithIf(replacement, [&](OpOperand &use) {
459 auto *user = use.getOwner();
460 if (!layerBlock->isAncestor(user))
462 if (
auto connectLike = dyn_cast<FConnectLike>(user)) {
463 if (use.getOperandNumber() == 0)
468 connectValues.push_back({dest, ConnectKind::Ref});
471 connectValues.push_back({dest, ConnectKind::NonRef});
472 OpBuilder::InsertionGuard guard(builder);
473 builder.setInsertionPointAfterValue(src);
474 builder.create<RefDefineOp>(
475 loc, body->getArgument(portNum),
476 builder.create<RefSendOp>(loc, src)->getResult(0));
479 SmallVector<hw::InnerSymAttr> innerSyms;
480 SmallVector<RWProbeOp> rwprobes;
481 SmallVector<sv::VerbatimOp> verbatims;
482 auto layerBlockWalkResult = layerBlock.walk([&](Operation *op) {
485 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op))
486 if (
auto innerSym = symOp.getInnerSymAttr())
487 innerSyms.push_back(innerSym);
499 if (
auto instOp = dyn_cast<InstanceOp>(op)) {
501 if (!createdInstances.contains(instOp))
502 return WalkResult::advance();
506 <<
" Found instance created from nested layer block:\n"
507 <<
" module: " << instOp.getModuleName() <<
"\n"
508 <<
" instance: " << instOp.getName() <<
"\n";
510 instOp->moveBefore(layerBlock);
511 return WalkResult::advance();
523 if (isa<SubfieldOp, SubindexOp>(op)) {
524 auto input = op->getOperand(0);
525 if (!firrtl::type_cast<FIRRTLBaseType>(input.getType()).isPassive() &&
527 op->moveBefore(layerBlock);
528 return WalkResult::advance();
531 if (
auto subOp = dyn_cast<SubaccessOp>(op)) {
532 auto input = subOp.getInput();
533 if (firrtl::type_cast<FIRRTLBaseType>(input.getType()).isPassive())
534 return WalkResult::advance();
538 subOp->moveBefore(layerBlock);
539 return WalkResult::advance();
541 auto diag = op->emitOpError()
542 <<
"has a non-passive operand and captures a value defined "
543 "outside its enclosing bind-convention layerblock. The "
544 "'LowerLayers' pass cannot lower this as it would "
545 "create an output port on the resulting module.";
546 diag.attachNote(layerBlock.getLoc())
547 <<
"the layerblock is defined here";
548 return WalkResult::interrupt();
551 if (
auto rwprobe = dyn_cast<RWProbeOp>(op)) {
552 rwprobes.push_back(rwprobe);
553 return WalkResult::advance();
556 if (
auto connect = dyn_cast<FConnectLike>(op)) {
557 auto src = connect.getSrc();
558 auto dst = connect.getDest();
561 if (!srcInLayerBlock && !dstInLayerBlock) {
562 connect->moveBefore(layerBlock);
563 return WalkResult::advance();
566 if (!srcInLayerBlock) {
567 createInputPort(src, op->getLoc());
568 return WalkResult::advance();
571 if (!dstInLayerBlock) {
572 createOutputPort(dst, src);
573 if (!isa<RefType>(dst.getType()))
575 return WalkResult::advance();
578 return WalkResult::advance();
594 if (
auto refResolve = dyn_cast<RefResolveOp>(op))
595 if (refResolve.getResult().hasOneUse() &&
596 refResolve.getRef().getParentBlock() != body)
597 if (
auto connect = dyn_cast<MatchingConnectOp>(
598 *refResolve.getResult().getUsers().begin()))
599 if (connect.getDest().getParentBlock() != body) {
600 refResolve->moveBefore(layerBlock);
601 return WalkResult::advance();
605 for (
size_t i = 0, e = op->getNumOperands(); i != e; ++i) {
606 auto operand = op->getOperand(i);
617 if (type_isa<FStringType>(operand.getType())) {
618 OpBuilder::InsertionGuard guard(builder);
619 builder.setInsertionPoint(op);
621 builder.clone(*operand.getDefiningOp())->getResult(0));
626 createInputPort(operand, op->getLoc());
629 if (
auto verbatim = dyn_cast<sv::VerbatimOp>(op))
630 verbatims.push_back(verbatim);
632 return WalkResult::advance();
635 if (layerBlockWalkResult.wasInterrupted())
636 return WalkResult::interrupt();
640 SymbolTable::setSymbolVisibility(newModule,
641 SymbolTable::Visibility::Private);
642 newModule.getBody().takeBody(layerBlock.getRegion());
645 llvm::dbgs() <<
" New Module: " <<
moduleNames.lookup(layerBlock)
647 llvm::dbgs() <<
" ports:\n";
648 for (
size_t i = 0, e = ports.size(); i != e; ++i) {
649 auto port = ports[i];
650 auto value = connectValues[i];
651 llvm::dbgs() <<
" - name: " << port.getName() <<
"\n"
652 <<
" type: " << port.type <<
"\n"
653 <<
" direction: " << port.direction <<
"\n"
654 <<
" value: " << value.value <<
"\n"
656 << (value.kind == ConnectKind::NonRef ?
"NonRef" :
"Ref")
666 builder.setInsertionPointAfter(layerBlock);
668 auto instanceOp = builder.create<InstanceOp>(
669 layerBlock.getLoc(), newModule,
671 instanceName, NameKindEnum::DroppableName,
672 ArrayRef<Attribute>{},
673 ArrayRef<Attribute>{},
true,
676 (innerSyms.empty() ? hw::InnerSymAttr{}
677 : hw::InnerSymAttr::get(builder.getStringAttr(
682 instanceOp->setAttr(
"output_file", outputFile);
684 createdInstances.try_emplace(instanceOp, newModule);
686 LLVM_DEBUG(llvm::dbgs() <<
" moved inner refs:\n");
687 for (hw::InnerSymAttr innerSym : innerSyms) {
688 auto oldInnerRef = hw::InnerRefAttr::get(moduleOp.getModuleNameAttr(),
689 innerSym.getSymName());
690 auto splice = std::make_pair(instanceOp.getInnerSymAttr(),
691 newModule.getModuleNameAttr());
692 innerRefMap.insert({oldInnerRef, splice});
693 LLVM_DEBUG(llvm::dbgs() <<
" - ref: " << oldInnerRef <<
"\n"
694 <<
" splice: " << splice.first <<
", "
695 << splice.second <<
"\n";);
699 for (
auto rwprobe : rwprobes) {
700 auto targetRef = rwprobe.getTarget();
701 auto mapped = innerRefMap.find(targetRef);
702 if (mapped == innerRefMap.end()) {
703 assert(targetRef.getModule() == moduleOp.getNameAttr());
706 return WalkResult::interrupt();
707 auto target = ist->lookup(targetRef.getName());
712 "rwprobe capture not supported with bind convention layer")
713 .attachNote(fieldref.getLoc())
714 .append(
"rwprobe target outside of bind layer");
715 return WalkResult::interrupt();
718 if (mapped->second.second != newModule.getModuleNameAttr())
719 return rwprobe.emitError(
"rwprobe target refers to different module"),
720 WalkResult::interrupt();
722 rwprobe.setTargetAttr(
723 hw::InnerRefAttr::get(mapped->second.second, targetRef.getName()));
727 if (!verbatims.empty()) {
728 mlir::AttrTypeReplacer replacer;
729 replacer.addReplacement(
730 [&innerRefMap](hw::InnerRefAttr ref) -> std::optional<Attribute> {
731 auto it = innerRefMap.find(ref);
732 if (it != innerRefMap.end())
733 return hw::InnerRefAttr::get(it->second.second, ref.getName());
736 for (
auto verbatim : verbatims)
737 replacer.replaceElementsIn(verbatim);
741 assert(ports.size() == connectValues.size() &&
742 "the number of instance ports and values to connect to them must be "
744 for (
unsigned portNum = 0, e = newModule.getNumPorts(); portNum < e;
746 OpBuilder::InsertionGuard guard(builder);
747 builder.setInsertionPointAfterValue(instanceOp.getResult(portNum));
748 if (instanceOp.getPortDirection(portNum) == Direction::In) {
749 auto src = connectValues[portNum].value;
750 if (isa<RefType>(src.getType()))
751 src = builder.create<RefResolveOp>(
752 newModule.getPortLocationAttr(portNum), src);
753 builder.create<MatchingConnectOp>(
754 newModule.getPortLocationAttr(portNum),
755 instanceOp.getResult(portNum), src);
756 }
else if (isa<RefType>(instanceOp.getResult(portNum).getType()) &&
757 connectValues[portNum].kind == ConnectKind::Ref)
758 builder.create<RefDefineOp>(getPortLoc(connectValues[portNum].value),
759 connectValues[portNum].value,
760 instanceOp.getResult(portNum));
762 builder.create<MatchingConnectOp>(
763 getPortLoc(connectValues[portNum].value),
764 connectValues[portNum].value,
765 builder.create<RefResolveOp>(newModule.getPortLocationAttr(portNum),
766 instanceOp.getResult(portNum)));
770 return WalkResult::advance();
772 return success(!result.wasInterrupted());
813 llvm::dbgs() <<
"==----- Running LowerLayers "
814 "-------------------------------------------------===\n");
815 CircuitOp circuitOp = getOperation();
816 StringRef circuitName = circuitOp.getName();
819 llvm::sys::SmartMutex<true> mutex;
823 for (
auto &op : *circuitOp.getBodyBlock()) {
826 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
827 moduleOp->walk([&](LayerBlockOp layerBlockOp) {
829 layerBlockOp.getLayerName());
836 if (
auto layerOp = dyn_cast<LayerOp>(op)) {
842 auto mergeMaps = [](
auto &&a,
auto &&b) {
844 return std::forward<
decltype(a)>(a);
846 return std::forward<
decltype(b)>(b);
850 return std::forward<decltype(a)>(a);
854 SmallVector<FModuleLike> modules(
855 circuitOp.getBodyBlock()->getOps<FModuleLike>());
857 circuitOp.getContext(), modules, FailureOr<InnerRefMap>(
InnerRefMap{}),
858 mergeMaps, [
this](FModuleLike mod) -> FailureOr<InnerRefMap> {
859 return runOnModuleLike(mod);
861 if (failed(failureOrInnerRefMap))
862 return signalPassFailure();
863 auto &innerRefMap = *failureOrInnerRefMap;
872 for (hw::HierPathOp hierPathOp : circuitOp.getOps<hw::HierPathOp>()) {
873 SmallVector<Attribute> newNamepath;
874 bool modified =
false;
875 for (
auto attr : hierPathOp.getNamepath()) {
876 hw::InnerRefAttr innerRef = dyn_cast<hw::InnerRefAttr>(attr);
878 newNamepath.push_back(attr);
881 auto it = innerRefMap.find(innerRef);
882 if (it == innerRefMap.end()) {
883 newNamepath.push_back(attr);
887 auto &[inst, mod] = it->getSecond();
888 newNamepath.push_back(
889 hw::InnerRefAttr::get(innerRef.getModule(), inst.getSymName()));
890 newNamepath.push_back(hw::InnerRefAttr::get(mod, innerRef.getName()));
894 hierPathOp.setNamepathAttr(
895 ArrayAttr::get(circuitOp.getContext(), newNamepath));
910 OpBuilder builder(circuitOp);
911 SmallVector<std::pair<LayerOp, StringAttr>> layers;
912 circuitOp.walk<mlir::WalkOrder::PreOrder>([&](LayerOp layerOp) {
913 auto parentOp = layerOp->getParentOfType<LayerOp>();
914 while (!layers.empty() && parentOp != layers.back().first)
917 if (layerOp.getConvention() == LayerConvention::Inline) {
918 layers.emplace_back(layerOp,
nullptr);
922 builder.setInsertionPointToStart(circuitOp.getBodyBlock());
926 SmallString<32> prefixFile(
"layers-"), prefixMacro(
"layers_");
927 prefixFile.append(circuitName);
928 prefixFile.append(
"-");
929 prefixMacro.append(circuitName);
930 prefixMacro.append(
"_");
931 for (
auto [layer, _] : layers) {
932 prefixFile.append(layer.getSymName());
933 prefixFile.append(
"-");
934 prefixMacro.append(layer.getSymName());
935 prefixMacro.append(
"_");
937 prefixFile.append(layerOp.getSymName());
938 prefixMacro.append(layerOp.getSymName());
940 SmallString<128> includes;
941 for (
auto [_, strAttr] : layers) {
944 includes.append(strAttr);
945 includes.append(
"\n");
948 hw::OutputFileAttr bindFile;
949 if (
auto outputFile =
950 layerOp->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
951 auto dir = outputFile.getDirectory();
952 bindFile = hw::OutputFileAttr::getFromDirectoryAndFilename(
953 &getContext(), dir, prefixFile +
".sv",
956 bindFile = hw::OutputFileAttr::getFromFilename(
957 &getContext(), prefixFile +
".sv",
true);
961 auto header = builder.create<sv::VerbatimOp>(
963 includes +
"`ifndef " + prefixMacro +
"\n" +
"`define " + prefixMacro);
964 header->setAttr(
"output_file", bindFile);
967 builder.setInsertionPointToEnd(circuitOp.getBodyBlock());
968 auto footer = builder.create<sv::VerbatimOp>(layerOp.getLoc(),
969 "`endif // " + prefixMacro);
970 footer->setAttr(
"output_file", bindFile);
972 if (!layerOp.getBody().getOps<LayerOp>().
empty())
975 builder.getStringAttr(
"`include \"" +
976 bindFile.getFilename().getValue() +
"\""));
981 llvm::make_early_inc_range(circuitOp.getBodyBlock()->getOps<LayerOp>()))