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