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  /// Lookup the registered operation information for the given operation.
680  /// Returns std::nullopt if the operation isn't registered.
681  static std::optional<RegisteredOperationName> lookup(TypeID typeID,
682  MLIRContext *ctx);
683 
684  /// Register a new operation in a Dialect object.
685  /// This constructor is used by Dialect objects when they register the list
686  /// of operations they contain.
687  template <typename T>
688  static void insert(Dialect &dialect) {
689  insert(std::make_unique<Model<T>>(&dialect), T::getAttributeNames());
690  }
691  /// The use of this method is in general discouraged in favor of
692  /// 'insert<CustomOp>(dialect)'.
693  static void insert(std::unique_ptr<OperationName::Impl> ownedImpl,
694  ArrayRef<StringRef> attrNames);
695 
696  /// Return the dialect this operation is registered to.
697  Dialect &getDialect() const { return *getImpl()->getDialect(); }
698 
699  /// Use the specified object to parse this ops custom assembly format.
701 
702  /// Represent the operation name as an opaque pointer. (Used to support
703  /// PointerLikeTypeTraits).
704  static RegisteredOperationName getFromOpaquePointer(const void *pointer) {
706  const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
707  }
708 
709 private:
711 
712  /// Allow access to the constructor.
713  friend OperationName;
714 };
715 
716 inline std::optional<RegisteredOperationName>
719  : std::optional<RegisteredOperationName>();
720 }
721 
722 //===----------------------------------------------------------------------===//
723 // Attribute Dictionary-Like Interface
724 //===----------------------------------------------------------------------===//
725 
726 /// Attribute collections provide a dictionary-like interface. Define common
727 /// lookup functions.
728 namespace impl {
729 
730 /// Unsorted string search or identifier lookups are linear scans.
731 template <typename IteratorT, typename NameT>
732 std::pair<IteratorT, bool> findAttrUnsorted(IteratorT first, IteratorT last,
733  NameT name) {
734  for (auto it = first; it != last; ++it)
735  if (it->getName() == name)
736  return {it, true};
737  return {last, false};
738 }
739 
740 /// Using llvm::lower_bound requires an extra string comparison to check whether
741 /// the returned iterator points to the found element or whether it indicates
742 /// the lower bound. Skip this redundant comparison by checking if `compare ==
743 /// 0` during the binary search.
744 template <typename IteratorT>
745 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
746  StringRef name) {
747  ptrdiff_t length = std::distance(first, last);
748 
749  while (length > 0) {
750  ptrdiff_t half = length / 2;
751  IteratorT mid = first + half;
752  int compare = mid->getName().strref().compare(name);
753  if (compare < 0) {
754  first = mid + 1;
755  length = length - half - 1;
756  } else if (compare > 0) {
757  length = half;
758  } else {
759  return {mid, true};
760  }
761  }
762  return {first, false};
763 }
764 
765 /// StringAttr lookups on large attribute lists will switch to string binary
766 /// search. String binary searches become significantly faster than linear scans
767 /// with the identifier when the attribute list becomes very large.
768 template <typename IteratorT>
769 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
770  StringAttr name) {
771  constexpr unsigned kSmallAttributeList = 16;
772  if (std::distance(first, last) > kSmallAttributeList)
773  return findAttrSorted(first, last, name.strref());
774  return findAttrUnsorted(first, last, name);
775 }
776 
777 /// Get an attribute from a sorted range of named attributes. Returns null if
778 /// the attribute was not found.
779 template <typename IteratorT, typename NameT>
780 Attribute getAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
781  std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
782  return result.second ? result.first->getValue() : Attribute();
783 }
784 
785 /// Get an attribute from a sorted range of named attributes. Returns
786 /// std::nullopt if the attribute was not found.
787 template <typename IteratorT, typename NameT>
788 std::optional<NamedAttribute>
789 getNamedAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
790  std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
791  return result.second ? *result.first : std::optional<NamedAttribute>();
792 }
793 
794 } // namespace impl
795 
796 //===----------------------------------------------------------------------===//
797 // NamedAttrList
798 //===----------------------------------------------------------------------===//
799 
800 /// NamedAttrList is array of NamedAttributes that tracks whether it is sorted
801 /// and does some basic work to remain sorted.
803 public:
808  using size_type = size_t;
809 
810  NamedAttrList() : dictionarySorted({}, true) {}
811  NamedAttrList(std::nullopt_t none) : NamedAttrList() {}
813  NamedAttrList(DictionaryAttr attributes);
815 
816  template <typename Container>
817  NamedAttrList(const Container &vec)
819 
820  bool operator!=(const NamedAttrList &other) const {
821  return !(*this == other);
822  }
823  bool operator==(const NamedAttrList &other) const {
824  return attrs == other.attrs;
825  }
826 
827  /// Add an attribute with the specified name.
828  void append(StringRef name, Attribute attr);
829 
830  /// Add an attribute with the specified name.
831  void append(StringAttr name, Attribute attr) {
832  append(NamedAttribute(name, attr));
833  }
834 
835  /// Append the given named attribute.
836  void append(NamedAttribute attr) { push_back(attr); }
837 
838  /// Add an array of named attributes.
839  template <typename RangeT>
840  void append(RangeT &&newAttributes) {
841  append(std::begin(newAttributes), std::end(newAttributes));
842  }
843 
844  /// Add a range of named attributes.
845  template <typename IteratorT,
846  typename = std::enable_if_t<std::is_convertible<
847  typename std::iterator_traits<IteratorT>::iterator_category,
848  std::input_iterator_tag>::value>>
849  void append(IteratorT inStart, IteratorT inEnd) {
850  // TODO: expand to handle case where values appended are in order & after
851  // end of current list.
852  dictionarySorted.setPointerAndInt(nullptr, false);
853  attrs.append(inStart, inEnd);
854  }
855 
856  /// Replaces the attributes with new list of attributes.
857  void assign(const_iterator inStart, const_iterator inEnd);
858 
859  /// Replaces the attributes with new list of attributes.
861  assign(range.begin(), range.end());
862  }
863 
864  void clear() {
865  attrs.clear();
866  dictionarySorted.setPointerAndInt(nullptr, false);
867  }
868 
869  bool empty() const { return attrs.empty(); }
870 
871  void reserve(size_type N) { attrs.reserve(N); }
872 
873  /// Add an attribute with the specified name.
874  void push_back(NamedAttribute newAttribute);
875 
876  /// Pop last element from list.
877  void pop_back() { attrs.pop_back(); }
878 
879  /// Returns an entry with a duplicate name the list, if it exists, else
880  /// returns std::nullopt.
881  std::optional<NamedAttribute> findDuplicate() const;
882 
883  /// Return a dictionary attribute for the underlying dictionary. This will
884  /// return an empty dictionary attribute if empty rather than null.
885  DictionaryAttr getDictionary(MLIRContext *context) const;
886 
887  /// Return all of the attributes on this operation.
889 
890  /// Return the specified attribute if present, null otherwise.
891  Attribute get(StringAttr name) const;
892  Attribute get(StringRef name) const;
893 
894  /// Return the specified named attribute if present, std::nullopt otherwise.
895  std::optional<NamedAttribute> getNamed(StringRef name) const;
896  std::optional<NamedAttribute> getNamed(StringAttr name) const;
897 
898  /// If the an attribute exists with the specified name, change it to the new
899  /// value. Otherwise, add a new attribute with the specified name/value.
900  /// Returns the previous attribute value of `name`, or null if no
901  /// attribute previously existed with `name`.
902  Attribute set(StringAttr name, Attribute value);
903  Attribute set(StringRef name, Attribute value);
904 
905  /// Erase the attribute with the given name from the list. Return the
906  /// attribute that was erased, or nullptr if there was no attribute with such
907  /// name.
908  Attribute erase(StringAttr name);
909  Attribute erase(StringRef name);
910 
911  iterator begin() { return attrs.begin(); }
912  iterator end() { return attrs.end(); }
913  const_iterator begin() const { return attrs.begin(); }
914  const_iterator end() const { return attrs.end(); }
915 
917  operator ArrayRef<NamedAttribute>() const;
918 
919 private:
920  /// Return whether the attributes are sorted.
921  bool isSorted() const { return dictionarySorted.getInt(); }
922 
923  /// Erase the attribute at the given iterator position.
924  Attribute eraseImpl(SmallVectorImpl<NamedAttribute>::iterator it);
925 
926  /// Lookup an attribute in the list.
927  template <typename AttrListT, typename NameT>
928  static auto findAttr(AttrListT &attrs, NameT name) {
929  return attrs.isSorted()
930  ? impl::findAttrSorted(attrs.begin(), attrs.end(), name)
931  : impl::findAttrUnsorted(attrs.begin(), attrs.end(), name);
932  }
933 
934  // These are marked mutable as they may be modified (e.g., sorted)
935  mutable SmallVector<NamedAttribute, 4> attrs;
936  // Pair with cached DictionaryAttr and status of whether attrs is sorted.
937  // Note: just because sorted does not mean a DictionaryAttr has been created
938  // but the case where there is a DictionaryAttr but attrs isn't sorted should
939  // not occur.
940  mutable llvm::PointerIntPair<Attribute, 1, bool> dictionarySorted;
941 };
942 
943 //===----------------------------------------------------------------------===//
944 // OperationState
945 //===----------------------------------------------------------------------===//
946 
947 /// This represents an operation in an abstracted form, suitable for use with
948 /// the builder APIs. This object is a large and heavy weight object meant to
949 /// be used as a temporary object on the stack. It is generally unwise to put
950 /// this in a collection.
955  /// Types of the results of this operation.
958  /// Successors of this operation and their respective operands.
960  /// Regions that the op will hold.
962 
963  /// This Attribute is used to opaquely construct the properties of the
964  /// operation. If we're creating an unregistered operation, the Attribute is
965  /// used as-is as the Properties storage of the operation. Otherwise, the
966  /// operation properties are constructed opaquely using its
967  /// `setPropertiesFromAttr` hook. Note that `getOrAddProperties` is the
968  /// preferred method to construct properties from C++.
970 
971 private:
972  OpaqueProperties properties = nullptr;
973  TypeID propertiesId;
974  llvm::function_ref<void(OpaqueProperties)> propertiesDeleter;
976  propertiesSetter;
977  friend class Operation;
978 
979 public:
980  OperationState(Location location, StringRef name);
982 
985  BlockRange successors = {},
986  MutableArrayRef<std::unique_ptr<Region>> regions = {});
987  OperationState(Location location, StringRef name, ValueRange operands,
988  TypeRange types, ArrayRef<NamedAttribute> attributes = {},
989  BlockRange successors = {},
990  MutableArrayRef<std::unique_ptr<Region>> regions = {});
991  OperationState(OperationState &&other) = default;
992  OperationState(const OperationState &other) = default;
994  OperationState &operator=(const OperationState &other) = default;
995  ~OperationState();
996 
997  /// Get (or create) a properties of the provided type to be set on the
998  /// operation on creation.
999  template <typename T>
1001  if (!properties) {
1002  T *p = new T{};
1003  properties = p;
1004  propertiesDeleter = [](OpaqueProperties prop) {
1005  delete prop.as<const T *>();
1006  };
1007  propertiesSetter = [](OpaqueProperties new_prop,
1008  const OpaqueProperties prop) {
1009  *new_prop.as<T *>() = *prop.as<const T *>();
1010  };
1011  propertiesId = TypeID::get<T>();
1012  }
1013  assert(propertiesId == TypeID::get<T>() && "Inconsistent properties");
1014  return *properties.as<T *>();
1015  }
1016  OpaqueProperties getRawProperties() { return properties; }
1017 
1018  // Set the properties defined on this OpState on the given operation,
1019  // optionally emit diagnostics on error through the provided diagnostic.
1023 
1024  void addOperands(ValueRange newOperands);
1025 
1026  void addTypes(ArrayRef<Type> newTypes) {
1027  types.append(newTypes.begin(), newTypes.end());
1028  }
1029  template <typename RangeT>
1030  std::enable_if_t<!std::is_convertible<RangeT, ArrayRef<Type>>::value>
1031  addTypes(RangeT &&newTypes) {
1032  types.append(newTypes.begin(), newTypes.end());
1033  }
1034 
1035  /// Add an attribute with the specified name.
1036  void addAttribute(StringRef name, Attribute attr) {
1038  }
1039 
1040  /// Add an attribute with the specified name.
1041  void addAttribute(StringAttr name, Attribute attr) {
1042  attributes.append(name, attr);
1043  }
1044 
1045  /// Add an array of named attributes.
1047  attributes.append(newAttributes);
1048  }
1049 
1050  void addSuccessors(Block *successor) { successors.push_back(successor); }
1051  void addSuccessors(BlockRange newSuccessors);
1052 
1053  /// Create a region that should be attached to the operation. These regions
1054  /// can be filled in immediately without waiting for Operation to be
1055  /// created. When it is, the region bodies will be transferred.
1056  Region *addRegion();
1057 
1058  /// Take a region that should be attached to the Operation. The body of the
1059  /// region will be transferred when the Operation is constructed. If the
1060  /// region is null, a new empty region will be attached to the Operation.
1061  void addRegion(std::unique_ptr<Region> &&region);
1062 
1063  /// Take ownership of a set of regions that should be attached to the
1064  /// Operation.
1065  void addRegions(MutableArrayRef<std::unique_ptr<Region>> regions);
1066 
1067  /// Get the context held by this operation state.
1068  MLIRContext *getContext() const { return location->getContext(); }
1069 };
1070 
1071 //===----------------------------------------------------------------------===//
1072 // OperandStorage
1073 //===----------------------------------------------------------------------===//
1074 
1075 namespace detail {
1076 /// This class handles the management of operation operands. Operands are
1077 /// stored either in a trailing array, or a dynamically resizable vector.
1078 class alignas(8) OperandStorage {
1079 public:
1080  OperandStorage(Operation *owner, OpOperand *trailingOperands,
1081  ValueRange values);
1082  ~OperandStorage();
1083 
1084  /// Replace the operands contained in the storage with the ones provided in
1085  /// 'values'.
1086  void setOperands(Operation *owner, ValueRange values);
1087 
1088  /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
1089  /// with the ones provided in 'operands'. 'operands' may be smaller or larger
1090  /// than the range pointed to by 'start'+'length'.
1091  void setOperands(Operation *owner, unsigned start, unsigned length,
1092  ValueRange operands);
1093 
1094  /// Erase the operands held by the storage within the given range.
1095  void eraseOperands(unsigned start, unsigned length);
1096 
1097  /// Erase the operands held by the storage that have their corresponding bit
1098  /// set in `eraseIndices`.
1099  void eraseOperands(const BitVector &eraseIndices);
1100 
1101  /// Get the operation operands held by the storage.
1102  MutableArrayRef<OpOperand> getOperands() { return {operandStorage, size()}; }
1103 
1104  /// Return the number of operands held in the storage.
1105  unsigned size() { return numOperands; }
1106 
1107 private:
1108  /// Resize the storage to the given size. Returns the array containing the new
1109  /// operands.
1110  MutableArrayRef<OpOperand> resize(Operation *owner, unsigned newSize);
1111 
1112  /// The total capacity number of operands that the storage can hold.
1113  unsigned capacity : 31;
1114  /// A flag indicating if the operand storage was dynamically allocated, as
1115  /// opposed to inlined into the owning operation.
1116  unsigned isStorageDynamic : 1;
1117  /// The number of operands within the storage.
1118  unsigned numOperands;
1119  /// A pointer to the operand storage.
1120  OpOperand *operandStorage;
1121 };
1122 } // namespace detail
1123 
1124 //===----------------------------------------------------------------------===//
1125 // OpPrintingFlags
1126 //===----------------------------------------------------------------------===//
1127 
1128 /// Set of flags used to control the behavior of the various IR print methods
1129 /// (e.g. Operation::Print).
1131 public:
1132  OpPrintingFlags();
1133  OpPrintingFlags(std::nullopt_t) : OpPrintingFlags() {}
1134 
1135  /// Enables the elision of large elements attributes by printing a lexically
1136  /// valid but otherwise meaningless form instead of the element data. The
1137  /// `largeElementLimit` is used to configure what is considered to be a
1138  /// "large" ElementsAttr by providing an upper limit to the number of
1139  /// elements.
1140  OpPrintingFlags &elideLargeElementsAttrs(int64_t largeElementLimit = 16);
1141 
1142  /// Enables the printing of large element attributes with a hex string. The
1143  /// `largeElementLimit` is used to configure what is considered to be a
1144  /// "large" ElementsAttr by providing an upper limit to the number of
1145  /// elements. Use -1 to disable the hex printing.
1146  OpPrintingFlags &
1147  printLargeElementsAttrWithHex(int64_t largeElementLimit = 100);
1148 
1149  /// Enables the elision of large resources strings by omitting them from the
1150  /// `dialect_resources` section. The `largeResourceLimit` is used to configure
1151  /// what is considered to be a "large" resource by providing an upper limit to
1152  /// the string size.
1153  OpPrintingFlags &elideLargeResourceString(int64_t largeResourceLimit = 64);
1154 
1155  /// Enable or disable printing of debug information (based on `enable`). If
1156  /// 'prettyForm' is set to true, debug information is printed in a more
1157  /// readable 'pretty' form. Note: The IR generated with 'prettyForm' is not
1158  /// parsable.
1159  OpPrintingFlags &enableDebugInfo(bool enable = true, bool prettyForm = false);
1160 
1161  /// Always print operations in the generic form.
1162  OpPrintingFlags &printGenericOpForm(bool enable = true);
1163 
1164  /// Skip printing regions.
1165  OpPrintingFlags &skipRegions(bool skip = true);
1166 
1167  /// Do not verify the operation when using custom operation printers.
1169 
1170  /// Use local scope when printing the operation. This allows for using the
1171  /// printer in a more localized and thread-safe setting, but may not
1172  /// necessarily be identical to what the IR will look like when dumping
1173  /// the full module.
1175 
1176  /// Print users of values as comments.
1178 
1179  /// Return if the given ElementsAttr should be elided.
1180  bool shouldElideElementsAttr(ElementsAttr attr) const;
1181 
1182  /// Return if the given ElementsAttr should be printed as hex string.
1183  bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const;
1184 
1185  /// Return the size limit for printing large ElementsAttr.
1186  std::optional<int64_t> getLargeElementsAttrLimit() const;
1187 
1188  /// Return the size limit for printing large ElementsAttr as hex string.
1189  int64_t getLargeElementsAttrHexLimit() const;
1190 
1191  /// Return the size limit in chars for printing large resources.
1192  std::optional<uint64_t> getLargeResourceStringLimit() const;
1193 
1194  /// Return if debug information should be printed.
1195  bool shouldPrintDebugInfo() const;
1196 
1197  /// Return if debug information should be printed in the pretty form.
1198  bool shouldPrintDebugInfoPrettyForm() const;
1199 
1200  /// Return if operations should be printed in the generic form.
1201  bool shouldPrintGenericOpForm() const;
1202 
1203  /// Return if regions should be skipped.
1204  bool shouldSkipRegions() const;
1205 
1206  /// Return if operation verification should be skipped.
1207  bool shouldAssumeVerified() const;
1208 
1209  /// Return if the printer should use local scope when dumping the IR.
1210  bool shouldUseLocalScope() const;
1211 
1212  /// Return if the printer should print users of values.
1213  bool shouldPrintValueUsers() const;
1214 
1215 private:
1216  /// Elide large elements attributes if the number of elements is larger than
1217  /// the upper limit.
1218  std::optional<int64_t> elementsAttrElementLimit;
1219 
1220  /// Elide printing large resources based on size of string.
1221  std::optional<uint64_t> resourceStringCharLimit;
1222 
1223  /// Print large element attributes with hex strings if the number of elements
1224  /// is larger than the upper limit.
1225  int64_t elementsAttrHexElementLimit = 100;
1226 
1227  /// Print debug information.
1228  bool printDebugInfoFlag : 1;
1229  bool printDebugInfoPrettyFormFlag : 1;
1230 
1231  /// Print operations in the generic form.
1232  bool printGenericOpFormFlag : 1;
1233 
1234  /// Always skip Regions.
1235  bool skipRegionsFlag : 1;
1236 
1237  /// Skip operation verification.
1238  bool assumeVerifiedFlag : 1;
1239 
1240  /// Print operations with numberings local to the current operation.
1241  bool printLocalScope : 1;
1242 
1243  /// Print users of values.
1244  bool printValueUsersFlag : 1;
1245 };
1246 
1247 //===----------------------------------------------------------------------===//
1248 // Operation Equivalency
1249 //===----------------------------------------------------------------------===//
1250 
1251 /// This class provides utilities for computing if two operations are
1252 /// equivalent.
1254  enum Flags {
1255  None = 0,
1256 
1257  // When provided, the location attached to the operation are ignored.
1259 
1260  LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
1261  };
1262 
1263  /// Compute a hash for the given operation.
1264  /// The `hashOperands` and `hashResults` callbacks are expected to return a
1265  /// unique hash_code for a given Value.
1266  static llvm::hash_code computeHash(
1267  Operation *op,
1268  function_ref<llvm::hash_code(Value)> hashOperands =
1269  [](Value v) { return hash_value(v); },
1270  function_ref<llvm::hash_code(Value)> hashResults =
1271  [](Value v) { return hash_value(v); },
1272  Flags flags = Flags::None);
1273 
1274  /// Helper that can be used with `computeHash` above to ignore operation
1275  /// operands/result mapping.
1276  static llvm::hash_code ignoreHashValue(Value) { return llvm::hash_code{}; }
1277  /// Helper that can be used with `computeHash` above to ignore operation
1278  /// operands/result mapping.
1279  static llvm::hash_code directHashValue(Value v) { return hash_value(v); }
1280 
1281  /// Compare two operations (including their regions) and return if they are
1282  /// equivalent.
1283  ///
1284  /// * `checkEquivalent` is a callback to check if two values are equivalent.
1285  /// For two operations to be equivalent, their operands must be the same SSA
1286  /// value or this callback must return `success`.
1287  /// * `markEquivalent` is a callback to inform the caller that the analysis
1288  /// determined that two values are equivalent.
1289  /// * `checkCommutativeEquivalent` is an optional callback to check for
1290  /// equivalence across two ranges for a commutative operation. If not passed
1291  /// in, then equivalence is checked pairwise. This callback is needed to be
1292  /// able to query the optional equivalence classes.
1293  ///
1294  /// Note: Additional information regarding value equivalence can be injected
1295  /// into the analysis via `checkEquivalent`. Typically, callers may want
1296  /// values that were determined to be equivalent as per `markEquivalent` to be
1297  /// reflected in `checkEquivalent`, unless `exactValueMatch` or a different
1298  /// equivalence relationship is desired.
1299  static bool
1300  isEquivalentTo(Operation *lhs, Operation *rhs,
1301  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1302  function_ref<void(Value, Value)> markEquivalent = nullptr,
1303  Flags flags = Flags::None,
1305  checkCommutativeEquivalent = nullptr);
1306 
1307  /// Compare two operations and return if they are equivalent.
1308  static bool isEquivalentTo(Operation *lhs, Operation *rhs, Flags flags);
1309 
1310  /// Compare two regions (including their subregions) and return if they are
1311  /// equivalent. See also `isEquivalentTo` for details.
1312  static bool isRegionEquivalentTo(
1313  Region *lhs, Region *rhs,
1314  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1315  function_ref<void(Value, Value)> markEquivalent,
1318  checkCommutativeEquivalent = nullptr);
1319 
1320  /// Compare two regions and return if they are equivalent.
1321  static bool isRegionEquivalentTo(Region *lhs, Region *rhs,
1323 
1324  /// Helper that can be used with `isEquivalentTo` above to consider ops
1325  /// equivalent even if their operands are not equivalent.
1327  return success();
1328  }
1329  /// Helper that can be used with `isEquivalentTo` above to consider ops
1330  /// equivalent only if their operands are the exact same SSA values.
1332  return success(lhs == rhs);
1333  }
1334 };
1335 
1336 /// Enable Bitmask enums for OperationEquivalence::Flags.
1338 
1339 //===----------------------------------------------------------------------===//
1340 // OperationFingerPrint
1341 //===----------------------------------------------------------------------===//
1342 
1343 /// A unique fingerprint for a specific operation, and all of it's internal
1344 /// operations (if `includeNested` is set).
1346 public:
1347  OperationFingerPrint(Operation *topOp, bool includeNested = true);
1350 
1351  bool operator==(const OperationFingerPrint &other) const {
1352  return hash == other.hash;
1353  }
1354  bool operator!=(const OperationFingerPrint &other) const {
1355  return !(*this == other);
1356  }
1357 
1358 private:
1359  std::array<uint8_t, 20> hash;
1360 };
1361 
1362 } // namespace mlir
1363 
1364 namespace llvm {
1365 template <>
1366 struct DenseMapInfo<mlir::OperationName> {
1368  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1370  }
1374  }
1375  static unsigned getHashValue(mlir::OperationName val) {
1377  }
1379  return lhs == rhs;
1380  }
1381 };
1382 template <>
1383 struct DenseMapInfo<mlir::RegisteredOperationName>
1384  : public DenseMapInfo<mlir::OperationName> {
1386  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1388  }
1392  }
1393 };
1394 
1395 template <>
1396 struct PointerLikeTypeTraits<mlir::OperationName> {
1397  static inline void *getAsVoidPointer(mlir::OperationName I) {
1398  return const_cast<void *>(I.getAsOpaquePointer());
1399  }
1400  static inline mlir::OperationName getFromVoidPointer(void *P) {
1402  }
1403  static constexpr int NumLowBitsAvailable =
1404  PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
1405 };
1406 template <>
1407 struct PointerLikeTypeTraits<mlir::RegisteredOperationName>
1408  : public PointerLikeTypeTraits<mlir::OperationName> {
1411  }
1412 };
1413 
1414 } // namespace llvm
1415 
1416 #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:267
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:293
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
Definition: AsmPrinter.cpp:308
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
Definition: AsmPrinter.cpp:341
OpPrintingFlags & printValueUsers()
Print users of values as comments.
Definition: AsmPrinter.cpp:287
OpPrintingFlags & printLargeElementsAttrWithHex(int64_t largeElementLimit=100)
Enables the printing of large element attributes with a hex string.
Definition: AsmPrinter.cpp:240
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
Definition: AsmPrinter.cpp:346
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
Definition: AsmPrinter.cpp:328
bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const
Return if the given ElementsAttr should be printed as hex string.
Definition: AsmPrinter.cpp:300
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
Definition: AsmPrinter.cpp:349
int64_t getLargeElementsAttrHexLimit() const
Return the size limit for printing large ElementsAttr as hex string.
Definition: AsmPrinter.cpp:313
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
Definition: AsmPrinter.cpp:333
OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
Definition: AsmPrinter.cpp:246
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
Definition: AsmPrinter.cpp:323
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
Definition: AsmPrinter.cpp:234
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
Definition: AsmPrinter.cpp:253
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:338
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
Definition: AsmPrinter.cpp:261
OpPrintingFlags & assumeVerified()
Do not verify the operation when using custom operation printers.
Definition: AsmPrinter.cpp:273
OpPrintingFlags(std::nullopt_t)
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
Definition: AsmPrinter.cpp:318
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
Definition: AsmPrinter.cpp:281
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
Definition: AsmPrinter.cpp:267
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:381
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:21
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)
Attribute propertiesAttr
This Attribute is used to opaquely construct the properties of the operation.
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.