31 #include "mlir/IR/Diagnostics.h"
32 #include "llvm/ADT/APSInt.h"
33 #include "llvm/ADT/PostOrderIterator.h"
34 #include "llvm/ADT/StringExtras.h"
35 #include "llvm/Support/Debug.h"
37 #define DEBUG_TYPE "lower-annos"
39 using namespace circt;
40 using namespace firrtl;
41 using namespace chirrtl;
54 SmallVector<Attribute> old(array.begin(), array.end());
62 SmallVector<Attribute> old(array.begin(), array.end());
70 ArrayRef<NamedAttribute> anno) {
71 auto *context = ref.
getOp()->getContext();
72 DictionaryAttr annotation;
74 SmallVector<NamedAttribute> annoField(anno.begin(), anno.end());
75 annoField.emplace_back(
94 SmallVector<Attribute> emptyPortAttr(
100 portAnno, portRef.getPortNo(),
103 ref.
getOp()->setAttr(
"portAnnotations", portAnno);
110 OpBuilder b(state.
circuit.getBodyRegion());
111 SmallVector<Attribute> insts;
114 state.
getNamespace(inst->getParentOfType<FModuleLike>())));
131 FlatSymbolRefAttr sym =
buildNLA(target, state);
140 static std::optional<AnnoPathValue>
noResolve(DictionaryAttr anno,
150 StringRef path{pathStr};
154 mlir::emitError(state.
circuit.getLoc())
155 <<
"Cannot tokenize annotation path " << rawPath;
168 auto target = anno.getNamed(
"target");
170 mlir::emitError(state.
circuit.getLoc())
171 <<
"No target field in annotation " << anno;
174 if (!isa<StringAttr>(target->getValue())) {
175 mlir::emitError(state.
circuit.getLoc())
176 <<
"Target field in annotation doesn't contain string " << anno;
179 return stdResolveImpl(cast<StringAttr>(target->getValue()).getValue(), state);
185 auto target = anno.getNamed(
"target");
187 return stdResolveImpl(cast<StringAttr>(target->getValue()).getValue(),
202 bool allowNonLocal) {
203 if (!allowNonLocal && !target.
isLocal()) {
205 auto diag = mlir::emitError(target.
ref.
getOp()->getLoc())
206 <<
"is targeted by a non-local annotation \""
207 << annotation.
getClass() <<
"\" with target "
209 <<
", but this annotation cannot be non-local";
210 diag.attachNote() <<
"see current annotation: " << anno <<
"\n";
213 SmallVector<NamedAttribute> newAnnoAttrs;
214 for (
auto &na : anno) {
215 if (na.getName().getValue() !=
"target") {
216 newAnnoAttrs.push_back(na);
217 }
else if (!target.
isLocal()) {
219 newAnnoAttrs.push_back(
240 auto loc = op->getLoc();
243 return mlir::emitError(loc) <<
"must be local";
246 return mlir::emitError(loc) <<
"can only target to a module";
248 auto moduleOp = cast<FModuleOp>(op);
251 moduleOp.setPublic();
252 SmallVector<NamedAttribute> newAnnoAttrs;
253 for (
auto &na : anno)
254 if (na.getName().getValue() !=
"target")
255 newAnnoAttrs.push_back(na);
262 return ::llvm::StringSwitch<::std::optional<Convention>>(str)
263 .Case(
"scalarized", Convention::Scalarized)
264 .Default(std::nullopt);
271 auto loc = op->getLoc();
273 auto diag = mlir::emitError(loc);
274 diag <<
"circuit.ConventionAnnotation ";
280 return error() <<
"must target a module object";
283 return error() <<
"must be local";
285 auto conventionStrAttr =
287 if (!conventionStrAttr)
290 auto conventionStr = conventionStrAttr.getValue();
293 return error() <<
"unknown convention " << conventionStr;
295 auto convention = *conventionOpt;
297 if (
auto moduleOp = dyn_cast<FModuleOp>(op)) {
298 moduleOp.setConvention(convention);
302 if (
auto extModuleOp = dyn_cast<FExtModuleOp>(op)) {
303 extModuleOp.setConvention(convention);
307 return error() <<
"can only target to a module or extmodule";
316 auto diag = mlir::emitError(op->getLoc());
317 diag << anno.getAs<StringAttr>(
"class").getValue() <<
" ";
323 <<
"must target an operation. Currently ports are not supported";
326 return error() <<
"must be local";
328 if (!isa<FModuleOp, WireOp, NodeOp, RegOp, RegResetOp>(op))
330 <<
"unhandled operation. The target must be a module, wire, node or "
333 auto name = anno.getAs<StringAttr>(
"description");
340 template <
bool isInline>
345 mlir::emitError(state.
circuit.getLoc())
346 <<
"has a " << anno.get(
"class")
347 <<
" annotation which is non-local, but this annotation is not allowed "
354 if (!target.
isOpOfType<MemOp, CombMemOp, SeqMemOp>()) {
355 mlir::emitError(op->getLoc())
356 <<
"can only apply a load memory annotation to a memory";
361 StringAttr filename = tryGetAs<StringAttr>(
362 anno, anno, isInline ?
"filename" :
"fileName", op->getLoc(),
363 anno.getAs<StringAttr>(
"class").getValue());
368 tryGetAs<StringAttr>(anno, anno,
"hexOrBinary", op->getLoc(),
369 anno.getAs<StringAttr>(
"class").getValue());
373 auto hexOrBinaryValue = hexOrBinary.getValue();
374 if (hexOrBinaryValue !=
"h" && hexOrBinaryValue !=
"b") {
375 auto diag = mlir::emitError(op->getLoc())
376 <<
"has memory initialization annotation with invalid format, "
377 "'hexOrBinary' field must be either 'h' or 'b'";
378 diag.attachNote() <<
"the full annotation is: " << anno;
383 hexOrBinaryValue ==
"b", isInline));
406 applyWithoutTarget<false, CircuitOp>};
411 {
"circt.test", {
stdResolve, applyWithoutTarget<true>}},
412 {
"circt.testLocalOnly", {
stdResolve, applyWithoutTarget<>}},
413 {
"circt.testNT", {
noResolve, applyWithoutTarget<>}},
414 {
"circt.missing", {
tryResolve, applyWithoutTarget<true>}},
415 {
"circt.Intrinsic", {
stdResolve, applyWithoutTarget<false, FExtModuleOp>}},
445 RegResetOp, InstanceOp, MemOp, CombMemOp,
446 MemoryPortOp, SeqMemOp>}},
449 applyWithoutTarget<true, FModuleOp, FExtModuleOp, InstanceOp>}},
455 {
stdResolve, applyWithoutTarget<true, MemOp, CombMemOp>}},
461 {
stdResolve, applyWithoutTarget<true, FModuleOp, FExtModuleOp>}},
465 {
stdResolve, applyWithoutTarget<false, FModuleOp, FExtModuleOp>}},
467 {
stdResolve, applyWithoutTarget<false, FModuleOp, FExtModuleOp>}},
469 {
stdResolve, applyWithoutTarget<false, FExtModuleOp>}},
471 {
stdResolve, applyWithoutTarget<false, FExtModuleOp>}},
473 {
stdResolve, applyWithoutTarget<false, FModuleOp>}},
475 {
stdResolve, applyWithoutTarget<false, FExtModuleOp>}},
480 {
stdResolve, applyWithoutTarget<false, FModuleOp, FExtModuleOp>}},
502 {
stdResolve, applyWithoutTarget<true, FModuleOp>}},
516 const std::function<
void(llvm::Twine)> &errorHandler) {
519 return LogicalResult::success();
521 errorHandler(
"annotation record '" + annoClass +
"' is registered twice\n");
522 return LogicalResult::failure();
530 bool ignoreAnnotationUnknown) {
534 if (ignoreAnnotationUnknown)
544 struct LowerAnnotationsPass
545 :
public LowerFIRRTLAnnotationsBase<LowerAnnotationsPass> {
546 void runOnOperation()
override;
547 LogicalResult applyAnnotation(DictionaryAttr anno,
ApplyState &state);
548 LogicalResult legacyToWiringProblems(
ApplyState &state);
549 LogicalResult solveWiringProblems(
ApplyState &state);
551 using LowerFIRRTLAnnotationsBase::ignoreAnnotationClassless;
552 using LowerFIRRTLAnnotationsBase::ignoreAnnotationUnknown;
553 using LowerFIRRTLAnnotationsBase::noRefTypePorts;
554 SmallVector<DictionaryAttr> worklistAttrs;
558 LogicalResult LowerAnnotationsPass::applyAnnotation(DictionaryAttr anno,
560 LLVM_DEBUG(
llvm::dbgs() <<
" - anno: " << anno <<
"\n";);
563 StringRef annoClassVal;
564 if (
auto annoClass = anno.getNamed(
"class"))
565 annoClassVal = cast<StringAttr>(annoClass->getValue()).getValue();
566 else if (ignoreAnnotationClassless)
567 annoClassVal =
"circt.missing";
569 return mlir::emitError(state.
circuit.getLoc())
570 <<
"Annotation without a class: " << anno;
576 if (!ignoreAnnotationUnknown)
577 return mlir::emitError(state.
circuit.getLoc())
578 <<
"Unhandled annotation: " << anno;
586 auto target = record->resolver(anno, state);
588 return mlir::emitError(state.
circuit.getLoc())
589 <<
"Unable to resolve target of annotation: " << anno;
590 if (record->applier(*target, anno, state).failed())
591 return mlir::emitError(state.
circuit.getLoc())
592 <<
"Unable to apply annotation: " << anno;
598 LogicalResult LowerAnnotationsPass::legacyToWiringProblems(
ApplyState &state) {
601 return mlir::emitError(state.
circuit.getLoc())
602 <<
"Unable to resolve source for pin: " << name;
604 if (problem.sinks.empty())
605 return mlir::emitError(state.
circuit.getLoc())
606 <<
"Unable to resolve sink(s) for pin: " << name;
608 for (
const auto &sink : problem.sinks) {
623 LogicalResult LowerAnnotationsPass::solveWiringProblems(
ApplyState &state) {
626 auto getModule = [](Value
value) {
627 if (BlockArgument blockArg = dyn_cast<BlockArgument>(
value))
628 return cast<FModuleLike>(blockArg.getParentBlock()->getParentOp());
629 return value.getDefiningOp()->getParentOfType<FModuleLike>();
633 auto findInsertionBlock = [&getModule](Value src, Value dest) -> Block * {
635 if (src.getParentBlock() == dest.getParentBlock())
636 return src.getParentBlock();
640 assert(getModule(src) == getModule(dest));
642 auto safelyDoms = [&](Value a, Value b) {
643 if (isa<BlockArgument>(a))
645 if (isa<BlockArgument>(b))
649 a.getParentBlock()->findAncestorOpInBlock(*b.getDefiningOp());
650 return ancestor && a.getDefiningOp()->isBeforeInBlock(ancestor);
652 if (safelyDoms(src, dest))
653 return dest.getParentBlock();
654 if (safelyDoms(dest, src))
655 return src.getParentBlock();
659 auto getNoopCast = [](Value v) -> mlir::UnrealizedConversionCastOp {
661 dyn_cast_or_null<mlir::UnrealizedConversionCastOp>(v.getDefiningOp());
662 if (op && op.getNumResults() == 1 && op.getNumOperands() == 1 &&
663 op.getResultTypes()[0] == op.getOperandTypes()[0])
670 SmallVector<Operation *> opsToErase;
671 auto connect = [&](Value src, Value dest,
672 ImplicitLocOpBuilder &
builder) -> LogicalResult {
675 if (
auto op = getNoopCast(dest)) {
676 dest = op.getOperand(0);
677 opsToErase.push_back(op);
678 std::swap(src, dest);
679 }
else if (
auto op = getNoopCast(src)) {
680 src = op.getOperand(0);
681 opsToErase.push_back(op);
685 std::swap(src, dest);
688 auto *insertBlock = findInsertionBlock(src, dest);
690 return emitError(src.getLoc())
691 .append(
"This value is involved with a Wiring Problem where the "
692 "destination is in the same module but neither dominates the "
693 "other, which is not supported.")
694 .attachNote(dest.getLoc())
695 .append(
"The destination is here.");
698 builder.setInsertionPointToEnd(insertBlock);
701 if (type_isa<RefType>(dest.getType()) != type_isa<RefType>(src.getType())) {
702 if (type_isa<RefType>(dest.getType()))
703 src =
builder.create<RefSendOp>(src);
705 src =
builder.create<RefResolveOp>(src);
709 auto destOp = dyn_cast_or_null<WireOp>(dest.getDefiningOp());
710 if (destOp && dest.getUses().empty()) {
711 builder.create<NodeOp>(src, destOp.getName())
712 .setAnnotationsAttr(destOp.getAnnotations());
713 opsToErase.push_back(destOp);
724 auto *context = state.
circuit.getContext();
728 LLVM_DEBUG({
llvm::dbgs() <<
"Analyzing wiring problems:\n"; });
729 DenseMap<FModuleLike, ModuleModifications> moduleModifications;
730 DenseSet<Value> visitedSinks;
732 auto index = e.index();
733 auto problem = e.value();
737 auto source = problem.source;
738 auto sink = problem.sink;
742 if (!visitedSinks.insert(sink).second) {
743 auto diag = mlir::emitError(source.getLoc())
744 <<
"This sink is involved with a Wiring Problem which is "
745 "targeted by a source used by another Wiring Problem. "
746 "(This is both illegal and should be impossible.)";
747 diag.attachNote(source.getLoc()) <<
"The source is here";
750 FModuleLike sourceModule = getModule(source);
751 FModuleLike sinkModule = getModule(sink);
752 if (isa<FExtModuleOp>(sourceModule) || isa<FExtModuleOp>(sinkModule)) {
753 auto diag = mlir::emitError(source.getLoc())
754 <<
"This source is involved with a Wiring Problem which "
755 "includes an External Module port and External Module "
756 "ports anre not supported.";
757 diag.attachNote(sink.getLoc()) <<
"The sink is here.";
764 <<
" module: " << sourceModule.getModuleName() <<
"\n"
765 <<
" value: " << source <<
"\n"
767 <<
" module: " << sinkModule.getModuleName() <<
"\n"
768 <<
" value: " << sink <<
"\n"
769 <<
" newNameHint: " << problem.newNameHint <<
"\n";
773 if (sink.getParentBlock() == source.getParentBlock()) {
775 sink.getParentBlock());
783 if (sourceModule == sinkModule) {
785 <<
" LCA: " << sourceModule.getModuleName() <<
"\n");
786 moduleModifications[sourceModule].connectionMap[index] = source;
787 moduleModifications[sourceModule].uturns.push_back({index, sink});
795 if (sourcePaths.size() != 1 || sinkPaths.size() != 1) {
797 mlir::emitError(source.getLoc())
798 <<
"This source is involved with a Wiring Problem where the source "
799 "or the sink are multiply instantiated and this is not supported.";
800 diag.attachNote(sink.getLoc()) <<
"The sink is here.";
805 cast<FModuleOp>(instanceGraph.getTopLevelNode()->getModule());
806 auto sources = sourcePaths[0];
807 auto sinks = sinkPaths[0];
808 while (!sources.empty() && !sinks.empty()) {
809 if (sources.top() != sinks.top())
811 auto newLCA = sources.top();
812 lca = cast<FModuleOp>(instanceGraph.getReferencedModule(newLCA));
813 sources = sources.dropFront();
814 sinks = sinks.dropFront();
818 llvm::dbgs() <<
" LCA: " << lca.getModuleName() <<
"\n"
819 <<
" sourcePaths:\n";
820 for (
auto inst : sourcePaths[0])
821 llvm::dbgs() <<
" - " << inst.getInstanceName() <<
" of "
822 << inst.getReferencedModuleName() <<
"\n";
824 for (
auto inst : sinkPaths[0])
825 llvm::dbgs() <<
" - " << inst.getInstanceName() <<
" of "
826 << inst.getReferencedModuleName() <<
"\n";
830 moduleModifications[sourceModule].connectionMap[index] = source;
831 moduleModifications[sinkModule].connectionMap[index] = sink;
834 Type sourceType, sinkType;
840 RefType refType = TypeSwitch<Type, RefType>(source.getType())
844 .Case<RefType>([](RefType ref) {
return ref; });
845 sourceType = refType;
846 sinkType = refType.getType();
849 sourceType = source.getType();
850 sinkType = sink.getType();
853 auto sourceFType = type_dyn_cast<FIRRTLType>(sourceType);
854 auto sinkFType = type_dyn_cast<FIRRTLType>(sinkType);
856 return emitError(source.getLoc())
857 <<
"Wiring Problem source type \"" << sourceType
858 <<
"\" must be a FIRRTL type";
860 return emitError(sink.getLoc())
861 <<
"Wiring Problem sink type \"" << sinkType
862 <<
"\" must be a FIRRTL type";
866 if (sourceFType != sinkFType &&
868 auto diag = mlir::emitError(source.getLoc())
869 <<
"Wiring Problem source type " << sourceType
870 <<
" does not match sink type " << sinkType;
871 diag.attachNote(sink.getLoc()) <<
"The sink is here.";
877 if (
auto sinkFType = type_dyn_cast<FIRRTLType>(sink.getType());
878 sinkFType && type_isa<RefType>(sourceType) &&
880 return emitError(sink.getLoc())
881 <<
"Wiring Problem sink type \"" << sink.getType()
882 <<
"\" must be passive (no flips) when using references";
887 StringRef name, instName;
888 for (
auto inst : llvm::reverse(insts)) {
889 auto mod = instanceGraph.getReferencedModule<FModuleOp>(inst);
891 if (problem.newNameHint.empty())
901 assert(!instName.empty());
904 moduleModifications[mod].portsToAdd.push_back(
906 instName = inst.getInstanceName();
917 LLVM_DEBUG({
llvm::dbgs() <<
"Updating modules:\n"; });
918 for (
auto *op : llvm::post_order(instanceGraph.getTopLevelNode())) {
919 auto fmodule = dyn_cast<FModuleOp>(*op->getModule());
921 if (!fmodule || !moduleModifications.count(fmodule))
924 auto modifications = moduleModifications[fmodule];
926 llvm::dbgs() <<
" - module: " << fmodule.getModuleName() <<
"\n";
928 for (
auto [index, port] : modifications.portsToAdd) {
929 llvm::dbgs() <<
" - name: " << port.getName() <<
"\n"
930 <<
" id: " << index <<
"\n"
931 <<
" type: " << port.type <<
"\n"
939 SmallVector<std::pair<unsigned, PortInfo>> newPorts;
940 SmallVector<unsigned> problemIndices;
941 for (
auto [problemIdx, portInfo] : modifications.portsToAdd) {
943 newPorts.push_back({fmodule.getNumPorts(), portInfo});
944 problemIndices.push_back(problemIdx);
946 auto originalNumPorts = fmodule.getNumPorts();
947 auto portIdx = fmodule.getNumPorts();
948 fmodule.insertPorts(newPorts);
951 fmodule.getBodyBlock());
955 for (
auto [problemIdx, portPair] : llvm::zip(problemIndices, newPorts)) {
956 Value src = moduleModifications[fmodule].connectionMap[problemIdx];
957 assert(src &&
"there did not exist a driver for the port");
958 Value dest = fmodule.getArgument(portIdx++);
965 for (
auto [problemIdx, dest] : moduleModifications[fmodule].uturns) {
966 Value src = moduleModifications[fmodule].connectionMap[problemIdx];
967 assert(src &&
"there did not exist a connection for the u-turn");
973 for (
auto *inst : instanceGraph.lookup(fmodule)->uses()) {
974 InstanceOp useInst = cast<InstanceOp>(inst->getInstance());
975 auto enclosingModule = useInst->getParentOfType<FModuleOp>();
976 auto clonedInst = useInst.cloneAndInsertPorts(newPorts);
980 useInst->replaceAllUsesWith(
981 clonedInst.getResults().drop_back(newPorts.size()));
988 for (
auto [newPortIdx, problemIdx] : llvm::enumerate(problemIndices)) {
989 auto &modifications = moduleModifications[enclosingModule];
990 auto newPort = clonedInst.getResult(newPortIdx + originalNumPorts);
991 if (modifications.connectionMap.count(problemIdx)) {
992 modifications.uturns.push_back({problemIdx, newPort});
995 modifications.connectionMap[problemIdx] = newPort;
1001 for (
auto *op : opsToErase)
1008 void LowerAnnotationsPass::runOnOperation() {
1009 CircuitOp circuit = getOperation();
1010 SymbolTable modules(circuit);
1012 LLVM_DEBUG(
llvm::dbgs() <<
"===- Running LowerAnnotations Pass "
1013 "------------------------------------------===\n");
1021 auto annotations = circuit->getAttrOfType<ArrayAttr>(
rawAnnotations);
1029 for (
auto anno : llvm::reverse(annotations.getValue()))
1030 worklistAttrs.push_back(cast<DictionaryAttr>(anno));
1032 size_t numFailures = 0;
1033 size_t numAdded = 0;
1034 auto addToWorklist = [&](DictionaryAttr anno) {
1036 worklistAttrs.push_back(anno);
1039 ApplyState state{circuit, modules, addToWorklist, instancePathCache,
1041 LLVM_DEBUG(
llvm::dbgs() <<
"Processing annotations:\n");
1042 while (!worklistAttrs.empty()) {
1043 auto attr = worklistAttrs.pop_back_val();
1044 if (applyAnnotation(attr, state).failed())
1048 if (failed(legacyToWiringProblems(state)))
1051 if (failed(solveWiringProblems(state)))
1055 numRawAnnotations += annotations.size();
1056 numAddedAnnos += numAdded;
1057 numAnnos += numAdded + annotations.size();
1061 signalPassFailure();
1065 std::unique_ptr<mlir::Pass>
1067 bool ignoreAnnotationClassless,
1068 bool noRefTypePorts) {
1069 auto pass = std::make_unique<LowerAnnotationsPass>();
1070 pass->ignoreAnnotationUnknown = ignoreAnnotationUnknown;
1071 pass->ignoreAnnotationClassless = ignoreAnnotationClassless;
1072 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 * dftTestModeEnableAnnoClass
constexpr const char * extractCoverageAnnoClass
constexpr const char * excludeMemToRegAnnoClass
constexpr const char * dftClockDividerBypassAnnoClass
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 * subCircuitsTargetDirectoryAnnoClass
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 * subCircuitDirAnnotation
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.
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
mlir::raw_indented_ostream & dbgs()
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.