MLIR  16.0.0git
SideEffectInterfaces.cpp
Go to the documentation of this file.
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 
10 
11 #include "llvm/ADT/SmallPtrSet.h"
12 
13 using namespace mlir;
14 
15 //===----------------------------------------------------------------------===//
16 // SideEffect Interfaces
17 //===----------------------------------------------------------------------===//
18 
19 /// Include the definitions of the side effect interfaces.
20 #include "mlir/Interfaces/SideEffectInterfaces.cpp.inc"
21 
22 //===----------------------------------------------------------------------===//
23 // MemoryEffects
24 //===----------------------------------------------------------------------===//
25 
27  return isa<Allocate, Free, Read, Write>(effect);
28 }
29 
30 //===----------------------------------------------------------------------===//
31 // SideEffect Utilities
32 //===----------------------------------------------------------------------===//
33 
35  return op->use_empty() && wouldOpBeTriviallyDead(op);
36 }
37 
38 /// Internal implementation of `mlir::wouldOpBeTriviallyDead` that also
39 /// considers terminator operations as dead if they have no side effects. This
40 /// allows for marking region operations as trivially dead without always being
41 /// conservative of terminators.
42 static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp) {
43  // The set of operations to consider when checking for side effects.
44  SmallVector<Operation *, 1> effectingOps(1, rootOp);
45  while (!effectingOps.empty()) {
46  Operation *op = effectingOps.pop_back_val();
47 
48  // If the operation has recursive effects, push all of the nested operations
49  // on to the stack to consider.
50  bool hasRecursiveEffects = op->hasTrait<OpTrait::HasRecursiveSideEffects>();
51  if (hasRecursiveEffects) {
52  for (Region &region : op->getRegions()) {
53  for (auto &block : region) {
54  for (auto &nestedOp : block)
55  effectingOps.push_back(&nestedOp);
56  }
57  }
58  }
59 
60  // If the op has memory effects, try to characterize them to see if the op
61  // is trivially dead here.
62  if (auto effectInterface = dyn_cast<MemoryEffectOpInterface>(op)) {
63  // Check to see if this op either has no effects, or only allocates/reads
64  // memory.
66  effectInterface.getEffects(effects);
67 
68  // Gather all results of this op that are allocated.
69  SmallPtrSet<Value, 4> allocResults;
70  for (const MemoryEffects::EffectInstance &it : effects)
71  if (isa<MemoryEffects::Allocate>(it.getEffect()) && it.getValue() &&
72  it.getValue().getDefiningOp() == op)
73  allocResults.insert(it.getValue());
74 
75  if (!llvm::all_of(effects, [&allocResults](
77  // We can drop effects if the value is an allocation and is a result
78  // of the operation.
79  if (allocResults.contains(it.getValue()))
80  return true;
81  // Otherwise, the effect must be a read.
82  return isa<MemoryEffects::Read>(it.getEffect());
83  })) {
84  return false;
85  }
86  continue;
87 
88  // Otherwise, if the op has recursive side effects we can treat the
89  // operation itself as having no effects.
90  }
91  if (hasRecursiveEffects)
92  continue;
93 
94  // If there were no effect interfaces, we treat this op as conservatively
95  // having effects.
96  return false;
97  }
98 
99  // If we get here, none of the operations had effects that prevented marking
100  // 'op' as dead.
101  return true;
102 }
103 
104 template <typename EffectTy>
106  auto memOp = dyn_cast<MemoryEffectOpInterface>(op);
107  if (!memOp)
108  return false;
110  memOp.getEffects(effects);
111  bool hasSingleEffectOnVal = false;
112  // Iterate through `effects` and check if an effect of type `EffectTy` and
113  // only of that type is present. A `value` to check the effect on may or may
114  // not have been provided.
115  for (auto &effect : effects) {
116  if (value && effect.getValue() != value)
117  continue;
118  hasSingleEffectOnVal = isa<EffectTy>(effect.getEffect());
119  if (!hasSingleEffectOnVal)
120  return false;
121  }
122  return hasSingleEffectOnVal;
123 }
124 
125 template bool mlir::hasSingleEffect<MemoryEffects::Allocate>(Operation *,
126  Value);
127 template bool mlir::hasSingleEffect<MemoryEffects::Free>(Operation *, Value);
128 template bool mlir::hasSingleEffect<MemoryEffects::Read>(Operation *, Value);
129 template bool mlir::hasSingleEffect<MemoryEffects::Write>(Operation *, Value);
130 
133  return false;
134  return wouldOpBeTriviallyDeadImpl(op);
135 }
Include the generated interface declarations.
This class contains a list of basic blocks and a link to the parent operation it is attached to...
Definition: Region.h:26
bool wouldOpBeTriviallyDead(Operation *op)
Return true if the given operation would be dead if unused, and has no side effects on memory that wo...
bool isOpTriviallyDead(Operation *op)
Return true if the given operation is unused, and has no side effects on memory that prevent erasing...
Operation is a basic unit of execution within MLIR.
Definition: Operation.h:28
MutableArrayRef< Region > getRegions()
Returns the regions held by this operation.
Definition: Operation.h:480
EffectT * getEffect() const
Return the effect being applied.
Value getValue() const
Return the value the effect is applied on, or nullptr if there isn&#39;t a known value being affected...
bool mightHaveTrait()
Returns true if the operation might have the provided trait.
Definition: Operation.h:536
This class provides the API for ops that are known to be terminators.
Definition: OpDefinition.h:707
This trait indicates that the side effects of an operation includes the effects of operations nested ...
static constexpr const bool value
static bool classof(const SideEffects::Effect *effect)
Include the definitions of the side effect interfaces.
bool hasTrait()
Returns true if the operation was registered with a particular trait, e.g.
Definition: Operation.h:528
bool hasSingleEffect(Operation *op, Value value=nullptr)
Returns true if op has only an effect of type EffectTy (and of no other type) on value.
This class represents a specific instance of an effect.
bool use_empty()
Returns true if this operation has no uses.
Definition: Operation.h:629
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Definition: Value.h:85
This class represents a base class for a specific effect type.
static bool wouldOpBeTriviallyDeadImpl(Operation *rootOp)
Internal implementation of mlir::wouldOpBeTriviallyDead that also considers terminator operations as ...