CIRCT  19.0.0git
FIRRTLAnnotations.cpp
Go to the documentation of this file.
1 //===- FIRRTLAnnotations.cpp - Code for working with Annotations ----------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements helpers for working with FIRRTL annotations.
10 //
11 //===----------------------------------------------------------------------===//
12 
21 #include "mlir/IR/Operation.h"
22 #include "mlir/Interfaces/FunctionImplementation.h"
23 #include "llvm/ADT/TypeSwitch.h"
24 
25 using namespace circt;
26 using namespace firrtl;
27 
28 static ArrayAttr getAnnotationsFrom(Operation *op) {
29  if (auto annots = op->getAttrOfType<ArrayAttr>(getAnnotationAttrName()))
30  return annots;
31  return ArrayAttr::get(op->getContext(), {});
32 }
33 
34 static ArrayAttr getAnnotationsFrom(ArrayRef<Annotation> annotations,
35  MLIRContext *context) {
36  if (annotations.empty())
37  return ArrayAttr::get(context, {});
38  SmallVector<Attribute> attrs;
39  attrs.reserve(annotations.size());
40  for (auto anno : annotations)
41  attrs.push_back(anno.getAttr());
42  return ArrayAttr::get(context, attrs);
43 }
44 
45 /// Form an annotation set from an array of annotation attributes.
46 AnnotationSet::AnnotationSet(ArrayRef<Attribute> annotations,
47  MLIRContext *context)
48  : annotations(ArrayAttr::get(context, annotations)) {}
49 
50 /// Form an annotation set from an array of annotations.
51 AnnotationSet::AnnotationSet(ArrayRef<Annotation> annotations,
52  MLIRContext *context)
53  : annotations(getAnnotationsFrom(annotations, context)) {}
54 
55 /// Form an annotation set with a possibly-null ArrayAttr.
56 AnnotationSet::AnnotationSet(ArrayAttr annotations, MLIRContext *context)
57  : AnnotationSet(annotations ? annotations : ArrayAttr::get(context, {})) {}
58 
59 /// Get an annotation set for the specified operation.
62 
63 static AnnotationSet forPort(Operation *op, size_t portNo) {
64  auto ports = op->getAttrOfType<ArrayAttr>(getPortAnnotationAttrName());
65  if (ports && !ports.empty())
66  return AnnotationSet(cast<ArrayAttr>(ports[portNo]));
67  return AnnotationSet(ArrayAttr::get(op->getContext(), {}));
68 }
69 
70 AnnotationSet AnnotationSet::forPort(FModuleLike op, size_t portNo) {
71  return ::forPort(op.getOperation(), portNo);
72 }
73 
74 AnnotationSet AnnotationSet::forPort(MemOp op, size_t portNo) {
75  return ::forPort(op.getOperation(), portNo);
76 }
77 
78 /// Get an annotation set for the specified value.
80  if (auto op = v.getDefiningOp())
81  return AnnotationSet(op);
82  // If its not an Operation, then must be a block argument.
83  auto arg = dyn_cast<BlockArgument>(v);
84  auto module = cast<FModuleOp>(arg.getOwner()->getParentOp());
85  return forPort(module, arg.getArgNumber());
86 }
87 
88 /// Store the annotations in this set in an operation's `annotations` attribute,
89 /// overwriting any existing annotations.
90 bool AnnotationSet::applyToOperation(Operation *op) const {
91  auto before = op->getAttrDictionary();
92  op->setAttr(getAnnotationAttrName(), getArrayAttr());
93  return op->getAttrDictionary() != before;
94 }
95 
96 static bool applyToPort(AnnotationSet annos, Operation *op, size_t portCount,
97  size_t portNo) {
98  assert(portNo < portCount && "port index out of range.");
99  auto *context = op->getContext();
100  auto before = op->getAttrOfType<ArrayAttr>(getPortAnnotationAttrName());
101  SmallVector<Attribute> portAnnotations;
102  if (!before || before.empty())
103  portAnnotations.assign(portCount, ArrayAttr::get(context, {}));
104  else
105  portAnnotations.append(before.begin(), before.end());
106  portAnnotations[portNo] = annos.getArrayAttr();
107  auto after = ArrayAttr::get(context, portAnnotations);
108  if (before != after)
109  op->setAttr(getPortAnnotationAttrName(), after);
110  return before != after;
111 }
112 
113 bool AnnotationSet::applyToPort(FModuleLike op, size_t portNo) const {
114  return ::applyToPort(*this, op.getOperation(), op.getNumPorts(), portNo);
115 }
116 
117 bool AnnotationSet::applyToPort(MemOp op, size_t portNo) const {
118  return ::applyToPort(*this, op.getOperation(), op->getNumResults(), portNo);
119 }
120 
121 static bool applyToAttrListImpl(const AnnotationSet &annoSet, StringRef key,
122  NamedAttrList &attrs) {
123  if (annoSet.empty())
124  return bool(attrs.erase(key));
125  else {
126  auto attr = annoSet.getArrayAttr();
127  return attrs.set(key, attr) != attr;
128  }
129 }
130 
131 /// Store the annotations in this set in a `NamedAttrList` as an array attribute
132 /// with the name `annotations`.
133 bool AnnotationSet::applyToAttrList(NamedAttrList &attrs) const {
134  return applyToAttrListImpl(*this, getAnnotationAttrName(), attrs);
135 }
136 
137 /// Store the annotations in this set in a `NamedAttrList` as an array attribute
138 /// with the name `firrtl.annotations`.
139 bool AnnotationSet::applyToPortAttrList(NamedAttrList &attrs) const {
140  return applyToAttrListImpl(*this, getDialectAnnotationAttrName(), attrs);
141 }
142 
143 static DictionaryAttr applyToDictionaryAttrImpl(const AnnotationSet &annoSet,
144  StringRef key,
145  ArrayRef<NamedAttribute> attrs,
146  bool sorted,
147  DictionaryAttr originalDict) {
148  // Find the location in the dictionary where the entry would go.
149  ArrayRef<NamedAttribute>::iterator it;
150  if (sorted) {
151  it = llvm::lower_bound(attrs, key);
152  if (it != attrs.end() && it->getName() != key)
153  it = attrs.end();
154  } else {
155  it = llvm::find_if(
156  attrs, [key](NamedAttribute attr) { return attr.getName() == key; });
157  }
158 
159  // Fast path in case there are no annotations in the dictionary and we are not
160  // supposed to add any.
161  if (it == attrs.end() && annoSet.empty())
162  return originalDict;
163 
164  // Fast path in case there already is an entry in the dictionary, it matches
165  // the set, and, in the case we're supposed to remove empty sets, we're not
166  // leaving an empty entry in the dictionary.
167  if (it != attrs.end() && it->getValue() == annoSet.getArrayAttr() &&
168  !annoSet.empty())
169  return originalDict;
170 
171  // If we arrive here, we are supposed to assemble a new dictionary.
172  SmallVector<NamedAttribute> newAttrs;
173  newAttrs.reserve(attrs.size() + 1);
174  newAttrs.append(attrs.begin(), it);
175  if (!annoSet.empty())
176  newAttrs.push_back(
177  {StringAttr::get(annoSet.getContext(), key), annoSet.getArrayAttr()});
178  if (it != attrs.end())
179  newAttrs.append(it + 1, attrs.end());
180  return sorted ? DictionaryAttr::getWithSorted(annoSet.getContext(), newAttrs)
181  : DictionaryAttr::get(annoSet.getContext(), newAttrs);
182 }
183 
184 /// Update the attribute dictionary of an operation to contain this annotation
185 /// set.
186 DictionaryAttr
187 AnnotationSet::applyToDictionaryAttr(DictionaryAttr attrs) const {
189  attrs.getValue(), true, attrs);
190 }
191 
192 DictionaryAttr
193 AnnotationSet::applyToDictionaryAttr(ArrayRef<NamedAttribute> attrs) const {
194  return applyToDictionaryAttrImpl(*this, getAnnotationAttrName(), attrs, false,
195  {});
196 }
197 
198 /// Update the attribute dictionary of a port to contain this annotation set.
199 DictionaryAttr
200 AnnotationSet::applyToPortDictionaryAttr(DictionaryAttr attrs) const {
202  attrs.getValue(), true, attrs);
203 }
204 
205 DictionaryAttr
206 AnnotationSet::applyToPortDictionaryAttr(ArrayRef<NamedAttribute> attrs) const {
208  false, {});
209 }
210 
211 Annotation AnnotationSet::getAnnotationImpl(StringAttr className) const {
212  for (auto annotation : *this) {
213  if (annotation.getClassAttr() == className)
214  return annotation;
215  }
216  return {};
217 }
218 
219 Annotation AnnotationSet::getAnnotationImpl(StringRef className) const {
220  for (auto annotation : *this) {
221  if (annotation.getClass() == className)
222  return annotation;
223  }
224  return {};
225 }
226 
227 bool AnnotationSet::hasAnnotationImpl(StringAttr className) const {
228  return getAnnotationImpl(className) != Annotation();
229 }
230 
231 bool AnnotationSet::hasAnnotationImpl(StringRef className) const {
232  return getAnnotationImpl(className) != Annotation();
233 }
234 
237 }
238 
239 bool AnnotationSet::setDontTouch(bool dontTouch) {
240  if (dontTouch)
241  return addDontTouch();
242  else
243  return removeDontTouch();
244 }
245 
247  if (hasDontTouch())
248  return false;
250  getContext(), {{StringAttr::get(getContext(), "class"),
252  return true;
253 }
254 
257 }
258 
259 bool AnnotationSet::hasDontTouch(Operation *op) {
260  return AnnotationSet(op).hasDontTouch();
261 }
262 
263 bool AnnotationSet::setDontTouch(Operation *op, bool dontTouch) {
264  if (dontTouch)
265  return addDontTouch(op);
266  else
267  return removeDontTouch(op);
268 }
269 
270 bool AnnotationSet::addDontTouch(Operation *op) {
271  AnnotationSet annos(op);
272  auto changed = annos.addDontTouch();
273  if (changed)
274  annos.applyToOperation(op);
275  return changed;
276 }
277 
278 bool AnnotationSet::removeDontTouch(Operation *op) {
279  AnnotationSet annos(op);
280  auto changed = annos.removeDontTouch();
281  if (changed)
282  annos.applyToOperation(op);
283  return changed;
284 }
285 
287  return llvm::all_of(annotations, [](Attribute attr) {
288  return Annotation(attr).canBeDeleted();
289  });
290 }
291 
292 bool AnnotationSet::canBeDeleted(Operation *op) {
293  return AnnotationSet(op).canBeDeleted();
294 }
295 
296 /// Add more annotations to this AttributeSet.
297 void AnnotationSet::addAnnotations(ArrayRef<Annotation> newAnnotations) {
298  if (newAnnotations.empty())
299  return;
300 
301  SmallVector<Attribute> annotationVec;
302  annotationVec.reserve(annotations.size() + newAnnotations.size());
303  annotationVec.append(annotations.begin(), annotations.end());
304  for (auto anno : newAnnotations)
305  annotationVec.push_back(anno.getDict());
306  annotations = ArrayAttr::get(getContext(), annotationVec);
307 }
308 
309 void AnnotationSet::addAnnotations(ArrayRef<Attribute> newAnnotations) {
310  if (newAnnotations.empty())
311  return;
312 
313  if (empty()) {
314  annotations = ArrayAttr::get(getContext(), newAnnotations);
315  return;
316  }
317 
318  SmallVector<Attribute> annotationVec;
319  annotationVec.reserve(annotations.size() + newAnnotations.size());
320  annotationVec.append(annotations.begin(), annotations.end());
321  annotationVec.append(newAnnotations.begin(), newAnnotations.end());
322  annotations = ArrayAttr::get(getContext(), annotationVec);
323 }
324 
325 void AnnotationSet::addAnnotations(ArrayAttr newAnnotations) {
326  if (!newAnnotations)
327  return;
328 
329  if (empty()) {
330  annotations = newAnnotations;
331  return;
332  }
333 
334  SmallVector<Attribute> annotationVec;
335  annotationVec.reserve(annotations.size() + newAnnotations.size());
336  annotationVec.append(annotations.begin(), annotations.end());
337  annotationVec.append(newAnnotations.begin(), newAnnotations.end());
338  annotations = ArrayAttr::get(getContext(), annotationVec);
339 }
340 
341 /// Remove an annotation from this annotation set. Returns true if any were
342 /// removed, false otherwise.
344  return removeAnnotations([&](Annotation other) { return other == anno; });
345 }
346 
347 /// Remove an annotation from this annotation set. Returns true if any were
348 /// removed, false otherwise.
349 bool AnnotationSet::removeAnnotation(Attribute anno) {
350  return removeAnnotations(
351  [&](Annotation other) { return other.getDict() == anno; });
352 }
353 
354 /// Remove an annotation from this annotation set. Returns true if any were
355 /// removed, false otherwise.
356 bool AnnotationSet::removeAnnotation(StringRef className) {
357  return removeAnnotations(
358  [&](Annotation other) { return other.getClass() == className; });
359 }
360 
361 /// Remove all annotations from this annotation set for which `predicate`
362 /// returns true.
364  llvm::function_ref<bool(Annotation)> predicate) {
365  // Fast path for empty sets.
366  auto attr = getArrayAttr();
367  if (!attr)
368  return false;
369 
370  // Search for the first match.
371  ArrayRef<Attribute> annos = getArrayAttr().getValue();
372  auto it = annos.begin();
373  while (it != annos.end() && !predicate(Annotation(*it)))
374  ++it;
375 
376  // Fast path for sets where the predicate never matched.
377  if (it == annos.end())
378  return false;
379 
380  // Build a filtered list of annotations.
381  SmallVector<Attribute> filteredAnnos;
382  filteredAnnos.reserve(annos.size());
383  filteredAnnos.append(annos.begin(), it);
384  ++it;
385  while (it != annos.end()) {
386  if (!predicate(Annotation(*it)))
387  filteredAnnos.push_back(*it);
388  ++it;
389  }
390  annotations = ArrayAttr::get(getContext(), filteredAnnos);
391  return true;
392 }
393 
394 /// Remove all annotations from an operation for which `predicate` returns true.
396  Operation *op, llvm::function_ref<bool(Annotation)> predicate) {
397  AnnotationSet annos(op);
398  if (!annos.empty() && annos.removeAnnotations(predicate)) {
399  annos.applyToOperation(op);
400  return true;
401  }
402  return false;
403 }
404 
405 bool AnnotationSet::removeAnnotations(Operation *op, StringRef className) {
406  return removeAnnotations(
407  op, [&](Annotation a) { return (a.getClass() == className); });
408 }
409 
410 /// Remove all port annotations from a module or extmodule for which `predicate`
411 /// returns true.
413  Operation *module,
414  llvm::function_ref<bool(unsigned, Annotation)> predicate) {
415  auto ports = dyn_cast_or_null<ArrayAttr>(module->getAttr("portAnnotations"));
416  if (!ports || ports.empty())
417  return false;
418 
419  // Collect results
420  SmallVector<Attribute> newAnnos;
421 
422  // Filter the annotations on each argument.
423  bool changed = false;
424  for (unsigned argNum = 0, argNumEnd = ports.size(); argNum < argNumEnd;
425  ++argNum) {
426  AnnotationSet annos(AnnotationSet(cast<ArrayAttr>(ports[argNum])));
427 
428  // Go through all annotations on this port and extract the interesting
429  // ones. If any modifications were done, keep a reduced set of attributes
430  // around for the port, otherwise just stick with the existing ones.
431  if (!annos.empty())
432  changed |= annos.removeAnnotations(
433  [&](Annotation anno) { return predicate(argNum, anno); });
434  newAnnos.push_back(annos.getArrayAttr());
435  }
436 
437  // If we have made any changes, apply them to the operation.
438  if (changed)
439  module->setAttr("portAnnotations",
440  ArrayAttr::get(module->getContext(), newAnnos));
441  return changed;
442 }
443 
444 //===----------------------------------------------------------------------===//
445 // Annotation
446 //===----------------------------------------------------------------------===//
447 
448 DictionaryAttr Annotation::getDict() const {
449  return cast<DictionaryAttr>(attr);
450 }
451 
452 void Annotation::setDict(DictionaryAttr dict) { attr = dict; }
453 
454 unsigned Annotation::getFieldID() const {
455  if (auto fieldID = getMember<IntegerAttr>("circt.fieldID"))
456  return fieldID.getInt();
457  return 0;
458 }
459 
460 /// Return the 'class' that this annotation is representing.
461 StringAttr Annotation::getClassAttr() const {
462  return getDict().getAs<StringAttr>("class");
463 }
464 
465 /// Return the 'class' that this annotation is representing.
466 StringRef Annotation::getClass() const {
467  if (auto classAttr = getClassAttr())
468  return classAttr.getValue();
469  return {};
470 }
471 
472 void Annotation::setMember(StringAttr name, Attribute value) {
473  setMember(name.getValue(), value);
474 }
475 
476 void Annotation::setMember(StringRef name, Attribute value) {
477  // Binary search for the matching field.
478  auto dict = getDict();
479  auto [it, found] = mlir::impl::findAttrSorted(dict.begin(), dict.end(), name);
480  auto index = std::distance(dict.begin(), it);
481  // Create an array for the new members.
482  SmallVector<NamedAttribute> attributes;
483  attributes.reserve(dict.size() + 1);
484  // Copy over the leading annotations.
485  for (auto field : dict.getValue().take_front(index))
486  attributes.push_back(field);
487  // Push the new member.
488  auto nameAttr = StringAttr::get(dict.getContext(), name);
489  attributes.push_back(NamedAttribute(nameAttr, value));
490  // Copy remaining members, skipping the old field value.
491  for (auto field : dict.getValue().drop_front(index + found))
492  attributes.push_back(field);
493  // Commit the dictionary.
494  setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
495 }
496 
497 void Annotation::removeMember(StringAttr name) {
498  auto dict = getDict();
499  SmallVector<NamedAttribute> attributes;
500  attributes.reserve(dict.size() - 1);
501  auto i = dict.begin();
502  auto e = dict.end();
503  while (i != e && i->getValue() != name)
504  attributes.push_back(*(i++));
505  // If the member was not here, just return.
506  if (i == e)
507  return;
508  // Copy the rest of the members over.
509  attributes.append(++i, e);
510  // Commit the dictionary.
511  setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
512 }
513 
514 void Annotation::removeMember(StringRef name) {
515  // Binary search for the matching field.
516  auto dict = getDict();
517  auto [it, found] = mlir::impl::findAttrSorted(dict.begin(), dict.end(), name);
518  auto index = std::distance(dict.begin(), it);
519  if (!found)
520  return;
521  // Create an array for the new members.
522  SmallVector<NamedAttribute> attributes;
523  attributes.reserve(dict.size() - 1);
524  // Copy over the leading annotations.
525  for (auto field : dict.getValue().take_front(index))
526  attributes.push_back(field);
527  // Copy remaining members, skipping the old field value.
528  for (auto field : dict.getValue().drop_front(index + 1))
529  attributes.push_back(field);
530  // Commit the dictionary.
531  setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
532 }
533 
535 
536  // The only annotations which can be deleted are OM-affiliated.
538  return false;
539 
540  auto tpe = getMember<StringAttr>("type");
541  return tpe &&
542  (tpe == "OMReferenceTarget" || tpe == "OMMemberReferenceTarget" ||
543  tpe == "OMMemberInstanceTarget");
544 }
545 
546 void Annotation::dump() { attr.dump(); }
547 
548 //===----------------------------------------------------------------------===//
549 // AnnotationSetIterator
550 //===----------------------------------------------------------------------===//
551 
553  return Annotation(this->getBase().getArray()[this->getIndex()]);
554 }
555 
556 //===----------------------------------------------------------------------===//
557 // AnnoTarget
558 //===----------------------------------------------------------------------===//
559 
560 FModuleLike AnnoTarget::getModule() const {
561  auto *op = getOp();
562  if (auto module = llvm::dyn_cast<FModuleLike>(op))
563  return module;
564  return op->getParentOfType<FModuleLike>();
565 }
566 
568  return TypeSwitch<AnnoTarget, AnnotationSet>(*this)
570  [&](auto target) { return target.getAnnotations(); })
571  .Default([&](auto target) { return AnnotationSet(getOp()); });
572 }
573 
574 void AnnoTarget::setAnnotations(AnnotationSet annotations) const {
575  TypeSwitch<AnnoTarget>(*this).Case<OpAnnoTarget, PortAnnoTarget>(
576  [&](auto target) { target.setAnnotations(annotations); });
577 }
578 
579 Attribute
581  return TypeSwitch<AnnoTarget, Attribute>(*this)
583  [&](auto target) { return target.getNLAReference(moduleNamespace); })
584  .Default([](auto target) { return Attribute(); });
585 }
586 
588  return TypeSwitch<AnnoTarget, FIRRTLType>(*this)
590  [](auto target) { return target.getType(); })
591  .Default([](auto target) { return FIRRTLType(); });
592 }
593 
595  return AnnotationSet(getOp());
596 }
597 
599  annotations.applyToOperation(getOp());
600 }
601 
602 Attribute
604  // If the op is a module, just return the module name.
605  if (auto module = llvm::dyn_cast<FModuleLike>(getOp())) {
606  assert(module.getModuleNameAttr() && "invalid NLA reference");
607  return FlatSymbolRefAttr::get(module.getModuleNameAttr());
608  }
609  // Return an inner-ref to the target.
611  getOp(), [&moduleNamespace](auto _) -> hw::InnerSymbolNamespace & {
612  return moduleNamespace;
613  });
614 }
615 
617  auto *op = getOp();
618  // Annotations that target operations are resolved like inner symbols.
619  if (auto is = llvm::dyn_cast<hw::InnerSymbolOpInterface>(op)) {
620  auto result = is.getTargetResult();
621  if (!result)
622  return {};
623  return type_cast<FIRRTLType>(result.getType());
624  }
625  // Fallback to assuming the single result is the target.
626  if (op->getNumResults() != 1)
627  return {};
628  return type_cast<FIRRTLType>(op->getResult(0).getType());
629 }
630 
631 PortAnnoTarget::PortAnnoTarget(FModuleLike op, unsigned portNo)
632  : AnnoTarget({op, portNo}) {}
633 
634 PortAnnoTarget::PortAnnoTarget(MemOp op, unsigned portNo)
635  : AnnoTarget({op, portNo}) {}
636 
638  if (auto memOp = llvm::dyn_cast<MemOp>(getOp()))
639  return AnnotationSet::forPort(memOp, getPortNo());
640  if (auto moduleOp = llvm::dyn_cast<FModuleLike>(getOp()))
641  return AnnotationSet::forPort(moduleOp, getPortNo());
642  llvm_unreachable("unknown port target");
643  return AnnotationSet(getOp()->getContext());
644 }
645 
647  if (auto memOp = llvm::dyn_cast<MemOp>(getOp()))
648  annotations.applyToPort(memOp, getPortNo());
649  else if (auto moduleOp = llvm::dyn_cast<FModuleLike>(getOp()))
650  annotations.applyToPort(moduleOp, getPortNo());
651  else
652  llvm_unreachable("unknown port target");
653 }
654 
656  hw::InnerSymbolNamespace &moduleNamespace) const {
657  auto module = llvm::dyn_cast<FModuleLike>(getOp());
658  auto target = module ? hw::InnerSymTarget(getPortNo(), module)
661  target, [&moduleNamespace](auto _) -> hw::InnerSymbolNamespace & {
662  return moduleNamespace;
663  });
664 }
665 
667  auto *op = getOp();
668  if (auto module = llvm::dyn_cast<FModuleLike>(op))
669  return type_cast<FIRRTLType>(module.getPortType(getPortNo()));
670  if (llvm::isa<MemOp, InstanceOp>(op))
671  return type_cast<FIRRTLType>(op->getResult(getPortNo()).getType());
672  llvm_unreachable("unknown operation kind");
673  return {};
674 }
675 
676 //===----------------------------------------------------------------------===//
677 // Annotation Details
678 //===----------------------------------------------------------------------===//
679 
680 /// Check if an OMIR type is a string-encoded value that the FIRRTL dialect
681 /// simply passes through as a string without any decoding.
683  return type == "OMID" || type == "OMReference" || type == "OMBigInt" ||
684  type == "OMLong" || type == "OMString" || type == "OMDouble" ||
685  type == "OMBigDecimal" || type == "OMDeleted";
686 }
687 
688 //===----------------------------------------------------------------------===//
689 // Utilities for Specific Annotations
690 //
691 // TODO: Remove these in favor of first-class annotations.
692 //===----------------------------------------------------------------------===//
693 
694 LogicalResult circt::firrtl::extractDUT(const FModuleOp mod, FModuleOp &dut) {
695  if (!AnnotationSet(mod).hasAnnotation(dutAnnoClass))
696  return success();
697 
698  // TODO: This check is duplicated multiple places. This should be factored
699  // out as part of the annotation lowering pass.
700  if (dut) {
701  auto diag = emitError(mod->getLoc())
702  << "is marked with a '" << dutAnnoClass << "', but '"
703  << dut.getModuleName()
704  << "' also had such an annotation (this should "
705  "be impossible!)";
706  diag.attachNote(dut.getLoc()) << "the first DUT was found here";
707  return failure();
708  }
709  dut = mod;
710  return success();
711 }
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)
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.
Definition: CalyxOps.cpp:54
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.
Definition: DebugAnalysis.h:21
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
AnnotationSet getAnnotations() const
This represents an annotation targeting a specific port of a module, memory, or instance.
AnnotationSet getAnnotations() const
void setAnnotations(AnnotationSet annotations) const
Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const
PortAnnoTarget(FModuleLike op, unsigned portNo)