MLIR  16.0.0git
OperationSupport.h
Go to the documentation of this file.
1 //===- OperationSupport.h ---------------------------------------*- 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 defines a number of support types that Operation and related
10 // classes build on top of.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_IR_OPERATIONSUPPORT_H
15 #define MLIR_IR_OPERATIONSUPPORT_H
16 
17 #include "mlir/IR/BlockSupport.h"
19 #include "mlir/IR/Location.h"
20 #include "mlir/IR/TypeRange.h"
21 #include "mlir/IR/Types.h"
22 #include "mlir/IR/Value.h"
24 #include "llvm/ADT/BitmaskEnum.h"
25 #include "llvm/ADT/PointerUnion.h"
26 #include "llvm/Support/PointerLikeTypeTraits.h"
27 #include "llvm/Support/TrailingObjects.h"
28 #include <memory>
29 
30 namespace llvm {
31 class BitVector;
32 } // namespace llvm
33 
34 namespace mlir {
35 class Dialect;
36 class DictionaryAttr;
37 class ElementsAttr;
38 class MutableOperandRangeRange;
39 class NamedAttrList;
40 class Operation;
41 struct OperationState;
42 class OpAsmParser;
43 class OpAsmParserResult;
44 class OpAsmPrinter;
45 class OperandRange;
46 class OperandRangeRange;
47 class OpFoldResult;
48 class ParseResult;
49 class Pattern;
50 class Region;
51 class ResultRange;
52 class RewritePattern;
53 class RewritePatternSet;
54 class Type;
55 class Value;
56 class ValueRange;
57 template <typename ValueRangeT>
58 class ValueTypeRange;
59 
60 //===----------------------------------------------------------------------===//
61 // OperationName
62 //===----------------------------------------------------------------------===//
63 
65 public:
67  llvm::unique_function<void(RewritePatternSet &, MLIRContext *) const>;
68  using FoldHookFn = llvm::unique_function<LogicalResult(
70  using HasTraitFn = llvm::unique_function<bool(TypeID) const>;
72  llvm::unique_function<ParseResult(OpAsmParser &, OperationState &) const>;
73  // Note: RegisteredOperationName is passed as reference here as the derived
74  // class is defined below.
75  using PopulateDefaultAttrsFn = llvm::unique_function<void(
76  const RegisteredOperationName &, NamedAttrList &) const>;
78  llvm::unique_function<void(Operation *, OpAsmPrinter &, StringRef) const>;
80  llvm::unique_function<LogicalResult(Operation *) const>;
82  llvm::unique_function<LogicalResult(Operation *) const>;
83 
84 protected:
85  /// This class represents a type erased version of an operation. It contains
86  /// all of the components necessary for opaquely interacting with an
87  /// operation. If the operation is not registered, some of these components
88  /// may not be populated.
89  struct Impl {
90  Impl(StringAttr name)
91  : name(name), dialect(nullptr), interfaceMap(llvm::None) {}
92 
93  /// The name of the operation.
94  StringAttr name;
95 
96  //===------------------------------------------------------------------===//
97  // Registered Operation Info
98 
99  /// The following fields are only populated when the operation is
100  /// registered.
101 
102  /// Returns true if the operation has been registered, i.e. if the
103  /// registration info has been populated.
104  bool isRegistered() const { return dialect; }
105 
106  /// This is the dialect that this operation belongs to.
108 
109  /// The unique identifier of the derived Op class.
111 
112  /// A map of interfaces that were registered to this operation.
114 
115  /// Internal callback hooks provided by the op implementation.
124 
125  /// A list of attribute names registered to this operation in StringAttr
126  /// form. This allows for operation classes to use StringAttr for attribute
127  /// lookup/creation/etc., as opposed to raw strings.
129  };
130 
131 public:
132  OperationName(StringRef name, MLIRContext *context);
133 
134  /// Return if this operation is registered.
135  bool isRegistered() const { return impl->isRegistered(); }
136 
137  /// If this operation is registered, returns the registered information, None
138  /// otherwise.
140 
141  /// Returns true if the operation was registered with a particular trait, e.g.
142  /// hasTrait<OperandsAreSignlessIntegerLike>(). Returns false if the operation
143  /// is unregistered.
144  template <template <typename T> class Trait>
145  bool hasTrait() const {
146  return hasTrait(TypeID::get<Trait>());
147  }
148  bool hasTrait(TypeID traitID) const {
149  return isRegistered() && impl->hasTraitFn(traitID);
150  }
151 
152  /// Returns true if the operation *might* have the provided trait. This
153  /// means that either the operation is unregistered, or it was registered with
154  /// the provide trait.
155  template <template <typename T> class Trait>
156  bool mightHaveTrait() const {
157  return mightHaveTrait(TypeID::get<Trait>());
158  }
159  bool mightHaveTrait(TypeID traitID) const {
160  return !isRegistered() || impl->hasTraitFn(traitID);
161  }
162 
163  /// Returns an instance of the concept object for the given interface if it
164  /// was registered to this operation, null otherwise. This should not be used
165  /// directly.
166  template <typename T>
167  typename T::Concept *getInterface() const {
168  return impl->interfaceMap.lookup<T>();
169  }
170 
171  /// Returns true if this operation has the given interface registered to it.
172  template <typename T>
173  bool hasInterface() const {
174  return hasInterface(TypeID::get<T>());
175  }
176  bool hasInterface(TypeID interfaceID) const {
177  return impl->interfaceMap.contains(interfaceID);
178  }
179 
180  /// Returns true if the operation *might* have the provided interface. This
181  /// means that either the operation is unregistered, or it was registered with
182  /// the provide interface.
183  template <typename T>
184  bool mightHaveInterface() const {
185  return mightHaveInterface(TypeID::get<T>());
186  }
187  bool mightHaveInterface(TypeID interfaceID) const {
188  return !isRegistered() || hasInterface(interfaceID);
189  }
190 
191  /// Return the dialect this operation is registered to if the dialect is
192  /// loaded in the context, or nullptr if the dialect isn't loaded.
193  Dialect *getDialect() const {
194  return isRegistered() ? impl->dialect : impl->name.getReferencedDialect();
195  }
196 
197  /// Return the name of the dialect this operation is registered to.
198  StringRef getDialectNamespace() const;
199 
200  /// Return the operation name with dialect name stripped, if it has one.
201  StringRef stripDialect() const { return getStringRef().split('.').second; }
202 
203  /// Return the name of this operation. This always succeeds.
204  StringRef getStringRef() const { return getIdentifier(); }
205 
206  /// Return the name of this operation as a StringAttr.
207  StringAttr getIdentifier() const { return impl->name; }
208 
209  void print(raw_ostream &os) const;
210  void dump() const;
211 
212  /// Represent the operation name as an opaque pointer. (Used to support
213  /// PointerLikeTypeTraits).
214  void *getAsOpaquePointer() const { return const_cast<Impl *>(impl); }
215  static OperationName getFromOpaquePointer(const void *pointer) {
216  return OperationName(
217  const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
218  }
219 
220  bool operator==(const OperationName &rhs) const { return impl == rhs.impl; }
221  bool operator!=(const OperationName &rhs) const { return !(*this == rhs); }
222 
223 protected:
225 
226  /// The internal implementation of the operation name.
228 
229  /// Allow access to the Impl struct.
231 };
232 
233 inline raw_ostream &operator<<(raw_ostream &os, OperationName info) {
234  info.print(os);
235  return os;
236 }
237 
238 // Make operation names hashable.
239 inline llvm::hash_code hash_value(OperationName arg) {
240  return llvm::hash_value(arg.getAsOpaquePointer());
241 }
242 
243 //===----------------------------------------------------------------------===//
244 // RegisteredOperationName
245 //===----------------------------------------------------------------------===//
246 
247 /// This is a "type erased" representation of a registered operation. This
248 /// should only be used by things like the AsmPrinter and other things that need
249 /// to be parameterized by generic operation hooks. Most user code should use
250 /// the concrete operation types.
252 public:
253  /// Lookup the registered operation information for the given operation.
254  /// Returns None if the operation isn't registered.
255  static Optional<RegisteredOperationName> lookup(StringRef name,
256  MLIRContext *ctx);
257 
258  /// Register a new operation in a Dialect object.
259  /// This constructor is used by Dialect objects when they register the list of
260  /// operations they contain.
261  template <typename T>
262  static void insert(Dialect &dialect) {
263  insert(T::getOperationName(), dialect, TypeID::get<T>(),
264  T::getParseAssemblyFn(), T::getPrintAssemblyFn(),
265  T::getVerifyInvariantsFn(), T::getVerifyRegionInvariantsFn(),
266  T::getFoldHookFn(), T::getGetCanonicalizationPatternsFn(),
267  T::getInterfaceMap(), T::getHasTraitFn(), T::getAttributeNames(),
268  T::getPopulateDefaultAttrsFn());
269  }
270  /// The use of this method is in general discouraged in favor of
271  /// 'insert<CustomOp>(dialect)'.
272  static void
273  insert(StringRef name, Dialect &dialect, TypeID typeID,
279  detail::InterfaceMap &&interfaceMap, HasTraitFn &&hasTrait,
280  ArrayRef<StringRef> attrNames,
282 
283  /// Return the dialect this operation is registered to.
284  Dialect &getDialect() const { return *impl->dialect; }
285 
286  /// Return the unique identifier of the derived Op class.
287  TypeID getTypeID() const { return impl->typeID; }
288 
289  /// Use the specified object to parse this ops custom assembly format.
290  ParseResult parseAssembly(OpAsmParser &parser, OperationState &result) const;
291 
292  /// Return the static hook for parsing this operation assembly.
294  return impl->parseAssemblyFn;
295  }
296 
297  /// This hook implements the AsmPrinter for this operation.
299  StringRef defaultDialect) const {
300  return impl->printAssemblyFn(op, p, defaultDialect);
301  }
302 
303  /// These hooks implement the verifiers for this operation. It should emits
304  /// an error message and returns failure if a problem is detected, or returns
305  /// success if everything is ok.
307  return impl->verifyInvariantsFn(op);
308  }
310  return impl->verifyRegionInvariantsFn(op);
311  }
312 
313  /// This hook implements a generalized folder for this operation. Operations
314  /// can implement this to provide simplifications rules that are applied by
315  /// the Builder::createOrFold API and the canonicalization pass.
316  ///
317  /// This is an intentionally limited interface - implementations of this hook
318  /// can only perform the following changes to the operation:
319  ///
320  /// 1. They can leave the operation alone and without changing the IR, and
321  /// return failure.
322  /// 2. They can mutate the operation in place, without changing anything else
323  /// in the IR. In this case, return success.
324  /// 3. They can return a list of existing values that can be used instead of
325  /// the operation. In this case, fill in the results list and return
326  /// success. The caller will remove the operation and use those results
327  /// instead.
328  ///
329  /// This allows expression of some simple in-place canonicalizations (e.g.
330  /// "x+0 -> x", "min(x,y,x,z) -> min(x,y,z)", "x+y-x -> y", etc), as well as
331  /// generalized constant folding.
333  SmallVectorImpl<OpFoldResult> &results) const {
334  return impl->foldHookFn(op, operands, results);
335  }
336 
337  /// This hook returns any canonicalization pattern rewrites that the operation
338  /// supports, for use by the canonicalization pass.
340  MLIRContext *context) const {
341  return impl->getCanonicalizationPatternsFn(results, context);
342  }
343 
344  /// Attach the given models as implementations of the corresponding interfaces
345  /// for the concrete operation.
346  template <typename... Models>
348  impl->interfaceMap.insert<Models...>();
349  }
350 
351  /// Returns true if the operation has a particular trait.
352  template <template <typename T> class Trait>
353  bool hasTrait() const {
354  return hasTrait(TypeID::get<Trait>());
355  }
356 
357  /// Returns true if the operation has a particular trait.
358  bool hasTrait(TypeID traitID) const { return impl->hasTraitFn(traitID); }
359 
360  /// Return the list of cached attribute names registered to this operation.
361  /// The order of attributes cached here is unique to each type of operation,
362  /// and the interpretation of this attribute list should generally be driven
363  /// by the respective operation. In many cases, this caching removes the need
364  /// to use the raw string name of a known attribute.
365  ///
366  /// For example the ODS generator, with an op defining the following
367  /// attributes:
368  ///
369  /// let arguments = (ins I32Attr:$attr1, I32Attr:$attr2);
370  ///
371  /// ... may produce an order here of ["attr1", "attr2"]. This allows for the
372  /// ODS generator to directly access the cached name for a known attribute,
373  /// greatly simplifying the cost and complexity of attribute usage produced by
374  /// the generator.
375  ///
377  return impl->attributeNames;
378  }
379 
380  /// This hook implements the method to populate defaults attributes that are
381  /// unset.
382  void populateDefaultAttrs(NamedAttrList &attrs) const;
383 
384  /// Represent the operation name as an opaque pointer. (Used to support
385  /// PointerLikeTypeTraits).
386  static RegisteredOperationName getFromOpaquePointer(const void *pointer) {
388  const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
389  }
390 
391 private:
393 
394  /// Allow access to the constructor.
395  friend OperationName;
396 };
397 
398 inline Optional<RegisteredOperationName>
402 }
403 
404 //===----------------------------------------------------------------------===//
405 // Attribute Dictionary-Like Interface
406 //===----------------------------------------------------------------------===//
407 
408 /// Attribute collections provide a dictionary-like interface. Define common
409 /// lookup functions.
410 namespace impl {
411 
412 /// Unsorted string search or identifier lookups are linear scans.
413 template <typename IteratorT, typename NameT>
414 std::pair<IteratorT, bool> findAttrUnsorted(IteratorT first, IteratorT last,
415  NameT name) {
416  for (auto it = first; it != last; ++it)
417  if (it->getName() == name)
418  return {it, true};
419  return {last, false};
420 }
421 
422 /// Using llvm::lower_bound requires an extra string comparison to check whether
423 /// the returned iterator points to the found element or whether it indicates
424 /// the lower bound. Skip this redundant comparison by checking if `compare ==
425 /// 0` during the binary search.
426 template <typename IteratorT>
427 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
428  StringRef name) {
429  ptrdiff_t length = std::distance(first, last);
430 
431  while (length > 0) {
432  ptrdiff_t half = length / 2;
433  IteratorT mid = first + half;
434  int compare = mid->getName().strref().compare(name);
435  if (compare < 0) {
436  first = mid + 1;
437  length = length - half - 1;
438  } else if (compare > 0) {
439  length = half;
440  } else {
441  return {mid, true};
442  }
443  }
444  return {first, false};
445 }
446 
447 /// StringAttr lookups on large attribute lists will switch to string binary
448 /// search. String binary searches become significantly faster than linear scans
449 /// with the identifier when the attribute list becomes very large.
450 template <typename IteratorT>
451 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
452  StringAttr name) {
453  constexpr unsigned kSmallAttributeList = 16;
454  if (std::distance(first, last) > kSmallAttributeList)
455  return findAttrSorted(first, last, name.strref());
456  return findAttrUnsorted(first, last, name);
457 }
458 
459 /// Get an attribute from a sorted range of named attributes. Returns null if
460 /// the attribute was not found.
461 template <typename IteratorT, typename NameT>
462 Attribute getAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
463  std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
464  return result.second ? result.first->getValue() : Attribute();
465 }
466 
467 /// Get an attribute from a sorted range of named attributes. Returns None if
468 /// the attribute was not found.
469 template <typename IteratorT, typename NameT>
471 getNamedAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
472  std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
473  return result.second ? *result.first : Optional<NamedAttribute>();
474 }
475 
476 } // namespace impl
477 
478 //===----------------------------------------------------------------------===//
479 // NamedAttrList
480 //===----------------------------------------------------------------------===//
481 
482 /// NamedAttrList is array of NamedAttributes that tracks whether it is sorted
483 /// and does some basic work to remain sorted.
485 public:
490  using size_type = size_t;
491 
492  NamedAttrList() : dictionarySorted({}, true) {}
493  NamedAttrList(std::nullopt_t none) : NamedAttrList() {}
495  NamedAttrList(DictionaryAttr attributes);
497 
498  template <typename Container>
499  NamedAttrList(const Container &vec)
501 
502  bool operator!=(const NamedAttrList &other) const {
503  return !(*this == other);
504  }
505  bool operator==(const NamedAttrList &other) const {
506  return attrs == other.attrs;
507  }
508 
509  /// Add an attribute with the specified name.
510  void append(StringRef name, Attribute attr);
511 
512  /// Add an attribute with the specified name.
513  void append(StringAttr name, Attribute attr) {
514  append(NamedAttribute(name, attr));
515  }
516 
517  /// Append the given named attribute.
518  void append(NamedAttribute attr) { push_back(attr); }
519 
520  /// Add an array of named attributes.
521  template <typename RangeT>
522  void append(RangeT &&newAttributes) {
523  append(std::begin(newAttributes), std::end(newAttributes));
524  }
525 
526  /// Add a range of named attributes.
527  template <typename IteratorT,
528  typename = std::enable_if_t<std::is_convertible<
529  typename std::iterator_traits<IteratorT>::iterator_category,
530  std::input_iterator_tag>::value>>
531  void append(IteratorT inStart, IteratorT inEnd) {
532  // TODO: expand to handle case where values appended are in order & after
533  // end of current list.
534  dictionarySorted.setPointerAndInt(nullptr, false);
535  attrs.append(inStart, inEnd);
536  }
537 
538  /// Replaces the attributes with new list of attributes.
539  void assign(const_iterator inStart, const_iterator inEnd);
540 
541  /// Replaces the attributes with new list of attributes.
543  assign(range.begin(), range.end());
544  }
545 
546  bool empty() const { return attrs.empty(); }
547 
548  void reserve(size_type N) { attrs.reserve(N); }
549 
550  /// Add an attribute with the specified name.
551  void push_back(NamedAttribute newAttribute);
552 
553  /// Pop last element from list.
554  void pop_back() { attrs.pop_back(); }
555 
556  /// Returns an entry with a duplicate name the list, if it exists, else
557  /// returns llvm::None.
559 
560  /// Return a dictionary attribute for the underlying dictionary. This will
561  /// return an empty dictionary attribute if empty rather than null.
562  DictionaryAttr getDictionary(MLIRContext *context) const;
563 
564  /// Return all of the attributes on this operation.
566 
567  /// Return the specified attribute if present, null otherwise.
568  Attribute get(StringAttr name) const;
569  Attribute get(StringRef name) const;
570 
571  /// Return the specified named attribute if present, None otherwise.
572  Optional<NamedAttribute> getNamed(StringRef name) const;
573  Optional<NamedAttribute> getNamed(StringAttr name) const;
574 
575  /// If the an attribute exists with the specified name, change it to the new
576  /// value. Otherwise, add a new attribute with the specified name/value.
577  /// Returns the previous attribute value of `name`, or null if no
578  /// attribute previously existed with `name`.
579  Attribute set(StringAttr name, Attribute value);
580  Attribute set(StringRef name, Attribute value);
581 
582  /// Erase the attribute with the given name from the list. Return the
583  /// attribute that was erased, or nullptr if there was no attribute with such
584  /// name.
585  Attribute erase(StringAttr name);
586  Attribute erase(StringRef name);
587 
588  iterator begin() { return attrs.begin(); }
589  iterator end() { return attrs.end(); }
590  const_iterator begin() const { return attrs.begin(); }
591  const_iterator end() const { return attrs.end(); }
592 
594  operator ArrayRef<NamedAttribute>() const;
595 
596 private:
597  /// Return whether the attributes are sorted.
598  bool isSorted() const { return dictionarySorted.getInt(); }
599 
600  /// Erase the attribute at the given iterator position.
601  Attribute eraseImpl(SmallVectorImpl<NamedAttribute>::iterator it);
602 
603  /// Lookup an attribute in the list.
604  template <typename AttrListT, typename NameT>
605  static auto findAttr(AttrListT &attrs, NameT name) {
606  return attrs.isSorted()
607  ? impl::findAttrSorted(attrs.begin(), attrs.end(), name)
608  : impl::findAttrUnsorted(attrs.begin(), attrs.end(), name);
609  }
610 
611  // These are marked mutable as they may be modified (e.g., sorted)
612  mutable SmallVector<NamedAttribute, 4> attrs;
613  // Pair with cached DictionaryAttr and status of whether attrs is sorted.
614  // Note: just because sorted does not mean a DictionaryAttr has been created
615  // but the case where there is a DictionaryAttr but attrs isn't sorted should
616  // not occur.
617  mutable llvm::PointerIntPair<Attribute, 1, bool> dictionarySorted;
618 };
619 
620 //===----------------------------------------------------------------------===//
621 // OperationState
622 //===----------------------------------------------------------------------===//
623 
624 /// This represents an operation in an abstracted form, suitable for use with
625 /// the builder APIs. This object is a large and heavy weight object meant to
626 /// be used as a temporary object on the stack. It is generally unwise to put
627 /// this in a collection.
632  /// Types of the results of this operation.
635  /// Successors of this operation and their respective operands.
637  /// Regions that the op will hold.
639 
640 public:
641  OperationState(Location location, StringRef name);
643 
646  BlockRange successors = {},
647  MutableArrayRef<std::unique_ptr<Region>> regions = {});
648  OperationState(Location location, StringRef name, ValueRange operands,
649  TypeRange types, ArrayRef<NamedAttribute> attributes = {},
650  BlockRange successors = {},
651  MutableArrayRef<std::unique_ptr<Region>> regions = {});
652 
653  void addOperands(ValueRange newOperands);
654 
655  void addTypes(ArrayRef<Type> newTypes) {
656  types.append(newTypes.begin(), newTypes.end());
657  }
658  template <typename RangeT>
659  std::enable_if_t<!std::is_convertible<RangeT, ArrayRef<Type>>::value>
660  addTypes(RangeT &&newTypes) {
661  types.append(newTypes.begin(), newTypes.end());
662  }
663 
664  /// Add an attribute with the specified name.
665  void addAttribute(StringRef name, Attribute attr) {
666  addAttribute(StringAttr::get(getContext(), name), attr);
667  }
668 
669  /// Add an attribute with the specified name.
670  void addAttribute(StringAttr name, Attribute attr) {
671  attributes.append(name, attr);
672  }
673 
674  /// Add an array of named attributes.
676  attributes.append(newAttributes);
677  }
678 
679  void addSuccessors(Block *successor) { successors.push_back(successor); }
680  void addSuccessors(BlockRange newSuccessors);
681 
682  /// Create a region that should be attached to the operation. These regions
683  /// can be filled in immediately without waiting for Operation to be
684  /// created. When it is, the region bodies will be transferred.
685  Region *addRegion();
686 
687  /// Take a region that should be attached to the Operation. The body of the
688  /// region will be transferred when the Operation is constructed. If the
689  /// region is null, a new empty region will be attached to the Operation.
690  void addRegion(std::unique_ptr<Region> &&region);
691 
692  /// Take ownership of a set of regions that should be attached to the
693  /// Operation.
694  void addRegions(MutableArrayRef<std::unique_ptr<Region>> regions);
695 
696  /// Get the context held by this operation state.
697  MLIRContext *getContext() const { return location->getContext(); }
698 };
699 
700 //===----------------------------------------------------------------------===//
701 // OperandStorage
702 //===----------------------------------------------------------------------===//
703 
704 namespace detail {
705 /// This class handles the management of operation operands. Operands are
706 /// stored either in a trailing array, or a dynamically resizable vector.
707 class alignas(8) OperandStorage {
708 public:
709  OperandStorage(Operation *owner, OpOperand *trailingOperands,
710  ValueRange values);
711  ~OperandStorage();
712 
713  /// Replace the operands contained in the storage with the ones provided in
714  /// 'values'.
715  void setOperands(Operation *owner, ValueRange values);
716 
717  /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
718  /// with the ones provided in 'operands'. 'operands' may be smaller or larger
719  /// than the range pointed to by 'start'+'length'.
720  void setOperands(Operation *owner, unsigned start, unsigned length,
721  ValueRange operands);
722 
723  /// Erase the operands held by the storage within the given range.
724  void eraseOperands(unsigned start, unsigned length);
725 
726  /// Erase the operands held by the storage that have their corresponding bit
727  /// set in `eraseIndices`.
728  void eraseOperands(const BitVector &eraseIndices);
729 
730  /// Get the operation operands held by the storage.
731  MutableArrayRef<OpOperand> getOperands() { return {operandStorage, size()}; }
732 
733  /// Return the number of operands held in the storage.
734  unsigned size() { return numOperands; }
735 
736 private:
737  /// Resize the storage to the given size. Returns the array containing the new
738  /// operands.
739  MutableArrayRef<OpOperand> resize(Operation *owner, unsigned newSize);
740 
741  /// The total capacity number of operands that the storage can hold.
742  unsigned capacity : 31;
743  /// A flag indicating if the operand storage was dynamically allocated, as
744  /// opposed to inlined into the owning operation.
745  unsigned isStorageDynamic : 1;
746  /// The number of operands within the storage.
747  unsigned numOperands;
748  /// A pointer to the operand storage.
749  OpOperand *operandStorage;
750 };
751 } // namespace detail
752 
753 //===----------------------------------------------------------------------===//
754 // OpPrintingFlags
755 //===----------------------------------------------------------------------===//
756 
757 /// Set of flags used to control the behavior of the various IR print methods
758 /// (e.g. Operation::Print).
760 public:
761  OpPrintingFlags();
762  OpPrintingFlags(std::nullopt_t) : OpPrintingFlags() {}
763 
764  /// Enables the elision of large elements attributes by printing a lexically
765  /// valid but otherwise meaningless form instead of the element data. The
766  /// `largeElementLimit` is used to configure what is considered to be a
767  /// "large" ElementsAttr by providing an upper limit to the number of
768  /// elements.
769  OpPrintingFlags &elideLargeElementsAttrs(int64_t largeElementLimit = 16);
770 
771  /// Enable or disable printing of debug information (based on `enable`). If
772  /// 'prettyForm' is set to true, debug information is printed in a more
773  /// readable 'pretty' form. Note: The IR generated with 'prettyForm' is not
774  /// parsable.
775  OpPrintingFlags &enableDebugInfo(bool enable = true, bool prettyForm = false);
776 
777  /// Always print operations in the generic form.
779 
780  /// Do not verify the operation when using custom operation printers.
782 
783  /// Use local scope when printing the operation. This allows for using the
784  /// printer in a more localized and thread-safe setting, but may not
785  /// necessarily be identical to what the IR will look like when dumping
786  /// the full module.
788 
789  /// Print users of values as comments.
791 
792  /// Return if the given ElementsAttr should be elided.
793  bool shouldElideElementsAttr(ElementsAttr attr) const;
794 
795  /// Return the size limit for printing large ElementsAttr.
797 
798  /// Return if debug information should be printed.
799  bool shouldPrintDebugInfo() const;
800 
801  /// Return if debug information should be printed in the pretty form.
802  bool shouldPrintDebugInfoPrettyForm() const;
803 
804  /// Return if operations should be printed in the generic form.
805  bool shouldPrintGenericOpForm() const;
806 
807  /// Return if operation verification should be skipped.
808  bool shouldAssumeVerified() const;
809 
810  /// Return if the printer should use local scope when dumping the IR.
811  bool shouldUseLocalScope() const;
812 
813  /// Return if the printer should print users of values.
814  bool shouldPrintValueUsers() const;
815 
816 private:
817  /// Elide large elements attributes if the number of elements is larger than
818  /// the upper limit.
819  Optional<int64_t> elementsAttrElementLimit;
820 
821  /// Print debug information.
822  bool printDebugInfoFlag : 1;
823  bool printDebugInfoPrettyFormFlag : 1;
824 
825  /// Print operations in the generic form.
826  bool printGenericOpFormFlag : 1;
827 
828  /// Skip operation verification.
829  bool assumeVerifiedFlag : 1;
830 
831  /// Print operations with numberings local to the current operation.
832  bool printLocalScope : 1;
833 
834  /// Print users of values.
835  bool printValueUsersFlag : 1;
836 };
837 
838 //===----------------------------------------------------------------------===//
839 // Operation Equivalency
840 //===----------------------------------------------------------------------===//
841 
842 /// This class provides utilities for computing if two operations are
843 /// equivalent.
845  enum Flags {
846  None = 0,
847 
848  // When provided, the location attached to the operation are ignored.
850 
851  LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
852  };
853 
854  /// Compute a hash for the given operation.
855  /// The `hashOperands` and `hashResults` callbacks are expected to return a
856  /// unique hash_code for a given Value.
857  static llvm::hash_code computeHash(
858  Operation *op,
859  function_ref<llvm::hash_code(Value)> hashOperands =
860  [](Value v) { return hash_value(v); },
861  function_ref<llvm::hash_code(Value)> hashResults =
862  [](Value v) { return hash_value(v); },
863  Flags flags = Flags::None);
864 
865  /// Helper that can be used with `computeHash` above to ignore operation
866  /// operands/result mapping.
867  static llvm::hash_code ignoreHashValue(Value) { return llvm::hash_code{}; }
868  /// Helper that can be used with `computeHash` above to ignore operation
869  /// operands/result mapping.
870  static llvm::hash_code directHashValue(Value v) { return hash_value(v); }
871 
872  /// Compare two operations and return if they are equivalent.
873  /// `mapOperands` and `mapResults` are optional callbacks that allows the
874  /// caller to check the mapping of SSA value between the lhs and rhs
875  /// operations. It is expected to return success if the mapping is valid and
876  /// failure if it conflicts with a previous mapping.
877  static bool
879  function_ref<LogicalResult(Value, Value)> mapOperands,
880  function_ref<LogicalResult(Value, Value)> mapResults,
881  Flags flags = Flags::None);
882 
883  /// Helper that can be used with `isEquivalentTo` above to ignore operation
884  /// operands/result mapping.
886  return success();
887  }
888  /// Helper that can be used with `isEquivalentTo` above to ignore operation
889  /// operands/result mapping.
891  return success(lhs == rhs);
892  }
893 };
894 
895 /// Enable Bitmask enums for OperationEquivalence::Flags.
897 
898 //===----------------------------------------------------------------------===//
899 // OperationFingerPrint
900 //===----------------------------------------------------------------------===//
901 
902 /// A unique fingerprint for a specific operation, and all of it's internal
903 /// operations.
905 public:
909 
910  bool operator==(const OperationFingerPrint &other) const {
911  return hash == other.hash;
912  }
913  bool operator!=(const OperationFingerPrint &other) const {
914  return !(*this == other);
915  }
916 
917 private:
918  std::array<uint8_t, 20> hash;
919 };
920 
921 } // namespace mlir
922 
923 namespace llvm {
924 template <>
925 struct DenseMapInfo<mlir::OperationName> {
927  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
929  }
933  }
934  static unsigned getHashValue(mlir::OperationName val) {
936  }
938  return lhs == rhs;
939  }
940 };
941 template <>
942 struct DenseMapInfo<mlir::RegisteredOperationName>
943  : public DenseMapInfo<mlir::OperationName> {
945  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
947  }
951  }
952 };
953 
954 template <>
955 struct PointerLikeTypeTraits<mlir::OperationName> {
956  static inline void *getAsVoidPointer(mlir::OperationName I) {
957  return const_cast<void *>(I.getAsOpaquePointer());
958  }
959  static inline mlir::OperationName getFromVoidPointer(void *P) {
961  }
962  static constexpr int NumLowBitsAvailable =
963  PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
964 };
965 template <>
966 struct PointerLikeTypeTraits<mlir::RegisteredOperationName>
967  : public PointerLikeTypeTraits<mlir::OperationName> {
970  }
971 };
972 
973 } // namespace llvm
974 
975 #endif
static constexpr const bool value
@ None
Attributes are known-constant values of operations.
Definition: Attributes.h:25
MLIRContext * getContext() const
Return the context this attribute belongs to.
Definition: Attributes.cpp:20
This class provides an abstraction over the different types of ranges over Blocks.
Definition: BlockSupport.h:106
Block represents an ordered list of Operations.
Definition: Block.h:30
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:41
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:64
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:56
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
void append(IteratorT inStart, IteratorT inEnd)
Add a range of named attributes.
void assign(ArrayRef< NamedAttribute > range)
Replaces the attributes with new list of attributes.
const_iterator begin() const
Optional< NamedAttribute > findDuplicate() const
Returns an entry with a duplicate name the list, if it exists, else returns llvm::None.
void assign(const_iterator inStart, const_iterator inEnd)
Replaces the attributes with new list of attributes.
SmallVectorImpl< NamedAttribute >::const_iterator const_iterator
void append(NamedAttribute attr)
Append the given named attribute.
bool operator!=(const NamedAttrList &other) const
Optional< NamedAttribute > getNamed(StringRef name) const
Return the specified named attribute if present, None otherwise.
ArrayRef< NamedAttribute > getAttrs() const
Return all of the attributes on this operation.
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
SmallVectorImpl< NamedAttribute >::iterator iterator
const_iterator end() const
NamedAttrList(const Container &vec)
void append(StringAttr name, Attribute attr)
Add an attribute with the specified name.
void pop_back()
Pop last element from list.
bool operator==(const NamedAttrList &other) const
Attribute get(StringAttr name) const
Return the specified attribute if present, null otherwise.
Attribute erase(StringAttr name)
Erase the attribute with the given name from the list.
Attribute set(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
void append(RangeT &&newAttributes)
Add an array of named attributes.
void reserve(size_type N)
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
NamedAttrList & operator=(const SmallVectorImpl< NamedAttribute > &rhs)
NamedAttrList(std::nullopt_t none)
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:150
The OpAsmParser has methods for interacting with the asm parser: parsing things from it,...
This is a pure-virtual base class that exposes the asmprinter hooks necessary to implement a custom p...
This class represents an operand of an operation.
Definition: Value.h:247
Set of flags used to control the behavior of the various IR print methods (e.g.
bool shouldElideElementsAttr(ElementsAttr attr) const
Return if the given ElementsAttr should be elided.
Definition: AsmPrinter.cpp:247
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
Definition: AsmPrinter.cpp:274
OpPrintingFlags & printValueUsers()
Print users of values as comments.
Definition: AsmPrinter.cpp:241
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
Definition: AsmPrinter.cpp:279
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
Definition: AsmPrinter.cpp:264
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
Definition: AsmPrinter.cpp:282
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
Definition: AsmPrinter.cpp:269
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
Definition: AsmPrinter.cpp:259
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
Definition: AsmPrinter.cpp:206
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
Definition: AsmPrinter.cpp:213
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
Definition: AsmPrinter.cpp:184
OpPrintingFlags & assumeVerified()
Do not verify the operation when using custom operation printers.
Definition: AsmPrinter.cpp:227
OpPrintingFlags(std::nullopt_t)
OpPrintingFlags & printGenericOpForm()
Always print operations in the generic form.
Definition: AsmPrinter.cpp:221
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
Definition: AsmPrinter.cpp:235
Optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
Definition: AsmPrinter.cpp:254
A unique fingerprint for a specific operation, and all of it's internal operations.
bool operator!=(const OperationFingerPrint &other) const
OperationFingerPrint & operator=(const OperationFingerPrint &)=default
OperationFingerPrint(Operation *topOp)
bool operator==(const OperationFingerPrint &other) const
OperationFingerPrint(const OperationFingerPrint &)=default
bool operator==(const OperationName &rhs) const
llvm::unique_function< LogicalResult(Operation *) const > VerifyInvariantsFn
void dump() const
Definition: AsmPrinter.cpp:57
StringRef getStringRef() const
Return the name of this operation. This always succeeds.
bool operator!=(const OperationName &rhs) const
StringRef stripDialect() const
Return the operation name with dialect name stripped, if it has one.
Impl * impl
The internal implementation of the operation name.
bool hasTrait() const
Returns true if the operation was registered with a particular trait, e.g.
llvm::unique_function< bool(TypeID) const > HasTraitFn
StringAttr getIdentifier() const
Return the name of this operation as a StringAttr.
Dialect * getDialect() const
Return the dialect this operation is registered to if the dialect is loaded in the context,...
OperationName(StringRef name, MLIRContext *context)
StringRef getDialectNamespace() const
Return the name of the dialect this operation is registered to.
llvm::unique_function< LogicalResult(Operation *) const > VerifyRegionInvariantsFn
bool mightHaveTrait() const
Returns true if the operation might have the provided trait.
bool mightHaveTrait(TypeID traitID) const
bool hasInterface() const
Returns true if this operation has the given interface registered to it.
llvm::unique_function< void(Operation *, OpAsmPrinter &, StringRef) const > PrintAssemblyFn
T::Concept * getInterface() const
Returns an instance of the concept object for the given interface if it was registered to this operat...
bool isRegistered() const
Return if this operation is registered.
bool mightHaveInterface() const
Returns true if the operation might have the provided interface.
bool mightHaveInterface(TypeID interfaceID) const
friend MLIRContextImpl
Allow access to the Impl struct.
bool hasTrait(TypeID traitID) const
void * getAsOpaquePointer() const
Represent the operation name as an opaque pointer.
llvm::unique_function< LogicalResult(Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &) const > FoldHookFn
llvm::unique_function< ParseResult(OpAsmParser &, OperationState &) const > ParseAssemblyFn
llvm::unique_function< void(RewritePatternSet &, MLIRContext *) const > GetCanonicalizationPatternsFn
void print(raw_ostream &os) const
Definition: AsmPrinter.cpp:55
llvm::unique_function< void(const RegisteredOperationName &, NamedAttrList &) const > PopulateDefaultAttrsFn
bool hasInterface(TypeID interfaceID) const
Optional< RegisteredOperationName > getRegisteredInfo() const
If this operation is registered, returns the registered information, None otherwise.
static OperationName getFromOpaquePointer(const void *pointer)
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:31
This class represents success/failure for parsing-like operations that find it important to chain tog...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
This is a "type erased" representation of a registered operation.
static void insert(Dialect &dialect)
Register a new operation in a Dialect object.
ArrayRef< StringAttr > getAttributeNames() const
Return the list of cached attribute names registered to this operation.
const ParseAssemblyFn & getParseAssemblyFn() const
Return the static hook for parsing this operation assembly.
void populateDefaultAttrs(NamedAttrList &attrs) const
This hook implements the method to populate defaults attributes that are unset.
ParseResult parseAssembly(OpAsmParser &parser, OperationState &result) const
Use the specified object to parse this ops custom assembly format.
bool hasTrait(TypeID traitID) const
Returns true if the operation has a particular trait.
LogicalResult foldHook(Operation *op, ArrayRef< Attribute > operands, SmallVectorImpl< OpFoldResult > &results) const
This hook implements a generalized folder for this operation.
static RegisteredOperationName getFromOpaquePointer(const void *pointer)
Represent the operation name as an opaque pointer.
void getCanonicalizationPatterns(RewritePatternSet &results, MLIRContext *context) const
This hook returns any canonicalization pattern rewrites that the operation supports,...
TypeID getTypeID() const
Return the unique identifier of the derived Op class.
bool hasTrait() const
Returns true if the operation has a particular trait.
LogicalResult verifyInvariants(Operation *op) const
These hooks implement the verifiers for this operation.
static Optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
void attachInterface()
Attach the given models as implementations of the corresponding interfaces for the concrete operation...
LogicalResult verifyRegionInvariants(Operation *op) const
Dialect & getDialect() const
Return the dialect this operation is registered to.
void printAssembly(Operation *op, OpAsmPrinter &p, StringRef defaultDialect) const
This hook implements the AsmPrinter for this operation.
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:36
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:349
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
This class provides an efficient mapping between a given Interface type, and a particular implementat...
This class handles the management of operation operands.
MutableArrayRef< OpOperand > getOperands()
Get the operation operands held by the storage.
void eraseOperands(unsigned start, unsigned length)
Erase the operands held by the storage within the given range.
unsigned size()
Return the number of operands held in the storage.
void setOperands(Operation *owner, ValueRange values)
Replace the operands contained in the storage with the ones provided in 'values'.
OperandStorage(Operation *owner, OpOperand *trailingOperands, ValueRange values)
Include the generated interface declarations.
Definition: CallGraph.h:229
Optional< NamedAttribute > getNamedAttrFromSortedRange(IteratorT first, IteratorT last, NameT name)
Get an attribute from a sorted range of named attributes.
Attribute getAttrFromSortedRange(IteratorT first, IteratorT last, NameT name)
Get an attribute from a sorted range of named attributes.
std::pair< IteratorT, bool > findAttrSorted(IteratorT first, IteratorT last, StringRef name)
Using llvm::lower_bound requires an extra string comparison to check whether the returned iterator po...
std::pair< IteratorT, bool > findAttrUnsorted(IteratorT first, IteratorT last, NameT name)
Unsorted string search or identifier lookups are linear scans.
@ Type
An inlay hint that for a type annotation.
int compare(const Fraction &x, const Fraction &y)
Three-way comparison between two fractions.
Definition: Fraction.h:59
Include the generated interface declarations.
llvm::function_ref< Fn > function_ref
Definition: LLVM.h:150
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
inline ::llvm::hash_code hash_value(AffineExpr arg)
Make AffineExpr hashable.
Definition: AffineExpr.h:240
llvm::hash_code hash_value(OperationName arg)
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Definition: AliasAnalysis.h:78
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()
Enable Bitmask enums for OperationEquivalence::Flags.
static mlir::OperationName getTombstoneKey()
static mlir::OperationName getEmptyKey()
static bool isEqual(mlir::OperationName lhs, mlir::OperationName rhs)
static unsigned getHashValue(mlir::OperationName val)
static mlir::RegisteredOperationName getEmptyKey()
static mlir::RegisteredOperationName getTombstoneKey()
static mlir::OperationName getFromVoidPointer(void *P)
static void * getAsVoidPointer(mlir::OperationName I)
static mlir::RegisteredOperationName getFromVoidPointer(void *P)
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
This class provides utilities for computing if two operations are equivalent.
static llvm::hash_code ignoreHashValue(Value)
Helper that can be used with computeHash above to ignore operation operands/result mapping.
static llvm::hash_code directHashValue(Value v)
Helper that can be used with computeHash above to ignore operation operands/result mapping.
static LogicalResult ignoreValueEquivalence(Value lhs, Value rhs)
Helper that can be used with isEquivalentTo above to ignore operation operands/result mapping.
static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> mapOperands, function_ref< LogicalResult(Value, Value)> mapResults, Flags flags=Flags::None)
Compare two operations and return if they are equivalent.
static LogicalResult exactValueMatch(Value lhs, Value rhs)
Helper that can be used with isEquivalentTo above to ignore operation operands/result mapping.
static llvm::hash_code computeHash(Operation *op, function_ref< llvm::hash_code(Value)> hashOperands=[](Value v) { return hash_value(v);}, function_ref< llvm::hash_code(Value)> hashResults=[](Value v) { return hash_value(v);}, Flags flags=Flags::None)
Compute a hash for the given operation.
This class represents a type erased version of an operation.
VerifyInvariantsFn verifyInvariantsFn
FoldHookFn foldHookFn
Internal callback hooks provided by the op implementation.
PopulateDefaultAttrsFn populateDefaultAttrsFn
VerifyRegionInvariantsFn verifyRegionInvariantsFn
ArrayRef< StringAttr > attributeNames
A list of attribute names registered to this operation in StringAttr form.
StringAttr name
The name of the operation.
TypeID typeID
The unique identifier of the derived Op class.
PrintAssemblyFn printAssemblyFn
ParseAssemblyFn parseAssemblyFn
Dialect * dialect
This is the dialect that this operation belongs to.
GetCanonicalizationPatternsFn getCanonicalizationPatternsFn
detail::InterfaceMap interfaceMap
A map of interfaces that were registered to this operation.
bool isRegistered() const
The following fields are only populated when the operation is registered.
This represents an operation in an abstracted form, suitable for use with the builder APIs.
void addRegions(MutableArrayRef< std::unique_ptr< Region >> regions)
Take ownership of a set of regions that should be attached to the Operation.
SmallVector< Block *, 1 > successors
Successors of this operation and their respective operands.
SmallVector< Value, 4 > operands
void addOperands(ValueRange newOperands)
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
void addAttribute(StringAttr name, Attribute attr)
Add an attribute with the specified name.
std::enable_if_t<!std::is_convertible< RangeT, ArrayRef< Type > >::value > addTypes(RangeT &&newTypes)
void addSuccessors(Block *successor)
void addTypes(ArrayRef< Type > newTypes)
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
NamedAttrList attributes
OperationState(Location location, StringRef name)
MLIRContext * getContext() const
Get the context held by this operation state.
SmallVector< Type, 4 > types
Types of the results of this operation.
Region * addRegion()
Create a region that should be attached to the operation.