llvm/mlir/include/mlir/Interfaces/SideEffectInterfaces.h

//===- 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