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 ®ion : 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 ®ion : 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 ®ion : 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 ®ion : 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