MLIR  19.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/Attributes.h"
18 #include "mlir/IR/BlockSupport.h"
20 #include "mlir/IR/Diagnostics.h"
22 #include "mlir/IR/Location.h"
23 #include "mlir/IR/TypeRange.h"
24 #include "mlir/IR/Types.h"
25 #include "mlir/IR/Value.h"
27 #include "llvm/ADT/BitmaskEnum.h"
28 #include "llvm/ADT/PointerUnion.h"
29 #include "llvm/ADT/STLFunctionalExtras.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/PointerLikeTypeTraits.h"
32 #include "llvm/Support/TrailingObjects.h"
33 #include <memory>
34 #include <optional>
35 
36 namespace llvm {
37 class BitVector;
38 } // namespace llvm
39 
40 namespace mlir {
41 class Dialect;
42 class DictionaryAttr;
43 class ElementsAttr;
44 struct EmptyProperties;
45 class MutableOperandRangeRange;
46 class NamedAttrList;
47 class Operation;
48 struct OperationState;
49 class OpAsmParser;
50 class OpAsmPrinter;
51 class OperandRange;
52 class OperandRangeRange;
53 class OpFoldResult;
54 class ParseResult;
55 class Pattern;
56 class Region;
57 class ResultRange;
58 class RewritePattern;
59 class RewritePatternSet;
60 class Type;
61 class Value;
62 class ValueRange;
63 template <typename ValueRangeT>
64 class ValueTypeRange;
65 
66 //===----------------------------------------------------------------------===//
67 // OpaqueProperties
68 //===----------------------------------------------------------------------===//
69 
70 /// Simple wrapper around a void* in order to express generically how to pass
71 /// in op properties through APIs.
73 public:
74  OpaqueProperties(void *prop) : properties(prop) {}
75  operator bool() const { return properties != nullptr; }
76  template <typename Dest>
77  Dest as() const {
78  return static_cast<Dest>(const_cast<void *>(properties));
79  }
80 
81 private:
82  void *properties;
83 };
84 
85 //===----------------------------------------------------------------------===//
86 // OperationName
87 //===----------------------------------------------------------------------===//
88 
90 public:
91  using FoldHookFn = llvm::unique_function<LogicalResult(
93  using HasTraitFn = llvm::unique_function<bool(TypeID) const>;
95  llvm::unique_function<ParseResult(OpAsmParser &, OperationState &)>;
96  // Note: RegisteredOperationName is passed as reference here as the derived
97  // class is defined below.
99  llvm::unique_function<void(const OperationName &, NamedAttrList &) const>;
101  llvm::unique_function<void(Operation *, OpAsmPrinter &, StringRef) const>;
103  llvm::unique_function<LogicalResult(Operation *) const>;
105  llvm::unique_function<LogicalResult(Operation *) const>;
106 
107  /// This class represents a type erased version of an operation. It contains
108  /// all of the components necessary for opaquely interacting with an
109  /// operation. If the operation is not registered, some of these components
110  /// may not be populated.
112  virtual ~InterfaceConcept() = default;
116  MLIRContext *) = 0;
117  virtual bool hasTrait(TypeID) = 0;
119  virtual void populateDefaultAttrs(const OperationName &,
120  NamedAttrList &) = 0;
121  virtual void printAssembly(Operation *, OpAsmPrinter &, StringRef) = 0;
124  /// Implementation for properties
125  virtual std::optional<Attribute> getInherentAttr(Operation *,
126  StringRef name) = 0;
127  virtual void setInherentAttr(Operation *op, StringAttr name,
128  Attribute value) = 0;
129  virtual void populateInherentAttrs(Operation *op, NamedAttrList &attrs) = 0;
130  virtual LogicalResult
133  virtual int getOpPropertyByteSize() = 0;
134  virtual void initProperties(OperationName opName, OpaqueProperties storage,
135  OpaqueProperties init) = 0;
138  OpaqueProperties properties) = 0;
139  virtual LogicalResult
145  virtual llvm::hash_code hashProperties(OpaqueProperties) = 0;
146  };
147 
148 public:
149  class Impl : public InterfaceConcept {
150  public:
151  Impl(StringRef, Dialect *dialect, TypeID typeID,
156  interfaceMap(std::move(interfaceMap)) {}
157 
158  /// Returns true if this is a registered operation.
159  bool isRegistered() const { return typeID != TypeID::get<void>(); }
161  Dialect *getDialect() const { return dialect; }
162  StringAttr getName() const { return name; }
163  TypeID getTypeID() const { return typeID; }
165 
166  protected:
167  //===------------------------------------------------------------------===//
168  // Registered Operation Info
169 
170  /// The name of the operation.
171  StringAttr name;
172 
173  /// The unique identifier of the derived Op class.
175 
176  /// The following fields are only populated when the operation is
177  /// registered.
178 
179  /// This is the dialect that this operation belongs to.
181 
182  /// A map of interfaces that were registered to this operation.
184 
185  /// A list of attribute names registered to this operation in StringAttr
186  /// form. This allows for operation classes to use StringAttr for attribute
187  /// lookup/creation/etc., as opposed to raw strings.
189 
191  };
192 
193 protected:
194  /// Default implementation for unregistered operations.
195  struct UnregisteredOpModel : public Impl {
196  using Impl::Impl;
200  bool hasTrait(TypeID) final;
202  void populateDefaultAttrs(const OperationName &, NamedAttrList &) final;
203  void printAssembly(Operation *, OpAsmPrinter &, StringRef) final;
206  /// Implementation for properties
207  std::optional<Attribute> getInherentAttr(Operation *op,
208  StringRef name) final;
209  void setInherentAttr(Operation *op, StringAttr name, Attribute value) final;
210  void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final;
212  verifyInherentAttrs(OperationName opName, NamedAttrList &attributes,
214  int getOpPropertyByteSize() final;
215  void initProperties(OperationName opName, OpaqueProperties storage,
216  OpaqueProperties init) final;
219  OpaqueProperties properties) final;
226  llvm::hash_code hashProperties(OpaqueProperties) final;
227  };
228 
229 public:
230  OperationName(StringRef name, MLIRContext *context);
231 
232  /// Return if this operation is registered.
233  bool isRegistered() const { return getImpl()->isRegistered(); }
234 
235  /// Return the unique identifier of the derived Op class, or null if not
236  /// registered.
237  TypeID getTypeID() const { return getImpl()->getTypeID(); }
238 
239  /// If this operation is registered, returns the registered information,
240  /// std::nullopt otherwise.
241  std::optional<RegisteredOperationName> getRegisteredInfo() const;
242 
243  /// This hook implements a generalized folder for this operation. Operations
244  /// can implement this to provide simplifications rules that are applied by
245  /// the Builder::createOrFold API and the canonicalization pass.
246  ///
247  /// This is an intentionally limited interface - implementations of this
248  /// hook can only perform the following changes to the operation:
249  ///
250  /// 1. They can leave the operation alone and without changing the IR, and
251  /// return failure.
252  /// 2. They can mutate the operation in place, without changing anything
253  /// else
254  /// in the IR. In this case, return success.
255  /// 3. They can return a list of existing values that can be used instead
256  /// of
257  /// the operation. In this case, fill in the results list and return
258  /// success. The caller will remove the operation and use those results
259  /// instead.
260  ///
261  /// This allows expression of some simple in-place canonicalizations (e.g.
262  /// "x+0 -> x", "min(x,y,x,z) -> min(x,y,z)", "x+y-x -> y", etc), as well as
263  /// generalized constant folding.
265  SmallVectorImpl<OpFoldResult> &results) const {
266  return getImpl()->foldHook(op, operands, results);
267  }
268 
269  /// This hook returns any canonicalization pattern rewrites that the
270  /// operation supports, for use by the canonicalization pass.
272  MLIRContext *context) const {
273  return getImpl()->getCanonicalizationPatterns(results, context);
274  }
275 
276  /// Returns true if the operation was registered with a particular trait, e.g.
277  /// hasTrait<OperandsAreSignlessIntegerLike>(). Returns false if the operation
278  /// is unregistered.
279  template <template <typename T> class Trait>
280  bool hasTrait() const {
281  return hasTrait(TypeID::get<Trait>());
282  }
283  bool hasTrait(TypeID traitID) const { return getImpl()->hasTrait(traitID); }
284 
285  /// Returns true if the operation *might* have the provided trait. This
286  /// means that either the operation is unregistered, or it was registered with
287  /// the provide trait.
288  template <template <typename T> class Trait>
289  bool mightHaveTrait() const {
290  return mightHaveTrait(TypeID::get<Trait>());
291  }
292  bool mightHaveTrait(TypeID traitID) const {
293  return !isRegistered() || getImpl()->hasTrait(traitID);
294  }
295 
296  /// Return the static hook for parsing this operation assembly.
298  return getImpl()->getParseAssemblyFn();
299  }
300 
301  /// This hook implements the method to populate defaults attributes that are
302  /// unset.
303  void populateDefaultAttrs(NamedAttrList &attrs) const {
304  getImpl()->populateDefaultAttrs(*this, attrs);
305  }
306 
307  /// This hook implements the AsmPrinter for this operation.
309  StringRef defaultDialect) const {
310  return getImpl()->printAssembly(op, p, defaultDialect);
311  }
312 
313  /// These hooks implement the verifiers for this operation. It should emits
314  /// an error message and returns failure if a problem is detected, or
315  /// returns success if everything is ok.
317  return getImpl()->verifyInvariants(op);
318  }
320  return getImpl()->verifyRegionInvariants(op);
321  }
322 
323  /// Return the list of cached attribute names registered to this operation.
324  /// The order of attributes cached here is unique to each type of operation,
325  /// and the interpretation of this attribute list should generally be driven
326  /// by the respective operation. In many cases, this caching removes the
327  /// need to use the raw string name of a known attribute.
328  ///
329  /// For example the ODS generator, with an op defining the following
330  /// attributes:
331  ///
332  /// let arguments = (ins I32Attr:$attr1, I32Attr:$attr2);
333  ///
334  /// ... may produce an order here of ["attr1", "attr2"]. This allows for the
335  /// ODS generator to directly access the cached name for a known attribute,
336  /// greatly simplifying the cost and complexity of attribute usage produced
337  /// by the generator.
338  ///
340  return getImpl()->getAttributeNames();
341  }
342 
343  /// Returns an instance of the concept object for the given interface if it
344  /// was registered to this operation, null otherwise. This should not be used
345  /// directly.
346  template <typename T>
347  typename T::Concept *getInterface() const {
348  return getImpl()->getInterfaceMap().lookup<T>();
349  }
350 
351  /// Attach the given models as implementations of the corresponding
352  /// interfaces for the concrete operation.
353  template <typename... Models>
355  // Handle the case where the models resolve a promised interface.
357  *getDialect(), getTypeID(), Models::Interface::getInterfaceID()),
358  ...);
359 
360  getImpl()->getInterfaceMap().insertModels<Models...>();
361  }
362 
363  /// Returns true if `InterfaceT` has been promised by the dialect or
364  /// implemented.
365  template <typename InterfaceT>
368  getDialect(), getTypeID(), InterfaceT::getInterfaceID()) ||
369  hasInterface<InterfaceT>();
370  }
371 
372  /// Returns true if this operation has the given interface registered to it.
373  template <typename T>
374  bool hasInterface() const {
375  return hasInterface(TypeID::get<T>());
376  }
377  bool hasInterface(TypeID interfaceID) const {
378  return getImpl()->getInterfaceMap().contains(interfaceID);
379  }
380 
381  /// Returns true if the operation *might* have the provided interface. This
382  /// means that either the operation is unregistered, or it was registered with
383  /// the provide interface.
384  template <typename T>
385  bool mightHaveInterface() const {
386  return mightHaveInterface(TypeID::get<T>());
387  }
388  bool mightHaveInterface(TypeID interfaceID) const {
389  return !isRegistered() || hasInterface(interfaceID);
390  }
391 
392  /// Lookup an inherent attribute by name, this method isn't recommended
393  /// and may be removed in the future.
394  std::optional<Attribute> getInherentAttr(Operation *op,
395  StringRef name) const {
396  return getImpl()->getInherentAttr(op, name);
397  }
398 
399  void setInherentAttr(Operation *op, StringAttr name, Attribute value) const {
400  return getImpl()->setInherentAttr(op, name, value);
401  }
402 
404  return getImpl()->populateInherentAttrs(op, attrs);
405  }
406  /// This method exists for backward compatibility purpose when using
407  /// properties to store inherent attributes, it enables validating the
408  /// attributes when parsed from the older generic syntax pre-Properties.
412  return getImpl()->verifyInherentAttrs(*this, attributes, emitError);
413  }
414  /// This hooks return the number of bytes to allocate for the op properties.
415  int getOpPropertyByteSize() const {
416  return getImpl()->getOpPropertyByteSize();
417  }
418 
419  /// This hooks destroy the op properties.
420  void destroyOpProperties(OpaqueProperties properties) const {
421  getImpl()->deleteProperties(properties);
422  }
423 
424  /// Initialize the op properties.
426  getImpl()->initProperties(*this, storage, init);
427  }
428 
429  /// Set the default values on the ODS attribute in the properties.
431  getImpl()->populateDefaultProperties(*this, properties);
432  }
433 
434  /// Return the op properties converted to an Attribute.
436  return getImpl()->getPropertiesAsAttr(op);
437  }
438 
439  /// Define the op properties from the provided Attribute.
441  OperationName opName, OpaqueProperties properties, Attribute attr,
443  return getImpl()->setPropertiesFromAttr(opName, properties, attr,
444  emitError);
445  }
446 
448  return getImpl()->copyProperties(lhs, rhs);
449  }
450 
452  return getImpl()->compareProperties(lhs, rhs);
453  }
454 
455  llvm::hash_code hashOpProperties(OpaqueProperties properties) const {
456  return getImpl()->hashProperties(properties);
457  }
458 
459  /// Return the dialect this operation is registered to if the dialect is
460  /// loaded in the context, or nullptr if the dialect isn't loaded.
461  Dialect *getDialect() const {
462  return isRegistered() ? getImpl()->getDialect()
463  : getImpl()->getName().getReferencedDialect();
464  }
465 
466  /// Return the name of the dialect this operation is registered to.
467  StringRef getDialectNamespace() const;
468 
469  /// Return the operation name with dialect name stripped, if it has one.
470  StringRef stripDialect() const { return getStringRef().split('.').second; }
471 
472  /// Return the context this operation is associated with.
473  MLIRContext *getContext() { return getIdentifier().getContext(); }
474 
475  /// Return the name of this operation. This always succeeds.
476  StringRef getStringRef() const { return getIdentifier(); }
477 
478  /// Return the name of this operation as a StringAttr.
479  StringAttr getIdentifier() const { return getImpl()->getName(); }
480 
481  void print(raw_ostream &os) const;
482  void dump() const;
483 
484  /// Represent the operation name as an opaque pointer. (Used to support
485  /// PointerLikeTypeTraits).
486  void *getAsOpaquePointer() const { return const_cast<Impl *>(impl); }
487  static OperationName getFromOpaquePointer(const void *pointer) {
488  return OperationName(
489  const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
490  }
491 
492  bool operator==(const OperationName &rhs) const { return impl == rhs.impl; }
493  bool operator!=(const OperationName &rhs) const { return !(*this == rhs); }
494 
495 protected:
497  Impl *getImpl() const { return impl; }
498  void setImpl(Impl *rhs) { impl = rhs; }
499 
500 private:
501  /// The internal implementation of the operation name.
502  Impl *impl = nullptr;
503 
504  /// Allow access to the Impl struct.
505  friend MLIRContextImpl;
508 };
509 
510 inline raw_ostream &operator<<(raw_ostream &os, OperationName info) {
511  info.print(os);
512  return os;
513 }
514 
515 // Make operation names hashable.
516 inline llvm::hash_code hash_value(OperationName arg) {
517  return llvm::hash_value(arg.getAsOpaquePointer());
518 }
519 
520 //===----------------------------------------------------------------------===//
521 // RegisteredOperationName
522 //===----------------------------------------------------------------------===//
523 
524 /// This is a "type erased" representation of a registered operation. This
525 /// should only be used by things like the AsmPrinter and other things that need
526 /// to be parameterized by generic operation hooks. Most user code should use
527 /// the concrete operation types.
529 public:
530  /// Implementation of the InterfaceConcept for operation APIs that forwarded
531  /// to a concrete op implementation.
532  template <typename ConcreteOp>
533  struct Model : public Impl {
535  : Impl(ConcreteOp::getOperationName(), dialect,
536  TypeID::get<ConcreteOp>(), ConcreteOp::getInterfaceMap()) {}
538  SmallVectorImpl<OpFoldResult> &results) final {
539  return ConcreteOp::getFoldHookFn()(op, attrs, results);
540  }
542  MLIRContext *context) final {
543  ConcreteOp::getCanonicalizationPatterns(set, context);
544  }
545  bool hasTrait(TypeID id) final { return ConcreteOp::getHasTraitFn()(id); }
547  return ConcreteOp::parse;
548  }
550  NamedAttrList &attrs) final {
551  ConcreteOp::populateDefaultAttrs(name, attrs);
552  }
554  StringRef name) final {
555  ConcreteOp::getPrintAssemblyFn()(op, printer, name);
556  }
558  return ConcreteOp::getVerifyInvariantsFn()(op);
559  }
561  return ConcreteOp::getVerifyRegionInvariantsFn()(op);
562  }
563 
564  /// Implementation for "Properties"
565 
566  using Properties = std::remove_reference_t<
567  decltype(std::declval<ConcreteOp>().getProperties())>;
568 
569  std::optional<Attribute> getInherentAttr(Operation *op,
570  StringRef name) final {
571  if constexpr (hasProperties) {
572  auto concreteOp = cast<ConcreteOp>(op);
573  return ConcreteOp::getInherentAttr(concreteOp->getContext(),
574  concreteOp.getProperties(), name);
575  }
576  // If the op does not have support for properties, we dispatch back to the
577  // dictionnary of discardable attributes for now.
578  return cast<ConcreteOp>(op)->getDiscardableAttr(name);
579  }
580  void setInherentAttr(Operation *op, StringAttr name,
581  Attribute value) final {
582  if constexpr (hasProperties) {
583  auto concreteOp = cast<ConcreteOp>(op);
584  return ConcreteOp::setInherentAttr(concreteOp.getProperties(), name,
585  value);
586  }
587  // If the op does not have support for properties, we dispatch back to the
588  // dictionnary of discardable attributes for now.
589  return cast<ConcreteOp>(op)->setDiscardableAttr(name, value);
590  }
592  if constexpr (hasProperties) {
593  auto concreteOp = cast<ConcreteOp>(op);
594  ConcreteOp::populateInherentAttrs(concreteOp->getContext(),
595  concreteOp.getProperties(), attrs);
596  }
597  }
601  if constexpr (hasProperties)
602  return ConcreteOp::verifyInherentAttrs(opName, attributes, emitError);
603  return success();
604  }
605  // Detect if the concrete operation defined properties.
606  static constexpr bool hasProperties = !std::is_same_v<
607  typename ConcreteOp::template InferredProperties<ConcreteOp>,
609 
610  int getOpPropertyByteSize() final {
611  if constexpr (hasProperties)
612  return sizeof(Properties);
613  return 0;
614  }
616  OpaqueProperties init) final {
617  using Properties =
618  typename ConcreteOp::template InferredProperties<ConcreteOp>;
619  if (init)
620  new (storage.as<Properties *>()) Properties(*init.as<Properties *>());
621  else
622  new (storage.as<Properties *>()) Properties();
623  if constexpr (hasProperties)
624  ConcreteOp::populateDefaultProperties(opName,
625  *storage.as<Properties *>());
626  }
628  prop.as<Properties *>()->~Properties();
629  }
631  OpaqueProperties properties) final {
632  if constexpr (hasProperties)
633  ConcreteOp::populateDefaultProperties(opName,
634  *properties.as<Properties *>());
635  }
636 
639  Attribute attr,
641  if constexpr (hasProperties) {
642  auto p = properties.as<Properties *>();
643  return ConcreteOp::setPropertiesFromAttr(*p, attr, emitError);
644  }
645  emitError() << "this operation does not support properties";
646  return failure();
647  }
649  if constexpr (hasProperties) {
650  auto concreteOp = cast<ConcreteOp>(op);
651  return ConcreteOp::getPropertiesAsAttr(concreteOp->getContext(),
652  concreteOp.getProperties());
653  }
654  return {};
655  }
657  if constexpr (hasProperties) {
658  return *lhs.as<Properties *>() == *rhs.as<Properties *>();
659  } else {
660  return true;
661  }
662  }
664  *lhs.as<Properties *>() = *rhs.as<Properties *>();
665  }
666  llvm::hash_code hashProperties(OpaqueProperties prop) final {
667  if constexpr (hasProperties)
668  return ConcreteOp::computePropertiesHash(*prop.as<Properties *>());
669 
670  return {};
671  }
672  };
673 
674  /// Lookup the registered operation information for the given operation.
675  /// Returns std::nullopt if the operation isn't registered.
676  static std::optional<RegisteredOperationName> lookup(StringRef name,
677  MLIRContext *ctx);
678 
679  /// Register a new operation in a Dialect object.
680  /// This constructor is used by Dialect objects when they register the list
681  /// of operations they contain.
682  template <typename T>
683  static void insert(Dialect &dialect) {
684  insert(std::make_unique<Model<T>>(&dialect), T::getAttributeNames());
685  }
686  /// The use of this method is in general discouraged in favor of
687  /// 'insert<CustomOp>(dialect)'.
688  static void insert(std::unique_ptr<OperationName::Impl> ownedImpl,
689  ArrayRef<StringRef> attrNames);
690 
691  /// Return the dialect this operation is registered to.
692  Dialect &getDialect() const { return *getImpl()->getDialect(); }
693 
694  /// Use the specified object to parse this ops custom assembly format.
696 
697  /// Represent the operation name as an opaque pointer. (Used to support
698  /// PointerLikeTypeTraits).
699  static RegisteredOperationName getFromOpaquePointer(const void *pointer) {
701  const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
702  }
703 
704 private:
706 
707  /// Allow access to the constructor.
708  friend OperationName;
709 };
710 
711 inline std::optional<RegisteredOperationName>
714  : std::optional<RegisteredOperationName>();
715 }
716 
717 //===----------------------------------------------------------------------===//
718 // Attribute Dictionary-Like Interface
719 //===----------------------------------------------------------------------===//
720 
721 /// Attribute collections provide a dictionary-like interface. Define common
722 /// lookup functions.
723 namespace impl {
724 
725 /// Unsorted string search or identifier lookups are linear scans.
726 template <typename IteratorT, typename NameT>
727 std::pair<IteratorT, bool> findAttrUnsorted(IteratorT first, IteratorT last,
728  NameT name) {
729  for (auto it = first; it != last; ++it)
730  if (it->getName() == name)
731  return {it, true};
732  return {last, false};
733 }
734 
735 /// Using llvm::lower_bound requires an extra string comparison to check whether
736 /// the returned iterator points to the found element or whether it indicates
737 /// the lower bound. Skip this redundant comparison by checking if `compare ==
738 /// 0` during the binary search.
739 template <typename IteratorT>
740 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
741  StringRef name) {
742  ptrdiff_t length = std::distance(first, last);
743 
744  while (length > 0) {
745  ptrdiff_t half = length / 2;
746  IteratorT mid = first + half;
747  int compare = mid->getName().strref().compare(name);
748  if (compare < 0) {
749  first = mid + 1;
750  length = length - half - 1;
751  } else if (compare > 0) {
752  length = half;
753  } else {
754  return {mid, true};
755  }
756  }
757  return {first, false};
758 }
759 
760 /// StringAttr lookups on large attribute lists will switch to string binary
761 /// search. String binary searches become significantly faster than linear scans
762 /// with the identifier when the attribute list becomes very large.
763 template <typename IteratorT>
764 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
765  StringAttr name) {
766  constexpr unsigned kSmallAttributeList = 16;
767  if (std::distance(first, last) > kSmallAttributeList)
768  return findAttrSorted(first, last, name.strref());
769  return findAttrUnsorted(first, last, name);
770 }
771 
772 /// Get an attribute from a sorted range of named attributes. Returns null if
773 /// the attribute was not found.
774 template <typename IteratorT, typename NameT>
775 Attribute getAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
776  std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
777  return result.second ? result.first->getValue() : Attribute();
778 }
779 
780 /// Get an attribute from a sorted range of named attributes. Returns
781 /// std::nullopt if the attribute was not found.
782 template <typename IteratorT, typename NameT>
783 std::optional<NamedAttribute>
784 getNamedAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
785  std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
786  return result.second ? *result.first : std::optional<NamedAttribute>();
787 }
788 
789 } // namespace impl
790 
791 //===----------------------------------------------------------------------===//
792 // NamedAttrList
793 //===----------------------------------------------------------------------===//
794 
795 /// NamedAttrList is array of NamedAttributes that tracks whether it is sorted
796 /// and does some basic work to remain sorted.
798 public:
803  using size_type = size_t;
804 
805  NamedAttrList() : dictionarySorted({}, true) {}
806  NamedAttrList(std::nullopt_t none) : NamedAttrList() {}
808  NamedAttrList(DictionaryAttr attributes);
810 
811  template <typename Container>
812  NamedAttrList(const Container &vec)
814 
815  bool operator!=(const NamedAttrList &other) const {
816  return !(*this == other);
817  }
818  bool operator==(const NamedAttrList &other) const {
819  return attrs == other.attrs;
820  }
821 
822  /// Add an attribute with the specified name.
823  void append(StringRef name, Attribute attr);
824 
825  /// Add an attribute with the specified name.
826  void append(StringAttr name, Attribute attr) {
827  append(NamedAttribute(name, attr));
828  }
829 
830  /// Append the given named attribute.
831  void append(NamedAttribute attr) { push_back(attr); }
832 
833  /// Add an array of named attributes.
834  template <typename RangeT>
835  void append(RangeT &&newAttributes) {
836  append(std::begin(newAttributes), std::end(newAttributes));
837  }
838 
839  /// Add a range of named attributes.
840  template <typename IteratorT,
841  typename = std::enable_if_t<std::is_convertible<
842  typename std::iterator_traits<IteratorT>::iterator_category,
843  std::input_iterator_tag>::value>>
844  void append(IteratorT inStart, IteratorT inEnd) {
845  // TODO: expand to handle case where values appended are in order & after
846  // end of current list.
847  dictionarySorted.setPointerAndInt(nullptr, false);
848  attrs.append(inStart, inEnd);
849  }
850 
851  /// Replaces the attributes with new list of attributes.
852  void assign(const_iterator inStart, const_iterator inEnd);
853 
854  /// Replaces the attributes with new list of attributes.
856  assign(range.begin(), range.end());
857  }
858 
859  void clear() {
860  attrs.clear();
861  dictionarySorted.setPointerAndInt(nullptr, false);
862  }
863 
864  bool empty() const { return attrs.empty(); }
865 
866  void reserve(size_type N) { attrs.reserve(N); }
867 
868  /// Add an attribute with the specified name.
869  void push_back(NamedAttribute newAttribute);
870 
871  /// Pop last element from list.
872  void pop_back() { attrs.pop_back(); }
873 
874  /// Returns an entry with a duplicate name the list, if it exists, else
875  /// returns std::nullopt.
876  std::optional<NamedAttribute> findDuplicate() const;
877 
878  /// Return a dictionary attribute for the underlying dictionary. This will
879  /// return an empty dictionary attribute if empty rather than null.
880  DictionaryAttr getDictionary(MLIRContext *context) const;
881 
882  /// Return all of the attributes on this operation.
884 
885  /// Return the specified attribute if present, null otherwise.
886  Attribute get(StringAttr name) const;
887  Attribute get(StringRef name) const;
888 
889  /// Return the specified named attribute if present, std::nullopt otherwise.
890  std::optional<NamedAttribute> getNamed(StringRef name) const;
891  std::optional<NamedAttribute> getNamed(StringAttr name) const;
892 
893  /// If the an attribute exists with the specified name, change it to the new
894  /// value. Otherwise, add a new attribute with the specified name/value.
895  /// Returns the previous attribute value of `name`, or null if no
896  /// attribute previously existed with `name`.
897  Attribute set(StringAttr name, Attribute value);
898  Attribute set(StringRef name, Attribute value);
899 
900  /// Erase the attribute with the given name from the list. Return the
901  /// attribute that was erased, or nullptr if there was no attribute with such
902  /// name.
903  Attribute erase(StringAttr name);
904  Attribute erase(StringRef name);
905 
906  iterator begin() { return attrs.begin(); }
907  iterator end() { return attrs.end(); }
908  const_iterator begin() const { return attrs.begin(); }
909  const_iterator end() const { return attrs.end(); }
910 
912  operator ArrayRef<NamedAttribute>() const;
913 
914 private:
915  /// Return whether the attributes are sorted.
916  bool isSorted() const { return dictionarySorted.getInt(); }
917 
918  /// Erase the attribute at the given iterator position.
919  Attribute eraseImpl(SmallVectorImpl<NamedAttribute>::iterator it);
920 
921  /// Lookup an attribute in the list.
922  template <typename AttrListT, typename NameT>
923  static auto findAttr(AttrListT &attrs, NameT name) {
924  return attrs.isSorted()
925  ? impl::findAttrSorted(attrs.begin(), attrs.end(), name)
926  : impl::findAttrUnsorted(attrs.begin(), attrs.end(), name);
927  }
928 
929  // These are marked mutable as they may be modified (e.g., sorted)
930  mutable SmallVector<NamedAttribute, 4> attrs;
931  // Pair with cached DictionaryAttr and status of whether attrs is sorted.
932  // Note: just because sorted does not mean a DictionaryAttr has been created
933  // but the case where there is a DictionaryAttr but attrs isn't sorted should
934  // not occur.
935  mutable llvm::PointerIntPair<Attribute, 1, bool> dictionarySorted;
936 };
937 
938 //===----------------------------------------------------------------------===//
939 // OperationState
940 //===----------------------------------------------------------------------===//
941 
942 /// This represents an operation in an abstracted form, suitable for use with
943 /// the builder APIs. This object is a large and heavy weight object meant to
944 /// be used as a temporary object on the stack. It is generally unwise to put
945 /// this in a collection.
950  /// Types of the results of this operation.
953  /// Successors of this operation and their respective operands.
955  /// Regions that the op will hold.
957 
958  // If we're creating an unregistered operation, this Attribute is used to
959  // build the properties. Otherwise it is ignored. For registered operations
960  // see the `getOrAddProperties` method.
962 
963 private:
964  OpaqueProperties properties = nullptr;
965  TypeID propertiesId;
966  llvm::function_ref<void(OpaqueProperties)> propertiesDeleter;
968  propertiesSetter;
969  friend class Operation;
970 
971 public:
972  OperationState(Location location, StringRef name);
974 
977  BlockRange successors = {},
978  MutableArrayRef<std::unique_ptr<Region>> regions = {});
979  OperationState(Location location, StringRef name, ValueRange operands,
980  TypeRange types, ArrayRef<NamedAttribute> attributes = {},
981  BlockRange successors = {},
982  MutableArrayRef<std::unique_ptr<Region>> regions = {});
983  OperationState(OperationState &&other) = default;
984  OperationState(const OperationState &other) = default;
986  OperationState &operator=(const OperationState &other) = default;
987  ~OperationState();
988 
989  /// Get (or create) a properties of the provided type to be set on the
990  /// operation on creation.
991  template <typename T>
993  if (!properties) {
994  T *p = new T{};
995  properties = p;
996  propertiesDeleter = [](OpaqueProperties prop) {
997  delete prop.as<const T *>();
998  };
999  propertiesSetter = [](OpaqueProperties new_prop,
1000  const OpaqueProperties prop) {
1001  *new_prop.as<T *>() = *prop.as<const T *>();
1002  };
1003  propertiesId = TypeID::get<T>();
1004  }
1005  assert(propertiesId == TypeID::get<T>() && "Inconsistent properties");
1006  return *properties.as<T *>();
1007  }
1008  OpaqueProperties getRawProperties() { return properties; }
1009 
1010  // Set the properties defined on this OpState on the given operation,
1011  // optionally emit diagnostics on error through the provided diagnostic.
1015 
1016  void addOperands(ValueRange newOperands);
1017 
1018  void addTypes(ArrayRef<Type> newTypes) {
1019  types.append(newTypes.begin(), newTypes.end());
1020  }
1021  template <typename RangeT>
1022  std::enable_if_t<!std::is_convertible<RangeT, ArrayRef<Type>>::value>
1023  addTypes(RangeT &&newTypes) {
1024  types.append(newTypes.begin(), newTypes.end());
1025  }
1026 
1027  /// Add an attribute with the specified name.
1028  void addAttribute(StringRef name, Attribute attr) {
1030  }
1031 
1032  /// Add an attribute with the specified name.
1033  void addAttribute(StringAttr name, Attribute attr) {
1034  attributes.append(name, attr);
1035  }
1036 
1037  /// Add an array of named attributes.
1039  attributes.append(newAttributes);
1040  }
1041 
1042  void addSuccessors(Block *successor) { successors.push_back(successor); }
1043  void addSuccessors(BlockRange newSuccessors);
1044 
1045  /// Create a region that should be attached to the operation. These regions
1046  /// can be filled in immediately without waiting for Operation to be
1047  /// created. When it is, the region bodies will be transferred.
1048  Region *addRegion();
1049 
1050  /// Take a region that should be attached to the Operation. The body of the
1051  /// region will be transferred when the Operation is constructed. If the
1052  /// region is null, a new empty region will be attached to the Operation.
1053  void addRegion(std::unique_ptr<Region> &&region);
1054 
1055  /// Take ownership of a set of regions that should be attached to the
1056  /// Operation.
1057  void addRegions(MutableArrayRef<std::unique_ptr<Region>> regions);
1058 
1059  /// Get the context held by this operation state.
1060  MLIRContext *getContext() const { return location->getContext(); }
1061 };
1062 
1063 //===----------------------------------------------------------------------===//
1064 // OperandStorage
1065 //===----------------------------------------------------------------------===//
1066 
1067 namespace detail {
1068 /// This class handles the management of operation operands. Operands are
1069 /// stored either in a trailing array, or a dynamically resizable vector.
1070 class alignas(8) OperandStorage {
1071 public:
1072  OperandStorage(Operation *owner, OpOperand *trailingOperands,
1073  ValueRange values);
1074  ~OperandStorage();
1075 
1076  /// Replace the operands contained in the storage with the ones provided in
1077  /// 'values'.
1078  void setOperands(Operation *owner, ValueRange values);
1079 
1080  /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
1081  /// with the ones provided in 'operands'. 'operands' may be smaller or larger
1082  /// than the range pointed to by 'start'+'length'.
1083  void setOperands(Operation *owner, unsigned start, unsigned length,
1084  ValueRange operands);
1085 
1086  /// Erase the operands held by the storage within the given range.
1087  void eraseOperands(unsigned start, unsigned length);
1088 
1089  /// Erase the operands held by the storage that have their corresponding bit
1090  /// set in `eraseIndices`.
1091  void eraseOperands(const BitVector &eraseIndices);
1092 
1093  /// Get the operation operands held by the storage.
1094  MutableArrayRef<OpOperand> getOperands() { return {operandStorage, size()}; }
1095 
1096  /// Return the number of operands held in the storage.
1097  unsigned size() { return numOperands; }
1098 
1099 private:
1100  /// Resize the storage to the given size. Returns the array containing the new
1101  /// operands.
1102  MutableArrayRef<OpOperand> resize(Operation *owner, unsigned newSize);
1103 
1104  /// The total capacity number of operands that the storage can hold.
1105  unsigned capacity : 31;
1106  /// A flag indicating if the operand storage was dynamically allocated, as
1107  /// opposed to inlined into the owning operation.
1108  unsigned isStorageDynamic : 1;
1109  /// The number of operands within the storage.
1110  unsigned numOperands;
1111  /// A pointer to the operand storage.
1112  OpOperand *operandStorage;
1113 };
1114 } // namespace detail
1115 
1116 //===----------------------------------------------------------------------===//
1117 // OpPrintingFlags
1118 //===----------------------------------------------------------------------===//
1119 
1120 /// Set of flags used to control the behavior of the various IR print methods
1121 /// (e.g. Operation::Print).
1123 public:
1124  OpPrintingFlags();
1125  OpPrintingFlags(std::nullopt_t) : OpPrintingFlags() {}
1126 
1127  /// Enables the elision of large elements attributes by printing a lexically
1128  /// valid but otherwise meaningless form instead of the element data. The
1129  /// `largeElementLimit` is used to configure what is considered to be a
1130  /// "large" ElementsAttr by providing an upper limit to the number of
1131  /// elements.
1132  OpPrintingFlags &elideLargeElementsAttrs(int64_t largeElementLimit = 16);
1133 
1134  /// Enables the elision of large resources strings by omitting them from the
1135  /// `dialect_resources` section. The `largeResourceLimit` is used to configure
1136  /// what is considered to be a "large" resource by providing an upper limit to
1137  /// the string size.
1138  OpPrintingFlags &elideLargeResourceString(int64_t largeResourceLimit = 64);
1139 
1140  /// Enable or disable printing of debug information (based on `enable`). If
1141  /// 'prettyForm' is set to true, debug information is printed in a more
1142  /// readable 'pretty' form. Note: The IR generated with 'prettyForm' is not
1143  /// parsable.
1144  OpPrintingFlags &enableDebugInfo(bool enable = true, bool prettyForm = false);
1145 
1146  /// Always print operations in the generic form.
1147  OpPrintingFlags &printGenericOpForm(bool enable = true);
1148 
1149  /// Skip printing regions.
1150  OpPrintingFlags &skipRegions(bool skip = true);
1151 
1152  /// Do not verify the operation when using custom operation printers.
1154 
1155  /// Use local scope when printing the operation. This allows for using the
1156  /// printer in a more localized and thread-safe setting, but may not
1157  /// necessarily be identical to what the IR will look like when dumping
1158  /// the full module.
1160 
1161  /// Print users of values as comments.
1163 
1164  /// Return if the given ElementsAttr should be elided.
1165  bool shouldElideElementsAttr(ElementsAttr attr) const;
1166 
1167  /// Return the size limit for printing large ElementsAttr.
1168  std::optional<int64_t> getLargeElementsAttrLimit() const;
1169 
1170  /// Return the size limit in chars for printing large resources.
1171  std::optional<uint64_t> getLargeResourceStringLimit() const;
1172 
1173  /// Return if debug information should be printed.
1174  bool shouldPrintDebugInfo() const;
1175 
1176  /// Return if debug information should be printed in the pretty form.
1177  bool shouldPrintDebugInfoPrettyForm() const;
1178 
1179  /// Return if operations should be printed in the generic form.
1180  bool shouldPrintGenericOpForm() const;
1181 
1182  /// Return if regions should be skipped.
1183  bool shouldSkipRegions() const;
1184 
1185  /// Return if operation verification should be skipped.
1186  bool shouldAssumeVerified() const;
1187 
1188  /// Return if the printer should use local scope when dumping the IR.
1189  bool shouldUseLocalScope() const;
1190 
1191  /// Return if the printer should print users of values.
1192  bool shouldPrintValueUsers() const;
1193 
1194 private:
1195  /// Elide large elements attributes if the number of elements is larger than
1196  /// the upper limit.
1197  std::optional<int64_t> elementsAttrElementLimit;
1198 
1199  /// Elide printing large resources based on size of string.
1200  std::optional<uint64_t> resourceStringCharLimit;
1201 
1202  /// Print debug information.
1203  bool printDebugInfoFlag : 1;
1204  bool printDebugInfoPrettyFormFlag : 1;
1205 
1206  /// Print operations in the generic form.
1207  bool printGenericOpFormFlag : 1;
1208 
1209  /// Always skip Regions.
1210  bool skipRegionsFlag : 1;
1211 
1212  /// Skip operation verification.
1213  bool assumeVerifiedFlag : 1;
1214 
1215  /// Print operations with numberings local to the current operation.
1216  bool printLocalScope : 1;
1217 
1218  /// Print users of values.
1219  bool printValueUsersFlag : 1;
1220 };
1221 
1222 //===----------------------------------------------------------------------===//
1223 // Operation Equivalency
1224 //===----------------------------------------------------------------------===//
1225 
1226 /// This class provides utilities for computing if two operations are
1227 /// equivalent.
1229  enum Flags {
1230  None = 0,
1231 
1232  // When provided, the location attached to the operation are ignored.
1234 
1235  LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
1236  };
1237 
1238  /// Compute a hash for the given operation.
1239  /// The `hashOperands` and `hashResults` callbacks are expected to return a
1240  /// unique hash_code for a given Value.
1241  static llvm::hash_code computeHash(
1242  Operation *op,
1243  function_ref<llvm::hash_code(Value)> hashOperands =
1244  [](Value v) { return hash_value(v); },
1245  function_ref<llvm::hash_code(Value)> hashResults =
1246  [](Value v) { return hash_value(v); },
1247  Flags flags = Flags::None);
1248 
1249  /// Helper that can be used with `computeHash` above to ignore operation
1250  /// operands/result mapping.
1251  static llvm::hash_code ignoreHashValue(Value) { return llvm::hash_code{}; }
1252  /// Helper that can be used with `computeHash` above to ignore operation
1253  /// operands/result mapping.
1254  static llvm::hash_code directHashValue(Value v) { return hash_value(v); }
1255 
1256  /// Compare two operations (including their regions) and return if they are
1257  /// equivalent.
1258  ///
1259  /// * `checkEquivalent` is a callback to check if two values are equivalent.
1260  /// For two operations to be equivalent, their operands must be the same SSA
1261  /// value or this callback must return `success`.
1262  /// * `markEquivalent` is a callback to inform the caller that the analysis
1263  /// determined that two values are equivalent.
1264  /// * `checkCommutativeEquivalent` is an optional callback to check for
1265  /// equivalence across two ranges for a commutative operation. If not passed
1266  /// in, then equivalence is checked pairwise. This callback is needed to be
1267  /// able to query the optional equivalence classes.
1268  ///
1269  /// Note: Additional information regarding value equivalence can be injected
1270  /// into the analysis via `checkEquivalent`. Typically, callers may want
1271  /// values that were determined to be equivalent as per `markEquivalent` to be
1272  /// reflected in `checkEquivalent`, unless `exactValueMatch` or a different
1273  /// equivalence relationship is desired.
1274  static bool
1275  isEquivalentTo(Operation *lhs, Operation *rhs,
1276  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1277  function_ref<void(Value, Value)> markEquivalent = nullptr,
1278  Flags flags = Flags::None,
1280  checkCommutativeEquivalent = nullptr);
1281 
1282  /// Compare two operations and return if they are equivalent.
1283  static bool isEquivalentTo(Operation *lhs, Operation *rhs, Flags flags);
1284 
1285  /// Compare two regions (including their subregions) and return if they are
1286  /// equivalent. See also `isEquivalentTo` for details.
1287  static bool isRegionEquivalentTo(
1288  Region *lhs, Region *rhs,
1289  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1290  function_ref<void(Value, Value)> markEquivalent,
1293  checkCommutativeEquivalent = nullptr);
1294 
1295  /// Compare two regions and return if they are equivalent.
1296  static bool isRegionEquivalentTo(Region *lhs, Region *rhs,
1298 
1299  /// Helper that can be used with `isEquivalentTo` above to consider ops
1300  /// equivalent even if their operands are not equivalent.
1302  return success();
1303  }
1304  /// Helper that can be used with `isEquivalentTo` above to consider ops
1305  /// equivalent only if their operands are the exact same SSA values.
1307  return success(lhs == rhs);
1308  }
1309 };
1310 
1311 /// Enable Bitmask enums for OperationEquivalence::Flags.
1313 
1314 //===----------------------------------------------------------------------===//
1315 // OperationFingerPrint
1316 //===----------------------------------------------------------------------===//
1317 
1318 /// A unique fingerprint for a specific operation, and all of it's internal
1319 /// operations (if `includeNested` is set).
1321 public:
1322  OperationFingerPrint(Operation *topOp, bool includeNested = true);
1325 
1326  bool operator==(const OperationFingerPrint &other) const {
1327  return hash == other.hash;
1328  }
1329  bool operator!=(const OperationFingerPrint &other) const {
1330  return !(*this == other);
1331  }
1332 
1333 private:
1334  std::array<uint8_t, 20> hash;
1335 };
1336 
1337 } // namespace mlir
1338 
1339 namespace llvm {
1340 template <>
1341 struct DenseMapInfo<mlir::OperationName> {
1343  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1345  }
1349  }
1350  static unsigned getHashValue(mlir::OperationName val) {
1352  }
1354  return lhs == rhs;
1355  }
1356 };
1357 template <>
1358 struct DenseMapInfo<mlir::RegisteredOperationName>
1359  : public DenseMapInfo<mlir::OperationName> {
1361  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1363  }
1367  }
1368 };
1369 
1370 template <>
1371 struct PointerLikeTypeTraits<mlir::OperationName> {
1372  static inline void *getAsVoidPointer(mlir::OperationName I) {
1373  return const_cast<void *>(I.getAsOpaquePointer());
1374  }
1375  static inline mlir::OperationName getFromVoidPointer(void *P) {
1377  }
1378  static constexpr int NumLowBitsAvailable =
1379  PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
1380 };
1381 template <>
1382 struct PointerLikeTypeTraits<mlir::RegisteredOperationName>
1383  : public PointerLikeTypeTraits<mlir::OperationName> {
1386  }
1387 };
1388 
1389 } // namespace llvm
1390 
1391 #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 represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:308
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:202
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:263
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:284
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
Definition: AsmPrinter.cpp:291
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
Definition: AsmPrinter.cpp:319
OpPrintingFlags & printValueUsers()
Print users of values as comments.
Definition: AsmPrinter.cpp:278
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
Definition: AsmPrinter.cpp:324
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
Definition: AsmPrinter.cpp:306
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
Definition: AsmPrinter.cpp:327
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
Definition: AsmPrinter.cpp:311
OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
Definition: AsmPrinter.cpp:237
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
Definition: AsmPrinter.cpp:301
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
Definition: AsmPrinter.cpp:231
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
Definition: AsmPrinter.cpp:244
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
Definition: AsmPrinter.cpp:205
bool shouldSkipRegions() const
Return if regions should be skipped.
Definition: AsmPrinter.cpp:316
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
Definition: AsmPrinter.cpp:252
OpPrintingFlags & assumeVerified()
Do not verify the operation when using custom operation printers.
Definition: AsmPrinter.cpp:264
OpPrintingFlags(std::nullopt_t)
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
Definition: AsmPrinter.cpp:296
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
Definition: AsmPrinter.cpp:272
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
Definition: AsmPrinter.cpp:258
Simple wrapper around a void* in order to express generically how to pass in op properties through AP...
A unique fingerprint for a specific operation, and all of it's internal operations (if includeNested ...
OperationFingerPrint(Operation *topOp, bool includeNested=true)
bool operator!=(const OperationFingerPrint &other) const
OperationFingerPrint & operator=(const OperationFingerPrint &)=default
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
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) const
bool operator==(const OperationName &rhs) const
llvm::unique_function< LogicalResult(Operation *) const > VerifyInvariantsFn
void dump() const
Definition: AsmPrinter.cpp:62
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.
void setInherentAttr(Operation *op, StringAttr name, Attribute value) const
Attribute getOpPropertiesAsAttribute(Operation *op) const
Return the op properties converted to an Attribute.
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.
bool hasPromiseOrImplementsInterface() const
Returns true if InterfaceT has been promised by the dialect or implemented.
llvm::unique_function< bool(TypeID) const > HasTraitFn
std::optional< Attribute > getInherentAttr(Operation *op, StringRef name) const
Lookup an inherent attribute by name, this method isn't recommended and may be removed in the future.
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.
LogicalResult verifyInherentAttrs(NamedAttrList &attributes, function_ref< InFlightDiagnostic()> emitError) const
This method exists for backward compatibility purpose when using properties to store inherent attribu...
void initOpProperties(OpaqueProperties storage, OpaqueProperties init) const
Initialize the op properties.
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...
llvm::hash_code hashOpProperties(OpaqueProperties properties) const
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 setOpPropertiesFromAttribute(OperationName opName, OpaqueProperties properties, Attribute attr, function_ref< InFlightDiagnostic()> emitError) const
Define the op properties from the provided Attribute.
LogicalResult verifyInvariants(Operation *op) const
These hooks implement the verifiers for this operation.
llvm::unique_function< void(const OperationName &, NamedAttrList &) const > PopulateDefaultAttrsFn
void destroyOpProperties(OpaqueProperties properties) const
This hooks destroy the op properties.
bool compareOpProperties(OpaqueProperties lhs, OpaqueProperties rhs) const
int getOpPropertyByteSize() const
This hooks return the number of bytes to allocate for the op properties.
void populateDefaultProperties(OpaqueProperties properties) const
Set the default values on the ODS attribute in the properties.
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:60
void copyOpProperties(OpaqueProperties lhs, OpaqueProperties rhs) const
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:88
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:378
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
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
bool hasPromisedInterface(Dialect &dialect, TypeID interfaceRequestorID, TypeID interfaceID)
Checks if a promise has been made for the interface/requestor pair.
Definition: Dialect.cpp:166
void handleAdditionOfUndefinedPromisedInterface(Dialect &dialect, TypeID interfaceRequestorID, TypeID interfaceID)
Checks if the given interface, which is attempting to be attached, is a promised interface of this di...
Definition: Dialect.cpp:160
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:65
QueryRef parse(llvm::StringRef line, const QuerySession &qs)
Definition: Query.cpp:19
Include the generated interface declarations.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
llvm::function_ref< Fn > function_ref
Definition: LLVM.h:147
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
inline ::llvm::hash_code hash_value(AffineExpr arg)
Make AffineExpr hashable.
Definition: AffineExpr.h:261
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)
Structure used by default as a "marker" when no "Properties" are set on an Operation.
Definition: OpDefinition.h:77
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, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)
Compare two regions (including their subregions) and return if they are equivalent.
static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent=nullptr, Flags flags=Flags::None, function_ref< LogicalResult(ValueRange, ValueRange)> checkCommutativeEquivalent=nullptr)
Compare two operations (including their regions) 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.
This class represents a type erased version of an operation.
virtual void initProperties(OperationName opName, OpaqueProperties storage, OpaqueProperties init)=0
virtual void populateInherentAttrs(Operation *op, NamedAttrList &attrs)=0
virtual void deleteProperties(OpaqueProperties)=0
virtual void getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *)=0
virtual OperationName::ParseAssemblyFn getParseAssemblyFn()=0
virtual void printAssembly(Operation *, OpAsmPrinter &, StringRef)=0
virtual LogicalResult verifyInvariants(Operation *)=0
virtual void setInherentAttr(Operation *op, StringAttr name, Attribute value)=0
virtual LogicalResult setPropertiesFromAttr(OperationName, OpaqueProperties, Attribute, function_ref< InFlightDiagnostic()> emitError)=0
virtual void populateDefaultProperties(OperationName opName, OpaqueProperties properties)=0
virtual Attribute getPropertiesAsAttr(Operation *)=0
virtual LogicalResult foldHook(Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &)=0
virtual bool compareProperties(OpaqueProperties, OpaqueProperties)=0
virtual void copyProperties(OpaqueProperties, OpaqueProperties)=0
virtual void populateDefaultAttrs(const OperationName &, NamedAttrList &)=0
virtual LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> emitError)=0
virtual llvm::hash_code hashProperties(OpaqueProperties)=0
virtual std::optional< Attribute > getInherentAttr(Operation *, StringRef name)=0
Implementation for properties.
virtual LogicalResult verifyRegionInvariants(Operation *)=0
Default implementation for unregistered operations.
LogicalResult foldHook(Operation *, ArrayRef< Attribute >, SmallVectorImpl< OpFoldResult > &) final
llvm::hash_code hashProperties(OpaqueProperties) final
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final
void deleteProperties(OpaqueProperties) final
LogicalResult setPropertiesFromAttr(OperationName, OpaqueProperties, Attribute, function_ref< InFlightDiagnostic()> emitError) final
void setInherentAttr(Operation *op, StringAttr name, Attribute value) final
void populateDefaultProperties(OperationName opName, OpaqueProperties properties) final
OperationName::ParseAssemblyFn getParseAssemblyFn() final
LogicalResult verifyRegionInvariants(Operation *) final
std::optional< Attribute > getInherentAttr(Operation *op, StringRef name) final
Implementation for properties.
void getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) final
void initProperties(OperationName opName, OpaqueProperties storage, OpaqueProperties init) final
void populateDefaultAttrs(const OperationName &, NamedAttrList &) final
void printAssembly(Operation *, OpAsmPrinter &, StringRef) final
LogicalResult verifyInvariants(Operation *) final
void copyProperties(OpaqueProperties, OpaqueProperties) final
LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> emitError) final
Attribute getPropertiesAsAttr(Operation *) final
bool compareProperties(OpaqueProperties, OpaqueProperties) final
This represents an operation in an abstracted form, suitable for use with the builder APIs.
OperationState(const OperationState &other)=default
void addRegions(MutableArrayRef< std::unique_ptr< Region >> regions)
Take ownership of a set of regions that should be attached to the Operation.
OpaqueProperties getRawProperties()
SmallVector< Block *, 1 > successors
Successors of this operation and their respective operands.
T & getOrAddProperties()
Get (or create) a properties of the provided type to be set on the operation on creation.
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)
OperationState(OperationState &&other)=default
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.
OperationState & operator=(const OperationState &other)=default
OperationState & operator=(OperationState &&other)=default
LogicalResult setProperties(Operation *op, function_ref< InFlightDiagnostic()> emitError) const
Implementation of the InterfaceConcept for operation APIs that forwarded to a concrete op implementat...
void initProperties(OperationName opName, OpaqueProperties storage, OpaqueProperties init) final
LogicalResult setPropertiesFromAttr(OperationName opName, OpaqueProperties properties, Attribute attr, function_ref< InFlightDiagnostic()> emitError) final
void copyProperties(OpaqueProperties lhs, OpaqueProperties rhs) final
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
void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final
llvm::hash_code hashProperties(OpaqueProperties prop) final
LogicalResult foldHook(Operation *op, ArrayRef< Attribute > attrs, SmallVectorImpl< OpFoldResult > &results) final
bool compareProperties(OpaqueProperties lhs, OpaqueProperties rhs) final
std::remove_reference_t< decltype(std::declval< ConcreteOp >().getProperties())> Properties
Implementation for "Properties".
Attribute getPropertiesAsAttr(Operation *op) final
LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> emitError) final
void populateDefaultProperties(OperationName opName, OpaqueProperties properties) final
void deleteProperties(OpaqueProperties prop) final
void setInherentAttr(Operation *op, StringAttr name, Attribute value) final
std::optional< Attribute > getInherentAttr(Operation *op, StringRef name) final
Implementation for properties.