MLIR  19.0.0git
SideEffectInterfaces.h
Go to the documentation of this file.
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:
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 
65 protected:
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:
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 
113 protected:
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> {
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.
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.
138 template <typename EffectT>
140 public:
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>(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 
224 private:
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.
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 
248 namespace Speculation {
249 /// This enum is returned from the `getSpeculatability` method in the
250 /// `ConditionallySpeculatable` op interface.
251 enum 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.
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.
263 };
264 
267 constexpr auto RecursivelySpeculatable =
269 } // namespace Speculation
270 
271 //===----------------------------------------------------------------------===//
272 // SideEffect Traits
273 //===----------------------------------------------------------------------===//
274 
275 namespace 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.
280 template <typename ConcreteType>
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.
288 template <typename ConcreteType>
290  : public TraitBase<ConcreteType, RecursivelySpeculatableImplTrait> {
291 
294  }
295 };
296 
297 /// This trait marks an op (which must be tagged as implementing the
298 /// ConditionallySpeculatable interface) as being always speculatable.
299 template <typename ConcreteType>
301  : public TraitBase<ConcreteType, AlwaysSpeculatableImplTrait> {
302 
305  }
306 };
307 } // namespace OpTrait
308 
309 //===----------------------------------------------------------------------===//
310 // Operation Memory-Effect Modeling
311 //===----------------------------------------------------------------------===//
312 
313 namespace MemoryEffects {
314 /// This class represents the base class used for memory effects.
315 struct Effect : public SideEffects::Effect {
317 
318  /// A base class for memory effects that provides helper utilities.
319  template <typename DerivedEffect>
321 
322  static bool classof(const SideEffects::Effect *effect);
323 };
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.
329 struct 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.
334 struct 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.
339 struct 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.
344 struct 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.
354 template <typename EffectTy>
355 bool 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.
360 template <typename... EffectTys>
361 bool 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.
365 bool 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.
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.
384 bool 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.
394 std::optional<llvm::SmallVector<MemoryEffects::EffectInstance>>
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.
402 bool 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.
408 bool 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
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This trait indicates that the memory effects of an operation includes the effects of operations neste...
Helper class for implementing traits.
Definition: OpDefinition.h:373
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
This class represents a specific instance of an effect.
EffectInstance(EffectT *effect, Value value, Attribute parameters, int stage, bool effectOnFullRegion, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, Value value, Attribute parameters, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, Value value, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, SymbolRefAttr symbol, Attribute parameters, int stage, bool effectOnFullRegion, Resource *resource=DefaultResource::get())
bool getEffectOnFullRegion() const
Return if this side effect act on every single value of resource.
int getStage() const
Return the effect happen stage.
EffectInstance(EffectT *effect, SymbolRefAttr symbol, Attribute parameters, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, SymbolRefAttr symbol, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, Resource *resource=DefaultResource::get())
SymbolRefAttr getSymbolRef() const
Return the symbol reference the effect is applied on, or nullptr if there isn't a known smbol being a...
EffectInstance(EffectT *effect, int stage, bool effectOnFullRegion, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, Attribute parameters, Resource *resource=DefaultResource::get())
Resource * getResource() const
Return the resource that the effect applies to.
Attribute getParameters() const
Return the parameters of the effect, if any.
EffectT * getEffect() const
Return the effect being applied.
Value getValue() const
Return the value the effect is applied on, or nullptr if there isn't a known value being affected.
EffectInstance(EffectT *effect, Attribute parameters, int stage, bool effectOnFullRegion, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, Value value, int stage, bool effectOnFullRegion, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, SymbolRefAttr symbol, int stage, bool effectOnFullRegion, Resource *resource=DefaultResource::get())
This base class is used for derived effects that are non-parametric.
static TypeID getEffectID()
Return the unique identifier for the base effects class.
static bool classof(const ::mlir::SideEffects::Effect *effect)
'classof' used to support llvm style cast functionality.
static DerivedEffect * get()
Returns a unique instance for the derived effect class.
This class represents a base class for a specific effect type.
TypeID getEffectID() const
Return the unique identifier for the base effects class.
static DerivedEffect * get()
Returns a unique instance for the given effect class.
This base class is used for derived effects that are non-parametric.
static DerivedResource * get()
Returns a unique instance for the given effect class.
static TypeID getResourceID()
Return the unique identifier for the base resource class.
static bool classof(const Resource *resource)
'classof' used to support llvm style cast functionality.
This class represents a specific resource that an effect applies to.
TypeID getResourceID() const
Return the unique identifier for the base resource class.
virtual StringRef getName()=0
Return a string name of the resource.
virtual ~Resource()=default
This class provides an efficient unique identifier for a specific C++ type.
Definition: TypeID.h:104
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:96
constexpr auto RecursivelySpeculatable
Speculatability
This enum is returned from the getSpeculatability method in the ConditionallySpeculatable op interfac...
@ NotSpeculatable
The Operation in question cannot be speculatively executed.
constexpr auto Speculatable
constexpr auto NotSpeculatable
Include the generated interface declarations.
bool hasEffect(Operation *op, Value value=nullptr)
Returns true if op has an effect of type EffectTy on value.
bool isPure(Operation *op)
Returns true if the given operation is pure, i.e., is speculatable that does not touch memory.
bool isMemoryEffectFree(Operation *op)
Returns true if the given operation is free of memory effects.
bool wouldOpBeTriviallyDead(Operation *op)
Return true if the given operation would be dead if unused, and has no side effects on memory that wo...
bool hasSingleEffect(Operation *op, Value value=nullptr)
Returns true if op has only an effect of type EffectTy (and of no other type) on value.
bool isSpeculatable(Operation *op)
Returns true if the given operation is speculatable, i.e.
bool isOpTriviallyDead(Operation *op)
Return true if the given operation is unused, and has no side effects on memory that prevent erasing.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
std::optional< llvm::SmallVector< MemoryEffects::EffectInstance > > getEffectsRecursively(Operation *rootOp)
Returns the side effects of an operation.
The following effect indicates that the operation allocates from some resource.
This class represents the base class used for memory effects.
static bool classof(const SideEffects::Effect *effect)
Include the definitions of the side effect interfaces.
The following effect indicates that the operation frees some resource that has been allocated.
The following effect indicates that the operation reads from some resource.
The following effect indicates that the operation writes to some resource.
This trait marks an op (which must be tagged as implementing the ConditionallySpeculatable interface)...
Speculation::Speculatability getSpeculatability()
This trait marks an op (which must be tagged as implementing the ConditionallySpeculatable interface)...
An automatic allocation-scope resource that is valid in the context of a parent AutomaticAllocationSc...
StringRef getName() final
Return a string name of the resource.
A conservative default resource kind.
StringRef getName() final
Return a string name of the resource.