[Mlir-commits] [mlir] [mlir][EmitC] Add rank-0 MemRef conversion (PR #205774)
ioana ghiban
llvmlistbot at llvm.org
Thu Jun 25 04:06:13 PDT 2026
https://github.com/ioghiban created https://github.com/llvm/llvm-project/pull/205774
Add rank-0 memref support to MemRefToEmitC and the EmitC TypeConverter, needed for lowering the models generated by:
- `llvm/lib/Analysis/models/gen-inline-oz-test-model.py`
- `llvm/lib/Analysis/models/gen-regalloc-eviction-test-model.py`
Rank-0 memrefs are no longer rejected by `isMemRefTypeLegalForEmitC`. The EmitC type converter maps `memref<T>` to `!emitc.ptr<T>`, giving rank-0 memrefs addressable scalar storage.
`memref.alloc` now allocates one element for rank-0 memrefs. `memref.dealloc` frees the pointer-backed value. `memref.load` and `memref.store` lower rank-0 accesses through `emitc.subscript %ptr[0]`, followed by `emitc.load` or `emitc.assign`. `memref.copy` lowers rank-0 copies as scalar load plus assign.
`memref.alloca` still rejects rank-0 memrefs because this patch only supports pointer-backed rank-0 lowering.
The pointer recovery helper now accepts both direct `emitc.ptr<T>` values and pointer values behind `builtin.unrealized_conversion_cast`, which is needed by dealloc, copy, load, and store depending on where the value comes from in conversion.
Tests cover rank-0 alloc/dealloc, load/store, alloc-backed load/store, and copy. Removed cases this patch adds support for (rank-0) from `func-to-emitc-failed`.
Assisted-by: Codex (refine implementation + tests). I reviewed all code and tests before submission.
>From e9787b54e9992a9ba4ab61be46286d3ff7d27f54 Mon Sep 17 00:00:00 2001
From: Ioana Ghiban <ioana.ghiban at arm.com>
Date: Mon, 22 Jun 2026 14:05:19 +0200
Subject: [PATCH] [mlir][EmitC] Add rank-0 MemRef conversion
---
.../Conversion/EmitCCommon/TypeConverter.cpp | 3 +-
.../MemRefToEmitC/MemRefToEmitC.cpp | 72 ++++++++++++++-----
.../FuncToEmitC/func-to-emitc-failed.mlir | 15 ----
.../memref-to-emitc-alloc-dealloc.mlir | 26 +++++++
.../memref-to-emitc-alloc-load-store.mlir | 48 +++++++++++++
.../MemRefToEmitC/memref-to-emitc-copy.mlir | 21 +++++-
6 files changed, 150 insertions(+), 35 deletions(-)
diff --git a/mlir/lib/Conversion/EmitCCommon/TypeConverter.cpp b/mlir/lib/Conversion/EmitCCommon/TypeConverter.cpp
index a65edcf8306b8..1722fb95524d5 100644
--- a/mlir/lib/Conversion/EmitCCommon/TypeConverter.cpp
+++ b/mlir/lib/Conversion/EmitCCommon/TypeConverter.cpp
@@ -18,7 +18,6 @@ namespace {
static bool isMemRefTypeLegalForEmitC(MemRefType memRefType) {
return memRefType.hasStaticShape() && memRefType.getLayout().isIdentity() &&
- memRefType.getRank() != 0 &&
!llvm::is_contained(memRefType.getShape(), 0);
}
@@ -50,6 +49,8 @@ EmitCTypeConverter::EmitCTypeConverter(MLIRContext *ctx) {
if (!convertedElementType)
return {};
+ if (memRefType.getRank() == 0)
+ return emitc::PointerType::get(convertedElementType);
return emitc::ArrayType::get(memRefType.getShape(), convertedElementType);
});
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 8acb737f0e9b8..3af48fe23d140 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -30,7 +30,6 @@ using namespace mlir;
static bool isMemRefTypeLegalForEmitC(MemRefType memRefType) {
return memRefType.hasStaticShape() && memRefType.getLayout().isIdentity() &&
- memRefType.getRank() != 0 &&
!llvm::is_contained(memRefType.getShape(), 0);
}
@@ -73,6 +72,11 @@ struct ConvertAlloca final : public OpConversionPattern<memref::AllocaOp> {
op.getLoc(), "cannot transform alloca with dynamic shape");
}
+ if (op.getType().getRank() == 0) {
+ return rewriter.notifyMatchFailure(
+ op.getLoc(), "cannot transform alloca with zero rank");
+ }
+
if (op.getAlignment().value_or(1) > 1) {
// TODO: Allow alignment if it is not more than the natural alignment
// of the C array.
@@ -142,9 +146,12 @@ createPointerFromEmitcArray(Location loc, OpBuilder &builder,
return ptr;
}
-// If `v` is defined through an unrealized cast and the source of that cast
-// is `emitc.ptr`, return the pointer.
-static Value stripPointerUnrealizedCast(Value v) {
+static Value getPointerOrStripUnrealizedCast(Value v) {
+ if (isa<emitc::PointerType>(v.getType()))
+ return v;
+
+ // If `v` is defined through an unrealized cast and the source of that cast
+ // is `emitc.ptr`, return the pointer.
if (auto cast = v.getDefiningOp<UnrealizedConversionCastOp>())
if (cast.getNumOperands() == 1 &&
isa<emitc::PointerType>(cast.getOperand(0).getType()))
@@ -165,6 +172,9 @@ static Value computeRowMajorLinearIndex(ImplicitLocOpBuilder &builder,
? emitc::ConstantOp::create(builder, idxType, builder.getIndexAttr(0))
: indices[0];
+ if (shape.empty())
+ return linearIndex;
+
for (auto [dim, idx] : llvm::zip(shape.drop_front(), indices.drop_front())) {
Value dimSize =
emitc::ConstantOp::create(builder, idxType, builder.getIndexAttr(dim));
@@ -238,10 +248,9 @@ struct ConvertDealloc final : public OpConversionPattern<memref::DeallocOp> {
ConversionPatternRewriter &rewriter) const override {
Location loc = deallocOp.getLoc();
// `free` can only be emitted when the dealloc operand is recoverable as an
- // `emitc.ptr<T>`. In the current conversion, that happens via an
- // unrealized_conversion_cast from the pointer-backed EmitC form.
- Value strippedPtr = stripPointerUnrealizedCast(operands.getMemref());
- if (!strippedPtr) {
+ // `emitc.ptr<T>`.
+ Value ptr = getPointerOrStripUnrealizedCast(operands.getMemref());
+ if (!ptr) {
return rewriter.notifyMatchFailure(
loc, "expected pointer-backed memref for EmitC deallocation");
}
@@ -252,7 +261,7 @@ struct ConvertDealloc final : public OpConversionPattern<memref::DeallocOp> {
Type opaqueVoidPtrType = emitc::PointerType::get(
emitc::OpaqueType::get(rewriter.getContext(), "void"));
Value freeArg =
- emitc::CastOp::create(rewriter, loc, opaqueVoidPtrType, strippedPtr);
+ emitc::CastOp::create(rewriter, loc, opaqueVoidPtrType, ptr);
emitc::CallOpaqueOp freeCall = emitc::CallOpaqueOp::create(
rewriter, loc, TypeRange{}, rewriter.getStringAttr(freeFunctionName),
ValueRange{freeArg});
@@ -280,6 +289,35 @@ struct ConvertCopy final : public OpConversionPattern<memref::CopyOp> {
return rewriter.notifyMatchFailure(
loc, "incompatible target memref type for EmitC conversion");
+ if (srcMemrefType.getRank() == 0) {
+ assert(targetMemrefType.getRank() == 0 &&
+ "target must have same rank as source");
+ Type elementType =
+ getTypeConverter()->convertType(srcMemrefType.getElementType());
+ if (!elementType)
+ return rewriter.notifyMatchFailure(loc, "cannot convert element type");
+
+ Value srcPtr = getPointerOrStripUnrealizedCast(operands.getSource());
+ Value targetPtr = getPointerOrStripUnrealizedCast(operands.getTarget());
+ if (!srcPtr || !targetPtr)
+ return rewriter.notifyMatchFailure(loc, "expected pointer operands");
+
+ Value zeroIndex = emitc::ConstantOp::create(
+ rewriter, loc, rewriter.getIndexType(), rewriter.getIndexAttr(0));
+ auto srcLValue = emitc::SubscriptOp::create(
+ rewriter, loc, cast<TypedValue<emitc::PointerType>>(srcPtr),
+ zeroIndex);
+ auto value = emitc::LoadOp::create(rewriter, loc, elementType,
+ srcLValue.getResult());
+
+ auto targetLValue = emitc::SubscriptOp::create(
+ rewriter, loc, cast<TypedValue<emitc::PointerType>>(targetPtr),
+ zeroIndex);
+ rewriter.replaceOpWithNewOp<emitc::AssignOp>(
+ copyOp, targetLValue.getResult(), value.getResult());
+ return success();
+ }
+
auto srcArrayValue =
cast<TypedValue<emitc::ArrayType>>(operands.getSource());
emitc::AddressOfOp srcPtr =
@@ -414,8 +452,8 @@ struct ConvertLoad final : public OpConversionPattern<memref::LoadOp> {
auto arrayValue =
dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
- Value strippedPtr = stripPointerUnrealizedCast(operands.getMemref());
- if (!strippedPtr && arrayValue) {
+ Value ptr = getPointerOrStripUnrealizedCast(operands.getMemref());
+ if (!ptr && arrayValue) {
auto subscript = emitc::SubscriptOp::create(rewriter, loc, arrayValue,
operands.getIndices());
@@ -423,14 +461,14 @@ struct ConvertLoad final : public OpConversionPattern<memref::LoadOp> {
return success();
}
- if (!strippedPtr)
+ if (!ptr)
return rewriter.notifyMatchFailure(loc, "expected array or pointer type");
MemRefType opMemrefType = cast<MemRefType>(op.getMemref().getType());
ValueRange indices = operands.getIndices();
ImplicitLocOpBuilder b(loc, rewriter);
Value linearIndex = computeRowMajorLinearIndex(b, opMemrefType, indices);
- auto typedPtr = cast<TypedValue<emitc::PointerType>>(strippedPtr);
+ auto typedPtr = cast<TypedValue<emitc::PointerType>>(ptr);
auto subscript =
emitc::SubscriptOp::create(rewriter, loc, typedPtr, linearIndex);
@@ -448,8 +486,8 @@ struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
Location loc = op.getLoc();
auto arrayValue =
dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
- Value strippedPtr = stripPointerUnrealizedCast(operands.getMemref());
- if (!strippedPtr && arrayValue) {
+ Value ptr = getPointerOrStripUnrealizedCast(operands.getMemref());
+ if (!ptr && arrayValue) {
auto subscript = emitc::SubscriptOp::create(rewriter, loc, arrayValue,
operands.getIndices());
rewriter.replaceOpWithNewOp<emitc::AssignOp>(op, subscript,
@@ -457,14 +495,14 @@ struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
return success();
}
- if (!strippedPtr)
+ if (!ptr)
return rewriter.notifyMatchFailure(loc, "expected array or pointer type");
MemRefType opMemrefType = cast<MemRefType>(op.getMemref().getType());
ValueRange indices = operands.getIndices();
ImplicitLocOpBuilder b(loc, rewriter);
Value linearIndex = computeRowMajorLinearIndex(b, opMemrefType, indices);
- auto typedPtr = cast<TypedValue<emitc::PointerType>>(strippedPtr);
+ auto typedPtr = cast<TypedValue<emitc::PointerType>>(ptr);
auto subscript =
emitc::SubscriptOp::create(rewriter, loc, typedPtr, linearIndex);
diff --git a/mlir/test/Conversion/FuncToEmitC/func-to-emitc-failed.mlir b/mlir/test/Conversion/FuncToEmitC/func-to-emitc-failed.mlir
index 46e5319d7d17c..85410ec0134e6 100644
--- a/mlir/test/Conversion/FuncToEmitC/func-to-emitc-failed.mlir
+++ b/mlir/test/Conversion/FuncToEmitC/func-to-emitc-failed.mlir
@@ -7,21 +7,6 @@ func.func @unsuppoted_emitc_type(%arg0: i4) -> i4 {
// -----
-// expected-error at +1 {{failed to legalize operation 'func.func'}}
-func.func private @return_rank0_alloc() -> memref<i32> {
- %alloc = memref.alloc() : memref<i32>
- return %alloc : memref<i32>
-}
-
-// -----
-
-// expected-error at +1 {{failed to legalize operation 'func.func'}}
-func.func private @return_rank0_arg(%arg0: memref<i32>) -> memref<i32> {
- return %arg0 : memref<i32>
-}
-
-// -----
-
// expected-error at +1 {{failed to legalize operation 'func.func'}}
func.func private @return_rank1_alloc() -> memref<1xi32> {
%alloc = memref.alloc() : memref<1xi32>
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir
index 9d20667a6490c..3194a40c16eeb 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-dealloc.mlir
@@ -89,3 +89,29 @@ func.func @allocating_and_deallocating_multi() {
// NOCPP-NEXT: %[[FREE_PTR:.*]] = emitc.cast %[[ALLOC_CAST]] : !emitc.ptr<i32> to !emitc.ptr<!emitc.opaque<"void">>
// NOCPP-NEXT: emitc.call_opaque "free"(%[[FREE_PTR]]) : (!emitc.ptr<!emitc.opaque<"void">>) -> ()
// NOCPP-NEXT: return
+
+func.func @alloc_and_dealloc_rank0() {
+ %alloc = memref.alloc() : memref<i32>
+ memref.dealloc %alloc : memref<i32>
+ return
+}
+
+// CPP-LABEL: alloc_and_dealloc_rank0
+// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 1 : index}> : () -> index
+// CPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "malloc"(%[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+// CPP-NEXT: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+// CPP-NEXT: %[[FREE_PTR:.*]] = emitc.cast %[[ALLOC_CAST]] : !emitc.ptr<i32> to !emitc.ptr<!emitc.opaque<"void">>
+// CPP-NEXT: emitc.call_opaque "free"(%[[FREE_PTR]]) : (!emitc.ptr<!emitc.opaque<"void">>) -> ()
+// CPP-NEXT: return
+
+// NOCPP-LABEL: alloc_and_dealloc_rank0
+// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 1 : index}> : () -> index
+// NOCPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "malloc"(%[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+// NOCPP-NEXT: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+// NOCPP-NEXT: %[[FREE_PTR:.*]] = emitc.cast %[[ALLOC_CAST]] : !emitc.ptr<i32> to !emitc.ptr<!emitc.opaque<"void">>
+// NOCPP-NEXT: emitc.call_opaque "free"(%[[FREE_PTR]]) : (!emitc.ptr<!emitc.opaque<"void">>) -> ()
+// NOCPP-NEXT: return
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir
index 07cad3b0c4dc2..5e466630a66a0 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-load-store.mlir
@@ -72,3 +72,51 @@ func.func @memref_load_store(%buff0: memref<2xf32>,
memref.store %v, %buff1[%i, %j] : memref<4x8xf32>
return
}
+
+/// Rank-0 alloc-backed load/store lower through pointer subscript at index 0.
+// CHECK-LABEL: emitc.func private @memref_rank0_alloc_store(
+// CHECK-SAME: %[[VAL:.*]]: i32)
+func.func private @memref_rank0_alloc_store(%v : i32) {
+ // CHECK: %[[SIZEOF_I32:.*]] = call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
+ // CHECK: %[[NUM_ELEMS:.*]] = "emitc.constant"() <{value = 1 : index}> : () -> index
+ // CHECK: %[[TOTAL_BYTES:.*]] = mul %[[SIZEOF_I32]], %[[NUM_ELEMS]] : (!emitc.size_t, index) -> !emitc.size_t
+ // CHECK: %[[MALLOC_PTR:.*]] = call_opaque "malloc"(%[[TOTAL_BYTES]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+ // CHECK: %[[ELEM_PTR:.*]] = cast %[[MALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+ %alloc = memref.alloc() : memref<i32>
+ // CHECK: %[[ZERO:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
+ // CHECK: %[[ELEM_LVALUE:.*]] = subscript %[[ELEM_PTR]]{{\[}}%[[ZERO]]] : (!emitc.ptr<i32>, index) -> !emitc.lvalue<i32>
+ // CHECK: assign %[[VAL]] : i32 to %[[ELEM_LVALUE]] : <i32>
+ memref.store %v, %alloc[] : memref<i32>
+ return
+}
+
+// CHECK-LABEL: emitc.func private @memref_rank0_alloc_load() -> i32
+func.func private @memref_rank0_alloc_load() -> i32 {
+ // CHECK: %[[SIZEOF_I32:.*]] = call_opaque "sizeof"() <{args = [i32]}> : () -> !emitc.size_t
+ // CHECK: %[[NUM_ELEMS:.*]] = "emitc.constant"() <{value = 1 : index}> : () -> index
+ // CHECK: %[[TOTAL_BYTES:.*]] = mul %[[SIZEOF_I32]], %[[NUM_ELEMS]] : (!emitc.size_t, index) -> !emitc.size_t
+ // CHECK: %[[MALLOC_PTR:.*]] = call_opaque "malloc"(%[[TOTAL_BYTES]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+ // CHECK: %[[ELEM_PTR:.*]] = cast %[[MALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+ %alloc = memref.alloc() : memref<i32>
+ // CHECK: %[[ZERO:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
+ // CHECK: %[[ELEM_LVALUE:.*]] = subscript %[[ELEM_PTR]]{{\[}}%[[ZERO]]] : (!emitc.ptr<i32>, index) -> !emitc.lvalue<i32>
+ // CHECK: %[[LOADED_VAL:.*]] = load %[[ELEM_LVALUE]] : <i32>
+ %v = memref.load %alloc[] : memref<i32>
+ // CHECK: return %[[LOADED_VAL]] : i32
+ return %v : i32
+}
+
+// CHECK-LABEL: emitc.func @memref_rank0_load_store(
+// CHECK-SAME: %[[SRC:.*]]: !emitc.ptr<i32>,
+// CHECK-SAME: %[[DST:.*]]: !emitc.ptr<i32>)
+func.func @memref_rank0_load_store(%src: memref<i32>, %dst: memref<i32>) {
+ // CHECK: %[[LOAD_ZERO:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
+ // CHECK: %[[SRC_LVALUE:.*]] = subscript %[[SRC]]{{\[}}%[[LOAD_ZERO]]] : (!emitc.ptr<i32>, index) -> !emitc.lvalue<i32>
+ // CHECK: %[[VAL:.*]] = load %[[SRC_LVALUE]] : <i32>
+ %v = memref.load %src[] : memref<i32>
+ // CHECK: %[[STORE_ZERO:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
+ // CHECK: %[[DST_LVALUE:.*]] = subscript %[[DST]]{{\[}}%[[STORE_ZERO]]] : (!emitc.ptr<i32>, index) -> !emitc.lvalue<i32>
+ // CHECK: assign %[[VAL]] : i32 to %[[DST_LVALUE]] : <i32>
+ memref.store %v, %dst[] : memref<i32>
+ return
+}
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
index 04e6edd5b6981..de3741e83c01c 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
@@ -1,5 +1,5 @@
-// RUN: mlir-opt -convert-memref-to-emitc="lower-to-cpp=true" %s -split-input-file | FileCheck %s --check-prefixes=CPP,CHECK
-// RUN: mlir-opt -convert-memref-to-emitc="lower-to-cpp=false" %s -split-input-file | FileCheck %s --check-prefixes=NOCPP,CHECK
+// RUN: mlir-opt -convert-memref-to-emitc="lower-to-cpp=true" %s | FileCheck %s --check-prefixes=CPP,CHECK
+// RUN: mlir-opt -convert-memref-to-emitc="lower-to-cpp=false" %s | FileCheck %s --check-prefixes=NOCPP,CHECK
func.func @copying(%arg0 : memref<9x4x5x7xf32>, %arg1 : memref<9x4x5x7xf32>) {
memref.copy %arg0, %arg1 : memref<9x4x5x7xf32> to memref<9x4x5x7xf32>
@@ -28,3 +28,20 @@ func.func @copying(%arg0 : memref<9x4x5x7xf32>, %arg1 : memref<9x4x5x7xf32>) {
// CHECK: return
// CHECK: }
+func.func @copying_rank0(%arg0 : memref<i32>, %arg1 : memref<i32>) {
+ memref.copy %arg0, %arg1 : memref<i32> to memref<i32>
+ return
+}
+
+// CHECK-LABEL: func.func @copying_rank0(
+// CHECK-SAME: %[[ARG0:.*]]: memref<i32>,
+// CHECK-SAME: %[[ARG1:.*]]: memref<i32>) {
+// CHECK: %[[TARGET_CAST:.*]] = builtin.unrealized_conversion_cast %[[ARG1]] : memref<i32> to !emitc.ptr<i32>
+// CHECK: %[[SOURCE_CAST:.*]] = builtin.unrealized_conversion_cast %[[ARG0]] : memref<i32> to !emitc.ptr<i32>
+// CHECK: %[[ZERO:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
+// CHECK: %[[SOURCE_LVALUE:.*]] = emitc.subscript %[[SOURCE_CAST]]{{\[}}%[[ZERO]]] : (!emitc.ptr<i32>, index) -> !emitc.lvalue<i32>
+// CHECK: %[[VALUE:.*]] = emitc.load %[[SOURCE_LVALUE]] : <i32>
+// CHECK: %[[TARGET_LVALUE:.*]] = emitc.subscript %[[TARGET_CAST]]{{\[}}%[[ZERO]]] : (!emitc.ptr<i32>, index) -> !emitc.lvalue<i32>
+// CHECK: emitc.assign %[[VALUE]] : i32 to %[[TARGET_LVALUE]] : <i32>
+// CHECK: return
+// CHECK: }
More information about the Mlir-commits
mailing list