MLIR  18.0.0git
OperationSupport.h
Go to the documentation of this file.
1 //===- OperationSupport.h ---------------------------------------*- C++ -*-===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file defines a number of support types that Operation and related
10 // classes build on top of.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_IR_OPERATIONSUPPORT_H
15 #define MLIR_IR_OPERATIONSUPPORT_H
16 
17 #include "mlir/IR/Attributes.h"
18 #include "mlir/IR/BlockSupport.h"
20 #include "mlir/IR/Diagnostics.h"
22 #include "mlir/IR/Location.h"
23 #include "mlir/IR/TypeRange.h"
24 #include "mlir/IR/Types.h"
25 #include "mlir/IR/Value.h"
27 #include "llvm/ADT/BitmaskEnum.h"
28 #include "llvm/ADT/PointerUnion.h"
29 #include "llvm/ADT/STLFunctionalExtras.h"
30 #include "llvm/Support/ErrorHandling.h"
31 #include "llvm/Support/PointerLikeTypeTraits.h"
32 #include "llvm/Support/TrailingObjects.h"
33 #include <memory>
34 #include <optional>
35 
36 namespace llvm {
37 class BitVector;
38 } // namespace llvm
39 
40 namespace mlir {
41 class Dialect;
42 class DictionaryAttr;
43 class ElementsAttr;
44 struct EmptyProperties;
45 class MutableOperandRangeRange;
46 class NamedAttrList;
47 class Operation;
48 struct OperationState;
49 class OpAsmParser;
50 class OpAsmPrinter;
51 class OperandRange;
52 class OperandRangeRange;
53 class OpFoldResult;
54 class ParseResult;
55 class Pattern;
56 class Region;
57 class ResultRange;
58 class RewritePattern;
59 class RewritePatternSet;
60 class Type;
61 class Value;
62 class ValueRange;
63 template <typename ValueRangeT>
64 class ValueTypeRange;
65 
66 //===----------------------------------------------------------------------===//
67 // OpaqueProperties
68 //===----------------------------------------------------------------------===//
69 
70 /// Simple wrapper around a void* in order to express generically how to pass
71 /// in op properties through APIs.
73 public:
74  OpaqueProperties(void *prop) : properties(prop) {}
75  operator bool() const { return properties != nullptr; }
76  template <typename Dest>
77  Dest as() const {
78  return static_cast<Dest>(const_cast<void *>(properties));
79  }
80 
81 private:
82  void *properties;
83 };
84 
85 //===----------------------------------------------------------------------===//
86 // OperationName
87 //===----------------------------------------------------------------------===//
88 
90 public:
91  using FoldHookFn = llvm::unique_function<LogicalResult(
93  using HasTraitFn = llvm::unique_function<bool(TypeID) const>;
95  llvm::unique_function<ParseResult(OpAsmParser &, OperationState &)>;
96  // Note: RegisteredOperationName is passed as reference here as the derived
97  // class is defined below.
99  llvm::unique_function<void(const OperationName &, NamedAttrList &) const>;
101  llvm::unique_function<void(Operation *, OpAsmPrinter &, StringRef) const>;
103  llvm::unique_function<LogicalResult(Operation *) const>;
105  llvm::unique_function<LogicalResult(Operation *) const>;
106 
107  /// This class represents a type erased version of an operation. It contains
108  /// all of the components necessary for opaquely interacting with an
109  /// operation. If the operation is not registered, some of these components
110  /// may not be populated.
112  virtual ~InterfaceConcept() = default;
116  MLIRContext *) = 0;
117  virtual bool hasTrait(TypeID) = 0;
119  virtual void populateDefaultAttrs(const OperationName &,
120  NamedAttrList &) = 0;
121  virtual void printAssembly(Operation *, OpAsmPrinter &, StringRef) = 0;
124  /// Implementation for properties
125  virtual std::optional<Attribute> getInherentAttr(Operation *,
126  StringRef name) = 0;
127  virtual void setInherentAttr(Operation *op, StringAttr name,
128  Attribute value) = 0;
129  virtual void populateInherentAttrs(Operation *op, NamedAttrList &attrs) = 0;
130  virtual LogicalResult
132  function_ref<InFlightDiagnostic()> getDiag) = 0;
133  virtual int getOpPropertyByteSize() = 0;
134  virtual void initProperties(OperationName opName, OpaqueProperties storage,
135  OpaqueProperties init) = 0;
138  OpaqueProperties properties) = 0;
139  virtual LogicalResult
141  function_ref<InFlightDiagnostic &()> getDiag) = 0;
145  virtual llvm::hash_code hashProperties(OpaqueProperties) = 0;
146  };
147 
148 public:
149  class Impl : public InterfaceConcept {
150  public:
151  Impl(StringRef, Dialect *dialect, TypeID typeID,
156  interfaceMap(std::move(interfaceMap)) {}
157 
158  /// Returns true if this is a registered operation.
159  bool isRegistered() const { return typeID != TypeID::get<void>(); }
161  Dialect *getDialect() const { return dialect; }
162  StringAttr getName() const { return name; }
163  TypeID getTypeID() const { return typeID; }
165 
166  protected:
167  //===------------------------------------------------------------------===//
168  // Registered Operation Info
169 
170  /// The name of the operation.
171  StringAttr name;
172 
173  /// The unique identifier of the derived Op class.
175 
176  /// The following fields are only populated when the operation is
177  /// registered.
178 
179  /// This is the dialect that this operation belongs to.
181 
182  /// A map of interfaces that were registered to this operation.
184 
185  /// A list of attribute names registered to this operation in StringAttr
186  /// form. This allows for operation classes to use StringAttr for attribute
187  /// lookup/creation/etc., as opposed to raw strings.
189 
191  };
192 
193 protected:
194  /// Default implementation for unregistered operations.
195  struct UnregisteredOpModel : public Impl {
196  using Impl::Impl;
200  bool hasTrait(TypeID) final;
202  void populateDefaultAttrs(const OperationName &, NamedAttrList &) final;
203  void printAssembly(Operation *, OpAsmPrinter &, StringRef) final;
206  /// Implementation for properties
207  std::optional<Attribute> getInherentAttr(Operation *op,
208  StringRef name) final;
209  void setInherentAttr(Operation *op, StringAttr name, Attribute value) final;
210  void populateInherentAttrs(Operation *op, NamedAttrList &attrs) final;
212  verifyInherentAttrs(OperationName opName, NamedAttrList &attributes,
213  function_ref<InFlightDiagnostic()> getDiag) final;
214  int getOpPropertyByteSize() final;
215  void initProperties(OperationName opName, OpaqueProperties storage,
216  OpaqueProperties init) final;
219  OpaqueProperties properties) final;
222  function_ref<InFlightDiagnostic &()> getDiag) final;
226  llvm::hash_code hashProperties(OpaqueProperties) final;
227  };
228 
229 public:
230  OperationName(StringRef name, MLIRContext *context);
231 
232  /// Return if this operation is registered.
233  bool isRegistered() const { return getImpl()->isRegistered(); }
234 
235  /// Return the unique identifier of the derived Op class, or null if not
236  /// registered.
237  TypeID getTypeID() const { return getImpl()->getTypeID(); }
238 
239  /// If this operation is registered, returns the registered information,
240  /// std::nullopt otherwise.
241  std::optional<RegisteredOperationName> getRegisteredInfo() const;
242 
243  /// This hook implements a generalized folder for this operation. Operations
244  /// can implement this to provide simplifications rules that are applied by
245  /// the Builder::createOrFold API and the canonicalization pass.
246  ///
247  /// This is an intentionally limited interface - implementations of this
248  /// hook can only perform the following changes to the operation:
249  ///
250  /// 1. They can leave the operation alone and without changing the IR, and
251  /// return failure.
252  /// 2. They can mutate the operation in place, without changing anything
253  /// else
254  /// in the IR. In this case, return success.
255  /// 3. They can return a list of existing values that can be used instead
256  /// of
257  /// the operation. In this case, fill in the results list and return
258  /// success. The caller will remove the operation and use those results
259  /// instead.
260  ///
261  /// This allows expression of some simple in-place canonicalizations (e.g.
262  /// "x+0 -> x", "min(x,y,x,z) -> min(x,y,z)", "x+y-x -> y", etc), as well as
263  /// generalized constant folding.
265  SmallVectorImpl<OpFoldResult> &results) const {
266  return getImpl()->foldHook(op, operands, results);
267  }
268 
269  /// This hook returns any canonicalization pattern rewrites that the
270  /// operation supports, for use by the canonicalization pass.
272  MLIRContext *context) const {
273  return getImpl()->getCanonicalizationPatterns(results, context);
274  }
275 
276  /// Returns true if the operation was registered with a particular trait, e.g.
277  /// hasTrait<OperandsAreSignlessIntegerLike>(). Returns false if the operation
278  /// is unregistered.
279  template <template <typename T> class Trait>
280  bool hasTrait() const {
281  return hasTrait(TypeID::get<Trait>());
282  }
283  bool hasTrait(TypeID traitID) const { return getImpl()->hasTrait(traitID); }
284 
285  /// Returns true if the operation *might* have the provided trait. This
286  /// means that either the operation is unregistered, or it was registered with
287  /// the provide trait.
288  template <template <typename T> class Trait>
289  bool mightHaveTrait() const {
290  return mightHaveTrait(TypeID::get<Trait>());
291  }
292  bool mightHaveTrait(TypeID traitID) const {
293  return !isRegistered() || getImpl()->hasTrait(traitID);
294  }
295 
296  /// Return the static hook for parsing this operation assembly.
298  return getImpl()->getParseAssemblyFn();
299  }
300 
301  /// This hook implements the method to populate defaults attributes that are
302  /// unset.
303  void populateDefaultAttrs(NamedAttrList &attrs) const {
304  getImpl()->populateDefaultAttrs(*this, attrs);
305  }
306 
307  /// This hook implements the AsmPrinter for this operation.
309  StringRef defaultDialect) const {
310  return getImpl()->printAssembly(op, p, defaultDialect);
311  }
312 
313  /// These hooks implement the verifiers for this operation. It should emits
314  /// an error message and returns failure if a problem is detected, or
315  /// returns success if everything is ok.
317  return getImpl()->verifyInvariants(op);
318  }
320  return getImpl()->verifyRegionInvariants(op);
321  }
322 
323  /// Return the list of cached attribute names registered to this operation.
324  /// The order of attributes cached here is unique to each type of operation,
325  /// and the interpretation of this attribute list should generally be driven
326  /// by the respective operation. In many cases, this caching removes the
327  /// need to use the raw string name of a known attribute.
328  ///
329  /// For example the ODS generator, with an op defining the following
330  /// attributes:
331  ///
332  /// let arguments = (ins I32Attr:$attr1, I32Attr:$attr2);
333  ///
334  /// ... may produce an order here of ["attr1", "attr2"]. This allows for the
335  /// ODS generator to directly access the cached name for a known attribute,
336  /// greatly simplifying the cost and complexity of attribute usage produced
337  /// by the generator.
338  ///
340  return getImpl()->getAttributeNames();
341  }
342 
343  /// Returns an instance of the concept object for the given interface if it
344  /// was registered to this operation, null otherwise. This should not be used
345  /// directly.
346  template <typename T>
347  typename T::Concept *getInterface() const {
348  return getImpl()->getInterfaceMap().lookup<T>();
349  }
350 
351  /// Attach the given models as implementations of the corresponding
352  /// interfaces for the concrete operation.
353  template <typename... Models>
355  // Handle the case where the models resolve a promised interface.
357  *getDialect(), getTypeID(), Models::Interface::getInterfaceID()),
358  ...);
359 
360  getImpl()->getInterfaceMap().insertModels<Models...>();
361  }
362 
363  /// Returns true if `InterfaceT` has been promised by the dialect or
364  /// implemented.
365  template <typename InterfaceT>
368  getDialect(), getTypeID(), InterfaceT::getInterfaceID()) ||
369  hasInterface<InterfaceT>();
370  }
371 
372  /// Returns true if this operation has the given interface registered to it.
373  template <typename T>
374  bool hasInterface() const {
375  return hasInterface(TypeID::get<T>());
376  }
377  bool hasInterface(TypeID interfaceID) const {
378  return getImpl()->getInterfaceMap().contains(interfaceID);
379  }
380 
381  /// Returns true if the operation *might* have the provided interface. This
382  /// means that either the operation is unregistered, or it was registered with
383  /// the provide interface.
384  template <typename T>
385  bool mightHaveInterface() const {
386  return mightHaveInterface(TypeID::get<T>());
387  }
388  bool mightHaveInterface(TypeID interfaceID) const {
389  return !isRegistered() || hasInterface(interfaceID);
390  }
391 
392  /// Lookup an inherent attribute by name, this method isn't recommended
393  /// and may be removed in the future.
394  std::optional<Attribute> getInherentAttr(Operation *op,
395  StringRef name) const {
396  return getImpl()->getInherentAttr(op, name);
397  }
398 
399  void setInherentAttr(Operation *op, StringAttr name, Attribute value) const {
400  return getImpl()->setInherentAttr(op, name, value);
401  }
402 
404  return getImpl()->populateInherentAttrs(op, attrs);
405  }
406  /// This method exists for backward compatibility purpose when using
407  /// properties to store inherent attributes, it enables validating the
408  /// attributes when parsed from the older generic syntax pre-Properties.
411  function_ref<InFlightDiagnostic()> getDiag) const {
412  return getImpl()->verifyInherentAttrs(*this, attributes, getDiag);
413  }
414  /// This hooks return the number of bytes to allocate for the op properties.
415  int getOpPropertyByteSize() const {
416  return getImpl()->getOpPropertyByteSize();
417  }
418 
419  /// This hooks destroy the op properties.
420  void destroyOpProperties(OpaqueProperties properties) const {
421  getImpl()->deleteProperties(properties);
422  }
423 
424  /// Initialize the op properties.
426  getImpl()->initProperties(*this, storage, init);
427  }
428 
429  /// Set the default values on the ODS attribute in the properties.
431  getImpl()->populateDefaultProperties(*this, properties);
432  }
433 
434  /// Return the op properties converted to an Attribute.
436  return getImpl()->getPropertiesAsAttr(op);
437  }
438 
439  /// Define the op properties from the provided Attribute.
441  OperationName opName, OpaqueProperties properties, Attribute attr,
442  function_ref<InFlightDiagnostic &()> getDiag) const {
443  return getImpl()->setPropertiesFromAttr(opName, properties, attr, getDiag);
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()) {}
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  }
557  return ConcreteOp::getVerifyInvariantsFn()(op);
558  }
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  }
599  function_ref<InFlightDiagnostic()> getDiag) final {
600  if constexpr (hasProperties)
601  return ConcreteOp::verifyInherentAttrs(opName, attributes, getDiag);
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 
638  Attribute attr,
639  function_ref<InFlightDiagnostic &()> getDiag) final {
640  if constexpr (hasProperties) {
641  auto p = properties.as<Properties *>();
642  return ConcreteOp::setPropertiesFromAttr(*p, attr, getDiag);
643  }
644  getDiag() << "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  /// Register a new operation in a Dialect object.
679  /// This constructor is used by Dialect objects when they register the list
680  /// of operations they contain.
681  template <typename T>
682  static void insert(Dialect &dialect) {
683  insert(std::make_unique<Model<T>>(&dialect), T::getAttributeNames());
684  }
685  /// The use of this method is in general discouraged in favor of
686  /// 'insert<CustomOp>(dialect)'.
687  static void insert(std::unique_ptr<OperationName::Impl> ownedImpl,
688  ArrayRef<StringRef> attrNames);
689 
690  /// Return the dialect this operation is registered to.
691  Dialect &getDialect() const { return *getImpl()->getDialect(); }
692 
693  /// Use the specified object to parse this ops custom assembly format.
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  // If we're creating an unregistered operation, this Attribute is used to
958  // build the properties. Otherwise it is ignored. For registered operations
959  // see the `getOrAddProperties` method.
961 
962 private:
963  OpaqueProperties properties = nullptr;
964  TypeID propertiesId;
965  llvm::function_ref<void(OpaqueProperties)> propertiesDeleter;
967  propertiesSetter;
968  friend class Operation;
969 
970 public:
971  OperationState(Location location, StringRef name);
973 
976  BlockRange successors = {},
977  MutableArrayRef<std::unique_ptr<Region>> regions = {});
978  OperationState(Location location, StringRef name, ValueRange operands,
979  TypeRange types, ArrayRef<NamedAttribute> attributes = {},
980  BlockRange successors = {},
981  MutableArrayRef<std::unique_ptr<Region>> regions = {});
982  OperationState(OperationState &&other) = default;
983  OperationState(const OperationState &other) = default;
985  OperationState &operator=(const OperationState &other) = default;
986  ~OperationState();
987 
988  /// Get (or create) a properties of the provided type to be set on the
989  /// operation on creation.
990  template <typename T>
992  if (!properties) {
993  T *p = new T{};
994  properties = p;
995  propertiesDeleter = [](OpaqueProperties prop) {
996  delete prop.as<const T *>();
997  };
998  propertiesSetter = [](OpaqueProperties new_prop,
999  const OpaqueProperties prop) {
1000  *new_prop.as<T *>() = *prop.as<const T *>();
1001  };
1002  propertiesId = TypeID::get<T>();
1003  }
1004  assert(propertiesId == TypeID::get<T>() && "Inconsistent properties");
1005  return *properties.as<T *>();
1006  }
1007  OpaqueProperties getRawProperties() { return properties; }
1008 
1009  // Set the properties defined on this OpState on the given operation,
1010  // optionally emit diagnostics on error through the provided diagnostic.
1013  function_ref<InFlightDiagnostic &()> getDiag) const;
1014 
1015  void addOperands(ValueRange newOperands);
1016 
1017  void addTypes(ArrayRef<Type> newTypes) {
1018  types.append(newTypes.begin(), newTypes.end());
1019  }
1020  template <typename RangeT>
1021  std::enable_if_t<!std::is_convertible<RangeT, ArrayRef<Type>>::value>
1022  addTypes(RangeT &&newTypes) {
1023  types.append(newTypes.begin(), newTypes.end());
1024  }
1025 
1026  /// Add an attribute with the specified name.
1027  void addAttribute(StringRef name, Attribute attr) {
1029  }
1030 
1031  /// Add an attribute with the specified name.
1032  void addAttribute(StringAttr name, Attribute attr) {
1033  attributes.append(name, attr);
1034  }
1035 
1036  /// Add an array of named attributes.
1038  attributes.append(newAttributes);
1039  }
1040 
1041  void addSuccessors(Block *successor) { successors.push_back(successor); }
1042  void addSuccessors(BlockRange newSuccessors);
1043 
1044  /// Create a region that should be attached to the operation. These regions
1045  /// can be filled in immediately without waiting for Operation to be
1046  /// created. When it is, the region bodies will be transferred.
1047  Region *addRegion();
1048 
1049  /// Take a region that should be attached to the Operation. The body of the
1050  /// region will be transferred when the Operation is constructed. If the
1051  /// region is null, a new empty region will be attached to the Operation.
1052  void addRegion(std::unique_ptr<Region> &&region);
1053 
1054  /// Take ownership of a set of regions that should be attached to the
1055  /// Operation.
1056  void addRegions(MutableArrayRef<std::unique_ptr<Region>> regions);
1057 
1058  /// Get the context held by this operation state.
1059  MLIRContext *getContext() const { return location->getContext(); }
1060 };
1061 
1062 //===----------------------------------------------------------------------===//
1063 // OperandStorage
1064 //===----------------------------------------------------------------------===//
1065 
1066 namespace detail {
1067 /// This class handles the management of operation operands. Operands are
1068 /// stored either in a trailing array, or a dynamically resizable vector.
1069 class alignas(8) OperandStorage {
1070 public:
1071  OperandStorage(Operation *owner, OpOperand *trailingOperands,
1072  ValueRange values);
1073  ~OperandStorage();
1074 
1075  /// Replace the operands contained in the storage with the ones provided in
1076  /// 'values'.
1077  void setOperands(Operation *owner, ValueRange values);
1078 
1079  /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
1080  /// with the ones provided in 'operands'. 'operands' may be smaller or larger
1081  /// than the range pointed to by 'start'+'length'.
1082  void setOperands(Operation *owner, unsigned start, unsigned length,
1083  ValueRange operands);
1084 
1085  /// Erase the operands held by the storage within the given range.
1086  void eraseOperands(unsigned start, unsigned length);
1087 
1088  /// Erase the operands held by the storage that have their corresponding bit
1089  /// set in `eraseIndices`.
1090  void eraseOperands(const BitVector &eraseIndices);
1091 
1092  /// Get the operation operands held by the storage.
1093  MutableArrayRef<OpOperand> getOperands() { return {operandStorage, size()}; }
1094 
1095  /// Return the number of operands held in the storage.
1096  unsigned size() { return numOperands; }
1097 
1098 private:
1099  /// Resize the storage to the given size. Returns the array containing the new
1100  /// operands.
1101  MutableArrayRef<OpOperand> resize(Operation *owner, unsigned newSize);
1102 
1103  /// The total capacity number of operands that the storage can hold.
1104  unsigned capacity : 31;
1105  /// A flag indicating if the operand storage was dynamically allocated, as
1106  /// opposed to inlined into the owning operation.
1107  unsigned isStorageDynamic : 1;
1108  /// The number of operands within the storage.
1109  unsigned numOperands;
1110  /// A pointer to the operand storage.
1111  OpOperand *operandStorage;
1112 };
1113 } // namespace detail
1114 
1115 //===----------------------------------------------------------------------===//
1116 // OpPrintingFlags
1117 //===----------------------------------------------------------------------===//
1118 
1119 /// Set of flags used to control the behavior of the various IR print methods
1120 /// (e.g. Operation::Print).
1122 public:
1123  OpPrintingFlags();
1124  OpPrintingFlags(std::nullopt_t) : OpPrintingFlags() {}
1125 
1126  /// Enables the elision of large elements attributes by printing a lexically
1127  /// valid but otherwise meaningless form instead of the element data. The
1128  /// `largeElementLimit` is used to configure what is considered to be a
1129  /// "large" ElementsAttr by providing an upper limit to the number of
1130  /// elements.
1131  OpPrintingFlags &elideLargeElementsAttrs(int64_t largeElementLimit = 16);
1132 
1133  /// Enable or disable printing of debug information (based on `enable`). If
1134  /// 'prettyForm' is set to true, debug information is printed in a more
1135  /// readable 'pretty' form. Note: The IR generated with 'prettyForm' is not
1136  /// parsable.
1137  OpPrintingFlags &enableDebugInfo(bool enable = true, bool prettyForm = false);
1138 
1139  /// Always print operations in the generic form.
1140  OpPrintingFlags &printGenericOpForm(bool enable = true);
1141 
1142  /// Skip printing regions.
1143  OpPrintingFlags &skipRegions(bool skip = true);
1144 
1145  /// Do not verify the operation when using custom operation printers.
1147 
1148  /// Use local scope when printing the operation. This allows for using the
1149  /// printer in a more localized and thread-safe setting, but may not
1150  /// necessarily be identical to what the IR will look like when dumping
1151  /// the full module.
1153 
1154  /// Print users of values as comments.
1156 
1157  /// Return if the given ElementsAttr should be elided.
1158  bool shouldElideElementsAttr(ElementsAttr attr) const;
1159 
1160  /// Return the size limit for printing large ElementsAttr.
1161  std::optional<int64_t> getLargeElementsAttrLimit() const;
1162 
1163  /// Return the size limit in chars for printing large resources.
1164  std::optional<uint64_t> getLargeResourceStringLimit() const;
1165 
1166  /// Return if debug information should be printed.
1167  bool shouldPrintDebugInfo() const;
1168 
1169  /// Return if debug information should be printed in the pretty form.
1170  bool shouldPrintDebugInfoPrettyForm() const;
1171 
1172  /// Return if operations should be printed in the generic form.
1173  bool shouldPrintGenericOpForm() const;
1174 
1175  /// Return if regions should be skipped.
1176  bool shouldSkipRegions() const;
1177 
1178  /// Return if operation verification should be skipped.
1179  bool shouldAssumeVerified() const;
1180 
1181  /// Return if the printer should use local scope when dumping the IR.
1182  bool shouldUseLocalScope() const;
1183 
1184  /// Return if the printer should print users of values.
1185  bool shouldPrintValueUsers() const;
1186 
1187 private:
1188  /// Elide large elements attributes if the number of elements is larger than
1189  /// the upper limit.
1190  std::optional<int64_t> elementsAttrElementLimit;
1191 
1192  /// Elide printing large resources based on size of string.
1193  std::optional<uint64_t> resourceStringCharLimit;
1194 
1195  /// Print debug information.
1196  bool printDebugInfoFlag : 1;
1197  bool printDebugInfoPrettyFormFlag : 1;
1198 
1199  /// Print operations in the generic form.
1200  bool printGenericOpFormFlag : 1;
1201 
1202  /// Always skip Regions.
1203  bool skipRegionsFlag : 1;
1204 
1205  /// Skip operation verification.
1206  bool assumeVerifiedFlag : 1;
1207 
1208  /// Print operations with numberings local to the current operation.
1209  bool printLocalScope : 1;
1210 
1211  /// Print users of values.
1212  bool printValueUsersFlag : 1;
1213 };
1214 
1215 //===----------------------------------------------------------------------===//
1216 // Operation Equivalency
1217 //===----------------------------------------------------------------------===//
1218 
1219 /// This class provides utilities for computing if two operations are
1220 /// equivalent.
1222  enum Flags {
1223  None = 0,
1224 
1225  // When provided, the location attached to the operation are ignored.
1227 
1228  LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreLocations)
1229  };
1230 
1231  /// Compute a hash for the given operation.
1232  /// The `hashOperands` and `hashResults` callbacks are expected to return a
1233  /// unique hash_code for a given Value.
1234  static llvm::hash_code computeHash(
1235  Operation *op,
1236  function_ref<llvm::hash_code(Value)> hashOperands =
1237  [](Value v) { return hash_value(v); },
1238  function_ref<llvm::hash_code(Value)> hashResults =
1239  [](Value v) { return hash_value(v); },
1240  Flags flags = Flags::None);
1241 
1242  /// Helper that can be used with `computeHash` above to ignore operation
1243  /// operands/result mapping.
1244  static llvm::hash_code ignoreHashValue(Value) { return llvm::hash_code{}; }
1245  /// Helper that can be used with `computeHash` above to ignore operation
1246  /// operands/result mapping.
1247  static llvm::hash_code directHashValue(Value v) { return hash_value(v); }
1248 
1249  /// Compare two operations (including their regions) and return if they are
1250  /// equivalent.
1251  ///
1252  /// * `checkEquivalent` is a callback to check if two values are equivalent.
1253  /// For two operations to be equivalent, their operands must be the same SSA
1254  /// value or this callback must return `success`.
1255  /// * `markEquivalent` is a callback to inform the caller that the analysis
1256  /// determined that two values are equivalent.
1257  ///
1258  /// Note: Additional information regarding value equivalence can be injected
1259  /// into the analysis via `checkEquivalent`. Typically, callers may want
1260  /// values that were determined to be equivalent as per `markEquivalent` to be
1261  /// reflected in `checkEquivalent`, unless `exactValueMatch` or a different
1262  /// equivalence relationship is desired.
1263  static bool
1264  isEquivalentTo(Operation *lhs, Operation *rhs,
1265  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1266  function_ref<void(Value, Value)> markEquivalent = nullptr,
1267  Flags flags = Flags::None);
1268 
1269  /// Compare two operations and return if they are equivalent.
1270  static bool isEquivalentTo(Operation *lhs, Operation *rhs, Flags flags);
1271 
1272  /// Compare two regions (including their subregions) and return if they are
1273  /// equivalent. See also `isEquivalentTo` for details.
1274  static bool isRegionEquivalentTo(
1275  Region *lhs, Region *rhs,
1276  function_ref<LogicalResult(Value, Value)> checkEquivalent,
1277  function_ref<void(Value, Value)> markEquivalent,
1279 
1280  /// Compare two regions and return if they are equivalent.
1281  static bool isRegionEquivalentTo(Region *lhs, Region *rhs,
1283 
1284  /// Helper that can be used with `isEquivalentTo` above to consider ops
1285  /// equivalent even if their operands are not equivalent.
1287  return success();
1288  }
1289  /// Helper that can be used with `isEquivalentTo` above to consider ops
1290  /// equivalent only if their operands are the exact same SSA values.
1292  return success(lhs == rhs);
1293  }
1294 };
1295 
1296 /// Enable Bitmask enums for OperationEquivalence::Flags.
1298 
1299 //===----------------------------------------------------------------------===//
1300 // OperationFingerPrint
1301 //===----------------------------------------------------------------------===//
1302 
1303 /// A unique fingerprint for a specific operation, and all of it's internal
1304 /// operations.
1306 public:
1310 
1311  bool operator==(const OperationFingerPrint &other) const {
1312  return hash == other.hash;
1313  }
1314  bool operator!=(const OperationFingerPrint &other) const {
1315  return !(*this == other);
1316  }
1317 
1318 private:
1319  std::array<uint8_t, 20> hash;
1320 };
1321 
1322 } // namespace mlir
1323 
1324 namespace llvm {
1325 template <>
1326 struct DenseMapInfo<mlir::OperationName> {
1328  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1330  }
1334  }
1335  static unsigned getHashValue(mlir::OperationName val) {
1337  }
1339  return lhs == rhs;
1340  }
1341 };
1342 template <>
1343 struct DenseMapInfo<mlir::RegisteredOperationName>
1344  : public DenseMapInfo<mlir::OperationName> {
1346  void *pointer = llvm::DenseMapInfo<void *>::getEmptyKey();
1348  }
1352  }
1353 };
1354 
1355 template <>
1356 struct PointerLikeTypeTraits<mlir::OperationName> {
1357  static inline void *getAsVoidPointer(mlir::OperationName I) {
1358  return const_cast<void *>(I.getAsOpaquePointer());
1359  }
1360  static inline mlir::OperationName getFromVoidPointer(void *P) {
1362  }
1363  static constexpr int NumLowBitsAvailable =
1364  PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
1365 };
1366 template <>
1367 struct PointerLikeTypeTraits<mlir::RegisteredOperationName>
1368  : public PointerLikeTypeTraits<mlir::OperationName> {
1371  }
1372 };
1373 
1374 } // namespace llvm
1375 
1376 #endif
@ None
Attributes are known-constant values of operations.
Definition: Attributes.h:25
MLIRContext * getContext() const
Return the context this attribute belongs to.
Definition: Attributes.cpp:37
This class provides an abstraction over the different types of ranges over Blocks.
Definition: BlockSupport.h:106
Block represents an ordered list of Operations.
Definition: Block.h:30
Dialects are groups of MLIR operations, types and attributes, as well as behavior associated with the...
Definition: Dialect.h:41
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:308
This class defines the main interface for locations in MLIR and acts as a non-nullable wrapper around...
Definition: Location.h:63
This is the implementation of the MLIRContext class, using the pImpl idiom.
MLIRContext is the top-level object for a collection of MLIR operations.
Definition: MLIRContext.h:60
NamedAttrList is array of NamedAttributes that tracks whether it is sorted and does some basic work t...
std::optional< NamedAttribute > getNamed(StringRef name) const
Return the specified named attribute if present, std::nullopt otherwise.
void append(IteratorT inStart, IteratorT inEnd)
Add a range of named attributes.
void assign(ArrayRef< NamedAttribute > range)
Replaces the attributes with new list of attributes.
const_iterator begin() const
void assign(const_iterator inStart, const_iterator inEnd)
Replaces the attributes with new list of attributes.
SmallVectorImpl< NamedAttribute >::const_iterator const_iterator
void append(NamedAttribute attr)
Append the given named attribute.
bool operator!=(const NamedAttrList &other) const
ArrayRef< NamedAttribute > getAttrs() const
Return all of the attributes on this operation.
DictionaryAttr getDictionary(MLIRContext *context) const
Return a dictionary attribute for the underlying dictionary.
void push_back(NamedAttribute newAttribute)
Add an attribute with the specified name.
SmallVectorImpl< NamedAttribute >::iterator iterator
const_iterator end() const
NamedAttrList(const Container &vec)
void append(StringAttr name, Attribute attr)
Add an attribute with the specified name.
void pop_back()
Pop last element from list.
bool operator==(const NamedAttrList &other) const
Attribute get(StringAttr name) const
Return the specified attribute if present, null otherwise.
Attribute erase(StringAttr name)
Erase the attribute with the given name from the list.
std::optional< NamedAttribute > findDuplicate() const
Returns an entry with a duplicate name the list, if it exists, else returns std::nullopt.
Attribute set(StringAttr name, Attribute value)
If the an attribute exists with the specified name, change it to the new value.
void append(RangeT &&newAttributes)
Add an array of named attributes.
void reserve(size_type N)
void append(StringRef name, Attribute attr)
Add an attribute with the specified name.
NamedAttrList & operator=(const SmallVectorImpl< NamedAttribute > &rhs)
NamedAttrList(std::nullopt_t none)
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:198
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:261
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:262
std::optional< int64_t > getLargeElementsAttrLimit() const
Return the size limit for printing large ElementsAttr.
Definition: AsmPrinter.cpp:269
bool shouldAssumeVerified() const
Return if operation verification should be skipped.
Definition: AsmPrinter.cpp:297
OpPrintingFlags & printValueUsers()
Print users of values as comments.
Definition: AsmPrinter.cpp:256
bool shouldUseLocalScope() const
Return if the printer should use local scope when dumping the IR.
Definition: AsmPrinter.cpp:302
bool shouldPrintDebugInfoPrettyForm() const
Return if debug information should be printed in the pretty form.
Definition: AsmPrinter.cpp:284
bool shouldPrintValueUsers() const
Return if the printer should print users of values.
Definition: AsmPrinter.cpp:305
bool shouldPrintGenericOpForm() const
Return if operations should be printed in the generic form.
Definition: AsmPrinter.cpp:289
bool shouldPrintDebugInfo() const
Return if debug information should be printed.
Definition: AsmPrinter.cpp:279
OpPrintingFlags & elideLargeElementsAttrs(int64_t largeElementLimit=16)
Enables the elision of large elements attributes by printing a lexically valid but otherwise meaningl...
Definition: AsmPrinter.cpp:215
OpPrintingFlags & enableDebugInfo(bool enable=true, bool prettyForm=false)
Enable or disable printing of debug information (based on enable).
Definition: AsmPrinter.cpp:222
OpPrintingFlags()
Initialize the printing flags with default supplied by the cl::opts above.
Definition: AsmPrinter.cpp:190
bool shouldSkipRegions() const
Return if regions should be skipped.
Definition: AsmPrinter.cpp:294
OpPrintingFlags & printGenericOpForm(bool enable=true)
Always print operations in the generic form.
Definition: AsmPrinter.cpp:230
OpPrintingFlags & assumeVerified()
Do not verify the operation when using custom operation printers.
Definition: AsmPrinter.cpp:242
OpPrintingFlags(std::nullopt_t)
std::optional< uint64_t > getLargeResourceStringLimit() const
Return the size limit in chars for printing large resources.
Definition: AsmPrinter.cpp:274
OpPrintingFlags & useLocalScope()
Use local scope when printing the operation.
Definition: AsmPrinter.cpp:250
OpPrintingFlags & skipRegions(bool skip=true)
Skip printing regions.
Definition: AsmPrinter.cpp:236
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.
bool operator!=(const OperationFingerPrint &other) const
OperationFingerPrint & operator=(const OperationFingerPrint &)=default
OperationFingerPrint(Operation *topOp)
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:58
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()> getDiag) 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 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:56
void copyOpProperties(OpaqueProperties lhs, OpaqueProperties rhs) const
bool hasInterface(TypeID interfaceID) const
LogicalResult setOpPropertiesFromAttribute(OperationName opName, OpaqueProperties properties, Attribute attr, function_ref< InFlightDiagnostic &()> getDiag) const
Define the op properties from the provided Attribute.
static OperationName getFromOpaquePointer(const void *pointer)
void attachInterface()
Attach the given models as implementations of the corresponding interfaces for the concrete operation...
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
This class represents success/failure for parsing-like operations that find it important to chain tog...
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
This is a "type erased" representation of a registered operation.
static void insert(Dialect &dialect)
Register a new operation in a Dialect object.
static RegisteredOperationName getFromOpaquePointer(const void *pointer)
Represent the operation name as an opaque pointer.
static std::optional< RegisteredOperationName > lookup(StringRef name, MLIRContext *ctx)
Lookup the registered operation information for the given operation.
ParseResult parseAssembly(OpAsmParser &parser, OperationState &result) const
Use the specified object to parse this ops custom assembly format.
static void insert(std::unique_ptr< OperationName::Impl > ownedImpl, ArrayRef< StringRef > attrNames)
The use of this method is in general discouraged in favor of 'insert<CustomOp>(dialect)'.
Dialect & getDialect() const
Return the dialect this operation is registered to.
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
This class provides an abstraction over the various different ranges of value types.
Definition: TypeRange.h:36
This class provides an abstraction over the different types of ranges over Values.
Definition: ValueRange.h:372
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:93
This class provides an efficient mapping between a given Interface type, and a particular implementat...
void insertModels()
Insert the given interface models.
bool contains(TypeID interfaceID) const
Returns true if the interface map contains an interface for the given id.
T::Concept * lookup() const
Returns an instance of the concept object for the given interface if it was registered to this map,...
This class handles the management of operation operands.
MutableArrayRef< OpOperand > getOperands()
Get the operation operands held by the storage.
void eraseOperands(unsigned start, unsigned length)
Erase the operands held by the storage within the given range.
unsigned size()
Return the number of operands held in the storage.
void setOperands(Operation *owner, ValueRange values)
Replace the operands contained in the storage with the ones provided in 'values'.
OperandStorage(Operation *owner, OpOperand *trailingOperands, ValueRange values)
Include the generated interface declarations.
Definition: CallGraph.h:229
bool hasPromisedInterface(Dialect &dialect, TypeID interfaceRequestorID, TypeID interfaceID)
Checks if a promise has been made for the interface/requestor pair.
Definition: Dialect.cpp:166
void handleAdditionOfUndefinedPromisedInterface(Dialect &dialect, TypeID interfaceRequestorID, TypeID interfaceID)
Checks if the given interface, which is attempting to be attached, is a promised interface of this di...
Definition: Dialect.cpp:160
std::optional< NamedAttribute > getNamedAttrFromSortedRange(IteratorT first, IteratorT last, NameT name)
Get an attribute from a sorted range of named attributes.
Attribute getAttrFromSortedRange(IteratorT first, IteratorT last, NameT name)
Get an attribute from a sorted range of named attributes.
std::pair< IteratorT, bool > findAttrSorted(IteratorT first, IteratorT last, StringRef name)
Using llvm::lower_bound requires an extra string comparison to check whether the returned iterator po...
std::pair< IteratorT, bool > findAttrUnsorted(IteratorT first, IteratorT last, NameT name)
Unsorted string search or identifier lookups are linear scans.
@ Type
An inlay hint that for a type annotation.
int compare(const Fraction &x, const Fraction &y)
Three-way comparison between two fractions.
Definition: Fraction.h:63
This header declares functions that assist transformations in the MemRef dialect.
LogicalResult failure(bool isFailure=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:62
llvm::function_ref< Fn > function_ref
Definition: LLVM.h:147
LogicalResult success(bool isSuccess=true)
Utility function to generate a LogicalResult.
Definition: LogicalResult.h:56
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
inline ::llvm::hash_code hash_value(AffineExpr arg)
Make AffineExpr hashable.
Definition: AffineExpr.h:240
llvm::hash_code hash_value(OperationName arg)
raw_ostream & operator<<(raw_ostream &os, const AliasResult &result)
Definition: AliasAnalysis.h:78
LLVM_ENABLE_BITMASK_ENUMS_IN_NAMESPACE()
Enable Bitmask enums for OperationEquivalence::Flags.
static mlir::OperationName getTombstoneKey()
static mlir::OperationName getEmptyKey()
static bool isEqual(mlir::OperationName lhs, mlir::OperationName rhs)
static unsigned getHashValue(mlir::OperationName val)
static mlir::RegisteredOperationName getEmptyKey()
static mlir::RegisteredOperationName getTombstoneKey()
static mlir::OperationName getFromVoidPointer(void *P)
static void * getAsVoidPointer(mlir::OperationName I)
static mlir::RegisteredOperationName getFromVoidPointer(void *P)
Structure used by default as a "marker" when no "Properties" are set on an Operation.
Definition: OpDefinition.h:77
This class represents an efficient way to signal success or failure.
Definition: LogicalResult.h:26
This class provides utilities for computing if two operations are equivalent.
static llvm::hash_code ignoreHashValue(Value)
Helper that can be used with computeHash above to ignore operation operands/result mapping.
static bool isRegionEquivalentTo(Region *lhs, Region *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent, OperationEquivalence::Flags flags)
Compare two regions (including their subregions) 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.
static bool isEquivalentTo(Operation *lhs, Operation *rhs, function_ref< LogicalResult(Value, Value)> checkEquivalent, function_ref< void(Value, Value)> markEquivalent=nullptr, Flags flags=Flags::None)
Compare two operations (including their regions) and return if they are equivalent.
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 setPropertiesFromAttr(OperationName, OpaqueProperties, Attribute, function_ref< InFlightDiagnostic &()> getDiag)=0
virtual LogicalResult verifyInvariants(Operation *)=0
virtual LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> getDiag)=0
virtual void setInherentAttr(Operation *op, StringAttr name, Attribute value)=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 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 verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> getDiag) 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 setPropertiesFromAttr(OperationName, OpaqueProperties, Attribute, function_ref< InFlightDiagnostic &()> getDiag) final
LogicalResult verifyInvariants(Operation *) final
void copyProperties(OpaqueProperties, OpaqueProperties) final
Attribute getPropertiesAsAttr(Operation *) final
bool compareProperties(OpaqueProperties, OpaqueProperties) final
This represents an operation in an abstracted form, suitable for use with the builder APIs.
OperationState(const OperationState &other)=default
void addRegions(MutableArrayRef< std::unique_ptr< Region >> regions)
Take ownership of a set of regions that should be attached to the Operation.
OpaqueProperties getRawProperties()
SmallVector< Block *, 1 > successors
Successors of this operation and their respective operands.
T & getOrAddProperties()
Get (or create) a properties of the provided type to be set on the operation on creation.
SmallVector< Value, 4 > operands
void addOperands(ValueRange newOperands)
void addAttributes(ArrayRef< NamedAttribute > newAttributes)
Add an array of named attributes.
void addAttribute(StringRef name, Attribute attr)
Add an attribute with the specified name.
void addAttribute(StringAttr name, Attribute attr)
Add an attribute with the specified name.
std::enable_if_t<!std::is_convertible< RangeT, ArrayRef< Type > >::value > addTypes(RangeT &&newTypes)
void addSuccessors(Block *successor)
void addTypes(ArrayRef< Type > newTypes)
OperationState(OperationState &&other)=default
SmallVector< std::unique_ptr< Region >, 1 > regions
Regions that the op will hold.
NamedAttrList attributes
LogicalResult setProperties(Operation *op, function_ref< InFlightDiagnostic &()> getDiag) const
OperationState(Location location, StringRef name)
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
Implementation of the InterfaceConcept for operation APIs that forwarded to a concrete op implementat...
void initProperties(OperationName opName, OpaqueProperties storage, OpaqueProperties init) final
void copyProperties(OpaqueProperties lhs, OpaqueProperties rhs) final
LogicalResult verifyInherentAttrs(OperationName opName, NamedAttrList &attributes, function_ref< InFlightDiagnostic()> getDiag) 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
LogicalResult setPropertiesFromAttr(OperationName opName, OpaqueProperties properties, Attribute attr, function_ref< InFlightDiagnostic &()> getDiag) final
std::remove_reference_t< decltype(std::declval< ConcreteOp >().getProperties())> Properties
Implementation for "Properties".
Attribute getPropertiesAsAttr(Operation *op) 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.