CIRCT 20.0.0git
Loading...
Searching...
No Matches
FIRRTLAnnotations.h
Go to the documentation of this file.
1//===- FIRRTLAnnotations.h - Code for working with Annotations --*- C++ -*-===//
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 declares helpers for working with FIRRTL annotations.
10//
11//===----------------------------------------------------------------------===//
12
13#ifndef CIRCT_DIALECT_FIRRTL_ANNOTATIONS_H
14#define CIRCT_DIALECT_FIRRTL_ANNOTATIONS_H
15
16#include "circt/Support/LLVM.h"
17#include "mlir/IR/BuiltinAttributes.h"
18#include "mlir/IR/BuiltinTypes.h"
19#include "mlir/IR/Operation.h"
20#include "llvm/ADT/STLExtras.h"
21#include "llvm/Support/PointerLikeTypeTraits.h"
22
23namespace circt {
24namespace hw {
25struct InnerSymbolNamespace;
26} // namespace hw
27namespace firrtl {
28
29class AnnotationSetIterator;
30class FModuleOp;
31class FModuleLike;
32class MemOp;
33class InstanceOp;
34class FIRRTLType;
35
36/// Return the name of the attribute used for annotations on FIRRTL ops.
37inline StringRef getAnnotationAttrName() { return "annotations"; }
38
39/// Return the name of the attribute used for port annotations on FIRRTL ops.
40inline StringRef getPortAnnotationAttrName() { return "portAnnotations"; }
41
42inline ArrayAttr getAnnotationsIfPresent(Operation *op) {
43 return op->getAttrOfType<ArrayAttr>(getAnnotationAttrName());
44}
45
46/// This class provides a read-only projection of an annotation.
48public:
49 Annotation() = default;
50
51 explicit Annotation(Attribute attr) : attr(attr) {
52 assert(attr && "null attributes not allowed");
53 }
54
55 // Make a new annotation which is a clone of anno with a new fieldID.
56 Annotation(Annotation anno, uint64_t fieldID) : attr(anno.attr) {
57 auto oldFieldID = anno.getMember<IntegerAttr>("circt.fieldID");
58 if (oldFieldID && !fieldID) {
59 removeMember("circt.fieldID");
60 return;
61 }
62 if (fieldID)
63 setMember("circt.fieldID",
64 IntegerAttr::get(IntegerType::get(anno.attr.getContext(), 32),
65 APInt(32, fieldID)));
66 }
67
68 /// Get the data dictionary of this attribute.
69 DictionaryAttr getDict() const;
70
71 /// Set the data dictionary of this attribute.
72 void setDict(DictionaryAttr dict);
73
74 /// Get the field id this attribute targets.
75 unsigned getFieldID() const;
76
77 /// Get the underlying attribute.
78 Attribute getAttr() const { return attr; }
79
80 /// Return the 'class' that this annotation is representing.
81 StringAttr getClassAttr() const;
82 StringRef getClass() const;
83
84 /// Return true if this annotation matches any of the specified class names.
85 template <typename... Args>
86 bool isClass(Args... names) const {
87 return ClassIsa{getClassAttr()}(names...);
88 }
89
90 /// Return a member of the annotation.
91 template <typename AttrClass = Attribute>
92 AttrClass getMember(StringAttr name) const {
93 return getDict().getAs<AttrClass>(name);
94 }
95 template <typename AttrClass = Attribute>
96 AttrClass getMember(StringRef name) const {
97 return getDict().getAs<AttrClass>(name);
98 }
99
100 /// Add or set a member of the annotation to a value.
101 void setMember(StringAttr name, Attribute value);
102 void setMember(StringRef name, Attribute value);
103
104 /// Remove a member of the annotation.
105 void removeMember(StringAttr name);
106 void removeMember(StringRef name);
107
108 using iterator = llvm::ArrayRef<NamedAttribute>::iterator;
109 iterator begin() const { return getDict().begin(); }
110 iterator end() const { return getDict().end(); }
111
112 bool operator==(const Annotation &other) const { return attr == other.attr; }
113 bool operator!=(const Annotation &other) const { return !(*this == other); }
114 explicit operator bool() const { return bool(attr); }
115 bool operator!() const { return attr == nullptr; }
116
117 void dump();
118
119private:
120 Attribute attr;
121
122 /// Helper struct to perform variadic class equality check.
123 struct ClassIsa {
124 StringAttr cls;
125
126 bool operator()() const { return false; }
127 template <typename T, typename... Rest>
128 bool operator()(T name, Rest... rest) const {
129 return compare(name) || (*this)(rest...);
130 }
131
132 private:
133 bool compare(StringAttr name) const { return cls == name; }
134 bool compare(StringRef name) const { return cls && cls.getValue() == name; }
135 };
136};
137
138/// This class provides a read-only projection over the MLIR attributes that
139/// represent a set of annotations. It is intended to make this work less
140/// stringly typed and fiddly for clients.
141///
143public:
145
146 /// Form an empty annotation set.
147 explicit AnnotationSet(MLIRContext *context)
148 : annotations(ArrayAttr::get(context, {})) {}
149
150 /// Form an annotation set from an array of annotation attributes.
151 explicit AnnotationSet(ArrayRef<Attribute> annotations, MLIRContext *context);
152
153 /// Form an annotation set from an array of annotations.
154 explicit AnnotationSet(ArrayRef<Annotation> annotations,
155 MLIRContext *context);
156
157 /// Form an annotation set with a non-null ArrayAttr.
159 assert(annotations && "Cannot use null attribute set");
160 }
161
162 /// Form an annotation set with a possibly-null ArrayAttr.
163 explicit AnnotationSet(ArrayAttr annotations, MLIRContext *context);
164
165 /// Get an annotation set for the specified operation.
166 explicit AnnotationSet(Operation *op);
167
168 /// Get an annotation set for the specified port.
169 static AnnotationSet forPort(FModuleLike op, size_t portNo);
170 static AnnotationSet forPort(MemOp op, size_t portNo);
171
172 /// Get an annotation set for the specified value.
173 static AnnotationSet get(Value v);
174
175 /// Return all the raw annotations that exist.
176 ArrayRef<Attribute> getArray() const { return annotations.getValue(); }
177
178 /// Return this annotation set as an ArrayAttr.
179 ArrayAttr getArrayAttr() const {
180 assert(annotations && "Cannot use null attribute set");
181 return annotations;
182 }
183
184 /// Store the annotations in this set in an operation's `annotations`
185 /// attribute, overwriting any existing annotations. Removes the `annotations`
186 /// attribute if the set is empty. Returns true if the operation was modified,
187 /// false otherwise.
188 bool applyToOperation(Operation *op) const;
189
190 /// Store the annotations in this set in an operation's `portAnnotations`
191 /// attribute, overwriting any existing annotations for this port. Returns
192 /// true if the operation was modified, false otherwise.
193 bool applyToPort(FModuleLike op, size_t portNo) const;
194 bool applyToPort(MemOp op, size_t portNo) const;
195
196 /// Return true if we have an annotation with the specified class name.
197 bool hasAnnotation(StringRef className) const {
198 return !annotations.empty() && hasAnnotationImpl(className);
199 }
200 bool hasAnnotation(StringAttr className) const {
201 return !annotations.empty() && hasAnnotationImpl(className);
202 }
203
204 /// Return true if we have an annotation with the specified class name.
205 template <typename... Args>
206 static bool hasAnnotation(Operation *op, Args... args) {
207 auto annosArray = getAnnotationsIfPresent(op);
208 if (!annosArray)
209 return false;
210 AnnotationSet annotations(annosArray);
211 return !annotations.empty() && (... || annotations.hasAnnotationImpl(args));
212 }
213
214 /// If this annotation set has an annotation with the specified class name,
215 /// return it. Otherwise return a null DictionaryAttr.
216 Annotation getAnnotation(StringRef className) const {
217 if (annotations.empty())
218 return {};
219 return getAnnotationImpl(className);
220 }
221 Annotation getAnnotation(StringAttr className) const {
222 if (annotations.empty())
223 return {};
224 return getAnnotationImpl(className);
225 }
226
228 iterator begin() const;
229 iterator end() const;
230
231 /// Return the MLIRContext corresponding to this AnnotationSet.
232 MLIRContext *getContext() const { return annotations.getContext(); }
233
234 // Support for widely used annotations.
235
236 /// firrtl.transforms.DontTouchAnnotation
237 bool hasDontTouch() const;
238 bool setDontTouch(bool dontTouch);
239 bool addDontTouch();
240 bool removeDontTouch();
241 static bool hasDontTouch(Operation *op);
242 static bool setDontTouch(Operation *op, bool dontTouch);
243 static bool addDontTouch(Operation *op);
244 static bool removeDontTouch(Operation *op);
245
246 bool operator==(const AnnotationSet &other) const {
247 return annotations == other.annotations;
248 }
249 bool operator!=(const AnnotationSet &other) const {
250 return !(*this == other);
251 }
252
253 bool empty() const { return annotations.empty(); }
254
255 size_t size() const { return annotations.size(); }
256
257 /// Add more annotations to this annotation set.
258 void addAnnotations(ArrayRef<Annotation> annotations);
259 void addAnnotations(ArrayRef<Attribute> annotations);
260 void addAnnotations(ArrayAttr annotations);
261
262 /// Remove an annotation from this annotation set. Returns true if any were
263 /// removed, false otherwise.
264 bool removeAnnotation(Annotation anno);
265 bool removeAnnotation(Attribute anno);
266 bool removeAnnotation(StringRef className);
267
268 /// Remove all annotations from this annotation set for which `predicate`
269 /// returns true. The predicate is guaranteed to be called on every
270 /// annotation, such that this method can be used to partition the set by
271 /// extracting and removing annotations at the same time. Returns true if any
272 /// annotations were removed, false otherwise.
273 bool removeAnnotations(llvm::function_ref<bool(Annotation)> predicate);
274
275 /// Remove all annotations with one of the given classes from this annotation
276 /// set.
277 template <typename... Args>
278 bool removeAnnotationsWithClass(Args... names) {
279 return removeAnnotations(
280 [&](Annotation anno) { return anno.isClass(names...); });
281 }
282
283 /// Remove all annotations from an operation for which `predicate` returns
284 /// true. The predicate is guaranteed to be called on every annotation, such
285 /// that this method can be used to partition the set by extracting and
286 /// removing annotations at the same time. Returns true if any annotations
287 /// were removed, false otherwise.
288 static bool removeAnnotations(Operation *op,
289 llvm::function_ref<bool(Annotation)> predicate);
290 static bool removeAnnotations(Operation *op, StringRef className);
291
292 /// Remove all port annotations from a module or extmodule for which
293 /// `predicate` returns true. The predicate is guaranteed to be called on
294 /// every annotation, such that this method can be used to partition a
295 /// module's port annotations by extracting and removing annotations at the
296 /// same time. Returns true if any annotations were removed, false otherwise.
297 static bool removePortAnnotations(
298 Operation *module,
299 llvm::function_ref<bool(unsigned, Annotation)> predicate);
300
301private:
302 bool hasAnnotationImpl(StringAttr className) const;
303 bool hasAnnotationImpl(StringRef className) const;
304 Annotation getAnnotationImpl(StringAttr className) const;
305 Annotation getAnnotationImpl(StringRef className) const;
306
307 ArrayAttr annotations;
308};
309
310// Iteration over the annotation set.
312 : public llvm::indexed_accessor_iterator<AnnotationSetIterator,
313 AnnotationSet, Annotation,
314 Annotation, Annotation> {
315public:
316 // Index into this iterator.
317 Annotation operator*() const;
318
319private:
320 AnnotationSetIterator(AnnotationSet owner, ptrdiff_t curIndex)
321 : llvm::indexed_accessor_iterator<AnnotationSetIterator, AnnotationSet,
323 owner, curIndex) {}
324 friend llvm::indexed_accessor_iterator<AnnotationSetIterator, AnnotationSet,
326 friend class AnnotationSet;
327};
328
329inline auto AnnotationSet::begin() const -> iterator {
330 return AnnotationSetIterator(*this, 0);
331}
332inline auto AnnotationSet::end() const -> iterator {
333 return iterator(*this, annotations.size());
334}
335
336//===----------------------------------------------------------------------===//
337// AnnoTarget
338//===----------------------------------------------------------------------===//
339
340namespace detail {
342 /* implicit */ AnnoTargetImpl(Operation *op) : op(op), portNo(~0UL) {}
343
344 AnnoTargetImpl(Operation *op, unsigned portNo) : op(op), portNo(portNo) {}
345
346 operator bool() const { return getOp(); }
347 bool operator==(const AnnoTargetImpl &other) const {
348 return op == other.op && portNo == other.portNo;
349 }
350 bool operator!=(const AnnoTargetImpl &other) const {
351 return !(*this == other);
352 }
353
354 bool isPort() const { return op && portNo != ~0UL; }
355 bool isOp() const { return op && portNo == ~0UL; }
356
357 Operation *getOp() const { return op; }
358 void setOp(Operation *op) { this->op = op; }
359
360 unsigned getPortNo() const { return portNo; }
361 void setPortNo(unsigned portNo) { this->portNo = portNo; }
362
363protected:
364 Operation *op;
365 size_t portNo;
366};
367} // namespace detail
368
369/// An annotation target is used to keep track of something that is targeted by
370/// an Annotation.
373
374 operator bool() const { return impl; }
375 bool operator==(const AnnoTarget &other) const { return impl == other.impl; }
376 bool operator!=(const AnnoTarget &other) const { return !(*this == other); }
377
378 Operation *getOp() const { return getImpl().getOp(); }
379 void setOp(Operation *op) { getImpl().setOp(op); }
380
381 /// Get the annotations associated with the target.
383
384 /// Set the annotations associated with the target.
385 void setAnnotations(AnnotationSet annotations) const;
386
387 /// Get the parent module of the target.
388 FModuleLike getModule() const;
389
390 /// Get a reference to this target suitable for use in an NLA.
391 Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const;
392
393 /// Get the type of the target.
394 FIRRTLType getType() const;
395
397
398protected:
400};
401
402/// This represents an annotation targeting a specific operation.
403struct OpAnnoTarget : public AnnoTarget {
405
406 OpAnnoTarget(Operation *op) : AnnoTarget(op) {}
407
409 void setAnnotations(AnnotationSet annotations) const;
410 Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const;
411 FIRRTLType getType() const;
412
413 static bool classof(const AnnoTarget &annoTarget) {
414 return annoTarget.getImpl().isOp();
415 }
416};
417
418/// This represents an annotation targeting a specific port of a module, memory,
419/// or instance.
420struct PortAnnoTarget : public AnnoTarget {
422
423 PortAnnoTarget(FModuleLike op, unsigned portNo);
424 PortAnnoTarget(MemOp op, unsigned portNo);
425
426 unsigned getPortNo() const { return getImpl().getPortNo(); }
427 void setPortNo(unsigned portNo) { getImpl().setPortNo(portNo); }
428
430 void setAnnotations(AnnotationSet annotations) const;
431 Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const;
432 FIRRTLType getType() const;
433
434 static bool classof(const AnnoTarget &annoTarget) {
435 return annoTarget.getImpl().isPort();
436 }
437};
438
439} // namespace firrtl
440} // namespace circt
441
442//===----------------------------------------------------------------------===//
443// Traits
444//===----------------------------------------------------------------------===//
445
446namespace llvm {
447
448/// Add support for llvm style casts to AnnoTarget.
449template <typename To, typename From>
450struct CastInfo<
451 To, From,
452 std::enable_if_t<std::is_base_of_v<::circt::firrtl::AnnoTarget, From>>>
454 DefaultDoCastIfPossible<To, From, CastInfo<To, From>> {
455 static inline bool isPossible(From target) {
456 // Allow constant upcasting. This also gets around the fact that AnnoTarget
457 // does not implement classof.
458 if constexpr (std::is_base_of_v<To, From>)
459 return true;
460 else
461 return To::classof(target);
462 }
463 static inline To doCast(From target) { return To(target.getImpl()); }
464};
465
466/// Make `Annotation` behave like a `Attribute` in terms of pointer-likeness.
467template <>
468struct PointerLikeTypeTraits<circt::firrtl::Annotation>
469 : PointerLikeTypeTraits<mlir::Attribute> {
471 static inline void *getAsVoidPointer(Annotation v) {
472 return const_cast<void *>(v.getAttr().getAsOpaquePointer());
473 }
474 static inline Annotation getFromVoidPointer(void *p) {
475 return Annotation(mlir::DictionaryAttr::getFromOpaquePointer(p));
476 }
477};
478
479/// Make `Annotation` hash just like `Attribute`.
480template <>
481struct DenseMapInfo<circt::firrtl::Annotation> {
484 return Annotation(
485 mlir::DictionaryAttr(static_cast<mlir::Attribute::ImplType *>(
487 }
489 return Annotation(
490 mlir::DictionaryAttr(static_cast<mlir::Attribute::ImplType *>(
492 }
493 static unsigned getHashValue(Annotation val) {
494 return mlir::hash_value(val.getAttr());
495 }
496 static bool isEqual(Annotation lhs, Annotation rhs) { return lhs == rhs; }
497};
498
499/// Make `AnnoTarget` hash.
500template <>
501struct DenseMapInfo<circt::firrtl::AnnoTarget> {
514 static unsigned getHashValue(AnnoTarget val) {
515 auto impl = val.getImpl();
516 return hash_combine(impl.getOp(), impl.getPortNo());
517 }
518 static bool isEqual(AnnoTarget lhs, AnnoTarget rhs) { return lhs == rhs; }
519};
520
521} // namespace llvm
522
523#endif // CIRCT_DIALECT_FIRRTL_ANNOTATIONS_H
assert(baseType &&"element must be base type")
AnnotationSetIterator(AnnotationSet owner, ptrdiff_t curIndex)
This class provides a read-only projection over the MLIR attributes that represent a set of annotatio...
MLIRContext * getContext() const
Return the MLIRContext corresponding to this AnnotationSet.
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.
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.
AnnotationSet(ArrayAttr annotations)
Form an annotation set with a non-null ArrayAttr.
bool removeAnnotation(Annotation anno)
Remove an annotation from this annotation set.
static bool hasAnnotation(Operation *op, Args... args)
Return true if we have an annotation with the specified class name.
bool removeAnnotationsWithClass(Args... names)
Remove all annotations with one of the given classes from this annotation set.
static AnnotationSet get(Value v)
Get an annotation set for the specified value.
Annotation getAnnotation(StringAttr className) const
bool hasAnnotation(StringAttr className) const
bool operator!=(const AnnotationSet &other) const
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.
ArrayRef< Attribute > getArray() const
Return all the raw annotations that exist.
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.
Annotation getAnnotation(StringRef className) const
If this annotation set has an annotation with the specified class name, return it.
bool operator==(const AnnotationSet &other) const
AnnotationSetIterator iterator
This class provides a read-only projection of an annotation.
Attribute getAttr() const
Get the underlying attribute.
DictionaryAttr getDict() const
Get the data dictionary of this attribute.
void setDict(DictionaryAttr dict)
Set the data dictionary of this attribute.
bool operator==(const Annotation &other) const
unsigned getFieldID() const
Get the field id this attribute targets.
AttrClass getMember(StringAttr name) const
Return a member of the annotation.
void setMember(StringAttr name, Attribute value)
Add or set a member of the annotation to a value.
Annotation(Annotation anno, uint64_t fieldID)
void removeMember(StringAttr name)
Remove a member of the annotation.
bool operator!=(const Annotation &other) const
AttrClass getMember(StringRef name) const
StringRef getClass() const
Return the 'class' that this annotation is representing.
StringAttr getClassAttr() const
Return the 'class' that this annotation is representing.
llvm::ArrayRef< NamedAttribute >::iterator iterator
bool isClass(Args... names) const
Return true if this annotation matches any of the specified class names.
StringRef getAnnotationAttrName()
Return the name of the attribute used for annotations on FIRRTL ops.
StringRef getPortAnnotationAttrName()
Return the name of the attribute used for port annotations on FIRRTL ops.
ArrayAttr getAnnotationsIfPresent(Operation *op)
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Definition hw.py:1
llvm::hash_code hash_value(const T &e)
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.
bool operator!=(const AnnoTarget &other) const
Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const
Get a reference to this target suitable for use in an NLA.
detail::AnnoTargetImpl getImpl() const
detail::AnnoTargetImpl impl
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.
bool operator==(const AnnoTarget &other) const
AnnoTarget(detail::AnnoTargetImpl impl=nullptr)
Helper struct to perform variadic class equality check.
bool compare(StringRef name) const
bool compare(StringAttr name) const
bool operator()(T name, Rest... rest) const
This represents an annotation targeting a specific operation.
Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const
void setAnnotations(AnnotationSet annotations) const
static bool classof(const AnnoTarget &annoTarget)
AnnotationSet getAnnotations() const
This represents an annotation targeting a specific port of a module, memory, or instance.
static bool classof(const AnnoTarget &annoTarget)
void setPortNo(unsigned portNo)
AnnotationSet getAnnotations() const
void setAnnotations(AnnotationSet annotations) const
Attribute getNLAReference(hw::InnerSymbolNamespace &moduleNamespace) const
bool operator!=(const AnnoTargetImpl &other) const
bool operator==(const AnnoTargetImpl &other) const
AnnoTargetImpl(Operation *op, unsigned portNo)
static bool isEqual(AnnoTarget lhs, AnnoTarget rhs)
static bool isEqual(Annotation lhs, Annotation rhs)