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