CIRCT  18.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  op->setAttr(getPortAnnotationAttrName(), after);
109  return before != after;
110 }
111 
112 bool AnnotationSet::applyToPort(FModuleLike op, size_t portNo) const {
113  return ::applyToPort(*this, op.getOperation(), op.getNumPorts(), portNo);
114 }
115 
116 bool AnnotationSet::applyToPort(MemOp op, size_t portNo) const {
117  return ::applyToPort(*this, op.getOperation(), op->getNumResults(), portNo);
118 }
119 
120 static bool applyToAttrListImpl(const AnnotationSet &annoSet, StringRef key,
121  NamedAttrList &attrs) {
122  if (annoSet.empty())
123  return bool(attrs.erase(key));
124  else {
125  auto attr = annoSet.getArrayAttr();
126  return attrs.set(key, attr) != attr;
127  }
128 }
129 
130 /// Store the annotations in this set in a `NamedAttrList` as an array attribute
131 /// with the name `annotations`.
132 bool AnnotationSet::applyToAttrList(NamedAttrList &attrs) const {
133  return applyToAttrListImpl(*this, getAnnotationAttrName(), attrs);
134 }
135 
136 /// Store the annotations in this set in a `NamedAttrList` as an array attribute
137 /// with the name `firrtl.annotations`.
138 bool AnnotationSet::applyToPortAttrList(NamedAttrList &attrs) const {
139  return applyToAttrListImpl(*this, getDialectAnnotationAttrName(), attrs);
140 }
141 
142 static DictionaryAttr applyToDictionaryAttrImpl(const AnnotationSet &annoSet,
143  StringRef key,
144  ArrayRef<NamedAttribute> attrs,
145  bool sorted,
146  DictionaryAttr originalDict) {
147  // Find the location in the dictionary where the entry would go.
148  ArrayRef<NamedAttribute>::iterator it;
149  if (sorted) {
150  it = llvm::lower_bound(attrs, key);
151  if (it != attrs.end() && it->getName() != key)
152  it = attrs.end();
153  } else {
154  it = llvm::find_if(
155  attrs, [key](NamedAttribute attr) { return attr.getName() == key; });
156  }
157 
158  // Fast path in case there are no annotations in the dictionary and we are not
159  // supposed to add any.
160  if (it == attrs.end() && annoSet.empty())
161  return originalDict;
162 
163  // Fast path in case there already is an entry in the dictionary, it matches
164  // the set, and, in the case we're supposed to remove empty sets, we're not
165  // leaving an empty entry in the dictionary.
166  if (it != attrs.end() && it->getValue() == annoSet.getArrayAttr() &&
167  !annoSet.empty())
168  return originalDict;
169 
170  // If we arrive here, we are supposed to assemble a new dictionary.
171  SmallVector<NamedAttribute> newAttrs;
172  newAttrs.reserve(attrs.size() + 1);
173  newAttrs.append(attrs.begin(), it);
174  if (!annoSet.empty())
175  newAttrs.push_back(
176  {StringAttr::get(annoSet.getContext(), key), annoSet.getArrayAttr()});
177  if (it != attrs.end())
178  newAttrs.append(it + 1, attrs.end());
179  return sorted ? DictionaryAttr::getWithSorted(annoSet.getContext(), newAttrs)
180  : DictionaryAttr::get(annoSet.getContext(), newAttrs);
181 }
182 
183 /// Update the attribute dictionary of an operation to contain this annotation
184 /// set.
185 DictionaryAttr
186 AnnotationSet::applyToDictionaryAttr(DictionaryAttr attrs) const {
188  attrs.getValue(), true, attrs);
189 }
190 
191 DictionaryAttr
192 AnnotationSet::applyToDictionaryAttr(ArrayRef<NamedAttribute> attrs) const {
193  return applyToDictionaryAttrImpl(*this, getAnnotationAttrName(), attrs, false,
194  {});
195 }
196 
197 /// Update the attribute dictionary of a port to contain this annotation set.
198 DictionaryAttr
199 AnnotationSet::applyToPortDictionaryAttr(DictionaryAttr attrs) const {
201  attrs.getValue(), true, attrs);
202 }
203 
204 DictionaryAttr
205 AnnotationSet::applyToPortDictionaryAttr(ArrayRef<NamedAttribute> attrs) const {
207  false, {});
208 }
209 
210 Annotation AnnotationSet::getAnnotationImpl(StringAttr className) const {
211  for (auto annotation : *this) {
212  if (annotation.getClassAttr() == className)
213  return annotation;
214  }
215  return {};
216 }
217 
218 Annotation AnnotationSet::getAnnotationImpl(StringRef className) const {
219  for (auto annotation : *this) {
220  if (annotation.getClass() == className)
221  return annotation;
222  }
223  return {};
224 }
225 
226 bool AnnotationSet::hasAnnotationImpl(StringAttr className) const {
227  return getAnnotationImpl(className) != Annotation();
228 }
229 
230 bool AnnotationSet::hasAnnotationImpl(StringRef className) const {
231  return getAnnotationImpl(className) != Annotation();
232 }
233 
236 }
237 
238 bool AnnotationSet::setDontTouch(bool dontTouch) {
239  if (dontTouch)
240  return addDontTouch();
241  else
242  return removeDontTouch();
243 }
244 
246  if (hasDontTouch())
247  return false;
249  getContext(), {{StringAttr::get(getContext(), "class"),
251  return true;
252 }
253 
256 }
257 
258 bool AnnotationSet::hasDontTouch(Operation *op) {
259  return AnnotationSet(op).hasDontTouch();
260 }
261 
262 bool AnnotationSet::setDontTouch(Operation *op, bool dontTouch) {
263  if (dontTouch)
264  return addDontTouch(op);
265  else
266  return removeDontTouch(op);
267 }
268 
269 bool AnnotationSet::addDontTouch(Operation *op) {
270  AnnotationSet annos(op);
271  auto changed = annos.addDontTouch();
272  if (changed)
273  annos.applyToOperation(op);
274  return changed;
275 }
276 
277 bool AnnotationSet::removeDontTouch(Operation *op) {
278  AnnotationSet annos(op);
279  auto changed = annos.removeDontTouch();
280  if (changed)
281  annos.applyToOperation(op);
282  return changed;
283 }
284 
286  return llvm::all_of(annotations, [](Attribute attr) {
287  return Annotation(attr).canBeDeleted();
288  });
289 }
290 
291 bool AnnotationSet::canBeDeleted(Operation *op) {
292  return AnnotationSet(op).canBeDeleted();
293 }
294 
295 /// Add more annotations to this AttributeSet.
296 void AnnotationSet::addAnnotations(ArrayRef<Annotation> newAnnotations) {
297  if (newAnnotations.empty())
298  return;
299 
300  SmallVector<Attribute> annotationVec;
301  annotationVec.reserve(annotations.size() + newAnnotations.size());
302  annotationVec.append(annotations.begin(), annotations.end());
303  for (auto anno : newAnnotations)
304  annotationVec.push_back(anno.getDict());
305  annotations = ArrayAttr::get(getContext(), annotationVec);
306 }
307 
308 void AnnotationSet::addAnnotations(ArrayRef<Attribute> newAnnotations) {
309  if (newAnnotations.empty())
310  return;
311 
312  if (empty()) {
313  annotations = ArrayAttr::get(getContext(), newAnnotations);
314  return;
315  }
316 
317  SmallVector<Attribute> annotationVec;
318  annotationVec.reserve(annotations.size() + newAnnotations.size());
319  annotationVec.append(annotations.begin(), annotations.end());
320  annotationVec.append(newAnnotations.begin(), newAnnotations.end());
321  annotations = ArrayAttr::get(getContext(), annotationVec);
322 }
323 
324 void AnnotationSet::addAnnotations(ArrayAttr newAnnotations) {
325  if (!newAnnotations)
326  return;
327 
328  if (empty()) {
329  annotations = newAnnotations;
330  return;
331  }
332 
333  SmallVector<Attribute> annotationVec;
334  annotationVec.reserve(annotations.size() + newAnnotations.size());
335  annotationVec.append(annotations.begin(), annotations.end());
336  annotationVec.append(newAnnotations.begin(), newAnnotations.end());
337  annotations = ArrayAttr::get(getContext(), annotationVec);
338 }
339 
340 /// Remove an annotation from this annotation set. Returns true if any were
341 /// removed, false otherwise.
343  return removeAnnotations([&](Annotation other) { return other == anno; });
344 }
345 
346 /// Remove an annotation from this annotation set. Returns true if any were
347 /// removed, false otherwise.
348 bool AnnotationSet::removeAnnotation(Attribute anno) {
349  return removeAnnotations(
350  [&](Annotation other) { return other.getDict() == anno; });
351 }
352 
353 /// Remove an annotation from this annotation set. Returns true if any were
354 /// removed, false otherwise.
355 bool AnnotationSet::removeAnnotation(StringRef className) {
356  return removeAnnotations(
357  [&](Annotation other) { return other.getClass() == className; });
358 }
359 
360 /// Remove all annotations from this annotation set for which `predicate`
361 /// returns true.
363  llvm::function_ref<bool(Annotation)> predicate) {
364  // Fast path for empty sets.
365  auto attr = getArrayAttr();
366  if (!attr)
367  return false;
368 
369  // Search for the first match.
370  ArrayRef<Attribute> annos = getArrayAttr().getValue();
371  auto it = annos.begin();
372  while (it != annos.end() && !predicate(Annotation(*it)))
373  ++it;
374 
375  // Fast path for sets where the predicate never matched.
376  if (it == annos.end())
377  return false;
378 
379  // Build a filtered list of annotations.
380  SmallVector<Attribute> filteredAnnos;
381  filteredAnnos.reserve(annos.size());
382  filteredAnnos.append(annos.begin(), it);
383  ++it;
384  while (it != annos.end()) {
385  if (!predicate(Annotation(*it)))
386  filteredAnnos.push_back(*it);
387  ++it;
388  }
389  annotations = ArrayAttr::get(getContext(), filteredAnnos);
390  return true;
391 }
392 
393 /// Remove all annotations from an operation for which `predicate` returns true.
395  Operation *op, llvm::function_ref<bool(Annotation)> predicate) {
396  AnnotationSet annos(op);
397  if (!annos.empty() && annos.removeAnnotations(predicate)) {
398  annos.applyToOperation(op);
399  return true;
400  }
401  return false;
402 }
403 
404 bool AnnotationSet::removeAnnotations(Operation *op, StringRef className) {
405  return removeAnnotations(
406  op, [&](Annotation a) { return (a.getClass() == className); });
407 }
408 
409 /// Remove all port annotations from a module or extmodule for which `predicate`
410 /// returns true.
412  Operation *module,
413  llvm::function_ref<bool(unsigned, Annotation)> predicate) {
414  auto ports = module->getAttr("portAnnotations").dyn_cast_or_null<ArrayAttr>();
415  if (!ports || ports.empty())
416  return false;
417 
418  // Collect results
419  SmallVector<Attribute> newAnnos;
420 
421  // Filter the annotations on each argument.
422  bool changed = false;
423  for (unsigned argNum = 0, argNumEnd = ports.size(); argNum < argNumEnd;
424  ++argNum) {
425  AnnotationSet annos(AnnotationSet(cast<ArrayAttr>(ports[argNum])));
426 
427  // Go through all annotations on this port and extract the interesting
428  // ones. If any modifications were done, keep a reduced set of attributes
429  // around for the port, otherwise just stick with the existing ones.
430  if (!annos.empty())
431  changed |= annos.removeAnnotations(
432  [&](Annotation anno) { return predicate(argNum, anno); });
433  newAnnos.push_back(annos.getArrayAttr());
434  }
435 
436  // If we have made any changes, apply them to the operation.
437  if (changed)
438  module->setAttr("portAnnotations",
439  ArrayAttr::get(module->getContext(), newAnnos));
440  return changed;
441 }
442 
443 //===----------------------------------------------------------------------===//
444 // Annotation
445 //===----------------------------------------------------------------------===//
446 
447 DictionaryAttr Annotation::getDict() const {
448  return cast<DictionaryAttr>(attr);
449 }
450 
451 void Annotation::setDict(DictionaryAttr dict) { attr = dict; }
452 
453 unsigned Annotation::getFieldID() const {
454  if (auto fieldID = getMember<IntegerAttr>("circt.fieldID"))
455  return fieldID.getInt();
456  return 0;
457 }
458 
459 /// Return the 'class' that this annotation is representing.
460 StringAttr Annotation::getClassAttr() const {
461  return getDict().getAs<StringAttr>("class");
462 }
463 
464 /// Return the 'class' that this annotation is representing.
465 StringRef Annotation::getClass() const {
466  if (auto classAttr = getClassAttr())
467  return classAttr.getValue();
468  return {};
469 }
470 
471 void Annotation::setMember(StringAttr name, Attribute value) {
472  setMember(name.getValue(), value);
473 }
474 
475 void Annotation::setMember(StringRef name, Attribute value) {
476  // Binary search for the matching field.
477  auto dict = getDict();
478  auto [it, found] = mlir::impl::findAttrSorted(dict.begin(), dict.end(), name);
479  auto index = std::distance(dict.begin(), it);
480  // Create an array for the new members.
481  SmallVector<NamedAttribute> attributes;
482  attributes.reserve(dict.size() + 1);
483  // Copy over the leading annotations.
484  for (auto field : dict.getValue().take_front(index))
485  attributes.push_back(field);
486  // Push the new member.
487  auto nameAttr = StringAttr::get(dict.getContext(), name);
488  attributes.push_back(NamedAttribute(nameAttr, value));
489  // Copy remaining members, skipping the old field value.
490  for (auto field : dict.getValue().drop_front(index + found))
491  attributes.push_back(field);
492  // Commit the dictionary.
493  setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
494 }
495 
496 void Annotation::removeMember(StringAttr name) {
497  auto dict = getDict();
498  SmallVector<NamedAttribute> attributes;
499  attributes.reserve(dict.size() - 1);
500  auto i = dict.begin();
501  auto e = dict.end();
502  while (i != e && i->getValue() != name)
503  attributes.push_back(*(i++));
504  // If the member was not here, just return.
505  if (i == e)
506  return;
507  // Copy the rest of the members over.
508  attributes.append(++i, e);
509  // Commit the dictionary.
510  setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
511 }
512 
513 void Annotation::removeMember(StringRef name) {
514  // Binary search for the matching field.
515  auto dict = getDict();
516  auto [it, found] = mlir::impl::findAttrSorted(dict.begin(), dict.end(), name);
517  auto index = std::distance(dict.begin(), it);
518  if (!found)
519  return;
520  // Create an array for the new members.
521  SmallVector<NamedAttribute> attributes;
522  attributes.reserve(dict.size() - 1);
523  // Copy over the leading annotations.
524  for (auto field : dict.getValue().take_front(index))
525  attributes.push_back(field);
526  // Copy remaining members, skipping the old field value.
527  for (auto field : dict.getValue().drop_front(index + 1))
528  attributes.push_back(field);
529  // Commit the dictionary.
530  setDict(DictionaryAttr::getWithSorted(dict.getContext(), attributes));
531 }
532 
534 
535  // The only annotations which can be deleted are OM-affiliated.
537  return false;
538 
539  auto tpe = getMember<StringAttr>("type");
540  return tpe &&
541  (tpe == "OMReferenceTarget" || tpe == "OMMemberReferenceTarget" ||
542  tpe == "OMMemberInstanceTarget");
543 }
544 
545 void Annotation::dump() { attr.dump(); }
546 
547 //===----------------------------------------------------------------------===//
548 // AnnotationSetIterator
549 //===----------------------------------------------------------------------===//
550 
552  return Annotation(this->getBase().getArray()[this->getIndex()]);
553 }
554 
555 //===----------------------------------------------------------------------===//
556 // AnnoTarget
557 //===----------------------------------------------------------------------===//
558 
559 FModuleLike AnnoTarget::getModule() const {
560  auto *op = getOp();
561  if (auto module = llvm::dyn_cast<FModuleLike>(op))
562  return module;
563  return op->getParentOfType<FModuleLike>();
564 }
565 
567  return TypeSwitch<AnnoTarget, AnnotationSet>(*this)
569  [&](auto target) { return target.getAnnotations(); })
570  .Default([&](auto target) { return AnnotationSet(getOp()); });
571 }
572 
573 void AnnoTarget::setAnnotations(AnnotationSet annotations) const {
574  TypeSwitch<AnnoTarget>(*this).Case<OpAnnoTarget, PortAnnoTarget>(
575  [&](auto target) { target.setAnnotations(annotations); });
576 }
577 
578 Attribute
580  return TypeSwitch<AnnoTarget, Attribute>(*this)
582  [&](auto target) { return target.getNLAReference(moduleNamespace); })
583  .Default([](auto target) { return Attribute(); });
584 }
585 
587  return TypeSwitch<AnnoTarget, FIRRTLType>(*this)
589  [](auto target) { return target.getType(); })
590  .Default([](auto target) { return FIRRTLType(); });
591 }
592 
594  return AnnotationSet(getOp());
595 }
596 
598  annotations.applyToOperation(getOp());
599 }
600 
601 Attribute
603  // If the op is a module, just return the module name.
604  if (auto module = llvm::dyn_cast<FModuleLike>(getOp())) {
605  assert(module.getModuleNameAttr() && "invalid NLA reference");
606  return FlatSymbolRefAttr::get(module.getModuleNameAttr());
607  }
608  // Return an inner-ref to the target.
610  getOp(), [&moduleNamespace](auto _) -> hw::InnerSymbolNamespace & {
611  return moduleNamespace;
612  });
613 }
614 
616  auto *op = getOp();
617  // Annotations that target operations are resolved like inner symbols.
618  if (auto is = llvm::dyn_cast<hw::InnerSymbolOpInterface>(op)) {
619  auto result = is.getTargetResult();
620  if (!result)
621  return {};
622  return type_cast<FIRRTLType>(result.getType());
623  }
624  // Fallback to assuming the single result is the target.
625  if (op->getNumResults() != 1)
626  return {};
627  return type_cast<FIRRTLType>(op->getResult(0).getType());
628 }
629 
630 PortAnnoTarget::PortAnnoTarget(FModuleLike op, unsigned portNo)
631  : AnnoTarget({op, portNo}) {}
632 
633 PortAnnoTarget::PortAnnoTarget(MemOp op, unsigned portNo)
634  : AnnoTarget({op, portNo}) {}
635 
637  if (auto memOp = llvm::dyn_cast<MemOp>(getOp()))
638  return AnnotationSet::forPort(memOp, getPortNo());
639  if (auto moduleOp = llvm::dyn_cast<FModuleLike>(getOp()))
640  return AnnotationSet::forPort(moduleOp, getPortNo());
641  llvm_unreachable("unknown port target");
642  return AnnotationSet(getOp()->getContext());
643 }
644 
646  if (auto memOp = llvm::dyn_cast<MemOp>(getOp()))
647  annotations.applyToPort(memOp, getPortNo());
648  else if (auto moduleOp = llvm::dyn_cast<FModuleLike>(getOp()))
649  annotations.applyToPort(moduleOp, getPortNo());
650  else
651  llvm_unreachable("unknown port target");
652 }
653 
655  hw::InnerSymbolNamespace &moduleNamespace) const {
656  auto module = llvm::dyn_cast<FModuleLike>(getOp());
657  auto target = module ? hw::InnerSymTarget(getPortNo(), module)
660  target, [&moduleNamespace](auto _) -> hw::InnerSymbolNamespace & {
661  return moduleNamespace;
662  });
663 }
664 
666  auto *op = getOp();
667  if (auto module = llvm::dyn_cast<FModuleLike>(op))
668  return type_cast<FIRRTLType>(module.getPortType(getPortNo()));
669  if (llvm::isa<MemOp, InstanceOp>(op))
670  return type_cast<FIRRTLType>(op->getResult(getPortNo()).getType());
671  llvm_unreachable("unknown operation kind");
672  return {};
673 }
674 
675 //===----------------------------------------------------------------------===//
676 // Annotation Details
677 //===----------------------------------------------------------------------===//
678 
679 /// Check if an OMIR type is a string-encoded value that the FIRRTL dialect
680 /// simply passes through as a string without any decoding.
682  return type == "OMID" || type == "OMReference" || type == "OMBigInt" ||
683  type == "OMLong" || type == "OMString" || type == "OMDouble" ||
684  type == "OMBigDecimal" || type == "OMDeleted";
685 }
686 
687 //===----------------------------------------------------------------------===//
688 // Utilities for Specific Annotations
689 //
690 // TODO: Remove these in favor of first-class annotations.
691 //===----------------------------------------------------------------------===//
692 
693 LogicalResult circt::firrtl::extractDUT(const FModuleOp mod, FModuleOp &dut) {
694  if (!AnnotationSet(mod).hasAnnotation(dutAnnoClass))
695  return success();
696 
697  // TODO: This check is duplicated multiple places, e.g., in
698  // WireDFT. This should be factored out as part of the annotation
699  // 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 }
lowerAnnotationsNoRefTypePorts FirtoolPreserveValuesMode value
Definition: Firtool.cpp:95
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:53
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...
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)