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