xref: /llvm-project/mlir/lib/Interfaces/SideEffectInterfaces.cpp (revision 21f04b1458c52ba875a23b58b02cf6b1f8db0661)
1eb623ae8SStephen Neuendorffer //===- SideEffectInterfaces.cpp - SideEffects in MLIR ---------------------===//
2eb623ae8SStephen Neuendorffer //
3eb623ae8SStephen Neuendorffer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4eb623ae8SStephen Neuendorffer // See https://llvm.org/LICENSE.txt for license information.
5eb623ae8SStephen Neuendorffer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6eb623ae8SStephen Neuendorffer //
7eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
8eb623ae8SStephen Neuendorffer 
9eb623ae8SStephen Neuendorffer #include "mlir/Interfaces/SideEffectInterfaces.h"
10eb623ae8SStephen Neuendorffer 
11253afd03SMatthias Springer #include "mlir/IR/SymbolTable.h"
1261394636SMarkus Böck #include "llvm/ADT/SmallPtrSet.h"
13*21f04b14SAdam Paszke #include <utility>
1461394636SMarkus Böck 
15eb623ae8SStephen Neuendorffer using namespace mlir;
16eb623ae8SStephen Neuendorffer 
17eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
18eb623ae8SStephen Neuendorffer // SideEffect Interfaces
19eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
20eb623ae8SStephen Neuendorffer 
21eb623ae8SStephen Neuendorffer /// Include the definitions of the side effect interfaces.
22eb623ae8SStephen Neuendorffer #include "mlir/Interfaces/SideEffectInterfaces.cpp.inc"
23eb623ae8SStephen Neuendorffer 
24eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
25eb623ae8SStephen Neuendorffer // MemoryEffects
26eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
27eb623ae8SStephen Neuendorffer 
28eb623ae8SStephen Neuendorffer bool MemoryEffects::Effect::classof(const SideEffects::Effect *effect) {
29d891d738SRahul Joshi   return isa<Allocate, Free, Read, Write>(effect);
30eb623ae8SStephen Neuendorffer }
31eb623ae8SStephen Neuendorffer 
32eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
33eb623ae8SStephen Neuendorffer // SideEffect Utilities
34eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
35eb623ae8SStephen Neuendorffer 
36eb623ae8SStephen Neuendorffer bool mlir::isOpTriviallyDead(Operation *op) {
37eb623ae8SStephen Neuendorffer   return op->use_empty() && wouldOpBeTriviallyDead(op);
38eb623ae8SStephen Neuendorffer }
39eb623ae8SStephen Neuendorffer 
40eb623ae8SStephen Neuendorffer /// Internal implementation of `mlir::wouldOpBeTriviallyDead` that also
41eb623ae8SStephen Neuendorffer /// considers terminator operations as dead if they have no side effects. This
42eb623ae8SStephen Neuendorffer /// allows for marking region operations as trivially dead without always being
43eb623ae8SStephen Neuendorffer /// conservative of terminators.
44eb623ae8SStephen Neuendorffer static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp) {
45*21f04b14SAdam Paszke   // The set of operation intervals (end-exclusive) to consider when checking
46*21f04b14SAdam Paszke   // for side effects.
47*21f04b14SAdam Paszke   SmallVector<std::pair<Block::iterator, Block::iterator>, 1> effectingOps = {
48*21f04b14SAdam Paszke       std::make_pair(Block::iterator(rootOp), ++Block::iterator(rootOp))};
49eb623ae8SStephen Neuendorffer   while (!effectingOps.empty()) {
50*21f04b14SAdam Paszke     Block::iterator &it = effectingOps.back().first;
51*21f04b14SAdam Paszke     Block::iterator end = effectingOps.back().second;
52*21f04b14SAdam Paszke     if (it == end) {
53*21f04b14SAdam Paszke       effectingOps.pop_back();
54*21f04b14SAdam Paszke       continue;
55*21f04b14SAdam Paszke     }
56*21f04b14SAdam Paszke     mlir::Operation *op = &*(it++);
57eb623ae8SStephen Neuendorffer 
58eb623ae8SStephen Neuendorffer     // If the operation has recursive effects, push all of the nested operations
59eb623ae8SStephen Neuendorffer     // on to the stack to consider.
6086771d0bSSanjoy Das     bool hasRecursiveEffects =
6186771d0bSSanjoy Das         op->hasTrait<OpTrait::HasRecursiveMemoryEffects>();
62eb623ae8SStephen Neuendorffer     if (hasRecursiveEffects) {
63eb623ae8SStephen Neuendorffer       for (Region &region : op->getRegions()) {
64eb623ae8SStephen Neuendorffer         for (auto &block : region) {
65*21f04b14SAdam Paszke           effectingOps.push_back(std::make_pair(block.begin(), block.end()));
66eb623ae8SStephen Neuendorffer         }
67eb623ae8SStephen Neuendorffer       }
68eb623ae8SStephen Neuendorffer     }
69eb623ae8SStephen Neuendorffer 
70eb623ae8SStephen Neuendorffer     // If the op has memory effects, try to characterize them to see if the op
71eb623ae8SStephen Neuendorffer     // is trivially dead here.
72eb623ae8SStephen Neuendorffer     if (auto effectInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
73eb623ae8SStephen Neuendorffer       // Check to see if this op either has no effects, or only allocates/reads
74eb623ae8SStephen Neuendorffer       // memory.
75eb623ae8SStephen Neuendorffer       SmallVector<MemoryEffects::EffectInstance, 1> effects;
76eb623ae8SStephen Neuendorffer       effectInterface.getEffects(effects);
7761394636SMarkus Böck 
7861394636SMarkus Böck       // Gather all results of this op that are allocated.
7961394636SMarkus Böck       SmallPtrSet<Value, 4> allocResults;
8061394636SMarkus Böck       for (const MemoryEffects::EffectInstance &it : effects)
8161394636SMarkus Böck         if (isa<MemoryEffects::Allocate>(it.getEffect()) && it.getValue() &&
8261394636SMarkus Böck             it.getValue().getDefiningOp() == op)
8361394636SMarkus Böck           allocResults.insert(it.getValue());
8461394636SMarkus Böck 
8561394636SMarkus Böck       if (!llvm::all_of(effects, [&allocResults](
8661394636SMarkus Böck                                      const MemoryEffects::EffectInstance &it) {
8761394636SMarkus Böck             // We can drop effects if the value is an allocation and is a result
8861394636SMarkus Böck             // of the operation.
8961394636SMarkus Böck             if (allocResults.contains(it.getValue()))
9061394636SMarkus Böck               return true;
91eb623ae8SStephen Neuendorffer             // Otherwise, the effect must be a read.
92eb623ae8SStephen Neuendorffer             return isa<MemoryEffects::Read>(it.getEffect());
93eb623ae8SStephen Neuendorffer           })) {
94eb623ae8SStephen Neuendorffer         return false;
95eb623ae8SStephen Neuendorffer       }
96eb623ae8SStephen Neuendorffer       continue;
97eb623ae8SStephen Neuendorffer     }
98*21f04b14SAdam Paszke     // Otherwise, if the op only has recursive side effects we can treat the
99*21f04b14SAdam Paszke     // operation itself as having no effects. We will visit its children next.
10002b6fb21SMehdi Amini     if (hasRecursiveEffects)
10102b6fb21SMehdi Amini       continue;
102eb623ae8SStephen Neuendorffer 
103eb623ae8SStephen Neuendorffer     // If there were no effect interfaces, we treat this op as conservatively
104eb623ae8SStephen Neuendorffer     // having effects.
105eb623ae8SStephen Neuendorffer     return false;
106eb623ae8SStephen Neuendorffer   }
107eb623ae8SStephen Neuendorffer 
108eb623ae8SStephen Neuendorffer   // If we get here, none of the operations had effects that prevented marking
109eb623ae8SStephen Neuendorffer   // 'op' as dead.
110eb623ae8SStephen Neuendorffer   return true;
111eb623ae8SStephen Neuendorffer }
112eb623ae8SStephen Neuendorffer 
11316219f8cSArnab Dutta template <typename EffectTy>
1142c1ae801Sdonald chen bool mlir::hasSingleEffect(Operation *op) {
1152c1ae801Sdonald chen   auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
1162c1ae801Sdonald chen   if (!memOp)
1172c1ae801Sdonald chen     return false;
1182c1ae801Sdonald chen   SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
1192c1ae801Sdonald chen   memOp.getEffects(effects);
1202c1ae801Sdonald chen   bool hasSingleEffectOnVal = false;
1212c1ae801Sdonald chen   // Iterate through `effects` and check if an effect of type `EffectTy` and
1222c1ae801Sdonald chen   // only of that type is present.
1232c1ae801Sdonald chen   for (auto &effect : effects) {
1242c1ae801Sdonald chen     hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
1252c1ae801Sdonald chen     if (!hasSingleEffectOnVal)
1262c1ae801Sdonald chen       return false;
1272c1ae801Sdonald chen   }
1282c1ae801Sdonald chen   return hasSingleEffectOnVal;
1292c1ae801Sdonald chen }
1302c1ae801Sdonald chen template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *);
1312c1ae801Sdonald chen template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *);
1322c1ae801Sdonald chen template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *);
1332c1ae801Sdonald chen template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *);
1342c1ae801Sdonald chen 
1352c1ae801Sdonald chen template <typename EffectTy>
13616219f8cSArnab Dutta bool mlir::hasSingleEffect(Operation *op, Value value) {
13716219f8cSArnab Dutta   auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
13816219f8cSArnab Dutta   if (!memOp)
13916219f8cSArnab Dutta     return false;
14016219f8cSArnab Dutta   SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
14116219f8cSArnab Dutta   memOp.getEffects(effects);
1429f7d8014SUday Bondhugula   bool hasSingleEffectOnVal = false;
1439f7d8014SUday Bondhugula   // Iterate through `effects` and check if an effect of type `EffectTy` and
1442c1ae801Sdonald chen   // only of that type is present.
14516219f8cSArnab Dutta   for (auto &effect : effects) {
1462c1ae801Sdonald chen     if (effect.getValue() != value)
1479f7d8014SUday Bondhugula       continue;
1489f7d8014SUday Bondhugula     hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
1499f7d8014SUday Bondhugula     if (!hasSingleEffectOnVal)
1509f7d8014SUday Bondhugula       return false;
15116219f8cSArnab Dutta   }
1529f7d8014SUday Bondhugula   return hasSingleEffectOnVal;
15316219f8cSArnab Dutta }
15416219f8cSArnab Dutta 
15516219f8cSArnab Dutta template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *,
1562c1ae801Sdonald chen                                                              Value value);
1572c1ae801Sdonald chen template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *,
1582c1ae801Sdonald chen                                                          Value value);
1592c1ae801Sdonald chen template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *,
1602c1ae801Sdonald chen                                                          Value value);
1612c1ae801Sdonald chen template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *,
1622c1ae801Sdonald chen                                                           Value value);
1632c1ae801Sdonald chen 
1642c1ae801Sdonald chen template <typename ValueTy, typename EffectTy>
1652c1ae801Sdonald chen bool mlir::hasSingleEffect(Operation *op, ValueTy value) {
1662c1ae801Sdonald chen   auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
1672c1ae801Sdonald chen   if (!memOp)
1682c1ae801Sdonald chen     return false;
1692c1ae801Sdonald chen   SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
1702c1ae801Sdonald chen   memOp.getEffects(effects);
1712c1ae801Sdonald chen   bool hasSingleEffectOnVal = false;
1722c1ae801Sdonald chen   // Iterate through `effects` and check if an effect of type `EffectTy` and
1732c1ae801Sdonald chen   // only of that type is present on value.
1742c1ae801Sdonald chen   for (auto &effect : effects) {
1752c1ae801Sdonald chen     if (effect.getEffectValue<ValueTy>() != value)
1762c1ae801Sdonald chen       continue;
1772c1ae801Sdonald chen     hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
1782c1ae801Sdonald chen     if (!hasSingleEffectOnVal)
1792c1ae801Sdonald chen       return false;
1802c1ae801Sdonald chen   }
1812c1ae801Sdonald chen   return hasSingleEffectOnVal;
1822c1ae801Sdonald chen }
1832c1ae801Sdonald chen 
1842c1ae801Sdonald chen template bool
1852c1ae801Sdonald chen mlir::hasSingleEffect<OpOperand *, MemoryEffects::Allocate>(Operation *,
1862c1ae801Sdonald chen                                                             OpOperand *);
1872c1ae801Sdonald chen template bool
1882c1ae801Sdonald chen mlir::hasSingleEffect<OpOperand *, MemoryEffects::Free>(Operation *,
1892c1ae801Sdonald chen                                                         OpOperand *);
1902c1ae801Sdonald chen template bool
1912c1ae801Sdonald chen mlir::hasSingleEffect<OpOperand *, MemoryEffects::Read>(Operation *,
1922c1ae801Sdonald chen                                                         OpOperand *);
1932c1ae801Sdonald chen template bool
1942c1ae801Sdonald chen mlir::hasSingleEffect<OpOperand *, MemoryEffects::Write>(Operation *,
1952c1ae801Sdonald chen                                                          OpOperand *);
1962c1ae801Sdonald chen template bool
1972c1ae801Sdonald chen mlir::hasSingleEffect<OpResult, MemoryEffects::Allocate>(Operation *, OpResult);
1982c1ae801Sdonald chen template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Free>(Operation *,
1992c1ae801Sdonald chen                                                                    OpResult);
2002c1ae801Sdonald chen template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Read>(Operation *,
2012c1ae801Sdonald chen                                                                    OpResult);
2022c1ae801Sdonald chen template bool mlir::hasSingleEffect<OpResult, MemoryEffects::Write>(Operation *,
2032c1ae801Sdonald chen                                                                     OpResult);
2042c1ae801Sdonald chen template bool
2052c1ae801Sdonald chen mlir::hasSingleEffect<BlockArgument, MemoryEffects::Allocate>(Operation *,
2062c1ae801Sdonald chen                                                               BlockArgument);
2072c1ae801Sdonald chen template bool
2082c1ae801Sdonald chen mlir::hasSingleEffect<BlockArgument, MemoryEffects::Free>(Operation *,
2092c1ae801Sdonald chen                                                           BlockArgument);
2102c1ae801Sdonald chen template bool
2112c1ae801Sdonald chen mlir::hasSingleEffect<BlockArgument, MemoryEffects::Read>(Operation *,
2122c1ae801Sdonald chen                                                           BlockArgument);
2132c1ae801Sdonald chen template bool
2142c1ae801Sdonald chen mlir::hasSingleEffect<BlockArgument, MemoryEffects::Write>(Operation *,
2152c1ae801Sdonald chen                                                            BlockArgument);
2162c1ae801Sdonald chen 
2172c1ae801Sdonald chen template <typename... EffectTys>
2182c1ae801Sdonald chen bool mlir::hasEffect(Operation *op) {
2192c1ae801Sdonald chen   auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
2202c1ae801Sdonald chen   if (!memOp)
2212c1ae801Sdonald chen     return false;
2222c1ae801Sdonald chen   SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
2232c1ae801Sdonald chen   memOp.getEffects(effects);
2242c1ae801Sdonald chen   return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
2252c1ae801Sdonald chen     return isa<EffectTys...>(effect.getEffect());
2262c1ae801Sdonald chen   });
2272c1ae801Sdonald chen }
2282c1ae801Sdonald chen template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *);
2292c1ae801Sdonald chen template bool mlir::hasEffect<MemoryEffects::Free>(Operation *);
2302c1ae801Sdonald chen template bool mlir::hasEffect<MemoryEffects::Read>(Operation *);
2312c1ae801Sdonald chen template bool mlir::hasEffect<MemoryEffects::Write>(Operation *);
2322c1ae801Sdonald chen template bool
2332c1ae801Sdonald chen mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *);
23416219f8cSArnab Dutta 
2358d7f2701SUday Bondhugula template <typename... EffectTys>
2368d7f2701SUday Bondhugula bool mlir::hasEffect(Operation *op, Value value) {
2378d7f2701SUday Bondhugula   auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
2388d7f2701SUday Bondhugula   if (!memOp)
2398d7f2701SUday Bondhugula     return false;
2408d7f2701SUday Bondhugula   SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
2418d7f2701SUday Bondhugula   memOp.getEffects(effects);
2428d7f2701SUday Bondhugula   return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
2432c1ae801Sdonald chen     if (effect.getValue() != value)
2448d7f2701SUday Bondhugula       return false;
2458d7f2701SUday Bondhugula     return isa<EffectTys...>(effect.getEffect());
2468d7f2701SUday Bondhugula   });
2478d7f2701SUday Bondhugula }
2482c1ae801Sdonald chen template bool mlir::hasEffect<MemoryEffects::Allocate>(Operation *,
2492c1ae801Sdonald chen                                                        Value value);
2502c1ae801Sdonald chen template bool mlir::hasEffect<MemoryEffects::Free>(Operation *, Value value);
2512c1ae801Sdonald chen template bool mlir::hasEffect<MemoryEffects::Read>(Operation *, Value value);
2522c1ae801Sdonald chen template bool mlir::hasEffect<MemoryEffects::Write>(Operation *, Value value);
2538d7f2701SUday Bondhugula template bool
2542c1ae801Sdonald chen mlir::hasEffect<MemoryEffects::Write, MemoryEffects::Free>(Operation *,
2552c1ae801Sdonald chen                                                            Value value);
2562c1ae801Sdonald chen 
2572c1ae801Sdonald chen template <typename ValueTy, typename... EffectTys>
2582c1ae801Sdonald chen bool mlir::hasEffect(Operation *op, ValueTy value) {
2592c1ae801Sdonald chen   auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
2602c1ae801Sdonald chen   if (!memOp)
2612c1ae801Sdonald chen     return false;
2622c1ae801Sdonald chen   SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
2632c1ae801Sdonald chen   memOp.getEffects(effects);
2642c1ae801Sdonald chen   return llvm::any_of(effects, [&](MemoryEffects::EffectInstance &effect) {
2652c1ae801Sdonald chen     if (effect.getEffectValue<ValueTy>() != value)
2662c1ae801Sdonald chen       return false;
2672c1ae801Sdonald chen     return isa<EffectTys...>(effect.getEffect());
2682c1ae801Sdonald chen   });
2692c1ae801Sdonald chen }
2702c1ae801Sdonald chen template bool
2712c1ae801Sdonald chen mlir::hasEffect<OpOperand *, MemoryEffects::Allocate>(Operation *, OpOperand *);
2722c1ae801Sdonald chen template bool mlir::hasEffect<OpOperand *, MemoryEffects::Free>(Operation *,
2732c1ae801Sdonald chen                                                                 OpOperand *);
2742c1ae801Sdonald chen template bool mlir::hasEffect<OpOperand *, MemoryEffects::Read>(Operation *,
2752c1ae801Sdonald chen                                                                 OpOperand *);
2762c1ae801Sdonald chen template bool mlir::hasEffect<OpOperand *, MemoryEffects::Write>(Operation *,
2772c1ae801Sdonald chen                                                                  OpOperand *);
2782c1ae801Sdonald chen template bool
2792c1ae801Sdonald chen mlir::hasEffect<OpOperand *, MemoryEffects::Write, MemoryEffects::Free>(
2802c1ae801Sdonald chen     Operation *, OpOperand *);
2812c1ae801Sdonald chen 
2822c1ae801Sdonald chen template bool mlir::hasEffect<OpResult, MemoryEffects::Allocate>(Operation *,
2832c1ae801Sdonald chen                                                                  OpResult);
2842c1ae801Sdonald chen template bool mlir::hasEffect<OpResult, MemoryEffects::Free>(Operation *,
2852c1ae801Sdonald chen                                                              OpResult);
2862c1ae801Sdonald chen template bool mlir::hasEffect<OpResult, MemoryEffects::Read>(Operation *,
2872c1ae801Sdonald chen                                                              OpResult);
2882c1ae801Sdonald chen template bool mlir::hasEffect<OpResult, MemoryEffects::Write>(Operation *,
2892c1ae801Sdonald chen                                                               OpResult);
2902c1ae801Sdonald chen template bool
2912c1ae801Sdonald chen mlir::hasEffect<OpResult, MemoryEffects::Write, MemoryEffects::Free>(
2922c1ae801Sdonald chen     Operation *, OpResult);
2932c1ae801Sdonald chen 
2942c1ae801Sdonald chen template bool
2952c1ae801Sdonald chen mlir::hasEffect<BlockArgument, MemoryEffects::Allocate>(Operation *,
2962c1ae801Sdonald chen                                                         BlockArgument);
2972c1ae801Sdonald chen template bool
2982c1ae801Sdonald chen mlir::hasEffect<BlockArgument, MemoryEffects::Free>(Operation *, BlockArgument);
2992c1ae801Sdonald chen template bool
3002c1ae801Sdonald chen mlir::hasEffect<BlockArgument, MemoryEffects::Read>(Operation *, BlockArgument);
3012c1ae801Sdonald chen template bool
3022c1ae801Sdonald chen mlir::hasEffect<BlockArgument, MemoryEffects::Write>(Operation *,
3032c1ae801Sdonald chen                                                      BlockArgument);
3042c1ae801Sdonald chen template bool
3052c1ae801Sdonald chen mlir::hasEffect<BlockArgument, MemoryEffects::Write, MemoryEffects::Free>(
3062c1ae801Sdonald chen     Operation *, BlockArgument);
3078d7f2701SUday Bondhugula 
308eb623ae8SStephen Neuendorffer bool mlir::wouldOpBeTriviallyDead(Operation *op) {
309fe7c0d90SRiver Riddle   if (op->mightHaveTrait<OpTrait::IsTerminator>())
310eb623ae8SStephen Neuendorffer     return false;
311253afd03SMatthias Springer   if (isa<SymbolOpInterface>(op))
312253afd03SMatthias Springer     return false;
313eb623ae8SStephen Neuendorffer   return wouldOpBeTriviallyDeadImpl(op);
314eb623ae8SStephen Neuendorffer }
315fc367dfaSMahesh Ravishankar 
316fc367dfaSMahesh Ravishankar bool mlir::isMemoryEffectFree(Operation *op) {
317fc367dfaSMahesh Ravishankar   if (auto memInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
318fc367dfaSMahesh Ravishankar     if (!memInterface.hasNoEffect())
319fc367dfaSMahesh Ravishankar       return false;
320fc367dfaSMahesh Ravishankar     // If the op does not have recursive side effects, then it is memory effect
321fc367dfaSMahesh Ravishankar     // free.
322fc367dfaSMahesh Ravishankar     if (!op->hasTrait<OpTrait::HasRecursiveMemoryEffects>())
323fc367dfaSMahesh Ravishankar       return true;
324fc367dfaSMahesh Ravishankar   } else if (!op->hasTrait<OpTrait::HasRecursiveMemoryEffects>()) {
325fc367dfaSMahesh Ravishankar     // Otherwise, if the op does not implement the memory effect interface and
326fc367dfaSMahesh Ravishankar     // it does not have recursive side effects, then it cannot be known that the
327fc367dfaSMahesh Ravishankar     // op is moveable.
328fc367dfaSMahesh Ravishankar     return false;
329fc367dfaSMahesh Ravishankar   }
330fc367dfaSMahesh Ravishankar 
331fc367dfaSMahesh Ravishankar   // Recurse into the regions and ensure that all nested ops are memory effect
332fc367dfaSMahesh Ravishankar   // free.
333fc367dfaSMahesh Ravishankar   for (Region &region : op->getRegions())
334fc367dfaSMahesh Ravishankar     for (Operation &op : region.getOps())
335fc367dfaSMahesh Ravishankar       if (!isMemoryEffectFree(&op))
336fc367dfaSMahesh Ravishankar         return false;
337fc367dfaSMahesh Ravishankar   return true;
338fc367dfaSMahesh Ravishankar }
339fc367dfaSMahesh Ravishankar 
340dea33c80STom Eccles // the returned vector may contain duplicate effects
341dea33c80STom Eccles std::optional<llvm::SmallVector<MemoryEffects::EffectInstance>>
342dea33c80STom Eccles mlir::getEffectsRecursively(Operation *rootOp) {
343dea33c80STom Eccles   SmallVector<MemoryEffects::EffectInstance> effects;
344dea33c80STom Eccles   SmallVector<Operation *> effectingOps(1, rootOp);
345dea33c80STom Eccles   while (!effectingOps.empty()) {
346dea33c80STom Eccles     Operation *op = effectingOps.pop_back_val();
347dea33c80STom Eccles 
348dea33c80STom Eccles     // If the operation has recursive effects, push all of the nested
349dea33c80STom Eccles     // operations on to the stack to consider.
350dea33c80STom Eccles     bool hasRecursiveEffects =
351dea33c80STom Eccles         op->hasTrait<OpTrait::HasRecursiveMemoryEffects>();
352dea33c80STom Eccles     if (hasRecursiveEffects) {
353dea33c80STom Eccles       for (Region &region : op->getRegions()) {
354dea33c80STom Eccles         for (Block &block : region) {
355dea33c80STom Eccles           for (Operation &nestedOp : block) {
356dea33c80STom Eccles             effectingOps.push_back(&nestedOp);
357dea33c80STom Eccles           }
358dea33c80STom Eccles         }
359dea33c80STom Eccles       }
360dea33c80STom Eccles     }
361dea33c80STom Eccles 
362dea33c80STom Eccles     if (auto effectInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
363dea33c80STom Eccles       effectInterface.getEffects(effects);
364dea33c80STom Eccles     } else if (!hasRecursiveEffects) {
365dea33c80STom Eccles       // the operation does not have recursive memory effects or implement
366dea33c80STom Eccles       // the memory effect op interface. Its effects are unknown.
367dea33c80STom Eccles       return std::nullopt;
368dea33c80STom Eccles     }
369dea33c80STom Eccles   }
370dea33c80STom Eccles   return effects;
371dea33c80STom Eccles }
372dea33c80STom Eccles 
373fc367dfaSMahesh Ravishankar bool mlir::isSpeculatable(Operation *op) {
374fc367dfaSMahesh Ravishankar   auto conditionallySpeculatable = dyn_cast<ConditionallySpeculatable>(op);
375fc367dfaSMahesh Ravishankar   if (!conditionallySpeculatable)
376fc367dfaSMahesh Ravishankar     return false;
377fc367dfaSMahesh Ravishankar 
378fc367dfaSMahesh Ravishankar   switch (conditionallySpeculatable.getSpeculatability()) {
379fc367dfaSMahesh Ravishankar   case Speculation::RecursivelySpeculatable:
380fc367dfaSMahesh Ravishankar     for (Region &region : op->getRegions()) {
381fc367dfaSMahesh Ravishankar       for (Operation &op : region.getOps())
382fc367dfaSMahesh Ravishankar         if (!isSpeculatable(&op))
383fc367dfaSMahesh Ravishankar           return false;
384fc367dfaSMahesh Ravishankar     }
385fc367dfaSMahesh Ravishankar     return true;
386fc367dfaSMahesh Ravishankar 
387fc367dfaSMahesh Ravishankar   case Speculation::Speculatable:
388fc367dfaSMahesh Ravishankar     return true;
389fc367dfaSMahesh Ravishankar 
390fc367dfaSMahesh Ravishankar   case Speculation::NotSpeculatable:
391fc367dfaSMahesh Ravishankar     return false;
392fc367dfaSMahesh Ravishankar   }
393fc367dfaSMahesh Ravishankar 
394fc367dfaSMahesh Ravishankar   llvm_unreachable("Unhandled enum in mlir::isSpeculatable!");
395fc367dfaSMahesh Ravishankar }
3963a43e68eSIngo Müller 
3973a43e68eSIngo Müller /// The implementation of this function replicates the `def Pure : TraitList`
3983a43e68eSIngo Müller /// in `SideEffectInterfaces.td` and has to be kept in sync manually.
3993a43e68eSIngo Müller bool mlir::isPure(Operation *op) {
4003a43e68eSIngo Müller   return isSpeculatable(op) && isMemoryEffectFree(op);
4013a43e68eSIngo Müller }
402