[Mlir-commits] [mlir] [mlir][bufferization] Skip unsupported element types in static memory planning (PR #237123)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Fri Oct 30 02:04:54 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-mlir-bufferization

Author: Zhijie Wang (aeft)

<details>
<summary>Changes</summary>

The static memory planner can crash when sizing memrefs with unsupported element types, such as index, complex, or vector. Skip these allocations and preserve their alloc/dealloc operations.

Reproducer: https://godbolt.org/z/7PG6faEab

Assisted-by: Codex

---
Full diff: https://github.com/llvm/llvm-project/pull/237123.diff


3 Files Affected:

- (modified) mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td (+3) 
- (modified) mlir/lib/Dialect/Bufferization/Transforms/StaticMemoryPlannerAnalysis.cpp (+14-7) 
- (modified) mlir/test/Dialect/Bufferization/Transforms/static-memory-planner-analysis.mlir (+27) 


``````````diff
diff --git a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
index a0a585e6c977cb..ec503217a12278 100644
--- a/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/Bufferization/Transforms/Passes.td
@@ -193,6 +193,7 @@ def StaticMemoryPlannerAnalysisPass
     For each `memref.alloc` the pass checks a conservative eligibility
     envelope:
     - Static memref shape.
+    - Integer or floating-point element type.
     - The allocation lives directly in the function's entry block
       (allocations nested in a region are skipped for now).
     - Every `memref.dealloc` that may free the buffer is anchored in the entry
@@ -261,6 +262,8 @@ def StaticMemoryPlannerAnalysisPass
                  "Number of alloc/dealloc pairs eligible for static planning">,
        Statistic<"numSkipDynamic", "num-skipped-dynamic",
                  "Number of allocations skipped: dynamic shape">,
+       Statistic<"numSkipUnsupportedType", "num-skipped-unsupported-type",
+                 "Number of allocations skipped: unsupported element type">,
        Statistic<
            "numSkipNested", "num-skipped-nested",
            "Number of allocations skipped: nested in loop or conditional">,
diff --git a/mlir/lib/Dialect/Bufferization/Transforms/StaticMemoryPlannerAnalysis.cpp b/mlir/lib/Dialect/Bufferization/Transforms/StaticMemoryPlannerAnalysis.cpp
index 6d5a9f0aba6a96..a819e37d6fe00c 100644
--- a/mlir/lib/Dialect/Bufferization/Transforms/StaticMemoryPlannerAnalysis.cpp
+++ b/mlir/lib/Dialect/Bufferization/Transforms/StaticMemoryPlannerAnalysis.cpp
@@ -138,6 +138,7 @@ static int64_t buildAllocInfos(
 /// through `arith.select`, `scf.if`/`scf.for` results, `cf` branches, or view
 /// ops are handled uniformly. An allocation is eligible when:
 ///   - it has a static shape (dynamic shapes are silently skipped), and
+///   - its element type is an integer or float, and
 ///   - it lives directly in the function's entry block (allocs nested in a
 ///     region are skipped for now), and
 ///   - every dealloc that may free it is anchored in that same entry block --
@@ -150,12 +151,11 @@ static int64_t buildAllocInfos(
 /// free (per the reverse alias set) are themselves candidates in this block;
 /// otherwise erasing it during the rewrite could leak or double-free a buffer
 /// that is not managed by the arena.
-static LogicalResult
-collectCandidates(FunctionOpInterface funcOp,
-                  const BufferViewFlowAnalysis &analysis,
-                  llvm::Statistic &numSkipDynamic,
-                  llvm::Statistic &numSkipNested, llvm::Statistic &numEligible,
-                  SmallVector<AllocationCandidate> &candidates) {
+static LogicalResult collectCandidates(
+    FunctionOpInterface funcOp, const BufferViewFlowAnalysis &analysis,
+    llvm::Statistic &numSkipDynamic, llvm::Statistic &numSkipUnsupportedType,
+    llvm::Statistic &numSkipNested, llvm::Statistic &numEligible,
+    SmallVector<AllocationCandidate> &candidates) {
   // All candidates are planned relative to the function's entry block.
   if (funcOp.getFunctionBody().empty())
     return success();
@@ -176,6 +176,12 @@ collectCandidates(FunctionOpInterface funcOp,
       return WalkResult::advance();
     }
 
+    // computeSizeInBytes only supports integer and floating-point elements.
+    if (!memrefType.getElementType().isIntOrFloat()) {
+      ++numSkipUnsupportedType;
+      return WalkResult::advance();
+    }
+
     SmallVector<memref::DeallocOp> deallocs;
     collectDeallocs(allocOp.getResult(), analysis, deallocs);
 
@@ -322,7 +328,8 @@ void StaticMemoryPlannerAnalysisPass::runOnOperation() {
   // and view ops so we can find deallocs and freed allocs uniformly.
   BufferViewFlowAnalysis analysis(funcOp);
   SmallVector<AllocationCandidate> candidates;
-  if (failed(collectCandidates(funcOp, analysis, numSkipDynamic, numSkipNested,
+  if (failed(collectCandidates(funcOp, analysis, numSkipDynamic,
+                               numSkipUnsupportedType, numSkipNested,
                                numEligible, candidates)))
     return signalPassFailure();
 
diff --git a/mlir/test/Dialect/Bufferization/Transforms/static-memory-planner-analysis.mlir b/mlir/test/Dialect/Bufferization/Transforms/static-memory-planner-analysis.mlir
index 46f9f9ec96fd19..1171d28178fcce 100644
--- a/mlir/test/Dialect/Bufferization/Transforms/static-memory-planner-analysis.mlir
+++ b/mlir/test/Dialect/Bufferization/Transforms/static-memory-planner-analysis.mlir
@@ -598,3 +598,30 @@ func.func @scf_for_reads_entry_block_bufs(%lb: index, %ub: index, %step: index)
   memref.dealloc %b : memref<1024xf32>
   return
 }
+
+// -----
+
+// Preserve allocations with unsupported element types instead of asserting.
+// An independent allocation with a supported element type can still be planned.
+// CHECK-LABEL: func.func @unsupported_element_types(
+// CHECK-NEXT: %[[INDEX:.*]] = memref.alloc() : memref<4xindex>
+// CHECK-NEXT: %[[COMPLEX:.*]] = memref.alloc() : memref<4xcomplex<f32>>
+// CHECK-NEXT: %[[VECTOR:.*]] = memref.alloc() : memref<4xvector<2xf32>>
+// CHECK-NEXT: memref.dealloc %[[INDEX]] : memref<4xindex>
+// CHECK-NEXT: memref.dealloc %[[COMPLEX]] : memref<4xcomplex<f32>>
+// CHECK-NEXT: memref.dealloc %[[VECTOR]] : memref<4xvector<2xf32>>
+// CHECK-NEXT: %[[ARENA:.*]] = memref.alloc() alignment = 1 : memref<32xi8>
+// CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : index
+// CHECK-NEXT: %{{.*}} = memref.view %[[ARENA]][%[[C0]]][] : memref<32xi8> to memref<8xi32>
+// CHECK-NEXT: return
+func.func @unsupported_element_types() {
+  %index = memref.alloc() : memref<4xindex>
+  %complex = memref.alloc() : memref<4xcomplex<f32>>
+  %vector = memref.alloc() : memref<4xvector<2xf32>>
+  memref.dealloc %index : memref<4xindex>
+  memref.dealloc %complex : memref<4xcomplex<f32>>
+  memref.dealloc %vector : memref<4xvector<2xf32>>
+  %supported = memref.alloc() : memref<8xi32>
+  memref.dealloc %supported : memref<8xi32>
+  return
+}

``````````

</details>


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


More information about the Mlir-commits mailing list