1 //===- SideEffectInterfaces.cpp - SideEffects in MLIR ---------------------===//
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
7 //===----------------------------------------------------------------------===//
9 #include "mlir/Interfaces/SideEffectInterfaces.h"
11 #include "mlir/IR/SymbolTable.h"
12 #include "llvm/ADT/SmallPtrSet.h"
16 //===----------------------------------------------------------------------===//
17 // SideEffect Interfaces
18 //===----------------------------------------------------------------------===//
20 /// Include the definitions of the side effect interfaces.
21 #include "mlir/Interfaces/SideEffectInterfaces.cpp.inc"
23 //===----------------------------------------------------------------------===//
25 //===----------------------------------------------------------------------===//
27 bool MemoryEffects::Effect::classof(const SideEffects::Effect
*effect
) {
28 return isa
<Allocate
, Free
, Read
, Write
>(effect
);
31 //===----------------------------------------------------------------------===//
32 // SideEffect Utilities
33 //===----------------------------------------------------------------------===//
35 bool mlir::isOpTriviallyDead(Operation
*op
) {
36 return op
->use_empty() && wouldOpBeTriviallyDead(op
);
39 /// Internal implementation of `mlir::wouldOpBeTriviallyDead` that also
40 /// considers terminator operations as dead if they have no side effects. This
41 /// allows for marking region operations as trivially dead without always being
42 /// conservative of terminators.
43 static bool wouldOpBeTriviallyDeadImpl(Operation
*rootOp
) {
44 // The set of operations to consider when checking for side effects.
45 SmallVector
<Operation
*, 1> effectingOps(1, rootOp
);
46 while (!effectingOps
.empty()) {
47 Operation
*op
= effectingOps
.pop_back_val();
49 // If the operation has recursive effects, push all of the nested operations
50 // on to the stack to consider.
51 bool hasRecursiveEffects
=
52 op
->hasTrait
<OpTrait::HasRecursiveMemoryEffects
>();
53 if (hasRecursiveEffects
) {
54 for (Region
®ion
: op
->getRegions()) {
55 for (auto &block
: region
) {
56 for (auto &nestedOp
: block
)
57 effectingOps
.push_back(&nestedOp
);
62 // If the op has memory effects, try to characterize them to see if the op
63 // is trivially dead here.
64 if (auto effectInterface
= dyn_cast
<MemoryEffectOpInterface
>(op
)) {
65 // Check to see if this op either has no effects, or only allocates/reads
67 SmallVector
<MemoryEffects::EffectInstance
, 1> effects
;
68 effectInterface
.getEffects(effects
);
70 // Gather all results of this op that are allocated.
71 SmallPtrSet
<Value
, 4> allocResults
;
72 for (const MemoryEffects::EffectInstance
&it
: effects
)
73 if (isa
<MemoryEffects::Allocate
>(it
.getEffect()) && it
.getValue() &&
74 it
.getValue().getDefiningOp() == op
)
75 allocResults
.insert(it
.getValue());
77 if (!llvm::all_of(effects
, [&allocResults
](
78 const MemoryEffects::EffectInstance
&it
) {
79 // We can drop effects if the value is an allocation and is a result
81 if (allocResults
.contains(it
.getValue()))
83 // Otherwise, the effect must be a read.
84 return isa
<MemoryEffects::Read
>(it
.getEffect());
90 // Otherwise, if the op has recursive side effects we can treat the
91 // operation itself as having no effects.
93 if (hasRecursiveEffects
)
96 // If there were no effect interfaces, we treat this op as conservatively
101 // If we get here, none of the operations had effects that prevented marking
106 template <typename EffectTy
>
107 bool mlir::hasSingleEffect(Operation
*op
, Value value
) {
108 auto memOp
= dyn_cast
<MemoryEffectOpInterface
>(op
);
111 SmallVector
<SideEffects::EffectInstance
<MemoryEffects::Effect
>, 4> effects
;
112 memOp
.getEffects(effects
);
113 bool hasSingleEffectOnVal
= false;
114 // Iterate through `effects` and check if an effect of type `EffectTy` and
115 // only of that type is present. A `value` to check the effect on may or may
116 // not have been provided.
117 for (auto &effect
: effects
) {
118 if (value
&& effect
.getValue() != value
)
120 hasSingleEffectOnVal
= isa
<EffectTy
>(effect
.getEffect());
121 if (!hasSingleEffectOnVal
)
124 return hasSingleEffectOnVal
;
127 template bool mlir::hasSingleEffect
<MemoryEffects::Allocate
>(Operation
*,
129 template bool mlir::hasSingleEffect
<MemoryEffects::Free
>(Operation
*, Value
);
130 template bool mlir::hasSingleEffect
<MemoryEffects::Read
>(Operation
*, Value
);
131 template bool mlir::hasSingleEffect
<MemoryEffects::Write
>(Operation
*, Value
);
133 template <typename
... EffectTys
>
134 bool mlir::hasEffect(Operation
*op
, Value value
) {
135 auto memOp
= dyn_cast
<MemoryEffectOpInterface
>(op
);
138 SmallVector
<SideEffects::EffectInstance
<MemoryEffects::Effect
>, 4> effects
;
139 memOp
.getEffects(effects
);
140 return llvm::any_of(effects
, [&](MemoryEffects::EffectInstance
&effect
) {
141 if (value
&& effect
.getValue() != value
)
143 return isa
<EffectTys
...>(effect
.getEffect());
146 template bool mlir::hasEffect
<MemoryEffects::Allocate
>(Operation
*, Value
);
147 template bool mlir::hasEffect
<MemoryEffects::Free
>(Operation
*, Value
);
148 template bool mlir::hasEffect
<MemoryEffects::Read
>(Operation
*, Value
);
149 template bool mlir::hasEffect
<MemoryEffects::Write
>(Operation
*, Value
);
151 mlir::hasEffect
<MemoryEffects::Write
, MemoryEffects::Free
>(Operation
*, Value
);
153 bool mlir::wouldOpBeTriviallyDead(Operation
*op
) {
154 if (op
->mightHaveTrait
<OpTrait::IsTerminator
>())
156 if (isa
<SymbolOpInterface
>(op
))
158 return wouldOpBeTriviallyDeadImpl(op
);
161 bool mlir::isMemoryEffectFree(Operation
*op
) {
162 if (auto memInterface
= dyn_cast
<MemoryEffectOpInterface
>(op
)) {
163 if (!memInterface
.hasNoEffect())
165 // If the op does not have recursive side effects, then it is memory effect
167 if (!op
->hasTrait
<OpTrait::HasRecursiveMemoryEffects
>())
169 } else if (!op
->hasTrait
<OpTrait::HasRecursiveMemoryEffects
>()) {
170 // Otherwise, if the op does not implement the memory effect interface and
171 // it does not have recursive side effects, then it cannot be known that the
176 // Recurse into the regions and ensure that all nested ops are memory effect
178 for (Region
®ion
: op
->getRegions())
179 for (Operation
&op
: region
.getOps())
180 if (!isMemoryEffectFree(&op
))
185 // the returned vector may contain duplicate effects
186 std::optional
<llvm::SmallVector
<MemoryEffects::EffectInstance
>>
187 mlir::getEffectsRecursively(Operation
*rootOp
) {
188 SmallVector
<MemoryEffects::EffectInstance
> effects
;
189 SmallVector
<Operation
*> effectingOps(1, rootOp
);
190 while (!effectingOps
.empty()) {
191 Operation
*op
= effectingOps
.pop_back_val();
193 // If the operation has recursive effects, push all of the nested
194 // operations on to the stack to consider.
195 bool hasRecursiveEffects
=
196 op
->hasTrait
<OpTrait::HasRecursiveMemoryEffects
>();
197 if (hasRecursiveEffects
) {
198 for (Region
®ion
: op
->getRegions()) {
199 for (Block
&block
: region
) {
200 for (Operation
&nestedOp
: block
) {
201 effectingOps
.push_back(&nestedOp
);
207 if (auto effectInterface
= dyn_cast
<MemoryEffectOpInterface
>(op
)) {
208 effectInterface
.getEffects(effects
);
209 } else if (!hasRecursiveEffects
) {
210 // the operation does not have recursive memory effects or implement
211 // the memory effect op interface. Its effects are unknown.
218 bool mlir::isSpeculatable(Operation
*op
) {
219 auto conditionallySpeculatable
= dyn_cast
<ConditionallySpeculatable
>(op
);
220 if (!conditionallySpeculatable
)
223 switch (conditionallySpeculatable
.getSpeculatability()) {
224 case Speculation::RecursivelySpeculatable
:
225 for (Region
®ion
: op
->getRegions()) {
226 for (Operation
&op
: region
.getOps())
227 if (!isSpeculatable(&op
))
232 case Speculation::Speculatable
:
235 case Speculation::NotSpeculatable
:
239 llvm_unreachable("Unhandled enum in mlir::isSpeculatable!");
242 /// The implementation of this function replicates the `def Pure : TraitList`
243 /// in `SideEffectInterfaces.td` and has to be kept in sync manually.
244 bool mlir::isPure(Operation
*op
) {
245 return isSpeculatable(op
) && isMemoryEffectFree(op
);