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());
109 return before != after;
121 NamedAttrList &attrs) {
123 return bool(attrs.erase(key));
126 return attrs.set(key, attr) != attr;
144 ArrayRef<NamedAttribute> attrs,
146 DictionaryAttr originalDict) {
148 ArrayRef<NamedAttribute>::iterator it;
150 it = llvm::lower_bound(attrs, key);
151 if (it != attrs.end() && it->getName() != key)
155 attrs, [key](NamedAttribute attr) {
return attr.getName() == key; });
160 if (it == attrs.end() && annoSet.
empty())
166 if (it != attrs.end() && it->getValue() == annoSet.
getArrayAttr() &&
171 SmallVector<NamedAttribute> newAttrs;
172 newAttrs.reserve(attrs.size() + 1);
173 newAttrs.append(attrs.begin(), it);
174 if (!annoSet.
empty())
177 if (it != attrs.end())
178 newAttrs.append(it + 1, attrs.end());
179 return sorted ? DictionaryAttr::getWithSorted(annoSet.
getContext(), newAttrs)
188 attrs.getValue(),
true, attrs);
201 attrs.getValue(),
true, attrs);
211 for (
auto annotation : *
this) {
212 if (annotation.getClassAttr() == className)
219 for (
auto annotation : *
this) {
220 if (annotation.getClass() == className)
286 return llvm::all_of(
annotations, [](Attribute attr) {
297 if (newAnnotations.empty())
300 SmallVector<Attribute> annotationVec;
301 annotationVec.reserve(
annotations.size() + newAnnotations.size());
303 for (
auto anno : newAnnotations)
304 annotationVec.push_back(anno.getDict());
309 if (newAnnotations.empty())
317 SmallVector<Attribute> annotationVec;
318 annotationVec.reserve(
annotations.size() + newAnnotations.size());
320 annotationVec.append(newAnnotations.begin(), newAnnotations.end());
333 SmallVector<Attribute> annotationVec;
334 annotationVec.reserve(
annotations.size() + newAnnotations.size());
336 annotationVec.append(newAnnotations.begin(), newAnnotations.end());
363 llvm::function_ref<
bool(
Annotation)> predicate) {
371 auto it = annos.begin();
372 while (it != annos.end() && !predicate(
Annotation(*it)))
376 if (it == annos.end())
380 SmallVector<Attribute> filteredAnnos;
381 filteredAnnos.reserve(annos.size());
382 filteredAnnos.append(annos.begin(), it);
384 while (it != annos.end()) {
386 filteredAnnos.push_back(*it);
395 Operation *op, llvm::function_ref<
bool(
Annotation)> predicate) {
413 llvm::function_ref<
bool(
unsigned,
Annotation)> predicate) {
414 auto ports = module->getAttr(
"portAnnotations").dyn_cast_or_null<ArrayAttr>();
415 if (!ports || ports.empty())
419 SmallVector<Attribute> newAnnos;
422 bool changed =
false;
423 for (
unsigned argNum = 0, argNumEnd = ports.size(); argNum < argNumEnd;
432 [&](
Annotation anno) {
return predicate(argNum, anno); });
438 module->setAttr(
"portAnnotations",
448 return cast<DictionaryAttr>(
attr);
454 if (
auto fieldID = getMember<IntegerAttr>(
"circt.fieldID"))
455 return fieldID.getInt();
461 return getDict().getAs<StringAttr>(
"class");
467 return classAttr.getValue();
478 auto [it, found] = mlir::impl::findAttrSorted(dict.begin(), dict.end(), name);
479 auto index = std::distance(dict.begin(), it);
481 SmallVector<NamedAttribute> attributes;
482 attributes.reserve(dict.size() + 1);
484 for (
auto field : dict.getValue().take_front(index))
485 attributes.push_back(field);
488 attributes.push_back(NamedAttribute(nameAttr,
value));
490 for (
auto field : dict.getValue().drop_front(index + found))
491 attributes.push_back(field);
493 setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
498 SmallVector<NamedAttribute> attributes;
499 attributes.reserve(dict.size() - 1);
500 auto i = dict.begin();
502 while (i != e && i->getValue() != name)
503 attributes.push_back(*(i++));
508 attributes.append(++i, e);
510 setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
516 auto [it, found] = mlir::impl::findAttrSorted(dict.begin(), dict.end(), name);
517 auto index = std::distance(dict.begin(), it);
521 SmallVector<NamedAttribute> attributes;
522 attributes.reserve(dict.size() - 1);
524 for (
auto field : dict.getValue().take_front(index))
525 attributes.push_back(field);
527 for (
auto field : dict.getValue().drop_front(index + 1))
528 attributes.push_back(field);
530 setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
539 auto tpe = getMember<StringAttr>(
"type");
541 (tpe ==
"OMReferenceTarget" || tpe ==
"OMMemberReferenceTarget" ||
542 tpe ==
"OMMemberInstanceTarget");
552 return Annotation(this->getBase().getArray()[this->getIndex()]);
561 if (
auto module = llvm::dyn_cast<FModuleLike>(op))
563 return op->getParentOfType<FModuleLike>();
567 return TypeSwitch<AnnoTarget, AnnotationSet>(*
this)
569 [&](
auto target) {
return target.getAnnotations(); })
575 [&](
auto target) { target.setAnnotations(annotations); });
580 return TypeSwitch<AnnoTarget, Attribute>(*
this)
582 [&](
auto target) {
return target.getNLAReference(moduleNamespace); })
583 .Default([](
auto target) {
return Attribute(); });
587 return TypeSwitch<AnnoTarget, FIRRTLType>(*
this)
589 [](
auto target) {
return target.getType(); })
590 .Default([](
auto target) {
return FIRRTLType(); });
604 if (
auto module = llvm::dyn_cast<FModuleLike>(
getOp())) {
605 assert(module.getModuleNameAttr() &&
"invalid NLA reference");
611 return moduleNamespace;
618 if (
auto is = llvm::dyn_cast<hw::InnerSymbolOpInterface>(op)) {
619 auto result = is.getTargetResult();
622 return type_cast<FIRRTLType>(result.getType());
625 if (op->getNumResults() != 1)
627 return type_cast<FIRRTLType>(op->getResult(0).getType());
637 if (
auto memOp = llvm::dyn_cast<MemOp>(
getOp()))
639 if (
auto moduleOp = llvm::dyn_cast<FModuleLike>(
getOp()))
641 llvm_unreachable(
"unknown port target");
646 if (
auto memOp = llvm::dyn_cast<MemOp>(
getOp()))
648 else if (
auto moduleOp = llvm::dyn_cast<FModuleLike>(
getOp()))
651 llvm_unreachable(
"unknown port target");
656 auto module = llvm::dyn_cast<FModuleLike>(
getOp());
661 return moduleNamespace;
667 if (
auto module = llvm::dyn_cast<FModuleLike>(op))
668 return type_cast<FIRRTLType>(module.getPortType(
getPortNo()));
669 if (llvm::isa<MemOp, InstanceOp>(op))
671 llvm_unreachable(
"unknown operation kind");
682 return type ==
"OMID" || type ==
"OMReference" || type ==
"OMBigInt" ||
683 type ==
"OMLong" || type ==
"OMString" || type ==
"OMDouble" ||
684 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
This file defines an intermediate representation for circuits acting as an abstraction for constraint...
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)