1//===-- SideEffectInterfaceBase.td - Side Effect Base ------*- tablegen -*-===//
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 contains base class definitions for side effect interfaces, i.e.
10// the customizable interfaces that provide information about which effects are
11// applied by an operation.
12//
13//===----------------------------------------------------------------------===//
14
15#ifndef MLIR_INTERFACES_SIDEEFFECTS_BASE
16#define MLIR_INTERFACES_SIDEEFFECTS_BASE
17
18include "mlir/IR/OpBase.td"
19
20//===----------------------------------------------------------------------===//
21// Resource Bindings
22//===----------------------------------------------------------------------===//
23
24// A generic resource that can be attached to a general base side effect.
25class Resource<string resourceName> {
26  /// The resource that the associated effect is being applied to.
27  string name = resourceName;
28}
29
30// An intrinsic resource that lives in the ::mlir::SideEffects namespace.
31class IntrinsicResource<string resourceName> :
32  Resource<!strconcat("::mlir::SideEffects::", resourceName)> {
33}
34
35// A link to the DefaultResource class.
36def DefaultResource : IntrinsicResource<"DefaultResource">;
37// A link to the AutomaticAllocationScopeResource class.
38def AutomaticAllocationScopeResource :
39  IntrinsicResource<"AutomaticAllocationScopeResource">;
40
41//===----------------------------------------------------------------------===//
42// EffectOpInterface
43//===----------------------------------------------------------------------===//
44
45// A base interface used to query information about the side effects applied to
46// an operation. This template class takes the name of the derived interface
47// class, as well as the name of the base effect class.
48class EffectOpInterfaceBase<string name, string baseEffect>
49    : OpInterface<name> {
50  let methods = [
51    InterfaceMethod<[{
52        Collects all of the operation's effects into `effects`.
53      }],
54      "void", "getEffects",
55         (ins "::llvm::SmallVectorImpl<::mlir::SideEffects::EffectInstance<"
56              # baseEffect # ">> &":$effects)
57    >,
58  ];
59
60  let extraClassDeclaration = [{
61    /// Collect all of the effect instances that correspond to the given
62    /// `Effect` and place them in 'effects'.
63    template <typename Effect> void getEffects(
64      SmallVectorImpl<::mlir::SideEffects::EffectInstance<
65                                              }] # baseEffect # [{>> &effects) {
66      getEffects(effects);
67      llvm::erase_if(effects, [&](auto &it) {
68        return !llvm::isa<Effect>(it.getEffect());
69      });
70    }
71
72    /// Returns true if this operation exhibits the given effect.
73    template <typename Effect> bool hasEffect() {
74      SmallVector<SideEffects::EffectInstance<}] # baseEffect # [{>, 4> effects;
75      getEffects(effects);
76      return llvm::any_of(effects, [](const auto &it) {
77        return llvm::isa<Effect>(it.getEffect());
78      });
79    }
80
81    /// Returns true if this operation only has the given effect.
82    template <typename Effect> bool onlyHasEffect() {
83      SmallVector<SideEffects::EffectInstance<}] # baseEffect # [{>, 4> effects;
84      getEffects(effects);
85      return !effects.empty() && llvm::all_of(effects, [](const auto &it) {
86        return isa<Effect>(it.getEffect());
87      });
88    }
89
90    /// Returns true if this operation has no effects.
91    bool hasNoEffect() {
92      SmallVector<::mlir::SideEffects::EffectInstance<}] # baseEffect # [{>, 4> effects;
93      getEffects(effects);
94      return effects.empty();
95    }
96
97    /// Returns true if the given operation has no effects for this interface.
98    static bool hasNoEffect(Operation *op) {
99      if (auto interface = dyn_cast<}] # name # [{>(op))
100        return interface.hasNoEffect();
101      return op->hasTrait<::mlir::OpTrait::HasRecursiveSideEffects>();
102    }
103
104    /// Collect all of the effect instances that operate on the provided value
105    /// and place them in 'effects'.
106    void getEffectsOnValue(::mlir::Value value,
107              llvm::SmallVectorImpl<::mlir::SideEffects::EffectInstance<
108              }] # baseEffect # [{>> & effects) {
109      getEffects(effects);
110      llvm::erase_if(effects, [&](auto &it) { return it.getValue() != value; });
111    }
112
113    /// Return the effect of the given type `Effect` that is applied to the
114    /// given value, or None if no effect exists.
115    template <typename Effect>
116    ::llvm::Optional<::mlir::SideEffects::EffectInstance<}] # baseEffect # [{>>
117    getEffectOnValue(::mlir::Value value) {
118      llvm::SmallVector<::mlir::SideEffects::EffectInstance<
119              }] # baseEffect # [{>, 4> effects;
120      getEffects(effects);
121      auto it = llvm::find_if(effects, [&](auto &it) {
122        return isa<Effect>(it.getEffect()) && it.getValue() == value;
123      });
124      if (it == effects.end())
125        return llvm::None;
126      return *it;
127    }
128
129    /// Collect all of the effect instances that operate on the provided symbol
130    /// reference and place them in 'effects'.
131    void getEffectsOnSymbol(::mlir::SymbolRefAttr value,
132              llvm::SmallVectorImpl<::mlir::SideEffects::EffectInstance<
133              }] # baseEffect # [{>> & effects) {
134      getEffects(effects);
135      llvm::erase_if(effects, [&](auto &it) {
136        return it.getSymbolRef() != value;
137      });
138    }
139
140    /// Collect all of the effect instances that operate on the provided
141    /// resource and place them in 'effects'.
142    void getEffectsOnResource(::mlir::SideEffects::Resource *resource,
143              llvm::SmallVectorImpl<::mlir::SideEffects::EffectInstance<
144              }] # baseEffect # [{>> & effects) {
145      getEffects(effects);
146      llvm::erase_if(effects, [&](auto &it) {
147        return it.getResource() != resource;
148      });
149    }
150  }];
151
152  // The base effect name of this interface.
153  string baseEffectName = baseEffect;
154}
155
156// This class is the general base side effect class. This is used by derived
157// effect interfaces to define their effects.
158class SideEffect<EffectOpInterfaceBase interface, string effectName,
159                 Resource resourceReference> : OpVariableDecorator {
160  /// The name of the base effects class.
161  string baseEffectName = interface.baseEffectName;
162
163  /// The parent interface that the effect belongs to.
164  string interfaceTrait = interface.trait;
165
166  /// The cpp namespace of the interface trait.
167  string cppNamespace = interface.cppNamespace;
168
169  /// The derived effect that is being applied.
170  string effect = effectName;
171
172  /// The resource that the effect is being applied to.
173  string resource = resourceReference.name;
174}
175
176// This class is the base used for specifying effects applied to an operation.
177class SideEffectsTraitBase<EffectOpInterfaceBase parentInterface,
178                           list<SideEffect> staticEffects>
179    : OpInterfaceTrait<""> {
180  /// The name of the interface trait to use.
181  let trait = parentInterface.trait;
182
183  /// The cpp namespace of the interface trait.
184  string cppNamespace = parentInterface.cppNamespace;
185
186  /// The name of the base effects class.
187  string baseEffectName = parentInterface.baseEffectName;
188
189  /// The derived effects being applied.
190  list<SideEffect> effects = staticEffects;
191}
192
193#endif // MLIR_INTERFACES_SIDEEFFECTS_BASE
194