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
19namespace mlir {
20namespace SideEffects {
21//===----------------------------------------------------------------------===//
22// Effects
23//===----------------------------------------------------------------------===//
24
25/// This class represents a base class for a specific effect type.
26class Effect {
27public:
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.
35 static TypeID getEffectID() { return TypeID::get<DerivedEffect>(); }
36
37 /// 'classof' used to support llvm style cast functionality.
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.
43 static DerivedEffect *get() {
44 return BaseEffect::template get<DerivedEffect>();
45 }
46 using BaseEffect::get;
47
48 protected:
49 Base() : BaseEffect(BaseT::getEffectID()) {}
50 };
51
52 /// Return the unique identifier for the base effects class.
53 TypeID getEffectID() const { return id; }
54
55 /// Returns a unique instance for the given effect class.
56 template <typename DerivedEffect>
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
65protected:
66 Effect(TypeID id) : id(id) {}
67
68private:
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.
79class Resource {
80public:
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.
90 static DerivedResource *get() {
91 static DerivedResource instance;
92 return &instance;
93 }
94
95 /// Return the unique identifier for the base resource class.
96 static TypeID getResourceID() { return TypeID::get<DerivedResource>(); }
97
98 /// 'classof' used to support llvm style cast functionality.
99 static bool classof(const Resource *resource) {
100 return resource->getResourceID() == BaseT::getResourceID();
101 }
102
103 protected:
104 Base() : BaseResource(BaseT::getResourceID()){};
105 };
106
107 /// Return the unique identifier for the base resource class.
108 TypeID getResourceID() const { return id; }
109
110 /// Return a string name of the resource.
111 virtual StringRef getName() = 0;
112
113protected:
114 Resource(TypeID id) : id(id) {}
115
116private:
117 /// The id of the derived resource class.
118 TypeID id;
119};
120
121/// A conservative default resource kind.
122struct DefaultResource : public Resource::Base<DefaultResource> {
123 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.
128struct AutomaticAllocationScopeResource
129 : public Resource::Base<AutomaticAllocationScopeResource> {
130 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.
138template <typename EffectT>
139class EffectInstance {
140public:
141 EffectInstance(EffectT *effect, Resource *resource = DefaultResource::get())
142 : effect(effect), resource(resource), stage(0),
143 effectOnFullRegion(false) {}
144 EffectInstance(EffectT *effect, int stage, bool effectOnFullRegion,
145 Resource *resource = DefaultResource::get())
146 : effect(effect), resource(resource), stage(stage),
147 effectOnFullRegion(effectOnFullRegion) {}
148 EffectInstance(EffectT *effect, Value value,
149 Resource *resource = DefaultResource::get())
150 : effect(effect), resource(resource), value(value), stage(0),
151 effectOnFullRegion(false) {}
152 EffectInstance(EffectT *effect, Value value, int stage,
153 bool effectOnFullRegion,
154 Resource *resource = DefaultResource::get())
155 : effect(effect), resource(resource), value(value), stage(stage),
156 effectOnFullRegion(effectOnFullRegion) {}
157 EffectInstance(EffectT *effect, SymbolRefAttr symbol,
158 Resource *resource = DefaultResource::get())
159 : effect(effect), resource(resource), value(symbol), stage(0),
160 effectOnFullRegion(false) {}
161 EffectInstance(EffectT *effect, SymbolRefAttr symbol, int stage,
162 bool effectOnFullRegion,
163 Resource *resource = DefaultResource::get())
164 : effect(effect), resource(resource), value(symbol), stage(stage),
165 effectOnFullRegion(effectOnFullRegion) {}
166 EffectInstance(EffectT *effect, Attribute parameters,
167 Resource *resource = DefaultResource::get())
168 : effect(effect), resource(resource), parameters(parameters), stage(0),
169 effectOnFullRegion(false) {}
170 EffectInstance(EffectT *effect, Attribute parameters, int stage,
171 bool effectOnFullRegion,
172 Resource *resource = DefaultResource::get())
173 : effect(effect), resource(resource), parameters(parameters),
174 stage(stage), effectOnFullRegion(effectOnFullRegion) {}
175 EffectInstance(EffectT *effect, Value value, Attribute parameters,
176 Resource *resource = DefaultResource::get())
177 : effect(effect), resource(resource), value(value),
178 parameters(parameters), stage(0), effectOnFullRegion(false) {}
179 EffectInstance(EffectT *effect, Value value, Attribute parameters, int stage,
180 bool effectOnFullRegion,
181 Resource *resource = DefaultResource::get())
182 : effect(effect), resource(resource), value(value),
183 parameters(parameters), stage(stage),
184 effectOnFullRegion(effectOnFullRegion) {}
185 EffectInstance(EffectT *effect, SymbolRefAttr symbol, Attribute parameters,
186 Resource *resource = DefaultResource::get())
187 : effect(effect), resource(resource), value(symbol),
188 parameters(parameters), stage(0), effectOnFullRegion(false) {}
189 EffectInstance(EffectT *effect, SymbolRefAttr symbol, Attribute parameters,
190 int stage, bool effectOnFullRegion,
191 Resource *resource = DefaultResource::get())
192 : effect(effect), resource(resource), value(symbol),
193 parameters(parameters), stage(stage),
194 effectOnFullRegion(effectOnFullRegion) {}
195
196 /// Return the effect being applied.
197 EffectT *getEffect() const { return effect; }
198
199 /// Return the value the effect is applied on, or nullptr if there isn't a
200 /// known value being affected.
201 Value getValue() const {
202 return value ? llvm::dyn_cast_if_present<Value>(Val: value) : Value();
203 }
204
205 /// Return the symbol reference the effect is applied on, or nullptr if there
206 /// isn't a known smbol being affected.
207 SymbolRefAttr getSymbolRef() const {
208 return value ? llvm::dyn_cast_if_present<SymbolRefAttr>(value)
209 : SymbolRefAttr();
210 }
211
212 /// Return the resource that the effect applies to.
213 Resource *getResource() const { return resource; }
214
215 /// Return the parameters of the effect, if any.
216 Attribute getParameters() const { return parameters; }
217
218 /// Return the effect happen stage.
219 int getStage() const { return stage; }
220
221 /// Return if this side effect act on every single value of resource.
222 bool getEffectOnFullRegion() const { return effectOnFullRegion; }
223
224private:
225 /// The specific effect being applied.
226 EffectT *effect;
227
228 /// The resource that the given value resides in.
229 Resource *resource;
230
231 /// The Symbol or Value that the effect applies to. This is optionally null.
232 PointerUnion<SymbolRefAttr, Value> value;
233
234 /// Additional parameters of the effect instance. An attribute is used for
235 /// type-safe structured storage and context-based uniquing. Concrete effects
236 /// can use this at their convenience. This is optionally null.
237 Attribute parameters;
238
239 // The stage side effect happen. Side effect with a lower stage
240 // number happen earlier than those with a higher stage number
241 int stage;
242
243 // Does this side effect act on every single value of resource.
244 bool effectOnFullRegion;
245};
246} // namespace SideEffects
247
248namespace Speculation {
249/// This enum is returned from the `getSpeculatability` method in the
250/// `ConditionallySpeculatable` op interface.
251enum class Speculatability {
252 /// The Operation in question cannot be speculatively executed. This could be
253 /// because it may invoke undefined behavior or have other side effects.
254 NotSpeculatable,
255
256 // The Operation in question can be speculatively executed. It does not have
257 // any side effects or undefined behavior.
258 Speculatable,
259
260 // The Operation in question can be speculatively executed if all the
261 // operations in all attached regions can also be speculatively executed.
262 RecursivelySpeculatable,
263};
264
265constexpr auto NotSpeculatable = Speculatability::NotSpeculatable;
266constexpr auto Speculatable = Speculatability::Speculatable;
267constexpr auto RecursivelySpeculatable =
268 Speculatability::RecursivelySpeculatable;
269} // namespace Speculation
270
271//===----------------------------------------------------------------------===//
272// SideEffect Traits
273//===----------------------------------------------------------------------===//
274
275namespace OpTrait {
276/// This trait indicates that the memory effects of an operation includes the
277/// effects of operations nested within its regions. If the operation has no
278/// derived effects interfaces, the operation itself can be assumed to have no
279/// memory effects.
280template <typename ConcreteType>
281class HasRecursiveMemoryEffects
282 : public TraitBase<ConcreteType, HasRecursiveMemoryEffects> {};
283
284/// This trait marks an op (which must be tagged as implementing the
285/// ConditionallySpeculatable interface) as being recursively speculatable.
286/// This means that said op can be speculated only if all the instructions in
287/// all the regions attached to the op can be speculated.
288template <typename ConcreteType>
289struct RecursivelySpeculatableImplTrait
290 : public TraitBase<ConcreteType, RecursivelySpeculatableImplTrait> {
291
292 Speculation::Speculatability getSpeculatability() {
293 return Speculation::RecursivelySpeculatable;
294 }
295};
296
297/// This trait marks an op (which must be tagged as implementing the
298/// ConditionallySpeculatable interface) as being always speculatable.
299template <typename ConcreteType>
300struct AlwaysSpeculatableImplTrait
301 : public TraitBase<ConcreteType, AlwaysSpeculatableImplTrait> {
302
303 Speculation::Speculatability getSpeculatability() {
304 return Speculation::Speculatable;
305 }
306};
307} // namespace OpTrait
308
309//===----------------------------------------------------------------------===//
310// Operation Memory-Effect Modeling
311//===----------------------------------------------------------------------===//
312
313namespace MemoryEffects {
314/// This class represents the base class used for memory effects.
315struct Effect : public SideEffects::Effect {
316 using SideEffects::Effect::Effect;
317
318 /// A base class for memory effects that provides helper utilities.
319 template <typename DerivedEffect>
320 using Base = SideEffects::Effect::Base<DerivedEffect, Effect>;
321
322 static bool classof(const SideEffects::Effect *effect);
323};
324using EffectInstance = SideEffects::EffectInstance<Effect>;
325
326/// The following effect indicates that the operation allocates from some
327/// resource. An 'allocate' effect implies only allocation of the resource, and
328/// not any visible mutation or dereference.
329struct Allocate : public Effect::Base<Allocate> {};
330
331/// The following effect indicates that the operation frees some resource that
332/// has been allocated. An 'allocate' effect implies only de-allocation of the
333/// resource, and not any visible allocation, mutation or dereference.
334struct Free : public Effect::Base<Free> {};
335
336/// The following effect indicates that the operation reads from some resource.
337/// A 'read' effect implies only dereferencing of the resource, and not any
338/// visible mutation.
339struct Read : public Effect::Base<Read> {};
340
341/// The following effect indicates that the operation writes to some resource. A
342/// 'write' effect implies only mutating a resource, and not any visible
343/// dereference or read.
344struct Write : public Effect::Base<Write> {};
345} // namespace MemoryEffects
346
347//===----------------------------------------------------------------------===//
348// SideEffect Utilities
349//===----------------------------------------------------------------------===//
350
351/// Returns true if `op` has only an effect of type `EffectTy` (and of no other
352/// type) on `value`. If no value is provided, simply check if effects of that
353/// type and only of that type are present.
354template <typename EffectTy>
355bool hasSingleEffect(Operation *op, Value value = nullptr);
356
357/// Returns true if `op` has an effect of type `EffectTy` on `value`. If no
358/// `value` is provided, simply check if effects of the given type(s) are
359/// present.
360template <typename... EffectTys>
361bool hasEffect(Operation *op, Value value = nullptr);
362
363/// Return true if the given operation is unused, and has no side effects on
364/// memory that prevent erasing.
365bool isOpTriviallyDead(Operation *op);
366
367/// Return true if the given operation would be dead if unused, and has no side
368/// effects on memory that would prevent erasing. This is equivalent to checking
369/// `isOpTriviallyDead` if `op` was unused.
370///
371/// Note: Terminators and symbols are never considered to be trivially dead.
372bool wouldOpBeTriviallyDead(Operation *op);
373
374/// Returns true if the given operation is free of memory effects.
375///
376/// An operation is free of memory effects if its implementation of
377/// `MemoryEffectOpInterface` indicates that it has no memory effects. For
378/// example, it may implement `NoMemoryEffect` in ODS. Alternatively, if the
379/// operation has the `HasRecursiveMemoryEffects` trait, then it is free of
380/// memory effects if all of its nested operations are free of memory effects.
381///
382/// If the operation has both, then it is free of memory effects if both
383/// conditions are satisfied.
384bool isMemoryEffectFree(Operation *op);
385
386/// Returns the side effects of an operation. If the operation has
387/// RecursiveMemoryEffects, include all side effects of child operations.
388///
389/// std::nullopt indicates that an option did not have a memory effect interface
390/// and so no result could be obtained. An empty vector indicates that there
391/// were no memory effects found (but every operation implemented the memory
392/// effect interface or has RecursiveMemoryEffects). If the vector contains
393/// multiple effects, these effects may be duplicates.
394std::optional<llvm::SmallVector<MemoryEffects::EffectInstance>>
395getEffectsRecursively(Operation *rootOp);
396
397/// Returns true if the given operation is speculatable, i.e. has no undefined
398/// behavior or other side effects.
399///
400/// An operation can indicate that it is speculatable by implementing the
401/// getSpeculatability hook in the ConditionallySpeculatable op interface.
402bool isSpeculatable(Operation *op);
403
404/// Returns true if the given operation is pure, i.e., is speculatable that does
405/// not touch memory.
406///
407/// This function is the C++ equivalent of the `Pure` trait.
408bool isPure(Operation *op);
409
410} // namespace mlir
411
412//===----------------------------------------------------------------------===//
413// SideEffect Interfaces
414//===----------------------------------------------------------------------===//
415
416/// Include the definitions of the side effect interfaces.
417#include "mlir/Interfaces/SideEffectInterfaces.h.inc"
418
419#endif // MLIR_INTERFACES_SIDEEFFECTINTERFACES_H
420

source code of mlir/include/mlir/Interfaces/SideEffectInterfaces.h