[Mlir-commits] [llvm] [mlir] [mlir][emitc] Ensure memref-to-emitc applies type converter to memref element types (PR #203742)

Jeremy Kun llvmlistbot at llvm.org
Sat Jun 13 21:18:22 PDT 2026


https://github.com/j2kun updated https://github.com/llvm/llvm-project/pull/203742

>From 4bc0f882a0c0d7269dc9811e2d9a5395d56c1050 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Sat, 13 Jun 2026 19:41:23 -0700
Subject: [PATCH 1/5] memref-to-emitc: convert element type in memref.alloc
 lowering

---
 mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 693ebc7bc3bd0..cfe4f8bc23b3f 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -186,7 +186,12 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
     }
 
     Type sizeTType = emitc::SizeTType::get(rewriter.getContext());
-    Type elementType = memrefType.getElementType();
+    Type elementType =
+        getTypeConverter()->convertType(memrefType.getElementType());
+    if (!elementType) {
+      return rewriter.notifyMatchFailure(
+          loc, "failed to convert memref element type");
+    }
     IndexType indexType = rewriter.getIndexType();
     emitc::CallOpaqueOp sizeofElementOp = emitc::CallOpaqueOp::create(
         rewriter, loc, sizeTType, rewriter.getStringAttr("sizeof"),

>From ce61e9eec95edfa8a38edfc2a927b4e5e7cfb4f6 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Sat, 13 Jun 2026 20:29:46 -0700
Subject: [PATCH 2/5] memref-to-emitc test with custom type conversion

---
 .../Conversion/ConvertToEmitC/memref.mlir     | 12 ++++++++++++
 mlir/test/lib/Dialect/Test/CMakeLists.txt     |  2 ++
 .../Dialect/Test/TestDialectInterfaces.cpp    | 19 +++++++++++++++++++
 .../mlir/test/BUILD.bazel                     |  2 ++
 4 files changed, 35 insertions(+)
 create mode 100644 mlir/test/Conversion/ConvertToEmitC/memref.mlir

diff --git a/mlir/test/Conversion/ConvertToEmitC/memref.mlir b/mlir/test/Conversion/ConvertToEmitC/memref.mlir
new file mode 100644
index 0000000000000..7e8993bdd0972
--- /dev/null
+++ b/mlir/test/Conversion/ConvertToEmitC/memref.mlir
@@ -0,0 +1,12 @@
+// RUN: mlir-opt -convert-to-emitc -split-input-file %s | FileCheck %s
+
+// CHECK-LABEL: emitc.func @test_memref_alloc()
+func.func @test_memref_alloc() {
+  // CHECK: %[[SIZEOF:.*]] = call_opaque "sizeof"() <{args = [!emitc.opaque<"TestElementT">]}> : () -> !emitc.size_t
+  // CHECK: %[[C10:.*]] = "emitc.constant"() <{value = 10 : index}> : () -> index
+  // CHECK: %[[BYTES:.*]] = mul %[[SIZEOF]], %[[C10]] : (!emitc.size_t, index) -> !emitc.size_t
+  // CHECK: %[[MALLOC:.*]] = call_opaque "malloc"(%[[BYTES]]) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+  // CHECK: %[[CAST:.*]] = cast %[[MALLOC]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.opaque<"TestElementT">>
+  %0 = memref.alloc() : memref<10x!test.memref_element>
+  return
+}
diff --git a/mlir/test/lib/Dialect/Test/CMakeLists.txt b/mlir/test/lib/Dialect/Test/CMakeLists.txt
index 9354a85d984c9..4c4721193322b 100644
--- a/mlir/test/lib/Dialect/Test/CMakeLists.txt
+++ b/mlir/test/lib/Dialect/Test/CMakeLists.txt
@@ -68,6 +68,7 @@ add_mlir_library(MLIRTestDialect
   MLIRTestOpsIncGen
   MLIRTestOpsSyntaxIncGen
   MLIRTestOpsShardGen
+  MLIRConvertToEmitCPatternInterfaceIncGen
   )
 mlir_target_link_libraries(MLIRTestDialect PUBLIC
   MLIRControlFlowInterfaces
@@ -77,6 +78,7 @@ mlir_target_link_libraries(MLIRTestDialect PUBLIC
   MLIRDestinationStyleOpInterface
   MLIRDialect
   MLIRDLTIDialect
+  MLIREmitCDialect
   MLIRFuncDialect
   MLIRFunctionInterfaces
   MLIRFuncTransforms
diff --git a/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp b/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
index 1c9dbe1640687..04d956cce2eea 100644
--- a/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
+++ b/mlir/test/lib/Dialect/Test/TestDialectInterfaces.cpp
@@ -8,9 +8,13 @@
 
 #include "TestDialect.h"
 #include "TestOps.h"
+#include "TestTypes.h"
+#include "mlir/Conversion/ConvertToEmitC/ToEmitCInterface.h"
 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
+#include "mlir/Dialect/EmitC/IR/EmitC.h"
 #include "mlir/Interfaces/FoldInterfaces.h"
 #include "mlir/Reducer/ReductionPatternInterface.h"
+#include "mlir/Transforms/DialectConversion.h"
 #include "mlir/Transforms/InliningUtils.h"
 
 using namespace mlir;
@@ -432,6 +436,20 @@ struct TestReductionPatternInterface : public DialectReductionPatternInterface {
   }
 };
 
+struct TestToEmitCDialectInterface : public ConvertToEmitCPatternInterface {
+  explicit TestToEmitCDialectInterface(Dialect *dialect)
+      : ConvertToEmitCPatternInterface(dialect) {}
+
+  void populateConvertToEmitCConversionPatterns(
+      ConversionTarget &target, TypeConverter &typeConverter,
+      RewritePatternSet &patterns,
+      ::std::optional<bool> lowerToCpp) const final {
+    typeConverter.addConversion([](test::TestMemRefElementTypeType type) {
+      return emitc::OpaqueType::get(type.getContext(), "TestElementT");
+    });
+  }
+};
+
 } // namespace
 
 void TestDialect::registerInterfaces() {
@@ -440,4 +458,5 @@ void TestDialect::registerInterfaces() {
 
   addInterfaces<TestDialectFoldInterface, TestInlinerInterface,
                 TestReductionPatternInterface, TestBytecodeDialectInterface>();
+  addInterface<TestToEmitCDialectInterface>();
 }
diff --git a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
index f00a4eee0c6b2..0a0d373def04b 100644
--- a/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
+++ b/utils/bazel/llvm-project-overlay/mlir/test/BUILD.bazel
@@ -401,12 +401,14 @@ cc_library(
         "//mlir:ControlFlowDialect",
         "//mlir:ControlFlowInterfaces",
         "//mlir:ControlFlowTransforms",
+        "//mlir:ConvertToEmitCInterface",
         "//mlir:DLTIDialect",
         "//mlir:DataLayoutInterfaces",
         "//mlir:DerivedAttributeOpInterface",
         "//mlir:DestinationStyleOpInterface",
         "//mlir:Dialect",
         "//mlir:DialectUtils",
+        "//mlir:EmitCDialect",
         "//mlir:FromLLVMIRTranslation",
         "//mlir:FuncDialect",
         "//mlir:FuncTransforms",

>From f6ce2290aec17818d09044d16269d1627b6c0e04 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Sat, 13 Jun 2026 21:08:50 -0700
Subject: [PATCH 3/5] memref-to-emitc: convert element type in
 calculateMemrefTotalSizeBytes

---
 .../MemRefToEmitC/MemRefToEmitC.cpp           | 31 ++++++++++++++-----
 1 file changed, 23 insertions(+), 8 deletions(-)

diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index cfe4f8bc23b3f..e29e9a19b149e 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -101,15 +101,22 @@ Type convertMemRefType(MemRefType opTy, const TypeConverter *typeConverter) {
   return resultTy;
 }
 
-static Value calculateMemrefTotalSizeBytes(Location loc, MemRefType memrefType,
-                                           OpBuilder &builder) {
+static FailureOr<Value>
+calculateMemrefTotalSizeBytes(Location loc, MemRefType memrefType,
+                              OpBuilder &builder,
+                              const TypeConverter *typeConverter) {
   assert(isMemRefTypeLegalForEmitC(memrefType) &&
          "incompatible memref type for EmitC conversion");
+
+  Type elementType = typeConverter->convertType(memrefType.getElementType());
+  if (!elementType) {
+    return failure();
+  }
   emitc::CallOpaqueOp elementSize = emitc::CallOpaqueOp::create(
       builder, loc, emitc::SizeTType::get(builder.getContext()),
       builder.getStringAttr("sizeof"), ValueRange{},
       ArrayAttr::get(builder.getContext(),
-                     {TypeAttr::get(memrefType.getElementType())}));
+                     {TypeAttr::get(elementType)}));
 
   IndexType indexType = builder.getIndexType();
   int64_t numElements = llvm::product_of(memrefType.getShape());
@@ -302,11 +309,19 @@ struct ConvertCopy final : public OpConversionPattern<memref::CopyOp> {
     emitc::AddressOfOp targetPtr =
         createPointerFromEmitcArray(loc, rewriter, targetArrayValue);
 
-    emitc::CallOpaqueOp memCpyCall = emitc::CallOpaqueOp::create(
-        rewriter, loc, TypeRange{}, "memcpy",
-        ValueRange{
-            targetPtr.getResult(), srcPtr.getResult(),
-            calculateMemrefTotalSizeBytes(loc, srcMemrefType, rewriter)});
+    FailureOr<Value> totalSizeOrFail = calculateMemrefTotalSizeBytes(
+        loc, srcMemrefType, rewriter, getTypeConverter());
+    if (failed(totalSizeOrFail)) {
+      return rewriter.notifyMatchFailure(
+          loc, "Failed to calculate total size of memref in bytes.");
+    }
+    emitc::CallOpaqueOp memCpyCall =
+        emitc::CallOpaqueOp::create(rewriter, loc, TypeRange{}, "memcpy",
+                                    ValueRange{
+                                        targetPtr.getResult(),
+                                        srcPtr.getResult(),
+                                        *totalSizeOrFail,
+                                    });
 
     rewriter.replaceOp(copyOp, memCpyCall.getResults());
 

>From 0b7f6a549578cfd47e2bccf45ea88376f128eee4 Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Sat, 13 Jun 2026 21:12:36 -0700
Subject: [PATCH 4/5] memref-to-emitc: use calculateMemrefTotalSizeBytes in
 ConvertAlloc

---
 .../MemRefToEmitC/MemRefToEmitC.cpp           | 20 ++++++-------------
 1 file changed, 6 insertions(+), 14 deletions(-)

diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index e29e9a19b149e..175b24baa55c1 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -200,21 +200,13 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
           loc, "failed to convert memref element type");
     }
     IndexType indexType = rewriter.getIndexType();
-    emitc::CallOpaqueOp sizeofElementOp = emitc::CallOpaqueOp::create(
-        rewriter, loc, sizeTType, rewriter.getStringAttr("sizeof"),
-        ValueRange{},
-        ArrayAttr::get(rewriter.getContext(), {TypeAttr::get(elementType)}));
-
-    int64_t numElements = 1;
-    for (int64_t dimSize : memrefType.getShape()) {
-      numElements *= dimSize;
+    FailureOr<Value> totalSizeOrFail = calculateMemrefTotalSizeBytes(
+        loc, memrefType, rewriter, getTypeConverter());
+    if (failed(totalSizeOrFail)) {
+      return rewriter.notifyMatchFailure(
+          loc, "Failed to calculate total size of memref in bytes.");
     }
-    Value numElementsValue = emitc::ConstantOp::create(
-        rewriter, loc, indexType, rewriter.getIndexAttr(numElements));
-
-    Value totalSizeBytes =
-        emitc::MulOp::create(rewriter, loc, sizeTType,
-                             sizeofElementOp.getResult(0), numElementsValue);
+    Value totalSizeBytes = *totalSizeOrFail;
 
     emitc::CallOpaqueOp allocCall;
     StringAttr allocFunctionName;

>From 5f93647993678b475eb0195cb8309f9e731fd68b Mon Sep 17 00:00:00 2001
From: Jeremy Kun <jkun at google.com>
Date: Sat, 13 Jun 2026 21:16:10 -0700
Subject: [PATCH 5/5] add a test for memref.copy

---
 .../Conversion/ConvertToEmitC/memref.mlir     | 20 +++++++++++++++++++
 1 file changed, 20 insertions(+)

diff --git a/mlir/test/Conversion/ConvertToEmitC/memref.mlir b/mlir/test/Conversion/ConvertToEmitC/memref.mlir
index 7e8993bdd0972..faee2a9ce5d01 100644
--- a/mlir/test/Conversion/ConvertToEmitC/memref.mlir
+++ b/mlir/test/Conversion/ConvertToEmitC/memref.mlir
@@ -10,3 +10,23 @@ func.func @test_memref_alloc() {
   %0 = memref.alloc() : memref<10x!test.memref_element>
   return
 }
+
+// -----
+
+// CHECK-LABEL:   emitc.func @test_memref_copy(
+// CHECK-SAME:      %[[ARG0:.*]]: !emitc.array<10x!emitc.opaque<"TestElementT">>,
+// CHECK-SAME:      %[[ARG1:.*]]: !emitc.array<10x!emitc.opaque<"TestElementT">>) {
+func.func @test_memref_copy(%arg0: memref<10x!test.memref_element>, %arg1: memref<10x!test.memref_element>) {
+  // CHECK:           %[[C0_0:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
+  // CHECK:           %[[SUB_0:.*]] = subscript %[[ARG0]][%[[C0_0]]] : (!emitc.array<10x!emitc.opaque<"TestElementT">>, index) -> !emitc.lvalue<!emitc.opaque<"TestElementT">>
+  // CHECK:           %[[ADDR_0:.*]] = address_of %[[SUB_0]] : !emitc.lvalue<!emitc.opaque<"TestElementT">>
+  // CHECK:           %[[C0_1:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> index
+  // CHECK:           %[[SUB_1:.*]] = subscript %[[ARG1]][%[[C0_1]]] : (!emitc.array<10x!emitc.opaque<"TestElementT">>, index) -> !emitc.lvalue<!emitc.opaque<"TestElementT">>
+  // CHECK:           %[[ADDR_1:.*]] = address_of %[[SUB_1]] : !emitc.lvalue<!emitc.opaque<"TestElementT">>
+  // CHECK:           %[[SIZEOF:.*]] = call_opaque "sizeof"() <{args = [!emitc.opaque<"TestElementT">]}> : () -> !emitc.size_t
+  // CHECK:           %[[C10:.*]] = "emitc.constant"() <{value = 10 : index}> : () -> index
+  // CHECK:           %[[BYTES:.*]] = mul %[[SIZEOF]], %[[C10]] : (!emitc.size_t, index) -> !emitc.size_t
+  // CHECK:           call_opaque "memcpy"(%[[ADDR_1]], %[[ADDR_0]], %[[BYTES]]) : (!emitc.ptr<!emitc.opaque<"TestElementT">>, !emitc.ptr<!emitc.opaque<"TestElementT">>, !emitc.size_t) -> ()
+  memref.copy %arg0, %arg1 : memref<10x!test.memref_element> to memref<10x!test.memref_element>
+  return
+}



More information about the Mlir-commits mailing list