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
253  /// in the IR. In this case, return success.
254  /// 3. They can return a list of existing values that can be used instead
255  /// of
256  /// the operation. In this case, fill in the results list and return
257  /// success. The caller will remove the operation and use those results
258  /// instead.
259  ///
260  /// This allows expression of some simple in-place canonicalizations (e.g.
261  /// "x+0 -> x", "min(x,y,x,z) -> min(x,y,z)", "x+y-x -> y", etc), as well as
262  /// generalized constant folding.
263  LogicalResult foldHook(Operation *op, ArrayRef<Attribute> operands,
264  SmallVectorImpl<OpFoldResult> &results) const {
265  return getImpl()->foldHook(op, operands, results);
266  }
267 
268  /// This hook returns any canonicalization pattern rewrites that the
269  /// operation supports, for use by the canonicalization pass.
271  MLIRContext *context) const {
272  return getImpl()->getCanonicalizationPatterns(results, context);
273  }
274 
275  /// Returns true if the operation was registered with a particular trait, e.g.
276  /// hasTrait<OperandsAreSignlessIntegerLike>(). Returns false if the operation
277  /// is unregistered.
278  template <template <typename T> class Trait>
279  bool hasTrait() const {
280  return hasTrait(TypeID::get<Trait>());
281  }
282  bool hasTrait(TypeID traitID) const { return getImpl()->hasTrait(traitID); }
283 
284  /// Returns true if the operation *might* have the provided trait. This
285  /// means that either the operation is unregistered, or it was registered with
286  /// the provide trait.
287  template <template <typename T> class Trait>
288  bool mightHaveTrait() const {
289  return mightHaveTrait(TypeID::get<Trait>());
290  }
291  bool mightHaveTrait(TypeID traitID) const {
292  return !isRegistered() || getImpl()->hasTrait(traitID);
293  }
294 
295  /// Return the static hook for parsing this operation assembly.
297  return getImpl()->getParseAssemblyFn();
298  }
299 
300  /// This hook implements the method to populate defaults attributes that are
301  /// unset.
302  void populateDefaultAttrs(NamedAttrList &attrs) const {
303  getImpl()->populateDefaultAttrs(*this, attrs);
304  }
305 
306  /// This hook implements the AsmPrinter for this operation.
308  StringRef defaultDialect) const {
309  return getImpl()->printAssembly(op, p, defaultDialect);
310  }
311 
312  /// These hooks implement the verifiers for this operation. It should emits
313  /// an error message and returns failure if a problem is detected, or
314  /// returns success if everything is ok.
315  LogicalResult verifyInvariants(Operation *op) const {
316  return getImpl()->verifyInvariants(op);
317  }
318  LogicalResult verifyRegionInvariants(Operation *op) const {
319  return getImpl()->verifyRegionInvariants(op);
320  }
321 
322  /// Return the list of cached attribute names registered to this operation.
323  /// The order of attributes cached here is unique to each type of operation,
324  /// and the interpretation of this attribute list should generally be driven
325  /// by the respective operation. In many cases, this caching removes the
326  /// need to use the raw string name of a known attribute.
327  ///
328  /// For example the ODS generator, with an op defining the following
329  /// attributes:
330  ///
331  /// let arguments = (ins I32Attr:$attr1, I32Attr:$attr2);
332  ///
333  /// ... may produce an order here of ["attr1", "attr2"]. This allows for the
334  /// ODS generator to directly access the cached name for a known attribute,
335  /// greatly simplifying the cost and complexity of attribute usage produced
336  /// by the generator.
337  ///
339  return getImpl()->getAttributeNames();
340  }
341 
342  /// Returns an instance of the concept object for the given interface if it
343  /// was registered to this operation, null otherwise. This should not be used
344  /// directly.
345  template <typename T>
346  typename T::Concept *getInterface() const {
347  return getImpl()->getInterfaceMap().lookup<T>();
348  }
349 
350  /// Attach the given models as implementations of the corresponding
351  /// interfaces for the concrete operation.
352  template <typename... Models>
354  // Handle the case where the models resolve a promised interface.
356  *getDialect(), getTypeID(), Models::Interface::getInterfaceID()),
357  ...);
358 
359  getImpl()->getInterfaceMap().insertModels<Models...>();
360  }
361 
362  /// Returns true if `InterfaceT` has been promised by the dialect or
363  /// implemented.
364  template <typename InterfaceT>
367  getDialect(), getTypeID(), InterfaceT::getInterfaceID()) ||
368  hasInterface<InterfaceT>();
369  }
370 
371  /// Returns true if this operation has the given interface registered to it.
372  template <typename T>
373  bool hasInterface() const {
374  return hasInterface(TypeID::get<T>());
375  }
376  bool hasInterface(TypeID interfaceID) const {
377  return getImpl()->getInterfaceMap().contains(interfaceID);
378  }
379 
380  /// Returns true if the operation *might* have the provided interface. This
381  /// means that either the operation is unregistered, or it was registered with
382  /// the provide interface.
383  template <typename T>
384  bool mightHaveInterface() const {
385  return mightHaveInterface(TypeID::get<T>());
386  }
387  bool mightHaveInterface(TypeID interfaceID) const {
388  return !isRegistered() || hasInterface(interfaceID);
389  }
390 
391  /// Lookup an inherent attribute by name, this method isn't recommended
392  /// and may be removed in the future.
393  std::optional<Attribute> getInherentAttr(Operation *op,
394  StringRef name) const {
395  return getImpl()->getInherentAttr(op, name);
396  }
397 
398  void setInherentAttr(Operation *op, StringAttr name, Attribute value) const {
399  return getImpl()->setInherentAttr(op, name, value);
400  }
401 
403  return getImpl()->populateInherentAttrs(op, attrs);
404  }
405  /// This method exists for backward compatibility purpose when using
406  /// properties to store inherent attributes, it enables validating the
407  /// attributes when parsed from the older generic syntax pre-Properties.
408  LogicalResult
411  return getImpl()->verifyInherentAttrs(*this, attributes, emitError);
412  }
413  /// This hooks return the number of bytes to allocate for the op properties.
414  int getOpPropertyByteSize() const {
415  return getImpl()->getOpPropertyByteSize();
416  }
417 
418  /// This hooks destroy the op properties.
419  void destroyOpProperties(OpaqueProperties properties) const {
420  getImpl()->deleteProperties(properties);
421  }
422 
423  /// Initialize the op properties.
425  getImpl()->initProperties(*this, storage, init);
426  }
427 
428  /// Set the default values on the ODS attribute in the properties.
430  getImpl()->populateDefaultProperties(*this, properties);
431  }
432 
433  /// Return the op properties converted to an Attribute.
435  return getImpl()->getPropertiesAsAttr(op);
436  }
437 
438  /// Define the op properties from the provided Attribute.
440  OperationName opName, OpaqueProperties properties, Attribute attr,
442  return getImpl()->setPropertiesFromAttr(opName, properties, attr,
443  emitError);
444  }
445 
447  return getImpl()->copyProperties(lhs, rhs);
448  }
449 
451  return getImpl()->compareProperties(lhs, rhs);
452  }
453 
454  llvm::hash_code hashOpProperties(OpaqueProperties properties) const {
455  return getImpl()->hashProperties(properties);
456  }
457 
458  /// Return the dialect this operation is registered to if the dialect is
459  /// loaded in the context, or nullptr if the dialect isn't loaded.
460  Dialect *getDialect() const {
461  return isRegistered() ? getImpl()->getDialect()
462  : getImpl()->getName().getReferencedDialect();
463  }
464 
465  /// Return the name of the dialect this operation is registered to.
466  StringRef getDialectNamespace() const;
467 
468  /// Return the operation name with dialect name stripped, if it has one.
469  StringRef stripDialect() const { return getStringRef().split('.').second; }
470 
471  /// Return the context this operation is associated with.
472  MLIRContext *getContext() { return getIdentifier().getContext(); }
473 
474  /// Return the name of this operation. This always succeeds.
475  StringRef getStringRef() const { return getIdentifier(); }
476 
477  /// Return the name of this operation as a StringAttr.
478  StringAttr getIdentifier() const { return getImpl()->getName(); }
479 
480  void print(raw_ostream &os) const;
481  void dump() const;
482 
483  /// Represent the operation name as an opaque pointer. (Used to support
484  /// PointerLikeTypeTraits).
485  void *getAsOpaquePointer() const { return const_cast<Impl *>(impl); }
486  static OperationName getFromOpaquePointer(const void *pointer) {
487  return OperationName(
488  const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
489  }
490 
491  bool operator==(const OperationName &rhs) const { return impl == rhs.impl; }
492  bool operator!=(const OperationName &rhs) const { return !(*this == rhs); }
493 
494 protected:
496  Impl *getImpl() const { return impl; }
497  void setImpl(Impl *rhs) { impl = rhs; }
498 
499 private:
500  /// The internal implementation of the operation name.
501  Impl *impl = nullptr;
502 
503  /// Allow access to the Impl struct.
504  friend MLIRContextImpl;
507 };
508 
509 inline raw_ostream &operator<<(raw_ostream &os, OperationName info) {
510  info.print(os);
511  return os;
512 }
513 
514 // Make operation names hashable.
515 inline llvm::hash_code hash_value(OperationName arg) {
516  return llvm::hash_value(arg.getAsOpaquePointer());
517 }
518 
519 //===----------------------------------------------------------------------===//
520 // RegisteredOperationName
521 //===----------------------------------------------------------------------===//
522 
523 /// This is a "type erased" representation of a registered operation. This
524 /// should only be used by things like the AsmPrinter and other things that need
525 /// to be parameterized by generic operation hooks. Most user code should use
526 /// the concrete operation types.
528 public:
529  /// Implementation of the InterfaceConcept for operation APIs that forwarded
530  /// to a concrete op implementation.
531  template <typename ConcreteOp>
532  struct Model : public Impl {
534  : Impl(ConcreteOp::getOperationName(), dialect,
535  TypeID::get<ConcreteOp>(), ConcreteOp::getInterfaceMap()) {}
536  LogicalResult foldHook(Operation *op, ArrayRef<Attribute> attrs,
537  SmallVectorImpl<OpFoldResult> &results) final {
538  return ConcreteOp::getFoldHookFn()(op, attrs, results);
539  }
541  MLIRContext *context) final {
542  ConcreteOp::getCanonicalizationPatterns(set, context);
543  }
544  bool hasTrait(TypeID id) final { return ConcreteOp::getHasTraitFn()(id); }
546  return ConcreteOp::parse;
547  }
549  NamedAttrList &attrs) final {
550  ConcreteOp::populateDefaultAttrs(name, attrs);
551  }
553  StringRef name) final {
554  ConcreteOp::getPrintAssemblyFn()(op, printer, name);
555  }
556  LogicalResult verifyInvariants(Operation *op) final {
557  return ConcreteOp::getVerifyInvariantsFn()(op);
558  }
559  LogicalResult verifyRegionInvariants(Operation *op) final {
560  return ConcreteOp::getVerifyRegionInvariantsFn()(op);
561  }
562 
563  /// Implementation for "Properties"
564 
565  using Properties = std::remove_reference_t<
566  decltype(std::declval<ConcreteOp>().getProperties())>;
567 
568  std::optional<Attribute> getInherentAttr(Operation *op,
569  StringRef name) final {
570  if constexpr (hasProperties) {
571  auto concreteOp = cast<ConcreteOp>(op);
572  return ConcreteOp::getInherentAttr(concreteOp->getContext(),
573  concreteOp.getProperties(), name);
574  }
575  // If the op does not have support for properties, we dispatch back to the
576  // dictionnary of discardable attributes for now.
577  return cast<ConcreteOp>(op)->getDiscardableAttr(name);
578  }
579  void setInherentAttr(Operation *op, StringAttr name,
580  Attribute value) final {
581  if constexpr (hasProperties) {
582  auto concreteOp = cast<ConcreteOp>(op);
583  return ConcreteOp::setInherentAttr(concreteOp.getProperties(), name,
584  value);
585  }
586  // If the op does not have support for properties, we dispatch back to the
587  // dictionnary of discardable attributes for now.
588  return cast<ConcreteOp>(op)->setDiscardableAttr(name, value);
589  }
591  if constexpr (hasProperties) {
592  auto concreteOp = cast<ConcreteOp>(op);
593  ConcreteOp::populateInherentAttrs(concreteOp->getContext(),
594  concreteOp.getProperties(), attrs);
595  }
596  }
597  LogicalResult
600  if constexpr (hasProperties)
601  return ConcreteOp::verifyInherentAttrs(opName, attributes, emitError);
602  return success();
603  }
604  // Detect if the concrete operation defined properties.
605  static constexpr bool hasProperties = !std::is_same_v<
606  typename ConcreteOp::template InferredProperties<ConcreteOp>,
608 
609  int getOpPropertyByteSize() final {
610  if constexpr (hasProperties)
611  return sizeof(Properties);
612  return 0;
613  }
615  OpaqueProperties init) final {
616  using Properties =
617  typename ConcreteOp::template InferredProperties<ConcreteOp>;
618  if (init)
619  new (storage.as<Properties *>()) Properties(*init.as<Properties *>());
620  else
621  new (storage.as<Properties *>()) Properties();
622  if constexpr (hasProperties)
623  ConcreteOp::populateDefaultProperties(opName,
624  *storage.as<Properties *>());
625  }
627  prop.as<Properties *>()->~Properties();
628  }
630  OpaqueProperties properties) final {
631  if constexpr (hasProperties)
632  ConcreteOp::populateDefaultProperties(opName,
633  *properties.as<Properties *>());
634  }
635 
636  LogicalResult
638  Attribute attr,
640  if constexpr (hasProperties) {
641  auto p = properties.as<Properties *>();
642  return ConcreteOp::setPropertiesFromAttr(*p, attr, emitError);
643  }
644  emitError() << "this operation does not support properties";
645  return failure();
646  }
648  if constexpr (hasProperties) {
649  auto concreteOp = cast<ConcreteOp>(op);
650  return ConcreteOp::getPropertiesAsAttr(concreteOp->getContext(),
651  concreteOp.getProperties());
652  }
653  return {};
654  }
656  if constexpr (hasProperties) {
657  return *lhs.as<Properties *>() == *rhs.as<Properties *>();
658  } else {
659  return true;
660  }
661  }
663  *lhs.as<Properties *>() = *rhs.as<Properties *>();
664  }
665  llvm::hash_code hashProperties(OpaqueProperties prop) final {
666  if constexpr (hasProperties)
667  return ConcreteOp::computePropertiesHash(*prop.as<Properties *>());
668 
669  return {};
670  }
671  };
672 
673  /// Lookup the registered operation information for the given operation.
674  /// Returns std::nullopt if the operation isn't registered.
675  static std::optional<RegisteredOperationName> lookup(StringRef name,
676  MLIRContext *ctx);
677 
678  /// Lookup the registered operation information for the given operation.
679  /// Returns std::nullopt if the operation isn't registered.
680  static std::optional<RegisteredOperationName> lookup(TypeID typeID,
681  MLIRContext *ctx);
682 
683  /// Register a new operation in a Dialect object.
684  /// This constructor is used by Dialect objects when they register the list
685  /// of operations they contain.
686  template <typename T>
687  static void insert(Dialect &dialect) {
688  insert(std::make_unique<Model<T>>(&dialect), T::getAttributeNames());
689  }
690  /// The use of this method is in general discouraged in favor of
691  /// 'insert<CustomOp>(dialect)'.
692  static void insert(std::unique_ptr<OperationName::Impl> ownedImpl,
693  ArrayRef<StringRef> attrNames);
694 
695  /// Return the dialect this operation is registered to.
696  Dialect &getDialect() const { return *getImpl()->getDialect(); }
697 
698  /// Use the specified object to parse this ops custom assembly format.
699  ParseResult parseAssembly(OpAsmParser &parser, OperationState &result) const;
700 
701  /// Represent the operation name as an opaque pointer. (Used to support
702  /// PointerLikeTypeTraits).
703  static RegisteredOperationName getFromOpaquePointer(const void *pointer) {
705  const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
706  }
707 
708 private:
710 
711  /// Allow access to the constructor.
712  friend OperationName;
713 };
714 
715 inline std::optional<RegisteredOperationName>
718  : std::optional<RegisteredOperationName>();
719 }
720 
721 //===----------------------------------------------------------------------===//
722 // Attribute Dictionary-Like Interface
723 //===----------------------------------------------------------------------===//
724 
725 /// Attribute collections provide a dictionary-like interface. Define common
726 /// lookup functions.
727 namespace impl {
728 
729 /// Unsorted string search or identifier lookups are linear scans.
730 template <typename IteratorT, typename NameT>
731 std::pair<IteratorT, bool> findAttrUnsorted(IteratorT first, IteratorT last,
732  NameT name) {
733  for (auto it = first; it != last; ++it)
734  if (it->getName() == name)
735  return {it, true};
736  return {last, false};
737 }
738 
739 /// Using llvm::lower_bound requires an extra string comparison to check whether
740 /// the returned iterator points to the found element or whether it indicates
741 /// the lower bound. Skip this redundant comparison by checking if `compare ==
742 /// 0` during the binary search.
743 template <typename IteratorT>
744 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
745  StringRef name) {
746  ptrdiff_t length = std::distance(first, last);
747 
748  while (length > 0) {
749  ptrdiff_t half = length / 2;
750  IteratorT mid = first + half;
751  int compare = mid->getName().strref().compare(name);
752  if (compare < 0) {
753  first = mid + 1;
754  length = length - half - 1;
755  } else if (compare > 0) {
756  length = half;
757  } else {
758  return {mid, true};
759  }
760  }
761  return {first, false};
762 }
763 
764 /// StringAttr lookups on large attribute lists will switch to string binary
765 /// search. String binary searches become significantly faster than linear scans
766 /// with the identifier when the attribute list becomes very large.
767 template <typename IteratorT>
768 std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
769  StringAttr name) {
770  constexpr unsigned kSmallAttributeList = 16;
771  if (std::distance(first, last) > kSmallAttributeList)
772  return findAttrSorted(first, last, name.strref());
773  return findAttrUnsorted(first, last, name);
774 }
775 
776 /// Get an attribute from a sorted range of named attributes. Returns null if
777 /// the attribute was not found.
778 template <typename IteratorT, typename NameT>
779 Attribute getAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
780  std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
781  return result.second ? result.first->getValue() : Attribute();
782 }
783 
784 /// Get an attribute from a sorted range of named attributes. Returns
785 /// std::nullopt if the attribute was not found.
786 template <typename IteratorT, typename NameT>
787 std::optional<NamedAttribute>
788 getNamedAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
789  std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
790  return result.second ? *result.first : std::optional<NamedAttribute>();
791 }
792 
793 } // namespace impl
794 
795 //===----------------------------------------------------------------------===//
796 // NamedAttrList
797 //===----------------------------------------------------------------------===//
798 
799 /// NamedAttrList is array of NamedAttributes that tracks whether it is sorted
800 /// and does some basic work to remain sorted.
802 public:
807  using size_type = size_t;
808 
809  NamedAttrList() : dictionarySorted({}, true) {}
810  NamedAttrList(std::nullopt_t none) : NamedAttrList() {}
812  NamedAttrList(DictionaryAttr attributes);
814 
815  template <typename Container>
816  NamedAttrList(const Container &vec)
818 
819  bool operator!=(const NamedAttrList &other) const {
820  return !(*this == other);
821  }
822  bool operator==(const NamedAttrList &other) const {
823  return attrs == other.attrs;
824  }
825 
826  /// Add an attribute with the specified name.
827  void append(StringRef name, Attribute attr);
828 
829  /// Add an attribute with the specified name.
830  void append(StringAttr name, Attribute attr) {
831  append(NamedAttribute(name, attr));
832  }
833 
834  /// Append the given named attribute.
835  void append(NamedAttribute attr) { push_back(attr); }
836 
837  /// Add an array of named attributes.
838  template <typename RangeT>
839  void append(RangeT &&newAttributes) {
840  append(std::begin(newAttributes), std::end(newAttributes));
841  }
842 
843  /// Add a range of named attributes.
844  template <typename IteratorT,
845  typename = std::enable_if_t<std::is_convertible<
846  typename std::iterator_traits<IteratorT>::iterator_category,
847  std::input_iterator_tag>::value>>
848  void append(IteratorT inStart, IteratorT inEnd) {
849  // TODO: expand to handle case where values appended are in order & after
850  // end of current list.
851  dictionarySorted.setPointerAndInt(nullptr, false);
852  attrs.append(inStart, inEnd);
853  }
854 
855  /// Replaces the attributes with new list of attributes.
856  void assign(const_iterator inStart, const_iterator inEnd);
857 
858  /// Replaces the attributes with new list of attributes.
860  assign(range.begin(), range.end());
861  }
862 
863  void clear() {
864  attrs.clear();
865  dictionarySorted.setPointerAndInt(nullptr, false);
866  }
867 
868  bool empty() const { return attrs.empty(); }
869 
870  void reserve(size_type N) { attrs.reserve(N); }
871 
872  /// Add an attribute with the specified name.
873  void push_back(NamedAttribute newAttribute);
874 
875  /// Pop last element from list.
876  void pop_back() { attrs.pop_back(); }
877 
878  /// Returns an entry with a duplicate name the list, if it exists, else
879  /// returns std::nullopt.
880  std::optional<NamedAttribute> findDuplicate() const;
881 
882  /// Return a dictionary attribute for the underlying dictionary. This will
883  /// return an empty dictionary attribute if empty rather than null.
884  DictionaryAttr getDictionary(MLIRContext *context) const;
885 
886  /// Return all of the attributes on this operation.
888 
889  /// Return the specified attribute if present, null otherwise.
890  Attribute get(StringAttr name) const;
891  Attribute get(StringRef name) const;
892 
893  /// Return the specified named attribute if present, std::nullopt otherwise.
894  std::optional<NamedAttribute> getNamed(StringRef name) const;
895  std::optional<NamedAttribute> getNamed(StringAttr name) const;
896 
897  /// If the an attribute exists with the specified name, change it to the new
898  /// value. Otherwise, add a new attribute with the specified name/value.
899  /// Returns the previous attribute value of `name`, or null if no
900  /// attribute previously existed with `name`.
901  Attribute set(StringAttr name, Attribute value);
902  Attribute set(StringRef name, Attribute value);
903 
904  /// Erase the attribute with the given name from the list. Return the
905  /// attribute that was erased, or nullptr if there was no attribute with such
906  /// name.
907  Attribute erase(StringAttr name);
908  Attribute erase(StringRef name);
909 
910  iterator begin() { return attrs.begin(); }
911  iterator end() { return attrs.end(); }
912  const_iterator begin() const { return attrs.begin(); }
913  const_iterator end() const { return attrs.end(); }
914 
916  operator ArrayRef<NamedAttribute>() const;
917 
918 private:
919  /// Return whether the attributes are sorted.
920  bool isSorted() const { return dictionarySorted.getInt(); }
921 
922  /// Erase the attribute at the given iterator position.
923  Attribute eraseImpl(SmallVectorImpl<NamedAttribute>::iterator it);
924 
925  /// Lookup an attribute in the list.
926  template <typename AttrListT, typename NameT>
927  static auto findAttr(AttrListT &attrs, NameT name) {
928  return attrs.isSorted()
929  ? impl::findAttrSorted(attrs.begin(), attrs.end(), name)
930  : impl::findAttrUnsorted(attrs.begin(), attrs.end(), name);
931  }
932 
933  // These are marked mutable as they may be modified (e.g., sorted)
934  mutable SmallVector<NamedAttribute, 4> attrs;
935  // Pair with cached DictionaryAttr and status of whether attrs is sorted.
936  // Note: just because sorted does not mean a DictionaryAttr has been created
937  // but the case where there is a DictionaryAttr but attrs isn't sorted should
938  // not occur.
939  mutable llvm::PointerIntPair<Attribute, 1, bool> dictionarySorted;
940 };
941 
942 //===----------------------------------------------------------------------===//
943 // OperationState
944 //===----------------------------------------------------------------------===//
945 
946 /// This represents an operation in an abstracted form, suitable for use with
947 /// the builder APIs. This object is a large and heavy weight object meant to
948 /// be used as a temporary object on the stack. It is generally unwise to put
949 /// this in a collection.
954  /// Types of the results of this operation.
957  /// Successors of this operation and their respective operands.
959  /// Regions that the op will hold.
961 
962  /// This Attribute is used to opaquely construct the properties of the
963  /// operation. If we're creating an unregistered operation, the Attribute is
964  /// used as-is as the Properties storage of the operation. Otherwise, the
965  /// operation properties are constructed opaquely using its
966  /// `setPropertiesFromAttr` hook. Note that `getOrAddProperties` is the
967  /// preferred method to construct properties from C++.
969 
970 private:
971  OpaqueProperties properties = nullptr;
972  TypeID propertiesId;
973  llvm::function_ref<void(OpaqueProperties)> propertiesDeleter;
975  propertiesSetter;
976  friend class Operation;
977 
978 public:
979  OperationState(Location location, StringRef name);
981 
984  BlockRange successors = {},
985  MutableArrayRef<std::unique_ptr<Region>> regions = {});
986  OperationState(Location location, StringRef name, ValueRange operands,
987  TypeRange types, ArrayRef<NamedAttribute> attributes = {},
988  BlockRange successors = {},
989  MutableArrayRef<std::unique_ptr<Region>> regions = {});
990  OperationState(OperationState &&other) = default;
991  OperationState(const OperationState &other) = default;
993  OperationState &operator=(const OperationState &other) = default;
994  ~OperationState();
995 
996  /// Get (or create) a properties of the provided type to be set on the
997  /// operation on creation.
998  template <typename T>
1000  if (!properties) {
1001  T *p = new T{};
1002  properties = p;
1003  propertiesDeleter = [](OpaqueProperties prop) {
1004  delete prop.as<const T *>();
1005  };
1006  propertiesSetter = [](OpaqueProperties new_prop,
1007  const OpaqueProperties prop) {
1008  *new_prop.as<T *>() = *prop.as<const T *>();
1009  };
1010  propertiesId = TypeID::get<T>();
1011  }
1012  assert(propertiesId == TypeID::get<T>() && "Inconsistent properties");
1013  return *properties.as<T *>();
1014  }
1015  OpaqueProperties getRawProperties() { return properties; }
1016 
1017  // Set the properties defined on this OpState on the given operation,
1018  // optionally emit diagnostics on error through the provided diagnostic.
1019  LogicalResult
1022 
1023  void addOperands(ValueRange newOperands);
1024 
1025  void addTypes(ArrayRef<Type> newTypes) {
1026  types.append(newTypes.begin(), newTypes.end());
1027  }
1028  template <typename RangeT>
1029  std::enable_if_t<!std::is_convertible<RangeT, ArrayRef<Type>>::value>
1030  addTypes(RangeT &&newTypes) {
1031  types.append(newTypes.begin(), newTypes.end());
1032  }
1033 
1034  /// Add an attribute with the specified name.
1035  void addAttribute(StringRef name, Attribute attr) {
1037  }
1038 
1039  /// Add an attribute with the specified name. `name` and `attr` must not be
1040  /// null.
1041  void addAttribute(StringAttr name, Attribute attr) {
1042  assert(name && "attribute name cannot be null");
1043  assert(attr && "attribute cannot be null");
1044  attributes.append(name, attr);
1045  }
1046 
1047  /// Add an array of named attributes.
1049  attributes.append(newAttributes);
1050  }
1051 
1052  /// Adds a successor to the operation sate. `successor` must not be null.
1053  void addSuccessors(Block *successor) {
1054  assert(successor && "successor cannot be null");
1055  successors.push_back(successor);
1056  }
1057  void addSuccessors(BlockRange newSuccessors);
1058 
1059  /// Create a region that should be attached to the operation. These regions
1060  /// can be filled in immediately without waiting for Operation to be
1061  /// created. When it is, the region bodies will be transferred.
1062  Region *addRegion();
1063 
1064  /// Take a region that should be attached to the Operation. The body of the
1065  /// region will be transferred when the Operation is constructed. If the
1066  /// region is null, a new empty region will be attached to the Operation.
1067  void addRegion(std::unique_ptr<Region> &&region);
1068 
1069  /// Take ownership of a set of regions that should be attached to the
1070  /// Operation.
1071  void addRegions(MutableArrayRef<std::unique_ptr<Region>> regions);
1072 
1073  /// Get the context held by this operation state.
1074  MLIRContext *getContext() const { return location->getContext(); }
1075 };
1076 
1077 //===----------------------------------------------------------------------===//
1078 // OperandStorage
1079 //===----------------------------------------------------------------------===//
1080 
1081 namespace detail {
1082 /// This class handles the management of operation operands. Operands are
1083 /// stored either in a trailing array, or a dynamically resizable vector.
1084 class alignas(8) OperandStorage {
1085 public:
1086  OperandStorage(Operation *owner, OpOperand *trailingOperands,
1087  ValueRange values);
1088  ~OperandStorage();
1089 
1090  /// Replace the operands contained in the storage with the ones provided in
1091  /// 'values'.
1092  void setOperands(Operation *owner, ValueRange values);
1093 
1094  /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
1095  /// with the ones provided in 'operands'. 'operands' may be smaller or larger
1096  /// than the range pointed to by 'start'+'length'.
1097  void setOperands(Operation *owner, unsigned start, unsigned length,
1098  ValueRange operands);
1099 
1100  /// Erase the operands held by the storage within the given range.
1101  void eraseOperands(unsigned start, unsigned length);
1102 
1103  /// Erase the operands held by the storage that have their corresponding bit
1104  /// set in `eraseIndices`.
1105  void eraseOperands(const BitVector &eraseIndices);
1106 
1107  /// Get the operation operands held by the storage.
1108  MutableArrayRef<OpOperand> getOperands() { return {operandStorage, size()}; }
1109 
1110  /// Return the number of operands held in the storage.
1111  unsigned size() { return numOperands; }
1112 
1113 private:
1114  /// Resize the storage to the given size. Returns the array containing the new
1115  /// operands.
1116  MutableArrayRef<OpOperand> resize(Operation *owner, unsigned newSize);
1117 
1118  /// The total capacity number of operands that the storage can hold.
1119  unsigned capacity : 31;
1120  /// A flag indicating if the operand storage was dynamically allocated, as
1121  /// opposed to inlined into the owning operation.
1122  unsigned isStorageDynamic : 1;
1123  /// The number of operands within the storage.
1124  unsigned numOperands;
1125  /// A pointer to the operand storage.
1126  OpOperand *operandStorage;
1127 };
1128 } // namespace detail
1129 
1130 //===----------------------------------------------------------------------===//
1131 // OpPrintingFlags
1132 //===----------------------------------------------------------------------===//
1133 
1134 /// Set of flags used to control the behavior of the various IR print methods
1135 /// (e.g. Operation::Print).
1137 public:
1138  OpPrintingFlags();
1139  OpPrintingFlags(std::nullopt_t) : OpPrintingFlags() {}
1140 
1141  /// Enables the elision of large elements attributes by printing a lexically
1142  /// valid but otherwise meaningless form instead of the element data. The
1143  /// `largeElementLimit` is used to configure what is considered to be a
1144  /// "large" ElementsAttr by providing an upper limit to the number of
1145  /// elements.
1146  OpPrintingFlags &elideLargeElementsAttrs(int64_t largeElementLimit = 16);
1147 
1148  /// Enables the printing of large element attributes with a hex string. The
1149  /// `largeElementLimit` is used to configure what is considered to be a
1150  /// "large" ElementsAttr by providing an upper limit to the number of
1151  /// elements. Use -1 to disable the hex printing.
1152  OpPrintingFlags &
1153  printLargeElementsAttrWithHex(int64_t largeElementLimit = 100);
1154 
1155  /// Enables the elision of large resources strings by omitting them from the
1156  /// `dialect_resources` section. The `largeResourceLimit` is used to configure
1157  /// what is considered to be a "large" resource by providing an upper limit to
1158  /// the string size.
1159  OpPrintingFlags &elideLargeResourceString(int64_t largeResourceLimit = 64);
1160 
1161  /// Enable or disable printing of debug information (based on `enable`). If
1162  /// 'prettyForm' is set to true, debug information is printed in a more
1163  /// readable 'pretty' form. Note: The IR generated with 'prettyForm' is not
1164  /// parsable.
1165  OpPrintingFlags &enableDebugInfo(bool enable = true, bool prettyForm = false);
1166 
1167  /// Always print operations in the generic form.
1168  OpPrintingFlags &printGenericOpForm(bool enable = true);
1169 
1170  /// Skip printing regions.
1171  OpPrintingFlags &skipRegions(bool skip = true);
1172 
1173  /// Do not verify the operation when using custom operation printers.
1175 
1176  /// Use local scope when printing the operation. This allows for using the
1177  /// printer in a more localized and thread-safe setting, but may not
1178  /// necessarily be identical to what the IR will look like when dumping
1179  /// the full module.
1181 
1182  /// Print users of values as comments.
1184 
1185  /// Return if the given ElementsAttr should be elided.
1186  bool shouldElideElementsAttr(ElementsAttr attr) const;
1187 
1188  /// Return if the given ElementsAttr should be printed as hex string.
1189  bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const;
1190 
1191  /// Return the size limit for printing large ElementsAttr.
1192  std::optional<int64_t> getLargeElementsAttrLimit() const;
1193 
1194  /// Return the size limit for printing large ElementsAttr as hex string.
1195  int64_t getLargeElementsAttrHexLimit() const;
1196 
1197  /// Return the size limit in chars for printing large resources.
1198  std::optional<uint64_t> getLargeResourceStringLimit() const;
1199 
1200  /// Return if debug information should be printed.
1201  bool shouldPrintDebugInfo() const;
1202 
1203  /// Return if debug information should be printed in the pretty form.
1204  bool shouldPrintDebugInfoPrettyForm() const;
1205 
1206  /// Return if operations should be printed in the generic form.
1207  bool shouldPrintGenericOpForm() const;
1208 
1209  /// Return if regions should be skipped.
1210  bool shouldSkipRegions() const;
1211 
1212  /// Return if operation verification should be skipped.
1213  bool shouldAssumeVerified() const;
1214 
1215  /// Return if the printer should use local scope when dumping the IR.
1216  bool shouldUseLocalScope() const;
1217 
1218  /// Return if the printer should print users of values.
1219  bool shouldPrintValueUsers() const;
1220 
1221  /// Return if printer should use unique SSA IDs.
1222  bool shouldPrintUniqueSSAIDs() const;
1223 
1224  /// Return if the printer should use NameLocs as prefixes when printing SSA
1225  /// IDs
1226  bool shouldUseNameLocAsPrefix() const;
1227 
1228 private:
1229  /// Elide large elements attributes if the number of elements is larger than
1230  /// the upper limit.
1231  std::optional<int64_t> elementsAttrElementLimit;
1232 
1233  /// Elide printing large resources based on size of string.
1234  std::optional<uint64_t> resourceStringCharLimit;
1235 
1236  /// Print large element attributes with hex strings if the number of elements
1237  /// is larger than the upper limit.
1238  int64_t elementsAttrHexElementLimit = 100;
1239 
1240  /// Print debug information.
1241  bool printDebugInfoFlag : 1;
1242  bool printDebugInfoPrettyFormFlag : 1;
1243 
1244  /// Print operations in the generic form.
1245  bool printGenericOpFormFlag : 1;
1246 
1247  /// Always skip Regions.
1248  bool skipRegionsFlag : 1;
1249 
1250  /// Skip operation verification.
1251  bool assumeVerifiedFlag : 1;
1252 
1253  /// Print operations with numberings local to the current operation.
1254  bool printLocalScope : 1;
1255 
1256  /// Print users of values.
1257  bool printValueUsersFlag : 1;
1258 
1259  /// Print unique SSA IDs for values, block arguments and naming conflicts
1260  bool printUniqueSSAIDsFlag : 1;
1261 
1262  /// Print SSA IDs using NameLocs as prefixes
1263  bool useNameLocAsPrefix : 1;
1264 };
1265 
1266 //===----------------------------------------------------------------------===//
1267 // Operation Equivalency
1268 //===----------------------------------------------------------------------===//
1269 
1270 /// This class provides utilities for computing if two operations are
1271 /// equivalent.
1273  enum Flags {
1274  None = 0,
1275 
1276  // When provided, the location attached to the operation are ignored.
1278 
1279  LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
1280  };
1281 
1282  /// Compute a hash for the given operation.
1283  /// The `hashOperands` and `hashResults` callbacks are expected to return a
1284  /// unique hash_code for a given Value.
1285  static llvm::hash_code computeHash(
1286  Operation *op,
1287  function_ref<llvm::hash_code(Value)> hashOperands =
1288  [](Value v) { return hash_value(v); },
1289  function_ref<llvm::hash_code(Value)> hashResults =
1290  [](Value v) { return hash_value(v); },
1291  Flags flags = Flags::None);
1292 
1293  /// Helper that can be used with `computeHash` above to ignore operation
1294  /// operands/result mapping.
1295  static llvm::hash_code ignoreHashValue(Value) { return llvm::hash_code{}; }
1296  /// Helper that can be used with `computeHash` above to ignore operation
1297  /// operands/result mapping.
1298  static llvm::hash_code directHashValue(Value v) { return hash_value(v); }
1299 
1300  /// Compare two operations (including their regions) and return if they are
1301  /// equivalent.
1302  ///
1303  /// * `checkEquivalent` is a callback to check if two values are equivalent.
1304  /// For two operations to be equivalent, their operands must be the same SSA
1305  /// value or this callback must return `success`.
1306  /// * `markEquivalent` is a callback to inform the caller that the analysis
1307  /// determined that two values are equivalent.
1308  /// * `checkCommutativeEquivalent` is an optional callback to check for
1309  /// equivalence across two ranges for a commutative operation. If not passed
1310  /// in, then equivalence is checked pairwise. This callback is needed to be
1311  /// able to query the optional equivalence classes.
1312  ///
1313  /// Note: Additional information regarding value equivalence can be injected
1314  /// into the analysis via `checkEquivalent`. Typically, callers may want
1315  /// values that were determined to be equivalent as per `markEquivalent` to be
1316  /// reflected in `checkEquivalent`, unless `exactValueMatch` or a different
1317  /// equivalence relationship is desired.
1318  static bool
1319  isEquivalentTo(Operation *lhs, Operation *rhs,
1320  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1321  function_ref<void(Value, Value)> markEquivalent = nullptr,
1322  Flags flags = Flags::None,
1323  function_ref<LogicalResult(ValueRange, ValueRange)>
1324  checkCommutativeEquivalent = nullptr);
1325 
1326  /// Compare two operations and return if they are equivalent.
1327  static bool isEquivalentTo(Operation *lhs, Operation *rhs, Flags flags);
1328 
1329  /// Compare two regions (including their subregions) and return if they are
1330  /// equivalent. See also `isEquivalentTo` for details.
1331  static bool isRegionEquivalentTo(
1332  Region *lhs, Region *rhs,
1333  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1334  function_ref<void(Value, Value)> markEquivalent,
1336  function_ref<LogicalResult(ValueRange, ValueRange)>
1337  checkCommutativeEquivalent = nullptr);
1338 
1339  /// Compare two regions and return if they are equivalent.
1340  static bool isRegionEquivalentTo(Region *lhs, Region *rhs,
1342 
1343  /// Helper that can be used with `isEquivalentTo` above to consider ops
1344  /// equivalent even if their operands are not equivalent.
1345  static LogicalResult ignoreValueEquivalence(Value lhs, Value rhs) {
1346  return success();
1347  }
1348  /// Helper that can be used with `isEquivalentTo` above to consider ops
1349  /// equivalent only if their operands are the exact same SSA values.
1350  static LogicalResult exactValueMatch(Value lhs, Value rhs) {
1351  return success(lhs == rhs);
1352  }
1353 };
1354 
1355 /// Enable Bitmask enums for OperationEquivalence::Flags.
1357 
1358 //===----------------------------------------------------------------------===//
1359 // OperationFingerPrint
1360 //===----------------------------------------------------------------------===//
1361 
1362 /// A unique fingerprint for a specific operation, and all of it's internal
1363 /// operations (if `includeNested` is set).
1365 public:
1366  OperationFingerPrint(Operation *topOp, bool includeNested = true);
1369 
1370  bool operator==(const OperationFingerPrint &other) const {
1371  return hash == other.hash;
1372  }
1373  bool operator!=(const OperationFingerPrint &other) const {
1374  return !(*this == other);
1375  }
1376 
1377 private:
1378  std::array<uint8_t, 20> hash;
1379 };
1380 
1381 } // namespace mlir
1382 
1383 namespace llvm {
1384 template <>
1385 struct DenseMapInfo<mlir::OperationName> {
1387  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1389  }
1393  }
1394  static unsigned getHashValue(mlir::OperationName val) {
1396  }
1398  return lhs == rhs;
1399  }
1400 };
1401 template <>
1402 struct DenseMapInfo<mlir::RegisteredOperationName>
1403  : public DenseMapInfo<mlir::OperationName> {
1405  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1407  }
1411  }
1412 };
1413 
1414 template <>
1415 struct PointerLikeTypeTraits<mlir::OperationName> {
1416  static inline void *getAsVoidPointer(mlir::OperationName I) {
1417  return const_cast<void *>(I.getAsOpaquePointer());
1418  }
1419  static inline mlir::OperationName getFromVoidPointer(void *P) {
1421  }
1422  static constexpr int NumLowBitsAvailable =
1423  PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
1424 };
1425 template <>
1426 struct PointerLikeTypeTraits<mlir::RegisteredOperationName>
1427  : public PointerLikeTypeTraits<mlir::OperationName> {
1430  }
1431 };
1432 
1433 } // namespace llvm
1434 
1435 #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:307
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
Definition: AsmPrinter.cpp:322
bool shouldUseNameLocAsPrefix() const
Return if the printer should use NameLocs as prefixes when printing SSA IDs.
Definition: AsmPrinter.cpp:373
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
Definition: AsmPrinter.cpp:355
OpPrintingFlags & printValueUsers()
Print users of values as comments.
Definition: AsmPrinter.cpp:301
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:360
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
Definition: AsmPrinter.cpp:342
bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const
Return if the given ElementsAttr should be printed as hex string.
Definition: AsmPrinter.cpp:314
bool shouldPrintUniqueSSAIDs() const
Return if printer should use unique SSA IDs.
Definition: AsmPrinter.cpp:368
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
Definition: AsmPrinter.cpp:363
int64_t getLargeElementsAttrHexLimit() const
Return the size limit for printing large ElementsAttr as hex string.
Definition: AsmPrinter.cpp:327
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
Definition: AsmPrinter.cpp:347
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:337
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 & 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:352
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
Definition: AsmPrinter.cpp:275
OpPrintingFlags & assumeVerified()
Do not verify the operation when using custom operation printers.
Definition: AsmPrinter.cpp:287
OpPrintingFlags(std::nullopt_t)
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
Definition: AsmPrinter.cpp:332
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
Definition: AsmPrinter.cpp:295
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
Definition: AsmPrinter.cpp:281
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.
ParseResult parseAssembly(OpAsmParser &parser, OperationState &result) const
Use the specified object to parse this ops custom assembly format.
static void insert(std::unique_ptr< OperationName::Impl > ownedImpl, ArrayRef< StringRef > attrNames)
The use of this method is in general discouraged in favor of 'insert<CustomOp>(dialect)'.
Dialect & getDialect() const
Return the dialect this operation is registered to.
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:36
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:381
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
This class provides an efficient mapping between a given Interface type, and a particular implementat...
void insertModels()
Insert the given interface models.
bool contains(TypeID interfaceID) const
Returns true if the interface map contains an interface for the given id.
T::Concept * lookup() const
Returns an instance of the concept object for the given interface if it was registered to this map,...
This class handles the management of operation operands.
MutableArrayRef< OpOperand > getOperands()
Get the operation operands held by the storage.
void eraseOperands(unsigned start, unsigned length)
Erase the operands held by the storage within the given range.
unsigned size()
Return the number of operands held in the storage.
void setOperands(Operation *owner, ValueRange values)
Replace the operands contained in the storage with the ones provided in 'values'.
OperandStorage(Operation *owner, OpOperand *trailingOperands, ValueRange values)
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.