1 //===- SideEffectInterfaces.h - SideEffect in MLIR --------------*- 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 contains traits, interfaces, and utilities for defining and
10 // querying the side effects of an operation.
11 //
12 //===----------------------------------------------------------------------===//
13 
14 #ifndef MLIR_INTERFACES_SIDEEFFECTS_H
15 #define MLIR_INTERFACES_SIDEEFFECTS_H
16 
17 #include "mlir/IR/OpDefinition.h"
18 
19 namespace mlir {
20 namespace SideEffects {
21 //===----------------------------------------------------------------------===//
22 // Effects
23 //===----------------------------------------------------------------------===//
24 
25 /// This class represents a base class for a specific effect type.
26 class Effect {
27 public:
28   /// This base class is used for derived effects that are non-parametric.
29   template <typename DerivedEffect, typename BaseEffect = Effect>
30   class Base : public BaseEffect {
31   public:
32     using BaseT = Base<DerivedEffect>;
33 
34     /// Return the unique identifier for the base effects class.
getEffectID()35     static TypeID getEffectID() { return TypeID::get<DerivedEffect>(); }
36 
37     /// 'classof' used to support llvm style cast functionality.
classof(const::mlir::SideEffects::Effect * effect)38     static bool classof(const ::mlir::SideEffects::Effect *effect) {
39       return effect->getEffectID() == BaseT::getEffectID();
40     }
41 
42     /// Returns a unique instance for the derived effect class.
get()43     static DerivedEffect *get() {
44       return BaseEffect::template get<DerivedEffect>();
45     }
46     using BaseEffect::get;
47 
48   protected:
Base()49     Base() : BaseEffect(BaseT::getEffectID()) {}
50   };
51 
52   /// Return the unique identifier for the base effects class.
getEffectID()53   TypeID getEffectID() const { return id; }
54 
55   /// Returns a unique instance for the given effect class.
get()56   template <typename DerivedEffect> static DerivedEffect *get() {
57     static_assert(std::is_base_of<Effect, DerivedEffect>::value,
58                   "expected DerivedEffect to inherit from Effect");
59 
60     static DerivedEffect instance;
61     return &instance;
62   }
63 
64 protected:
Effect(TypeID id)65   Effect(TypeID id) : id(id) {}
66 
67 private:
68   /// The id of the derived effect class.
69   TypeID id;
70 };
71 
72 //===----------------------------------------------------------------------===//
73 // Resources
74 //===----------------------------------------------------------------------===//
75 
76 /// This class represents a specific resource that an effect applies to. This
77 /// class represents an abstract interface for a given resource.
78 class Resource {
79 public:
~Resource()80   virtual ~Resource() {}
81 
82   /// This base class is used for derived effects that are non-parametric.
83   template <typename DerivedResource, typename BaseResource = Resource>
84   class Base : public BaseResource {
85   public:
86     using BaseT = Base<DerivedResource>;
87 
88     /// Returns a unique instance for the given effect class.
get()89     static DerivedResource *get() {
90       static DerivedResource instance;
91       return &instance;
92     }
93 
94     /// Return the unique identifier for the base resource class.
getResourceID()95     static TypeID getResourceID() { return TypeID::get<DerivedResource>(); }
96 
97     /// 'classof' used to support llvm style cast functionality.
classof(const Resource * resource)98     static bool classof(const Resource *resource) {
99       return resource->getResourceID() == BaseT::getResourceID();
100     }
101 
102   protected:
Base()103     Base() : BaseResource(BaseT::getResourceID()){};
104   };
105 
106   /// Return the unique identifier for the base resource class.
getResourceID()107   TypeID getResourceID() const { return id; }
108 
109   /// Return a string name of the resource.
110   virtual StringRef getName() = 0;
111 
112 protected:
Resource(TypeID id)113   Resource(TypeID id) : id(id) {}
114 
115 private:
116   /// The id of the derived resource class.
117   TypeID id;
118 };
119 
120 /// A conservative default resource kind.
121 struct DefaultResource : public Resource::Base<DefaultResource> {
getNameDefaultResource122   StringRef getName() final { return "<Default>"; }
123 };
124 
125 /// An automatic allocation-scope resource that is valid in the context of a
126 /// parent AutomaticAllocationScope trait.
127 struct AutomaticAllocationScopeResource
128     : public Resource::Base<AutomaticAllocationScopeResource> {
getNameAutomaticAllocationScopeResource129   StringRef getName() final { return "AutomaticAllocationScope"; }
130 };
131 
132 /// This class represents a specific instance of an effect. It contains the
133 /// effect being applied, a resource that corresponds to where the effect is
134 /// applied, and an optional symbol reference or value(either operand, result,
135 /// or region entry argument) that the effect is applied to, and an optional
136 /// parameters attribute further specifying the details of the effect.
137 template <typename EffectT> class EffectInstance {
138 public:
139   EffectInstance(EffectT *effect, Resource *resource = DefaultResource::get())
effect(effect)140       : effect(effect), resource(resource) {}
141   EffectInstance(EffectT *effect, Value value,
142                  Resource *resource = DefaultResource::get())
effect(effect)143       : effect(effect), resource(resource), value(value) {}
144   EffectInstance(EffectT *effect, SymbolRefAttr symbol,
145                  Resource *resource = DefaultResource::get())
effect(effect)146       : effect(effect), resource(resource), value(symbol) {}
147   EffectInstance(EffectT *effect, Attribute parameters,
148                  Resource *resource = DefaultResource::get())
effect(effect)149       : effect(effect), resource(resource), parameters(parameters) {}
150   EffectInstance(EffectT *effect, Value value, Attribute parameters,
151                  Resource *resource = DefaultResource::get())
effect(effect)152       : effect(effect), resource(resource), value(value),
153         parameters(parameters) {}
154   EffectInstance(EffectT *effect, SymbolRefAttr symbol, Attribute parameters,
155                  Resource *resource = DefaultResource::get())
effect(effect)156       : effect(effect), resource(resource), value(symbol),
157         parameters(parameters) {}
158 
159   /// Return the effect being applied.
getEffect()160   EffectT *getEffect() const { return effect; }
161 
162   /// Return the value the effect is applied on, or nullptr if there isn't a
163   /// known value being affected.
getValue()164   Value getValue() const { return value ? value.dyn_cast<Value>() : Value(); }
165 
166   /// Return the symbol reference the effect is applied on, or nullptr if there
167   /// isn't a known smbol being affected.
getSymbolRef()168   SymbolRefAttr getSymbolRef() const {
169     return value ? value.dyn_cast<SymbolRefAttr>() : SymbolRefAttr();
170   }
171 
172   /// Return the resource that the effect applies to.
getResource()173   Resource *getResource() const { return resource; }
174 
175   /// Return the parameters of the effect, if any.
getParameters()176   Attribute getParameters() const { return parameters; }
177 
178 private:
179   /// The specific effect being applied.
180   EffectT *effect;
181 
182   /// The resource that the given value resides in.
183   Resource *resource;
184 
185   /// The Symbol or Value that the effect applies to. This is optionally null.
186   PointerUnion<SymbolRefAttr, Value> value;
187 
188   /// Additional parameters of the effect instance. An attribute is used for
189   /// type-safe structured storage and context-based uniquing. Concrete effects
190   /// can use this at their convenience. This is optionally null.
191   Attribute parameters;
192 };
193 } // namespace SideEffects
194 
195 //===----------------------------------------------------------------------===//
196 // SideEffect Traits
197 //===----------------------------------------------------------------------===//
198 
199 namespace OpTrait {
200 /// This trait indicates that the side effects of an operation includes the
201 /// effects of operations nested within its regions. If the operation has no
202 /// derived effects interfaces, the operation itself can be assumed to have no
203 /// side effects.
204 template <typename ConcreteType>
205 class HasRecursiveSideEffects
206     : public TraitBase<ConcreteType, HasRecursiveSideEffects> {};
207 } // namespace OpTrait
208 
209 //===----------------------------------------------------------------------===//
210 // Operation Memory-Effect Modeling
211 //===----------------------------------------------------------------------===//
212 
213 namespace MemoryEffects {
214 /// This class represents the base class used for memory effects.
215 struct Effect : public SideEffects::Effect {
216   using SideEffects::Effect::Effect;
217 
218   /// A base class for memory effects that provides helper utilities.
219   template <typename DerivedEffect>
220   using Base = SideEffects::Effect::Base<DerivedEffect, Effect>;
221 
222   static bool classof(const SideEffects::Effect *effect);
223 };
224 using EffectInstance = SideEffects::EffectInstance<Effect>;
225 
226 /// The following effect indicates that the operation allocates from some
227 /// resource. An 'allocate' effect implies only allocation of the resource, and
228 /// not any visible mutation or dereference.
229 struct Allocate : public Effect::Base<Allocate> {};
230 
231 /// The following effect indicates that the operation frees some resource that
232 /// has been allocated. An 'allocate' effect implies only de-allocation of the
233 /// resource, and not any visible allocation, mutation or dereference.
234 struct Free : public Effect::Base<Free> {};
235 
236 /// The following effect indicates that the operation reads from some resource.
237 /// A 'read' effect implies only dereferencing of the resource, and not any
238 /// visible mutation.
239 struct Read : public Effect::Base<Read> {};
240 
241 /// The following effect indicates that the operation writes to some resource. A
242 /// 'write' effect implies only mutating a resource, and not any visible
243 /// dereference or read.
244 struct Write : public Effect::Base<Write> {};
245 } // namespace MemoryEffects
246 
247 //===----------------------------------------------------------------------===//
248 // SideEffect Utilities
249 //===----------------------------------------------------------------------===//
250 
251 /// Return true if the given operation is unused, and has no side effects on
252 /// memory that prevent erasing.
253 bool isOpTriviallyDead(Operation *op);
254 
255 /// Return true if the given operation would be dead if unused, and has no side
256 /// effects on memory that would prevent erasing. This is equivalent to checking
257 /// `isOpTriviallyDead` if `op` was unused.
258 bool wouldOpBeTriviallyDead(Operation *op);
259 
260 } // end namespace mlir
261 
262 //===----------------------------------------------------------------------===//
263 // SideEffect Interfaces
264 //===----------------------------------------------------------------------===//
265 
266 /// Include the definitions of the side effect interfaces.
267 #include "mlir/Interfaces/SideEffectInterfaces.h.inc"
268 
269 #endif // MLIR_INTERFACES_SIDEEFFECTS_H
270