[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