//===- SideEffectInterfaces.h - SideEffect in MLIR --------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// // // This file contains traits, interfaces, and utilities for defining and // querying the side effects of an operation. // //===----------------------------------------------------------------------===// #ifndef MLIR_INTERFACES_SIDEEFFECTINTERFACES_H #define MLIR_INTERFACES_SIDEEFFECTINTERFACES_H #include "mlir/IR/OpDefinition.h" namespace mlir { namespace SideEffects { //===----------------------------------------------------------------------===// // Effects //===----------------------------------------------------------------------===// /// This class represents a base class for a specific effect type. class Effect { … }; //===----------------------------------------------------------------------===// // Resources //===----------------------------------------------------------------------===// /// This class represents a specific resource that an effect applies to. This /// class represents an abstract interface for a given resource. class Resource { … }; /// A conservative default resource kind. struct DefaultResource : public Resource::Base<DefaultResource> { … }; /// An automatic allocation-scope resource that is valid in the context of a /// parent AutomaticAllocationScope trait. struct AutomaticAllocationScopeResource : public Resource::Base<AutomaticAllocationScopeResource> { … }; /// This class represents a specific instance of an effect. It contains the /// effect being applied, a resource that corresponds to where the effect is /// applied, and an optional symbol reference or value(either operand, result, /// or region entry argument) that the effect is applied to, and an optional /// parameters attribute further specifying the details of the effect. template <typename EffectT> class EffectInstance { … }; } // namespace SideEffects namespace Speculation { /// This enum is returned from the `getSpeculatability` method in the /// `ConditionallySpeculatable` op interface. enum class Speculatability { … }; constexpr auto NotSpeculatable = …; constexpr auto Speculatable = …; constexpr auto RecursivelySpeculatable = …; } // namespace Speculation //===----------------------------------------------------------------------===// // SideEffect Traits //===----------------------------------------------------------------------===// namespace OpTrait { /// This trait indicates that the memory effects of an operation includes the /// effects of operations nested within its regions. If the operation has no /// derived effects interfaces, the operation itself can be assumed to have no /// memory effects. template <typename ConcreteType> class HasRecursiveMemoryEffects : public TraitBase<ConcreteType, HasRecursiveMemoryEffects> { … }; /// This trait marks an op (which must be tagged as implementing the /// ConditionallySpeculatable interface) as being recursively speculatable. /// This means that said op can be speculated only if all the instructions in /// all the regions attached to the op can be speculated. template <typename ConcreteType> struct RecursivelySpeculatableImplTrait : public TraitBase<ConcreteType, RecursivelySpeculatableImplTrait> { … }; /// This trait marks an op (which must be tagged as implementing the /// ConditionallySpeculatable interface) as being always speculatable. template <typename ConcreteType> struct AlwaysSpeculatableImplTrait : public TraitBase<ConcreteType, AlwaysSpeculatableImplTrait> { … }; } // namespace OpTrait //===----------------------------------------------------------------------===// // Operation Memory-Effect Modeling //===----------------------------------------------------------------------===// namespace MemoryEffects { /// This class represents the base class used for memory effects. struct Effect : public SideEffects::Effect { … }; EffectInstance; /// The following effect indicates that the operation allocates from some /// resource. An 'allocate' effect implies only allocation of the resource, and /// not any visible mutation or dereference. struct Allocate : public Effect::Base<Allocate> { … }; /// The following effect indicates that the operation frees some resource that /// has been allocated. An 'allocate' effect implies only de-allocation of the /// resource, and not any visible allocation, mutation or dereference. struct Free : public Effect::Base<Free> { … }; /// The following effect indicates that the operation reads from some resource. /// A 'read' effect implies only dereferencing of the resource, and not any /// visible mutation. struct Read : public Effect::Base<Read> { … }; /// The following effect indicates that the operation writes to some resource. A /// 'write' effect implies only mutating a resource, and not any visible /// dereference or read. struct Write : public Effect::Base<Write> { … }; } // namespace MemoryEffects //===----------------------------------------------------------------------===// // SideEffect Utilities //===----------------------------------------------------------------------===// /// Returns true if `op` has only an effect of type `EffectTy`. template <typename EffectTy> bool hasSingleEffect(Operation *op); /// Returns true if `op` has only an effect of type `EffectTy` (and of no other /// type) on `value`. template <typename EffectTy> bool hasSingleEffect(Operation *op, Value value); /// Returns true if `op` has only an effect of type `EffectTy` (and of no other /// type) on `value` of type `ValueTy`. template <typename ValueTy, typename EffectTy> bool hasSingleEffect(Operation *op, ValueTy value); /// Returns true if `op` has an effect of type `EffectTy`. template <typename... EffectTys> bool hasEffect(Operation *op); /// Returns true if `op` has an effect of type `EffectTy` on `value`. template <typename... EffectTys> bool hasEffect(Operation *op, Value value); /// Returns true if `op` has an effect of type `EffectTy` on `value` of type /// `ValueTy`. template <typename ValueTy, typename... EffectTys> bool hasEffect(Operation *op, ValueTy value); /// Return true if the given operation is unused, and has no side effects on /// memory that prevent erasing. bool isOpTriviallyDead(Operation *op); /// Return true if the given operation would be dead if unused, and has no side /// effects on memory that would prevent erasing. This is equivalent to checking /// `isOpTriviallyDead` if `op` was unused. /// /// Note: Terminators and symbols are never considered to be trivially dead. bool wouldOpBeTriviallyDead(Operation *op); /// Returns true if the given operation is free of memory effects. /// /// An operation is free of memory effects if its implementation of /// `MemoryEffectOpInterface` indicates that it has no memory effects. For /// example, it may implement `NoMemoryEffect` in ODS. Alternatively, if the /// operation has the `HasRecursiveMemoryEffects` trait, then it is free of /// memory effects if all of its nested operations are free of memory effects. /// /// If the operation has both, then it is free of memory effects if both /// conditions are satisfied. bool isMemoryEffectFree(Operation *op); /// Returns the side effects of an operation. If the operation has /// RecursiveMemoryEffects, include all side effects of child operations. /// /// std::nullopt indicates that an option did not have a memory effect interface /// and so no result could be obtained. An empty vector indicates that there /// were no memory effects found (but every operation implemented the memory /// effect interface or has RecursiveMemoryEffects). If the vector contains /// multiple effects, these effects may be duplicates. std::optional<llvm::SmallVector<MemoryEffects::EffectInstance>> getEffectsRecursively(Operation *rootOp); /// Returns true if the given operation is speculatable, i.e. has no undefined /// behavior or other side effects. /// /// An operation can indicate that it is speculatable by implementing the /// getSpeculatability hook in the ConditionallySpeculatable op interface. bool isSpeculatable(Operation *op); /// Returns true if the given operation is pure, i.e., is speculatable that does /// not touch memory. /// /// This function is the C++ equivalent of the `Pure` trait. bool isPure(Operation *op); } // namespace mlir //===----------------------------------------------------------------------===// // SideEffect Interfaces //===----------------------------------------------------------------------===// /// Include the definitions of the side effect interfaces. #include "mlir/Interfaces/SideEffectInterfaces.h.inc" #endif // MLIR_INTERFACES_SIDEEFFECTINTERFACES_H