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 using namespace mlir; 12 13 //===----------------------------------------------------------------------===// 14 // SideEffect Interfaces 15 //===----------------------------------------------------------------------===// 16 17 /// Include the definitions of the side effect interfaces. 18 #include "mlir/Interfaces/SideEffectInterfaces.cpp.inc" 19 20 //===----------------------------------------------------------------------===// 21 // MemoryEffects 22 //===----------------------------------------------------------------------===// 23 24 bool MemoryEffects::Effect::classof(const SideEffects::Effect *effect) { 25 return isa<Allocate>(effect) || isa<Free>(effect) || isa<Read>(effect) || 26 isa<Write>(effect); 27 } 28 29 //===----------------------------------------------------------------------===// 30 // SideEffect Utilities 31 //===----------------------------------------------------------------------===// 32 33 bool mlir::isOpTriviallyDead(Operation *op) { 34 return op->use_empty() && wouldOpBeTriviallyDead(op); 35 } 36 37 /// Internal implementation of `mlir::wouldOpBeTriviallyDead` that also 38 /// considers terminator operations as dead if they have no side effects. This 39 /// allows for marking region operations as trivially dead without always being 40 /// conservative of terminators. 41 static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp) { 42 // The set of operations to consider when checking for side effects. 43 SmallVector<Operation *, 1> effectingOps(1, rootOp); 44 while (!effectingOps.empty()) { 45 Operation *op = effectingOps.pop_back_val(); 46 47 // If the operation has recursive effects, push all of the nested operations 48 // on to the stack to consider. 49 bool hasRecursiveEffects = op->hasTrait<OpTrait::HasRecursiveSideEffects>(); 50 if (hasRecursiveEffects) { 51 for (Region ®ion : op->getRegions()) { 52 for (auto &block : region) { 53 for (auto &nestedOp : block) 54 effectingOps.push_back(&nestedOp); 55 } 56 } 57 } 58 59 // If the op has memory effects, try to characterize them to see if the op 60 // is trivially dead here. 61 if (auto effectInterface = dyn_cast<MemoryEffectOpInterface>(op)) { 62 // Check to see if this op either has no effects, or only allocates/reads 63 // memory. 64 SmallVector<MemoryEffects::EffectInstance, 1> effects; 65 effectInterface.getEffects(effects); 66 if (!llvm::all_of(effects, [op](const MemoryEffects::EffectInstance &it) { 67 // We can drop allocations if the value is a result of the 68 // operation. 69 if (isa<MemoryEffects::Allocate>(it.getEffect())) 70 return it.getValue() && it.getValue().getDefiningOp() == op; 71 // Otherwise, the effect must be a read. 72 return isa<MemoryEffects::Read>(it.getEffect()); 73 })) { 74 return false; 75 } 76 continue; 77 78 // Otherwise, if the op has recursive side effects we can treat the 79 // operation itself as having no effects. 80 } else if (hasRecursiveEffects) { 81 continue; 82 } 83 84 // If there were no effect interfaces, we treat this op as conservatively 85 // having effects. 86 return false; 87 } 88 89 // If we get here, none of the operations had effects that prevented marking 90 // 'op' as dead. 91 return true; 92 } 93 94 bool mlir::wouldOpBeTriviallyDead(Operation *op) { 95 if (!op->isKnownNonTerminator()) 96 return false; 97 return wouldOpBeTriviallyDeadImpl(op); 98 } 99