403 DenseMap<Value, Operation *> nodeCache;
406 auto getOrCreateNodeOp = [&](Value operand,
407 ImplicitLocOpBuilder &builder) -> Operation * {
409 auto *nodeOp = nodeCache.lookup(operand);
414 OpBuilder::InsertionGuard guard(builder);
415 builder.setInsertionPointAfterValue(operand);
416 SmallString<16> nameHint;
418 if (
auto *definingOp = operand.getDefiningOp()) {
419 if (
auto instanceOp = dyn_cast<InstanceOp>(definingOp)) {
420 nameHint.append(instanceOp.getName());
421 nameHint.push_back(
'_');
423 instanceOp.getPortName(cast<OpResult>(operand).getResultNumber()));
424 }
else if (
auto opName = definingOp->getAttrOfType<StringAttr>(
"name")) {
425 nameHint.append(opName);
428 return nodeOp = NodeOp::create(builder, operand.getLoc(), operand,
429 nameHint.empty() ?
"_layer_probe"
430 : StringRef(nameHint));
436 DenseMap<Value, Value> replacements;
437 auto getReplacement = [&](Operation *user, Value value) -> Value {
438 auto it = replacements.find(value);
439 if (it != replacements.end())
440 return it->getSecond();
442 ImplicitLocOpBuilder localBuilder(value.getLoc(), &getContext());
445 auto layerBlockOp = user->getParentOfType<LayerBlockOp>();
446 localBuilder.setInsertionPointToStart(layerBlockOp.getBody());
453 if (type_isa<FStringType>(value.getType())) {
454 localBuilder.setInsertionPoint(user);
455 replacement = localBuilder.clone(*value.getDefiningOp())->getResult(0);
456 replacements.insert({value, replacement});
461 auto *definingOp = value.getDefiningOp();
462 if (isa_and_present<XMRRefOp>(definingOp)) {
463 replacement = localBuilder.clone(*definingOp)->getResult(0);
464 replacements.insert({value, replacement});
477 auto baseType = type_cast<FIRRTLBaseType>(value.getType());
478 if (baseType && baseType.getBitWidthOrSentinel() == 0) {
479 OpBuilder::InsertionGuard guard(localBuilder);
480 auto zeroUIntType = UIntType::get(localBuilder.getContext(), 0);
481 replacement = localBuilder.createOrFold<BitCastOp>(
482 value.getType(), ConstantOp::create(localBuilder, zeroUIntType,
485 auto *definingOp = value.getDefiningOp();
486 hw::InnerRefAttr innerRef;
494 definingOp = getOrCreateNodeOp(value, localBuilder);
498 auto portIdx = cast<BlockArgument>(value).getArgNumber();
500 cast<FModuleLike>(*moduleOp), portIdx,
504 hw::HierPathOp hierPathOp;
507 auto insertPoint = OpBuilder::InsertPoint(moduleOp->getBlock(),
508 Block::iterator(moduleOp));
509 llvm::sys::SmartScopedLock<true> circuitLock(*
circuitMutex);
511 localBuilder.getArrayAttr({innerRef}), localBuilder.getLoc(),
513 hierPathOp.setVisibility(SymbolTable::Visibility::Private);
516 replacement = XMRDerefOp::create(localBuilder, value.getType(),
517 hierPathOp.getSymNameAttr());
520 replacements.insert({value, replacement});
528 DenseMap<InstanceOp, FModuleOp> createdInstances;
532 auto opPreconditionCheck = [](Operation *op) -> LogicalResult {
534 if (isa<RefCastOp, RefDefineOp, RefResolveOp, RefSendOp, RefSubOp,
536 return op->emitOpError()
537 <<
"cannot be handled by the lower-layers pass. This should have "
538 "already been removed by the lower-xmr pass.";
562 auto result = moduleOp.walk<mlir::WalkOrder::PostOrder>([&](Operation *op) {
563 if (failed(opPreconditionCheck(op)))
564 return WalkResult::interrupt();
567 for (
auto result : op->getResults())
571 if (
auto instance = dyn_cast<InstanceOp>(op))
572 instance.setLayers({});
574 auto layerBlock = dyn_cast<LayerBlockOp>(op);
576 return WalkResult::advance();
579 auto layer =
symbolToLayer.lookup(layerBlock.getLayerName());
581 if (layer.getConvention() == LayerConvention::Inline) {
583 return WalkResult::advance();
587 assert(layer.getConvention() == LayerConvention::Bind);
590 replacements.clear();
591 OpBuilder builder(moduleOp);
592 SmallVector<hw::InnerSymAttr> innerSyms;
593 SmallVector<sv::VerbatimOp> verbatims;
594 DenseSet<Operation *> spilledSubOps;
595 auto layerBlockWalkResult = layerBlock.walk([&](Operation *op) {
597 if (failed(opPreconditionCheck(op)))
598 return WalkResult::interrupt();
611 auto fixSubOp = [&](
auto subOp) {
612 auto input = subOp.getInput();
616 return WalkResult::advance();
619 if (firrtl::type_cast<FIRRTLBaseType>(input.getType()).isPassive()) {
620 subOp.getInputMutable().assign(getReplacement(subOp, input));
621 return WalkResult::advance();
625 op->moveBefore(layerBlock);
626 spilledSubOps.insert(op);
627 return WalkResult::advance();
630 if (
auto subOp = dyn_cast<SubfieldOp>(op))
631 return fixSubOp(subOp);
633 if (
auto subOp = dyn_cast<SubindexOp>(op))
634 return fixSubOp(subOp);
636 if (
auto subOp = dyn_cast<SubaccessOp>(op)) {
637 auto input = subOp.getInput();
638 auto index = subOp.getIndex();
644 subOp.getIndexMutable().assign(getReplacement(subOp, index));
646 return WalkResult::advance();
650 if (firrtl::type_cast<FIRRTLBaseType>(input.getType()).isPassive()) {
651 subOp.getInputMutable().assign(getReplacement(subOp, input));
653 subOp.getIndexMutable().assign(getReplacement(subOp, index));
654 return WalkResult::advance();
659 subOp->moveBefore(layerBlock);
660 spilledSubOps.insert(op);
661 return WalkResult::advance();
666 auto diag = op->emitOpError()
667 <<
"has a non-passive operand and captures a value defined "
668 "outside its enclosing bind-convention layerblock. The "
669 "'LowerLayers' pass cannot lower this as it would "
670 "create an output port on the resulting module.";
671 diag.attachNote(layerBlock.getLoc())
672 <<
"the layerblock is defined here";
673 return WalkResult::interrupt();
676 if (
auto nodeOp = dyn_cast<NodeOp>(op)) {
677 auto *definingOp = nodeOp.getInput().getDefiningOp();
679 spilledSubOps.contains(nodeOp.getInput().getDefiningOp())) {
680 op->moveBefore(layerBlock);
681 return WalkResult::advance();
689 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op))
690 if (
auto innerSym = symOp.getInnerSymAttr())
691 innerSyms.push_back(innerSym);
703 if (
auto instOp = dyn_cast<InstanceOp>(op)) {
705 if (!createdInstances.contains(instOp))
706 return WalkResult::advance();
710 <<
" Found instance created from nested layer block:\n"
711 <<
" module: " << instOp.getModuleName() <<
"\n"
712 <<
" instance: " << instOp.getName() <<
"\n";
714 instOp->moveBefore(layerBlock);
715 return WalkResult::advance();
721 for (
size_t i = 0, e = op->getNumOperands(); i != e; ++i) {
722 auto operand = op->getOperand(i);
730 op->setOperand(i, getReplacement(op, operand));
733 if (
auto verbatim = dyn_cast<sv::VerbatimOp>(op))
734 verbatims.push_back(verbatim);
736 return WalkResult::advance();
739 if (layerBlockWalkResult.wasInterrupted())
740 return WalkResult::interrupt();
744 SymbolTable::setSymbolVisibility(newModule,
745 SymbolTable::Visibility::Private);
746 newModule.getBody().takeBody(layerBlock.getRegion());
749 llvm::dbgs() <<
" New Module: "
759 builder.setInsertionPointAfter(layerBlock);
762 hw::InnerSymAttr::get(builder.getStringAttr(ns.
newName(instanceName)));
764 auto instanceOp = InstanceOp::create(
765 builder, layerBlock.getLoc(), newModule,
767 instanceName, NameKindEnum::DroppableName,
768 ArrayRef<Attribute>{},
769 ArrayRef<Attribute>{},
false,
773 layerBlock.getLayerName());
774 instanceOp->setAttr(
"output_file", outputFile);
776 createdInstances.try_emplace(instanceOp, newModule);
780 auto builder = OpBuilder::atBlockEnd(
bindFiles[moduleOp][layer].body);
781 BindOp::create(builder, layerBlock.getLoc(), moduleOp.getModuleNameAttr(),
782 instanceOp.getInnerSymAttr().getSymName());
785 LLVM_DEBUG(llvm::dbgs() <<
" moved inner refs:\n");
786 for (hw::InnerSymAttr innerSym : innerSyms) {
787 auto oldInnerRef = hw::InnerRefAttr::get(moduleOp.getModuleNameAttr(),
788 innerSym.getSymName());
789 auto splice = std::make_pair(instanceOp.getInnerSymAttr(),
790 newModule.getModuleNameAttr());
791 innerRefMap.insert({oldInnerRef, splice});
792 LLVM_DEBUG(llvm::dbgs() <<
" - ref: " << oldInnerRef <<
"\n"
793 <<
" splice: " << splice.first <<
", "
794 << splice.second <<
"\n";);
798 if (!verbatims.empty()) {
799 mlir::AttrTypeReplacer replacer;
800 replacer.addReplacement(
801 [&innerRefMap](hw::InnerRefAttr ref) -> std::optional<Attribute> {
802 auto it = innerRefMap.find(ref);
803 if (it != innerRefMap.end())
804 return hw::InnerRefAttr::get(it->second.second, ref.getName());
807 for (
auto verbatim : verbatims)
808 replacer.replaceElementsIn(verbatim);
813 return WalkResult::advance();
815 return success(!result.wasInterrupted());
857 SymbolRefAttr layerName, LayerOp layer) {
858 assert(layer.getConvention() == LayerConvention::Bind);
859 auto module = node->getModule<FModuleOp>();
860 auto loc =
module.getLoc();
864 auto macroSymbol = ns.
newName(macroName);
865 auto macroNameAttr = StringAttr::get(&getContext(), macroName);
866 auto macroSymbolAttr = StringAttr::get(&getContext(), macroSymbol);
867 auto macroSymbolRefAttr = FlatSymbolRefAttr::get(macroSymbolAttr);
874 auto dir = layer->getAttrOfType<hw::OutputFileAttr>(
"output_file");
875 StringAttr filename = StringAttr::get(&getContext(), bindFileName);
878 path = StringAttr::get(&getContext(),
879 Twine(dir.getDirectory()) + bindFileName);
884 sv::MacroDeclOp::create(b, loc, macroSymbolAttr, ArrayAttr{}, macroNameAttr);
887 auto bindFile = emit::FileOp::create(b, loc, path);
888 OpBuilder::InsertionGuard _(b);
889 b.setInsertionPointToEnd(bindFile.getBody());
892 auto includeGuard = sv::IfDefOp::create(b, loc, macroSymbolRefAttr);
893 b.createBlock(&includeGuard.getElseRegion());
896 sv::MacroDefOp::create(b, loc, macroSymbolRefAttr);
899 auto parent = layer->getParentOfType<LayerOp>();
903 if (parent.getConvention() == LayerConvention::Bind) {
904 auto target =
bindFiles[module][parent].filename;
905 sv::IncludeOp::create(b, loc, IncludeStyle::Local, target);
911 if (parent.getConvention() == LayerConvention::Inline) {
912 auto parentMacroSymbolRefAttr =
macroNames[parent];
913 auto parentGuard = sv::IfDefOp::create(b, loc, parentMacroSymbolRefAttr);
914 OpBuilder::InsertionGuard guard(b);
915 b.createBlock(&parentGuard.getElseRegion());
916 auto message = StringAttr::get(&getContext(),
917 Twine(parent.getName()) +
" not enabled");
918 sv::MacroErrorOp::create(b, loc, message);
919 parent = parent->getParentOfType<LayerOp>();
924 llvm_unreachable(
"unknown layer convention");
929 SmallPtrSet<Operation *, 8> seen;
930 for (
auto *record : *node) {
931 auto *child = record->getTarget()->getModule().getOperation();
932 if (!std::get<bool>(seen.insert(child)))
935 auto lookup = files.find(layer);
936 if (lookup != files.end())
937 sv::IncludeOp::create(b, loc, IncludeStyle::Local,
938 lookup->second.filename);
943 info.filename = filename;
944 info.body = includeGuard.getElseBlock();
1062 llvm::dbgs() <<
"==----- Running LowerLayers "
1063 "-------------------------------------------------===\n");
1064 CircuitOp circuitOp = getOperation();
1067 llvm::sys::SmartMutex<true> mutex;
1070 auto *ig = &getAnalysis<InstanceGraph>();
1073 &ns, OpBuilder::InsertPoint(getOperation().
getBodyBlock(),
1080 auto mergeMaps = [](
auto &&a,
auto &&b) {
1082 return std::forward<
decltype(a)>(a);
1084 return std::forward<
decltype(b)>(b);
1088 return std::forward<decltype(a)>(a);
1092 SmallVector<FModuleLike> modules(
1093 circuitOp.getBodyBlock()->getOps<FModuleLike>());
1095 circuitOp.getContext(), modules, FailureOr<InnerRefMap>(
InnerRefMap{}),
1096 mergeMaps, [
this](FModuleLike mod) -> FailureOr<InnerRefMap> {
1097 return runOnModuleLike(mod);
1099 if (failed(failureOrInnerRefMap))
1100 return signalPassFailure();
1101 auto &innerRefMap = *failureOrInnerRefMap;
1110 for (hw::HierPathOp hierPathOp : circuitOp.getOps<hw::HierPathOp>()) {
1111 SmallVector<Attribute> newNamepath;
1112 bool modified =
false;
1113 for (
auto attr : hierPathOp.getNamepath()) {
1114 hw::InnerRefAttr innerRef = dyn_cast<hw::InnerRefAttr>(attr);
1116 newNamepath.push_back(attr);
1119 auto it = innerRefMap.find(innerRef);
1120 if (it == innerRefMap.end()) {
1121 newNamepath.push_back(attr);
1125 auto &[inst, mod] = it->getSecond();
1126 newNamepath.push_back(
1127 hw::InnerRefAttr::get(innerRef.getModule(), inst.getSymName()));
1128 newNamepath.push_back(hw::InnerRefAttr::get(mod, innerRef.getName()));
1132 hierPathOp.setNamepathAttr(
1133 ArrayAttr::get(circuitOp.getContext(), newNamepath));
1138 llvm::make_early_inc_range(circuitOp.getBodyBlock()->getOps<LayerOp>()))