22 #include "llvm/Support/Debug.h"
23 #include "llvm/Support/ErrorHandling.h"
25 #define DEBUG_TYPE "optimize-allocation-liveness"
26 #define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
27 #define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n")
30 namespace bufferization {
31 #define GEN_PASS_DEF_OPTIMIZEALLOCATIONLIVENESSPASS
32 #include "mlir/Dialect/Bufferization/Transforms/Passes.h.inc"
62 if (MemoryEffectOpInterface memEffectOp =
63 dyn_cast<MemoryEffectOpInterface>(user)) {
65 memEffectOp.getEffects(effects);
67 for (
const auto &effect : effects) {
68 if (isa<MemoryEffects::Free>(effect.getEffect())) {
70 LDBG(
"Multiple users with free effect found: " << *freeOpUser
83 static bool hasMemoryAllocEffect(MemoryEffectOpInterface memEffectOp) {
85 memEffectOp.getEffects(effects);
86 for (
const auto &effect : effects) {
87 if (isa<MemoryEffects::Allocate>(effect.getEffect())) {
96 collectAllocations(MemoryEffectOpInterface allocOp) {
98 allocOp.getEffects(effects);
101 if (isa<MemoryEffects::Allocate>(it.getEffect()))
102 if (
auto val = it.getValue(); val && val.getDefiningOp() == allocOp)
103 allocResults.push_back(cast<OpResult>(val));
107 struct OptimizeAllocationLiveness
108 :
public bufferization::impl::OptimizeAllocationLivenessPassBase<
109 OptimizeAllocationLiveness> {
111 OptimizeAllocationLiveness() =
default;
113 void runOnOperation()
override {
114 func::FuncOp func = getOperation();
116 if (func.isExternal())
121 func.walk([&](MemoryEffectOpInterface memEffectOp) ->
WalkResult {
122 if (!hasMemoryAllocEffect(memEffectOp))
125 auto allocOp = memEffectOp;
126 LDBG(
"Checking alloc op: " << allocOp);
130 if (allocationResults.size() != 1)
133 OpResult allocResult = allocationResults[0];
134 LDBG(
"On allocation result: " << allocResult);
136 auto *deallocOp = findUserWithFreeSideEffect(allocResult);
137 if (!deallocOp || (deallocOp->getBlock() != allocOp->getBlock())) {
147 for (
auto dep : llvm::make_early_inc_range(deps)) {
148 for (
auto *user : dep.getUsers()) {
151 if (user == deallocOp)
155 auto topUser = allocOp->getBlock()->findAncestorOpInBlock(*user);
161 if (lastUser ==
nullptr) {
164 LDBG(
"Last user found: " << *lastUser);
165 assert(lastUser->
getBlock() == allocOp->getBlock());
166 assert(lastUser->
getBlock() == deallocOp->getBlock());
168 deallocOp->moveAfter(lastUser);
169 LDBG(
"Moved dealloc op after: " << *lastUser);
static bool happensBefore(Operation *a, Operation *b, const DominanceInfo &domInfo)
Return true if a happens before b, i.e., a or one of its ancestors properly dominates b and b is not ...
Operation * findAncestorOpInBlock(Operation &op)
Returns 'op' if 'op' lies in this block, or otherwise finds the ancestor operation of 'op' that lies ...
A straight-forward alias analysis which ensures that all dependencies of all values will be determine...
ValueSetT resolve(Value value) const
Find all immediate and indirect views upon this value.
This is a value defined by a result of an operation.
Operation is the basic unit of execution within MLIR.
bool isBeforeInBlock(Operation *other)
Given an operation 'other' that is within the same parent block, return whether the current operation...
Operation * getParentOp()
Returns the closest surrounding operation that contains this operation or nullptr if this is a top-le...
Block * getBlock()
Returns the operation block that contains this operation.
bool isProperAncestor(Operation *other)
Return true if this operation is a proper ancestor of the other operation.
This class represents a specific instance of an effect.
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
user_range getUsers() const
A utility result that is used to signal how to proceed with an ongoing walk:
static WalkResult advance()
Include the generated interface declarations.