1 //===- SideEffectInterfaces.cpp - SideEffects in MLIR ---------------------===// 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 #include "mlir/Interfaces/SideEffectInterfaces.h" 10 11 #include "llvm/ADT/SmallPtrSet.h" 12 13 using namespace mlir; 14 15 //===----------------------------------------------------------------------===// 16 // SideEffect Interfaces 17 //===----------------------------------------------------------------------===// 18 19 /// Include the definitions of the side effect interfaces. 20 #include "mlir/Interfaces/SideEffectInterfaces.cpp.inc" 21 22 //===----------------------------------------------------------------------===// 23 // MemoryEffects 24 //===----------------------------------------------------------------------===// 25 26 bool MemoryEffects::Effect::classof(const SideEffects::Effect *effect) { 27 return isa<Allocate, Free, Read, Write>(effect); 28 } 29 30 //===----------------------------------------------------------------------===// 31 // SideEffect Utilities 32 //===----------------------------------------------------------------------===// 33 34 bool mlir::isOpTriviallyDead(Operation *op) { 35 return op->use_empty() && wouldOpBeTriviallyDead(op); 36 } 37 38 /// Internal implementation of `mlir::wouldOpBeTriviallyDead` that also 39 /// considers terminator operations as dead if they have no side effects. This 40 /// allows for marking region operations as trivially dead without always being 41 /// conservative of terminators. 42 static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp) { 43 // The set of operations to consider when checking for side effects. 44 SmallVector<Operation *, 1> effectingOps(1, rootOp); 45 while (!effectingOps.empty()) { 46 Operation *op = effectingOps.pop_back_val(); 47 48 // If the operation has recursive effects, push all of the nested operations 49 // on to the stack to consider. 50 bool hasRecursiveEffects = op->hasTrait<OpTrait::HasRecursiveSideEffects>(); 51 if (hasRecursiveEffects) { 52 for (Region ®ion : op->getRegions()) { 53 for (auto &block : region) { 54 for (auto &nestedOp : block) 55 effectingOps.push_back(&nestedOp); 56 } 57 } 58 } 59 60 // If the op has memory effects, try to characterize them to see if the op 61 // is trivially dead here. 62 if (auto effectInterface = dyn_cast<MemoryEffectOpInterface>(op)) { 63 // Check to see if this op either has no effects, or only allocates/reads 64 // memory. 65 SmallVector<MemoryEffects::EffectInstance, 1> effects; 66 effectInterface.getEffects(effects); 67 68 // Gather all results of this op that are allocated. 69 SmallPtrSet<Value, 4> allocResults; 70 for (const MemoryEffects::EffectInstance &it : effects) 71 if (isa<MemoryEffects::Allocate>(it.getEffect()) && it.getValue() && 72 it.getValue().getDefiningOp() == op) 73 allocResults.insert(it.getValue()); 74 75 if (!llvm::all_of(effects, [&allocResults]( 76 const MemoryEffects::EffectInstance &it) { 77 // We can drop effects if the value is an allocation and is a result 78 // of the operation. 79 if (allocResults.contains(it.getValue())) 80 return true; 81 // Otherwise, the effect must be a read. 82 return isa<MemoryEffects::Read>(it.getEffect()); 83 })) { 84 return false; 85 } 86 continue; 87 88 // Otherwise, if the op has recursive side effects we can treat the 89 // operation itself as having no effects. 90 } 91 if (hasRecursiveEffects) 92 continue; 93 94 // If there were no effect interfaces, we treat this op as conservatively 95 // having effects. 96 return false; 97 } 98 99 // If we get here, none of the operations had effects that prevented marking 100 // 'op' as dead. 101 return true; 102 } 103 104 template <typename EffectTy> 105 bool mlir::hasSingleEffect(Operation *op, Value value) { 106 auto memOp = dyn_cast<MemoryEffectOpInterface>(op); 107 if (!memOp) 108 return false; 109 SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects; 110 memOp.getEffects(effects); 111 bool hasSingleEffectOnVal = false; 112 // Iterate through `effects` and check if an effect of type `EffectTy` and 113 // only of that type is present. A `value` to check the effect on may or may 114 // not have been provided. 115 for (auto &effect : effects) { 116 if (value && effect.getValue() != value) 117 continue; 118 hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect()); 119 if (!hasSingleEffectOnVal) 120 return false; 121 } 122 return hasSingleEffectOnVal; 123 } 124 125 template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *, 126 Value); 127 template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *, Value); 128 template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *, Value); 129 template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *, Value); 130 131 bool mlir::wouldOpBeTriviallyDead(Operation *op) { 132 if (op->mightHaveTrait<OpTrait::IsTerminator>()) 133 return false; 134 return wouldOpBeTriviallyDeadImpl(op); 135 } 136