373 DenseMap<Value, Operation *> nodeCache;
376 auto getOrCreateNodeOp = [&](Value operand,
377 ImplicitLocOpBuilder &builder) -> Operation * {
379 auto *nodeOp = nodeCache.lookup(operand);
384 OpBuilder::InsertionGuard guard(builder);
385 builder.setInsertionPointAfterValue(operand);
386 SmallString<16> nameHint;
388 if (
auto *definingOp = operand.getDefiningOp()) {
389 if (
auto instanceOp = dyn_cast<InstanceOp>(definingOp)) {
390 nameHint.append(instanceOp.getName());
391 nameHint.push_back(
'_');
393 instanceOp.getPortName(cast<OpResult>(operand).getResultNumber()));
394 }
else if (
auto opName = definingOp->getAttrOfType<StringAttr>(
"name")) {
395 nameHint.append(opName);
398 return nodeOp = builder.create<NodeOp>(
399 operand.getLoc(), operand,
400 nameHint.empty() ?
"_layer_probe" : StringRef(nameHint));
406 DenseMap<Value, Value> replacements;
407 auto getReplacement = [&](Operation *user, Value value) -> Value {
408 auto it = replacements.find(value);
409 if (it != replacements.end())
410 return it->getSecond();
412 ImplicitLocOpBuilder localBuilder(value.getLoc(), &getContext());
415 auto layerBlockOp = user->getParentOfType<LayerBlockOp>();
416 localBuilder.setInsertionPointToStart(layerBlockOp.getBody());
423 if (type_isa<FStringType>(value.getType())) {
424 localBuilder.setInsertionPoint(user);
425 replacement = localBuilder.clone(*value.getDefiningOp())->getResult(0);
426 replacements.insert({value, replacement});
431 auto *definingOp = value.getDefiningOp();
432 if (isa_and_present<XMRRefOp>(definingOp)) {
433 replacement = localBuilder.clone(*definingOp)->getResult(0);
434 replacements.insert({value, replacement});
447 auto baseType = type_cast<FIRRTLBaseType>(value.getType());
448 if (baseType && baseType.getBitWidthOrSentinel() == 0) {
449 OpBuilder::InsertionGuard guard(localBuilder);
450 auto zeroUIntType = UIntType::get(localBuilder.getContext(), 0);
451 replacement = localBuilder.createOrFold<BitCastOp>(
452 value.getType(), localBuilder.create<ConstantOp>(
455 auto *definingOp = value.getDefiningOp();
456 hw::InnerRefAttr innerRef;
464 definingOp = getOrCreateNodeOp(value, localBuilder);
468 auto portIdx = cast<BlockArgument>(value).getArgNumber();
470 cast<FModuleLike>(*moduleOp), portIdx,
474 hw::HierPathOp hierPathOp;
477 auto insertPoint = OpBuilder::InsertPoint(moduleOp->getBlock(),
478 Block::iterator(moduleOp));
479 llvm::sys::SmartScopedLock<true> circuitLock(*
circuitMutex);
481 localBuilder.getArrayAttr({innerRef}), localBuilder.getLoc(),
483 hierPathOp.setVisibility(SymbolTable::Visibility::Private);
486 replacement = localBuilder.create<XMRDerefOp>(
487 value.getType(), hierPathOp.getSymNameAttr());
490 replacements.insert({value, replacement});
498 DenseMap<InstanceOp, FModuleOp> createdInstances;
502 auto opPreconditionCheck = [](Operation *op) -> LogicalResult {
504 if (isa<RefCastOp, RefDefineOp, RefResolveOp, RefSendOp, RefSubOp,
506 return op->emitOpError()
507 <<
"cannot be handled by the lower-layers pass. This should have "
508 "already been removed by the lower-xmr pass.";
532 auto result = moduleOp.walk<mlir::WalkOrder::PostOrder>([&](Operation *op) {
533 if (failed(opPreconditionCheck(op)))
534 return WalkResult::interrupt();
537 if (
auto wire = dyn_cast<WireOp>(op)) {
539 return WalkResult::advance();
541 if (
auto instance = dyn_cast<InstanceOp>(op)) {
542 instance.setLayers({});
543 for (
auto result : instance.getResults())
545 return WalkResult::advance();
548 auto layerBlock = dyn_cast<LayerBlockOp>(op);
550 return WalkResult::advance();
553 auto layer =
symbolToLayer.lookup(layerBlock.getLayerName());
555 if (layer.getConvention() == LayerConvention::Inline) {
557 return WalkResult::advance();
561 assert(layer.getConvention() == LayerConvention::Bind);
564 replacements.clear();
565 OpBuilder builder(moduleOp);
566 SmallVector<hw::InnerSymAttr> innerSyms;
567 SmallVector<sv::VerbatimOp> verbatims;
568 DenseSet<Operation *> spilledSubOps;
569 auto layerBlockWalkResult = layerBlock.walk([&](Operation *op) {
571 if (failed(opPreconditionCheck(op)))
572 return WalkResult::interrupt();
585 if (isa<SubfieldOp, SubindexOp>(op)) {
586 auto input = op->getOperand(0);
587 if (!firrtl::type_cast<FIRRTLBaseType>(input.getType()).isPassive() &&
589 op->moveBefore(layerBlock);
590 spilledSubOps.insert(op);
592 return WalkResult::advance();
594 if (
auto subOp = dyn_cast<SubaccessOp>(op)) {
595 auto input = subOp.getInput();
596 if (firrtl::type_cast<FIRRTLBaseType>(input.getType()).isPassive())
597 return WalkResult::advance();
601 subOp->moveBefore(layerBlock);
602 spilledSubOps.insert(op);
603 return WalkResult::advance();
605 auto diag = op->emitOpError()
606 <<
"has a non-passive operand and captures a value defined "
607 "outside its enclosing bind-convention layerblock. The "
608 "'LowerLayers' pass cannot lower this as it would "
609 "create an output port on the resulting module.";
610 diag.attachNote(layerBlock.getLoc())
611 <<
"the layerblock is defined here";
612 return WalkResult::interrupt();
614 if (
auto nodeOp = dyn_cast<NodeOp>(op)) {
615 auto *definingOp = nodeOp.getInput().getDefiningOp();
617 spilledSubOps.contains(nodeOp.getInput().getDefiningOp())) {
618 op->moveBefore(layerBlock);
619 return WalkResult::advance();
627 if (
auto symOp = dyn_cast<hw::InnerSymbolOpInterface>(op))
628 if (
auto innerSym = symOp.getInnerSymAttr())
629 innerSyms.push_back(innerSym);
641 if (
auto instOp = dyn_cast<InstanceOp>(op)) {
643 if (!createdInstances.contains(instOp))
644 return WalkResult::advance();
648 <<
" Found instance created from nested layer block:\n"
649 <<
" module: " << instOp.getModuleName() <<
"\n"
650 <<
" instance: " << instOp.getName() <<
"\n";
652 instOp->moveBefore(layerBlock);
653 return WalkResult::advance();
659 for (
size_t i = 0, e = op->getNumOperands(); i != e; ++i) {
660 auto operand = op->getOperand(i);
668 op->setOperand(i, getReplacement(op, operand));
671 if (
auto verbatim = dyn_cast<sv::VerbatimOp>(op))
672 verbatims.push_back(verbatim);
674 return WalkResult::advance();
677 if (layerBlockWalkResult.wasInterrupted())
678 return WalkResult::interrupt();
682 SymbolTable::setSymbolVisibility(newModule,
683 SymbolTable::Visibility::Private);
684 newModule.getBody().takeBody(layerBlock.getRegion());
687 llvm::dbgs() <<
" New Module: "
697 builder.setInsertionPointAfter(layerBlock);
700 hw::InnerSymAttr::get(builder.getStringAttr(ns.
newName(instanceName)));
702 auto instanceOp = builder.create<InstanceOp>(
703 layerBlock.getLoc(), newModule,
705 instanceName, NameKindEnum::DroppableName,
706 ArrayRef<Attribute>{},
707 ArrayRef<Attribute>{},
false,
711 layerBlock.getLayerName());
712 instanceOp->setAttr(
"output_file", outputFile);
714 createdInstances.try_emplace(instanceOp, newModule);
717 OpBuilder::atBlockEnd(
bindFiles[moduleOp][layer].body)
718 .create<BindOp>(layerBlock.getLoc(), moduleOp.getModuleNameAttr(),
719 instanceOp.getInnerSymAttr().getSymName());
721 LLVM_DEBUG(llvm::dbgs() <<
" moved inner refs:\n");
722 for (hw::InnerSymAttr innerSym : innerSyms) {
723 auto oldInnerRef = hw::InnerRefAttr::get(moduleOp.getModuleNameAttr(),
724 innerSym.getSymName());
725 auto splice = std::make_pair(instanceOp.getInnerSymAttr(),
726 newModule.getModuleNameAttr());
727 innerRefMap.insert({oldInnerRef, splice});
728 LLVM_DEBUG(llvm::dbgs() <<
" - ref: " << oldInnerRef <<
"\n"
729 <<
" splice: " << splice.first <<
", "
730 << splice.second <<
"\n";);
734 if (!verbatims.empty()) {
735 mlir::AttrTypeReplacer replacer;
736 replacer.addReplacement(
737 [&innerRefMap](hw::InnerRefAttr ref) -> std::optional<Attribute> {
738 auto it = innerRefMap.find(ref);
739 if (it != innerRefMap.end())
740 return hw::InnerRefAttr::get(it->second.second, ref.getName());
743 for (
auto verbatim : verbatims)
744 replacer.replaceElementsIn(verbatim);
749 return WalkResult::advance();
751 return success(!result.wasInterrupted());
793 SymbolRefAttr layerName, LayerOp layer) {
794 assert(layer.getConvention() == LayerConvention::Bind);
795 auto module = node->getModule<FModuleOp>();
796 auto loc =
module.getLoc();
800 auto macroSymbol = ns.
newName(macroName);
801 auto macroNameAttr = StringAttr::get(&getContext(), macroName);
802 auto macroSymbolAttr = StringAttr::get(&getContext(), macroSymbol);
803 auto macroSymbolRefAttr = FlatSymbolRefAttr::get(macroSymbolAttr);
810 auto dir = layer->getAttrOfType<hw::OutputFileAttr>(
"output_file");
811 StringAttr filename = StringAttr::get(&getContext(), bindFileName);
814 path = StringAttr::get(&getContext(),
815 Twine(dir.getDirectory()) + bindFileName);
820 b.create<sv::MacroDeclOp>(loc, macroSymbolAttr, ArrayAttr{}, macroNameAttr);
823 auto bindFile = b.create<emit::FileOp>(loc, path);
824 OpBuilder::InsertionGuard _(b);
825 b.setInsertionPointToEnd(bindFile.getBody());
828 auto includeGuard = b.create<
sv::IfDefOp>(loc, macroSymbolRefAttr);
829 b.createBlock(&includeGuard.getElseRegion());
832 b.create<sv::MacroDefOp>(loc, macroSymbolRefAttr);
835 auto parent = layer->getParentOfType<LayerOp>();
839 if (parent.getConvention() == LayerConvention::Bind) {
840 auto target =
bindFiles[module][parent].filename;
841 b.create<sv::IncludeOp>(loc, IncludeStyle::Local, target);
848 b.create<sv::MacroDefOp>(loc, parentMacroSymbol);
849 parent = layer->getParentOfType<LayerOp>();
854 SmallPtrSet<Operation *, 8> seen;
855 for (
auto *record : *node) {
856 auto *child = record->getTarget()->getModule().getOperation();
857 if (!std::get<bool>(seen.insert(child)))
860 auto lookup = files.find(layer);
861 if (lookup != files.end())
862 b.create<sv::IncludeOp>(loc, IncludeStyle::Local,
863 lookup->second.filename);
868 info.filename = filename;
869 info.body = includeGuard.getElseBlock();
947 llvm::dbgs() <<
"==----- Running LowerLayers "
948 "-------------------------------------------------===\n");
949 CircuitOp circuitOp = getOperation();
952 llvm::sys::SmartMutex<true> mutex;
955 auto *ig = &getAnalysis<InstanceGraph>();
958 &ns, OpBuilder::InsertPoint(getOperation().
getBodyBlock(),
965 auto mergeMaps = [](
auto &&a,
auto &&b) {
967 return std::forward<
decltype(a)>(a);
969 return std::forward<
decltype(b)>(b);
973 return std::forward<decltype(a)>(a);
977 SmallVector<FModuleLike> modules(
978 circuitOp.getBodyBlock()->getOps<FModuleLike>());
980 circuitOp.getContext(), modules, FailureOr<InnerRefMap>(
InnerRefMap{}),
981 mergeMaps, [
this](FModuleLike mod) -> FailureOr<InnerRefMap> {
982 return runOnModuleLike(mod);
984 if (failed(failureOrInnerRefMap))
985 return signalPassFailure();
986 auto &innerRefMap = *failureOrInnerRefMap;
995 for (hw::HierPathOp hierPathOp : circuitOp.getOps<hw::HierPathOp>()) {
996 SmallVector<Attribute> newNamepath;
997 bool modified =
false;
998 for (
auto attr : hierPathOp.getNamepath()) {
999 hw::InnerRefAttr innerRef = dyn_cast<hw::InnerRefAttr>(attr);
1001 newNamepath.push_back(attr);
1004 auto it = innerRefMap.find(innerRef);
1005 if (it == innerRefMap.end()) {
1006 newNamepath.push_back(attr);
1010 auto &[inst, mod] = it->getSecond();
1011 newNamepath.push_back(
1012 hw::InnerRefAttr::get(innerRef.getModule(), inst.getSymName()));
1013 newNamepath.push_back(hw::InnerRefAttr::get(mod, innerRef.getName()));
1017 hierPathOp.setNamepathAttr(
1018 ArrayAttr::get(circuitOp.getContext(), newNamepath));
1023 llvm::make_early_inc_range(circuitOp.getBodyBlock()->getOps<LayerOp>()))