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