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 if (failed(verifyNoAbstractReset()))
309 return signalPassFailure();
312ResetSignal InferResetsPass::guessRoot(ResetNetwork net) {
313 ResetDrives &drives = getResetDrives(net);
314 ResetSignal bestSignal = *net.begin();
315 unsigned bestNumDrives = -1;
317 for (
auto signal : net) {
319 if (isa_and_nonnull<InvalidValueOp>(
320 signal.field.getValue().getDefiningOp()))
325 unsigned numDrives = 0;
326 for (
auto &drive : drives)
327 if (drive.dst == signal)
333 if (numDrives < bestNumDrives) {
334 bestNumDrives = numDrives;
353 .
Case<BundleType>([](
auto type) {
355 for (
auto e : type.getElements())
360 [](
auto type) {
return getMaxFieldID(type.getElementType()) + 1; })
361 .Default([](
auto) {
return 0; });
365 assert(index < type.getNumElements());
367 for (
unsigned i = 0; i < index; ++i)
375 assert(type.getNumElements() &&
"Bundle must have >0 fields");
377 for (
const auto &e : llvm::enumerate(type.getElements())) {
379 if (fieldID < numSubfields)
381 fieldID -= numSubfields;
383 assert(
false &&
"field id outside bundle");
389 if (oldType.isGround()) {
395 if (
auto bundleType = type_dyn_cast<BundleType>(oldType)) {
403 if (
auto vectorType = type_dyn_cast<FVectorType>(oldType)) {
404 if (vectorType.getNumElements() == 0)
421 if (
auto arg = dyn_cast<BlockArgument>(value)) {
422 auto module = cast<FModuleOp>(arg.getOwner()->getParentOp());
423 string +=
module.getPortName(arg.getArgNumber());
427 auto *op = value.getDefiningOp();
428 return TypeSwitch<Operation *, bool>(op)
429 .Case<InstanceOp, InstanceChoiceOp, MemOp>([&](
auto op) {
430 string += op.getName();
432 string += op.getPortName(cast<OpResult>(value).getResultNumber());
435 .Case<WireOp, NodeOp, RegOp, RegResetOp>([&](
auto op) {
436 string += op.getName();
439 .Default([](
auto) {
return false; });
443 SmallString<64> name;
448 auto type = value.getType();
451 if (
auto bundleType = type_dyn_cast<BundleType>(type)) {
454 auto &element = bundleType.getElements()[index];
457 string += element.name.getValue();
460 localID = localID -
getFieldID(bundleType, index);
461 }
else if (
auto vecType = type_dyn_cast<FVectorType>(type)) {
464 type = vecType.getElementType();
471 llvm_unreachable(
"unsupported type");
483 return TypeSwitch<Type, bool>(type)
485 return type.getRecursiveTypeProperties().hasUninferredReset;
487 .Default([](
auto) {
return false; });
494void InferResetsPass::traceResets(CircuitOp circuit) {
496 llvm::dbgs() <<
"\n";
497 debugHeader(
"Tracing uninferred resets") <<
"\n\n";
500 SmallVector<std::pair<FModuleOp, SmallVector<Operation *>>> moduleToOps;
502 for (
auto module : circuit.getOps<FModuleOp>())
503 moduleToOps.push_back({module, {}});
506 getAnalysis<hw::InnerSymbolTableCollection>()};
508 mlir::parallelForEach(circuit.getContext(), moduleToOps, [](
auto &e) {
509 e.first.walk([&](Operation *op) {
513 op->getResultTypes(),
514 [](mlir::Type type) { return typeContainsReset(type); }) ||
515 llvm::any_of(op->getOperandTypes(), typeContainsReset))
516 e.second.push_back(op);
520 for (
auto &[_, ops] : moduleToOps)
521 for (auto *op : ops) {
522 TypeSwitch<Operation *>(op)
523 .Case<FConnectLike>([&](
auto op) {
524 traceResets(op.getDest(), op.getSrc(), op.getLoc());
526 .Case<FInstanceLike>([&](
auto op) { traceResets(op); })
527 .Case<RefSendOp>([&](
auto op) {
529 traceResets(op.getType().getType(), op.getResult(), 0,
530 op.getBase().getType().getPassiveType(), op.getBase(),
533 .Case<RefResolveOp>([&](
auto op) {
535 traceResets(op.getType(), op.getResult(), 0,
536 op.getRef().getType().getType(), op.getRef(), 0,
539 .Case<Forceable>([&](Forceable op) {
540 if (
auto node = dyn_cast<NodeOp>(op.getOperation()))
541 traceResets(node.getResult(), node.getInput(), node.getLoc());
543 if (op.isForceable())
544 traceResets(op.getDataType(), op.getData(), 0, op.getDataType(),
545 op.getDataRef(), 0, op.getLoc());
547 .Case<RWProbeOp>([&](RWProbeOp op) {
548 auto ist = irn.lookup(op.getTarget());
551 auto baseType = op.getType().getType();
552 traceResets(baseType, op.getResult(), 0, baseType.getPassiveType(),
553 ref.getValue(), ref.getFieldID(), op.getLoc());
555 .Case<UninferredResetCastOp, ConstCastOp, RefCastOp,
556 UnsafeDomainCastOp>([&](
auto op) {
557 traceResets(op.getResult(), op.getInput(), op.getLoc());
559 .Case<InvalidValueOp>([&](
auto op) {
568 auto type = op.getType();
571 LLVM_DEBUG(llvm::dbgs() <<
"Uniquify " << op <<
"\n");
572 ImplicitLocOpBuilder builder(op->getLoc(), op);
574 llvm::make_early_inc_range(
llvm::drop_begin(op->getUses()))) {
580 auto newOp = InvalidValueOp::create(builder, type);
585 .Case<SubfieldOp>([&](
auto op) {
588 BundleType bundleType = op.getInput().getType();
589 auto index = op.getFieldIndex();
590 traceResets(op.getType(), op.getResult(), 0,
591 bundleType.getElements()[index].type, op.getInput(),
595 .Case<SubindexOp, SubaccessOp>([&](
auto op) {
608 FVectorType vectorType = op.getInput().getType();
609 traceResets(op.getType(), op.getResult(), 0,
610 vectorType.getElementType(), op.getInput(),
614 .Case<RefSubOp>([&](RefSubOp op) {
616 auto aggType = op.getInput().getType().getType();
617 uint64_t fieldID = TypeSwitch<FIRRTLBaseType, uint64_t>(aggType)
618 .Case<FVectorType>([](
auto type) {
621 .Case<BundleType>([&](
auto type) {
624 traceResets(op.getType(), op.getResult(), 0,
625 op.getResult().getType(), op.getInput(), fieldID,
633void InferResetsPass::traceResets(FInstanceLike inst) {
634 LLVM_DEBUG(llvm::dbgs() <<
"Visiting instance " << inst.getInstanceName()
636 auto moduleNames = inst.getReferencedModuleNamesAttr();
637 for (
auto moduleName : moduleNames.getAsRange<StringAttr>()) {
638 auto *node = instanceGraph->lookup(moduleName);
639 auto module = dyn_cast<FModuleOp>(*node->getModule());
644 for (
const auto &it :
llvm::enumerate(inst->getResults())) {
645 Value dstPort =
module.getArgument(it.index());
646 Value srcPort = it.value();
647 if (module.getPortDirection(it.index()) == Direction::Out)
648 std::swap(dstPort, srcPort);
649 traceResets(dstPort, srcPort, it.value().getLoc());
656void InferResetsPass::traceResets(Value dst, Value src, Location loc) {
658 traceResets(dst.getType(), dst, 0, src.getType(), src, 0, loc);
663void InferResetsPass::traceResets(Type dstType, Value dst,
unsigned dstID,
664 Type srcType, Value src,
unsigned srcID,
666 if (
auto dstBundle = type_dyn_cast<BundleType>(dstType)) {
667 auto srcBundle = type_cast<BundleType>(srcType);
668 for (
unsigned dstIdx = 0, e = dstBundle.getNumElements(); dstIdx < e;
670 auto dstField = dstBundle.getElements()[dstIdx].name;
671 auto srcIdx = srcBundle.getElementIndex(dstField);
674 auto &dstElt = dstBundle.getElements()[dstIdx];
675 auto &srcElt = srcBundle.getElements()[*srcIdx];
677 traceResets(srcElt.type, src, srcID +
getFieldID(srcBundle, *srcIdx),
678 dstElt.type, dst, dstID +
getFieldID(dstBundle, dstIdx),
681 traceResets(dstElt.type, dst, dstID +
getFieldID(dstBundle, dstIdx),
682 srcElt.type, src, srcID +
getFieldID(srcBundle, *srcIdx),
689 if (
auto dstVector = type_dyn_cast<FVectorType>(dstType)) {
690 auto srcVector = type_cast<FVectorType>(srcType);
691 auto srcElType = srcVector.getElementType();
692 auto dstElType = dstVector.getElementType();
705 traceResets(dstElType, dst, dstID +
getFieldID(dstVector), srcElType, src,
711 if (
auto dstRef = type_dyn_cast<RefType>(dstType)) {
712 auto srcRef = type_cast<RefType>(srcType);
713 return traceResets(dstRef.getType(), dst, dstID, srcRef.getType(), src,
718 auto dstBase = type_dyn_cast<FIRRTLBaseType>(dstType);
719 auto srcBase = type_dyn_cast<FIRRTLBaseType>(srcType);
720 if (!dstBase || !srcBase)
722 if (!type_isa<ResetType>(dstBase) && !type_isa<ResetType>(srcBase))
727 LLVM_DEBUG(llvm::dbgs() <<
"Visiting driver '" << dstField <<
"' = '"
728 << srcField <<
"' (" << dstType <<
" = " << srcType
734 ResetSignal dstLeader =
735 *resetClasses.findLeader(resetClasses.insert({dstField, dstBase}));
736 ResetSignal srcLeader =
737 *resetClasses.findLeader(resetClasses.insert({srcField, srcBase}));
740 ResetSignal unionLeader = *resetClasses.unionSets(dstLeader, srcLeader);
741 assert(unionLeader == dstLeader || unionLeader == srcLeader);
746 if (dstLeader != srcLeader) {
747 auto &unionDrives = resetDrives[unionLeader];
748 auto mergedDrivesIt =
749 resetDrives.find(unionLeader == dstLeader ? srcLeader : dstLeader);
750 if (mergedDrivesIt != resetDrives.end()) {
751 unionDrives.append(mergedDrivesIt->second);
752 resetDrives.erase(mergedDrivesIt);
758 resetDrives[unionLeader].push_back(
759 {{dstField, dstBase}, {srcField, srcBase}, loc});
766LogicalResult InferResetsPass::inferAndUpdateResets() {
768 llvm::dbgs() <<
"\n";
771 for (
const auto &it : resetClasses) {
774 ResetNetwork net = resetClasses.members(*it);
777 auto kind = inferReset(net);
782 if (failed(updateReset(net, *kind)))
788FailureOr<ResetKind> InferResetsPass::inferReset(ResetNetwork net) {
789 LLVM_DEBUG(llvm::dbgs() <<
"Inferring reset network with "
790 << std::distance(net.begin(), net.end())
794 unsigned asyncDrives = 0;
795 unsigned syncDrives = 0;
796 unsigned invalidDrives = 0;
797 for (ResetSignal signal : net) {
799 if (type_isa<AsyncResetType>(signal.type))
801 else if (type_isa<UIntType>(signal.type))
804 isa_and_nonnull<InvalidValueOp>(
805 signal.field.getValue().getDefiningOp()))
808 LLVM_DEBUG(llvm::dbgs() <<
"- Found " << asyncDrives <<
" async, "
809 << syncDrives <<
" sync, " << invalidDrives
810 <<
" invalid drives\n");
813 if (asyncDrives == 0 && syncDrives == 0 && invalidDrives == 0) {
814 ResetSignal root = guessRoot(net);
815 auto diag = mlir::emitError(root.field.getValue().getLoc())
816 <<
"reset network never driven with concrete type";
817 for (ResetSignal signal : net)
818 diag.attachNote(signal.field.
getLoc()) <<
"here: ";
823 if (asyncDrives > 0 && syncDrives > 0) {
824 ResetSignal root = guessRoot(net);
825 bool majorityAsync = asyncDrives >= syncDrives;
826 auto diag = mlir::emitError(root.field.getValue().getLoc())
828 SmallString<32> fieldName;
830 diag <<
" \"" << fieldName <<
"\"";
831 diag <<
" simultaneously connected to async and sync resets";
832 diag.attachNote(root.field.getValue().getLoc())
833 <<
"majority of connections to this reset are "
834 << (majorityAsync ?
"async" :
"sync");
835 for (
auto &drive : getResetDrives(net)) {
836 if ((type_isa<AsyncResetType>(drive.dst.type) && !majorityAsync) ||
837 (type_isa<AsyncResetType>(drive.src.type) && !majorityAsync) ||
838 (type_isa<UIntType>(drive.dst.type) && majorityAsync) ||
839 (type_isa<UIntType>(drive.src.type) && majorityAsync))
840 diag.attachNote(drive.loc)
841 << (type_isa<AsyncResetType>(drive.src.type) ?
"async" :
"sync")
850 auto kind = (asyncDrives ? ResetKind::Async : ResetKind::Sync);
851 LLVM_DEBUG(llvm::dbgs() <<
"- Inferred as " << kind <<
"\n");
859LogicalResult InferResetsPass::updateReset(ResetNetwork net, ResetKind kind) {
860 LLVM_DEBUG(llvm::dbgs() <<
"Updating reset network with "
861 << std::distance(net.begin(), net.end())
862 <<
" nodes to " << kind <<
"\n");
866 if (kind == ResetKind::Async)
867 resetType = AsyncResetType::get(&getContext());
869 resetType = UIntType::get(&getContext(), 1);
875 SmallDenseSet<Operation *> moduleWorklist;
876 SmallDenseSet<std::pair<Operation *, Operation *>> extmoduleWorklist;
877 for (
auto signal : net) {
878 Value value = signal.field.getValue();
879 if (!isa<BlockArgument>(value) &&
880 !isa_and_nonnull<WireOp, RegOp, RegResetOp, FInstanceLike,
881 InvalidValueOp, ConstCastOp, RefCastOp,
882 UninferredResetCastOp, RWProbeOp, AsResetPrimOp>(
883 value.getDefiningOp()))
885 if (updateReset(signal.field, resetType)) {
886 for (
auto *user : value.getUsers())
887 worklist.insert(user);
888 if (
auto blockArg = dyn_cast<BlockArgument>(value)) {
889 moduleWorklist.insert(blockArg.getOwner()->getParentOp());
893 TypeSwitch<Operation *>(value.getDefiningOp())
894 .Case<FInstanceLike>([&](FInstanceLike op) {
895 for (
auto moduleName : op.getReferencedModuleNamesAttr()) {
896 auto *node = instanceGraph->lookup(cast<StringAttr>(moduleName));
897 if (
auto refModule = dyn_cast<FExtModuleOp>(*node->getModule()))
898 extmoduleWorklist.insert({refModule, op.getOperation()});
901 .Case<UninferredResetCastOp>([&](
auto op) {
902 op.replaceAllUsesWith(op.getInput());
905 .Case<AsResetPrimOp>([&](
auto op) {
908 Value result = op.getInput();
909 if (type_isa<AsyncResetType>(resetType)) {
910 ImplicitLocOpBuilder builder(op.getLoc(), op);
911 result = AsAsyncResetPrimOp::create(builder, op.getInput());
913 op.replaceAllUsesWith(result);
923 while (!worklist.empty()) {
924 auto *wop = worklist.pop_back_val();
925 SmallVector<Type, 2> types;
926 if (
auto op = dyn_cast<InferTypeOpInterface>(wop)) {
928 SmallVector<Type, 2> types;
929 if (failed(op.inferReturnTypes(op->getContext(), op->getLoc(),
930 op->getOperands(), op->getAttrDictionary(),
931 op->getPropertiesStorage(),
932 op->getRegions(), types)))
937 for (
auto it :
llvm::zip(op->getResults(), types)) {
938 auto newType = std::get<1>(it);
939 if (std::get<0>(it).getType() == newType)
941 std::get<0>(it).setType(newType);
942 for (
auto *user : std::
get<0>(it).getUsers())
943 worklist.insert(user);
945 LLVM_DEBUG(llvm::dbgs() <<
"- Inferred " << *op <<
"\n");
946 }
else if (
auto uop = dyn_cast<UninferredResetCastOp>(wop)) {
947 for (
auto *user : uop.getResult().getUsers())
948 worklist.insert(user);
949 uop.replaceAllUsesWith(uop.getInput());
950 LLVM_DEBUG(llvm::dbgs() <<
"- Inferred " << uop <<
"\n");
956 for (
auto *op : moduleWorklist) {
957 auto module = dyn_cast<FModuleOp>(op);
961 SmallVector<Attribute> argTypes;
962 argTypes.reserve(module.getNumPorts());
963 for (
auto arg : module.getArguments())
964 argTypes.push_back(TypeAttr::
get(arg.getType()));
966 module.setPortTypesAttr(ArrayAttr::get(op->getContext(), argTypes));
967 LLVM_DEBUG(llvm::dbgs()
968 <<
"- Updated type of module '" << module.getName() <<
"'\n");
972 for (
auto [mod, instOp] : extmoduleWorklist) {
973 auto module = cast<FExtModuleOp>(mod);
975 SmallVector<Attribute> types;
976 for (
auto type : instOp->getResultTypes())
977 types.push_back(TypeAttr::
get(type));
979 module.setPortTypesAttr(ArrayAttr::get(module->getContext(), types));
980 LLVM_DEBUG(llvm::dbgs()
981 <<
"- Updated type of extmodule '" << module.getName() <<
"'\n");
991 if (oldType.isGround()) {
997 if (
auto bundleType = type_dyn_cast<BundleType>(oldType)) {
999 SmallVector<BundleType::BundleElement> fields(bundleType.begin(),
1002 fields[index].type, fieldID -
getFieldID(bundleType, index), fieldType);
1003 return BundleType::get(oldType.getContext(), fields, bundleType.
isConst());
1007 if (
auto vectorType = type_dyn_cast<FVectorType>(oldType)) {
1008 auto newType =
updateType(vectorType.getElementType(),
1009 fieldID -
getFieldID(vectorType), fieldType);
1010 return FVectorType::get(newType, vectorType.getNumElements(),
1011 vectorType.isConst());
1014 llvm_unreachable(
"unknown aggregate type");
1021 auto oldType = type_cast<FIRRTLType>(field.
getValue().getType());
1027 if (oldType == newType)
1029 LLVM_DEBUG(llvm::dbgs() <<
"- Updating '" << field <<
"' from " << oldType
1030 <<
" to " << newType <<
"\n");
1035LogicalResult InferResetsPass::verifyNoAbstractReset() {
1036 bool hasAbstractResetPorts =
false;
1037 for (FModuleLike module :
1038 getOperation().
getBodyBlock()->getOps<FModuleLike>()) {
1039 for (
PortInfo port : module.getPorts()) {
1040 if (getBaseOfType<ResetType>(port.type)) {
1041 auto diag = emitError(port.loc)
1042 <<
"a port \"" << port.getName()
1043 <<
"\" with abstract reset type was unable to be "
1044 "inferred by InferResets (is this a top-level port?)";
1045 diag.attachNote(module->getLoc())
1046 <<
"the module with this uninferred reset port was defined here";
1047 hasAbstractResetPorts =
true;
1052 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.
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)