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
classof(const SideEffects::Effect * effect)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
isOpTriviallyDead(Operation * op)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.
wouldOpBeTriviallyDeadImpl(Operation * rootOp)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
wouldOpBeTriviallyDead(Operation * op)93 bool mlir::wouldOpBeTriviallyDead(Operation *op) {
94 if (!op->isKnownNonTerminator())
95 return false;
96 return wouldOpBeTriviallyDeadImpl(op);
97 }
98