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 &region : 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