[Mlir-commits] [mlir] [mlir][memref] Move dealloc for unused memref to after alloc (PR #227975)

Pranav Alavandi llvmlistbot at llvm.org
Thu Oct 1 01:39:10 PDT 2026


https://github.com/pranavalavandi updated https://github.com/llvm/llvm-project/pull/227975

>From c048f1a1819f68cd5209943e992b98d4b936099e Mon Sep 17 00:00:00 2001
From: pranavalavandi <pranav.alavandi at q-ctrl.com>
Date: Thu, 1 Oct 2026 16:25:30 +1000
Subject: [PATCH 1/2] [mlir][memref] Move dealloc for unused memref to after
 alloc

---
 .../Transforms/OptimizeAllocationLiveness.cpp     |  3 +++
 .../Transforms/optimize-allocation-liveness.mlir  | 15 +++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/mlir/lib/Dialect/Bufferization/Transforms/OptimizeAllocationLiveness.cpp b/mlir/lib/Dialect/Bufferization/Transforms/OptimizeAllocationLiveness.cpp
index 28ee5b8e32b9913..3d4b8d2adb9117c 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/OptimizeAllocationLiveness.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/OptimizeAllocationLiveness.cpp
@@ -155,6 +155,9 @@ struct OptimizeAllocationLiveness
         }
       }
       if (lastUser == nullptr) {
+        LDBG() << "Last user not found ";
+        LDBG() << "Moved dealloc op after alloc: " << *allocOp;
+        deallocOp->moveAfter(allocOp);
         return WalkResult::advance();
       }
       LDBG() << "Last user found: " << *lastUser;
diff --git a/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir b/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
index b8fcccda8833aef..07620859cc0bb0a 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
@@ -234,3 +234,18 @@ func.func private @test_alloc_with_multiple_results() -> () {
   memref.dealloc %alloc2 : memref<64xf32>
   return
 }
+
+// -----
+func.func private @work()
+// CHECK-LABEL:   func.func private @test_alloc_with_no_uses() {
+// CHECK:           %[[ALLOC_0:.*]] = memref.alloc() : memref<1048576xi32>
+// CHECK:           memref.dealloc %[[ALLOC_0]] : memref<1048576xi32>
+// CHECK:           call @work() : () -> ()
+// CHECK:           return
+// CHECK:         }
+func.func private @test_alloc_with_no_uses() -> () {
+    %alloc = memref.alloc() : memref<1048576xi32>
+    call @work() : () -> ()
+    memref.dealloc %alloc : memref<1048576xi32>
+    return
+}

>From 06a57354de29f2936d17a4a02870f365b3fbd42a Mon Sep 17 00:00:00 2001
From: pranavalavandi <pranav.alavandi at q-ctrl.com>
Date: Thu, 1 Oct 2026 18:36:52 +1000
Subject: [PATCH 2/2] fix bug where dealloc operands were not considered

---
 .../Transforms/OptimizeAllocationLiveness.cpp | 35 +++++++++++------
 .../optimize-allocation-liveness.mlir         | 38 +++++++++++++++++++
 2 files changed, 62 insertions(+), 11 deletions(-)

diff --git a/mlir/lib/Dialect/Bufferization/Transforms/OptimizeAllocationLiveness.cpp b/mlir/lib/Dialect/Bufferization/Transforms/OptimizeAllocationLiveness.cpp
index 3d4b8d2adb9117c..7634f92c6281400 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/OptimizeAllocationLiveness.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/OptimizeAllocationLiveness.cpp
@@ -154,20 +154,33 @@ struct OptimizeAllocationLiveness
           }
         }
       }
