[Mlir-commits] [mlir] 83d27d8 - [mlir] [memref] [transform] Add alloc_to_global op. (#211141)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Thu Aug 13 13:11:37 PDT 2026


Author: Bhavesh M
Date: 2026-08-13T13:11:32-07:00
New Revision: 83d27d808c85b0fc6f59467d71de2fc1b03a6332

URL: https://github.com/llvm/llvm-project/commit/83d27d808c85b0fc6f59467d71de2fc1b03a6332
DIFF: https://github.com/llvm/llvm-project/commit/83d27d808c85b0fc6f59467d71de2fc1b03a6332.diff

LOG: [mlir] [memref] [transform] Add alloc_to_global op. (#211141)

This adds a new transform op that creates a `memref.global` op for
each provided `memref.alloc` and replaces `memref.alloc`s with
`memref.get_global`. It also creates a new helper function that contains
the shared logic between the existing `alloca_to_global` op and
`alloc_to_global`. It also checks whether `memref.alloc`s and
`memref.alloca`s are statically shaped since `memref.global` requires
statically shaped buffers.

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.td
    mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp
    mlir/test/Dialect/MemRef/transform-ops.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.td b/mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.td
index f4694a30a8a12..d07dbf3ec335b 100644
--- a/mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.td
+++ b/mlir/include/mlir/Dialect/MemRef/TransformOps/MemRefTransformOps.td
@@ -193,7 +193,11 @@ def MemRefAllocaToGlobalOp :
 
     #### Return modes
 
-    Succeeds always. The returned handles refer to the `memref.get_global` and
+    Succeeds if all payload operations are statically shaped allocations with static
+    layouts (no dynamic offsets, strides, or symbol operands).
+    Fails with a silenceable error if any allocation has a dynamic shape, dynamic
+    offset/stride, or symbol operands.
+    The returned handles refer to the `memref.get_global` and
     `memref.global` ops that were inserted by the transformation.
   }];
 
@@ -206,6 +210,81 @@ def MemRefAllocaToGlobalOp :
   }];
 }
 
+def MemRefAllocToGlobalOp :
+  Op<Transform_Dialect, "memref.alloc_to_global",
+     [TransformOpInterface,
+      DeclareOpInterfaceMethods<MemoryEffectsOpInterface>,
+      DeclareOpInterfaceMethods<TransformOpInterface>]> {
+  let description = [{
+    Inserts a new `memref.global` for each provided `memref.alloc` into the
+    nearest symbol table (e.g., a `builtin.module`) and replaces it with a
+    `memref.get_global`. Any direct `memref.dealloc` operations referencing the
+    allocation are also removed, since the memory is no longer dynamically
+    allocated.
+
+    This transformation assumes that the allocation does not escape the current
+    container (e.g., it is not returned from the function or passed to another
+    function that deallocates it) and is not passed through control-flow or
+    alias operations (e.g., `scf.if`, `cf.cond_br`, `select`, `memref.subview`).
+    Only direct `memref.dealloc` users of the allocation operation are removed;
+    indirect deallocations referencing block arguments, region results, or aliased
+    views will not be removed.
+
+    #### Example
+
+    Consider the following transform op:
+
+    ```mlir
+    %get_global, %global =
+        transform.memref.alloc_to_global %alloc
+          : (!transform.op<"memref.alloc">)
+            -> (!transform.any_op, !transform.any_op)
+    ```
+
+    and the following input payload:
+
+    ```mlir
+    module {
+      func.func @func() {
+        %alloc = memref.alloc() : memref<2x32xf32>
+        // usages of %alloc...
+        memref.dealloc %alloc : memref<2x32xf32>
+      }
+    }
+    ```
+
+    then applying the transform op to the payload would result in the following
+    output IR:
+
+    ```mlir
+    module {
+      memref.global "private" @alloc : memref<2x32xf32>
+      func.func @func() {
+        %alloc = memref.get_global @alloc : memref<2x32xf32>
+        // usages of %alloc...
+      }
+    }
+    ```
+
+    #### Return modes
+
+    Succeeds if all payload operations are statically shaped allocations with static
+    layouts (no dynamic offsets, strides, or symbol operands).
+    Fails with a silenceable error if any allocation has a dynamic shape, dynamic
+    offset/stride, or symbol operands.
+    The returned handles refer to the `memref.get_global` and
+    `memref.global` ops that were inserted by the transformation.
+  }];
+
+  let arguments = (ins Transform_MemRefAllocOp:$alloc);
+  let results = (outs TransformHandleTypeInterface:$getGlobal,
+                  TransformHandleTypeInterface:$global);
+
+  let assemblyFormat = [{
+    $alloc attr-dict `:` functional-type(operands, results)
+  }];
+}
+
 def MemRefMultiBufferOp : Op<Transform_Dialect, "memref.multibuffer",
     [FunctionalStyleTransformOpTrait, MemoryEffectsOpInterface,
      DeclareOpInterfaceMethods<TransformOpInterface>]> {

diff  --git a/mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp b/mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp
index 95eb2a9a95bc1..49120636485ef 100644
--- a/mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp
+++ b/mlir/lib/Dialect/MemRef/TransformOps/MemRefTransformOps.cpp
@@ -125,6 +125,101 @@ void transform::ApplyResolveRankedShapedTypeResultDimsPatternsOp::
   memref::populateResolveRankedShapedTypeResultDimsPatterns(patterns);
 }
 
