1eb623ae8SStephen Neuendorffer //===- SideEffectInterfaces.cpp - SideEffects in MLIR ---------------------===//
2eb623ae8SStephen Neuendorffer //
3eb623ae8SStephen Neuendorffer // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4eb623ae8SStephen Neuendorffer // See https://llvm.org/LICENSE.txt for license information.
5eb623ae8SStephen Neuendorffer // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6eb623ae8SStephen Neuendorffer //
7eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
8eb623ae8SStephen Neuendorffer 
9eb623ae8SStephen Neuendorffer #include "mlir/Interfaces/SideEffectInterfaces.h"
10eb623ae8SStephen Neuendorffer 
11*61394636SMarkus Böck #include "llvm/ADT/SmallPtrSet.h"
12*61394636SMarkus Böck 
13eb623ae8SStephen Neuendorffer using namespace mlir;
14eb623ae8SStephen Neuendorffer 
15eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
16eb623ae8SStephen Neuendorffer // SideEffect Interfaces
17eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
18eb623ae8SStephen Neuendorffer 
19eb623ae8SStephen Neuendorffer /// Include the definitions of the side effect interfaces.
20eb623ae8SStephen Neuendorffer #include "mlir/Interfaces/SideEffectInterfaces.cpp.inc"
21eb623ae8SStephen Neuendorffer 
22eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
23eb623ae8SStephen Neuendorffer // MemoryEffects
24eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
25eb623ae8SStephen Neuendorffer 
classof(const SideEffects::Effect * effect)26eb623ae8SStephen Neuendorffer bool MemoryEffects::Effect::classof(const SideEffects::Effect *effect) {
27d891d738SRahul Joshi   return isa<Allocate, Free, Read, Write>(effect);
28eb623ae8SStephen Neuendorffer }
29eb623ae8SStephen Neuendorffer 
30eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
31eb623ae8SStephen Neuendorffer // SideEffect Utilities
32eb623ae8SStephen Neuendorffer //===----------------------------------------------------------------------===//
33eb623ae8SStephen Neuendorffer 
isOpTriviallyDead(Operation * op)34eb623ae8SStephen Neuendorffer bool mlir::isOpTriviallyDead(Operation *op) {
35eb623ae8SStephen Neuendorffer   return op->use_empty() && wouldOpBeTriviallyDead(op);
36eb623ae8SStephen Neuendorffer }
37eb623ae8SStephen Neuendorffer 
38eb623ae8SStephen Neuendorffer /// Internal implementation of `mlir::wouldOpBeTriviallyDead` that also
39eb623ae8SStephen Neuendorffer /// considers terminator operations as dead if they have no side effects. This
40eb623ae8SStephen Neuendorffer /// allows for marking region operations as trivially dead without always being
41eb623ae8SStephen Neuendorffer /// conservative of terminators.
wouldOpBeTriviallyDeadImpl(Operation * rootOp)42eb623ae8SStephen Neuendorffer static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp) {
43eb623ae8SStephen Neuendorffer   // The set of operations to consider when checking for side effects.
44eb623ae8SStephen Neuendorffer   SmallVector<Operation *, 1> effectingOps(1, rootOp);
45eb623ae8SStephen Neuendorffer   while (!effectingOps.empty()) {
46eb623ae8SStephen Neuendorffer     Operation *op = effectingOps.pop_back_val();
47eb623ae8SStephen Neuendorffer 
48eb623ae8SStephen Neuendorffer     // If the operation has recursive effects, push all of the nested operations
49eb623ae8SStephen Neuendorffer     // on to the stack to consider.
50eb623ae8SStephen Neuendorffer     bool hasRecursiveEffects = op->hasTrait<OpTrait::HasRecursiveSideEffects>();
51eb623ae8SStephen Neuendorffer     if (hasRecursiveEffects) {
52eb623ae8SStephen Neuendorffer       for (Region &region : op->getRegions()) {
53eb623ae8SStephen Neuendorffer         for (auto &block : region) {
54eb623ae8SStephen Neuendorffer           for (auto &nestedOp : block)
55eb623ae8SStephen Neuendorffer             effectingOps.push_back(&nestedOp);
56eb623ae8SStephen Neuendorffer         }
57eb623ae8SStephen Neuendorffer       }
58eb623ae8SStephen Neuendorffer     }
59eb623ae8SStephen Neuendorffer 
60eb623ae8SStephen Neuendorffer     // If the op has memory effects, try to characterize them to see if the op
61eb623ae8SStephen Neuendorffer     // is trivially dead here.
62eb623ae8SStephen Neuendorffer     if (auto effectInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
63eb623ae8SStephen Neuendorffer       // Check to see if this op either has no effects, or only allocates/reads
64eb623ae8SStephen Neuendorffer       // memory.
65eb623ae8SStephen Neuendorffer       SmallVector<MemoryEffects::EffectInstance, 1> effects;
66eb623ae8SStephen Neuendorffer       effectInterface.getEffects(effects);
67*61394636SMarkus Böck 
68*61394636SMarkus Böck       // Gather all results of this op that are allocated.
69*61394636SMarkus Böck       SmallPtrSet<Value, 4> allocResults;
70*61394636SMarkus Böck       for (const MemoryEffects::EffectInstance &it : effects)
71*61394636SMarkus Böck         if (isa<MemoryEffects::Allocate>(it.getEffect()) && it.getValue() &&
72*61394636SMarkus Böck             it.getValue().getDefiningOp() == op)
73*61394636SMarkus Böck           allocResults.insert(it.getValue());
74*61394636SMarkus Böck 
75*61394636SMarkus Böck       if (!llvm::all_of(effects, [&allocResults](
76*61394636SMarkus Böck                                      const MemoryEffects::EffectInstance &it) {
77*61394636SMarkus Böck             // We can drop effects if the value is an allocation and is a result
78*61394636SMarkus Böck             // of the operation.
79*61394636SMarkus Böck             if (allocResults.contains(it.getValue()))
80*61394636SMarkus Böck               return true;
81eb623ae8SStephen Neuendorffer             // Otherwise, the effect must be a read.
82eb623ae8SStephen Neuendorffer             return isa<MemoryEffects::Read>(it.getEffect());
83eb623ae8SStephen Neuendorffer           })) {
84eb623ae8SStephen Neuendorffer         return false;
85eb623ae8SStephen Neuendorffer       }
86eb623ae8SStephen Neuendorffer       continue;
87eb623ae8SStephen Neuendorffer 
88eb623ae8SStephen Neuendorffer       // Otherwise, if the op has recursive side effects we can treat the
89eb623ae8SStephen Neuendorffer       // operation itself as having no effects.
90eb623ae8SStephen Neuendorffer     }
9102b6fb21SMehdi Amini     if (hasRecursiveEffects)
9202b6fb21SMehdi Amini       continue;
93eb623ae8SStephen Neuendorffer 
94eb623ae8SStephen Neuendorffer     // If there were no effect interfaces, we treat this op as conservatively
95eb623ae8SStephen Neuendorffer     // having effects.
96eb623ae8SStephen Neuendorffer     return false;
97eb623ae8SStephen Neuendorffer   }
98eb623ae8SStephen Neuendorffer 
99eb623ae8SStephen Neuendorffer   // If we get here, none of the operations had effects that prevented marking
100eb623ae8SStephen Neuendorffer   // 'op' as dead.
101eb623ae8SStephen Neuendorffer   return true;
102eb623ae8SStephen Neuendorffer }
103eb623ae8SStephen Neuendorffer 
10416219f8cSArnab Dutta template <typename EffectTy>
hasSingleEffect(Operation * op,Value value)10516219f8cSArnab Dutta bool mlir::hasSingleEffect(Operation *op, Value value) {
10616219f8cSArnab Dutta   auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
10716219f8cSArnab Dutta   if (!memOp)
10816219f8cSArnab Dutta     return false;
10916219f8cSArnab Dutta   SmallVector<SideEffects::EffectInstance<MemoryEffects::Effect>, 4> effects;
11016219f8cSArnab Dutta   memOp.getEffects(effects);
1119f7d8014SUday Bondhugula   bool hasSingleEffectOnVal = false;
1129f7d8014SUday Bondhugula   // Iterate through `effects` and check if an effect of type `EffectTy` and
1139819cbdaSUday Bondhugula   // only of that type is present. A `value` to check the effect on may or may
1149819cbdaSUday Bondhugula   // not have been provided.
11516219f8cSArnab Dutta   for (auto &effect : effects) {
1169819cbdaSUday Bondhugula     if (value && effect.getValue() != value)
1179f7d8014SUday Bondhugula       continue;
1189f7d8014SUday Bondhugula     hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
1199f7d8014SUday Bondhugula     if (!hasSingleEffectOnVal)
1209f7d8014SUday Bondhugula       return false;
12116219f8cSArnab Dutta   }
1229f7d8014SUday Bondhugula   return hasSingleEffectOnVal;
12316219f8cSArnab Dutta }
12416219f8cSArnab Dutta 
12516219f8cSArnab Dutta template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *,
12616219f8cSArnab Dutta                                                              Value);
12716219f8cSArnab Dutta template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *, Value);
12816219f8cSArnab Dutta template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *, Value);
1299f7d8014SUday Bondhugula template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *, Value);
13016219f8cSArnab Dutta 
wouldOpBeTriviallyDead(Operation * op)131eb623ae8SStephen Neuendorffer bool mlir::wouldOpBeTriviallyDead(Operation *op) {
132fe7c0d90SRiver Riddle   if (op->mightHaveTrait<OpTrait::IsTerminator>())
133eb623ae8SStephen Neuendorffer     return false;
134eb623ae8SStephen Neuendorffer   return wouldOpBeTriviallyDeadImpl(op);
135eb623ae8SStephen Neuendorffer }
136