24#include "mlir/IR/IRMapping.h"
25#include "mlir/IR/Threading.h"
26#include "mlir/Pass/Pass.h"
27#include "llvm/ADT/DenseMap.h"
28#include "llvm/ADT/DenseMapInfo.h"
29#include "llvm/ADT/Hashing.h"
30#include "llvm/ADT/PostOrderIterator.h"
31#include "llvm/ADT/SmallPtrSet.h"
32#include "llvm/Support/Format.h"
33#include "llvm/Support/SHA256.h"
37#define GEN_PASS_DEF_DEDUP
38#include "circt/Dialect/FIRRTL/Passes.h.inc"
43using namespace firrtl;
44using hw::InnerRefAttr;
53 if (!symbol.isPrivate())
58 if (isa<ClassLike>(*symbol))
63 if (!symbol.canDiscardOnUseEmpty())
73llvm::raw_ostream &
printHex(llvm::raw_ostream &stream,
74 ArrayRef<uint8_t> bytes) {
76 return stream << format_bytes(bytes, std::nullopt, 32) <<
"\n";
73llvm::raw_ostream &
printHex(llvm::raw_ostream &stream, {
…}
79llvm::raw_ostream &
printHash(llvm::raw_ostream &stream, llvm::SHA256 &
data) {
79llvm::raw_ostream &
printHash(llvm::raw_ostream &stream, llvm::SHA256 &
data) {
…}
83llvm::raw_ostream &
printHash(llvm::raw_ostream &stream, std::string
data) {
84 ArrayRef<uint8_t> bytes(
reinterpret_cast<const uint8_t *
>(
data.c_str()),
140 : constants(constants) {}
157 for (
auto [index, innerSym] : llvm::enumerate(module.getPortSymbols())) {
158 for (
auto prop : cast<hw::InnerSymAttr>(innerSym))
162 size_t index =
module.getNumPorts();
163 module.walk([&](hw::InnerSymbolOpInterface innerSymOp) {
164 if (auto innerSym = innerSymOp.getInnerSymAttr()) {
165 for (auto prop : innerSym)
166 innerSymIDTable[prop.getName()] = std::pair(index, prop.getFieldID());
174 auto [it, inserted] = idTable.try_emplace(
object, nextID);
182 auto it = idTable.find(
object);
183 if (it == idTable.end())
185 auto id = it->second;
191 return innerSymIDTable.at(name);
195 auto value = operand.get();
196 if (
auto result = dyn_cast<OpResult>(value)) {
197 auto *op = result.getOwner();
199 update(result.getResultNumber());
202 if (
auto argument = dyn_cast<BlockArgument>(value)) {
203 auto *block = argument.getOwner();
204 update(getID(block));
205 update(argument.getArgNumber());
208 llvm_unreachable(
"Unknown value type");
212 auto *
addr =
reinterpret_cast<const uint8_t *
>(&pointer);
213 sha.update(ArrayRef<uint8_t>(
addr,
sizeof pointer));
217 auto *
addr =
reinterpret_cast<const uint8_t *
>(&value);
218 sha.update(ArrayRef<uint8_t>(
addr,
sizeof value));
221 template <
typename T,
typename U>
222 void update(
const std::pair<T, U> &pair) {
231 update(type.getTypeID());
232 for (
auto &element : type.getElements()) {
233 update(element.isFlip);
234 update(element.type);
240 if (
auto bundle = type_dyn_cast<BundleType>(type))
241 return update(bundle);
242 update(type.getAsOpaquePointer());
249 if (
auto objectOp = dyn_cast<ObjectOp>(result.getOwner())) {
250 referredModuleNames.push_back(objectOp.getType().getNameAttr().getAttr());
254 update(result.getType());
259 void update(Operation *op, DictionaryAttr dict) {
260 for (
auto namedAttr : dict) {
261 auto name = namedAttr.getName();
262 auto value = namedAttr.getValue();
265 bool isClassPortNames =
266 isa<ClassLike>(op) && name == constants.portNamesAttr;
267 if (constants.nonessentialAttributes.contains(name) && !isClassPortNames)
271 update(name.getAsOpaquePointer());
274 if (name == constants.portTypesAttr) {
275 auto portTypes = cast<ArrayAttr>(value).getAsValueRange<TypeAttr>();
276 for (
auto type : portTypes)
286 if (isa<InstanceOp>(op) && name == constants.moduleNameAttr) {
287 referredModuleNames.push_back(cast<FlatSymbolRefAttr>(value).getAttr());
293 if (isa<DistinctAttr>(value))
297 if (
auto innerRef = dyn_cast<hw::InnerRefAttr>(value)) {
298 update(getInnerSymID(innerRef.getName()));
304 update(value.getAsOpaquePointer());
259 void update(Operation *op, DictionaryAttr dict) {
…}
310 update(name.getAsOpaquePointer());
315 for (
auto &op : llvm::reverse(*block))
317 for (
auto type : block->getArgumentTypes())
319 update(finalizeID(block));
326 for (
auto &block : llvm::reverse(region->getBlocks()))
336 update(op->getNumRegions());
337 for (
auto ®ion : reverse(op->getRegions()))
340 update(op->getName());
343 for (
auto &operand : op->getOpOperands())
348 update(op, op->getAttrDictionary());
351 for (
auto result : op->getResults())
355 update(finalizeID(op));
413 SmallString<64> buffer;
414 llvm::raw_svector_ostream os(buffer);
415 if (
auto integerAttr = dyn_cast<IntegerAttr>(attr)) {
417 if (integerAttr.getType().isSignlessInteger())
418 integerAttr.getValue().toStringUnsigned(buffer, 16);
420 integerAttr.getAPSInt().toString(buffer, 16);
424 return std::string(buffer);
428 LogicalResult
check(InFlightDiagnostic &diag,
const Twine &message,
429 Operation *a, BundleType aType, Operation *b,
431 if (aType.getNumElements() != bType.getNumElements()) {
432 diag.attachNote(a->getLoc())
433 << message <<
" bundle type has different number of elements";
434 diag.attachNote(b->getLoc()) <<
"second operation here";
438 for (
auto elementPair :
439 llvm::zip(aType.getElements(), bType.getElements())) {
440 auto aElement = std::get<0>(elementPair);
441 auto bElement = std::get<1>(elementPair);
442 if (aElement.isFlip != bElement.isFlip) {
443 diag.attachNote(a->getLoc()) << message <<
" bundle element "
444 << aElement.name <<
" flip does not match";
445 diag.attachNote(b->getLoc()) <<
"second operation here";
449 if (failed(
check(diag,
450 "bundle element \'" + aElement.name.getValue() +
"'", a,
451 aElement.type, b, bElement.type)))
428 LogicalResult
check(InFlightDiagnostic &diag,
const Twine &message, {
…}
457 LogicalResult
check(InFlightDiagnostic &diag,
const Twine &message,
458 Operation *a, Type aType, Operation *b, Type bType) {
461 if (
auto aBundleType = type_dyn_cast<BundleType>(aType))
462 if (
auto bBundleType = type_dyn_cast<BundleType>(bType))
463 return check(diag, message, a, aBundleType, b, bBundleType);
464 if (type_isa<RefType>(aType) && type_isa<RefType>(bType) &&
466 diag.attachNote(a->getLoc())
467 << message <<
", has a RefType with a different base type "
468 << type_cast<RefType>(aType).getType()
469 <<
" in the same position of the two modules marked as 'must dedup'. "
470 "(This may be due to Grand Central Taps or Views being different "
471 "between the two modules.)";
472 diag.attachNote(b->getLoc())
473 <<
"the second module has a different base type "
474 << type_cast<RefType>(bType).getType();
477 diag.attachNote(a->getLoc())
478 << message <<
" types don't match, first type is " << aType;
479 diag.attachNote(b->getLoc()) <<
"second type is " << bType;
457 LogicalResult
check(InFlightDiagnostic &diag,
const Twine &message, {
…}
484 Block &aBlock, Operation *b, Block &bBlock) {
487 auto portNames = a->getAttrOfType<ArrayAttr>(
"portNames");
489 auto emitMissingPort = [&](Value existsVal, Operation *opExists,
490 Operation *opDoesNotExist) {
492 auto portNames = opExists->getAttrOfType<ArrayAttr>(
"portNames");
494 if (
auto portNameAttr = dyn_cast<StringAttr>(portNames[portNo]))
495 portName = portNameAttr.getValue();
496 if (type_isa<RefType>(existsVal.getType())) {
497 diag.attachNote(opExists->getLoc())
498 <<
" contains a RefType port named '" + portName +
499 "' that only exists in one of the modules (can be due to "
500 "difference in Grand Central Tap or View of two modules "
501 "marked with must dedup)";
502 diag.attachNote(opDoesNotExist->getLoc())
503 <<
"second module to be deduped that does not have the RefType "
506 diag.attachNote(opExists->getLoc())
507 <<
"port '" + portName +
"' only exists in one of the modules";
508 diag.attachNote(opDoesNotExist->getLoc())
509 <<
"second module to be deduped that does not have the port";
515 llvm::zip_longest(aBlock.getArguments(), bBlock.getArguments())) {
516 auto &aArg = std::get<0>(argPair);
517 auto &bArg = std::get<1>(argPair);
518 if (aArg.has_value() && bArg.has_value()) {
523 if (
auto portNameAttr = dyn_cast<StringAttr>(portNames[portNo]))
524 portName = portNameAttr.getValue();
527 if (failed(
check(diag,
"module port '" + portName +
"'", a,
528 aArg->getType(), b, bArg->getType())))
530 data.map.map(aArg.value(), bArg.value());
534 if (!aArg.has_value())
536 return emitMissingPort(aArg.has_value() ? aArg.value() : bArg.value(), a,
541 auto aIt = aBlock.begin();
542 auto aEnd = aBlock.end();
543 auto bIt = bBlock.begin();
544 auto bEnd = bBlock.end();
545 while (aIt != aEnd && bIt != bEnd)
546 if (failed(
check(diag,
data, &*aIt++, &*bIt++)))
549 diag.attachNote(aIt->getLoc()) <<
"first block has more operations";
550 diag.attachNote(b->getLoc()) <<
"second block here";
554 diag.attachNote(bIt->getLoc()) <<
"second block has more operations";
555 diag.attachNote(a->getLoc()) <<
"first block here";
562 Region &aRegion, Operation *b, Region &bRegion) {
563 auto aIt = aRegion.begin();
564 auto aEnd = aRegion.end();
565 auto bIt = bRegion.begin();
566 auto bEnd = bRegion.end();
569 while (aIt != aEnd && bIt != bEnd)
570 if (failed(
check(diag,
data, a, *aIt++, b, *bIt++)))
572 if (aIt != aEnd || bIt != bEnd) {
573 diag.attachNote(a->getLoc())
574 <<
"operation regions have different number of blocks";
575 diag.attachNote(b->getLoc()) <<
"second operation here";
581 LogicalResult
check(InFlightDiagnostic &diag, Operation *a,
582 mlir::DenseBoolArrayAttr aAttr, Operation *b,
583 mlir::DenseBoolArrayAttr bAttr) {
586 auto portNames = a->getAttrOfType<ArrayAttr>(
"portNames");
587 for (
unsigned i = 0, e = aAttr.size(); i < e; ++i) {
588 auto aDirection = aAttr[i];
589 auto bDirection = bAttr[i];
590 if (aDirection != bDirection) {
591 auto ¬e = diag.attachNote(a->getLoc()) <<
"module port ";
593 note <<
"'" << cast<StringAttr>(portNames[i]).getValue() <<
"'";
596 note <<
" directions don't match, first direction is '"
598 diag.attachNote(b->getLoc()) <<
"second direction is '"
581 LogicalResult
check(InFlightDiagnostic &diag, Operation *a, {
…}
607 DictionaryAttr aDict, Operation *b,
608 DictionaryAttr bDict) {
613 DenseSet<Attribute> seenAttrs;
614 for (
auto namedAttr : aDict) {
615 auto attrName = namedAttr.getName();
619 auto aAttr = namedAttr.getValue();
620 auto bAttr = bDict.get(attrName);
622 diag.attachNote(a->getLoc())
623 <<
"second operation is missing attribute " << attrName;
624 diag.attachNote(b->getLoc()) <<
"second operation here";
628 if (isa<hw::InnerRefAttr>(aAttr) && isa<hw::InnerRefAttr>(bAttr)) {
629 auto bRef = cast<hw::InnerRefAttr>(bAttr);
630 auto aRef = cast<hw::InnerRefAttr>(aAttr);
632 auto aTarget =
data.a.lookup(aRef.getName());
633 auto bTarget =
data.b.lookup(bRef.getName());
634 if (!aTarget || !bTarget)
635 diag.attachNote(a->getLoc())
636 <<
"malformed ir, possibly violating use-before-def";
638 diag.attachNote(a->getLoc())
639 <<
"operations have different targets, first operation has "
641 diag.attachNote(b->getLoc()) <<
"second operation has " << bTarget;
644 if (aTarget.isPort()) {
646 if (!bTarget.isPort() || aTarget.getPort() != bTarget.getPort())
650 if (!bTarget.isOpOnly() ||
651 aTarget.getOp() !=
data.map.lookup(bTarget.getOp()))
654 if (aTarget.getField() != bTarget.getField())
659 if (failed(
check(diag, a, cast<mlir::DenseBoolArrayAttr>(aAttr), b,
660 cast<mlir::DenseBoolArrayAttr>(bAttr))))
662 }
else if (isa<DistinctAttr>(aAttr) && isa<DistinctAttr>(bAttr)) {
665 }
else if (aAttr != bAttr) {
666 diag.attachNote(a->getLoc())
667 <<
"first operation has attribute '" << attrName.getValue()
669 diag.attachNote(b->getLoc())
670 <<
"second operation has value " <<
prettyPrint(bAttr);
673 seenAttrs.insert(attrName);
675 if (aDict.getValue().size() != bDict.getValue().size()) {
676 for (
auto namedAttr : bDict) {
677 auto attrName = namedAttr.getName();
681 seenAttrs.contains(attrName))
684 diag.attachNote(a->getLoc())
685 <<
"first operation is missing attribute " << attrName;
686 diag.attachNote(b->getLoc()) <<
"second operation here";
694 LogicalResult
check(InFlightDiagnostic &diag, FInstanceLike a,
696 auto aName = a.getReferencedModuleNameAttr();
697 auto bName = b.getReferencedModuleNameAttr();
707 diag.attachNote(std::nullopt)
708 <<
"in instance " << a.getInstanceNameAttr() <<
" of " << aName
709 <<
", and instance " << b.getInstanceNameAttr() <<
" of " << bName;
710 check(diag, aModule, bModule);
694 LogicalResult
check(InFlightDiagnostic &diag, FInstanceLike a, {
…}
718 if (a->getName() != b->getName()) {
719 diag.attachNote(a->getLoc()) <<
"first operation is a " << a->getName();
720 diag.attachNote(b->getLoc()) <<
"second operation is a " << b->getName();
726 if (
auto aInst = dyn_cast<FInstanceLike>(a)) {
727 auto bInst = cast<FInstanceLike>(b);
728 if (failed(
check(diag, aInst, bInst)))
733 if (a->getNumResults() != b->getNumResults()) {
734 diag.attachNote(a->getLoc())
735 <<
"operations have different number of results";
736 diag.attachNote(b->getLoc()) <<
"second operation here";
739 for (
auto resultPair : llvm::zip(a->getResults(), b->getResults())) {
740 auto &aValue = std::get<0>(resultPair);
741 auto &bValue = std::get<1>(resultPair);
742 if (failed(
check(diag,
"operation result", a, aValue.getType(), b,
745 data.map.map(aValue, bValue);
749 if (a->getNumOperands() != b->getNumOperands()) {
750 diag.attachNote(a->getLoc())
751 <<
"operations have different number of operands";
752 diag.attachNote(b->getLoc()) <<
"second operation here";
755 for (
auto operandPair : llvm::zip(a->getOperands(), b->getOperands())) {
756 auto &aValue = std::get<0>(operandPair);
757 auto &bValue = std::get<1>(operandPair);
758 if (bValue !=
data.map.lookup(aValue)) {
759 diag.attachNote(a->getLoc())
760 <<
"operations use different operands, first operand is '"
765 diag.attachNote(b->getLoc())
766 <<
"second operand is '"
770 <<
"', but should have been '"
781 if (a->getNumRegions() != b->getNumRegions()) {
782 diag.attachNote(a->getLoc())
783 <<
"operations have different number of regions";
784 diag.attachNote(b->getLoc()) <<
"second operation here";
787 for (
auto regionPair : llvm::zip(a->getRegions(), b->getRegions())) {
788 auto &aRegion = std::get<0>(regionPair);
789 auto &bRegion = std::get<1>(regionPair);
790 if (failed(
check(diag,
data, a, aRegion, b, bRegion)))
795 if (failed(
check(diag,
data, a, a->getAttrDictionary(), b,
796 b->getAttrDictionary())))
802 void check(InFlightDiagnostic &diag, Operation *a, Operation *b) {
807 diag.attachNote(a->getLoc()) <<
"module marked NoDedup";
811 diag.attachNote(b->getLoc()) <<
"module marked NoDedup";
814 auto aSymbol = cast<mlir::SymbolOpInterface>(a);
815 auto bSymbol = cast<mlir::SymbolOpInterface>(b);
817 diag.attachNote(a->getLoc())
819 << (aSymbol.isPrivate() ?
"private but not discardable" :
"public");
823 diag.attachNote(b->getLoc())
825 << (bSymbol.isPrivate() ?
"private but not discardable" :
"public");
830 auto bGroup = dyn_cast_or_null<StringAttr>(
832 if (aGroup != bGroup) {
834 diag.attachNote(b->getLoc())
835 <<
"module is in dedup group '" << bGroup.str() <<
"'";
837 diag.attachNote(b->getLoc()) <<
"module is not part of a dedup group";
840 diag.attachNote(a->getLoc())
841 <<
"module is in dedup group '" << aGroup.str() <<
"'";
843 diag.attachNote(a->getLoc()) <<
"module is not part of a dedup group";
849 diag.attachNote(a->getLoc()) <<
"first module here";
850 diag.attachNote(b->getLoc()) <<
"second module here";
802 void check(InFlightDiagnostic &diag, Operation *a, Operation *b) {
…}
874static Location
mergeLoc(MLIRContext *context, Location to, Location from) {
876 llvm::SmallSetVector<Location, 4> decomposedLocs;
878 unsigned seenFIR = 0;
879 for (
auto loc : {to, from}) {
882 if (
auto fusedLoc = dyn_cast<FusedLoc>(loc)) {
885 for (
auto loc : fusedLoc.getLocations()) {
886 if (FileLineColLoc fileLoc = dyn_cast<FileLineColLoc>(loc)) {
887 if (fileLoc.getFilename().strref().ends_with(
".fir")) {
893 decomposedLocs.insert(loc);
899 if (FileLineColLoc fileLoc = dyn_cast<FileLineColLoc>(loc)) {
900 if (fileLoc.getFilename().strref().ends_with(
".fir")) {
907 if (!isa<UnknownLoc>(loc))
908 decomposedLocs.insert(loc);
911 auto locs = decomposedLocs.getArrayRef();
916 return UnknownLoc::get(context);
917 if (locs.size() == 1)
920 return FusedLoc::get(context, locs);
874static Location
mergeLoc(MLIRContext *context, Location to, Location from) {
…}
935 for (
auto nla : circuit.getOps<hw::HierPathOp>())
936 nlaCache[nla.getNamepathAttr()] = nla.getSymNameAttr();
943 void dedup(FModuleLike toModule, FModuleLike fromModule) {
949 SmallVector<Attribute> newLocs;
950 for (
auto [toLoc, fromLoc] : llvm::zip(toModule.getPortLocations(),
951 fromModule.getPortLocations())) {
952 if (toLoc == fromLoc)
953 newLocs.push_back(toLoc);
956 cast<LocationAttr>(fromLoc)));
958 toModule->setAttr(
"portLocations", ArrayAttr::get(
context, newLocs));
961 mergeOps(renameMap, toModule, toModule, fromModule, fromModule);
967 if (
auto to = dyn_cast<FModuleOp>(*toModule))
971 fromModule.getModuleNameAttr());
943 void dedup(FModuleLike toModule, FModuleLike fromModule) {
…}
982 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i)
985 module->walk([&](Operation *op) { recordAnnotations(op); });
991 return moduleNamespaces.try_emplace(module, cast<FModuleLike>(module))
999 if (
auto nlaRef = anno.getMember<FlatSymbolRefAttr>(
"circt.nonlocal"))
1000 targetMap[nlaRef.getAttr()].insert(target);
1009 auto mem = dyn_cast<MemOp>(op);
1014 for (
unsigned i = 0, e = mem->getNumResults(); i < e; ++i)
1023 instanceGraph[::cast<igraph::ModuleOpInterface>(fromModule)];
1024 auto *toNode = instanceGraph[toModule];
1025 auto toModuleRef = FlatSymbolRefAttr::get(toModule.getModuleNameAttr());
1026 for (
auto *oldInstRec : llvm::make_early_inc_range(fromNode->uses())) {
1027 auto inst = oldInstRec->getInstance();
1028 if (
auto instOp = dyn_cast<InstanceOp>(*inst)) {
1029 instOp.setModuleNameAttr(toModuleRef);
1030 instOp.setPortNamesAttr(toModule.getPortNamesAttr());
1031 }
else if (
auto objectOp = dyn_cast<ObjectOp>(*inst)) {
1032 auto classLike = cast<ClassLike>(*toNode->getModule());
1033 ClassType classType = detail::getInstanceTypeForClassLike(classLike);
1034 objectOp.getResult().setType(classType);
1036 oldInstRec->getParent()->addInstance(inst, toNode);
1037 oldInstRec->erase();
1039 instanceGraph.erase(fromNode);
1040 fromModule->erase();
1048 SmallVector<FlatSymbolRefAttr>
1049 createNLAs(Operation *fromModule, ArrayRef<Attribute> baseNamepath,
1050 SymbolTable::Visibility vis = SymbolTable::Visibility::Private) {
1053 SmallVector<Attribute> namepath = {
nullptr};
1054 namepath.append(baseNamepath.begin(), baseNamepath.end());
1056 auto loc = fromModule->getLoc();
1057 auto *fromNode = instanceGraph[cast<igraph::ModuleOpInterface>(fromModule)];
1058 SmallVector<FlatSymbolRefAttr> nlas;
1059 for (
auto *instanceRecord : fromNode->uses()) {
1060 auto parent = cast<FModuleOp>(*instanceRecord->getParent()->getModule());
1061 auto inst = instanceRecord->getInstance();
1063 auto arrayAttr = ArrayAttr::get(context, namepath);
1065 auto &cacheEntry = nlaCache[arrayAttr];
1067 auto nla = OpBuilder::atBlockBegin(nlaBlock).create<hw::HierPathOp>(
1068 loc,
"nla", arrayAttr);
1070 symbolTable.insert(nla);
1072 cacheEntry = nla.getNameAttr();
1073 nla.setVisibility(vis);
1074 nlaTable->addNLA(nla);
1076 auto nlaRef = FlatSymbolRefAttr::get(cast<StringAttr>(cacheEntry));
1077 nlas.push_back(nlaRef);
1049 createNLAs(Operation *fromModule, ArrayRef<Attribute> baseNamepath, {
…}
1085 SmallVector<FlatSymbolRefAttr>
1087 SymbolTable::Visibility vis = SymbolTable::Visibility::Private) {
1088 return createNLAs(fromModule, FlatSymbolRefAttr::get(toModuleName), vis);
1095 Annotation anno, ArrayRef<NamedAttribute> attributes,
1096 unsigned nonLocalIndex,
1097 SmallVectorImpl<Annotation> &newAnnotations) {
1098 SmallVector<NamedAttribute> mutableAttributes(attributes.begin(),
1100 for (
auto &nla : nlas) {
1102 mutableAttributes[nonLocalIndex].setValue(nla);
1103 auto dict = DictionaryAttr::getWithSorted(context, mutableAttributes);
1106 newAnnotations.push_back(anno);
1115 targetMap.erase(nla.getNameAttr());
1116 nlaTable->erase(nla);
1117 nlaCache.erase(nla.getNamepathAttr());
1118 symbolTable.erase(nla);
1124 FModuleOp fromModule) {
1125 auto toName = toModule.getNameAttr();
1126 auto fromName = fromModule.getNameAttr();
1129 auto moduleNLAs = nlaTable->lookup(fromModule.getNameAttr()).vec();
1131 nlaTable->renameModuleAndInnerRef(toName, fromName, renameMap);
1134 for (
auto nla : moduleNLAs) {
1135 auto elements = nla.getNamepath().getValue();
1137 if (nla.root() != toName)
1140 SmallVector<Attribute> namepath(elements.begin(), elements.end());
1141 auto nlaRefs = createNLAs(fromModule, namepath, nla.getVisibility());
1143 auto &set = targetMap[nla.getSymNameAttr()];
1144 SmallVector<AnnoTarget> targets(set.begin(), set.end());
1146 for (
auto target : targets) {
1149 SmallVector<Annotation> newAnnotations;
1150 for (
auto anno : target.getAnnotations()) {
1152 auto [it, found] = mlir::impl::findAttrSorted(
1153 anno.begin(), anno.end(), nonLocalString);
1156 if (!found || cast<FlatSymbolRefAttr>(it->getValue()).getAttr() !=
1157 nla.getSymNameAttr()) {
1158 newAnnotations.push_back(anno);
1161 auto nonLocalIndex = std::distance(anno.begin(), it);
1163 cloneAnnotation(nlaRefs, anno,
1164 ArrayRef<NamedAttribute>(anno.begin(), anno.end()),
1165 nonLocalIndex, newAnnotations);
1170 target.setAnnotations(annotations);
1172 for (
auto nla : nlaRefs)
1173 targetMap[nla.getAttr()].insert(target);
1185 FModuleOp fromModule) {
1186 addAnnotationContext(renameMap, toModule, toModule);
1187 addAnnotationContext(renameMap, toModule, fromModule);
1193 StringAttr fromName) {
1194 nlaTable->renameModuleAndInnerRef(toName, fromName, renameMap);
1202 SmallVectorImpl<Annotation> &newAnnotations) {
1205 SmallVector<NamedAttribute> attributes;
1206 int nonLocalIndex = -1;
1207 for (
const auto &val : llvm::enumerate(anno)) {
1208 auto attr = val.value();
1210 auto compare = attr.getName().compare(nonLocalString);
1211 assert(compare != 0 &&
"should not pass non-local annotations here");
1215 nonLocalIndex = val.index();
1216 attributes.push_back(NamedAttribute(nonLocalString, nonLocalString));
1221 attributes.push_back(attr);
1223 if (nonLocalIndex == -1) {
1225 nonLocalIndex = attributes.size();
1226 attributes.push_back(NamedAttribute(nonLocalString, nonLocalString));
1229 attributes.append(anno.
begin() + nonLocalIndex, anno.
end());
1233 auto nlaRefs = createNLAs(toModuleName, fromModule);
1234 for (
auto nla : nlaRefs)
1235 targetMap[nla.getAttr()].insert(to);
1238 cloneAnnotation(nlaRefs, anno, attributes, nonLocalIndex, newAnnotations);
1244 SmallVectorImpl<Annotation> &newAnnotations,
1245 SmallPtrSetImpl<Attribute> &dontTouches) {
1246 for (
auto anno : annos) {
1250 anno.removeMember(
"circt.nonlocal");
1251 auto [it, inserted] = dontTouches.insert(anno.getAttr());
1253 newAnnotations.push_back(anno);
1258 if (
auto nla = anno.getMember<FlatSymbolRefAttr>(
"circt.nonlocal")) {
1259 newAnnotations.push_back(anno);
1260 targetMap[nla.getAttr()].insert(to);
1264 makeAnnotationNonLocal(toModule.getModuleNameAttr(), to, fromModule, anno,
1275 SmallVector<Annotation> newAnnotations;
1279 llvm::SmallPtrSet<Attribute, 4> dontTouches;
1283 copyAnnotations(toModule, to, toModule, toAnnos, newAnnotations,
1285 copyAnnotations(toModule, to, fromModule, fromAnnos, newAnnotations,
1289 if (!newAnnotations.empty())
1295 FModuleLike fromModule, Operation *from) {
1301 if (toModule == to) {
1303 for (
unsigned i = 0, e =
getNumPorts(toModule); i < e; ++i)
1308 }
else if (
auto toMem = dyn_cast<MemOp>(to)) {
1310 auto fromMem = cast<MemOp>(from);
1311 for (
unsigned i = 0, e = toMem.getNumResults(); i < e; ++i)
1320 hw::InnerSymAttr toSym,
1321 hw::InnerSymAttr fromSym) {
1322 if (fromSym && !fromSym.getProps().empty()) {
1323 auto &isn = getNamespace(toModule);
1325 SmallVector<hw::InnerSymPropertiesAttr> newProps;
1328 llvm::append_range(newProps, toSym);
1330 for (
auto fromProp : fromSym) {
1331 hw::InnerSymPropertiesAttr newProp;
1332 auto *it = llvm::find_if(newProps, [&](
auto p) {
1333 return p.getFieldID() == fromProp.getFieldID();
1335 if (it != newProps.end()) {
1340 if (fromProp.getSymVisibility().getValue() ==
"public" &&
1341 newProp.getSymVisibility().getValue() !=
"public") {
1342 *it = hw::InnerSymPropertiesAttr::get(context, newProp.getName(),
1343 newProp.getFieldID(),
1344 fromProp.getSymVisibility());
1348 auto newName = isn.newName(fromProp.getName().getValue());
1349 newProp = hw::InnerSymPropertiesAttr::get(
1350 context, StringAttr::get(context, newName), fromProp.getFieldID(),
1351 fromProp.getSymVisibility());
1352 newProps.push_back(newProp);
1354 renameMap[fromProp.getName()] = newProp.getName();
1357 llvm::sort(newProps, [](
auto &p,
auto &q) {
1358 return p.getFieldID() < q.getFieldID();
1361 return hw::InnerSymAttr::get(context, newProps);
1363 return hw::InnerSymAttr();
1370 Operation *to, FModuleLike fromModule,
1374 if (
auto fromInnerSym = dyn_cast<hw::InnerSymbolOpInterface>(from)) {
1375 auto toInnerSym = cast<hw::InnerSymbolOpInterface>(to);
1376 if (
auto newSymAttr = mergeInnerSymbols(renameMap, toModule,
1377 toInnerSym.getInnerSymAttr(),
1378 fromInnerSym.getInnerSymAttr()))
1379 toInnerSym.setInnerSymbolAttr(newSymAttr);
1383 auto fromPortSyms = from->getAttrOfType<ArrayAttr>(
"portSymbols");
1384 if (!fromPortSyms || fromPortSyms.empty())
1387 auto portCount = fromPortSyms.size();
1388 auto toPortSyms = to->getAttrOfType<ArrayAttr>(
"portSymbols");
1392 SmallVector<Attribute> newPortSyms;
1393 if (toPortSyms.empty())
1394 newPortSyms.assign(portCount, hw::InnerSymAttr());
1396 newPortSyms.assign(toPortSyms.begin(), toPortSyms.end());
1398 for (
unsigned portNo = 0; portNo < portCount; ++portNo) {
1399 if (
auto newPortSym = mergeInnerSymbols(
1400 renameMap, toModule,
1401 llvm::cast_if_present<hw::InnerSymAttr>(newPortSyms[portNo]),
1402 cast<hw::InnerSymAttr>(fromPortSyms[portNo]))) {
1403 newPortSyms[portNo] = newPortSym;
1408 FModuleLike::fixupPortSymsArray(newPortSyms, toModule.getContext());
1409 cast<FModuleLike>(to).setPortSymbols(newPortSyms);
1415 FModuleLike fromModule, Operation *from) {
1417 if (to->getLoc() != from->getLoc())
1418 to->setLoc(
mergeLoc(context, to->getLoc(), from->getLoc()));
1421 for (
auto regions : llvm::zip(to->getRegions(), from->getRegions()))
1422 mergeRegions(renameMap, toModule, std::get<0>(regions), fromModule,
1423 std::get<1>(regions));
1426 recordSymRenames(renameMap, toModule, to, fromModule, from);
1429 mergeAnnotations(toModule, to, fromModule, from);
1434 FModuleLike fromModule, Block &fromBlock) {
1436 for (
auto [toArg, fromArg] :
1437 llvm::zip(toBlock.getArguments(), fromBlock.getArguments()))
1438 if (toArg.getLoc() != fromArg.getLoc())
1439 toArg.setLoc(
mergeLoc(context, toArg.getLoc(), fromArg.getLoc()));
1441 for (
auto ops : llvm::zip(toBlock, fromBlock))
1442 mergeOps(renameMap, toModule, &std::get<0>(ops), fromModule,
1448 Region &toRegion, FModuleLike fromModule,
1449 Region &fromRegion) {
1450 for (
auto blocks : llvm::zip(toRegion, fromRegion))
1451 mergeBlocks(renameMap, toModule, std::get<0>(blocks), fromModule,
1452 std::get<1>(blocks));
1466 DenseMap<Attribute, llvm::SmallDenseSet<AnnoTarget>>
targetMap;
1490 SmallVector<Attribute> newPortTypes;
1491 bool anyDifferences =
false;
1494 for (
size_t i = 0, e = classOp.getNumPorts(); i < e; ++i) {
1497 auto portClassType = dyn_cast<ClassType>(classOp.getPortType(i));
1498 if (!portClassType) {
1499 newPortTypes.push_back(classOp.getPortTypeAttr(i));
1504 Type newPortClassType;
1505 BlockArgument portArg = classOp.getArgument(i);
1506 for (
auto &use : portArg.getUses()) {
1507 if (
auto propassign = dyn_cast<PropAssignOp>(use.getOwner())) {
1508 Type sourceType = propassign.getSrc().getType();
1509 if (propassign.getDest() == use.get() && sourceType != portClassType) {
1511 if (newPortClassType) {
1512 assert(newPortClassType == sourceType &&
1513 "expected all references to be of the same type");
1517 newPortClassType = sourceType;
1524 if (!newPortClassType) {
1525 newPortTypes.push_back(classOp.getPortTypeAttr(i));
1531 classOp.getArgument(i).setType(newPortClassType);
1532 newPortTypes.push_back(TypeAttr::get(newPortClassType));
1533 anyDifferences =
true;
1538 classOp.setPortTypes(newPortTypes);
1540 return anyDifferences;
1547 objectOp.getResult().setType(newClassType);
1555 auto dstType = dst.getType();
1556 auto srcType = src.getType();
1557 if (dstType == srcType) {
1563 auto dstBundle = type_cast<BundleType>(dstType);
1564 auto srcBundle = type_cast<BundleType>(srcType);
1565 for (
unsigned i = 0; i < dstBundle.getNumElements(); ++i) {
1566 auto dstField = builder.create<SubfieldOp>(dst, i);
1567 auto srcField = builder.create<SubfieldOp>(src, i);
1568 if (dstBundle.getElement(i).isFlip) {
1569 std::swap(srcBundle, dstBundle);
1570 std::swap(srcField, dstField);
1580 for (
auto *node : instanceGraph) {
1581 auto module = cast<FModuleLike>(*node->getModule());
1584 bool shouldFixupObjects =
false;
1585 auto classOp = dyn_cast<ClassOp>(module.getOperation());
1589 for (
auto *instRec : node->uses()) {
1592 if (shouldFixupObjects) {
1594 classOp.getInstanceType());
1599 auto inst = instRec->getInstance<InstanceOp>();
1603 ImplicitLocOpBuilder builder(inst.getLoc(), inst->getContext());
1604 builder.setInsertionPointAfter(inst);
1605 for (
size_t i = 0, e =
getNumPorts(module); i < e; ++i) {
1606 auto result = inst.getResult(i);
1607 auto newType =
module.getPortType(i);
1608 auto oldType = result.getType();
1610 if (newType == oldType)
1615 builder.create<WireOp>(oldType, inst.getPortName(i)).getResult();
1616 result.replaceAllUsesWith(wire);
1617 result.setType(newType);
1618 if (inst.getPortDirection(i) == Direction::Out)
1635 std::array<uint8_t, 32> key;
1636 std::fill(key.begin(), key.end(), ~0);
1641 std::array<uint8_t, 32> key;
1642 std::fill(key.begin(), key.end(), ~0 - 1);
1650 std::memcpy(&hash, val.structuralHash.data(),
sizeof(
unsigned));
1653 return llvm::hash_combine(
1654 hash, llvm::hash_combine_range(val.referredModuleNames.begin(),
1655 val.referredModuleNames.end()));
1658 static bool isEqual(
const ModuleInfo &lhs,
const ModuleInfo &rhs) {
1658 static bool isEqual(
const ModuleInfo &lhs,
const ModuleInfo &rhs) {
…}
1669class DedupPass :
public circt::firrtl::impl::DedupBase<DedupPass> {
1670 void runOnOperation()
override {
1671 auto *context = &getContext();
1672 auto circuit = getOperation();
1673 auto &instanceGraph = getAnalysis<InstanceGraph>();
1674 auto *nlaTable = &getAnalysis<NLATable>();
1675 auto &symbolTable = getAnalysis<SymbolTable>();
1676 Deduper deduper(instanceGraph, symbolTable, nlaTable, circuit);
1678 auto anythingChanged =
false;
1687 llvm::DenseMap<ModuleInfo, Operation *> moduleInfoToModule;
1692 DenseMap<Attribute, StringAttr> dedupMap;
1697 SmallVector<FModuleLike, 0> modules(
1698 llvm::map_range(llvm::post_order(&instanceGraph), [](
auto *node) {
1699 return cast<FModuleLike>(*node->getModule());
1702 SmallVector<std::optional<ModuleInfo>> moduleInfos(modules.size());
1706 auto dedupGroupAttrName = StringAttr::get(context,
"firrtl.dedup_group");
1712 for (
auto module : modules) {
1713 llvm::SmallSetVector<StringAttr, 1> groups;
1715 module, [&groups, dedupGroupClass](
Annotation annotation) {
1718 groups.insert(annotation.
getMember<StringAttr>(
"group"));
1721 if (groups.size() > 1) {
1722 module.emitError("module belongs to multiple dedup groups: ") << groups;
1723 return signalPassFailure();
1725 assert(!module->hasAttr(dedupGroupAttrName) &&
1726 "unexpected existing use of temporary dedup group attribute");
1727 if (!groups.empty())
1728 module->setDiscardableAttr(dedupGroupAttrName, groups.front());
1732 auto result = mlir::failableParallelForEach(
1733 context, llvm::seq(modules.size()), [&](
unsigned idx) {
1734 auto module = modules[idx];
1736 if (AnnotationSet::hasAnnotation(module, noDedupClass))
1740 if (auto ext = dyn_cast<FExtModuleOp>(*module);
1741 ext && !ext.getDefname().has_value())
1744 StructuralHasher hasher(hasherConstants);
1746 moduleInfos[idx] = hasher.getModuleInfo(module);
1750 if (result.failed())
1751 return signalPassFailure();
1753 for (
auto [i, module] :
llvm::enumerate(modules)) {
1754 auto moduleName =
module.getModuleNameAttr();
1755 auto &maybeModuleInfo = moduleInfos[i];
1757 if (!maybeModuleInfo) {
1762 dedupMap[moduleName] = moduleName;
1766 auto &moduleInfo = maybeModuleInfo.value();
1769 for (
auto &referredModule : moduleInfo.referredModuleNames)
1770 referredModule = dedupMap[referredModule];
1773 auto it = moduleInfoToModule.find(moduleInfo);
1774 if (it != moduleInfoToModule.end()) {
1775 auto original = cast<FModuleLike>(it->second);
1776 auto originalName = original.getModuleNameAttr();
1785 for (
auto &[originalName, dedupedName] : dedupMap)
1786 if (dedupedName == originalName)
1787 dedupedName = moduleName;
1790 it->second =
module;
1792 std::swap(originalName, moduleName);
1793 std::swap(original, module);
1797 dedupMap[moduleName] = originalName;
1798 deduper.dedup(original, module);
1800 anythingChanged =
true;
1804 deduper.record(module);
1806 dedupMap[moduleName] = moduleName;
1808 moduleInfoToModule[std::move(moduleInfo)] =
module;
1816 auto failed =
false;
1818 auto parseModule = [&](Attribute path) -> StringAttr {
1821 auto [_, rhs] = cast<StringAttr>(path).getValue().split(
'|');
1822 return StringAttr::get(context, rhs);
1827 auto getLead = [&](StringAttr module) -> StringAttr {
1828 auto it = dedupMap.find(module);
1829 if (it == dedupMap.end()) {
1830 auto diag = emitError(circuit.getLoc(),
1831 "MustDeduplicateAnnotation references module ")
1832 <<
module << " which does not exist";
1842 auto modules = annotation.
getMember<ArrayAttr>(
"modules");
1844 emitError(circuit.getLoc(),
1845 "MustDeduplicateAnnotation missing \"modules\" member");
1850 if (modules.empty())
1853 auto firstModule = parseModule(modules[0]);
1854 auto firstLead = getLead(firstModule);
1858 for (
auto attr : modules.getValue().drop_front()) {
1859 auto nextModule = parseModule(attr);
1860 auto nextLead = getLead(nextModule);
1863 if (firstLead != nextLead) {
1864 auto diag = emitError(circuit.getLoc(),
"module ")
1865 << nextModule <<
" not deduplicated with " << firstModule;
1868 equiv.check(diag, a, b);
1876 return signalPassFailure();
1879 for (
auto module : circuit.getOps<FModuleLike>())
1880 module->removeDiscardableAttr(dedupGroupAttrName);
1887 markAnalysesPreserved<NLATable>();
1888 if (!anythingChanged)
1889 markAllAnalysesPreserved();
1895 return std::make_unique<DedupPass>();
assert(baseType &&"element must be base type")
static void mergeRegions(Region *region1, Region *region2)
static Block * getBodyBlock(FModuleLike mod)
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
bool hasAnnotation(StringRef className) const
Return true if we have an annotation with the specified class name.
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
This class provides a read-only projection of an annotation.
void setDict(DictionaryAttr dict)
Set the data dictionary of this attribute.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
StringAttr getClassAttr() const
Return the 'class' that this annotation is representing.
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
This graph tracks modules and where they are instantiated.
This table tracks nlas and what modules participate in them.
A table of inner symbols and their resolutions.
auto getModule()
Get the module that this node is tracking.
InstanceGraphNode * lookup(ModuleOpInterface op)
Look up an InstanceGraphNode for a module.
static StringRef toString(Direction direction)
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
constexpr const char * mustDedupAnnoClass
constexpr const char * noDedupAnnoClass
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
constexpr const char * dedupGroupAnnoClass
std::unique_ptr< mlir::Pass > createDedupPass()
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
constexpr const char * dontTouchAnnoClass
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
static bool operator==(const ModulePort &a, const ModulePort &b)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
SmallVector< FlatSymbolRefAttr > createNLAs(Operation *fromModule, ArrayRef< Attribute > baseNamepath, SymbolTable::Visibility vis=SymbolTable::Visibility::Private)
Look up the instantiations of the from module and create an NLA for each one, appending the baseNamep...
Block * nlaBlock
We insert all NLAs to the beginning of this block.
void recordAnnotations(Operation *op)
Record all targets which use an NLA.
void eraseNLA(hw::HierPathOp nla)
This erases the NLA op, and removes the NLA from every module's NLA map, but it does not delete the N...
void mergeAnnotations(FModuleLike toModule, Operation *to, FModuleLike fromModule, Operation *from)
Merge all annotations and port annotations on two operations.
void replaceInstances(FModuleLike toModule, Operation *fromModule)
This deletes and replaces all instances of the "fromModule" with instances of the "toModule".
void record(FModuleLike module)
Record the usages of any NLA's in this module, so that we may update the annotation if the parent mod...
void rewriteExtModuleNLAs(RenameMap &renameMap, StringAttr toName, StringAttr fromName)
void mergeRegions(RenameMap &renameMap, FModuleLike toModule, Region &toRegion, FModuleLike fromModule, Region &fromRegion)
void dedup(FModuleLike toModule, FModuleLike fromModule)
Remove the "fromModule", and replace all references to it with the "toModule".
void rewriteModuleNLAs(RenameMap &renameMap, FModuleOp toModule, FModuleOp fromModule)
Process all the NLAs that the two modules participate in, replacing references to the "from" module w...
SmallVector< FlatSymbolRefAttr > createNLAs(StringAttr toModuleName, FModuleLike fromModule, SymbolTable::Visibility vis=SymbolTable::Visibility::Private)
Look up the instantiations of this module and create an NLA for each one.
void recordAnnotations(AnnoTarget target)
For a specific annotation target, record all the unique NLAs which target it in the targetMap.
NLATable * nlaTable
Cached nla table analysis.
hw::InnerSymAttr mergeInnerSymbols(RenameMap &renameMap, FModuleLike toModule, hw::InnerSymAttr toSym, hw::InnerSymAttr fromSym)
void cloneAnnotation(SmallVectorImpl< FlatSymbolRefAttr > &nlas, Annotation anno, ArrayRef< NamedAttribute > attributes, unsigned nonLocalIndex, SmallVectorImpl< Annotation > &newAnnotations)
Clone the annotation for each NLA in a list.
void recordSymRenames(RenameMap &renameMap, FModuleLike toModule, Operation *to, FModuleLike fromModule, Operation *from)
void mergeAnnotations(FModuleLike toModule, AnnoTarget to, AnnotationSet toAnnos, FModuleLike fromModule, AnnoTarget from, AnnotationSet fromAnnos)
Merge the annotations of a specific target, either a operation or a port on an operation.
StringAttr nonLocalString
hw::InnerSymbolNamespace & getNamespace(Operation *module)
Get a cached namespace for a module.
SymbolTable & symbolTable
void mergeOps(RenameMap &renameMap, FModuleLike toModule, Operation *to, FModuleLike fromModule, Operation *from)
Recursively merge two operations.
DenseMap< Operation *, hw::InnerSymbolNamespace > moduleNamespaces
A module namespace cache.
bool makeAnnotationNonLocal(StringAttr toModuleName, AnnoTarget to, FModuleLike fromModule, Annotation anno, SmallVectorImpl< Annotation > &newAnnotations)
Take an annotation, and update it to be a non-local annotation.
InstanceGraph & instanceGraph
void mergeBlocks(RenameMap &renameMap, FModuleLike toModule, Block &toBlock, FModuleLike fromModule, Block &fromBlock)
Recursively merge two blocks.
DenseMap< Attribute, llvm::SmallDenseSet< AnnoTarget > > targetMap
void copyAnnotations(FModuleLike toModule, AnnoTarget to, FModuleLike fromModule, AnnotationSet annos, SmallVectorImpl< Annotation > &newAnnotations, SmallPtrSetImpl< Attribute > &dontTouches)
Deduper(InstanceGraph &instanceGraph, SymbolTable &symbolTable, NLATable *nlaTable, CircuitOp circuit)
void addAnnotationContext(RenameMap &renameMap, FModuleOp toModule, FModuleOp fromModule)
Process all NLAs referencing the "from" module to point to the "to" module.
DenseMap< StringAttr, StringAttr > RenameMap
DenseMap< Attribute, Attribute > nlaCache
const hw::InnerSymbolTable & a
ModuleData(const hw::InnerSymbolTable &a, const hw::InnerSymbolTable &b)
const hw::InnerSymbolTable & b
This class is for reporting differences between two modules which should have been deduplicated.
DenseSet< Attribute > nonessentialAttributes
std::string prettyPrint(Attribute attr)
LogicalResult check(InFlightDiagnostic &diag, FInstanceLike a, FInstanceLike b)
LogicalResult check(InFlightDiagnostic &diag, ModuleData &data, Operation *a, Block &aBlock, Operation *b, Block &bBlock)
LogicalResult check(InFlightDiagnostic &diag, const Twine &message, Operation *a, Type aType, Operation *b, Type bType)
StringAttr dedupGroupAttrName
LogicalResult check(InFlightDiagnostic &diag, ModuleData &data, Operation *a, DictionaryAttr aDict, Operation *b, DictionaryAttr bDict)
LogicalResult check(InFlightDiagnostic &diag, ModuleData &data, Operation *a, Region &aRegion, Operation *b, Region &bRegion)
StringAttr portDirectionsAttr
LogicalResult check(InFlightDiagnostic &diag, const Twine &message, Operation *a, BundleType aType, Operation *b, BundleType bType)
LogicalResult check(InFlightDiagnostic &diag, ModuleData &data, Operation *a, Operation *b)
Equivalence(MLIRContext *context, InstanceGraph &instanceGraph)
LogicalResult check(InFlightDiagnostic &diag, Operation *a, mlir::DenseBoolArrayAttr aAttr, Operation *b, mlir::DenseBoolArrayAttr bAttr)
InstanceGraph & instanceGraph
void check(InFlightDiagnostic &diag, Operation *a, Operation *b)
std::vector< StringAttr > referredModuleNames
std::array< uint8_t, 32 > structuralHash
This struct contains constant string attributes shared across different threads.
StringAttr moduleNameAttr
DenseSet< Attribute > nonessentialAttributes
StructuralHasherSharedConstants(MLIRContext *context)
void populateInnerSymIDTable(FModuleLike module)
Find all the ports and operations which may define an inner symbol operations and give each a unique ...
void update(Operation *op, DictionaryAttr dict)
Hash the top level attribute dictionary of the operation.
void update(const void *pointer)
DenseMap< void *, unsigned > idTable
void update(const std::pair< T, U > &pair)
void update(Operation *op)
DenseMap< StringAttr, std::pair< size_t, size_t > > innerSymIDTable
ModuleInfo getModuleInfo(FModuleLike module)
void update(size_t value)
void update(BundleType type)
unsigned getID(void *object)
void update(OpResult result)
void update(OpOperand &operand)
StructuralHasher(const StructuralHasherSharedConstants &constants)
void update(Region *region)
void update(Block *block)
std::vector< StringAttr > referredModuleNames
void update(TypeID typeID)
const StructuralHasherSharedConstants & constants
std::pair< size_t, size_t > getInnerSymID(StringAttr name)
unsigned finalizeID(void *object)
void update(mlir::OperationName name)
An annotation target is used to keep track of something that is targeted by an Annotation.
AnnotationSet getAnnotations() const
Get the annotations associated with the target.
void setAnnotations(AnnotationSet annotations) const
Set the annotations associated with the target.
This represents an annotation targeting a specific operation.
Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const
This represents an annotation targeting a specific port of a module, memory, or instance.
static ModuleInfo getEmptyKey()
static ModuleInfo getTombstoneKey()
static unsigned getHashValue(const ModuleInfo &val)
static bool isEqual(const ModuleInfo &lhs, const ModuleInfo &rhs)