-      if (lastUser == nullptr) {
-        LDBG() << "Last user not found ";
-        LDBG() << "Moved dealloc op after alloc: " << *allocOp;
-        deallocOp->moveAfter(allocOp);
-        return WalkResult::advance();
+
+      Operation *lastDeallocOperandDef = nullptr;
+      for (auto operand : deallocOp->getOperands()) {
+        auto *operandDefOp = operand.getDefiningOp();
+        if (!operandDefOp)
+          continue;
+        auto *topUser =
+            allocOp->getBlock()->findAncestorOpInBlock(*operandDefOp);
+        if (!lastDeallocOperandDef ||
+            happensBefore(lastDeallocOperandDef, topUser)) {
+          lastDeallocOperandDef = topUser;
+        }
       }
-      LDBG() << "Last user found: " << *lastUser;
-      assert(lastUser->getBlock() == allocOp->getBlock());
-      assert(lastUser->getBlock() == deallocOp->getBlock());
-      // Move the dealloc op after the last user.
-      deallocOp->moveAfter(lastUser);
-      LDBG() << "Moved dealloc op after: " << *lastUser;
 
+      Operation *target = lastUser;
+      if (!target || (lastDeallocOperandDef &&
+                      happensBefore(target, lastDeallocOperandDef)))
+        target = lastDeallocOperandDef;
+
+      if (!target)
+        target = allocOp;
+
+      LDBG() << "Moving dealloc op after: " << *target;
+
+      deallocOp->moveAfter(target);
       return WalkResult::advance();
+
     });
   }
 };
diff --git a/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir b/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
index 07620859cc0bb0a..6bb62d556feef31 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
@@ -249,3 +249,41 @@ func.func private @test_alloc_with_no_uses() -> () {
     memref.dealloc %alloc : memref<1048576xi32>
     return
 }
+
+// -----
+// CHECK-LABEL:   func.func @test_alloc_with_dealloc_operand(
+// CHECK-SAME:      %[[ARG0:.*]]: !gpu.async.token) {
+// CHECK:           %[[ALLOC_0:.*]] = gpu.alloc  () : memref<8xf32>
+// CHECK:           %[[WAIT_0:.*]] = gpu.wait async {{\[}}%[[ARG0]]]
+// CHECK:           %[[DEALLOC_0:.*]] = gpu.dealloc async {{\[}}%[[WAIT_0]]] %[[ALLOC_0]] : memref<8xf32>
+// CHECK:           gpu.wait {{\[}}%[[DEALLOC_0]]]
+// CHECK:           return
+// CHECK:         }
+func.func @test_alloc_with_dealloc_operand(%d: !gpu.async.token) {
+  %a = gpu.alloc () : memref<8xf32>
+  %w = gpu.wait async [%d]
+  %done = gpu.dealloc async [%w] %a : memref<8xf32>
+  gpu.wait [%done]
+  return
+}
+
+// -----
+// CHECK-LABEL:   func.func @test_alloc_with_dealloc_operand_and_load(
+// CHECK-SAME:      %[[ARG0:.*]]: !gpu.async.token) {
+// CHECK:           %[[CONSTANT_0:.*]] = arith.constant 0 : index
+// CHECK:           %[[ALLOC_0:.*]] = gpu.alloc  () : memref<8xf32>
+// CHECK:           %[[LOAD_0:.*]] = memref.load %[[ALLOC_0]]{{\[}}%[[CONSTANT_0]]] : memref<8xf32>
+// CHECK:           %[[WAIT_0:.*]] = gpu.wait async {{\[}}%[[ARG0]]]
+// CHECK:           %[[DEALLOC_0:.*]] = gpu.dealloc async {{\[}}%[[WAIT_0]]] %[[ALLOC_0]] : memref<8xf32>
+// CHECK:           gpu.wait {{\[}}%[[DEALLOC_0]]]
+// CHECK:           return
+// CHECK:         }
+func.func @test_alloc_with_dealloc_operand_and_load(%d: !gpu.async.token) {
+  %c0 = arith.constant 0 : index
+  %a = gpu.alloc () : memref<8xf32>
+  %x = memref.load %a[%c0] : memref<8xf32>
+  %w = gpu.wait async [%d]
+  %done = gpu.dealloc async [%w] %a : memref<8xf32>
+  gpu.wait [%done]
+  return
+}



More information about the Mlir-commits mailing list