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 void dump() const;
545
546 /// Represent the operation name as an opaque pointer. (Used to support
547 /// PointerLikeTypeTraits).
548 void *getAsOpaquePointer() const { return const_cast<Impl *>(impl); }
549 static OperationName getFromOpaquePointer(const void *pointer) {
550 return OperationName(
551 const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
552 }
553
554 bool operator==(const OperationName &rhs) const { return impl == rhs.impl; }
555 bool operator!=(const OperationName &rhs) const { return !(*this == rhs); }
556
557protected:
559 Impl *getImpl() const { return impl; }
560 void setImpl(Impl *rhs) { impl = rhs; }
561
562private:
563 /// The internal implementation of the operation name.
564 Impl *impl = nullptr;
565
566 /// Allow access to the Impl struct.
567 friend MLIRContextImpl;
570};
571
573 info.print(os);
574 return os;
575}
576
577// Make operation names hashable.
578inline llvm::hash_code hash_value(OperationName arg) {
579 return llvm::hash_value(arg.getAsOpaquePointer());
580}
581
582//===----------------------------------------------------------------------===//
583// RegisteredOperationName
584//===----------------------------------------------------------------------===//
585
586/// This is a "type erased" representation of a registered operation. This
587/// should only be used by things like the AsmPrinter and other things that need
588/// to be parameterized by generic operation hooks. Most user code should use
589/// the concrete operation types.
590class RegisteredOperationName : public OperationName {
591public:
592 /// Implementation of the InterfaceConcept for operation APIs that forwarded
593 /// to a concrete op implementation.
594 template <typename ConcreteOp>
595 struct Model : public Impl {
596 using Properties = std::remove_reference_t<
597 decltype(std::declval<ConcreteOp>().getProperties())>;
599 : Impl(ConcreteOp::getOperationName(), dialect,
600 TypeID::get<ConcreteOp>(), ConcreteOp::getInterfaceMap()) {
602 }
603 LogicalResult foldHook(Operation *op, ArrayRef<Attribute> attrs,
604 SmallVectorImpl<OpFoldResult> &results) final {
605 return ConcreteOp::getFoldHookFn()(op, attrs, results);
606 }
608 MLIRContext *context) final {
609 ConcreteOp::getCanonicalizationPatterns(set, context);
610 }
611 bool hasTrait(TypeID id) final { return ConcreteOp::getHasTraitFn()(id); }
613 return ConcreteOp::parse;
614 }
615 void populateDefaultAttrs(const OperationName &name,
616 NamedAttrList &attrs) final {
617 ConcreteOp::populateDefaultAttrs(name, attrs);
618 }
620 StringRef name) final {
621 ConcreteOp::getPrintAssemblyFn()(op, printer, name);
622 }
623 LogicalResult verifyInvariants(Operation *op) final {
624 return ConcreteOp::getVerifyInvariantsFn()(op);
625 }
626 LogicalResult verifyRegionInvariants(Operation *op) final {
627 return ConcreteOp::getVerifyRegionInvariantsFn()(op);
628 }
629
630 /// Implementation for "Properties"
631
632 std::optional<Attribute> getInherentAttr(Operation *op,
633 StringRef name) final {
634 if constexpr (hasProperties) {
635 auto concreteOp = cast<ConcreteOp>(op);
636 return ConcreteOp::getInherentAttr(concreteOp->getContext(),
637 concreteOp.getProperties(), name);
638 }
639 return std::nullopt;
640 }
641 void setInherentAttr(Operation *op, StringAttr name,
642 Attribute value) final {
643 if constexpr (hasProperties) {
644 auto concreteOp = cast<ConcreteOp>(op);
645 return ConcreteOp::setInherentAttr(concreteOp.getProperties(), name,
646 value);
647 }
648 llvm_unreachable(
649 "Can't call setInherentAttr on operation with empty properties");
650 }
652 if constexpr (hasProperties) {
653 auto concreteOp = cast<ConcreteOp>(op);
654 ConcreteOp::walkInherentAttrs(concreteOp->getContext(),
655 concreteOp.getProperties(), visitor);
656 }
657 }
658 LogicalResult
659 verifyInherentAttrs(OperationName opName, NamedAttrList &attributes,
661 if constexpr (hasProperties)
662 return ConcreteOp::verifyInherentAttrs(opName, attributes, emitError);
663 return success();
664 }
665 // Detect if the concrete operation defined properties.
666 static constexpr bool hasProperties = !std::is_same_v<
667 typename ConcreteOp::template InferredProperties<ConcreteOp>,
669
671 if constexpr (hasProperties)
672 return sizeof(Properties);
673 return 0;
674 }
675 void initProperties(OperationName opName, PropertyRef storage,
676 PropertyRef init) final {
677 using Properties =
678 typename ConcreteOp::template InferredProperties<ConcreteOp>;
679 if (init)
680 new (storage.as<Properties *>()) Properties(*init.as<Properties *>());
681 else
682 new (storage.as<Properties *>()) Properties();
683 if constexpr (hasProperties)
684 ConcreteOp::populateDefaultProperties(opName,
685 *storage.as<Properties *>());
686 }
687 void deleteProperties(PropertyRef prop) final {
688 prop.as<Properties *>()->~Properties();
689 }
690 void populateDefaultProperties(OperationName opName,
691 PropertyRef properties) final {
692 if constexpr (hasProperties)
693 ConcreteOp::populateDefaultProperties(opName,
694 *properties.as<Properties *>());
695 }
696
697 LogicalResult
698 setPropertiesFromAttr(OperationName opName, PropertyRef properties,
699 Attribute attr,
701 if constexpr (hasProperties) {
702 auto p = properties.as<Properties *>();
703 return ConcreteOp::setPropertiesFromAttr(*p, attr, emitError);
704 }
705 emitError() << "this operation has empty properties";
706 return failure();
707 }
709 if constexpr (hasProperties) {
710 auto concreteOp = cast<ConcreteOp>(op);
711 return ConcreteOp::getPropertiesAsAttr(concreteOp->getContext(),
712 concreteOp.getProperties());
713 }
714 return {};
715 }
717 if constexpr (hasProperties)
718 return *lhs.as<Properties *>() == *rhs.as<Properties *>();
719 return true;
720 }
722 *lhs.as<Properties *>() = *rhs.as<Properties *>();
723 }
724 llvm::hash_code hashProperties(PropertyRef prop) final {
725 if constexpr (hasProperties)
726 return ConcreteOp::computePropertiesHash(*prop.as<Properties *>());
727
728 return {};
729 }
730 };
731
732 /// Lookup the registered operation information for the given operation.
733 /// Returns std::nullopt if the operation isn't registered.
734 static std::optional<RegisteredOperationName> lookup(StringRef name,
735 MLIRContext *ctx);
736
737 /// Lookup the registered operation information for the given operation.
738 /// Returns std::nullopt if the operation isn't registered.
739 static std::optional<RegisteredOperationName> lookup(TypeID typeID,
740 MLIRContext *ctx);
741
742 /// Register a new operation in a Dialect object.
743 /// This constructor is used by Dialect objects when they register the list
744 /// of operations they contain.
745 template <typename T>
746 static void insert(Dialect &dialect) {
747 static_assert(sizeof(Model<T>) == sizeof(Impl));
748 static_assert(alignof(Model<T>) == alignof(Impl));
749 std::unique_ptr<Impl> ownedModel(new (allocateModelStorage())
750 Model<T>(&dialect));
751 insert(std::move(ownedModel), T::getAttributeNames());
752 }
753 /// The use of this method is in general discouraged in favor of
754 /// 'insert<CustomOp>(dialect)'.
755 static void insert(std::unique_ptr<OperationName::Impl> ownedImpl,
756 ArrayRef<StringRef> attrNames);
757
758 /// Return the dialect this operation is registered to.
759 Dialect &getDialect() const { return *getImpl()->getDialect(); }
760
761 /// Represent the operation name as an opaque pointer. (Used to support
762 /// PointerLikeTypeTraits).
763 static RegisteredOperationName getFromOpaquePointer(const void *pointer) {
764 return RegisteredOperationName(
765 const_cast<Impl *>(reinterpret_cast<const Impl *>(pointer)));
766 }
767
768private:
769 /// Allocate storage for one type-erased operation model.
770 static void *allocateModelStorage();
771
773
774 /// Allow access to the constructor.
775 friend OperationName;
776};
777
778inline std::optional<RegisteredOperationName>
781 : std::optional<RegisteredOperationName>();
782}
783
784//===----------------------------------------------------------------------===//
785// Attribute Dictionary-Like Interface
786//===----------------------------------------------------------------------===//
787
788/// Attribute collections provide a dictionary-like interface. Define common
789/// lookup functions.
790namespace impl {
791
792/// Unsorted string search or identifier lookups are linear scans.
793template <typename IteratorT, typename NameT>
794std::pair<IteratorT, bool> findAttrUnsorted(IteratorT first, IteratorT last,
795 NameT name) {
796 for (auto it = first; it != last; ++it)
797 if (it->getName() == name)
798 return {it, true};
799 return {last, false};
800}
801
802/// Using llvm::lower_bound requires an extra string comparison to check whether
803/// the returned iterator points to the found element or whether it indicates
804/// the lower bound. Skip this redundant comparison by checking if `compare ==
805/// 0` during the binary search.
806template <typename IteratorT>
807std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
808 StringRef name) {
809 ptrdiff_t length = std::distance(first, last);
810
811 while (length > 0) {
812 ptrdiff_t half = length / 2;
813 IteratorT mid = first + half;
814 int compare = mid->getName().strref().compare(name);
815 if (compare < 0) {
816 first = mid + 1;
817 length = length - half - 1;
818 } else if (compare > 0) {
819 length = half;
820 } else {
821 return {mid, true};
822 }
823 }
824 return {first, false};
825}
826
827/// StringAttr lookups on large attribute lists will switch to string binary
828/// search. String binary searches become significantly faster than linear scans
829/// with the identifier when the attribute list becomes very large.
830template <typename IteratorT>
831std::pair<IteratorT, bool> findAttrSorted(IteratorT first, IteratorT last,
832 StringAttr name) {
833 constexpr unsigned kSmallAttributeList = 16;
834 if (std::distance(first, last) > kSmallAttributeList)
835 return findAttrSorted(first, last, name.strref());
836 return findAttrUnsorted(first, last, name);
837}
838
839/// Get an attribute from a sorted range of named attributes. Returns null if
840/// the attribute was not found.
841template <typename IteratorT, typename NameT>
842Attribute getAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
843 std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
844 return result.second ? result.first->getValue() : Attribute();
845}
846
847/// Get an attribute from a sorted range of named attributes. Returns
848/// std::nullopt if the attribute was not found.
849template <typename IteratorT, typename NameT>
850std::optional<NamedAttribute>
851getNamedAttrFromSortedRange(IteratorT first, IteratorT last, NameT name) {
852 std::pair<IteratorT, bool> result = findAttrSorted(first, last, name);
853 return result.second ? *result.first : std::optional<NamedAttribute>();
854}
855
856} // namespace impl
857
858//===----------------------------------------------------------------------===//
859// NamedAttrList
860//===----------------------------------------------------------------------===//
861
862/// NamedAttrList is array of NamedAttributes that tracks whether it is sorted
863/// and does some basic work to remain sorted.
865public:
870 using size_type = size_t;
871
872 NamedAttrList() : dictionarySorted({}, true) {}
873 NamedAttrList(ArrayRef<NamedAttribute> attributes);
874 NamedAttrList(DictionaryAttr attributes);
875 NamedAttrList(const_iterator inStart, const_iterator inEnd);
876
877 template <typename Container>
878 NamedAttrList(const Container &vec)
880
881 bool operator!=(const NamedAttrList &other) const {
882 return !(*this == other);
883 }
884 bool operator==(const NamedAttrList &other) const {
885 return attrs == other.attrs;
886 }
887
888 /// Add an attribute with the specified name.
889 void append(StringRef name, Attribute attr) {
890 append(NamedAttribute(name, attr));
891 }
892
893 /// Add an attribute with the specified name.
894 void append(StringAttr name, Attribute attr) {
895 append(NamedAttribute(name, attr));
896 }
897
898 /// Append the given named attribute.
899 void append(NamedAttribute attr) { push_back(attr); }
900
901 /// Add an array of named attributes.
902 template <typename RangeT>
903 void append(RangeT &&newAttributes) {
904 append(std::begin(newAttributes), std::end(newAttributes));
905 }
906
907 /// Add a range of named attributes.
908 template <typename IteratorT,
909 typename = std::enable_if_t<std::is_convertible<
910 typename std::iterator_traits<IteratorT>::iterator_category,
911 std::input_iterator_tag>::value>>
912 void append(IteratorT inStart, IteratorT inEnd) {
913 // TODO: expand to handle case where values appended are in order & after
914 // end of current list.
915 dictionarySorted.setPointerAndInt(nullptr, false);
916 attrs.append(inStart, inEnd);
917 }
918
919 /// Replaces the attributes with new list of attributes.
920 void assign(const_iterator inStart, const_iterator inEnd);
921
922 /// Replaces the attributes with new list of attributes.
924 assign(range.begin(), range.end());
925 }
926
927 void clear() {
928 attrs.clear();
929 dictionarySorted.setPointerAndInt(nullptr, false);
930 }
931
932 bool empty() const { return attrs.empty(); }
933
934 void reserve(size_type N) { attrs.reserve(N); }
935
936 /// Add an attribute with the specified name.
937 void push_back(NamedAttribute newAttribute);
938
939 /// Pop last element from list.
940 void pop_back() { attrs.pop_back(); }
941
942 /// Returns an entry with a duplicate name the list, if it exists, else
943 /// returns std::nullopt.
944 std::optional<NamedAttribute> findDuplicate() const;
945
946 /// Return a dictionary attribute for the underlying dictionary. This will
947 /// return an empty dictionary attribute if empty rather than null.
948 DictionaryAttr getDictionary(MLIRContext *context) const;
949
950 /// Return all of the attributes on this operation.
951 ArrayRef<NamedAttribute> getAttrs() const;
952
953 /// Return the specified attribute if present, null otherwise.
954 Attribute get(StringAttr name) const;
955 Attribute get(StringRef name) const;
956
957 /// Return the specified named attribute if present, std::nullopt otherwise.
958 std::optional<NamedAttribute> getNamed(StringRef name) const;
959 std::optional<NamedAttribute> getNamed(StringAttr name) const;
960
961 /// If the an attribute exists with the specified name, change it to the new
962 /// value. Otherwise, add a new attribute with the specified name/value.
963 /// Returns the previous attribute value of `name`, or null if no
964 /// attribute previously existed with `name`.
965 Attribute set(StringAttr name, Attribute value);
966 Attribute set(StringRef name, Attribute value);
967
968 /// Erase the attribute with the given name from the list. Return the
969 /// attribute that was erased, or nullptr if there was no attribute with such
970 /// name.
971 Attribute erase(StringAttr name);
972 Attribute erase(StringRef name);
973
974 iterator begin() { return attrs.begin(); }
975 iterator end() { return attrs.end(); }
976 const_iterator begin() const { return attrs.begin(); }
977 const_iterator end() const { return attrs.end(); }
978
979 NamedAttrList &operator=(const SmallVectorImpl<NamedAttribute> &rhs);
980 operator ArrayRef<NamedAttribute>() const;
981
982private:
983 /// Return whether the attributes are sorted.
984 bool isSorted() const { return dictionarySorted.getInt(); }
985
986 /// Erase the attribute at the given iterator position.
987 Attribute eraseImpl(SmallVectorImpl<NamedAttribute>::iterator it);
988
989 /// Lookup an attribute in the list.
990 template <typename AttrListT, typename NameT>
991 static auto findAttr(AttrListT &attrs, NameT name) {
992 return attrs.isSorted()
993 ? impl::findAttrSorted(attrs.begin(), attrs.end(), name)
994 : impl::findAttrUnsorted(attrs.begin(), attrs.end(), name);
995 }
996
997 // These are marked mutable as they may be modified (e.g., sorted)
998 mutable SmallVector<NamedAttribute, 4> attrs;
999 // Pair with cached DictionaryAttr and status of whether attrs is sorted.
1000 // Note: just because sorted does not mean a DictionaryAttr has been created
1001 // but the case where there is a DictionaryAttr but attrs isn't sorted should
1002 // not occur.
1003 mutable llvm::PointerIntPair<Attribute, 1, bool> dictionarySorted;
1004};
1005
1007 NamedAttrList &attrs) const {
1009 op, [&](StringRef name, Attribute &attr) { attrs.append(name, attr); });
1010}
1011
1012//===----------------------------------------------------------------------===//
1013// OperationState
1014//===----------------------------------------------------------------------===//
1015
1016/// This represents an operation in an abstracted form, suitable for use with
1017/// the builder APIs. This object is a large and heavy weight object meant to
1018/// be used as a temporary object on the stack. It is generally unwise to put
1019/// this in a collection.
1024 /// Types of the results of this operation.
1027 /// Successors of this operation and their respective operands.
1029 /// Regions that the op will hold.
1031
1032 /// This Attribute is used to opaquely construct the properties of the
1033 /// operation. If we're creating an unregistered operation, the Attribute is
1034 /// used as-is as the Properties storage of the operation. Otherwise, the
1035 /// operation properties are constructed opaquely using its
1036 /// `setPropertiesFromAttr` hook. Note that `getOrAddProperties` is the
1037 /// preferred method to construct properties from C++.
1039
1040private:
1041 /// The deleter and setter are non-null whenever `properties` is, and are
1042 /// only called after checking it.
1043 PropertyRef properties;
1044 void (*propertiesDeleter)(PropertyRef) = nullptr;
1045 void (*propertiesSetter)(PropertyRef, const PropertyRef) = nullptr;
1046 friend class Operation;
1047
1048public:
1051
1054 BlockRange successors = {},
1055 MutableArrayRef<std::unique_ptr<Region>> regions = {});
1056 OperationState(Location location, StringRef name, ValueRange operands,
1057 TypeRange types, ArrayRef<NamedAttribute> attributes = {},
1058 BlockRange successors = {},
1059 MutableArrayRef<std::unique_ptr<Region>> regions = {});
1060 OperationState(OperationState &&other) = default;
1062 OperationState(const OperationState &other) = delete;
1063 OperationState &operator=(const OperationState &other) = delete;
1065
1066 /// Get (or create) the properties of the provided type to be set on the
1067 /// operation on creation.
1068 template <typename T>
1070 if (!properties) {
1071 T *p = new T{};
1072 properties = PropertyRef(TypeID::get<T>(), p);
1073#if defined(__clang__)
1074#if __has_warning("-Wdangling-assignment-gsl")
1075#pragma clang diagnostic push
1076// https://github.com/llvm/llvm-project/issues/126600
1077#pragma clang diagnostic ignored "-Wdangling-assignment-gsl"
1078#endif
1079#endif
1080 propertiesDeleter = [](PropertyRef prop) { delete prop.as<const T *>(); };
1081 propertiesSetter = [](PropertyRef newProp, const PropertyRef prop) {
1082 *newProp.as<T *>() = *prop.as<const T *>();
1083 };
1084#if defined(__clang__)
1085#if __has_warning("-Wdangling-assignment-gsl")
1086#pragma clang diagnostic pop
1087#endif
1088#endif
1089 }
1090 assert(properties.getTypeID() == TypeID::get<T>() &&
1091 "Inconsistent properties");
1092 return *properties.as<T *>();
1093 }
1094 PropertyRef getRawProperties() { return properties; }
1095
1096 // Set the properties defined on this OpState on the given operation,
1097 // optionally emit diagnostics on error through the provided diagnostic.
1098 LogicalResult
1099 setProperties(Operation *op,
1101
1102 // Make `newProperties` the source of the properties that will be copied into
1103 // the operation. The memory referenced by `newProperties` must remain live
1104 // until after the `Operation` is created, at which time it may be
1105 // deallocated. Calls to `getOrAddProperties<>()` will return references to
1106 // this memory.
1107 template <typename T>
1108 void useProperties(T &newProperties) {
1109 assert(!properties &&
1110 "Can't provide a properties struct when one has been allocated");
1111 properties = PropertyRef(TypeID::get<T>(), &newProperties);
1112#if defined(__clang__)
1113#if __has_warning("-Wdangling-assignment-gsl")
1114#pragma clang diagnostic push
1115// https://github.com/llvm/llvm-project/issues/126600
1116#pragma clang diagnostic ignored "-Wdangling-assignment-gsl"
1117#endif
1118#endif
1119 propertiesDeleter = [](PropertyRef) {};
1120 propertiesSetter = [](PropertyRef newProp, const PropertyRef prop) {
1121 *newProp.as<T *>() = *prop.as<const T *>();
1122 };
1123#if defined(__clang__)
1124#if __has_warning("-Wdangling-assignment-gsl")
1125#pragma clang diagnostic pop
1126#endif
1127#endif
1128 }
1129
1130 void addOperands(ValueRange newOperands);
1131
1132 void addTypes(ArrayRef<Type> newTypes) {
1133 types.append(newTypes.begin(), newTypes.end());
1134 }
1135 template <typename RangeT>
1136 std::enable_if_t<!std::is_convertible<RangeT, ArrayRef<Type>>::value>
1137 addTypes(RangeT &&newTypes) {
1138 types.append(newTypes.begin(), newTypes.end());
1139 }
1140
1141 /// Add an attribute with the specified name.
1142 void addAttribute(StringRef name, Attribute attr) {
1143 addAttribute(StringAttr::get(getContext(), name), attr);
1144 }
1145
1146 /// Add an attribute with the specified name. `name` and `attr` must not be
1147 /// null.
1148 void addAttribute(StringAttr name, Attribute attr) {
1149 assert(name && "attribute name cannot be null");
1150 assert(attr && "attribute cannot be null");
1151 attributes.append(name, attr);
1152 }
1153
1154 /// Add an array of named attributes.
1156 attributes.append(newAttributes);
1157 }
1158
1159 /// Adds a successor to the operation sate. `successor` must not be null.
1160 void addSuccessors(Block *successor) {
1161 assert(successor && "successor cannot be null");
1162 successors.push_back(successor);
1163 }
1164 void addSuccessors(BlockRange newSuccessors);
1165
1166 /// Create a region that should be attached to the operation. These regions
1167 /// can be filled in immediately without waiting for Operation to be
1168 /// created. When it is, the region bodies will be transferred.
1169 Region *addRegion();
1170
1171 /// Take a region that should be attached to the Operation. The body of the
1172 /// region will be transferred when the Operation is constructed. If the
1173 /// region is null, a new empty region will be attached to the Operation.
1174 void addRegion(std::unique_ptr<Region> &&region);
1175
1176 /// Take ownership of a set of regions that should be attached to the
1177 /// Operation.
1178 void addRegions(MutableArrayRef<std::unique_ptr<Region>> regions);
1179
1180 /// Get the context held by this operation state.
1181 MLIRContext *getContext() const { return location->getContext(); }
1182};
1183
1184//===----------------------------------------------------------------------===//
1185// OperandStorage
1186//===----------------------------------------------------------------------===//
1187
1188namespace detail {
1189/// This class handles the management of operation operands. Operands are
1190/// stored either in a trailing array, or a dynamically resizable vector.
1191class alignas(8) OperandStorage {
1192public:
1193 OperandStorage(Operation *owner, OpOperand *trailingOperands,
1194 ValueRange values);
1196
1197 /// Replace the operands contained in the storage with the ones provided in
1198 /// 'values'.
1199 void setOperands(Operation *owner, ValueRange values);
1200
1201 /// Replace the operands beginning at 'start' and ending at 'start' + 'length'
1202 /// with the ones provided in 'operands'. 'operands' may be smaller or larger
1203 /// than the range pointed to by 'start'+'length'.
1204 void setOperands(Operation *owner, unsigned start, unsigned length,
1205 ValueRange operands);
1206
1207 /// Erase the operands held by the storage within the given range.
1208 void eraseOperands(unsigned start, unsigned length);
1209
1210 /// Erase the operands held by the storage that have their corresponding bit
1211 /// set in `eraseIndices`.
1212 void eraseOperands(const BitVector &eraseIndices);
1213
1214 /// Get the operation operands held by the storage.
1215 MutableArrayRef<OpOperand> getOperands() { return {operandStorage, size()}; }
1216
1217 /// Return the number of operands held in the storage.
1218 unsigned size() { return numOperands; }
1219
1220private:
1221 /// Resize the storage to the given size. Returns the array containing the new
1222 /// operands.
1223 MutableArrayRef<OpOperand> resize(Operation *owner, unsigned newSize);
1224
1225 /// The total capacity number of operands that the storage can hold.
1226 unsigned capacity : 31;
1227 /// A flag indicating if the operand storage was dynamically allocated, as
1228 /// opposed to inlined into the owning operation.
1229 unsigned isStorageDynamic : 1;
1230 /// The number of operands within the storage.
1231 unsigned numOperands;
1232 /// A pointer to the operand storage.
1233 OpOperand *operandStorage;
1234};
1235} // namespace detail
1236
1237//===----------------------------------------------------------------------===//
1238// OpPrintingFlags
1239//===----------------------------------------------------------------------===//
1240
1241/// Set of flags used to control the behavior of the various IR print methods
1242/// (e.g. Operation::Print).
1244public:
1246
1247 /// Enables the elision of large elements attributes by printing a lexically
1248 /// valid but otherwise meaningless form instead of the element data. The
1249 /// `largeElementLimit` is used to configure what is considered to be a
1250 /// "large" ElementsAttr by providing an upper limit to the number of
1251 /// elements.
1252 OpPrintingFlags &elideLargeElementsAttrs(int64_t largeElementLimit = 16);
1253
1254 /// Enables the printing of large element attributes with a hex string. The
1255 /// `largeElementLimit` is used to configure what is considered to be a
1256 /// "large" ElementsAttr by providing an upper limit to the number of
1257 /// elements. Use -1 to disable the hex printing.
1259 printLargeElementsAttrWithHex(int64_t largeElementLimit = 100);
1260
1261 /// Enables the elision of large resources strings by omitting them from the
1262 /// `dialect_resources` section. The `largeResourceLimit` is used to configure
1263 /// what is considered to be a "large" resource by providing an upper limit to
1264 /// the string size.
1265 OpPrintingFlags &elideLargeResourceString(int64_t largeResourceLimit = 64);
1266
1267 /// Enable or disable printing of debug information (based on `enable`). If
1268 /// 'prettyForm' is set to true, debug information is printed in a more
1269 /// readable 'pretty' form. Note: The IR generated with 'prettyForm' is not
1270 /// parsable.
1271 OpPrintingFlags &enableDebugInfo(bool enable = true, bool prettyForm = false);
1272
1273 /// Always print operations in the generic form.
1274 OpPrintingFlags &printGenericOpForm(bool enable = true);
1275
1276 /// Skip printing regions.
1277 OpPrintingFlags &skipRegions(bool skip = true);
1278
1279 /// Do not verify the operation when using custom operation printers.
1280 OpPrintingFlags &assumeVerified(bool enable = true);
1281
1282 /// Use local scope when printing the operation. This allows for using the
1283 /// printer in a more localized and thread-safe setting, but may not
1284 /// necessarily be identical to what the IR will look like when dumping
1285 /// the full module.
1286 OpPrintingFlags &useLocalScope(bool enable = true);
1287
1288 /// Print users of values as comments.
1289 OpPrintingFlags &printValueUsers(bool enable = true);
1290
1291 /// Print unique SSA ID numbers for values, block arguments and naming
1292 /// conflicts across all regions
1293 OpPrintingFlags &printUniqueSSAIDs(bool enable = true);
1294
1295 /// Print SSA IDs using their NameLoc, if provided, as prefix.
1296 OpPrintingFlags &printNameLocAsPrefix(bool enable = true);
1297
1298 /// Return if the given ElementsAttr should be elided.
1299 bool shouldElideElementsAttr(ElementsAttr attr) const;
1300
1301 /// Return if the given ElementsAttr should be printed as hex string.
1302 bool shouldPrintElementsAttrWithHex(ElementsAttr attr) const;
1303
1304 /// Return the size limit for printing large ElementsAttr.
1305 std::optional<int64_t> getLargeElementsAttrLimit() const;
1306
1307 /// Return the size limit for printing large ElementsAttr as hex string.
1309
1310 /// Return the size limit in chars for printing large resources.
1311 std::optional<uint64_t> getLargeResourceStringLimit() const;
1312
1313 /// Return if debug information should be printed.
1314 bool shouldPrintDebugInfo() const;
1315
1316 /// Return if debug information should be printed in the pretty form.
1317 bool shouldPrintDebugInfoPrettyForm() const;
1318
1319 /// Return if operations should be printed in the generic form.
1320 bool shouldPrintGenericOpForm() const;
1321
1322 /// Return if regions should be skipped.
1323 bool shouldSkipRegions() const;
1324
1325 /// Return if operation verification should be skipped.
1326 bool shouldAssumeVerified() const;
1327
1328 /// Return if the printer should use local scope when dumping the IR.
1329 bool shouldUseLocalScope() const;
1330
1331 /// Return if the printer should print users of values.
1332 bool shouldPrintValueUsers() const;
1333
1334 /// Return if printer should use unique SSA IDs.
1335 bool shouldPrintUniqueSSAIDs() const;
1336
1337 /// Return if the printer should use NameLocs as prefixes when printing SSA
1338 /// IDs
1339 bool shouldUseNameLocAsPrefix() const;
1340
1341private:
1342 /// Elide large elements attributes if the number of elements is larger than
1343 /// the upper limit.
1344 std::optional<int64_t> elementsAttrElementLimit;
1345
1346 /// Elide printing large resources based on size of string.
1347 std::optional<uint64_t> resourceStringCharLimit;
1348
1349 /// Print large element attributes with hex strings if the number of elements
1350 /// is larger than the upper limit.
1351 int64_t elementsAttrHexElementLimit = 100;
1352
1353 /// Print debug information.
1354 bool printDebugInfoFlag : 1;
1355 bool printDebugInfoPrettyFormFlag : 1;
1356
1357 /// Print operations in the generic form.
1358 bool printGenericOpFormFlag : 1;
1359
1360 /// Always skip Regions.
1361 bool skipRegionsFlag : 1;
1362
1363 /// Skip operation verification.
1364 bool assumeVerifiedFlag : 1;
1365
1366 /// Print operations with numberings local to the current operation.
1367 bool printLocalScope : 1;
1368
1369 /// Print users of values.
1370 bool printValueUsersFlag : 1;
1371
1372 /// Print unique SSA IDs for values, block arguments and naming conflicts
1373 bool printUniqueSSAIDsFlag : 1;
1374
1375 /// Print SSA IDs using NameLocs as prefixes
1376 bool useNameLocAsPrefix : 1;
1377};
1378
1379//===----------------------------------------------------------------------===//
1380// Operation Equivalency
1381//===----------------------------------------------------------------------===//
1382
1383/// This class provides utilities for computing if two operations are
1384/// equivalent.
1386 enum Flags {
1387 None = 0,
1388
1389 // When provided, the location attached to the operation are ignored.
1391
1392 // When provided, the discardable attributes attached to the operation are
1393 // ignored.
1395
1396 // When provided, the properties attached to the operation are ignored.
1398
1399 // When provided, the commutativity of the operation is ignored, and
1400 // operands are compared in an order-sensitive way.
1402
1403 LLVM_MARK_AS_BITMASK_ENUM(/* LargestValue = */ IgnoreCommutativity)
1404 };
1405
1406 /// Compute a hash for the given operation.
1407 /// The `hashOperands` and `hashResults` callbacks are expected to return a
1408 /// unique hash_code for a given Value.
1409 static llvm::hash_code computeHash(
1410 Operation *op,
1411 function_ref<llvm::hash_code(Value)> hashOperands =
1412 [](Value v) { return hash_value(v); },
1413 function_ref<llvm::hash_code(Value)> hashResults =
1414 [](Value v) { return hash_value(v); },
1415 Flags flags = Flags::None);
1416
1417 /// Helper that can be used with `computeHash` above to ignore operation
1418 /// operands/result mapping.
1419 static llvm::hash_code ignoreHashValue(Value) { return llvm::hash_code{}; }
1420 /// Helper that can be used with `computeHash` to compute the hash value
1421 /// of operands/results directly.
1422 static llvm::hash_code directHashValue(Value v) { return hash_value(v); }
1423
1424 /// Compare two operations (including their regions) and return if they are
1425 /// equivalent.
1426 ///
1427 /// * `checkEquivalent` is a callback to check if two values are equivalent.
1428 /// For two operations to be equivalent, their operands must be the same SSA
1429 /// value or this callback must return `success`.
1430 /// * `markEquivalent` is a callback to inform the caller that the analysis
1431 /// determined that two values are equivalent.
1432 /// * `checkCommutativeEquivalent` is an optional callback to check for
1433 /// equivalence across two ranges for a commutative operation. If not passed
1434 /// in, then equivalence is checked pairwise. This callback is needed to be
1435 /// able to query the optional equivalence classes.
1436 ///
1437 /// Note: Additional information regarding value equivalence can be injected
1438 /// into the analysis via `checkEquivalent`. Typically, callers may want
1439 /// values that were determined to be equivalent as per `markEquivalent` to be
1440 /// reflected in `checkEquivalent`, unless `exactValueMatch` or a different
1441 /// equivalence relationship is desired.
1442 static bool
1443 isEquivalentTo(Operation *lhs, Operation *rhs,
1444 function_ref<LogicalResult(Value, Value)> checkEquivalent,
1445 function_ref<void(Value, Value)> markEquivalent = nullptr,
1446 Flags flags = Flags::None,
1447 function_ref<LogicalResult(ValueRange, ValueRange)>
1448 checkCommutativeEquivalent = nullptr);
1449
1450 /// Compare two operations and return if they are equivalent.
1451 static bool isEquivalentTo(Operation *lhs, Operation *rhs, Flags flags);
1452
1453 /// Compare two regions (including their subregions) and return if they are
1454 /// equivalent. See also `isEquivalentTo` for details.
1455 static bool isRegionEquivalentTo(
1456 Region *lhs, Region *rhs,
1457 function_ref<LogicalResult(Value, Value)> checkEquivalent,
1458 function_ref<void(Value, Value)> markEquivalent,
1460 function_ref<LogicalResult(ValueRange, ValueRange)>
1461 checkCommutativeEquivalent = nullptr);
1462
1463 /// Compare two regions and return if they are equivalent.
1464 static bool isRegionEquivalentTo(Region *lhs, Region *rhs,
1466
1467 /// Helper that can be used with `isEquivalentTo` above to consider ops
1468 /// equivalent even if their operands are not equivalent.
1469 static LogicalResult ignoreValueEquivalence(Value lhs, Value rhs) {
1470 return success();
1471 }
1472 /// Helper that can be used with `isEquivalentTo` above to consider ops
1473 /// equivalent only if their operands are the exact same SSA values.
1474 static LogicalResult exactValueMatch(Value lhs, Value rhs) {
1475 return success(lhs == rhs);
1476 }
1477};
1478
1479/// Enable Bitmask enums for OperationEquivalence::Flags.
1481
1482//===----------------------------------------------------------------------===//
1483// OperationFingerPrint
1484//===----------------------------------------------------------------------===//
1485
1486/// A unique fingerprint for a specific operation, and all of it's internal
1487/// operations (if `includeNested` is set).
1489public:
1490 OperationFingerPrint(Operation *topOp, bool includeNested = true);
1493
1494 bool operator==(const OperationFingerPrint &other) const {
1495 return hash == other.hash;
1496 }
1497 bool operator!=(const OperationFingerPrint &other) const {
1498 return !(*this == other);
1499 }
1500
1501private:
1502 std::array<uint8_t, 20> hash;
1503};
1504
1505} // namespace mlir
1506
1507namespace llvm {
1508template <>
1509struct DenseMapInfo<mlir::OperationName> {
1514 return lhs == rhs;
1515 }
1516};
1517template <>
1518struct DenseMapInfo<mlir::RegisteredOperationName>
1519 : public DenseMapInfo<mlir::OperationName> {
1520};
1521
1522template <>
1523struct PointerLikeTypeTraits<mlir::OperationName> {
1524 static inline void *getAsVoidPointer(mlir::OperationName I) {
1525 return const_cast<void *>(I.getAsOpaquePointer());
1526 }
1530 static constexpr int NumLowBitsAvailable =
1531 PointerLikeTypeTraits<void *>::NumLowBitsAvailable;
1532};
1533template <>
1534struct PointerLikeTypeTraits<mlir::RegisteredOperationName>
1535 : public PointerLikeTypeTraits<mlir::OperationName> {
1539};
1540
1541} // namespace llvm
1542
1543#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: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: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
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: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