21 #include "mlir/IR/Operation.h"
22 #include "mlir/Interfaces/FunctionImplementation.h"
23 #include "llvm/ADT/TypeSwitch.h"
25 using namespace circt;
26 using namespace firrtl;
35 MLIRContext *context) {
36 if (annotations.empty())
38 SmallVector<Attribute> attrs;
39 attrs.reserve(annotations.size());
40 for (
auto anno : annotations)
41 attrs.push_back(anno.getAttr());
48 : annotations(ArrayAttr::
get(context, annotations)) {}
65 if (ports && !ports.empty())
80 if (
auto op = v.getDefiningOp())
83 auto arg = dyn_cast<BlockArgument>(v);
84 auto module = cast<FModuleOp>(arg.getOwner()->getParentOp());
85 return forPort(module, arg.getArgNumber());
91 auto before = op->getAttrDictionary();
93 return op->getAttrDictionary() != before;
98 assert(portNo < portCount &&
"port index out of range.");
99 auto *context = op->getContext();
101 SmallVector<Attribute> portAnnotations;
102 if (!before || before.empty())
105 portAnnotations.append(before.begin(), before.end());
110 return before != after;
122 NamedAttrList &attrs) {
124 return bool(attrs.erase(key));
127 return attrs.set(key, attr) != attr;
145 ArrayRef<NamedAttribute> attrs,
147 DictionaryAttr originalDict) {
149 ArrayRef<NamedAttribute>::iterator it;
151 it = llvm::lower_bound(attrs, key);
152 if (it != attrs.end() && it->getName() != key)
156 attrs, [key](NamedAttribute attr) {
return attr.getName() == key; });
161 if (it == attrs.end() && annoSet.
empty())
167 if (it != attrs.end() && it->getValue() == annoSet.
getArrayAttr() &&
172 SmallVector<NamedAttribute> newAttrs;
173 newAttrs.reserve(attrs.size() + 1);
174 newAttrs.append(attrs.begin(), it);
175 if (!annoSet.
empty())
178 if (it != attrs.end())
179 newAttrs.append(it + 1, attrs.end());
180 return sorted ? DictionaryAttr::getWithSorted(annoSet.
getContext(), newAttrs)
189 attrs.getValue(),
true, attrs);
202 attrs.getValue(),
true, attrs);
212 for (
auto annotation : *
this) {
213 if (annotation.getClassAttr() == className)
220 for (
auto annotation : *
this) {
221 if (annotation.getClass() == className)
287 return llvm::all_of(
annotations, [](Attribute attr) {
298 if (newAnnotations.empty())
301 SmallVector<Attribute> annotationVec;
302 annotationVec.reserve(
annotations.size() + newAnnotations.size());
304 for (
auto anno : newAnnotations)
305 annotationVec.push_back(anno.getDict());
310 if (newAnnotations.empty())
318 SmallVector<Attribute> annotationVec;
319 annotationVec.reserve(
annotations.size() + newAnnotations.size());
321 annotationVec.append(newAnnotations.begin(), newAnnotations.end());
334 SmallVector<Attribute> annotationVec;
335 annotationVec.reserve(
annotations.size() + newAnnotations.size());
337 annotationVec.append(newAnnotations.begin(), newAnnotations.end());
364 llvm::function_ref<
bool(
Annotation)> predicate) {
372 auto it = annos.begin();
373 while (it != annos.end() && !predicate(
Annotation(*it)))
377 if (it == annos.end())
381 SmallVector<Attribute> filteredAnnos;
382 filteredAnnos.reserve(annos.size());
383 filteredAnnos.append(annos.begin(), it);
385 while (it != annos.end()) {
387 filteredAnnos.push_back(*it);
396 Operation *op, llvm::function_ref<
bool(
Annotation)> predicate) {
414 llvm::function_ref<
bool(
unsigned,
Annotation)> predicate) {
415 auto ports = dyn_cast_or_null<ArrayAttr>(module->getAttr(
"portAnnotations"));
416 if (!ports || ports.empty())
420 SmallVector<Attribute> newAnnos;
423 bool changed =
false;
424 for (
unsigned argNum = 0, argNumEnd = ports.size(); argNum < argNumEnd;
433 [&](
Annotation anno) {
return predicate(argNum, anno); });
439 module->setAttr(
"portAnnotations",
449 return cast<DictionaryAttr>(
attr);
455 if (
auto fieldID = getMember<IntegerAttr>(
"circt.fieldID"))
456 return fieldID.getInt();
462 return getDict().getAs<StringAttr>(
"class");
468 return classAttr.getValue();
479 auto [it, found] = mlir::impl::findAttrSorted(dict.begin(), dict.end(), name);
480 auto index = std::distance(dict.begin(), it);
482 SmallVector<NamedAttribute> attributes;
483 attributes.reserve(dict.size() + 1);
485 for (
auto field : dict.getValue().take_front(index))
486 attributes.push_back(field);
489 attributes.push_back(NamedAttribute(nameAttr, value));
491 for (
auto field : dict.getValue().drop_front(index + found))
492 attributes.push_back(field);
494 setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
499 SmallVector<NamedAttribute> attributes;
500 attributes.reserve(dict.size() - 1);
501 auto i = dict.begin();
503 while (i != e && i->getValue() != name)
504 attributes.push_back(*(i++));
509 attributes.append(++i, e);
511 setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
517 auto [it, found] = mlir::impl::findAttrSorted(dict.begin(), dict.end(), name);
518 auto index = std::distance(dict.begin(), it);
522 SmallVector<NamedAttribute> attributes;
523 attributes.reserve(dict.size() - 1);
525 for (
auto field : dict.getValue().take_front(index))
526 attributes.push_back(field);
528 for (
auto field : dict.getValue().drop_front(index + 1))
529 attributes.push_back(field);
531 setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
540 auto tpe = getMember<StringAttr>(
"type");
542 (tpe ==
"OMReferenceTarget" || tpe ==
"OMMemberReferenceTarget" ||
543 tpe ==
"OMMemberInstanceTarget");
553 return Annotation(this->getBase().getArray()[this->getIndex()]);
562 if (
auto module = llvm::dyn_cast<FModuleLike>(op))
564 return op->getParentOfType<FModuleLike>();
568 return TypeSwitch<AnnoTarget, AnnotationSet>(*
this)
570 [&](
auto target) {
return target.getAnnotations(); })
576 [&](
auto target) { target.setAnnotations(annotations); });
581 return TypeSwitch<AnnoTarget, Attribute>(*
this)
583 [&](
auto target) {
return target.getNLAReference(moduleNamespace); })
584 .Default([](
auto target) {
return Attribute(); });
588 return TypeSwitch<AnnoTarget, FIRRTLType>(*
this)
590 [](
auto target) {
return target.getType(); })
591 .Default([](
auto target) {
return FIRRTLType(); });
605 if (
auto module = llvm::dyn_cast<FModuleLike>(
getOp())) {
606 assert(module.getModuleNameAttr() &&
"invalid NLA reference");
612 return moduleNamespace;
619 if (
auto is = llvm::dyn_cast<hw::InnerSymbolOpInterface>(op)) {
620 auto result = is.getTargetResult();
623 return type_cast<FIRRTLType>(result.getType());
626 if (op->getNumResults() != 1)
628 return type_cast<FIRRTLType>(op->getResult(0).getType());
638 if (
auto memOp = llvm::dyn_cast<MemOp>(
getOp()))
640 if (
auto moduleOp = llvm::dyn_cast<FModuleLike>(
getOp()))
642 llvm_unreachable(
"unknown port target");
647 if (
auto memOp = llvm::dyn_cast<MemOp>(
getOp()))
649 else if (
auto moduleOp = llvm::dyn_cast<FModuleLike>(
getOp()))
652 llvm_unreachable(
"unknown port target");
657 auto module = llvm::dyn_cast<FModuleLike>(
getOp());
662 return moduleNamespace;
668 if (
auto module = llvm::dyn_cast<FModuleLike>(op))
669 return type_cast<FIRRTLType>(module.getPortType(
getPortNo()));
670 if (llvm::isa<MemOp, InstanceOp>(op))
672 llvm_unreachable(
"unknown operation kind");
683 return type ==
"OMID" || type ==
"OMReference" || type ==
"OMBigInt" ||
684 type ==
"OMLong" || type ==
"OMString" || type ==
"OMDouble" ||
685 type ==
"OMBigDecimal" || type ==
"OMDeleted";
701 auto diag = emitError(mod->getLoc())
703 << dut.getModuleName()
704 <<
"' also had such an annotation (this should "
706 diag.attachNote(dut.getLoc()) <<
"the first DUT was found here";
assert(baseType &&"element must be base type")
static DictionaryAttr applyToDictionaryAttrImpl(const AnnotationSet &annoSet, StringRef key, ArrayRef< NamedAttribute > attrs, bool sorted, DictionaryAttr originalDict)
static bool applyToPort(AnnotationSet annos, Operation *op, size_t portCount, size_t portNo)
static AnnotationSet forPort(Operation *op, size_t portNo)
static bool applyToAttrListImpl(const AnnotationSet &annoSet, StringRef key, NamedAttrList &attrs)
static ArrayAttr getAnnotationsFrom(Operation *op)
Annotation operator*() const
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
bool hasDontTouch() const
firrtl.transforms.DontTouchAnnotation
bool hasAnnotationImpl(StringAttr className) const
bool removeAnnotations(llvm::function_ref< bool(Annotation)> predicate)
Remove all annotations from this annotation set for which predicate returns true.
bool applyToPortAttrList(NamedAttrList &attrs) const
Store the annotations in this set in a NamedAttrList as an array attribute with the name firrtl....
Annotation getAnnotationImpl(StringAttr className) const
bool applyToPort(FModuleLike op, size_t portNo) const
Store the annotations in this set in an operation's portAnnotations attribute, overwriting any existi...
ArrayAttr getArrayAttr() const
Return this annotation set as an ArrayAttr.
bool removeAnnotation(Annotation anno)
Remove an annotation from this annotation set.
static AnnotationSet get(Value v)
Get an annotation set for the specified value.
bool applyToAttrList(NamedAttrList &attrs) const
Store the annotations in this set in a NamedAttrList as an array attribute with the name annotations.
DictionaryAttr applyToDictionaryAttr(DictionaryAttr attrs) const
Insert this annotation set into a DictionaryAttr under the annotations key.
bool applyToOperation(Operation *op) const
Store the annotations in this set in an operation's annotations attribute, overwriting any existing a...
void addAnnotations(ArrayRef< Annotation > annotations)
Add more annotations to this annotation set.
bool hasAnnotation(StringRef className) const
Return true if we have an annotation with the specified class name.
AnnotationSet(MLIRContext *context)
Form an empty annotation set.
static bool removePortAnnotations(Operation *module, llvm::function_ref< bool(unsigned, Annotation)> predicate)
Remove all port annotations from a module or extmodule for which predicate returns true.
static AnnotationSet forPort(FModuleLike op, size_t portNo)
Get an annotation set for the specified port.
bool canBeDeleted() const
Check if every annotation can be deleted.
bool setDontTouch(bool dontTouch)
MLIRContext * getContext() const
Return the MLIRContext corresponding to this AnnotationSet.
DictionaryAttr applyToPortDictionaryAttr(DictionaryAttr attrs) const
Insert this annotation set into a DictionaryAttr under the firrtl.annotations key.
This class provides a read-only projection of an annotation.
DictionaryAttr getDict() const
Get the data dictionary of this attribute.
void setDict(DictionaryAttr dict)
Set the data dictionary of this attribute.
unsigned getFieldID() const
Get the field id this attribute targets.
void setMember(StringAttr name, Attribute value)
Add or set a member of the annotation to a value.
bool canBeDeleted()
Returns true if this is an annotation which can be safely deleted without consequence.
void removeMember(StringAttr name)
Remove a member of the annotation.
StringRef getClass() const
Return the 'class' that this annotation is representing.
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.
The target of an inner symbol, the entity the symbol is a handle for.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
StringRef getAnnotationAttrName()
Return the name of the attribute used for annotations on FIRRTL ops.
LogicalResult extractDUT(FModuleOp mod, FModuleOp &dut)
Utility that searches for a MarkDUTAnnotation on a specific module, mod, and tries to update a design...
constexpr const char * dutAnnoClass
constexpr const char * omirTrackerAnnoClass
hw::InnerRefAttr getInnerRefTo(const hw::InnerSymTarget &target, GetNamespaceCallback getNamespace)
Obtain an inner reference to the target (operation or port), adding an inner symbol as necessary.
bool isOMIRStringEncodedPassthrough(StringRef type)
Check if an OMIR type is a string-encoded value that the FIRRTL dialect simply passes through as a st...
StringRef getDialectAnnotationAttrName()
Return the name of the dialect-prefixed attribute used for annotations.
StringRef getPortAnnotationAttrName()
Return the name of the attribute used for port annotations on FIRRTL ops.
constexpr const char * dontTouchAnnoClass
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
An annotation target is used to keep track of something that is targeted by an Annotation.
FIRRTLType getType() const
Get the type of the target.
Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const
Get a reference to this target suitable for use in an NLA.
Operation * getOp() const
FModuleLike getModule() const
Get the parent module of the target.
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
void setAnnotations(AnnotationSet annotations) const
FIRRTLType getType() const
AnnotationSet getAnnotations() const
This represents an annotation targeting a specific port of a module, memory, or instance.
FIRRTLType getType() const
AnnotationSet getAnnotations() const
void setAnnotations(AnnotationSet annotations) const
Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const
unsigned getPortNo() const
PortAnnoTarget(FModuleLike op, unsigned portNo)