33 #include "mlir/IR/Diagnostics.h"
34 #include "llvm/ADT/APSInt.h"
35 #include "llvm/ADT/PostOrderIterator.h"
36 #include "llvm/ADT/StringExtras.h"
37 #include "llvm/Support/Debug.h"
39 #define DEBUG_TYPE "lower-annos"
41 using namespace circt;
42 using namespace firrtl;
43 using namespace chirrtl;
56 SmallVector<Attribute> old(array.begin(), array.end());
64 SmallVector<Attribute> old(array.begin(), array.end());
72 ArrayRef<NamedAttribute> anno) {
73 auto *context = ref.
getOp()->getContext();
74 DictionaryAttr annotation;
76 SmallVector<NamedAttribute> annoField(anno.begin(), anno.end());
77 annoField.emplace_back(
96 SmallVector<Attribute> emptyPortAttr(
102 portAnno, portRef.getPortNo(),
105 ref.
getOp()->setAttr(
"portAnnotations", portAnno);
112 OpBuilder b(state.
circuit.getBodyRegion());
113 SmallVector<Attribute> insts;
116 state.
getNamespace(inst->getParentOfType<FModuleLike>())));
133 FlatSymbolRefAttr sym =
buildNLA(target, state);
142 static std::optional<AnnoPathValue>
noResolve(DictionaryAttr anno,
152 StringRef path{pathStr};
156 mlir::emitError(state.
circuit.getLoc())
157 <<
"Cannot tokenize annotation path " << rawPath;
170 auto target = anno.getNamed(
"target");
172 mlir::emitError(state.
circuit.getLoc())
173 <<
"No target field in annotation " << anno;
176 if (!isa<StringAttr>(target->getValue())) {
177 mlir::emitError(state.
circuit.getLoc())
178 <<
"Target field in annotation doesn't contain string " << anno;
181 return stdResolveImpl(cast<StringAttr>(target->getValue()).getValue(), state);
187 auto target = anno.getNamed(
"target");
189 return stdResolveImpl(cast<StringAttr>(target->getValue()).getValue(),
204 bool allowNonLocal) {
205 if (!allowNonLocal && !target.
isLocal()) {
207 auto diag = mlir::emitError(target.
ref.
getOp()->getLoc())
208 <<
"is targeted by a non-local annotation \""
209 << annotation.
getClass() <<
"\" with target "
211 <<
", but this annotation cannot be non-local";
212 diag.attachNote() <<
"see current annotation: " << anno <<
"\n";
215 SmallVector<NamedAttribute> newAnnoAttrs;
216 for (
auto &na : anno) {
217 if (na.getName().getValue() !=
"target") {
218 newAnnoAttrs.push_back(na);
219 }
else if (!target.
isLocal()) {
221 newAnnoAttrs.push_back(
242 auto loc = op->getLoc();
245 return mlir::emitError(loc) <<
"must be local";
248 return mlir::emitError(loc) <<
"can only target to a module";
250 auto moduleOp = cast<FModuleOp>(op);
253 moduleOp.setPublic();
254 SmallVector<NamedAttribute> newAnnoAttrs;
255 for (
auto &na : anno)
256 if (na.getName().getValue() !=
"target")
257 newAnnoAttrs.push_back(na);
264 return ::llvm::StringSwitch<::std::optional<Convention>>(str)
265 .Case(
"scalarized", Convention::Scalarized)
266 .Default(std::nullopt);
273 auto loc = op->getLoc();
275 auto diag = mlir::emitError(loc);
276 diag <<
"circuit.ConventionAnnotation ";
282 return error() <<
"must target a module object";
285 return error() <<
"must be local";
287 auto conventionStrAttr =
289 if (!conventionStrAttr)
292 auto conventionStr = conventionStrAttr.getValue();
295 return error() <<
"unknown convention " << conventionStr;
297 auto convention = *conventionOpt;
299 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
300 moduleOp.setConvention(convention);
304 if (
auto extModuleOp = dyn_cast<FExtModuleOp>(op)) {
305 extModuleOp.setConvention(convention);
309 return error() <<
"can only target to a module or extmodule";
318 auto diag = mlir::emitError(op->getLoc());
319 diag << anno.getAs<StringAttr>(
"class").getValue() <<
" ";
325 <<
"must target an operation. Currently ports are not supported";
328 return error() <<
"must be local";
330 if (!isa<FModuleOp, WireOp, NodeOp, RegOp, RegResetOp>(op))
332 <<
"unhandled operation. The target must be a module, wire, node or "
335 auto name = anno.getAs<StringAttr>(
"description");
342 template <
bool isInline>
347 mlir::emitError(state.
circuit.getLoc())
348 <<
"has a " << anno.get(
"class")
349 <<
" annotation which is non-local, but this annotation is not allowed "
356 if (!target.
isOpOfType<MemOp, CombMemOp, SeqMemOp>()) {
357 mlir::emitError(op->getLoc())
358 <<
"can only apply a load memory annotation to a memory";
363 StringAttr filename = tryGetAs<StringAttr>(
364 anno, anno, isInline ?
"filename" :
"fileName", op->getLoc(),
365 anno.getAs<StringAttr>(
"class").getValue());
370 tryGetAs<StringAttr>(anno, anno,
"hexOrBinary", op->getLoc(),
371 anno.getAs<StringAttr>(
"class").getValue());
375 auto hexOrBinaryValue = hexOrBinary.getValue();
376 if (hexOrBinaryValue !=
"h" && hexOrBinaryValue !=
"b") {
377 auto diag = mlir::emitError(op->getLoc())
378 <<
"has memory initialization annotation with invalid format, "
379 "'hexOrBinary' field must be either 'h' or 'b'";
380 diag.attachNote() <<
"the full annotation is: " << anno;
385 hexOrBinaryValue ==
"b", isInline));
408 applyWithoutTarget<false, CircuitOp>};
413 {
"circt.test", {
stdResolve, applyWithoutTarget<true>}},
414 {
"circt.testLocalOnly", {
stdResolve, applyWithoutTarget<>}},
415 {
"circt.testNT", {
noResolve, applyWithoutTarget<>}},
416 {
"circt.missing", {
tryResolve, applyWithoutTarget<true>}},
446 RegResetOp, InstanceOp, MemOp, CombMemOp,
447 MemoryPortOp, SeqMemOp>}},
450 applyWithoutTarget<true, FModuleOp, FExtModuleOp, InstanceOp>}},
456 {
stdResolve, applyWithoutTarget<true, MemOp, CombMemOp>}},
462 {
stdResolve, applyWithoutTarget<true, FModuleOp, FExtModuleOp>}},
466 {
stdResolve, applyWithoutTarget<false, FModuleOp, FExtModuleOp>}},
468 {
stdResolve, applyWithoutTarget<false, FModuleOp, FExtModuleOp>}},
470 {
stdResolve, applyWithoutTarget<false, FExtModuleOp>}},
472 {
stdResolve, applyWithoutTarget<false, FExtModuleOp>}},
474 {
stdResolve, applyWithoutTarget<false, FModuleOp>}},
476 {
stdResolve, applyWithoutTarget<false, FExtModuleOp>}},
480 {
stdResolve, applyWithoutTarget<false, FModuleOp, FExtModuleOp>}},
499 {
stdResolve, applyWithoutTarget<true, FModuleOp>}},
513 const std::function<
void(llvm::Twine)> &errorHandler) {
516 return LogicalResult::success();
518 errorHandler(
"annotation record '" + annoClass +
"' is registered twice\n");
519 return LogicalResult::failure();
527 bool ignoreAnnotationUnknown) {
531 if (ignoreAnnotationUnknown)
541 struct LowerAnnotationsPass
542 :
public LowerFIRRTLAnnotationsBase<LowerAnnotationsPass> {
543 void runOnOperation()
override;
544 LogicalResult applyAnnotation(DictionaryAttr anno,
ApplyState &state);
545 LogicalResult legacyToWiringProblems(
ApplyState &state);
546 LogicalResult solveWiringProblems(
ApplyState &state);
548 using LowerFIRRTLAnnotationsBase::ignoreAnnotationClassless;
549 using LowerFIRRTLAnnotationsBase::ignoreAnnotationUnknown;
550 using LowerFIRRTLAnnotationsBase::noRefTypePorts;
551 SmallVector<DictionaryAttr> worklistAttrs;
555 LogicalResult LowerAnnotationsPass::applyAnnotation(DictionaryAttr anno,
557 LLVM_DEBUG(llvm::dbgs() <<
" - anno: " << anno <<
"\n";);
560 StringRef annoClassVal;
561 if (
auto annoClass = anno.getNamed(
"class"))
562 annoClassVal = cast<StringAttr>(annoClass->getValue()).getValue();
563 else if (ignoreAnnotationClassless)
564 annoClassVal =
"circt.missing";
566 return mlir::emitError(state.
circuit.getLoc())
567 <<
"Annotation without a class: " << anno;
573 if (!ignoreAnnotationUnknown)
574 return mlir::emitError(state.
circuit.getLoc())
575 <<
"Unhandled annotation: " << anno;
583 auto target = record->resolver(anno, state);
585 return mlir::emitError(state.
circuit.getLoc())
586 <<
"Unable to resolve target of annotation: " << anno;
587 if (record->applier(*target, anno, state).failed())
588 return mlir::emitError(state.
circuit.getLoc())
589 <<
"Unable to apply annotation: " << anno;
595 LogicalResult LowerAnnotationsPass::legacyToWiringProblems(
ApplyState &state) {
598 return mlir::emitError(state.
circuit.getLoc())
599 <<
"Unable to resolve source for pin: " << name;
601 if (problem.sinks.empty())
602 return mlir::emitError(state.
circuit.getLoc())
603 <<
"Unable to resolve sink(s) for pin: " << name;
605 for (
const auto &sink : problem.sinks) {
620 LogicalResult LowerAnnotationsPass::solveWiringProblems(
ApplyState &state) {
623 auto getModule = [](Value value) {
624 if (BlockArgument blockArg = dyn_cast<BlockArgument>(value))
625 return cast<FModuleLike>(blockArg.getParentBlock()->getParentOp());
626 return value.getDefiningOp()->getParentOfType<FModuleLike>();
630 auto findInsertionBlock = [&getModule](Value src, Value dest) -> Block * {
632 if (src.getParentBlock() == dest.getParentBlock())
633 return src.getParentBlock();
637 assert(getModule(src) == getModule(dest));
639 auto safelyDoms = [&](Value a, Value b) {
640 if (isa<BlockArgument>(a))
642 if (isa<BlockArgument>(b))
646 a.getParentBlock()->findAncestorOpInBlock(*b.getDefiningOp());
647 return ancestor && a.getDefiningOp()->isBeforeInBlock(ancestor);
649 if (safelyDoms(src, dest))
650 return dest.getParentBlock();
651 if (safelyDoms(dest, src))
652 return src.getParentBlock();
656 auto getNoopCast = [](Value v) -> mlir::UnrealizedConversionCastOp {
658 dyn_cast_or_null<mlir::UnrealizedConversionCastOp>(v.getDefiningOp());
659 if (op && op.getNumResults() == 1 && op.getNumOperands() == 1 &&
660 op.getResultTypes()[0] == op.getOperandTypes()[0])
667 SmallVector<Operation *> opsToErase;
668 auto connect = [&](Value src, Value dest,
669 ImplicitLocOpBuilder &
builder) -> LogicalResult {
672 if (
auto op = getNoopCast(dest)) {
673 dest = op.getOperand(0);
674 opsToErase.push_back(op);
675 std::swap(src, dest);
676 }
else if (
auto op = getNoopCast(src)) {
677 src = op.getOperand(0);
678 opsToErase.push_back(op);
682 std::swap(src, dest);
685 auto *insertBlock = findInsertionBlock(src, dest);
687 return emitError(src.getLoc())
688 .append(
"This value is involved with a Wiring Problem where the "
689 "destination is in the same module but neither dominates the "
690 "other, which is not supported.")
691 .attachNote(dest.getLoc())
692 .append(
"The destination is here.");
695 builder.setInsertionPointToEnd(insertBlock);
698 if (type_isa<RefType>(dest.getType()) != type_isa<RefType>(src.getType())) {
699 if (type_isa<RefType>(dest.getType()))
700 src =
builder.create<RefSendOp>(src);
702 src =
builder.create<RefResolveOp>(src);
706 auto destOp = dyn_cast_or_null<WireOp>(dest.getDefiningOp());
707 if (destOp && dest.getUses().empty()) {
708 builder.create<NodeOp>(src, destOp.getName())
709 .setAnnotationsAttr(destOp.getAnnotations());
710 opsToErase.push_back(destOp);
721 auto *context = state.
circuit.getContext();
725 LLVM_DEBUG({ llvm::dbgs() <<
"Analyzing wiring problems:\n"; });
726 DenseMap<FModuleLike, ModuleModifications> moduleModifications;
727 DenseSet<Value> visitedSinks;
729 auto index = e.index();
730 auto problem = e.value();
734 auto source = problem.source;
735 auto sink = problem.sink;
739 if (!visitedSinks.insert(sink).second) {
740 auto diag = mlir::emitError(source.getLoc())
741 <<
"This sink is involved with a Wiring Problem which is "
742 "targeted by a source used by another Wiring Problem. "
743 "(This is both illegal and should be impossible.)";
744 diag.attachNote(source.getLoc()) <<
"The source is here";
747 FModuleLike sourceModule = getModule(source);
748 FModuleLike sinkModule = getModule(sink);
749 if (isa<FExtModuleOp>(sourceModule) || isa<FExtModuleOp>(sinkModule)) {
750 auto diag = mlir::emitError(source.getLoc())
751 <<
"This source is involved with a Wiring Problem which "
752 "includes an External Module port and External Module "
753 "ports anre not supported.";
754 diag.attachNote(sink.getLoc()) <<
"The sink is here.";
759 llvm::dbgs() <<
" - index: " << index <<
"\n"
761 <<
" module: " << sourceModule.getModuleName() <<
"\n"
762 <<
" value: " << source <<
"\n"
764 <<
" module: " << sinkModule.getModuleName() <<
"\n"
765 <<
" value: " << sink <<
"\n"
766 <<
" newNameHint: " << problem.newNameHint <<
"\n";
770 if (sink.getParentBlock() == source.getParentBlock()) {
772 sink.getParentBlock());
780 if (sourceModule == sinkModule) {
781 LLVM_DEBUG(llvm::dbgs()
782 <<
" LCA: " << sourceModule.getModuleName() <<
"\n");
783 moduleModifications[sourceModule].connectionMap[index] = source;
784 moduleModifications[sourceModule].uturns.push_back({index, sink});
792 if (sourcePaths.size() != 1 || sinkPaths.size() != 1) {
794 mlir::emitError(source.getLoc())
795 <<
"This source is involved with a Wiring Problem where the source "
796 "or the sink are multiply instantiated and this is not supported.";
797 diag.attachNote(sink.getLoc()) <<
"The sink is here.";
802 cast<FModuleOp>(instanceGraph.getTopLevelNode()->getModule());
803 auto sources = sourcePaths[0];
804 auto sinks = sinkPaths[0];
805 while (!sources.empty() && !sinks.empty()) {
806 if (sources.top() != sinks.top())
808 auto newLCA = cast<InstanceOp>(*sources.top());
809 lca = cast<FModuleOp>(newLCA.getReferencedModule(instanceGraph));
810 sources = sources.dropFront();
811 sinks = sinks.dropFront();
815 llvm::dbgs() <<
" LCA: " << lca.getModuleName() <<
"\n"
816 <<
" sourcePath: " << sourcePaths[0] <<
"\n"
817 <<
" sinkPaths: " << sinkPaths[0] <<
"\n";
821 moduleModifications[sourceModule].connectionMap[index] = source;
822 moduleModifications[sinkModule].connectionMap[index] = sink;
825 Type sourceType, sinkType;
831 RefType refType = TypeSwitch<Type, RefType>(source.getType())
835 .Case<RefType>([](RefType ref) {
return ref; });
836 sourceType = refType;
837 sinkType = refType.getType();
840 sourceType = source.getType();
841 sinkType = sink.getType();
844 auto sourceFType = type_dyn_cast<FIRRTLType>(sourceType);
845 auto sinkFType = type_dyn_cast<FIRRTLType>(sinkType);
847 return emitError(source.getLoc())
848 <<
"Wiring Problem source type \"" << sourceType
849 <<
"\" must be a FIRRTL type";
851 return emitError(sink.getLoc())
852 <<
"Wiring Problem sink type \"" << sinkType
853 <<
"\" must be a FIRRTL type";
857 if (sourceFType != sinkFType &&
859 auto diag = mlir::emitError(source.getLoc())
860 <<
"Wiring Problem source type " << sourceType
861 <<
" does not match sink type " << sinkType;
862 diag.attachNote(sink.getLoc()) <<
"The sink is here.";
868 if (
auto sinkFType = type_dyn_cast<FIRRTLType>(sink.getType());
869 sinkFType && type_isa<RefType>(sourceType) &&
871 return emitError(sink.getLoc())
872 <<
"Wiring Problem sink type \"" << sink.getType()
873 <<
"\" must be passive (no flips) when using references";
878 StringRef name, instName;
879 for (
auto instNode : llvm::reverse(insts)) {
880 auto inst = cast<InstanceOp>(*instNode);
881 auto mod = inst.getReferencedModule<FModuleOp>(instanceGraph);
883 if (problem.newNameHint.empty())
893 assert(!instName.empty());
896 moduleModifications[mod].portsToAdd.push_back(
898 instName = inst.getInstanceName();
909 LLVM_DEBUG({ llvm::dbgs() <<
"Updating modules:\n"; });
910 for (
auto *op : llvm::post_order(instanceGraph.getTopLevelNode())) {
911 auto fmodule = dyn_cast<FModuleOp>(*op->getModule());
913 if (!fmodule || !moduleModifications.count(fmodule))
916 auto modifications = moduleModifications[fmodule];
918 llvm::dbgs() <<
" - module: " << fmodule.getModuleName() <<
"\n";
919 llvm::dbgs() <<
" ports:\n";
920 for (
auto [index, port] : modifications.portsToAdd) {
921 llvm::dbgs() <<
" - name: " << port.getName() <<
"\n"
922 <<
" id: " << index <<
"\n"
923 <<
" type: " << port.type <<
"\n"
931 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
932 SmallVector<unsigned> problemIndices;
933 for (
auto [problemIdx, portInfo] : modifications.portsToAdd) {
935 newPorts.push_back({fmodule.getNumPorts(), portInfo});
936 problemIndices.push_back(problemIdx);
938 auto originalNumPorts = fmodule.getNumPorts();
939 auto portIdx = fmodule.getNumPorts();
940 fmodule.insertPorts(newPorts);
943 fmodule.getBodyBlock());
947 for (
auto [problemIdx, portPair] : llvm::zip(problemIndices, newPorts)) {
948 Value src = moduleModifications[fmodule].connectionMap[problemIdx];
949 assert(src &&
"there did not exist a driver for the port");
950 Value dest = fmodule.getArgument(portIdx++);
957 for (
auto [problemIdx, dest] : moduleModifications[fmodule].uturns) {
958 Value src = moduleModifications[fmodule].connectionMap[problemIdx];
959 assert(src &&
"there did not exist a connection for the u-turn");
965 for (
auto *inst : instanceGraph.lookup(fmodule)->uses()) {
966 InstanceOp useInst = cast<InstanceOp>(inst->getInstance());
967 auto enclosingModule = useInst->getParentOfType<FModuleOp>();
968 auto clonedInst = useInst.cloneAndInsertPorts(newPorts);
972 useInst->replaceAllUsesWith(
973 clonedInst.getResults().drop_back(newPorts.size()));
980 for (
auto [newPortIdx, problemIdx] : llvm::enumerate(problemIndices)) {
981 auto &modifications = moduleModifications[enclosingModule];
982 auto newPort = clonedInst.getResult(newPortIdx + originalNumPorts);
983 if (modifications.connectionMap.count(problemIdx)) {
984 modifications.uturns.push_back({problemIdx, newPort});
987 modifications.connectionMap[problemIdx] = newPort;
993 for (
auto *op : opsToErase)
1000 void LowerAnnotationsPass::runOnOperation() {
1001 CircuitOp circuit = getOperation();
1002 SymbolTable modules(circuit);
1012 auto annotations = circuit->getAttrOfType<ArrayAttr>(
rawAnnotations);
1020 for (
auto anno : llvm::reverse(annotations.getValue()))
1021 worklistAttrs.push_back(cast<DictionaryAttr>(anno));
1023 size_t numFailures = 0;
1024 size_t numAdded = 0;
1025 auto addToWorklist = [&](DictionaryAttr anno) {
1027 worklistAttrs.push_back(anno);
1030 ApplyState state{circuit, modules, addToWorklist, instancePathCache,
1032 LLVM_DEBUG(llvm::dbgs() <<
"Processing annotations:\n");
1033 while (!worklistAttrs.empty()) {
1034 auto attr = worklistAttrs.pop_back_val();
1035 if (applyAnnotation(attr, state).failed())
1039 if (failed(legacyToWiringProblems(state)))
1042 if (failed(solveWiringProblems(state)))
1046 numRawAnnotations += annotations.size();
1047 numAddedAnnos += numAdded;
1048 numAnnos += numAdded + annotations.size();
1052 signalPassFailure();
1056 std::unique_ptr<mlir::Pass>
1058 bool ignoreAnnotationClassless,
1059 bool noRefTypePorts) {
1060 auto pass = std::make_unique<LowerAnnotationsPass>();
1061 pass->ignoreAnnotationUnknown = ignoreAnnotationUnknown;
1062 pass->ignoreAnnotationClassless = ignoreAnnotationClassless;
1063 pass->noRefTypePorts = noRefTypePorts;
assert(baseType &&"element must be base type")
static void addAnnotation(AnnoTarget ref, unsigned fieldIdx, ArrayRef< NamedAttribute > anno)
Apply a new annotation to a resolved target.
static ArrayAttr replaceArrayAttrElement(ArrayAttr array, size_t elem, Attribute newVal)
Update an ArrayAttribute by replacing one entry.
static const AnnoRecord * getAnnotationHandler(StringRef annoStr, bool ignoreAnnotationUnknown)
Lookup a record for a given annotation class.
static std::optional< AnnoPathValue > stdResolveImpl(StringRef rawPath, ApplyState &state)
Implementation of standard resolution.
static ArrayAttr appendArrayAttr(ArrayAttr array, Attribute a)
Construct the annotation array with a new thing appended.
static LogicalResult applyDUTAnno(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
LogicalResult drop(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
Just drop the annotation.
static LogicalResult applyLoadMemoryAnno(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
Update a memory op with attributes about memory file loading.
static std::optional< Convention > parseConvention(llvm::StringRef str)
static std::optional< AnnoPathValue > noResolve(DictionaryAttr anno, ApplyState &state)
Always resolve to the circuit, ignoring the annotation.
static ArrayAttr getAnnotationsFrom(Operation *op)
Get annotations or an empty set of annotations.
static LogicalResult applyConventionAnno(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
static LogicalResult applyAttributeAnnotation(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
static FlatSymbolRefAttr scatterNonLocalPath(const AnnoPathValue &target, ApplyState &state)
Scatter breadcrumb annotations corresponding to non-local annotations along the instance path.
static FlatSymbolRefAttr buildNLA(const AnnoPathValue &target, ApplyState &state)
Make an anchor for a non-local annotation.
StringRef newName(const Twine &name)
Return a unique name, derived from the input name, and add the new name to the internal namespace.
This class provides a read-only projection of an annotation.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
StringRef getClass() const
Return the 'class' that this annotation is representing.
An instance path composed of a series of instances.
def connect(destination, source)
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
LogicalResult applyOMIR(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
Main entry point to handle scattering of an OMIRAnnotation.
constexpr const char * injectDUTHierarchyAnnoClass
constexpr const char * extractCoverageAnnoClass
constexpr const char * excludeMemToRegAnnoClass
constexpr const char * elaborationArtefactsDirectoryAnnoClass
StringRef getAnnotationAttrName()
Return the name of the attribute used for annotations on FIRRTL ops.
Direction
This represents the direction of a single port.
FIRRTLBaseType getBaseType(Type type)
If it is a base type, return it as is.
constexpr const char * extractGrandCentralClass
FieldRef getFieldRefFromValue(Value value, bool lookThroughCasts=false)
Get the FieldRef from a value.
std::optional< AnnoPathValue > stdResolve(DictionaryAttr anno, ApplyState &state)
===-------------------------------------------------------------------—===// Standard Utility Resolve...
constexpr const char * sitestBlackBoxAnnoClass
constexpr const char * convertMemToRegOfVecAnnoClass
constexpr const char * dontObfuscateModuleAnnoClass
constexpr const char * metadataDirectoryAttrName
constexpr const char * extractBlackBoxAnnoClass
constexpr const char * fullAsyncResetAnnoClass
Annotation that marks a reset (port or wire) and domain.
constexpr const char * testBenchDirAnnoClass
constexpr const char * sitestTestHarnessBlackBoxAnnoClass
constexpr const char * referenceKeyPortClass
constexpr const char * augmentedGroundTypeClass
constexpr const char * traceAnnoClass
constexpr const char * mustDedupAnnoClass
Flow foldFlow(Value val, Flow accumulatedFlow=Flow::Source)
Compute the flow for a Value, val, as determined by the FIRRTL specification.
constexpr const char * loadMemoryFromFileAnnoClass
constexpr const char * dutAnnoClass
constexpr const char * rawAnnotations
constexpr const char * extractSeqMemsAnnoClass
constexpr const char * attributeAnnoClass
bool areTypesEquivalent(FIRRTLType destType, FIRRTLType srcType, bool destOuterTypeIsConst=false, bool srcOuterTypeIsConst=false, bool requireSameWidths=false)
Returns whether the two types are equivalent.
std::optional< AnnoPathValue > resolveEntities(TokenAnnoTarget path, CircuitOp circuit, SymbolTable &symTbl, CircuitTargetCache &cache)
Convert a parsed target string to a resolved target structure.
constexpr const char * wiringSinkAnnoClass
constexpr const char * memTapSourceClass
constexpr const char * loadMemoryFromFileInlineAnnoClass
constexpr const char * forceNameAnnoClass
constexpr const char * memTapClass
constexpr const char * noDedupAnnoClass
constexpr const char * deletedKeyClass
size_t getNumPorts(Operation *op)
Return the number of ports in a module-like thing (modules, memories, etc)
constexpr const char * dataTapsClass
constexpr const char * conventionAnnoClass
constexpr const char * dedupGroupAnnoClass
constexpr const char * omirAnnoClass
constexpr const char * omirTrackerAnnoClass
constexpr const char * viewAnnoClass
constexpr const char * serializedViewAnnoClass
constexpr const char * enumDefAnnoClass
constexpr const char * enumVecAnnoClass
constexpr const char * omirFileAnnoClass
std::string canonicalizeTarget(StringRef target)
Return an input target string in canonical form.
constexpr const char * wiringSourceAnnoClass
LogicalResult applyGCTMemTaps(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
constexpr const char * traceNameAnnoClass
constexpr const char * enumComponentAnnoClass
constexpr const char * dataTapsBlackboxClass
constexpr const char * extractAssertAnnoClass
constexpr const char * memTapBlackboxClass
static LogicalResult applyWithoutTarget(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
An applier which puts the annotation on the target and drops the 'target' field from the annotation.
constexpr const char * testHarnessPathAnnoClass
constexpr const char * verifBlackBoxAnnoClass
constexpr const char * addSeqMemPortAnnoClass
LogicalResult applyWiring(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
Consume SourceAnnotation and SinkAnnotation, storing into state.
LogicalResult applyTraceName(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
Expand a TraceNameAnnotation (which has don't touch semantics) into a TraceAnnotation (which does NOT...
constexpr const char * blackBoxPathAnnoClass
constexpr const char * internalKeyPortClass
constexpr const char * addSeqMemPortsFileAnnoClass
constexpr const char * retimeModulesFileAnnoClass
constexpr const char * prefixModulesAnnoClass
constexpr const char * retimeModuleAnnoClass
constexpr const char * runFIRRTLTransformAnnoClass
constexpr const char * companionAnnoClass
std::pair< std::string, bool > getFieldName(const FieldRef &fieldRef, bool nameSafe=false)
Get a string identifier representing the FieldRef.
constexpr const char * referenceKeySourceClass
constexpr const char * literalKeyClass
constexpr const char * blackBoxTargetDirAnnoClass
constexpr const char * ignoreFullAsyncResetAnnoClass
Annotation that marks a module as not belonging to any reset domain.
LogicalResult registerAnnotationRecord(StringRef annoClass, AnnoRecord annoRecord, const std::function< void(llvm::Twine)> &errorHandler={})
Register external annotation records.
LogicalResult applyGCTDataTaps(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
constexpr const char * blackBoxInlineAnnoClass
StringRef getPortAnnotationAttrName()
Return the name of the attribute used for port annotations on FIRRTL ops.
constexpr const char * decodeTableAnnotation
constexpr const char * extractClockGatesAnnoClass
constexpr const char * inlineAnnoClass
constexpr const char * memTapPortClass
LogicalResult applyGCTView(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state)
constexpr const char * flattenAnnoClass
constexpr const char * prefixInterfacesAnnoClass
std::optional< TokenAnnoTarget > tokenizePath(StringRef origTarget)
Parse a FIRRTL annotation path into its constituent parts.
LogicalResult applyWithoutTargetImpl(const AnnoPathValue &target, DictionaryAttr anno, ApplyState &state, bool allowNonLocal)
===-------------------------------------------------------------------—===// Standard Utility Applier...
constexpr const char * extractAssumeAnnoClass
constexpr const char * grandCentralHierarchyFileAnnoClass
std::unique_ptr< mlir::Pass > createLowerFIRRTLAnnotationsPass(bool ignoreUnhandledAnnotations=false, bool ignoreClasslessAnnotations=false, bool noRefTypePorts=false)
This is the pass constructor.
std::optional< AnnoPathValue > tryResolve(DictionaryAttr anno, ApplyState &state)
Resolves with target, if it exists. If not, resolves to the circuit.
constexpr const char * dontTouchAnnoClass
void emitConnect(OpBuilder &builder, Location loc, Value lhs, Value rhs)
Emit a connect between two values.
constexpr const char * testHarnessHierAnnoClass
static llvm::StringMap< AnnoRecord > annotationRecords
constexpr const char * moduleHierAnnoClass
constexpr const char * internalKeySourceClass
static AnnoRecord NoTargetAnnotation
Resolution and application of a "firrtl.annotations.NoTargetAnnotation".
unsigned addSVAttributes(mlir::Operation *op, llvm::ArrayRef< SVAttributeAttr > attrs)
Add a list of SV attributes to an operation.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
llvm::raw_ostream & debugPassHeader(const mlir::Pass *pass, int width=80)
Write a boilerplate header for a pass to the debug stream.
SmallVector< InstanceOp > instances
===-------------------------------------------------------------------—===// LowerAnnotations ===----...
An annotation target is used to keep track of something that is targeted by an Annotation.
U dyn_cast_or_null() const
Operation * getOp() const
FModuleLike getModule() const
Get the parent module of the target.
State threaded through functions for resolving and applying annotations.
HierPathCache hierPathCache
hw::InnerSymbolNamespace & getNamespace(FModuleLike module)
DenseMap< StringAttr, LegacyWiringProblem > legacyWiringProblems
SmallVector< WiringProblem > wiringProblems
size_t numReusedHierPaths
InstancePathCache & instancePathCache
CircuitTargetCache targetCaches
FlatSymbolRefAttr getRefFor(ArrayAttr attr)
This represents an annotation targeting a specific operation.
This represents an annotation targeting a specific port of a module, memory, or instance.
A data structure that caches and provides absolute paths to module instances in the IR.
ArrayRef< InstancePath > getAbsolutePaths(ModuleOpInterface op)
void replaceInstance(InstanceOpInterface oldOp, InstanceOpInterface newOp)
Replace an InstanceOp. This is required to keep the cache updated.
InstanceGraph & instanceGraph
The instance graph of the IR.