MLIR  21.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  NamedAttrList(std::nullopt_t none) : NamedAttrList() {}
807  NamedAttrList(DictionaryAttr attributes);
809 
810  template <typename Container>
811  NamedAttrList(const Container &vec)
813 
814  bool operator!=(const NamedAttrList &other) const {
815  return !(*this == other);
816  }
817  bool operator==(const NamedAttrList &other) const {
818  return attrs == other.attrs;
819  }
820 
821  /// Add an attribute with the specified name.
822  void append(StringRef name, Attribute attr) {
823  append(NamedAttribute(name, attr));
824  }
825 
826  /// Add an attribute with the specified name.
827  void append(StringAttr name, Attribute attr) {
828  append(NamedAttribute(name, attr));
829  }
830 
831  /// Append the given named attribute.
832  void append(NamedAttribute attr) { push_back(attr); }
833 
834  /// Add an array of named attributes.
835  template <typename RangeT>
836  void append(RangeT &&newAttributes) {
837  append(std::begin(newAttributes), std::end(newAttributes));
838  }
839 
840  /// Add a range of named attributes.
841  template <typename IteratorT,
842  typename = std::enable_if_t<std::is_convertible<
843  typename std::iterator_traits<IteratorT>::iterator_category,
844  std::input_iterator_tag>::value>>
845  void append(IteratorT inStart, IteratorT inEnd) {
846  // TODO: expand to handle case where values appended are in order & after
847  // end of current list.
848  dictionarySorted.setPointerAndInt(nullptr, false);
849  attrs.append(inStart, inEnd);
850  }
851 
852  /// Replaces the attributes with new list of attributes.
853  void assign(const_iterator inStart, const_iterator inEnd);
854 
855  /// Replaces the attributes with new list of attributes.
857  assign(range.begin(), range.end());
858  }
859 
860  void clear() {
861  attrs.clear();
862  dictionarySorted.setPointerAndInt(nullptr, false);
863  }
864 
865  bool empty() const { return attrs.empty(); }
866 
867  void reserve(size_type N) { attrs.reserve(N); }
868 
869  /// Add an attribute with the specified name.
870  void push_back(NamedAttribute newAttribute);
871 
872  /// Pop last element from list.
873  void pop_back() { attrs.pop_back(); }
874 
875  /// Returns an entry with a duplicate name the list, if it exists, else
876  /// returns std::nullopt.
877  std::optional<NamedAttribute> findDuplicate() const;
878 
879  /// Return a dictionary attribute for the underlying dictionary. This will
880  /// return an empty dictionary attribute if empty rather than null.
881  DictionaryAttr getDictionary(MLIRContext *context) const;
882 
883  /// Return all of the attributes on this operation.
885 
886  /// Return the specified attribute if present, null otherwise.
887  Attribute get(StringAttr name) const;
888  Attribute get(StringRef name) const;
889 
890  /// Return the specified named attribute if present, std::nullopt otherwise.
891  std::optional<NamedAttribute> getNamed(StringRef name) const;
892  std::optional<NamedAttribute> getNamed(StringAttr name) const;
893 
894  /// If the an attribute exists with the specified name, change it to the new
895  /// value. Otherwise, add a new attribute with the specified name/value.
896  /// Returns the previous attribute value of `name`, or null if no
897  /// attribute previously existed with `name`.
898  Attribute set(StringAttr name, Attribute value);
899  Attribute set(StringRef name, Attribute value);
900 
901  /// Erase the attribute with the given name from the list. Return the
902  /// attribute that was erased, or nullptr if there was no attribute with such
903  /// name.
904  Attribute erase(StringAttr name);
905  Attribute erase(StringRef name);
906 
907  iterator begin() { return attrs.begin(); }
908  iterator end() { return attrs.end(); }
909  const_iterator begin() const { return attrs.begin(); }
910  const_iterator end() const { return attrs.end(); }
911 
913  operator ArrayRef<NamedAttribute>() const;
914 
915 private:
916  /// Return whether the attributes are sorted.
917  bool isSorted() const { return dictionarySorted.getInt(); }
918 
919  /// Erase the attribute at the given iterator position.
920  Attribute eraseImpl(SmallVectorImpl<NamedAttribute>::iterator it);
921 
922  /// Lookup an attribute in the list.
923  template <typename AttrListT, typename NameT>
924  static auto findAttr(AttrListT &attrs, NameT name) {
925  return attrs.isSorted()
926  ? impl::findAttrSorted(attrs.begin(), attrs.end(), name)
927  : impl::findAttrUnsorted(attrs.begin(), attrs.end(), name);
928  }
929 
930  // These are marked mutable as they may be modified (e.g., sorted)
931  mutable SmallVector<NamedAttribute, 4> attrs;
932  // Pair with cached DictionaryAttr and status of whether attrs is sorted.
933  // Note: just because sorted does not mean a DictionaryAttr has been created
934  // but the case where there is a DictionaryAttr but attrs isn't sorted should
935  // not occur.
936  mutable llvm::PointerIntPair<Attribute, 1, bool> dictionarySorted;
937 };
938 
939 //===----------------------------------------------------------------------===//
940 // OperationState
941 //===----------------------------------------------------------------------===//
942 
943 /// This represents an operation in an abstracted form, suitable for use with
944 /// the builder APIs. This object is a large and heavy weight object meant to
945 /// be used as a temporary object on the stack. It is generally unwise to put
946 /// this in a collection.
951  /// Types of the results of this operation.
954  /// Successors of this operation and their respective operands.
956  /// Regions that the op will hold.
958 
959  /// This Attribute is used to opaquely construct the properties of the
960  /// operation. If we're creating an unregistered operation, the Attribute is
961  /// used as-is as the Properties storage of the operation. Otherwise, the
962  /// operation properties are constructed opaquely using its
963  /// `setPropertiesFromAttr` hook. Note that `getOrAddProperties` is the
964  /// preferred method to construct properties from C++.
966 
967 private:
968  OpaqueProperties properties = nullptr;
969  TypeID propertiesId;
970  llvm::function_ref<void(OpaqueProperties)> propertiesDeleter;
972  propertiesSetter;
973  friend class Operation;
974 
975 public:
976  OperationState(Location location, StringRef name);
978 
981  BlockRange successors = {},
982  MutableArrayRef<std::unique_ptr<Region>> regions = {});
983  OperationState(Location location, StringRef name, ValueRange operands,
984  TypeRange types, ArrayRef<NamedAttribute> attributes = {},
985  BlockRange successors = {},
986  MutableArrayRef<std::unique_ptr<Region>> regions = {});
987  OperationState(OperationState &&other) = default;
988  OperationState(const OperationState &other) = default;
990  OperationState &operator=(const OperationState &other) = default;
991  ~OperationState();
992 
993  /// Get (or create) a properties of the provided type to be set on the
994  /// operation on creation.
995  template <typename T>
997  if (!properties) {
998  T *p = new T{};
999  properties = p;
1000 #if defined(__clang__)
1001 #if __has_warning("-Wdangling-assignment-gsl")
1002 #pragma clang diagnostic push
1003 // https://github.com/llvm/llvm-project/issues/126600
1004 #pragma clang diagnostic ignored "-Wdangling-assignment-gsl"
1005 #endif
1006 #endif
1007  propertiesDeleter = [](OpaqueProperties prop) {
1008  delete prop.as<const T *>();
1009  };
1010  propertiesSetter = [](OpaqueProperties newProp,
1011  const OpaqueProperties prop) {
1012  *newProp.as<T *>() = *prop.as<const T *>();
1013  };
1014 #if defined(__clang__)
1015 #if __has_warning("-Wdangling-assignment-gsl")
1016 #pragma clang diagnostic pop
1017 #endif
1018 #endif
1019  propertiesId = TypeID::get<T>();
1020  }
1021  assert(propertiesId == TypeID::get<T>() && "Inconsistent properties");
1022  return *properties.as<T *>();
1023  }
1024  OpaqueProperties getRawProperties() { return properties; }
1025 
1026  // Set the properties defined on this OpState on the given operation,
1027  // optionally emit diagnostics on error through the provided diagnostic.
1028  LogicalResult
1031 
1032  // Make `newProperties` the source of the properties that will be copied into
1033  // the operation. The memory referenced by `newProperties` must remain live
1034  // until after the `Operation` is created, at which time it may be
1035  // deallocated. Calls to `getOrAddProperties<>() will return references to
1036  // this memory.
1037  template <typename T>
1038  void useProperties(T &newProperties) {
1039  assert(!properties &&
1040  "Can't provide a properties struct when one has been allocated");
1041  properties = &newProperties;
1042 #if defined(__clang__)
1043 #if __has_warning("-Wdangling-assignment-gsl")
1044 #pragma clang diagnostic push
1045 // https://github.com/llvm/llvm-project/issues/126600
1046 #pragma clang diagnostic ignored "-Wdangling-assignment-gsl"
1047 #endif
1048 #endif
1049  propertiesDeleter = [](OpaqueProperties) {};
1050  propertiesSetter = [](OpaqueProperties newProp,
1051  const OpaqueProperties prop) {
1052  *newProp.as<T *>() = *prop.as<const T *>();
1053  };
1054 #if defined(__clang__)
1055 #if __has_warning("-Wdangling-assignment-gsl")
1056 #pragma clang diagnostic pop
1057 #endif
1058 #endif
1059  propertiesId = TypeID::get<T>();
1060  }
1061 
1062  void addOperands(ValueRange newOperands);
1063 
1064  void addTypes(ArrayRef<Type> newTypes) {
1065  types.append(newTypes.begin(), newTypes.end());
1066  }
1067  template <typename RangeT>
1068  std::enable_if_t<!std::is_convertible<RangeT, ArrayRef<Type>>::value>
1069  addTypes(RangeT &&newTypes) {
1070  types.append(newTypes.begin(), newTypes.end());
1071  }
1072 
1073  /// Add an attribute with the specified name.
1074  void addAttribute(StringRef name, Attribute attr) {
1076  }
1077 
1078  /// Add an attribute with the specified name. `name` and `attr` must not be
1079  /// null.
1080  void addAttribute(StringAttr name, Attribute attr) {
1081  assert(name && "attribute name cannot be null");
1082  assert(attr && "attribute cannot be null");
1083  attributes.append(name, attr);
1084  }
1085 
1086  /// Add an array of named attributes.
1088  attributes.append(newAttributes);
1089  }
1090 
1091  /// Adds a successor to the operation sate. `successor` must not be null.
1092  void addSuccessors(Block *successor) {
1093  assert(successor && "successor cannot be null");
1094  successors.push_back(successor);
1095  }
1096  void addSuccessors(BlockRange newSuccessors);
1097 
1098  /// Create a region that should be attached to the operation. These regions
1099  /// can be filled in immediately without waiting for Operation to be
1100  /// created. When it is, the region bodies will be transferred.
1101  Region *addRegion();
1102 
1103  /// Take a region that should be attached to the Operation. The body of the
1104  /// region will be transferred when the Operation is constructed. If the
1105  /// region is null, a new empty region will be attached to the Operation.
1106  void addRegion(std::unique_ptr<Region> &&region);
1107 
1108  /// Take ownership of a set of regions that should be attached to the
1109  /// Operation.
1110  void addRegions(MutableArrayRef<std::unique_ptr<Region>> regions);
1111 
1112  /// Get the context held by this operation state.
1113  MLIRContext *getContext() const { return location->getContext(); }
1114 };
1115 
1116 //===----------------------------------------------------------------------===//
1117 // OperandStorage
1118 //===----------------------------------------------------------------------===//
1119 
1120 namespace detail {
1121 /// This class handles the management of operation operands. Operands are
1122 /// stored either in a trailing array, or a dynamically resizable vector.
1123 class alignas(8) OperandStorage {
1124 public:
1125  OperandStorage(Operation *owner, OpOperand *trailingOperands,
1126  ValueRange values);
1127  ~OperandStorage();
1128 
1129  /// Replace the operands contained in the storage with the ones provided in
1130  /// 'values'.
1131  void setOperands(Operation *owner, ValueRange values);
1132 
1133  /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
1134  /// with the ones provided in 'operands'. 'operands' may be smaller or larger
1135  /// than the range pointed to by 'start'+'length'.
1136  void setOperands(Operation *owner, unsigned start, unsigned length,
1137  ValueRange operands);
1138 
1139  /// Erase the operands held by the storage within the given range.
1140  void eraseOperands(unsigned start, unsigned length);
1141 
1142  /// Erase the operands held by the storage that have their corresponding bit
1143  /// set in `eraseIndices`.
1144  void eraseOperands(const BitVector &eraseIndices);
1145 
1146  /// Get the operation operands held by the storage.
1147  MutableArrayRef<OpOperand> getOperands() { return {operandStorage, size()}; }
1148 
1149  /// Return the number of operands held in the storage.
1150  unsigned size() { return numOperands; }
1151 
1152 private:
1153  /// Resize the storage to the given size. Returns the array containing the new
1154  /// operands.
1155  MutableArrayRef<OpOperand> resize(Operation *owner, unsigned newSize);
1156 
1157  /// The total capacity number of operands that the storage can hold.
1158  unsigned capacity : 31;
1159  /// A flag indicating if the operand storage was dynamically allocated, as
1160  /// opposed to inlined into the owning operation.
1161  unsigned isStorageDynamic : 1;
1162  /// The number of operands within the storage.
1163  unsigned numOperands;
1164  /// A pointer to the operand storage.
1165  OpOperand *operandStorage;
1166 };
1167 } // namespace detail
1168 
1169 //===----------------------------------------------------------------------===//
1170 // OpPrintingFlags
1171 //===----------------------------------------------------------------------===//
1172 
1173 /// Set of flags used to control the behavior of the various IR print methods
1174 /// (e.g. Operation::Print).
1176 public:
1177  OpPrintingFlags();
1178  OpPrintingFlags(std::nullopt_t) : OpPrintingFlags() {}
1179 
1180  /// Enables the elision of large elements attributes by printing a lexically
1181  /// valid but otherwise meaningless form instead of the element data. The
1182  /// `largeElementLimit` is used to configure what is considered to be a
1183  /// "large" ElementsAttr by providing an upper limit to the number of
1184  /// elements.
1185  OpPrintingFlags &elideLargeElementsAttrs(int64_t largeElementLimit = 16);
1186 
1187  /// Enables the printing of large element attributes with a hex string. The
1188  /// `largeElementLimit` is used to configure what is considered to be a
1189  /// "large" ElementsAttr by providing an upper limit to the number of
1190  /// elements. Use -1 to disable the hex printing.
1191  OpPrintingFlags &
1192  printLargeElementsAttrWithHex(int64_t largeElementLimit = 100);
1193 
1194  /// Enables the elision of large resources strings by omitting them from the
1195  /// `dialect_resources` section. The `largeResourceLimit` is used to configure
1196  /// what is considered to be a "large" resource by providing an upper limit to
1197  /// the string size.
1198  OpPrintingFlags &elideLargeResourceString(int64_t largeResourceLimit = 64);
1199 
1200  /// Enable or disable printing of debug information (based on `enable`). If
1201  /// 'prettyForm' is set to true, debug information is printed in a more
1202  /// readable 'pretty' form. Note: The IR generated with 'prettyForm' is not
1203  /// parsable.
1204  OpPrintingFlags &enableDebugInfo(bool enable = true, bool prettyForm = false);
1205 
1206  /// Always print operations in the generic form.
1207  OpPrintingFlags &printGenericOpForm(bool enable = true);
1208 
1209  /// Skip printing regions.
1210  OpPrintingFlags &skipRegions(bool skip = true);
1211 
1212  /// Do not verify the operation when using custom operation printers.
1213  OpPrintingFlags &assumeVerified(bool enable = true);
1214 
1215  /// Use local scope when printing the operation. This allows for using the
1216  /// printer in a more localized and thread-safe setting, but may not
1217  /// necessarily be identical to what the IR will look like when dumping
1218  /// the full module.
1219  OpPrintingFlags &useLocalScope(bool enable = true);
1220 
1221  /// Print users of values as comments.
1222  OpPrintingFlags &printValueUsers(bool enable = true);
1223 
1224  /// Print unique SSA ID numbers for values, block arguments and naming
1225  /// conflicts across all regions
1226  OpPrintingFlags &printUniqueSSAIDs(bool enable = true);
1227 
1228  /// Print SSA IDs using their NameLoc, if provided, as prefix.
1229  OpPrintingFlags &printNameLocAsPrefix(bool enable = true);
1230 
1231  /// Return if the given ElementsAttr should be elided.
1232  bool shouldElideElementsAttr(ElementsAttr attr) const;
1233 
1234  /// Return if the given ElementsAttr should be printed as hex string.
1235  bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const;
1236 
1237  /// Return the size limit for printing large ElementsAttr.
1238  std::optional<int64_t> getLargeElementsAttrLimit() const;
1239 
1240  /// Return the size limit for printing large ElementsAttr as hex string.
1241  int64_t getLargeElementsAttrHexLimit() const;
1242 
1243  /// Return the size limit in chars for printing large resources.
1244  std::optional<uint64_t> getLargeResourceStringLimit() const;
1245 
1246  /// Return if debug information should be printed.
1247  bool shouldPrintDebugInfo() const;
1248 
1249  /// Return if debug information should be printed in the pretty form.
1250  bool shouldPrintDebugInfoPrettyForm() const;
1251 
1252  /// Return if operations should be printed in the generic form.
1253  bool shouldPrintGenericOpForm() const;
1254 
1255  /// Return if regions should be skipped.
1256  bool shouldSkipRegions() const;
1257 
1258  /// Return if operation verification should be skipped.
1259  bool shouldAssumeVerified() const;
1260 
1261  /// Return if the printer should use local scope when dumping the IR.
1262  bool shouldUseLocalScope() const;
1263 
1264  /// Return if the printer should print users of values.
1265  bool shouldPrintValueUsers() const;
1266 
1267  /// Return if printer should use unique SSA IDs.
1268  bool shouldPrintUniqueSSAIDs() const;
1269 
1270  /// Return if the printer should use NameLocs as prefixes when printing SSA
1271  /// IDs
1272  bool shouldUseNameLocAsPrefix() const;
1273 
1274 private:
1275  /// Elide large elements attributes if the number of elements is larger than
1276  /// the upper limit.
1277  std::optional<int64_t> elementsAttrElementLimit;
1278 
1279  /// Elide printing large resources based on size of string.
1280  std::optional<uint64_t> resourceStringCharLimit;
1281 
1282  /// Print large element attributes with hex strings if the number of elements
1283  /// is larger than the upper limit.
1284  int64_t elementsAttrHexElementLimit = 100;
1285 
1286  /// Print debug information.
1287  bool printDebugInfoFlag : 1;
1288  bool printDebugInfoPrettyFormFlag : 1;
1289 
1290  /// Print operations in the generic form.
1291  bool printGenericOpFormFlag : 1;
1292 
1293  /// Always skip Regions.
1294  bool skipRegionsFlag : 1;
1295 
1296  /// Skip operation verification.
1297  bool assumeVerifiedFlag : 1;
1298 
1299  /// Print operations with numberings local to the current operation.
1300  bool printLocalScope : 1;
1301 
1302  /// Print users of values.
1303  bool printValueUsersFlag : 1;
1304 
1305  /// Print unique SSA IDs for values, block arguments and naming conflicts
1306  bool printUniqueSSAIDsFlag : 1;
1307 
1308  /// Print SSA IDs using NameLocs as prefixes
1309  bool useNameLocAsPrefix : 1;
1310 };
1311 
1312 //===----------------------------------------------------------------------===//
1313 // Operation Equivalency
1314 //===----------------------------------------------------------------------===//
1315 
1316 /// This class provides utilities for computing if two operations are
1317 /// equivalent.
1319  enum Flags {
1320  None = 0,
1321 
1322  // When provided, the location attached to the operation are ignored.
1324 
1325  LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
1326  };
1327 
1328  /// Compute a hash for the given operation.
1329  /// The `hashOperands` and `hashResults` callbacks are expected to return a
1330  /// unique hash_code for a given Value.
1331  static llvm::hash_code computeHash(
1332  Operation *op,
1333  function_ref<llvm::hash_code(Value)> hashOperands =
1334  [](Value v) { return hash_value(v); },
1335  function_ref<llvm::hash_code(Value)> hashResults =
1336  [](Value v) { return hash_value(v); },
1337  Flags flags = Flags::None);
1338 
1339  /// Helper that can be used with `computeHash` above to ignore operation
1340  /// operands/result mapping.
1341  static llvm::hash_code ignoreHashValue(Value) { return llvm::hash_code{}; }
1342  /// Helper that can be used with `computeHash` above to ignore operation
1343  /// operands/result mapping.
1344  static llvm::hash_code directHashValue(Value v) { return hash_value(v); }
1345 
1346  /// Compare two operations (including their regions) and return if they are
1347  /// equivalent.
1348  ///
1349  /// * `checkEquivalent` is a callback to check if two values are equivalent.
1350  /// For two operations to be equivalent, their operands must be the same SSA
1351  /// value or this callback must return `success`.
1352  /// * `markEquivalent` is a callback to inform the caller that the analysis
1353  /// determined that two values are equivalent.
1354  /// * `checkCommutativeEquivalent` is an optional callback to check for
1355  /// equivalence across two ranges for a commutative operation. If not passed
1356  /// in, then equivalence is checked pairwise. This callback is needed to be
1357  /// able to query the optional equivalence classes.
1358  ///
1359  /// Note: Additional information regarding value equivalence can be injected
1360  /// into the analysis via `checkEquivalent`. Typically, callers may want
1361  /// values that were determined to be equivalent as per `markEquivalent` to be
1362  /// reflected in `checkEquivalent`, unless `exactValueMatch` or a different
1363  /// equivalence relationship is desired.
1364  static bool
1365  isEquivalentTo(Operation *lhs, Operation *rhs,
1366  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1367  function_ref<void(Value, Value)> markEquivalent = nullptr,
1368  Flags flags = Flags::None,
1369  function_ref<LogicalResult(ValueRange, ValueRange)>
1370  checkCommutativeEquivalent = nullptr);
1371 
1372  /// Compare two operations and return if they are equivalent.
1373  static bool isEquivalentTo(Operation *lhs, Operation *rhs, Flags flags);
1374 
1375  /// Compare two regions (including their subregions) and return if they are
1376  /// equivalent. See also `isEquivalentTo` for details.
1377  static bool isRegionEquivalentTo(
1378  Region *lhs, Region *rhs,
1379  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1380  function_ref<void(Value, Value)> markEquivalent,
1382  function_ref<LogicalResult(ValueRange, ValueRange)>
1383  checkCommutativeEquivalent = nullptr);
1384 
1385  /// Compare two regions and return if they are equivalent.
1386  static bool isRegionEquivalentTo(Region *lhs, Region *rhs,
1388 
1389  /// Helper that can be used with `isEquivalentTo` above to consider ops
1390  /// equivalent even if their operands are not equivalent.
1391  static LogicalResult ignoreValueEquivalence(Value lhs, Value rhs) {
1392  return success();
1393  }
1394  /// Helper that can be used with `isEquivalentTo` above to consider ops
1395  /// equivalent only if their operands are the exact same SSA values.
1396  static LogicalResult exactValueMatch(Value lhs, Value rhs) {
1397  return success(lhs == rhs);
1398  }
1399 };
1400 
1401 /// Enable Bitmask enums for OperationEquivalence::Flags.
1403 
1404 //===----------------------------------------------------------------------===//
1405 // OperationFingerPrint
1406 //===----------------------------------------------------------------------===//
1407 
1408 /// A unique fingerprint for a specific operation, and all of it's internal
1409 /// operations (if `includeNested` is set).
1411 public:
1412  OperationFingerPrint(Operation *topOp, bool includeNested = true);
1415 
1416  bool operator==(const OperationFingerPrint &other) const {
1417  return hash == other.hash;
1418  }
1419  bool operator!=(const OperationFingerPrint &other) const {
1420  return !(*this == other);
1421  }
1422 
1423 private:
1424  std::array<uint8_t, 20> hash;
1425 };
1426 
1427 } // namespace mlir
1428 
1429 namespace llvm {
1430 template <>
1431 struct DenseMapInfo<mlir::OperationName> {
1433  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1435  }
1439  }
1440  static unsigned getHashValue(mlir::OperationName val) {
1442  }
1444  return lhs == rhs;
1445  }
1446 };
1447 template <>
1448 struct DenseMapInfo<mlir::RegisteredOperationName>
1449  : public DenseMapInfo<mlir::OperationName> {
1451  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1453  }
1457  }
1458 };
1459 
1460 template <>
1461 struct PointerLikeTypeTraits<mlir::OperationName> {
1462  static inline void *getAsVoidPointer(mlir::OperationName I) {
1463  return const_cast<void *>(I.getAsOpaquePointer());
1464  }
1465  static inline mlir::OperationName getFromVoidPointer(void *P) {
1467  }
1468  static constexpr int NumLowBitsAvailable =
1469  PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
1470 };
1471 template <>
1472 struct PointerLikeTypeTraits<mlir::RegisteredOperationName>
1473  : public PointerLikeTypeTraits<mlir::OperationName> {
1476  }
1477 };
1478 
1479 } // namespace llvm
1480 
1481 #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:66
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.
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)
NamedAttrList(std::nullopt_t none)
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:243
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:316
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
Definition: AsmPrinter.cpp:336
bool shouldUseNameLocAsPrefix() const
Return if the printer should use NameLocs as prefixes when printing SSA IDs.
Definition: AsmPrinter.cpp:387
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
Definition: AsmPrinter.cpp:369
OpPrintingFlags & printLargeElementsAttrWithHex(int64_t largeElementLimit=100)
Enables the printing of large element attributes with a hex string.
Definition: AsmPrinter.cpp:256
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
Definition: AsmPrinter.cpp:374
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
Definition: AsmPrinter.cpp:356
bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const
Return if the given ElementsAttr should be printed as hex string.
Definition: AsmPrinter.cpp:323
bool shouldPrintUniqueSSAIDs() const
Return if printer should use unique SSA IDs.
Definition: AsmPrinter.cpp:382
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
Definition: AsmPrinter.cpp:377
int64_t getLargeElementsAttrHexLimit() const
Return the size limit for printing large ElementsAttr as hex string.
Definition: AsmPrinter.cpp:341
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
Definition: AsmPrinter.cpp:361
OpPrintingFlags & elideLargeResourceString(int64_t largeResourceLimit=64)
Enables the elision of large resources strings by omitting them from the dialect_resources section.
Definition: AsmPrinter.cpp:262
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
Definition: AsmPrinter.cpp:351
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
Definition: AsmPrinter.cpp:250
OpPrintingFlags & printNameLocAsPrefix(bool enable=true)
Print SSA IDs using their NameLoc, if provided, as prefix.
Definition: AsmPrinter.cpp:330
OpPrintingFlags & printValueUsers(bool enable=true)
Print users of values as comments.
Definition: AsmPrinter.cpp:303
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
Definition: AsmPrinter.cpp:269
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
Definition: AsmPrinter.cpp:218
bool shouldSkipRegions() const
Return if regions should be skipped.
Definition: AsmPrinter.cpp:366
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
Definition: AsmPrinter.cpp:277
OpPrintingFlags(std::nullopt_t)
OpPrintingFlags & useLocalScope(bool enable=true)
Use local scope when printing the operation.
Definition: AsmPrinter.cpp:297
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
Definition: AsmPrinter.cpp:346
OpPrintingFlags & assumeVerified(bool enable=true)
Do not verify the operation when using custom operation printers.
Definition: AsmPrinter.cpp:289
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
Definition: AsmPrinter.cpp:283
OpPrintingFlags & printUniqueSSAIDs(bool enable=true)
Print unique SSA ID numbers for values, block arguments and naming conflicts across all regions.
Definition: AsmPrinter.cpp:310
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:63
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:61
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:172
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:166
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:20
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:77
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)
Adds a successor to the operation sate. successor must not be null.
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)
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=(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.