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