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  template <typename T,
149  std::enable_if_t<
150  llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
151  bool> = true>
152  EffectInstance(EffectT *effect, T value,
153  Resource *resource = DefaultResource::get())
154  : effect(effect), resource(resource), value(value), stage(0),
155  effectOnFullRegion(false) {}
156  template <typename T,
157  std::enable_if_t<
158  llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
159  bool> = true>
160  EffectInstance(EffectT *effect, T value, int stage, bool effectOnFullRegion,
161  Resource *resource = DefaultResource::get())
162  : effect(effect), resource(resource), value(value), stage(stage),
163  effectOnFullRegion(effectOnFullRegion) {}
164  EffectInstance(EffectT *effect, SymbolRefAttr symbol,
165  Resource *resource = DefaultResource::get())
166  : effect(effect), resource(resource), value(symbol), stage(0),
167  effectOnFullRegion(false) {}
168  EffectInstance(EffectT *effect, SymbolRefAttr symbol, int stage,
169  bool effectOnFullRegion,
170  Resource *resource = DefaultResource::get())
171  : effect(effect), resource(resource), value(symbol), stage(stage),
172  effectOnFullRegion(effectOnFullRegion) {}
173  EffectInstance(EffectT *effect, Attribute parameters,
174  Resource *resource = DefaultResource::get())
175  : effect(effect), resource(resource), parameters(parameters), stage(0),
176  effectOnFullRegion(false) {}
177  EffectInstance(EffectT *effect, Attribute parameters, int stage,
178  bool effectOnFullRegion,
179  Resource *resource = DefaultResource::get())
180  : effect(effect), resource(resource), parameters(parameters),
181  stage(stage), effectOnFullRegion(effectOnFullRegion) {}
182  template <typename T,
183  std::enable_if_t<
184  llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
185  bool> = true>
186  EffectInstance(EffectT *effect, T value, Attribute parameters,
187  Resource *resource = DefaultResource::get())
188  : effect(effect), resource(resource), value(value),
189  parameters(parameters), stage(0), effectOnFullRegion(false) {}
190  template <typename T,
191  std::enable_if_t<
192  llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
193  bool> = true>
194  EffectInstance(EffectT *effect, T value, Attribute parameters, int stage,
195  bool effectOnFullRegion,
196  Resource *resource = DefaultResource::get())
197  : effect(effect), resource(resource), value(value),
198  parameters(parameters), stage(stage),
199  effectOnFullRegion(effectOnFullRegion) {}
200  EffectInstance(EffectT *effect, SymbolRefAttr symbol, Attribute parameters,
201  Resource *resource = DefaultResource::get())
202  : effect(effect), resource(resource), value(symbol),
203  parameters(parameters), stage(0), effectOnFullRegion(false) {}
204  EffectInstance(EffectT *effect, SymbolRefAttr symbol, Attribute parameters,
205  int stage, bool effectOnFullRegion,
206  Resource *resource = DefaultResource::get())
207  : effect(effect), resource(resource), value(symbol),
208  parameters(parameters), stage(stage),
209  effectOnFullRegion(effectOnFullRegion) {}
210 
211  /// Return the effect being applied.
212  EffectT *getEffect() const { return effect; }
213 
214  /// Return the value the effect is applied on, or nullptr if there isn't a
215  /// known value being affected.
216  Value getValue() const {
217  if (!value || llvm::isa_and_present<SymbolRefAttr>(value)) {
218  return Value();
219  }
220  if (OpOperand *operand = llvm::dyn_cast_if_present<OpOperand *>(value)) {
221  return operand->get();
222  }
223  if (OpResult result = llvm::dyn_cast_if_present<OpResult>(value)) {
224  return result;
225  }
226  return cast_if_present<BlockArgument>(value);
227  }
228 
229  /// Returns the OpOperand effect is applied on, or nullptr if there isn't a
230  /// known value being effected.
231  template <typename T,
232  std::enable_if_t<
233  llvm::is_one_of<T, OpOperand *, OpResult, BlockArgument>::value,
234  bool> = true>
235  T getEffectValue() const {
236  return value ? dyn_cast_if_present<T>(value) : nullptr;
237  }
238 
239  /// Return the symbol reference the effect is applied on, or nullptr if there
240  /// isn't a known smbol being affected.
241  SymbolRefAttr getSymbolRef() const {
242  return value ? llvm::dyn_cast_if_present<SymbolRefAttr>(value)
243  : SymbolRefAttr();
244  }
245 
246  /// Return the resource that the effect applies to.
247  Resource *getResource() const { return resource; }
248 
249  /// Return the parameters of the effect, if any.
250  Attribute getParameters() const { return parameters; }
251 
252  /// Return the effect happen stage.
253  int getStage() const { return stage; }
254 
255  /// Return if this side effect act on every single value of resource.
256  bool getEffectOnFullRegion() const { return effectOnFullRegion; }
257 
258 private:
259  /// The specific effect being applied.
260  EffectT *effect;
261 
262  /// The resource that the given value resides in.
263  Resource *resource;
264 
265  /// The Symbol, OpOperand, OpResult or BlockArgument that the effect applies
266  /// to. This is optionally null.
268 
269  /// Additional parameters of the effect instance. An attribute is used for
270  /// type-safe structured storage and context-based uniquing. Concrete effects
271  /// can use this at their convenience. This is optionally null.
272  Attribute parameters;
273 
274  // The stage side effect happen. Side effect with a lower stage
275  // number happen earlier than those with a higher stage number
276  int stage;
277 
278  // Does this side effect act on every single value of resource.
279  bool effectOnFullRegion;
280 };
281 } // namespace SideEffects
282 
283 namespace Speculation {
284 /// This enum is returned from the `getSpeculatability` method in the
285 /// `ConditionallySpeculatable` op interface.
286 enum class Speculatability {
287  /// The Operation in question cannot be speculatively executed. This could be
288  /// because it may invoke undefined behavior or have other side effects.
290 
291  // The Operation in question can be speculatively executed. It does not have
292  // any side effects or undefined behavior.
293  Speculatable,
294 
295  // The Operation in question can be speculatively executed if all the
296  // operations in all attached regions can also be speculatively executed.
298 };
299 
302 constexpr auto RecursivelySpeculatable =
304 } // namespace Speculation
305 
306 //===----------------------------------------------------------------------===//
307 // SideEffect Traits
308 //===----------------------------------------------------------------------===//
309 
310 namespace OpTrait {
311 /// This trait indicates that the memory effects of an operation includes the
312 /// effects of operations nested within its regions. If the operation has no
313 /// derived effects interfaces, the operation itself can be assumed to have no
314 /// memory effects.
315 template <typename ConcreteType>
317  : public TraitBase<ConcreteType, HasRecursiveMemoryEffects> {};
318 
319 /// This trait marks an op (which must be tagged as implementing the
320 /// ConditionallySpeculatable interface) as being recursively speculatable.
321 /// This means that said op can be speculated only if all the instructions in
322 /// all the regions attached to the op can be speculated.
323 template <typename ConcreteType>
325  : public TraitBase<ConcreteType, RecursivelySpeculatableImplTrait> {
326 
329  }
330 };
331 
332 /// This trait marks an op (which must be tagged as implementing the
333 /// ConditionallySpeculatable interface) as being always speculatable.
334 template <typename ConcreteType>
336  : public TraitBase<ConcreteType, AlwaysSpeculatableImplTrait> {
337 
340  }
341 };
342 } // namespace OpTrait
343 
344 //===----------------------------------------------------------------------===//
345 // Operation Memory-Effect Modeling
346 //===----------------------------------------------------------------------===//
347 
348 namespace MemoryEffects {
349 /// This class represents the base class used for memory effects.
350 struct Effect : public SideEffects::Effect {
352 
353  /// A base class for memory effects that provides helper utilities.
354  template <typename DerivedEffect>
356 
357  static bool classof(const SideEffects::Effect *effect);
358 };
360 
361 /// The following effect indicates that the operation allocates from some
362 /// resource. An 'allocate' effect implies only allocation of the resource, and
363 /// not any visible mutation or dereference.
364 struct Allocate : public Effect::Base<Allocate> {};
365 
366 /// The following effect indicates that the operation frees some resource that
367 /// has been allocated. An 'allocate' effect implies only de-allocation of the
368 /// resource, and not any visible allocation, mutation or dereference.
369 struct Free : public Effect::Base<Free> {};
370 
371 /// The following effect indicates that the operation reads from some resource.
372 /// A 'read' effect implies only dereferencing of the resource, and not any
373 /// visible mutation.
374 struct Read : public Effect::Base<Read> {};
375 
376 /// The following effect indicates that the operation writes to some resource. A
377 /// 'write' effect implies only mutating a resource, and not any visible
378 /// dereference or read.
379 struct Write : public Effect::Base<Write> {};
380 } // namespace MemoryEffects
381 
382 //===----------------------------------------------------------------------===//
383 // SideEffect Utilities
384 //===----------------------------------------------------------------------===//
385 
386 /// Returns true if `op` has only an effect of type `EffectTy`.
387 template <typename EffectTy>
388 bool hasSingleEffect(Operation *op);
389 
390 /// Returns true if `op` has only an effect of type `EffectTy` (and of no other
391 /// type) on `value`.
392 template <typename EffectTy>
393 bool hasSingleEffect(Operation *op, Value value);
394 
395 /// Returns true if `op` has only an effect of type `EffectTy` (and of no other
396 /// type) on `value` of type `ValueTy`.
397 template <typename ValueTy, typename EffectTy>
398 bool hasSingleEffect(Operation *op, ValueTy value);
399 
400 /// Returns true if `op` has an effect of type `EffectTy`.
401 template <typename... EffectTys>
402 bool hasEffect(Operation *op);
403 
404 /// Returns true if `op` has an effect of type `EffectTy` on `value`.
405 template <typename... EffectTys>
406 bool hasEffect(Operation *op, Value value);
407 
408 /// Returns true if `op` has an effect of type `EffectTy` on `value` of type
409 /// `ValueTy`.
410 template <typename ValueTy, typename... EffectTys>
411 bool hasEffect(Operation *op, ValueTy value);
412 
413 /// Return true if the given operation is unused, and has no side effects on
414 /// memory that prevent erasing.
415 bool isOpTriviallyDead(Operation *op);
416 
417 /// Return true if the given operation would be dead if unused, and has no side
418 /// effects on memory that would prevent erasing. This is equivalent to checking
419 /// `isOpTriviallyDead` if `op` was unused.
420 ///
421 /// Note: Terminators and symbols are never considered to be trivially dead.
423 
424 /// Returns true if the given operation is free of memory effects.
425 ///
426 /// An operation is free of memory effects if its implementation of
427 /// `MemoryEffectOpInterface` indicates that it has no memory effects. For
428 /// example, it may implement `NoMemoryEffect` in ODS. Alternatively, if the
429 /// operation has the `HasRecursiveMemoryEffects` trait, then it is free of
430 /// memory effects if all of its nested operations are free of memory effects.
431 ///
432 /// If the operation has both, then it is free of memory effects if both
433 /// conditions are satisfied.
434 bool isMemoryEffectFree(Operation *op);
435 
436 /// Returns the side effects of an operation. If the operation has
437 /// RecursiveMemoryEffects, include all side effects of child operations.
438 ///
439 /// std::nullopt indicates that an option did not have a memory effect interface
440 /// and so no result could be obtained. An empty vector indicates that there
441 /// were no memory effects found (but every operation implemented the memory
442 /// effect interface or has RecursiveMemoryEffects). If the vector contains
443 /// multiple effects, these effects may be duplicates.
444 std::optional<llvm::SmallVector<MemoryEffects::EffectInstance>>
446 
447 /// Returns true if the given operation is speculatable, i.e. has no undefined
448 /// behavior or other side effects.
449 ///
450 /// An operation can indicate that it is speculatable by implementing the
451 /// getSpeculatability hook in the ConditionallySpeculatable op interface.
452 bool isSpeculatable(Operation *op);
453 
454 /// Returns true if the given operation is pure, i.e., is speculatable that does
455 /// not touch memory.
456 ///
457 /// This function is the C++ equivalent of the `Pure` trait.
458 bool isPure(Operation *op);
459 
460 } // namespace mlir
461 
462 //===----------------------------------------------------------------------===//
463 // SideEffect Interfaces
464 //===----------------------------------------------------------------------===//
465 
466 /// Include the definitions of the side effect interfaces.
467 #include "mlir/Interfaces/SideEffectInterfaces.h.inc"
468 
469 #endif // MLIR_INTERFACES_SIDEEFFECTINTERFACES_H
Attributes are known-constant values of operations.
Definition: Attributes.h:25
This class represents an operand of an operation.
Definition: Value.h:267
This is a value defined by a result of an operation.
Definition: Value.h:457
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, T value, Attribute parameters, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, T 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())
T getEffectValue() const
Returns the OpOperand effect is applied on, or nullptr if there isn't a known value being effected.
EffectInstance(EffectT *effect, SymbolRefAttr symbol, Resource *resource=DefaultResource::get())
EffectInstance(EffectT *effect, T value, int stage, bool effectOnFullRegion, 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.
EffectInstance(EffectT *effect, T value, Attribute parameters, int stage, bool effectOnFullRegion, Resource *resource=DefaultResource::get())
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, 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 hasSingleEffect(Operation *op)
Returns true if op has only an effect of type EffectTy.
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 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.
bool hasEffect(Operation *op)
Returns true if op has an effect of type EffectTy.
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.