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