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");
820 diag.attachNote(b->getLoc())
822 << (bSymbol.isPrivate() ?
"private but not discardable" :
"public");
827 auto bGroup = dyn_cast_or_null<StringAttr>(
829 if (aGroup != bGroup) {
831 diag.attachNote(b->getLoc())
832 <<
"module is in dedup group '" << bGroup.str() <<
"'";
834 diag.attachNote(b->getLoc()) <<
"module is not part of a dedup group";
837 diag.attachNote(a->getLoc())
838 <<
"module is in dedup group '" << aGroup.str() <<
"'";
840 diag.attachNote(a->getLoc()) <<
"module is not part of a dedup group";
846 diag.attachNote(a->getLoc()) <<
"first module here";
847 diag.attachNote(b->getLoc()) <<
"second module here";
802 void check(InFlightDiagnostic &diag, Operation *a, Operation *b) {
…}
871static Location
mergeLoc(MLIRContext *context, Location to, Location from) {
873 llvm::SmallSetVector<Location, 4> decomposedLocs;
875 unsigned seenFIR = 0;
876 for (
auto loc : {to, from}) {
879 if (
auto fusedLoc = dyn_cast<FusedLoc>(loc)) {
882 for (
auto loc : fusedLoc.getLocations()) {
883 if (FileLineColLoc fileLoc = dyn_cast<FileLineColLoc>(loc)) {
884 if (fileLoc.getFilename().strref().ends_with(
".fir")) {
890 decomposedLocs.insert(loc);
896 if (FileLineColLoc fileLoc = dyn_cast<FileLineColLoc>(loc)) {
897 if (fileLoc.getFilename().strref().ends_with(
".fir")) {
904 if (!isa<UnknownLoc>(loc))
905 decomposedLocs.insert(loc);
908 auto locs = decomposedLocs.getArrayRef();
913 return UnknownLoc::get(context);
914 if (locs.size() == 1)
917 return FusedLoc::get(context, locs);
871static Location
mergeLoc(MLIRContext *context, Location to, Location from) {
…}
932 for (
auto nla : circuit.getOps<hw::HierPathOp>())
933 nlaCache[nla.getNamepathAttr()] = nla.getSymNameAttr();
940 void dedup(FModuleLike toModule, FModuleLike fromModule) {
946 SmallVector<Attribute> newLocs;
947 for (
auto [toLoc, fromLoc] : llvm::zip(toModule.getPortLocations(),
948 fromModule.getPortLocations())) {
949 if (toLoc == fromLoc)
950 newLocs.push_back(toLoc);
953 cast<LocationAttr>(fromLoc)));
955 toModule->setAttr(
"portLocations", ArrayAttr::get(
context, newLocs));
958 mergeOps(renameMap, toModule, toModule, fromModule, fromModule);
964 if (
auto to = dyn_cast<FModuleOp>(*toModule))
968 fromModule.getModuleNameAttr());
940 void dedup(FModuleLike toModule, FModuleLike fromModule) {
…}
979 for (
unsigned i = 0, e =
getNumPorts(module); i < e; ++i)
982 module->walk([&](Operation *op) { recordAnnotations(op); });
988 return moduleNamespaces.try_emplace(module, cast<FModuleLike>(module))
996 if (
auto nlaRef = anno.getMember<FlatSymbolRefAttr>(
"circt.nonlocal"))
997 targetMap[nlaRef.getAttr()].insert(target);
1006 auto mem = dyn_cast<MemOp>(op);
1011 for (
unsigned i = 0, e = mem->getNumResults(); i < e; ++i)
1020 instanceGraph[::cast<igraph::ModuleOpInterface>(fromModule)];
1021 auto *toNode = instanceGraph[toModule];
1022 auto toModuleRef = FlatSymbolRefAttr::get(toModule.getModuleNameAttr());
1023 for (
auto *oldInstRec : llvm::make_early_inc_range(fromNode->uses())) {
1024 auto inst = oldInstRec->getInstance();
1025 if (
auto instOp = dyn_cast<InstanceOp>(*inst)) {
1026 instOp.setModuleNameAttr(toModuleRef);
1027 instOp.setPortNamesAttr(toModule.getPortNamesAttr());
1028 }
else if (
auto objectOp = dyn_cast<ObjectOp>(*inst)) {
1029 auto classLike = cast<ClassLike>(*toNode->getModule());
1030 ClassType classType = detail::getInstanceTypeForClassLike(classLike);
1031 objectOp.getResult().setType(classType);
1033 oldInstRec->getParent()->addInstance(inst, toNode);
1034 oldInstRec->erase();
1036 instanceGraph.erase(fromNode);
1037 fromModule->erase();
1045 SmallVector<FlatSymbolRefAttr>
1046 createNLAs(Operation *fromModule, ArrayRef<Attribute> baseNamepath,
1047 SymbolTable::Visibility vis = SymbolTable::Visibility::Private) {
1050 SmallVector<Attribute> namepath = {
nullptr};
1051 namepath.append(baseNamepath.begin(), baseNamepath.end());
1053 auto loc = fromModule->getLoc();
1054 auto *fromNode = instanceGraph[cast<igraph::ModuleOpInterface>(fromModule)];
1055 SmallVector<FlatSymbolRefAttr> nlas;
1056 for (
auto *instanceRecord : fromNode->uses()) {
1057 auto parent = cast<FModuleOp>(*instanceRecord->getParent()->getModule());
1058 auto inst = instanceRecord->getInstance();
1060 auto arrayAttr = ArrayAttr::get(context, namepath);
1062 auto &cacheEntry = nlaCache[arrayAttr];
1064 auto nla = OpBuilder::atBlockBegin(nlaBlock).create<hw::HierPathOp>(
1065 loc,
"nla", arrayAttr);
1067 symbolTable.insert(nla);
1069 cacheEntry = nla.getNameAttr();
1070 nla.setVisibility(vis);
1071 nlaTable->addNLA(nla);
1073 auto nlaRef = FlatSymbolRefAttr::get(cast<StringAttr>(cacheEntry));
1074 nlas.push_back(nlaRef);
1046 createNLAs(Operation *fromModule, ArrayRef<Attribute> baseNamepath, {
…}
1082 SmallVector<FlatSymbolRefAttr>
1084 SymbolTable::Visibility vis = SymbolTable::Visibility::Private) {
1085 return createNLAs(fromModule, FlatSymbolRefAttr::get(toModuleName), vis);
1092 Annotation anno, ArrayRef<NamedAttribute> attributes,
1093 unsigned nonLocalIndex,
1094 SmallVectorImpl<Annotation> &newAnnotations) {
1095 SmallVector<NamedAttribute> mutableAttributes(attributes.begin(),
1097 for (
auto &nla : nlas) {
1099 mutableAttributes[nonLocalIndex].setValue(nla);
1100 auto dict = DictionaryAttr::getWithSorted(context, mutableAttributes);
1103 newAnnotations.push_back(anno);
1112 targetMap.erase(nla.getNameAttr());
1113 nlaTable->erase(nla);
1114 nlaCache.erase(nla.getNamepathAttr());
1115 symbolTable.erase(nla);
1121 FModuleOp fromModule) {
1122 auto toName = toModule.getNameAttr();
1123 auto fromName = fromModule.getNameAttr();
1126 auto moduleNLAs = nlaTable->lookup(fromModule.getNameAttr()).vec();
1128 nlaTable->renameModuleAndInnerRef(toName, fromName, renameMap);
1131 for (
auto nla : moduleNLAs) {
1132 auto elements = nla.getNamepath().getValue();
1134 if (nla.root() != toName)
1137 SmallVector<Attribute> namepath(elements.begin(), elements.end());
1138 auto nlaRefs = createNLAs(fromModule, namepath, nla.getVisibility());
1140 auto &set = targetMap[nla.getSymNameAttr()];
1141 SmallVector<AnnoTarget> targets(set.begin(), set.end());
1143 for (
auto target : targets) {
1146 SmallVector<Annotation> newAnnotations;
1147 for (
auto anno : target.getAnnotations()) {
1149 auto [it, found] = mlir::impl::findAttrSorted(
1150 anno.begin(), anno.end(), nonLocalString);
1153 if (!found || cast<FlatSymbolRefAttr>(it->getValue()).getAttr() !=
1154 nla.getSymNameAttr()) {
1155 newAnnotations.push_back(anno);
1158 auto nonLocalIndex = std::distance(anno.begin(), it);
1160 cloneAnnotation(nlaRefs, anno,
1161 ArrayRef<NamedAttribute>(anno.begin(), anno.end()),
1162 nonLocalIndex, newAnnotations);
1167 target.setAnnotations(annotations);
1169 for (
auto nla : nlaRefs)
1170 targetMap[nla.getAttr()].insert(target);
1182 FModuleOp fromModule) {
1183 addAnnotationContext(renameMap, toModule, toModule);
1184 addAnnotationContext(renameMap, toModule, fromModule);
1190 StringAttr fromName) {
1191 nlaTable->renameModuleAndInnerRef(toName, fromName, renameMap);
1199 SmallVectorImpl<Annotation> &newAnnotations) {
1202 SmallVector<NamedAttribute> attributes;
1203 int nonLocalIndex = -1;
1204 for (
const auto &val : llvm::enumerate(anno)) {
1205 auto attr = val.value();
1207 auto compare = attr.getName().compare(nonLocalString);
1208 assert(compare != 0 &&
"should not pass non-local annotations here");
1212 nonLocalIndex = val.index();
1213 attributes.push_back(NamedAttribute(nonLocalString, nonLocalString));
1218 attributes.push_back(attr);
1220 if (nonLocalIndex == -1) {
1222 nonLocalIndex = attributes.size();
1223 attributes.push_back(NamedAttribute(nonLocalString, nonLocalString));
1226 attributes.append(anno.
begin() + nonLocalIndex, anno.
end());
1230 auto nlaRefs = createNLAs(toModuleName, fromModule);
1231 for (
auto nla : nlaRefs)
1232 targetMap[nla.getAttr()].insert(to);
1235 cloneAnnotation(nlaRefs, anno, attributes, nonLocalIndex, newAnnotations);
1241 SmallVectorImpl<Annotation> &newAnnotations,
1242 SmallPtrSetImpl<Attribute> &dontTouches) {
1243 for (
auto anno : annos) {
1247 anno.removeMember(
"circt.nonlocal");
1248 auto [it, inserted] = dontTouches.insert(anno.getAttr());
1250 newAnnotations.push_back(anno);
1255 if (
auto nla = anno.getMember<FlatSymbolRefAttr>(
"circt.nonlocal")) {
1256 newAnnotations.push_back(anno);
1257 targetMap[nla.getAttr()].insert(to);
1261 makeAnnotationNonLocal(toModule.getModuleNameAttr(), to, fromModule, anno,
1272 SmallVector<Annotation> newAnnotations;
1276 llvm::SmallPtrSet<Attribute, 4> dontTouches;
1280 copyAnnotations(toModule, to, toModule, toAnnos, newAnnotations,
1282 copyAnnotations(toModule, to, fromModule, fromAnnos, newAnnotations,
1286 if (!newAnnotations.empty())
1292 FModuleLike fromModule, Operation *from) {
1298 if (toModule == to) {
1300 for (
unsigned i = 0, e =
getNumPorts(toModule); i < e; ++i)
1305 }
else if (
auto toMem = dyn_cast<MemOp>(to)) {
1307 auto fromMem = cast<MemOp>(from);
1308 for (
unsigned i = 0, e = toMem.getNumResults(); i < e; ++i)
1317 hw::InnerSymAttr toSym,
1318 hw::InnerSymAttr fromSym) {
1319 if (fromSym && !fromSym.getProps().empty()) {
1320 auto &isn = getNamespace(toModule);
1322 SmallVector<hw::InnerSymPropertiesAttr> newProps;
1325 llvm::append_range(newProps, toSym);
1327 for (
auto fromProp : fromSym) {
1328 hw::InnerSymPropertiesAttr newProp;
1329 auto *it = llvm::find_if(newProps, [&](
auto p) {
1330 return p.getFieldID() == fromProp.getFieldID();
1332 if (it != newProps.end()) {
1337 if (fromProp.getSymVisibility().getValue() ==
"public" &&
1338 newProp.getSymVisibility().getValue() !=
"public") {
1339 *it = hw::InnerSymPropertiesAttr::get(context, newProp.getName(),
1340 newProp.getFieldID(),
1341 fromProp.getSymVisibility());
1345 auto newName = isn.newName(fromProp.getName().getValue());
1346 newProp = hw::InnerSymPropertiesAttr::get(
1347 context, StringAttr::get(context, newName), fromProp.getFieldID(),
1348 fromProp.getSymVisibility());
1349 newProps.push_back(newProp);
1351 renameMap[fromProp.getName()] = newProp.getName();
1354 llvm::sort(newProps, [](
auto &p,
auto &q) {
1355 return p.getFieldID() < q.getFieldID();
1358 return hw::InnerSymAttr::get(context, newProps);
1360 return hw::InnerSymAttr();
1367 Operation *to, FModuleLike fromModule,
1371 if (
auto fromInnerSym = dyn_cast<hw::InnerSymbolOpInterface>(from)) {
1372 auto toInnerSym = cast<hw::InnerSymbolOpInterface>(to);
1373 if (
auto newSymAttr = mergeInnerSymbols(renameMap, toModule,
1374 toInnerSym.getInnerSymAttr(),
1375 fromInnerSym.getInnerSymAttr()))
1376 toInnerSym.setInnerSymbolAttr(newSymAttr);
1380 auto fromPortSyms = from->getAttrOfType<ArrayAttr>(
"portSymbols");
1381 if (!fromPortSyms || fromPortSyms.empty())
1384 auto portCount = fromPortSyms.size();
1385 auto toPortSyms = to->getAttrOfType<ArrayAttr>(
"portSymbols");
1389 SmallVector<Attribute> newPortSyms;
1390 if (toPortSyms.empty())
1391 newPortSyms.assign(portCount, hw::InnerSymAttr());
1393 newPortSyms.assign(toPortSyms.begin(), toPortSyms.end());
1395 for (
unsigned portNo = 0; portNo < portCount; ++portNo) {
1396 if (
auto newPortSym = mergeInnerSymbols(
1397 renameMap, toModule,
1398 llvm::cast_if_present<hw::InnerSymAttr>(newPortSyms[portNo]),
1399 cast<hw::InnerSymAttr>(fromPortSyms[portNo]))) {
1400 newPortSyms[portNo] = newPortSym;
1405 FModuleLike::fixupPortSymsArray(newPortSyms, toModule.getContext());
1406 cast<FModuleLike>(to).setPortSymbols(newPortSyms);
1412 FModuleLike fromModule, Operation *from) {
1414 if (to->getLoc() != from->getLoc())
1415 to->setLoc(
mergeLoc(context, to->getLoc(), from->getLoc()));
1418 for (
auto regions : llvm::zip(to->getRegions(), from->getRegions()))
1419 mergeRegions(renameMap, toModule, std::get<0>(regions), fromModule,
1420 std::get<1>(regions));
1423 recordSymRenames(renameMap, toModule, to, fromModule, from);
1426 mergeAnnotations(toModule, to, fromModule, from);
1431 FModuleLike fromModule, Block &fromBlock) {
1433 for (
auto [toArg, fromArg] :
1434 llvm::zip(toBlock.getArguments(), fromBlock.getArguments()))
1435 if (toArg.getLoc() != fromArg.getLoc())
1436 toArg.setLoc(
mergeLoc(context, toArg.getLoc(), fromArg.getLoc()));
1438 for (
auto ops : llvm::zip(toBlock, fromBlock))
1439 mergeOps(renameMap, toModule, &std::get<0>(ops), fromModule,
1445 Region &toRegion, FModuleLike fromModule,
1446 Region &fromRegion) {
1447 for (
auto blocks : llvm::zip(toRegion, fromRegion))
1448 mergeBlocks(renameMap, toModule, std::get<0>(blocks), fromModule,
1449 std::get<1>(blocks));
1463 DenseMap<Attribute, llvm::SmallDenseSet<AnnoTarget>>
targetMap;
1487 SmallVector<Attribute> newPortTypes;
1488 bool anyDifferences =
false;
1491 for (
size_t i = 0, e = classOp.getNumPorts(); i < e; ++i) {
1494 auto portClassType = dyn_cast<ClassType>(classOp.getPortType(i));
1495 if (!portClassType) {
1496 newPortTypes.push_back(classOp.getPortTypeAttr(i));
1501 Type newPortClassType;
1502 BlockArgument portArg = classOp.getArgument(i);
1503 for (
auto &use : portArg.getUses()) {
1504 if (
auto propassign = dyn_cast<PropAssignOp>(use.getOwner())) {
1505 Type sourceType = propassign.getSrc().getType();
1506 if (propassign.getDest() == use.get() && sourceType != portClassType) {
1508 if (newPortClassType) {
1509 assert(newPortClassType == sourceType &&
1510 "expected all references to be of the same type");
1514 newPortClassType = sourceType;
1521 if (!newPortClassType) {
1522 newPortTypes.push_back(classOp.getPortTypeAttr(i));
1528 classOp.getArgument(i).setType(newPortClassType);
1529 newPortTypes.push_back(TypeAttr::get(newPortClassType));
1530 anyDifferences =
true;
1535 classOp.setPortTypes(newPortTypes);
1537 return anyDifferences;
1544 objectOp.getResult().setType(newClassType);
1552 auto dstType = dst.getType();
1553 auto srcType = src.getType();
1554 if (dstType == srcType) {
1560 auto dstBundle = type_cast<BundleType>(dstType);
1561 auto srcBundle = type_cast<BundleType>(srcType);
1562 for (
unsigned i = 0; i < dstBundle.getNumElements(); ++i) {
1563 auto dstField = builder.create<SubfieldOp>(dst, i);
1564 auto srcField = builder.create<SubfieldOp>(src, i);
1565 if (dstBundle.getElement(i).isFlip) {
1566 std::swap(srcBundle, dstBundle);
1567 std::swap(srcField, dstField);
1577 for (
auto *node : instanceGraph) {
1578 auto module = cast<FModuleLike>(*node->getModule());
1581 bool shouldFixupObjects =
false;
1582 auto classOp = dyn_cast<ClassOp>(module.getOperation());
1586 for (
auto *instRec : node->uses()) {
1589 if (shouldFixupObjects) {
1591 classOp.getInstanceType());
1596 auto inst = instRec->getInstance<InstanceOp>();
1600 ImplicitLocOpBuilder builder(inst.getLoc(), inst->getContext());
1601 builder.setInsertionPointAfter(inst);
1602 for (
size_t i = 0, e =
getNumPorts(module); i < e; ++i) {
1603 auto result = inst.getResult(i);
1604 auto newType =
module.getPortType(i);
1605 auto oldType = result.getType();
1607 if (newType == oldType)
1612 builder.create<WireOp>(oldType, inst.getPortName(i)).getResult();
1613 result.replaceAllUsesWith(wire);
1614 result.setType(newType);
1615 if (inst.getPortDirection(i) == Direction::Out)
1632 std::array<uint8_t, 32> key;
1633 std::fill(key.begin(), key.end(), ~0);
1638 std::array<uint8_t, 32> key;
1639 std::fill(key.begin(), key.end(), ~0 - 1);
1647 std::memcpy(&hash, val.structuralHash.data(),
sizeof(
unsigned));
1650 return llvm::hash_combine(
1651 hash, llvm::hash_combine_range(val.referredModuleNames.begin(),
1652 val.referredModuleNames.end()));
1655 static bool isEqual(
const ModuleInfo &lhs,
const ModuleInfo &rhs) {
1655 static bool isEqual(
const ModuleInfo &lhs,
const ModuleInfo &rhs) {
…}
1666class DedupPass :
public circt::firrtl::impl::DedupBase<DedupPass> {
1667 void runOnOperation()
override {
1668 auto *context = &getContext();
1669 auto circuit = getOperation();
1670 auto &instanceGraph = getAnalysis<InstanceGraph>();
1671 auto *nlaTable = &getAnalysis<NLATable>();
1672 auto &symbolTable = getAnalysis<SymbolTable>();
1673 Deduper deduper(instanceGraph, symbolTable, nlaTable, circuit);
1675 auto anythingChanged =
false;
1684 llvm::DenseMap<ModuleInfo, Operation *> moduleInfoToModule;
1689 DenseMap<Attribute, StringAttr> dedupMap;
1694 SmallVector<FModuleLike, 0> modules(
1695 llvm::map_range(llvm::post_order(&instanceGraph), [](
auto *node) {
1696 return cast<FModuleLike>(*node->getModule());
1699 SmallVector<std::optional<ModuleInfo>> moduleInfos(modules.size());
1703 auto dedupGroupAttrName = StringAttr::get(context,
"firrtl.dedup_group");
1709 for (
auto module : modules) {
1710 llvm::SmallSetVector<StringAttr, 1> groups;
1712 module, [&groups, dedupGroupClass](
Annotation annotation) {
1715 groups.insert(annotation.
getMember<StringAttr>(
"group"));
1718 if (groups.size() > 1) {
1719 module.emitError("module belongs to multiple dedup groups: ") << groups;
1720 return signalPassFailure();
1722 assert(!module->hasAttr(dedupGroupAttrName) &&
1723 "unexpected existing use of temporary dedup group attribute");
1724 if (!groups.empty())
1725 module->setDiscardableAttr(dedupGroupAttrName, groups.front());
1729 auto result = mlir::failableParallelForEach(
1730 context, llvm::seq(modules.size()), [&](
unsigned idx) {
1731 auto module = modules[idx];
1733 if (AnnotationSet::hasAnnotation(module, noDedupClass))
1737 if (auto ext = dyn_cast<FExtModuleOp>(*module);
1738 ext && !ext.getDefname().has_value())
1741 StructuralHasher hasher(hasherConstants);
1743 moduleInfos[idx] = hasher.getModuleInfo(module);
1747 if (result.failed())
1748 return signalPassFailure();
1750 for (
auto [i, module] :
llvm::enumerate(modules)) {
1751 auto moduleName =
module.getModuleNameAttr();
1752 auto &maybeModuleInfo = moduleInfos[i];
1754 if (!maybeModuleInfo) {
1759 dedupMap[moduleName] = moduleName;
1763 auto &moduleInfo = maybeModuleInfo.value();
1766 for (
auto &referredModule : moduleInfo.referredModuleNames)
1767 referredModule = dedupMap[referredModule];
1770 auto it = moduleInfoToModule.find(moduleInfo);
1771 if (it != moduleInfoToModule.end()) {
1772 auto original = cast<FModuleLike>(it->second);
1773 auto originalName = original.getModuleNameAttr();
1782 for (
auto &[originalName, dedupedName] : dedupMap)
1783 if (dedupedName == originalName)
1784 dedupedName = moduleName;
1787 it->second =
module;
1789 std::swap(originalName, moduleName);
1790 std::swap(original, module);
1794 dedupMap[moduleName] = originalName;
1795 deduper.dedup(original, module);
1797 anythingChanged =
true;
1801 deduper.record(module);
1803 dedupMap[moduleName] = moduleName;
1805 moduleInfoToModule[std::move(moduleInfo)] =
module;
1813 auto failed =
false;
1815 auto parseModule = [&](Attribute path) -> StringAttr {
1818 auto [_, rhs] = cast<StringAttr>(path).getValue().split(
'|');
1819 return StringAttr::get(context, rhs);
1824 auto getLead = [&](StringAttr module) -> StringAttr {
1825 auto it = dedupMap.find(module);
1826 if (it == dedupMap.end()) {
1827 auto diag = emitError(circuit.getLoc(),
1828 "MustDeduplicateAnnotation references module ")
1829 <<
module << " which does not exist";
1839 auto modules = annotation.
getMember<ArrayAttr>(
"modules");
1841 emitError(circuit.getLoc(),
1842 "MustDeduplicateAnnotation missing \"modules\" member");
1847 if (modules.empty())
1850 auto firstModule = parseModule(modules[0]);
1851 auto firstLead = getLead(firstModule);
1855 for (
auto attr : modules.getValue().drop_front()) {
1856 auto nextModule = parseModule(attr);
1857 auto nextLead = getLead(nextModule);
1860 if (firstLead != nextLead) {
1861 auto diag = emitError(circuit.getLoc(),
"module ")
1862 << nextModule <<
" not deduplicated with " << firstModule;
1865 equiv.check(diag, a, b);
1873 return signalPassFailure();
1876 for (
auto module : circuit.getOps<FModuleLike>())
1877 module->removeDiscardableAttr(dedupGroupAttrName);
1884 markAnalysesPreserved<NLATable>();
1885 if (!anythingChanged)
1886 markAllAnalysesPreserved();
1892 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)