[Mlir-commits] [mlir] [mlir][bufferization] Add tests for OptimizeAllocationLiveness edge cases (PR #189505)

Mohamed Deraz Nasr llvmlistbot at llvm.org
Mon Mar 30 20:16:42 PDT 2026


https://github.com/MDerazNasr updated https://github.com/llvm/llvm-project/pull/189505

>From 5ae7f82d55027043a37a0236e94b1f25f1003df7 Mon Sep 17 00:00:00 2001
From: Mohamed Deraz Nasr <mderaznasr at gmail.com>
Date: Mon, 30 Mar 2026 19:22:52 -0400
Subject: [PATCH 1/2] [mlir][bufferization] Add tests for
 OptimizeAllocationLiveness edge cases

Add two test cases to optimize-allocation-liveness.mlir that cover
untested code paths in OptimizeAllocationLiveness.cpp:

1. An alloc with no users other than its dealloc. The pass hits the
   lastUser == nullptr branch and leaves the IR unchanged.

2. An alloc with a dynamic dimension (memref<?xf32>). All existing
   tests use static shapes. This verifies the pass moves the dealloc
   to right after the last user when the alloc size is not known at
   compile time.
---
 .../optimize-allocation-liveness.mlir         | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir b/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
index 63d33e3a88bed..31fbbf80a9c6d 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
@@ -234,3 +234,47 @@ func.func private @test_alloc_with_multiple_results() -> () {
   memref.dealloc %alloc2 : memref<64xf32>
   return
 }
+
+// -----
+
+// CHECK-LABEL:   func.func private @test_alloc_no_non_dealloc_users() {
+// CHECK:           %[[ALLOC:.*]] = memref.alloc() {alignment = 64 : i64} : memref<32xf32>
+// CHECK-NEXT:      memref.dealloc %[[ALLOC]] : memref<32xf32>
+// CHECK-NEXT:      return
+
+// The pass finds no last user when an alloc has only a dealloc as its user.
+// Verify the IR stays unchanged.
+func.func private @test_alloc_no_non_dealloc_users() {
+  %alloc = memref.alloc() {alignment = 64 : i64} : memref<32xf32>
+  memref.dealloc %alloc : memref<32xf32>
+  return
+}
+
+// -----
+
+// CHECK-LABEL:   func.func private @test_dynamic_dimensions(
+// CHECK-SAME:                                               %[[N:.*]]: index) {
+// CHECK:           %[[C0:.*]] = arith.constant 0 : index
+// CHECK:           %[[ALLOC:.*]] = memref.alloc(%[[N]]) {alignment = 64 : i64} : memref<?xf32>
+// CHECK:           memref.load %[[ALLOC]][%[[C0]]]
+// CHECK:           memref.dealloc %[[ALLOC]] : memref<?xf32>
+// CHECK:           %[[ALLOC1:.*]] = memref.alloc() {alignment = 64 : i64} : memref<32xf32>
+// CHECK:           arith.constant
+// CHECK:           memref.store {{.*}}, %[[ALLOC1]][%[[C0]]]
+// CHECK:           memref.dealloc %[[ALLOC1]] : memref<32xf32>
+// CHECK:           return
+
+// The pass moves the dealloc of a dynamic alloc to right after its last user.
+// %alloc starts with its dealloc at the end of the block. The pass moves it
+// to right after the memref.load, which is the last use of %alloc.
+func.func private @test_dynamic_dimensions(%n: index) {
+  %c0 = arith.constant 0 : index
+  %alloc = memref.alloc(%n) {alignment = 64 : i64} : memref<?xf32>
+  %val = memref.load %alloc[%c0] : memref<?xf32>
+  %alloc_1 = memref.alloc() {alignment = 64 : i64} : memref<32xf32>
+  %cf0 = arith.constant 0.0 : f32
+  memref.store %cf0, %alloc_1[%c0] : memref<32xf32>
+  memref.dealloc %alloc : memref<?xf32>
+  memref.dealloc %alloc_1 : memref<32xf32>
+  return
+}

>From c060c5d256c3dea95b90e4bf755352bb74841fb8 Mon Sep 17 00:00:00 2001
From: Mohamed Deraz Nasr <mderaznasr at gmail.com>
Date: Mon, 30 Mar 2026 23:16:33 -0400
Subject: [PATCH 2/2] [mlir][bufferization] Add tests for
 OptimizeAllocationLiveness edge cases

Add two test cases to optimize-allocation-liveness.mlir that cover
untested code paths in OptimizeAllocationLiveness.cpp:

1. An alloc with no users other than its dealloc. The pass hits the
   lastUser == nullptr branch and leaves the IR unchanged.

2. An alloc with a dynamic dimension (memref<?xf32>). All existing
   tests use static shapes. This verifies the pass moves the dealloc
   to right after the last user when the alloc size is not known at
   compile time.
---
 .../optimize-allocation-liveness.mlir         | 30 +++++++------------
 1 file changed, 10 insertions(+), 20 deletions(-)

diff --git a/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir b/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
index 31fbbf80a9c6d..27bca1214695a 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/optimize-allocation-liveness.mlir
@@ -237,13 +237,12 @@ func.func private @test_alloc_with_multiple_results() -> () {
 
 // -----
 
-// CHECK-LABEL:   func.func private @test_alloc_no_non_dealloc_users() {
-// CHECK:           %[[ALLOC:.*]] = memref.alloc() {alignment = 64 : i64} : memref<32xf32>
-// CHECK-NEXT:      memref.dealloc %[[ALLOC]] : memref<32xf32>
-// CHECK-NEXT:      return
+// CHECK-LABEL: func.func private @test_alloc_no_non_dealloc_users
+// CHECK: %[[alloc:.*]] = memref.alloc
+// CHECK-NEXT: memref.dealloc %[[alloc]]
+// CHECK-NEXT: return
 
-// The pass finds no last user when an alloc has only a dealloc as its user.
-// Verify the IR stays unchanged.
+// No non-dealloc users. The pass should not move the dealloc.
 func.func private @test_alloc_no_non_dealloc_users() {
   %alloc = memref.alloc() {alignment = 64 : i64} : memref<32xf32>
   memref.dealloc %alloc : memref<32xf32>
@@ -252,21 +251,12 @@ func.func private @test_alloc_no_non_dealloc_users() {
 
 // -----
 
-// CHECK-LABEL:   func.func private @test_dynamic_dimensions(
-// CHECK-SAME:                                               %[[N:.*]]: index) {
-// CHECK:           %[[C0:.*]] = arith.constant 0 : index
-// CHECK:           %[[ALLOC:.*]] = memref.alloc(%[[N]]) {alignment = 64 : i64} : memref<?xf32>
-// CHECK:           memref.load %[[ALLOC]][%[[C0]]]
-// CHECK:           memref.dealloc %[[ALLOC]] : memref<?xf32>
-// CHECK:           %[[ALLOC1:.*]] = memref.alloc() {alignment = 64 : i64} : memref<32xf32>
-// CHECK:           arith.constant
-// CHECK:           memref.store {{.*}}, %[[ALLOC1]][%[[C0]]]
-// CHECK:           memref.dealloc %[[ALLOC1]] : memref<32xf32>
-// CHECK:           return
+// CHECK-LABEL: func.func private @test_dynamic_dimensions
+// CHECK: %[[alloc:.*]] = memref.alloc
+// CHECK-NEXT: memref.load %[[alloc]]
+// CHECK-NEXT: memref.dealloc %[[alloc]]
 
-// The pass moves the dealloc of a dynamic alloc to right after its last user.
-// %alloc starts with its dealloc at the end of the block. The pass moves it
-// to right after the memref.load, which is the last use of %alloc.
+// The pass moves the dealloc of a dynamic alloc to right after its last use.
 func.func private @test_dynamic_dimensions(%n: index) {
   %c0 = arith.constant 0 : index
   %alloc = memref.alloc(%n) {alignment = 64 : i64} : memref<?xf32>



More information about the Mlir-commits mailing list