[Mlir-commits] [mlir] [mlir][emitc] Add a common type converter (PR #203763)
Gil Rapaport
llvmlistbot at llvm.org
Sun Jun 14 04:40:02 PDT 2026
https://github.com/aniragil created https://github.com/llvm/llvm-project/pull/203763
MemRef type conversion is currently implemented as part of the memref dialect lowering pass, which means e.g. that func-to-emitc cannot lower functions taking MemRef types as arguments.
This patch refactors the existing type conversions in EmitC's lowering passes into a structure similar to the LLVM dialect by adding a common EmitC type converter and using it across dialect-specfic EmitC lowering passes and the generic convert-to-emitc pass.
Assisted-by: Copilot
>From ace890db79fc41d41428c660c1c27f81671fc79f Mon Sep 17 00:00:00 2001
From: Gil Rapaport <gil.rapaport at mobileye.com>
Date: Sun, 14 Jun 2026 13:33:49 +0300
Subject: [PATCH] [mlir][emitc] Add a common type converter
MemRef type conversion is currently implemented as part of the memref
dialect lowering pass, which means e.g. that func-to-emitc cannot lower
functions taking MemRef types as arguments.
This patch refactors the existing type conversions in EmitC's lowering
passes into a structure similar to the LLVM dialect by adding a common
EmitC type converter and using it across dialect-specfic EmitC lowering
passes and the generic convert-to-emitc pass.
Assisted-by: Copilot
---
.../Conversion/EmitCCommon/TypeConverter.h | 31 ++++++++++
.../Conversion/MemRefToEmitC/MemRefToEmitC.h | 2 -
.../Conversion/ArithToEmitC/ArithToEmitC.cpp | 3 +
.../ArithToEmitC/ArithToEmitCPass.cpp | 9 +--
.../Conversion/ArithToEmitC/CMakeLists.txt | 1 +
mlir/lib/Conversion/CMakeLists.txt | 1 +
.../Conversion/ConvertToEmitC/CMakeLists.txt | 1 +
.../ConvertToEmitC/ConvertToEmitCPass.cpp | 10 +---
.../lib/Conversion/EmitCCommon/CMakeLists.txt | 11 ++++
.../Conversion/EmitCCommon/TypeConverter.cpp | 58 +++++++++++++++++++
.../lib/Conversion/FuncToEmitC/CMakeLists.txt | 1 +
.../FuncToEmitC/FuncToEmitCPass.cpp | 9 +--
.../Conversion/MemRefToEmitC/CMakeLists.txt | 1 +
.../MemRefToEmitC/MemRefToEmitC.cpp | 29 ----------
.../MemRefToEmitC/MemRefToEmitCPass.cpp | 11 +---
mlir/lib/Conversion/SCFToEmitC/CMakeLists.txt | 1 +
mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp | 9 +--
.../Conversion/FuncToEmitC/func-to-emitc.mlir | 14 +++++
18 files changed, 133 insertions(+), 69 deletions(-)
create mode 100644 mlir/include/mlir/Conversion/EmitCCommon/TypeConverter.h
create mode 100644 mlir/lib/Conversion/EmitCCommon/CMakeLists.txt
create mode 100644 mlir/lib/Conversion/EmitCCommon/TypeConverter.cpp
diff --git a/mlir/include/mlir/Conversion/EmitCCommon/TypeConverter.h b/mlir/include/mlir/Conversion/EmitCCommon/TypeConverter.h
new file mode 100644
index 0000000000000..9db077d662846
--- /dev/null
+++ b/mlir/include/mlir/Conversion/EmitCCommon/TypeConverter.h
@@ -0,0 +1,31 @@
+//===- TypeConverter.h - Convert builtin to EmitC dialect types -*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// Provides a type converter configuration for converting common builtin types
+// to the EmitC dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef MLIR_CONVERSION_EMITCCOMMON_TYPECONVERTER_H
+#define MLIR_CONVERSION_EMITCCOMMON_TYPECONVERTER_H
+
+#include "mlir/Transforms/DialectConversion.h"
+
+namespace mlir {
+
+/// Conversion from common builtin types to the EmitC dialect.
+class EmitCTypeConverter : public TypeConverter {
+public:
+ using TypeConverter::convertType;
+
+ explicit EmitCTypeConverter(MLIRContext *ctx);
+};
+
+} // namespace mlir
+
+#endif // MLIR_CONVERSION_EMITCCOMMON_TYPECONVERTER_H
diff --git a/mlir/include/mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h b/mlir/include/mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h
index 64c9ce091dcd0..061cf842e28ae 100644
--- a/mlir/include/mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h
+++ b/mlir/include/mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h
@@ -22,8 +22,6 @@ class DialectRegistry;
class RewritePatternSet;
class TypeConverter;
-void populateMemRefToEmitCTypeConversion(TypeConverter &typeConverter);
-
void populateMemRefToEmitCConversionPatterns(RewritePatternSet &patterns,
const TypeConverter &converter);
diff --git a/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp b/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
index 5b074130925a4..91dde9018a288 100644
--- a/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
+++ b/mlir/lib/Conversion/ArithToEmitC/ArithToEmitC.cpp
@@ -59,6 +59,9 @@ class ArithConstantOpConversionPattern
matchAndRewrite(arith::ConstantOp arithConst,
arith::ConstantOp::Adaptor adaptor,
ConversionPatternRewriter &rewriter) const override {
+ if (isa<MemRefType>(arithConst.getType()))
+ return rewriter.notifyMatchFailure(arithConst,
+ "memref constants are not supported");
Type newTy = this->getTypeConverter()->convertType(arithConst.getType());
if (!newTy)
return rewriter.notifyMatchFailure(arithConst, "type conversion failed");
diff --git a/mlir/lib/Conversion/ArithToEmitC/ArithToEmitCPass.cpp b/mlir/lib/Conversion/ArithToEmitC/ArithToEmitCPass.cpp
index 5ab1627ec40f3..52e3eb78a6280 100644
--- a/mlir/lib/Conversion/ArithToEmitC/ArithToEmitCPass.cpp
+++ b/mlir/lib/Conversion/ArithToEmitC/ArithToEmitCPass.cpp
@@ -13,6 +13,7 @@
#include "mlir/Conversion/ArithToEmitC/ArithToEmitCPass.h"
+#include "mlir/Conversion/EmitCCommon/TypeConverter.h"
#include "mlir/Conversion/ArithToEmitC/ArithToEmitC.h"
#include "mlir/Dialect/Arith/IR/Arith.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
@@ -41,13 +42,7 @@ void ConvertArithToEmitC::runOnOperation() {
RewritePatternSet patterns(&getContext());
- TypeConverter typeConverter;
- // Fallback for other types.
- typeConverter.addConversion([](Type type) -> std::optional<Type> {
- if (!emitc::isSupportedEmitCType(type))
- return {};
- return type;
- });
+ EmitCTypeConverter typeConverter(&getContext());
populateArithToEmitCPatterns(typeConverter, patterns);
diff --git a/mlir/lib/Conversion/ArithToEmitC/CMakeLists.txt b/mlir/lib/Conversion/ArithToEmitC/CMakeLists.txt
index 730a4b341673d..46f9aacbb14e1 100644
--- a/mlir/lib/Conversion/ArithToEmitC/CMakeLists.txt
+++ b/mlir/lib/Conversion/ArithToEmitC/CMakeLists.txt
@@ -10,6 +10,7 @@ add_mlir_conversion_library(MLIRArithToEmitC
LINK_LIBS PUBLIC
MLIRArithDialect
+ MLIREmitCCommonConversion
MLIREmitCDialect
MLIREmitCTransforms
MLIRPass
diff --git a/mlir/lib/Conversion/CMakeLists.txt b/mlir/lib/Conversion/CMakeLists.txt
index f5e0bcf613e59..b43ed905505fa 100644
--- a/mlir/lib/Conversion/CMakeLists.txt
+++ b/mlir/lib/Conversion/CMakeLists.txt
@@ -21,6 +21,7 @@ add_subdirectory(ComplexToStandard)
add_subdirectory(ControlFlowToLLVM)
add_subdirectory(ControlFlowToSCF)
add_subdirectory(ControlFlowToSPIRV)
+add_subdirectory(EmitCCommon)
add_subdirectory(ConvertToEmitC)
add_subdirectory(ConvertToLLVM)
add_subdirectory(FuncToEmitC)
diff --git a/mlir/lib/Conversion/ConvertToEmitC/CMakeLists.txt b/mlir/lib/Conversion/ConvertToEmitC/CMakeLists.txt
index 014ab26345033..e893d5cd1d35e 100644
--- a/mlir/lib/Conversion/ConvertToEmitC/CMakeLists.txt
+++ b/mlir/lib/Conversion/ConvertToEmitC/CMakeLists.txt
@@ -10,6 +10,7 @@ add_mlir_conversion_library(MLIRConvertToEmitC
LINK_LIBS PUBLIC
MLIRArithToEmitC
+ MLIREmitCCommonConversion
MLIRFuncToEmitC
MLIRMemRefToEmitC
MLIRPass
diff --git a/mlir/lib/Conversion/ConvertToEmitC/ConvertToEmitCPass.cpp b/mlir/lib/Conversion/ConvertToEmitC/ConvertToEmitCPass.cpp
index 4f060eafa14cc..60419f33a8774 100644
--- a/mlir/lib/Conversion/ConvertToEmitC/ConvertToEmitCPass.cpp
+++ b/mlir/lib/Conversion/ConvertToEmitC/ConvertToEmitCPass.cpp
@@ -8,6 +8,7 @@
#include "mlir/Conversion/ConvertToEmitC/ConvertToEmitCPass.h"
+#include "mlir/Conversion/EmitCCommon/TypeConverter.h"
#include "mlir/Conversion/ConvertToEmitC/ToEmitCInterface.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
#include "mlir/Pass/Pass.h"
@@ -112,14 +113,7 @@ struct StaticConvertToEmitC : public ConvertToEmitCPassInterface {
/// Configure the conversion to EmitC at pass initialization.
LogicalResult initialize() final {
auto target = std::make_shared<ConversionTarget>(*context);
- auto typeConverter = std::make_shared<TypeConverter>();
-
- // Add fallback identity converison.
- typeConverter->addConversion([](Type type) -> std::optional<Type> {
- if (emitc::isSupportedEmitCType(type))
- return type;
- return std::nullopt;
- });
+ auto typeConverter = std::make_shared<EmitCTypeConverter>(context);
RewritePatternSet tempPatterns(context);
target->addLegalDialect<emitc::EmitCDialect>();
diff --git a/mlir/lib/Conversion/EmitCCommon/CMakeLists.txt b/mlir/lib/Conversion/EmitCCommon/CMakeLists.txt
new file mode 100644
index 0000000000000..a47f14bfda114
--- /dev/null
+++ b/mlir/lib/Conversion/EmitCCommon/CMakeLists.txt
@@ -0,0 +1,11 @@
+add_mlir_conversion_library(MLIREmitCCommonConversion
+ TypeConverter.cpp
+
+ ADDITIONAL_HEADER_DIRS
+ ${MLIR_MAIN_INCLUDE_DIR}/mlir/Conversion/EmitCCommon
+
+ LINK_LIBS PUBLIC
+ MLIREmitCDialect
+ MLIRIR
+ MLIRTransforms
+ )
diff --git a/mlir/lib/Conversion/EmitCCommon/TypeConverter.cpp b/mlir/lib/Conversion/EmitCCommon/TypeConverter.cpp
new file mode 100644
index 0000000000000..a65edcf8306b8
--- /dev/null
+++ b/mlir/lib/Conversion/EmitCCommon/TypeConverter.cpp
@@ -0,0 +1,58 @@
+//===- TypeConverter.cpp - Convert builtin to EmitC dialect types ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+
+#include "mlir/Conversion/EmitCCommon/TypeConverter.h"
+
+#include "mlir/Dialect/EmitC/IR/EmitC.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "llvm/ADT/STLExtras.h"
+
+using namespace mlir;
+
+namespace {
+
+static bool isMemRefTypeLegalForEmitC(MemRefType memRefType) {
+ return memRefType.hasStaticShape() && memRefType.getLayout().isIdentity() &&
+ memRefType.getRank() != 0 &&
+ !llvm::is_contained(memRefType.getShape(), 0);
+}
+
+static Value materializeAsUnrealizedCast(OpBuilder &builder, Type resultType,
+ ValueRange inputs, Location loc) {
+ if (inputs.size() != 1)
+ return Value();
+
+ return UnrealizedConversionCastOp::create(builder, loc, resultType, inputs)
+ .getResult(0);
+}
+
+} // namespace
+
+EmitCTypeConverter::EmitCTypeConverter(MLIRContext *ctx) {
+ (void)ctx;
+
+ addConversion([](Type type) -> std::optional<Type> {
+ if (!emitc::isSupportedEmitCType(type))
+ return {};
+ return type;
+ });
+
+ addConversion([&](MemRefType memRefType) -> std::optional<Type> {
+ if (!isMemRefTypeLegalForEmitC(memRefType))
+ return {};
+
+ Type convertedElementType = convertType(memRefType.getElementType());
+ if (!convertedElementType)
+ return {};
+
+ return emitc::ArrayType::get(memRefType.getShape(), convertedElementType);
+ });
+
+ addSourceMaterialization(materializeAsUnrealizedCast);
+ addTargetMaterialization(materializeAsUnrealizedCast);
+}
diff --git a/mlir/lib/Conversion/FuncToEmitC/CMakeLists.txt b/mlir/lib/Conversion/FuncToEmitC/CMakeLists.txt
index 97752205bbcb4..c5d831f59379d 100644
--- a/mlir/lib/Conversion/FuncToEmitC/CMakeLists.txt
+++ b/mlir/lib/Conversion/FuncToEmitC/CMakeLists.txt
@@ -9,6 +9,7 @@ add_mlir_conversion_library(MLIRFuncToEmitC
MLIRConversionPassIncGen
LINK_LIBS PUBLIC
+ MLIREmitCCommonConversion
MLIREmitCDialect
MLIRFuncDialect
MLIRPass
diff --git a/mlir/lib/Conversion/FuncToEmitC/FuncToEmitCPass.cpp b/mlir/lib/Conversion/FuncToEmitC/FuncToEmitCPass.cpp
index 01129f3e4c5cd..d7052ad9837c1 100644
--- a/mlir/lib/Conversion/FuncToEmitC/FuncToEmitCPass.cpp
+++ b/mlir/lib/Conversion/FuncToEmitC/FuncToEmitCPass.cpp
@@ -12,6 +12,7 @@
#include "mlir/Conversion/FuncToEmitC/FuncToEmitCPass.h"
+#include "mlir/Conversion/EmitCCommon/TypeConverter.h"
#include "mlir/Conversion/FuncToEmitC/FuncToEmitC.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
#include "mlir/Dialect/Func/IR/FuncOps.h"
@@ -41,13 +42,7 @@ void ConvertFuncToEmitC::runOnOperation() {
RewritePatternSet patterns(&getContext());
- TypeConverter typeConverter;
- // Fallback for other types.
- typeConverter.addConversion([](Type type) -> std::optional<Type> {
- if (!emitc::isSupportedEmitCType(type))
- return {};
- return type;
- });
+ EmitCTypeConverter typeConverter(&getContext());
populateFuncToEmitCPatterns(typeConverter, patterns, this->lowerToCpp);
diff --git a/mlir/lib/Conversion/MemRefToEmitC/CMakeLists.txt b/mlir/lib/Conversion/MemRefToEmitC/CMakeLists.txt
index 8a72e747d024a..23a40e7e48b8d 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/CMakeLists.txt
+++ b/mlir/lib/Conversion/MemRefToEmitC/CMakeLists.txt
@@ -12,6 +12,7 @@ add_mlir_conversion_library(MLIRMemRefToEmitC
Core
LINK_LIBS PUBLIC
+ MLIREmitCCommonConversion
MLIREmitCDialect
MLIRMemRefDialect
MLIRTransforms
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 693ebc7bc3bd0..3e55f572d1418 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -45,7 +45,6 @@ struct MemRefToEmitCDialectInterface : public ConvertToEmitCPatternInterface {
void populateConvertToEmitCConversionPatterns(
ConversionTarget &target, TypeConverter &typeConverter,
RewritePatternSet &patterns, std::optional<bool> lowerToCpp) const final {
- populateMemRefToEmitCTypeConversion(typeConverter);
populateMemRefToEmitCConversionPatterns(patterns, typeConverter);
}
};
@@ -473,34 +472,6 @@ struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
} // namespace
-void mlir::populateMemRefToEmitCTypeConversion(TypeConverter &typeConverter) {
- typeConverter.addConversion(
- [&](MemRefType memRefType) -> std::optional<Type> {
- if (!isMemRefTypeLegalForEmitC(memRefType)) {
- return {};
- }
- Type convertedElementType =
- typeConverter.convertType(memRefType.getElementType());
- if (!convertedElementType)
- return {};
- return emitc::ArrayType::get(memRefType.getShape(),
- convertedElementType);
- });
-
- auto materializeAsUnrealizedCast = [](OpBuilder &builder, Type resultType,
- ValueRange inputs,
- Location loc) -> Value {
- if (inputs.size() != 1)
- return Value();
-
- return UnrealizedConversionCastOp::create(builder, loc, resultType, inputs)
- .getResult(0);
- };
-
- typeConverter.addSourceMaterialization(materializeAsUnrealizedCast);
- typeConverter.addTargetMaterialization(materializeAsUnrealizedCast);
-}
-
void mlir::populateMemRefToEmitCConversionPatterns(
RewritePatternSet &patterns, const TypeConverter &converter) {
patterns.add<ConvertAlloca, ConvertAlloc, ConvertCopy, ConvertDealloc,
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
index 29974c213fcfb..6a3e096ac5a18 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
@@ -12,6 +12,7 @@
#include "mlir/Conversion/MemRefToEmitC/MemRefToEmitCPass.h"
+#include "mlir/Conversion/EmitCCommon/TypeConverter.h"
#include "mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
@@ -42,17 +43,9 @@ struct ConvertMemRefToEmitCPass
: public impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass> {
using Base::Base;
void runOnOperation() override {
- TypeConverter converter;
+ EmitCTypeConverter converter(&getContext());
ConvertMemRefToEmitCOptions options;
options.lowerToCpp = this->lowerToCpp;
- // Fallback for other types.
- converter.addConversion([](Type type) -> std::optional<Type> {
- if (!emitc::isSupportedEmitCType(type))
- return {};
- return type;
- });
-
- populateMemRefToEmitCTypeConversion(converter);
RewritePatternSet patterns(&getContext());
populateMemRefToEmitCConversionPatterns(patterns, converter);
diff --git a/mlir/lib/Conversion/SCFToEmitC/CMakeLists.txt b/mlir/lib/Conversion/SCFToEmitC/CMakeLists.txt
index af5493be8a4b3..453aa6c44c467 100644
--- a/mlir/lib/Conversion/SCFToEmitC/CMakeLists.txt
+++ b/mlir/lib/Conversion/SCFToEmitC/CMakeLists.txt
@@ -12,6 +12,7 @@ add_mlir_conversion_library(MLIRSCFToEmitC
LINK_LIBS PUBLIC
MLIRArithDialect
+ MLIREmitCCommonConversion
MLIREmitCDialect
MLIREmitCTransforms
MLIRSCFDialect
diff --git a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp
index b4616e23a7066..b3c0b18698466 100644
--- a/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp
+++ b/mlir/lib/Conversion/SCFToEmitC/SCFToEmitC.cpp
@@ -12,6 +12,7 @@
#include "mlir/Conversion/SCFToEmitC/SCFToEmitC.h"
+#include "mlir/Conversion/EmitCCommon/TypeConverter.h"
#include "mlir/Conversion/ConvertToEmitC/ToEmitCInterface.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
#include "mlir/Dialect/EmitC/Transforms/TypeConversions.h"
@@ -519,13 +520,7 @@ void mlir::populateSCFToEmitCConversionPatterns(RewritePatternSet &patterns,
void SCFToEmitCPass::runOnOperation() {
RewritePatternSet patterns(&getContext());
- TypeConverter typeConverter;
- // Fallback for other types.
- typeConverter.addConversion([](Type type) -> std::optional<Type> {
- if (!emitc::isSupportedEmitCType(type))
- return {};
- return type;
- });
+ EmitCTypeConverter typeConverter(&getContext());
populateEmitCSizeTTypeConversions(typeConverter);
populateSCFToEmitCConversionPatterns(patterns, typeConverter);
diff --git a/mlir/test/Conversion/FuncToEmitC/func-to-emitc.mlir b/mlir/test/Conversion/FuncToEmitC/func-to-emitc.mlir
index 1a2a8e764e22d..65734da279d63 100644
--- a/mlir/test/Conversion/FuncToEmitC/func-to-emitc.mlir
+++ b/mlir/test/Conversion/FuncToEmitC/func-to-emitc.mlir
@@ -169,3 +169,17 @@ func.func @first(%arg0: i32) -> (i32, i32) {
func.func @second(%arg0: i32) -> (i32, i32) {
return %arg0, %arg0 : i32, i32
}
+
+// -----
+
+// CHECK-LABEL: emitc.func private @memref_callee(!emitc.array<4x8xf32>)
+func.func private @memref_callee(%buff : memref<4x8xf32>)
+
+// CHECK-LABEL: emitc.func @memref_call(
+// CHECK-SAME: %[[ARG0:.*]]: !emitc.array<4x8xf32>)
+// CHECK-NEXT: call @memref_callee(%[[ARG0]]) : (!emitc.array<4x8xf32>) -> ()
+// CHECK-NEXT: return
+func.func @memref_call(%buff : memref<4x8xf32>) {
+ func.call @memref_callee(%buff) : (memref<4x8xf32>) -> ()
+ return
+}
More information about the Mlir-commits
mailing list