25#include "mlir/IR/Dominance.h"
26#include "mlir/IR/ImplicitLocOpBuilder.h"
27#include "mlir/IR/Threading.h"
28#include "mlir/Pass/Pass.h"
29#include "llvm/ADT/EquivalenceClasses.h"
30#include "llvm/ADT/SetVector.h"
31#include "llvm/ADT/TypeSwitch.h"
32#include "llvm/Support/Debug.h"
33#include "llvm/Support/LogicalResult.h"
35#define DEBUG_TYPE "infer-resets"
39#define GEN_PASS_DEF_INFERRESETS
40#include "circt/Dialect/FIRRTL/Passes.h.inc"
44using circt::igraph::InstanceOpInterface;
47using llvm::BumpPtrAllocator;
49using llvm::SmallDenseSet;
52using mlir::InferTypeOpInterface;
55using namespace firrtl;
67 bool operator<(
const ResetSignal &other)
const {
return field < other.field; }
68 bool operator==(
const ResetSignal &other)
const {
69 return field == other.field;
71 bool operator!=(
const ResetSignal &other)
const {
return !(*
this == other); }
91using ResetDrives = SmallVector<ResetDrive, 1>;
94using ResetNetwork = llvm::iterator_range<
95 llvm::EquivalenceClasses<ResetSignal>::member_iterator>;
98enum class ResetKind { Async, Sync };
108 static bool isEqual(
const ResetSignal &lhs,
const ResetSignal &rhs) {
117 case ResetKind::Async:
118 return os <<
"async";
119 case ResetKind::Sync:
229struct InferResetsPass
230 :
public circt::firrtl::impl::InferResetsBase<InferResetsPass> {
231 void runOnOperation()
override;
232 void runOnOperationInner();
235 using InferResetsBase::InferResetsBase;
236 InferResetsPass(
const InferResetsPass &other) : InferResetsBase(other) {}
241 void traceResets(CircuitOp circuit);
242 void traceResets(FInstanceLike inst);
243 void traceResets(Value dst, Value src, Location loc);
244 void traceResets(Value value);
245 void traceResets(Type dstType, Value dst,
unsigned dstID, Type srcType,
246 Value src,
unsigned srcID, Location loc);
248 LogicalResult inferAndUpdateResets();
249 FailureOr<ResetKind> inferReset(ResetNetwork net);
250 LogicalResult updateReset(ResetNetwork net, ResetKind kind);
253 LogicalResult verifyNoAbstractReset();
259 ResetNetwork getResetNetwork(ResetSignal signal) {
260 return llvm::make_range(resetClasses.findLeader(signal),
261 resetClasses.member_end());
265 ResetDrives &getResetDrives(ResetNetwork net) {
266 return resetDrives[*net.begin()];
271 ResetSignal guessRoot(ResetNetwork net);
272 ResetSignal guessRoot(ResetSignal signal) {
273 return guessRoot(getResetNetwork(signal));
280 llvm::EquivalenceClasses<ResetSignal> resetClasses;
283 DenseMap<ResetSignal, ResetDrives> resetDrives;
290void InferResetsPass::runOnOperation() {
291 runOnOperationInner();
292 resetClasses = llvm::EquivalenceClasses<ResetSignal>();
294 markAnalysesPreserved<InstanceGraph>();
297void InferResetsPass::runOnOperationInner() {
298 instanceGraph = &getAnalysis<InstanceGraph>();
301 traceResets(getOperation());
304 if (failed(inferAndUpdateResets()))
305 return signalPassFailure();
308 getAnalysis<InstanceInfo>())))
309 return signalPassFailure();
312 if (failed(verifyNoAbstractReset()))
313 return signalPassFailure();
316ResetSignal InferResetsPass::guessRoot(ResetNetwork net) {
317 ResetDrives &drives = getResetDrives(net);
318 ResetSignal bestSignal = *net.begin();
319 unsigned bestNumDrives = -1;
321 for (
auto signal : net) {
323 if (isa_and_nonnull<InvalidValueOp>(
324 signal.field.getValue().getDefiningOp()))
329 unsigned numDrives = 0;
330 for (
auto &drive : drives)
331 if (drive.dst == signal)
337 if (numDrives < bestNumDrives) {
338 bestNumDrives = numDrives;
357 .
Case<BundleType>([](
auto type) {
359 for (
auto e : type.getElements())
364 [](
auto type) {
return getMaxFieldID(type.getElementType()) + 1; })
365 .Default([](
auto) {
return 0; });
369 assert(index < type.getNumElements());
371 for (
unsigned i = 0; i < index; ++i)
379 assert(type.getNumElements() &&
"Bundle must have >0 fields");
381 for (
const auto &e : llvm::enumerate(type.getElements())) {
383 if (fieldID < numSubfields)
385 fieldID -= numSubfields;
387 assert(
false &&
"field id outside bundle");
393 if (oldType.isGround()) {
399 if (
auto bundleType = type_dyn_cast<BundleType>(oldType)) {
407 if (
auto vectorType = type_dyn_cast<FVectorType>(oldType)) {
408 if (vectorType.getNumElements() == 0)
425 if (
auto arg = dyn_cast<BlockArgument>(value)) {
426 auto module = cast<FModuleOp>(arg.getOwner()->getParentOp());
427 string +=
module.getPortName(arg.getArgNumber());
431 auto *op = value.getDefiningOp();
432 return TypeSwitch<Operation *, bool>(op)
433 .Case<InstanceOp, InstanceChoiceOp, MemOp>([&](
auto op) {
434 string += op.getName();
436 string += op.getPortName(cast<OpResult>(value).getResultNumber());
439 .Case<WireOp, NodeOp, RegOp, RegResetOp>([&](
auto op) {
440 string += op.getName();
443 .Default([](
auto) {
return false; });
447 SmallString<64> name;
452 auto type = value.getType();
455 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
458 auto &element = bundleType.getElements()[index];
461 string += element.name.getValue();
464 localID = localID -
getFieldID(bundleType, index);
465 }
else if (
auto vecType = type_dyn_cast<FVectorType>(type)) {
468 type = vecType.getElementType();
475 llvm_unreachable(
"unsupported type");
487 return TypeSwitch<Type, bool>(type)
489 return type.getRecursiveTypeProperties().hasUninferredReset;
491 .Default([](
auto) {
return false; });
498void InferResetsPass::traceResets(CircuitOp circuit) {
500 llvm::dbgs() <<
"\n";
501 debugHeader(
"Tracing uninferred resets") <<
"\n\n";
504 SmallVector<std::pair<FModuleOp, SmallVector<Operation *>>> moduleToOps;
506 for (
auto module : circuit.getOps<FModuleOp>())
507 moduleToOps.push_back({module, {}});
510 getAnalysis<hw::InnerSymbolTableCollection>()};
512 mlir::parallelForEach(circuit.getContext(), moduleToOps, [](
auto &e) {
513 e.first.walk([&](Operation *op) {
517 op->getResultTypes(),
518 [](mlir::Type type) { return typeContainsReset(type); }) ||
519 llvm::any_of(op->getOperandTypes(), typeContainsReset))
520 e.second.push_back(op);
524 for (
auto &[_, ops] : moduleToOps)
525 for (auto *op : ops) {
526 TypeSwitch<Operation *>(op)
527 .Case<FConnectLike>([&](
auto op) {
528 traceResets(op.getDest(), op.getSrc(), op.getLoc());
530 .Case<FInstanceLike>([&](
auto op) { traceResets(op); })
531 .Case<RefSendOp>([&](
auto op) {
533 traceResets(op.getType().getType(), op.getResult(), 0,
534 op.getBase().getType().getPassiveType(), op.getBase(),
537 .Case<RefResolveOp>([&](
auto op) {
539 traceResets(op.getType(), op.getResult(), 0,
540 op.getRef().getType().getType(), op.getRef(), 0,
543 .Case<Forceable>([&](Forceable op) {
544 if (
auto node = dyn_cast<NodeOp>(op.getOperation()))
545 traceResets(node.getResult(), node.getInput(), node.getLoc());
547 if (op.isForceable())
548 traceResets(op.getDataType(), op.getData(), 0, op.getDataType(),
549 op.getDataRef(), 0, op.getLoc());
551 .Case<RWProbeOp>([&](RWProbeOp op) {
552 auto ist = irn.lookup(op.getTarget());
555 auto baseType = op.getType().getType();
556 traceResets(baseType, op.getResult(), 0, baseType.getPassiveType(),
557 ref.getValue(), ref.getFieldID(), op.getLoc());
559 .Case<UninferredResetCastOp, ConstCastOp, RefCastOp,
560 UnsafeDomainCastOp>([&](
auto op) {
561 traceResets(op.getResult(), op.getInput(), op.getLoc());
563 .Case<InvalidValueOp>([&](
auto op) {
572 auto type = op.getType();
575 LLVM_DEBUG(llvm::dbgs() <<
"Uniquify " << op <<
"\n");
576 ImplicitLocOpBuilder builder(op->getLoc(), op);
578 llvm::make_early_inc_range(
llvm::drop_begin(op->getUses()))) {
584 auto newOp = InvalidValueOp::create(builder, type);
589 .Case<SubfieldOp>([&](
auto op) {
592 BundleType bundleType = op.getInput().getType();
593 auto index = op.getFieldIndex();
594 traceResets(op.getType(), op.getResult(), 0,
595 bundleType.getElements()[index].type, op.getInput(),
599 .Case<SubindexOp, SubaccessOp>([&](
auto op) {
612 FVectorType vectorType = op.getInput().getType();
613 traceResets(op.getType(), op.getResult(), 0,
614 vectorType.getElementType(), op.getInput(),
618 .Case<RefSubOp>([&](RefSubOp op) {
620 auto aggType = op.getInput().getType().getType();
621 uint64_t fieldID = TypeSwitch<FIRRTLBaseType, uint64_t>(aggType)
622 .Case<FVectorType>([](
auto type) {
625 .Case<BundleType>([&](
auto type) {
628 traceResets(op.getType(), op.getResult(), 0,
629 op.getResult().getType(), op.getInput(), fieldID,
637void InferResetsPass::traceResets(FInstanceLike inst) {
638 LLVM_DEBUG(llvm::dbgs() <<
"Visiting instance " << inst.getInstanceName()
640 auto moduleNames = inst.getReferencedModuleNamesAttr();
641 for (
auto moduleName : moduleNames.getAsRange<StringAttr>()) {
642 auto *node = instanceGraph->lookup(moduleName);
643 auto module = dyn_cast<FModuleOp>(*node->getModule());
648 for (
const auto &it :
llvm::enumerate(inst->getResults())) {
649 Value dstPort =
module.getArgument(it.index());
650 Value srcPort = it.value();
651 if (module.getPortDirection(it.index()) == Direction::Out)
652 std::swap(dstPort, srcPort);
653 traceResets(dstPort, srcPort, it.value().getLoc());
660void InferResetsPass::traceResets(Value dst, Value src, Location loc) {
662 traceResets(dst.getType(), dst, 0, src.getType(), src, 0, loc);
667void InferResetsPass::traceResets(Type dstType, Value dst,
unsigned dstID,
668 Type srcType, Value src,
unsigned srcID,
670 if (
auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
671 auto srcBundle = type_cast<BundleType>(srcType);
672 for (
unsigned dstIdx = 0, e = dstBundle.getNumElements(); dstIdx < e;
674 auto dstField = dstBundle.getElements()[dstIdx].name;
675 auto srcIdx = srcBundle.getElementIndex(dstField);
678 auto &dstElt = dstBundle.getElements()[dstIdx];
679 auto &srcElt = srcBundle.getElements()[*srcIdx];
681 traceResets(srcElt.type, src, srcID +
getFieldID(srcBundle, *srcIdx),
682 dstElt.type, dst, dstID +
getFieldID(dstBundle, dstIdx),
685 traceResets(dstElt.type, dst, dstID +
getFieldID(dstBundle, dstIdx),
686 srcElt.type, src, srcID +
getFieldID(srcBundle, *srcIdx),
693 if (
auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
694 auto srcVector = type_cast<FVectorType>(srcType);
695 auto srcElType = srcVector.getElementType();
696 auto dstElType = dstVector.getElementType();
709 traceResets(dstElType, dst, dstID +
getFieldID(dstVector), srcElType, src,
715 if (
auto dstRef = type_dyn_cast<RefType>(dstType)) {
716 auto srcRef = type_cast<RefType>(srcType);
717 return traceResets(dstRef.getType(), dst, dstID, srcRef.getType(), src,
722 auto dstBase = type_dyn_cast<FIRRTLBaseType>(dstType);
723 auto srcBase = type_dyn_cast<FIRRTLBaseType>(srcType);
724 if (!dstBase || !srcBase)
726 if (!type_isa<ResetType>(dstBase) && !type_isa<ResetType>(srcBase))
731 LLVM_DEBUG(llvm::dbgs() <<
"Visiting driver '" << dstField <<
"' = '"
732 << srcField <<
"' (" << dstType <<
" = " << srcType
738 ResetSignal dstLeader =
739 *resetClasses.findLeader(resetClasses.insert({dstField, dstBase}));
740 ResetSignal srcLeader =
741 *resetClasses.findLeader(resetClasses.insert({srcField, srcBase}));
744 ResetSignal unionLeader = *resetClasses.unionSets(dstLeader, srcLeader);
745 assert(unionLeader == dstLeader || unionLeader == srcLeader);
750 if (dstLeader != srcLeader) {
751 auto &unionDrives = resetDrives[unionLeader];
752 auto mergedDrivesIt =
753 resetDrives.find(unionLeader == dstLeader ? srcLeader : dstLeader);
754 if (mergedDrivesIt != resetDrives.end()) {
755 unionDrives.append(mergedDrivesIt->second);
756 resetDrives.erase(mergedDrivesIt);
762 resetDrives[unionLeader].push_back(
763 {{dstField, dstBase}, {srcField, srcBase}, loc});
770LogicalResult InferResetsPass::inferAndUpdateResets() {
772 llvm::dbgs() <<
"\n";
775 for (
const auto &it : resetClasses) {
778 ResetNetwork net = resetClasses.members(*it);
781 auto kind = inferReset(net);
786 if (failed(updateReset(net, *kind)))
792FailureOr<ResetKind> InferResetsPass::inferReset(ResetNetwork net) {
793 LLVM_DEBUG(llvm::dbgs() <<
"Inferring reset network with "
794 << std::distance(net.begin(), net.end())
798 unsigned asyncDrives = 0;
799 unsigned syncDrives = 0;
800 unsigned invalidDrives = 0;
801 for (ResetSignal signal : net) {
803 if (type_isa<AsyncResetType>(signal.type))
805 else if (type_isa<UIntType>(signal.type))
808 isa_and_nonnull<InvalidValueOp>(
809 signal.field.getValue().getDefiningOp()))
812 LLVM_DEBUG(llvm::dbgs() <<
"- Found " << asyncDrives <<
" async, "
813 << syncDrives <<
" sync, " << invalidDrives
814 <<
" invalid drives\n");
817 if (asyncDrives == 0 && syncDrives == 0 && invalidDrives == 0) {
818 ResetSignal root = guessRoot(net);
819 auto diag = mlir::emitError(root.field.getValue().getLoc())
820 <<
"reset network never driven with concrete type";
821 for (ResetSignal signal : net)
822 diag.attachNote(signal.field.
getLoc()) <<
"here: ";
827 if (asyncDrives > 0 && syncDrives > 0) {
828 ResetSignal root = guessRoot(net);
829 bool majorityAsync = asyncDrives >= syncDrives;
830 auto diag = mlir::emitError(root.field.getValue().getLoc())
832 SmallString<32> fieldName;
834 diag <<
" \"" << fieldName <<
"\"";
835 diag <<
" simultaneously connected to async and sync resets";
836 diag.attachNote(root.field.getValue().getLoc())
837 <<
"majority of connections to this reset are "
838 << (majorityAsync ?
"async" :
"sync");
839 for (
auto &drive : getResetDrives(net)) {
840 if ((type_isa<AsyncResetType>(drive.dst.type) && !majorityAsync) ||
841 (type_isa<AsyncResetType>(drive.src.type) && !majorityAsync) ||
842 (type_isa<UIntType>(drive.dst.type) && majorityAsync) ||
843 (type_isa<UIntType>(drive.src.type) && majorityAsync))
844 diag.attachNote(drive.loc)
845 << (type_isa<AsyncResetType>(drive.src.type) ?
"async" :
"sync")
854 auto kind = (asyncDrives ? ResetKind::Async : ResetKind::Sync);
855 LLVM_DEBUG(llvm::dbgs() <<
"- Inferred as " << kind <<
"\n");
863LogicalResult InferResetsPass::updateReset(ResetNetwork net, ResetKind kind) {
864 LLVM_DEBUG(llvm::dbgs() <<
"Updating reset network with "
865 << std::distance(net.begin(), net.end())
866 <<
" nodes to " << kind <<
"\n");
870 if (kind == ResetKind::Async)
871 resetType = AsyncResetType::get(&getContext());
873 resetType = UIntType::get(&getContext(), 1);
879 SmallDenseSet<Operation *> moduleWorklist;
880 SmallDenseSet<std::pair<Operation *, Operation *>> extmoduleWorklist;
881 for (
auto signal : net) {
882 Value value = signal.field.getValue();
883 if (!isa<BlockArgument>(value) &&
884 !isa_and_nonnull<WireOp, RegOp, RegResetOp, FInstanceLike,
885 InvalidValueOp, ConstCastOp, RefCastOp,
886 UninferredResetCastOp, RWProbeOp, AsResetPrimOp>(
887 value.getDefiningOp()))
889 if (updateReset(signal.field, resetType)) {
890 for (
auto *user : value.getUsers())
891 worklist.insert(user);
892 if (
auto blockArg = dyn_cast<BlockArgument>(value)) {
893 moduleWorklist.insert(blockArg.getOwner()->getParentOp());
897 TypeSwitch<Operation *>(value.getDefiningOp())
898 .Case<FInstanceLike>([&](FInstanceLike op) {
899 for (
auto moduleName : op.getReferencedModuleNamesAttr()) {
900 auto *node = instanceGraph->lookup(cast<StringAttr>(moduleName));
901 if (
auto refModule = dyn_cast<FExtModuleOp>(*node->getModule()))
902 extmoduleWorklist.insert({refModule, op.getOperation()});
905 .Case<UninferredResetCastOp>([&](
auto op) {
906 op.replaceAllUsesWith(op.getInput());
909 .Case<AsResetPrimOp>([&](
auto op) {
912 Value result = op.getInput();
913 if (type_isa<AsyncResetType>(resetType)) {
914 ImplicitLocOpBuilder builder(op.getLoc(), op);
915 result = AsAsyncResetPrimOp::create(builder, op.getInput());
917 op.replaceAllUsesWith(result);
927 while (!worklist.empty()) {
928 auto *wop = worklist.pop_back_val();
929 SmallVector<Type, 2> types;
930 if (
auto op = dyn_cast<InferTypeOpInterface>(wop)) {
932 SmallVector<Type, 2> types;
933 if (failed(op.inferReturnTypes(op->getContext(), op->getLoc(),
934 op->getOperands(), op->getAttrDictionary(),
935 op->getPropertiesStorage(),
936 op->getRegions(), types)))
941 for (
auto it :
llvm::zip(op->getResults(), types)) {
942 auto newType = std::get<1>(it);
943 if (std::get<0>(it).getType() == newType)
945 std::get<0>(it).setType(newType);
946 for (
auto *user : std::
get<0>(it).getUsers())
947 worklist.insert(user);
949 LLVM_DEBUG(llvm::dbgs() <<
"- Inferred " << *op <<
"\n");
950 }
else if (
auto uop = dyn_cast<UninferredResetCastOp>(wop)) {
951 for (
auto *user : uop.getResult().getUsers())
952 worklist.insert(user);
953 uop.replaceAllUsesWith(uop.getInput());
954 LLVM_DEBUG(llvm::dbgs() <<
"- Inferred " << uop <<
"\n");
960 for (
auto *op : moduleWorklist) {
961 auto module = dyn_cast<FModuleOp>(op);
965 SmallVector<Attribute> argTypes;
966 argTypes.reserve(module.getNumPorts());
967 for (
auto arg : module.getArguments())
968 argTypes.push_back(TypeAttr::
get(arg.getType()));
970 module.setPortTypesAttr(ArrayAttr::get(op->getContext(), argTypes));
971 LLVM_DEBUG(llvm::dbgs()
972 <<
"- Updated type of module '" << module.getName() <<
"'\n");
976 for (
auto [mod, instOp] : extmoduleWorklist) {
977 auto module = cast<FExtModuleOp>(mod);
979 SmallVector<Attribute> types;
980 for (
auto type : instOp->getResultTypes())
981 types.push_back(TypeAttr::
get(type));
983 module.setPortTypesAttr(ArrayAttr::get(module->getContext(), types));
984 LLVM_DEBUG(llvm::dbgs()
985 <<
"- Updated type of extmodule '" << module.getName() <<
"'\n");
995 if (oldType.isGround()) {
1001 if (
auto bundleType = type_dyn_cast<BundleType>(oldType)) {
1003 SmallVector<BundleType::BundleElement> fields(bundleType.begin(),
1006 fields[index].type, fieldID -
getFieldID(bundleType, index), fieldType);
1007 return BundleType::get(oldType.getContext(), fields, bundleType.
isConst());
1011 if (
auto vectorType = type_dyn_cast<FVectorType>(oldType)) {
1012 auto newType =
updateType(vectorType.getElementType(),
1013 fieldID -
getFieldID(vectorType), fieldType);
1014 return FVectorType::get(newType, vectorType.getNumElements(),
1015 vectorType.isConst());
1018 llvm_unreachable(
"unknown aggregate type");
1025 auto oldType = type_cast<FIRRTLType>(field.
getValue().getType());
1031 if (oldType == newType)
1033 LLVM_DEBUG(llvm::dbgs() <<
"- Updating '" << field <<
"' from " << oldType
1034 <<
" to " << newType <<
"\n");
1039LogicalResult InferResetsPass::verifyNoAbstractReset() {
1040 bool hasAbstractResetPorts =
false;
1041 for (FModuleLike module :
1042 getOperation().
getBodyBlock()->getOps<FModuleLike>()) {
1043 for (
PortInfo port : module.getPorts()) {
1044 if (getBaseOfType<ResetType>(port.type)) {
1045 auto diag = emitError(port.loc)
1046 <<
"a port \"" << port.getName()
1047 <<
"\" with abstract reset type was unable to be "
1048 "inferred by InferResets (is this a top-level port?)";
1049 diag.attachNote(module->getLoc())
1050 <<
"the module with this uninferred reset port was defined here";
1051 hasAbstractResetPorts =
true;
1056 if (hasAbstractResetPorts)
assert(baseType &&"element must be base type")
static unsigned getFieldID(BundleType type, unsigned index)
static unsigned getIndexForFieldID(BundleType type, unsigned fieldID)
static FIRRTLBaseType updateType(FIRRTLBaseType oldType, unsigned fieldID, FIRRTLBaseType fieldType)
Update the type of a single field within a type.
static bool isUselessVec(FIRRTLBaseType oldType, unsigned fieldID)
static bool typeContainsReset(Type type)
Check whether a type contains a ResetType.
static bool getDeclName(Value value, SmallString< 32 > &string)
static unsigned getMaxFieldID(FIRRTLBaseType type)
static Location getLoc(DefSlot slot)
static Block * getBodyBlock(FModuleLike mod)
static InstancePath empty
This class represents a reference to a specific field or element of an aggregate value.
unsigned getFieldID() const
Get the field ID of this FieldRef, which is a unique identifier mapped to a specific field in a bundl...
Value getValue() const
Get the Value which created this location.
FIRRTLBaseType getConstType(bool isConst) const
Return a 'const' or non-'const' version of this type.
bool isConst() const
Returns true if this is a 'const' type that can only hold compile-time constant values.
This class implements the same functionality as TypeSwitch except that it uses firrtl::type_dyn_cast ...
FIRRTLTypeSwitch< T, ResultT > & Case(CallableT &&caseFn)
Add a case on the given type.
This graph tracks modules and where they are instantiated.
An instance path composed of a series of instances.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
FieldRef getFieldRefForTarget(const hw::InnerSymTarget &ist)
Get FieldRef pointing to the specified inner symbol target, which must be valid.
FIRRTLBaseType getBaseType(Type type)
If it is a base type, return it as is.
FIRRTLType mapBaseType(FIRRTLType type, function_ref< FIRRTLBaseType(FIRRTLBaseType)> fn)
Return a FIRRTLType with its base type component mutated by the given function.
llvm::raw_ostream & operator<<(llvm::raw_ostream &os, const InstanceInfo::LatticeValue &value)
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
LogicalResult runFullReset(CircuitOp circuit, InstanceGraph &ig, InstanceInfo &instanceInfo, bool convertAsyncDomainMems=false)
static bool operator==(const ModulePort &a, const ModulePort &b)
static llvm::hash_code hash_value(const ModulePort &port)
bool operator<(const DictEntry &entry, const DictEntry &other)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::raw_ostream & debugHeader(const llvm::Twine &str, unsigned width=80)
Write a "header"-like string to the debug stream with a certain width.
bool operator!=(uint64_t a, const FVInt &b)
This holds the name and type that describes the module's ports.
This class represents the namespace in which InnerRef's can be resolved.
A data structure that caches and provides paths to module instances in the IR.
static bool isEqual(const ResetSignal &lhs, const ResetSignal &rhs)
static unsigned getHashValue(const ResetSignal &x)