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