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 (
auto operand : op->getOperands()) {
607 createInputPort(operand, op->getLoc());
610 if (
auto verbatim = dyn_cast<sv::VerbatimOp>(op))
611 verbatims.push_back(verbatim);
613 return WalkResult::advance();
616 if (layerBlockWalkResult.wasInterrupted())
617 return WalkResult::interrupt();
621 SymbolTable::setSymbolVisibility(newModule,
622 SymbolTable::Visibility::Private);
623 newModule.getBody().takeBody(layerBlock.getRegion());
626 llvm::dbgs() <<
" New Module: " <<
moduleNames.lookup(layerBlock)
628 llvm::dbgs() <<
" ports:\n";
629 for (
size_t i = 0, e = ports.size(); i != e; ++i) {
630 auto port = ports[i];
631 auto value = connectValues[i];
632 llvm::dbgs() <<
" - name: " << port.getName() <<
"\n"
633 <<
" type: " << port.type <<
"\n"
634 <<
" direction: " << port.direction <<
"\n"
635 <<
" value: " << value.value <<
"\n"
637 << (value.kind == ConnectKind::NonRef ?
"NonRef" :
"Ref")
647 builder.setInsertionPointAfter(layerBlock);
649 auto instanceOp = builder.create<InstanceOp>(
650 layerBlock.getLoc(), newModule,
652 instanceName, NameKindEnum::DroppableName,
653 ArrayRef<Attribute>{},
654 ArrayRef<Attribute>{},
true,
656 (innerSyms.empty() ? hw::InnerSymAttr{}
657 : hw::InnerSymAttr::get(builder.getStringAttr(
662 instanceOp->setAttr(
"output_file", outputFile);
664 createdInstances.try_emplace(instanceOp, newModule);
666 LLVM_DEBUG(llvm::dbgs() <<
" moved inner refs:\n");
667 for (hw::InnerSymAttr innerSym : innerSyms) {
668 auto oldInnerRef = hw::InnerRefAttr::get(moduleOp.getModuleNameAttr(),
669 innerSym.getSymName());
670 auto splice = std::make_pair(instanceOp.getInnerSymAttr(),
671 newModule.getModuleNameAttr());
672 innerRefMap.insert({oldInnerRef, splice});
673 LLVM_DEBUG(llvm::dbgs() <<
" - ref: " << oldInnerRef <<
"\n"
674 <<
" splice: " << splice.first <<
", "
675 << splice.second <<
"\n";);
679 for (
auto rwprobe : rwprobes) {
680 auto targetRef = rwprobe.getTarget();
681 auto mapped = innerRefMap.find(targetRef);
682 if (mapped == innerRefMap.end()) {
683 assert(targetRef.getModule() == moduleOp.getNameAttr());
686 return WalkResult::interrupt();
687 auto target = ist->lookup(targetRef.getName());
692 "rwprobe capture not supported with bind convention layer")
693 .attachNote(fieldref.getLoc())
694 .append(
"rwprobe target outside of bind layer");
695 return WalkResult::interrupt();
698 if (mapped->second.second != newModule.getModuleNameAttr())
699 return rwprobe.emitError(
"rwprobe target refers to different module"),
700 WalkResult::interrupt();
702 rwprobe.setTargetAttr(
703 hw::InnerRefAttr::get(mapped->second.second, targetRef.getName()));
707 if (!verbatims.empty()) {
708 mlir::AttrTypeReplacer replacer;
709 replacer.addReplacement(
710 [&innerRefMap](hw::InnerRefAttr ref) -> std::optional<Attribute> {
711 auto it = innerRefMap.find(ref);
712 if (it != innerRefMap.end())
713 return hw::InnerRefAttr::get(it->second.second, ref.getName());
716 for (
auto verbatim : verbatims)
717 replacer.replaceElementsIn(verbatim);
721 assert(ports.size() == connectValues.size() &&
722 "the number of instance ports and values to connect to them must be "
724 for (
unsigned portNum = 0, e = newModule.getNumPorts(); portNum < e;
726 OpBuilder::InsertionGuard guard(builder);
727 builder.setInsertionPointAfterValue(instanceOp.getResult(portNum));
728 if (instanceOp.getPortDirection(portNum) == Direction::In) {
729 auto src = connectValues[portNum].value;
730 if (isa<RefType>(src.getType()))
731 src = builder.create<RefResolveOp>(
732 newModule.getPortLocationAttr(portNum), src);
733 builder.create<MatchingConnectOp>(
734 newModule.getPortLocationAttr(portNum),
735 instanceOp.getResult(portNum), src);
736 }
else if (isa<RefType>(instanceOp.getResult(portNum).getType()) &&
737 connectValues[portNum].kind == ConnectKind::Ref)
738 builder.create<RefDefineOp>(getPortLoc(connectValues[portNum].value),
739 connectValues[portNum].value,
740 instanceOp.getResult(portNum));
742 builder.create<MatchingConnectOp>(
743 getPortLoc(connectValues[portNum].value),
744 connectValues[portNum].value,
745 builder.create<RefResolveOp>(newModule.getPortLocationAttr(portNum),
746 instanceOp.getResult(portNum)));
750 return WalkResult::advance();
752 return success(!result.wasInterrupted());
793 llvm::dbgs() <<
"==----- Running LowerLayers "
794 "-------------------------------------------------===\n");
795 CircuitOp circuitOp = getOperation();
796 StringRef circuitName = circuitOp.getName();
799 llvm::sys::SmartMutex<true> mutex;
803 for (
auto &op : *circuitOp.getBodyBlock()) {
806 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
807 moduleOp->walk([&](LayerBlockOp layerBlockOp) {
809 layerBlockOp.getLayerName());
816 if (
auto layerOp = dyn_cast<LayerOp>(op)) {
822 auto mergeMaps = [](
auto &&a,
auto &&b) {
824 return std::forward<
decltype(a)>(a);
826 return std::forward<
decltype(b)>(b);
830 return std::forward<decltype(a)>(a);
834 SmallVector<FModuleLike> modules(
835 circuitOp.getBodyBlock()->getOps<FModuleLike>());
837 circuitOp.getContext(), modules, FailureOr<InnerRefMap>(
InnerRefMap{}),
838 mergeMaps, [
this](FModuleLike mod) -> FailureOr<InnerRefMap> {
839 return runOnModuleLike(mod);
841 if (failed(failureOrInnerRefMap))
842 return signalPassFailure();
843 auto &innerRefMap = *failureOrInnerRefMap;
852 for (hw::HierPathOp hierPathOp : circuitOp.getOps<hw::HierPathOp>()) {
853 SmallVector<Attribute> newNamepath;
854 bool modified =
false;
855 for (
auto attr : hierPathOp.getNamepath()) {
856 hw::InnerRefAttr innerRef = dyn_cast<hw::InnerRefAttr>(attr);
858 newNamepath.push_back(attr);
861 auto it = innerRefMap.find(innerRef);
862 if (it == innerRefMap.end()) {
863 newNamepath.push_back(attr);
867 auto &[inst, mod] = it->getSecond();
868 newNamepath.push_back(
869 hw::InnerRefAttr::get(innerRef.getModule(), inst.getSymName()));
870 newNamepath.push_back(hw::InnerRefAttr::get(mod, innerRef.getName()));
874 hierPathOp.setNamepathAttr(
875 ArrayAttr::get(circuitOp.getContext(), newNamepath));
890 OpBuilder builder(circuitOp);
891 SmallVector<std::pair<LayerOp, StringAttr>> layers;
892 circuitOp.walk<mlir::WalkOrder::PreOrder>([&](LayerOp layerOp) {
893 auto parentOp = layerOp->getParentOfType<LayerOp>();
894 while (!layers.empty() && parentOp != layers.back().first)
897 if (layerOp.getConvention() == LayerConvention::Inline) {
898 layers.emplace_back(layerOp,
nullptr);
902 builder.setInsertionPointToStart(circuitOp.getBodyBlock());
906 SmallString<32> prefixFile(
"layers-"), prefixMacro(
"layers_");
907 prefixFile.append(circuitName);
908 prefixFile.append(
"-");
909 prefixMacro.append(circuitName);
910 prefixMacro.append(
"_");
911 for (
auto [layer, _] : layers) {
912 prefixFile.append(layer.getSymName());
913 prefixFile.append(
"-");
914 prefixMacro.append(layer.getSymName());
915 prefixMacro.append(
"_");
917 prefixFile.append(layerOp.getSymName());
918 prefixMacro.append(layerOp.getSymName());
920 SmallString<128> includes;
921 for (
auto [_, strAttr] : layers) {
924 includes.append(strAttr);
925 includes.append(
"\n");
928 hw::OutputFileAttr bindFile;
929 if (
auto outputFile =
930 layerOp->getAttrOfType<hw::OutputFileAttr>(
"output_file")) {
931 auto dir = outputFile.getDirectory();
932 bindFile = hw::OutputFileAttr::getFromDirectoryAndFilename(
933 &getContext(), dir, prefixFile +
".sv",
936 bindFile = hw::OutputFileAttr::getFromFilename(
937 &getContext(), prefixFile +
".sv",
true);
941 auto header = builder.create<sv::VerbatimOp>(
943 includes +
"`ifndef " + prefixMacro +
"\n" +
"`define " + prefixMacro);
944 header->setAttr(
"output_file", bindFile);
947 builder.setInsertionPointToEnd(circuitOp.getBodyBlock());
948 auto footer = builder.create<sv::VerbatimOp>(layerOp.getLoc(),
949 "`endif // " + prefixMacro);
950 footer->setAttr(
"output_file", bindFile);
952 if (!layerOp.getBody().getOps<LayerOp>().
empty())
955 builder.getStringAttr(
"`include \"" +
956 bindFile.getFilename().getValue() +
"\""));
961 llvm::make_early_inc_range(circuitOp.getBodyBlock()->getOps<LayerOp>()))