[Mlir-commits] [mlir] [mlir][VectorToSCF] Decline transfer ops with no automatic allocation scope (PR #216947)

Alessandro Potenza llvmlistbot at llvm.org
Tue Aug 18 00:55:15 PDT 2026


https://github.com/alepot55 created https://github.com/llvm/llvm-project/pull/216947

Fixes #216225.

Lowering a `vector.transfer_*` whose rank exceeds the target rank allocates a
temporary buffer with `memref.alloca`, whose verifier requires an ancestor
carrying `AutomaticAllocationScope`. The pattern never checked for one, so a
transfer op sitting directly in `builtin.module` asserts in
`getAutomaticAllocationScope` instead of being left alone:

```mlir
%c0 = arith.constant 0 : index
%cst = arith.constant dense<0.0> : vector<2x3xf32>
%m = memref.alloc() : memref<2x3xf32>
vector.transfer_write %cst, %m[%c0, %c0] : vector<2x3xf32>, memref<2x3xf32>
```

Declining is the only option: there is no legal IR the pattern could emit here.
The check goes in `checkPrepareXferOp`, which both the read and the write
conversion already call.

Verified by execution: the input above aborts on `d4e78d7f5`, the new test fails
without the patch and passes with it, and `Conversion/VectorToSCF` plus
`Dialect/Vector` stay green (107 tests).

Assisted-by: Claude (Anthropic)

AI-assisted, disclosed per the LLVM AI Tool Use Policy.


>From 74a2aa81d7bb9975cf8340e0c72c7cd289e8fc4e Mon Sep 17 00:00:00 2001
From: Alessandro Potenza <ap.alessandro.potenza at gmail.com>
Date: Tue, 18 Aug 2026 09:31:07 +0200
Subject: [PATCH] [mlir][VectorToSCF] Decline transfer ops with no automatic
 allocation scope

Lowering a transfer op whose vector rank exceeds the target rank allocates a
temporary buffer via memref.alloca, whose verifier requires an ancestor with
the AutomaticAllocationScope trait. The pattern did not check for one, so a
transfer op at module scope hit an assertion in getAutomaticAllocationScope
instead of being left alone.

Fixes #216225.
---
 mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp      |  6 ++++++
 mlir/test/Conversion/VectorToSCF/no-alloc-scope.mlir | 12 ++++++++++++
 2 files changed, 18 insertions(+)
 create mode 100644 mlir/test/Conversion/VectorToSCF/no-alloc-scope.mlir

diff --git a/mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp b/mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp
index c9eba6962e6a4..1778fc2493c91 100644
--- a/mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp
+++ b/mlir/lib/Conversion/VectorToSCF/VectorToSCF.cpp
@@ -567,6 +567,12 @@ static LogicalResult checkPrepareXferOp(OpTy xferOp, PatternRewriter &rewriter,
       xferOp.getShapedType().getElementType())
     return rewriter.notifyMatchFailure(
         xferOp, "Mismatching source and destination element types.");
+  // The lowering allocates a temporary buffer, which `memref.alloca` only
+  // allows inside an automatic allocation scope.
+  Operation *op = xferOp.getOperation();
+  if (!op->getParentWithTrait<OpTrait::AutomaticAllocationScope>())
+    return rewriter.notifyMatchFailure(
+        xferOp, "xferOp is not inside an automatic allocation scope");
 
   return success();
 }
diff --git a/mlir/test/Conversion/VectorToSCF/no-alloc-scope.mlir b/mlir/test/Conversion/VectorToSCF/no-alloc-scope.mlir
new file mode 100644
index 0000000000000..6b817b933aa86
--- /dev/null
+++ b/mlir/test/Conversion/VectorToSCF/no-alloc-scope.mlir
@@ -0,0 +1,12 @@
+// RUN: mlir-opt %s -convert-vector-to-scf | FileCheck %s
+
+// The lowering of a transfer op whose rank exceeds the target rank allocates a
+// temporary buffer, so it needs an enclosing automatic allocation scope. These
+// ops sit directly in the implicit `builtin.module`, which is not one, so the
+// pattern has to decline instead of building an invalid `memref.alloca`.
+
+// CHECK: vector.transfer_write
+%c0 = arith.constant 0 : index
+%cst = arith.constant dense<0.0> : vector<2x3xf32>
+%m = memref.alloc() : memref<2x3xf32>
+vector.transfer_write %cst, %m[%c0, %c0] : vector<2x3xf32>, memref<2x3xf32>



More information about the Mlir-commits mailing list