+//===----------------------------------------------------------------------===//
+// Alloc and alloca to global utilities
+//===----------------------------------------------------------------------===//
+
+/// Checks whether an allocation operation can be converted to a
+/// `memref.global`.
+template <typename AllocLikeOp>
+static DiagnosedSilenceableFailure
+checkAllocToGlobalPreconditions(AllocLikeOp allocLikeOp) {
+  MemRefType memrefType = allocLikeOp.getType();
+  if (!memrefType.hasStaticShape()) {
+    return emitSilenceableFailure(allocLikeOp)
+           << "conversion to a global op requires statically shaped memrefs, "
+              "but got "
+           << memrefType;
+  }
+
+  if (!allocLikeOp.getSymbolOperands().empty()) {
+    return emitSilenceableFailure(allocLikeOp)
+           << "conversion to a global op does not support symbol operands, but "
+              "got "
+           << memrefType;
+  }
+
+  int64_t offset;
+  SmallVector<int64_t, 4> strides;
+  if (failed(memrefType.getStridesAndOffset(strides, offset))) {
+    return emitSilenceableFailure(allocLikeOp)
+           << "conversion to a global op requires strided layout, but got "
+           << memrefType;
+  }
+  if (!ShapedType::isStatic(offset) || !ShapedType::isStaticShape(strides)) {
+    return emitSilenceableFailure(allocLikeOp)
+           << "conversion to a global op does not support dynamic offset or "
+              "strides, but got "
+           << memrefType;
+  }
+
+  return DiagnosedSilenceableFailure::success();
+}
+
+/// Converts an allocation operation (`memref.alloca` or `memref.alloc`) to a
+/// `memref.global` operation in the nearest symbol table, and replaces the
+/// allocation with a `memref.get_global` operation. Any `memref.dealloc`
+/// operations referencing the allocation are erased.
+template <typename AllocLikeOp>
+static DiagnosedSilenceableFailure
+allocLikeToGlobal(transform::TransformRewriter &rewriter,
+                  AllocLikeOp allocLikeOp, StringRef globalName,
+                  memref::GlobalOp &globalOp,
+                  memref::GetGlobalOp &getGlobalOp) {
+  if (DiagnosedSilenceableFailure failure =
+          checkAllocToGlobalPreconditions(allocLikeOp);
+      !failure.succeeded())
+    return failure;
+
+  MLIRContext *ctx = rewriter.getContext();
+  Location loc = allocLikeOp->getLoc();
+
+  // Find nearest symbol table.
+  Operation *symbolTableOp = SymbolTable::getNearestSymbolTable(allocLikeOp);
+  assert(symbolTableOp && "expected payload to be in symbol table");
+  SymbolTable symbolTable(symbolTableOp);
+
+  // Insert a `memref.global` into the symbol table.
+  Type resultType = allocLikeOp.getResult().getType();
+  OpBuilder builder(rewriter.getContext());
+  // TODO: Add a better builder for this.
+  globalOp = memref::GlobalOp::create(
+      builder, loc, StringAttr::get(ctx, globalName),
+      StringAttr::get(ctx, "private"), TypeAttr::get(resultType), Attribute{},
+      UnitAttr{}, allocLikeOp.getAlignmentAttr());
+  symbolTable.insert(globalOp);
+
+  // Remove any `memref.dealloc` operations referencing this allocation.
+  // We assume that the allocation does not escape the current container
+  // (e.g., via return or interprocedural function calls) and is not passed
+  // through control-flow or alias operations (e.g., `scf.if`, `cf.cond_br`,
+  // `select`, `memref.subview`), so any deallocation is a direct user of the
+  // allocation. Indirect deallocations are not removed and must be handled
+  // separately.
+  for (Operation *user : llvm::make_early_inc_range(allocLikeOp->getUsers())) {
+    if (auto dealloc = dyn_cast<memref::DeallocOp>(user))
+      rewriter.eraseOp(dealloc);
+  }
+
+  // Replace the allocation with a `memref.get_global` accessing the
+  // global symbol inserted above.
+  rewriter.setInsertionPoint(allocLikeOp);
+  getGlobalOp = rewriter.replaceOpWithNewOp<memref::GetGlobalOp>(
+      allocLikeOp, globalOp.getType(), globalOp.getName());
+
+  return DiagnosedSilenceableFailure::success();
+}
+
 //===----------------------------------------------------------------------===//
 // AllocaToGlobalOp
 //===----------------------------------------------------------------------===//
