[Mlir-commits] [mlir] [mlir][bufferization] Adding the optimize-allocation-liveness pass (PR #101827)

Dennis Filimonov llvmlistbot at llvm.org
Wed Aug 14 01:11:24 PDT 2024


================
@@ -0,0 +1,157 @@
+//===- OptimizeAllocationLiveness.cpp - impl. optimize allocation liveness pass
+//-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements a pass for optimizing allocation liveness.
+// The pass moves the deallocation operation after the last user of the
+// allocated buffer.
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Dialect/Bufferization/Transforms/BufferViewFlowAnalysis.h"
+#include "mlir/Dialect/Bufferization/Transforms/Passes.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/IR/Operation.h"
+#include "llvm/Support/Debug.h"
+
+#define DEBUG_TYPE "optimize-allocation-liveness"
+#define DBGS() (llvm::dbgs() << '[' << DEBUG_TYPE << "] ")
+#define LDBG(X) LLVM_DEBUG(DBGS() << X << "\n")
+
+namespace mlir {
+namespace bufferization {
+#define GEN_PASS_DEF_OPTIMIZEALLOCATIONLIVENESS
+#include "mlir/Dialect/Bufferization/Transforms/Passes.h.inc"
+} // namespace bufferization
+} // namespace mlir
+
+using namespace mlir;
+
+namespace {
+
+//===----------------------------------------------------------------------===//
+// Helper functions
+//===----------------------------------------------------------------------===//
+
+/// Return true if `a` happens before `b`, i.e., `a` or one of its ancestors
+/// properly dominates `b` and `b` is not inside `a`.
+static bool happensBefore(Operation *a, Operation *b) {
+  do {
+    if (a->isProperAncestor(b))
+      return false;
+    if (Operation *bAncestor = a->getBlock()->findAncestorOpInBlock(*b)) {
+      return a->isBeforeInBlock(bAncestor);
+    }
+  } while ((a = a->getParentOp()));
+  return false;
+}
+
+/// This method searches for a user of value that is a dealloc operation.
+/// If multiple users with free effect are found, return nullptr.
+Operation *findUserWithFreeSideEffect(Value value) {
+  Operation *freeOpUser = nullptr;
+  for (Operation *user : value.getUsers()) {
+    if (MemoryEffectOpInterface memEffectOp =
+            dyn_cast<MemoryEffectOpInterface>(user)) {
+      SmallVector<MemoryEffects::EffectInstance, 2> effects;
+      memEffectOp.getEffects(effects);
+
+      for (const auto &effect : effects) {
+        if (isa<MemoryEffects::Free>(effect.getEffect())) {
+          if (freeOpUser) {
+            LDBG("Multiple users with free effect found: " << *freeOpUser
+                                                           << " and " << *user);
+            return nullptr;
+          }
+          freeOpUser = user;
+        }
+      }
+    }
+  }
+  return freeOpUser;
+}
+
+/// Checks if the given op allocates memory.
+static bool hasMemoryAllocEffect(MemoryEffectOpInterface memEffectOp) {
+  SmallVector<MemoryEffects::EffectInstance, 2> effects;
+  memEffectOp.getEffects(effects);
+  for (const auto &effect : effects) {
+    if (isa<MemoryEffects::Allocate>(effect.getEffect())) {
+      return true;
+    }
+  }
+  return false;
+}
+
+struct OptimizeAllocationLiveness
+    : public bufferization::impl::OptimizeAllocationLivenessBase<
+          OptimizeAllocationLiveness> {
+public:
+  OptimizeAllocationLiveness() = default;
+
+  void runOnOperation() override {
+    func::FuncOp func = getOperation();
+
+    if (func.isExternal())
+      return;
+
+    BufferViewFlowAnalysis analysis = BufferViewFlowAnalysis(func);
+
+    func.walk([&](MemoryEffectOpInterface memEffectOp) -> WalkResult {
+      if (!hasMemoryAllocEffect(memEffectOp))
+        return WalkResult::advance();
+
+      auto allocOp = memEffectOp;
+      LDBG("Checking alloc op: " << allocOp);
+
+      auto deallocOp = findUserWithFreeSideEffect(allocOp->getResult(0));
+      if (!deallocOp)
----------------
DennisFily wrote:

Thanks,  Will not hoist deallocs that are in different blocks and added a test as suggested.

https://github.com/llvm/llvm-project/pull/101827


More information about the Mlir-commits mailing list