@@ -141,32 +236,12 @@ transform::MemRefAllocaToGlobalOp::apply(transform::TransformRewriter &rewriter,
   // Transform `memref.alloca`s.
   for (auto *op : allocaOps) {
     auto alloca = cast<memref::AllocaOp>(op);
-    MLIRContext *ctx = rewriter.getContext();
-    Location loc = alloca->getLoc();
-
     memref::GlobalOp globalOp;
-    {
-      // Find nearest symbol table.
-      Operation *symbolTableOp = SymbolTable::getNearestSymbolTable(op);
-      assert(symbolTableOp && "expected alloca payload to be in symbol table");
-      SymbolTable symbolTable(symbolTableOp);
-
-      // Insert a `memref.global` into the symbol table.
-      Type resultType = alloca.getResult().getType();
-      OpBuilder builder(rewriter.getContext());
-      // TODO: Add a better builder for this.
-      globalOp = memref::GlobalOp::create(
-          builder, loc, StringAttr::get(ctx, "alloca"),
-          StringAttr::get(ctx, "private"), TypeAttr::get(resultType),
-          Attribute{}, UnitAttr{}, IntegerAttr{});
-      symbolTable.insert(globalOp);
-    }
-
-    // Replace the `memref.alloca` with a `memref.get_global` accessing the
-    // global symbol inserted above.
-    rewriter.setInsertionPoint(alloca);
-    auto getGlobalOp = rewriter.replaceOpWithNewOp<memref::GetGlobalOp>(
-        alloca, globalOp.getType(), globalOp.getName());
+    memref::GetGlobalOp getGlobalOp;
+    DiagnosedSilenceableFailure diag =
+        allocLikeToGlobal(rewriter, alloca, "alloca", globalOp, getGlobalOp);
+    if (!diag.succeeded())
+      return diag;
 
     globalOps.push_back(globalOp);
     getGlobalOps.push_back(getGlobalOp);
@@ -186,6 +261,47 @@ void transform::MemRefAllocaToGlobalOp::getEffects(
   modifiesPayload(effects);
 }
 
+//===----------------------------------------------------------------------===//
+// AllocToGlobalOp
+//===----------------------------------------------------------------------===//
+
+DiagnosedSilenceableFailure
+transform::MemRefAllocToGlobalOp::apply(transform::TransformRewriter &rewriter,
+                                        transform::TransformResults &results,
+                                        transform::TransformState &state) {
+  auto allocOps = state.getPayloadOps(getAlloc());
+
+  SmallVector<memref::GlobalOp> globalOps;
+  SmallVector<memref::GetGlobalOp> getGlobalOps;
+
+  // Transform `memref.alloc`s.
+  for (auto *op : allocOps) {
+    auto alloc = cast<memref::AllocOp>(op);
+    memref::GlobalOp globalOp;
+    memref::GetGlobalOp getGlobalOp;
+    DiagnosedSilenceableFailure diag =
+        allocLikeToGlobal(rewriter, alloc, "alloc", globalOp, getGlobalOp);
+    if (!diag.succeeded())
+      return diag;
+
+    globalOps.push_back(globalOp);
+    getGlobalOps.push_back(getGlobalOp);
+  }
+
+  // Assemble results.
+  results.set(cast<OpResult>(getGlobal()), globalOps);
+  results.set(cast<OpResult>(getGetGlobal()), getGlobalOps);
+
+  return DiagnosedSilenceableFailure::success();
+}
+
+void transform::MemRefAllocToGlobalOp::getEffects(
+    SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
+  producesHandle(getOperation()->getOpResults(), effects);
+  consumesHandle(getAllocMutable(), effects);
+  modifiesPayload(effects);
+}
+
 //===----------------------------------------------------------------------===//
 // MemRefMultiBufferOp
 //===----------------------------------------------------------------------===//

diff  --git a/mlir/test/Dialect/MemRef/transform-ops.mlir b/mlir/test/Dialect/MemRef/transform-ops.mlir
index 7fc84d419f18d..65dd659600158 100644
--- a/mlir/test/Dialect/MemRef/transform-ops.mlir
+++ b/mlir/test/Dialect/MemRef/transform-ops.mlir
@@ -3,14 +3,14 @@
 // CHECK-DAG: memref.global "private" @[[ALLOC0:alloc.*]] : memref<2x32xf32>
 // CHECK-DAG: memref.global "private" @[[ALLOC1:alloc.*]] : memref<2x32xf32>
 
-// CHECK-DAG: func.func @func(%[[LB:.*]]: index, %[[UB:.*]]: index)
-func.func @func(%lb: index, %ub: index) {
+// CHECK-DAG: func.func @func_alloca(%[[LB:.*]]: index, %[[UB:.*]]: index)
+func.func @func_alloca(%lb: index, %ub: index) {
   // CHECK-DAG: scf.forall (%[[ARG0:.*]], %[[ARG1:.*]]) in (%[[LB]], %[[UB]])
   scf.forall (%arg0, %arg1) in (%lb, %ub) {
-    // CHECK-DAG: %[[MR0:.*]] = memref.get_global @[[ALLOC0]] : memref<2x32xf32>
-    // CHECK-DAG: %[[MR1:.*]] = memref.get_global @[[ALLOC1]] : memref<2x32xf32>
-    // CHECK-DAG: memref.store %{{.*}}, %[[MR0]][%{{.*}}, %{{.*}}] : memref<2x32xf32>
-    // CHECK-DAG: memref.store %{{.*}}, %[[MR1]][%{{.*}}, %{{.*}}] : memref<2x32xf32>
+    // CHECK-DAG: %[[BUF0:.*]] = memref.get_global @[[ALLOC0]] : memref<2x32xf32>
+    // CHECK-DAG: %[[BUF1:.*]] = memref.get_global @[[ALLOC1]] : memref<2x32xf32>
+    // CHECK-DAG: memref.store %{{.*}}, %[[BUF0]][%{{.*}}, %{{.*}}] : memref<2x32xf32>
+    // CHECK-DAG: memref.store %{{.*}}, %[[BUF1]][%{{.*}}, %{{.*}}] : memref<2x32xf32>
     %cst = arith.constant 0.0 : f32
     %mr0 = memref.alloca() : memref<2x32xf32>
     %mr1 = memref.alloca() : memref<2x32xf32>
@@ -33,6 +33,206 @@ module attributes {transform.with_named_sequence} {
 
 // -----
 
+// CHECK-DAG: memref.global "private" @[[ALLOC0:alloc.*]] : memref<2xf32>
+// CHECK-DAG: memref.global "private" @[[ALLOC1:alloc.*]] : memref<2xf32>
+
+// CHECK-DAG: func.func @func_alloc()
+func.func @func_alloc() {
+  // CHECK-DAG: %[[BUF0:.*]] = memref.get_global @[[ALLOC0]] : memref<2xf32>
+  // CHECK-DAG: %[[BUF1:.*]] = memref.get_global @[[ALLOC1]] : memref<2xf32>
+  // CHECK-NOT: memref.dealloc
+  %mr0 = memref.alloc() : memref<2xf32>
+  %mr1 = memref.alloc() : memref<2xf32>
+  memref.dealloc %mr0 : memref<2xf32>
+  memref.dealloc %mr1 : memref<2xf32>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloc = transform.structured.match ops{["memref.alloc"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloc">
+    %get_global, %global = transform.memref.alloc_to_global %alloc
+          : (!transform.op<"memref.alloc">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
+// CHECK-DAG: memref.global "private" @[[ALLOC:alloc.*]] : memref<2xf32>
+
+// CHECK-DAG: func.func @func_alloc_with_uses(%[[VAL:.*]]: f32, %[[IDX:.*]]: index)
+func.func @func_alloc_with_uses(%val: f32, %idx: index) {
+  // CHECK-DAG: %[[BUF:.*]] = memref.get_global @[[ALLOC]] : memref<2xf32>
+  // CHECK-DAG: memref.store %[[VAL]], %[[BUF]][%[[IDX]]] : memref<2xf32>
+  // CHECK-NOT: memref.dealloc
+  %mr = memref.alloc() : memref<2xf32>
+  memref.store %val, %mr[%idx] : memref<2xf32>
+  memref.dealloc %mr : memref<2xf32>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloc = transform.structured.match ops{["memref.alloc"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloc">
+    %get_global, %global = transform.memref.alloc_to_global %alloc
+          : (!transform.op<"memref.alloc">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
+// Test failure when memref.alloc has dynamic shape.
+func.func @alloc_to_global_dynamic_shape(%arg0: index) {
+  // expected-error @below {{conversion to a global op requires statically shaped memrefs, but got 'memref<?xf32>'}}
+  %alloc = memref.alloc(%arg0) : memref<?xf32>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloc = transform.structured.match ops{["memref.alloc"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloc">
+    %get_global, %global = transform.memref.alloc_to_global %alloc
+          : (!transform.op<"memref.alloc">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
+// Test failure when memref.alloca has dynamic shape.
+func.func @alloca_to_global_dynamic_shape(%arg0: index) {
+  // expected-error @below {{conversion to a global op requires statically shaped memrefs, but got 'memref<?xf32>'}}
+  %alloca = memref.alloca(%arg0) : memref<?xf32>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloca = transform.structured.match ops{["memref.alloca"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloca">
+    %get_global, %global = transform.memref.alloca_to_global %alloca
+          : (!transform.op<"memref.alloca">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
+// Test failure when memref.alloca has symbol operands.
+#map0 = affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>
+
+func.func @alloca_to_global_symbol_operands(%s: index) {
+  // expected-error @below {{conversion to a global op does not support symbol operands, but got 'memref<8x8xf32, affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>>'}}
+  %alloca = memref.alloca()[%s] : memref<8x8xf32, #map0>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloca = transform.structured.match ops{["memref.alloca"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloca">
+    %get_global, %global = transform.memref.alloca_to_global %alloca
+          : (!transform.op<"memref.alloca">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
+// Test failure when memref.alloc has symbol operands.
+#map1 = affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>
+
+func.func @alloc_to_global_symbol_operands(%s: index) {
+  // expected-error @below {{conversion to a global op does not support symbol operands, but got 'memref<8x8xf32, affine_map<(d0, d1)[s0] -> (d0 + s0, d1)>>'}}
+  %alloc = memref.alloc()[%s] : memref<8x8xf32, #map1>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloc = transform.structured.match ops{["memref.alloc"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloc">
+    %get_global, %global = transform.memref.alloc_to_global %alloc
+          : (!transform.op<"memref.alloc">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
+// Test failure when memref.alloc has dynamic offset.
+func.func @alloc_to_global_dynamic_offset(%s: index) {
+  // expected-error @below {{conversion to a global op does not support symbol operands, but got 'memref<8x8xf32, strided<[8, 1], offset: ?>>'}}
+  %alloc = memref.alloc()[%s] : memref<8x8xf32, strided<[8, 1], offset: ?>>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloc = transform.structured.match ops{["memref.alloc"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloc">
+    %get_global, %global = transform.memref.alloc_to_global %alloc
+          : (!transform.op<"memref.alloc">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
+// Test failure when memref.alloc has dynamic stride.
+func.func @alloc_to_global_dynamic_stride(%s: index) {
+  // expected-error @below {{conversion to a global op does not support symbol operands, but got 'memref<8x8xf32, strided<[?, 1]>>'}}
+  %alloc = memref.alloc()[%s] : memref<8x8xf32, strided<[?, 1], offset: 0>>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloc = transform.structured.match ops{["memref.alloc"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloc">
+    %get_global, %global = transform.memref.alloc_to_global %alloc
+          : (!transform.op<"memref.alloc">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
+// Test failure when memref.alloc has non-strided layout.
+#map_non_strided = affine_map<(d0, d1) -> (d0 mod 3 + d1)>
+
+func.func @alloc_to_global_non_strided_layout() {
+  // expected-error @below {{conversion to a global op requires strided layout, but got 'memref<8x8xf32, affine_map<(d0, d1) -> (d0 mod 3 + d1)>>'}}
+  %alloc = memref.alloc() : memref<8x8xf32, #map_non_strided>
+  return
+}
+
+module attributes {transform.with_named_sequence} {
+  transform.named_sequence @__transform_main(%arg0: !transform.any_op {transform.readonly}) {
+    %alloc = transform.structured.match ops{["memref.alloc"]} in %arg0
+        : (!transform.any_op) -> !transform.op<"memref.alloc">
+    %get_global, %global = transform.memref.alloc_to_global %alloc
+          : (!transform.op<"memref.alloc">)
+            -> (!transform.any_op, !transform.any_op)
+    transform.yield
+  }
+}
+
+// -----
+
 // CHECK-DAG: #[[$MAP0:.*]] = affine_map<(d0) -> ((d0 floordiv 4) mod 2)>
 // CHECK-DAG: #[[$MAP1:.*]] = affine_map<(d0)[s0] -> (d0 + s0)>
 


        


More information about the Mlir-commits mailing list