[Mlir-commits] [mlir] [mlir][EmitC]Expand the MemRefToEmitC pass - Lowering `AllocOp` (PR #148257)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Jul 25 11:01:34 PDT 2025
https://github.com/ajaden-codes updated https://github.com/llvm/llvm-project/pull/148257
>From b62e8f9ac11a7e4d2dd70ab32258e58ac58e37bf Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Fri, 11 Jul 2025 00:23:11 +0000
Subject: [PATCH 01/11] allocop to emitc malloc
---
.../MemRefToEmitC/MemRefToEmitC.cpp | 36 +++++++++++++++++--
.../MemRefToEmitC/memref-to-emitc.mlir | 8 +++++
2 files changed, 42 insertions(+), 2 deletions(-)
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index db244d1d1cac8..382affaff429f 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -77,6 +77,38 @@ struct ConvertAlloca final : public OpConversionPattern<memref::AllocaOp> {
}
};
+struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
+ using OpConversionPattern::OpConversionPattern;
+ LogicalResult
+ matchAndRewrite(memref::AllocOp allocOp, OpAdaptor operands,
+ ConversionPatternRewriter &rewriter) const override {
+ mlir::Location loc = allocOp.getLoc();
+ auto memrefType = allocOp.getType();
+ if (!memrefType.hasStaticShape())
+ return rewriter.notifyMatchFailure(
+ allocOp.getLoc(), "cannot transform alloc op with dynamic shape");
+
+ int64_t totalSize =
+ memrefType.getNumElements() * memrefType.getElementTypeBitWidth() / 8;
+ auto alignment = allocOp.getAlignment();
+ if (alignment) {
+ int64_t alignVal = alignment.value();
+ totalSize = (totalSize + alignVal - 1) / alignVal * alignVal;
+ }
+ mlir::Value sizeBytes = rewriter.create<emitc::ConstantOp>(
+ loc, rewriter.getIndexType(),
+ rewriter.getIntegerAttr(rewriter.getIndexType(), totalSize));
+ auto mallocPtrType = emitc::PointerType::get(rewriter.getContext(),
+ memrefType.getElementType());
+ auto mallocCall = rewriter.create<emitc::CallOpaqueOp>(
+ loc, mallocPtrType, rewriter.getStringAttr("malloc"),
+ mlir::ValueRange{sizeBytes});
+
+ rewriter.replaceOp(allocOp, mallocCall);
+ return success();
+ }
+};
+
struct ConvertGlobal final : public OpConversionPattern<memref::GlobalOp> {
using OpConversionPattern::OpConversionPattern;
@@ -222,6 +254,6 @@ void mlir::populateMemRefToEmitCTypeConversion(TypeConverter &typeConverter) {
void mlir::populateMemRefToEmitCConversionPatterns(
RewritePatternSet &patterns, const TypeConverter &converter) {
- patterns.add<ConvertAlloca, ConvertGlobal, ConvertGetGlobal, ConvertLoad,
- ConvertStore>(converter, patterns.getContext());
+ patterns.add<ConvertAlloca, ConvertAlloc, ConvertGlobal, ConvertGetGlobal,
+ ConvertLoad, ConvertStore>(converter, patterns.getContext());
}
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
index d37fd1de90add..23e1c20670f8c 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
@@ -8,6 +8,14 @@ func.func @alloca() {
return
}
+// CHECK-LABEL: alloc()
+func.func @alloc() {
+ // CHECK-NEXT: %0 = "emitc.constant"() <{value = 3996 : index}> : () -> index
+ // CHECK-NEXT: %1 = emitc.call_opaque "malloc"(%0) : (index) -> !emitc.ptr<i32>
+ %alloc = memref.alloc() : memref<999xi32>
+ return
+}
+
// -----
// CHECK-LABEL: memref_store
>From a36e0a3e1dbc4d746073d82d1bf868b1e3403284 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Mon, 14 Jul 2025 20:24:46 +0000
Subject: [PATCH 02/11] Specific TODOs
---
mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp | 13 +++++++++----
1 file changed, 9 insertions(+), 4 deletions(-)
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 382affaff429f..ee6b7d89a76a6 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -85,13 +85,18 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
mlir::Location loc = allocOp.getLoc();
auto memrefType = allocOp.getType();
if (!memrefType.hasStaticShape())
+ // TODO: Handle Dynamic shapes in the future. If the size
+ // of the allocation is the result of some function, we could
+ // potentially evaluate the function and use the result in the call to
+ // allocate.
return rewriter.notifyMatchFailure(
allocOp.getLoc(), "cannot transform alloc op with dynamic shape");
- int64_t totalSize =
- memrefType.getNumElements() * memrefType.getElementTypeBitWidth() / 8;
- auto alignment = allocOp.getAlignment();
- if (alignment) {
+ // TODO: Is there a better API to determine the number of bits in a byte in
+ // MLIR?
+ int64_t totalSize = memrefType.getNumElements() *
+ memrefType.getElementTypeBitWidth() / CHAR_BIT;
+ if (auto alignment = allocOp.getAlignment()) {
int64_t alignVal = alignment.value();
totalSize = (totalSize + alignVal - 1) / alignVal * alignVal;
}
>From 69e5a982e826af1eb7dc12a49d0ff7902d3ea732 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Fri, 18 Jul 2025 05:14:35 +0000
Subject: [PATCH 03/11] Add the size computations to emitc output
---
mlir/include/mlir/Conversion/Passes.td | 2 +-
.../MemRefToEmitC/MemRefToEmitC.cpp | 74 ++++++++++++++-----
.../MemRefToEmitC/MemRefToEmitCPass.cpp | 10 +++
.../MemRefToEmitC/memref-to-emitc.mlir | 8 +-
4 files changed, 72 insertions(+), 22 deletions(-)
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index 76e751243a12c..4660758f35b04 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -841,7 +841,7 @@ def ConvertMathToFuncs : Pass<"convert-math-to-funcs", "ModuleOp"> {
// MemRefToEmitC
//===----------------------------------------------------------------------===//
-def ConvertMemRefToEmitC : Pass<"convert-memref-to-emitc"> {
+def ConvertMemRefToEmitC : Pass<"convert-memref-to-emitc", "ModuleOp"> {
let summary = "Convert MemRef dialect to EmitC dialect";
let dependentDialects = ["emitc::EmitCDialect"];
}
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index ee6b7d89a76a6..d8ceb4b205a55 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -16,6 +16,7 @@
#include "mlir/Dialect/EmitC/IR/EmitC.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/Transforms/DialectConversion.h"
@@ -84,34 +85,69 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
ConversionPatternRewriter &rewriter) const override {
mlir::Location loc = allocOp.getLoc();
auto memrefType = allocOp.getType();
- if (!memrefType.hasStaticShape())
+ if (!memrefType.hasStaticShape()) {
// TODO: Handle Dynamic shapes in the future. If the size
// of the allocation is the result of some function, we could
// potentially evaluate the function and use the result in the call to
// allocate.
return rewriter.notifyMatchFailure(
- allocOp.getLoc(), "cannot transform alloc op with dynamic shape");
-
- // TODO: Is there a better API to determine the number of bits in a byte in
- // MLIR?
- int64_t totalSize = memrefType.getNumElements() *
- memrefType.getElementTypeBitWidth() / CHAR_BIT;
- if (auto alignment = allocOp.getAlignment()) {
- int64_t alignVal = alignment.value();
- totalSize = (totalSize + alignVal - 1) / alignVal * alignVal;
+ loc, "cannot transform alloc with dynamic shape");
}
- mlir::Value sizeBytes = rewriter.create<emitc::ConstantOp>(
- loc, rewriter.getIndexType(),
- rewriter.getIntegerAttr(rewriter.getIndexType(), totalSize));
- auto mallocPtrType = emitc::PointerType::get(rewriter.getContext(),
- memrefType.getElementType());
- auto mallocCall = rewriter.create<emitc::CallOpaqueOp>(
- loc, mallocPtrType, rewriter.getStringAttr("malloc"),
- mlir::ValueRange{sizeBytes});
- rewriter.replaceOp(allocOp, mallocCall);
+ Type elementType = memrefType.getElementType();
+ mlir::Value elementTypeLiteral = rewriter.create<emitc::LiteralOp>(
+ loc, mlir::emitc::OpaqueType::get(rewriter.getContext(), "type"),
+ rewriter.getStringAttr(getCTypeName(elementType)));
+ emitc::CallOpaqueOp sizeofElementOp = rewriter.create<emitc::CallOpaqueOp>(
+ loc, mlir::emitc::SizeTType::get(rewriter.getContext()),
+ rewriter.getStringAttr("sizeof"), mlir::ValueRange{elementTypeLiteral});
+ mlir::Value sizeofElement = sizeofElementOp.getResult(0);
+
+ unsigned int elementWidth = elementType.getIntOrFloatBitWidth();
+ mlir::Value numElements;
+ if (elementType.isF32())
+ numElements = rewriter.create<emitc::ConstantOp>(
+ loc, elementType, rewriter.getFloatAttr(elementType, elementWidth));
+ else
+ numElements = rewriter.create<emitc::ConstantOp>(
+ loc, elementType, rewriter.getIntegerAttr(elementType, elementWidth));
+ mlir::Value totalSizeBytes = rewriter.create<emitc::MulOp>(
+ loc, mlir::emitc::SizeTType::get(rewriter.getContext()), sizeofElement,
+ numElements);
+
+ auto mallocCall = rewriter.create<emitc::CallOpaqueOp>(
+ loc,
+ emitc::PointerType::get(
+ rewriter.getContext(),
+ mlir::emitc::OpaqueType::get(rewriter.getContext(), "void")),
+ rewriter.getStringAttr("malloc"), mlir::ValueRange{totalSizeBytes});
+ auto targetPointerType =
+ emitc::PointerType::get(rewriter.getContext(), elementType);
+ auto castOp = rewriter.create<emitc::CastOp>(loc, targetPointerType,
+ mallocCall.getResult(0));
+
+ rewriter.replaceOp(allocOp, castOp);
return success();
}
+
+private:
+ std::string getCTypeName(mlir::Type type) const {
+ if (type.isF32())
+ return "float";
+ if (type.isF64())
+ return "double";
+ if (type.isInteger(8))
+ return "int8_t";
+ if (type.isInteger(16))
+ return "int16_t";
+ if (type.isInteger(32))
+ return "int32_t";
+ if (type.isInteger(64))
+ return "int64_t";
+ if (type.isIndex())
+ return "size_t";
+ return "void";
+ }
};
struct ConvertGlobal final : public OpConversionPattern<memref::GlobalOp> {
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
index cf25c09a2c2f3..d7544007718eb 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
@@ -30,6 +30,16 @@ struct ConvertMemRefToEmitCPass
: public impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass> {
void runOnOperation() override {
TypeConverter converter;
+ mlir::ModuleOp module = getOperation();
+ module.walk([&](mlir::Operation *op) {
+ if (llvm::isa<mlir::memref::AllocOp, mlir::memref::CopyOp>(op)) {
+ OpBuilder builder(module.getBody(), module.getBody()->begin());
+ builder.create<emitc::IncludeOp>(module.getLoc(),
+ builder.getStringAttr("stdlib.h"));
+ return mlir::WalkResult::interrupt();
+ }
+ return mlir::WalkResult::advance();
+ });
// Fallback for other types.
converter.addConversion([](Type type) -> std::optional<Type> {
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
index 23e1c20670f8c..ad401c1a604ef 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
@@ -10,8 +10,12 @@ func.func @alloca() {
// CHECK-LABEL: alloc()
func.func @alloc() {
- // CHECK-NEXT: %0 = "emitc.constant"() <{value = 3996 : index}> : () -> index
- // CHECK-NEXT: %1 = emitc.call_opaque "malloc"(%0) : (index) -> !emitc.ptr<i32>
+ // CHECK-NEXT: %0 = emitc.literal "int32_t" : !emitc.opaque<"type">
+ // CHECK-NEXT: %1 = emitc.call_opaque "sizeof"(%0) : (!emitc.opaque<"type">) -> !emitc.size_t
+ // CHECK-NEXT: %2 = "emitc.constant"() <{value = 32 : i32}> : () -> i32
+ // CHECK-NEXT: %3 = emitc.mul %1, %2 : (!emitc.size_t, i32) -> !emitc.size_t
+ // CHECK-NEXT: %4 = emitc.call_opaque "malloc"(%3) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+ // CHECK-NEXT: %5 = emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
%alloc = memref.alloc() : memref<999xi32>
return
}
>From f9d450e8d8c0bc0d376a942eab5d66c0376fdfac Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Mon, 21 Jul 2025 23:06:43 +0000
Subject: [PATCH 04/11] Remove unneeded context
---
.../MemRefToEmitC/MemRefToEmitC.cpp | 70 +++++++++++++------
.../MemRefToEmitC/memref-to-emitc.mlir | 11 ++-
2 files changed, 52 insertions(+), 29 deletions(-)
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index d8ceb4b205a55..14e13f22f072f 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -18,6 +18,7 @@
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/Value.h"
#include "mlir/Transforms/DialectConversion.h"
using namespace mlir;
@@ -95,22 +96,20 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
}
Type elementType = memrefType.getElementType();
- mlir::Value elementTypeLiteral = rewriter.create<emitc::LiteralOp>(
- loc, mlir::emitc::OpaqueType::get(rewriter.getContext(), "type"),
- rewriter.getStringAttr(getCTypeName(elementType)));
- emitc::CallOpaqueOp sizeofElementOp = rewriter.create<emitc::CallOpaqueOp>(
- loc, mlir::emitc::SizeTType::get(rewriter.getContext()),
- rewriter.getStringAttr("sizeof"), mlir::ValueRange{elementTypeLiteral});
+ mlir::emitc::CallOpaqueOp sizeofElementOp =
+ rewriter.create<mlir::emitc::CallOpaqueOp>(
+ loc, mlir::emitc::SizeTType::get(rewriter.getContext()),
+ rewriter.getStringAttr("sizeof"), mlir::ValueRange{},
+ mlir::ArrayAttr::get(rewriter.getContext(),
+ {mlir::TypeAttr::get(elementType)}));
mlir::Value sizeofElement = sizeofElementOp.getResult(0);
unsigned int elementWidth = elementType.getIntOrFloatBitWidth();
+ auto indexAttr = rewriter.getIndexAttr(elementWidth);
+
mlir::Value numElements;
- if (elementType.isF32())
- numElements = rewriter.create<emitc::ConstantOp>(
- loc, elementType, rewriter.getFloatAttr(elementType, elementWidth));
- else
- numElements = rewriter.create<emitc::ConstantOp>(
- loc, elementType, rewriter.getIntegerAttr(elementType, elementWidth));
+ numElements = rewriter.create<emitc::ConstantOp>(
+ loc, rewriter.getIndexType(), indexAttr);
mlir::Value totalSizeBytes = rewriter.create<emitc::MulOp>(
loc, mlir::emitc::SizeTType::get(rewriter.getContext()), sizeofElement,
numElements);
@@ -118,11 +117,9 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
auto mallocCall = rewriter.create<emitc::CallOpaqueOp>(
loc,
emitc::PointerType::get(
- rewriter.getContext(),
mlir::emitc::OpaqueType::get(rewriter.getContext(), "void")),
rewriter.getStringAttr("malloc"), mlir::ValueRange{totalSizeBytes});
- auto targetPointerType =
- emitc::PointerType::get(rewriter.getContext(), elementType);
+ auto targetPointerType = emitc::PointerType::get(elementType);
auto castOp = rewriter.create<emitc::CastOp>(loc, targetPointerType,
mallocCall.getResult(0));
@@ -136,14 +133,41 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
return "float";
if (type.isF64())
return "double";
- if (type.isInteger(8))
- return "int8_t";
- if (type.isInteger(16))
- return "int16_t";
- if (type.isInteger(32))
- return "int32_t";
- if (type.isInteger(64))
- return "int64_t";
+ if (auto integerType = mlir::dyn_cast<mlir::IntegerType>(type)) {
+ unsigned width = integerType.getWidth();
+ bool isSigned = integerType.isSigned();
+ if (isSigned) {
+ switch (width) {
+ case 8:
+ return "int8_t";
+ case 16:
+ return "int16_t";
+ case 32:
+ return "int32_t";
+ case 64:
+ return "int64_t";
+ case 128:
+ return "int128_t";
+ default:
+ return "unsupported_signed_integer_type";
+ }
+ } else {
+ switch (width) {
+ case 8:
+ return "uint8_t";
+ case 16:
+ return "uint16_t";
+ case 32:
+ return "uint32_t";
+ case 64:
+ return "uint64_t";
+ case 128:
+ return "uint128_t";
+ default:
+ return "unsupported_unsigned_integer_type";
+ }
+ }
+ }
if (type.isIndex())
return "size_t";
return "void";
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
index ad401c1a604ef..60cf47330169d 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
@@ -10,12 +10,11 @@ func.func @alloca() {
// CHECK-LABEL: alloc()
func.func @alloc() {
- // CHECK-NEXT: %0 = emitc.literal "int32_t" : !emitc.opaque<"type">
- // CHECK-NEXT: %1 = emitc.call_opaque "sizeof"(%0) : (!emitc.opaque<"type">) -> !emitc.size_t
- // CHECK-NEXT: %2 = "emitc.constant"() <{value = 32 : i32}> : () -> i32
- // CHECK-NEXT: %3 = emitc.mul %1, %2 : (!emitc.size_t, i32) -> !emitc.size_t
- // CHECK-NEXT: %4 = emitc.call_opaque "malloc"(%3) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
- // CHECK-NEXT: %5 = emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+ // CHECK-NEXT: %0 = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+ // CHECK-NEXT: %1 = "emitc.constant"() <{value = 32 : index}> : () -> index
+ // CHECK-NEXT: %2 = emitc.mul %0, %1 : (!emitc.size_t, index) -> !emitc.size_t
+ // CHECK-NEXT: %3 = emitc.call_opaque "malloc"(%2) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+ // CHECK-NEXT: %4 = emitc.cast %3 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
%alloc = memref.alloc() : memref<999xi32>
return
}
>From 13d5375ec072e1d134aee3d9f87cc62a255b5954 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Tue, 22 Jul 2025 21:53:28 +0000
Subject: [PATCH 05/11] Check for alignment
---
mlir/include/mlir/Conversion/Passes.td | 4 +
.../MemRefToEmitC/MemRefToEmitC.cpp | 92 ++++++++-----------
.../MemRefToEmitC/MemRefToEmitCPass.cpp | 44 ++++++---
.../MemRefToEmitC/memref-to-emitc-alloc.mlir | 17 ++++
.../MemRefToEmitC/memref-to-emitc.mlir | 11 ---
5 files changed, 91 insertions(+), 77 deletions(-)
create mode 100644 mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
diff --git a/mlir/include/mlir/Conversion/Passes.td b/mlir/include/mlir/Conversion/Passes.td
index 4660758f35b04..36567c62808dc 100644
--- a/mlir/include/mlir/Conversion/Passes.td
+++ b/mlir/include/mlir/Conversion/Passes.td
@@ -844,6 +844,10 @@ def ConvertMathToFuncs : Pass<"convert-math-to-funcs", "ModuleOp"> {
def ConvertMemRefToEmitC : Pass<"convert-memref-to-emitc", "ModuleOp"> {
let summary = "Convert MemRef dialect to EmitC dialect";
let dependentDialects = ["emitc::EmitCDialect"];
+ let options = [Option<
+ "lowerToCpp", "lower-to-cpp", "bool",
+ /*default=*/"false",
+ /*description=*/"Target C++ (true) instead of C (false)">];
}
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 14e13f22f072f..ffb456f743618 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -17,9 +17,11 @@
#include "mlir/Dialect/MemRef/IR/MemRef.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/PatternMatch.h"
#include "mlir/IR/Value.h"
#include "mlir/Transforms/DialectConversion.h"
+#include <cstdint>
using namespace mlir;
@@ -85,7 +87,7 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
matchAndRewrite(memref::AllocOp allocOp, OpAdaptor operands,
ConversionPatternRewriter &rewriter) const override {
mlir::Location loc = allocOp.getLoc();
- auto memrefType = allocOp.getType();
+ MemRefType memrefType = allocOp.getType();
if (!memrefType.hasStaticShape()) {
// TODO: Handle Dynamic shapes in the future. If the size
// of the allocation is the result of some function, we could
@@ -95,82 +97,62 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
loc, "cannot transform alloc with dynamic shape");
}
+ mlir::Type sizeTType = mlir::emitc::SizeTType::get(rewriter.getContext());
Type elementType = memrefType.getElementType();
mlir::emitc::CallOpaqueOp sizeofElementOp =
rewriter.create<mlir::emitc::CallOpaqueOp>(
- loc, mlir::emitc::SizeTType::get(rewriter.getContext()),
- rewriter.getStringAttr("sizeof"), mlir::ValueRange{},
+ loc, sizeTType, rewriter.getStringAttr("sizeof"),
+ mlir::ValueRange{},
mlir::ArrayAttr::get(rewriter.getContext(),
{mlir::TypeAttr::get(elementType)}));
mlir::Value sizeofElement = sizeofElementOp.getResult(0);
unsigned int elementWidth = elementType.getIntOrFloatBitWidth();
- auto indexAttr = rewriter.getIndexAttr(elementWidth);
+ IntegerAttr indexAttr = rewriter.getIndexAttr(elementWidth);
mlir::Value numElements;
numElements = rewriter.create<emitc::ConstantOp>(
loc, rewriter.getIndexType(), indexAttr);
mlir::Value totalSizeBytes = rewriter.create<emitc::MulOp>(
- loc, mlir::emitc::SizeTType::get(rewriter.getContext()), sizeofElement,
- numElements);
+ loc, sizeTType, sizeofElement, numElements);
- auto mallocCall = rewriter.create<emitc::CallOpaqueOp>(
+ int64_t alignment = alignedAllocationGetAlignment(allocOp, elementWidth);
+ mlir::Value alignmentValue = rewriter.create<emitc::ConstantOp>(
+ loc, sizeTType,
+ rewriter.getIntegerAttr(rewriter.getIndexType(), alignment));
+
+ emitc::CallOpaqueOp alignedAllocCall = rewriter.create<emitc::CallOpaqueOp>(
loc,
emitc::PointerType::get(
mlir::emitc::OpaqueType::get(rewriter.getContext(), "void")),
- rewriter.getStringAttr("malloc"), mlir::ValueRange{totalSizeBytes});
- auto targetPointerType = emitc::PointerType::get(elementType);
- auto castOp = rewriter.create<emitc::CastOp>(loc, targetPointerType,
- mallocCall.getResult(0));
+ rewriter.getStringAttr("aligned_alloc"),
+ mlir::ValueRange{alignmentValue, totalSizeBytes});
+ emitc::PointerType targetPointerType = emitc::PointerType::get(elementType);
+ emitc::CastOp castOp = rewriter.create<emitc::CastOp>(
+ loc, targetPointerType, alignedAllocCall.getResult(0));
rewriter.replaceOp(allocOp, castOp);
return success();
}
-private:
- std::string getCTypeName(mlir::Type type) const {
- if (type.isF32())
- return "float";
- if (type.isF64())
- return "double";
- if (auto integerType = mlir::dyn_cast<mlir::IntegerType>(type)) {
- unsigned width = integerType.getWidth();
- bool isSigned = integerType.isSigned();
- if (isSigned) {
- switch (width) {
- case 8:
- return "int8_t";
- case 16:
- return "int16_t";
- case 32:
- return "int32_t";
- case 64:
- return "int64_t";
- case 128:
- return "int128_t";
- default:
- return "unsupported_signed_integer_type";
- }
- } else {
- switch (width) {
- case 8:
- return "uint8_t";
- case 16:
- return "uint16_t";
- case 32:
- return "uint32_t";
- case 64:
- return "uint64_t";
- case 128:
- return "uint128_t";
- default:
- return "unsupported_unsigned_integer_type";
- }
- }
- }
- if (type.isIndex())
- return "size_t";
- return "void";
+ /// The minimum alignment to use with aligned_alloc (has to be a power of 2).
+ static constexpr uint64_t kMinAlignedAllocAlignment = 16UL;
+
+ /// Computes the alignment for aligned_alloc used to allocate the buffer for
+ /// the memory allocation op.
+ ///
+ /// Aligned_alloc requires the allocation size to be a power of two, and the
+ /// allocation size to be a multiple of the alignment.
+ int64_t alignedAllocationGetAlignment(memref::AllocOp op,
+ unsigned int elementWidth) const {
+ if (std::optional<uint64_t> alignment = op.getAlignment())
+ return *alignment;
+
+ // Whenever we don't have alignment set, we will use an alignment
+ // consistent with the element type; since the allocation size has to be a
+ // power of two, we will bump to the next power of two if it isn't.
+ return std::max(kMinAlignedAllocAlignment,
+ llvm::PowerOf2Ceil(elementWidth));
}
};
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
index d7544007718eb..d2fb448fe38ff 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
@@ -15,6 +15,7 @@
#include "mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h"
#include "mlir/Dialect/EmitC/IR/EmitC.h"
#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/IR/Attributes.h"
#include "mlir/Pass/Pass.h"
#include "mlir/Transforms/DialectConversion.h"
@@ -28,19 +29,15 @@ using namespace mlir;
namespace {
struct ConvertMemRefToEmitCPass
: public impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass> {
+ using Base = impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass>;
+ ConvertMemRefToEmitCPass() = default;
+ ConvertMemRefToEmitCPass(ConvertMemRefToEmitCOptions options) {
+ this->lowerToCpp = options.lowerToCpp;
+ }
void runOnOperation() override {
TypeConverter converter;
- mlir::ModuleOp module = getOperation();
- module.walk([&](mlir::Operation *op) {
- if (llvm::isa<mlir::memref::AllocOp, mlir::memref::CopyOp>(op)) {
- OpBuilder builder(module.getBody(), module.getBody()->begin());
- builder.create<emitc::IncludeOp>(module.getLoc(),
- builder.getStringAttr("stdlib.h"));
- return mlir::WalkResult::interrupt();
- }
- return mlir::WalkResult::advance();
- });
-
+ ConvertMemRefToEmitCOptions options;
+ options.lowerToCpp = this->lowerToCpp;
// Fallback for other types.
converter.addConversion([](Type type) -> std::optional<Type> {
if (!emitc::isSupportedEmitCType(type))
@@ -60,6 +57,31 @@ struct ConvertMemRefToEmitCPass
if (failed(applyPartialConversion(getOperation(), target,
std::move(patterns))))
return signalPassFailure();
+
+ mlir::ModuleOp module = getOperation();
+ module.walk([&](mlir::emitc::CallOpaqueOp callOp) {
+ if (callOp.getCallee() != "aligned_alloc") {
+ return mlir::WalkResult::advance();
+ }
+
+ for (auto &op : *module.getBody()) {
+ if (auto includeOp = llvm::dyn_cast<mlir::emitc::IncludeOp>(op)) {
+ if (includeOp.getIsStandardInclude() &&
+ ((options.lowerToCpp && includeOp.getInclude() == "cstdlib") ||
+ (!options.lowerToCpp && includeOp.getInclude() == "stdlib.h"))) {
+ return mlir::WalkResult::interrupt();
+ }
+ }
+ }
+
+ mlir::OpBuilder builder(module.getBody(), module.getBody()->begin());
+ StringAttr includeAttr =
+ builder.getStringAttr(options.lowerToCpp ? "cstdlib" : "stdlib.h");
+ builder.create<mlir::emitc::IncludeOp>(
+ module.getLoc(), includeAttr,
+ /*is_standard_include=*/builder.getUnitAttr());
+ return mlir::WalkResult::interrupt();
+ });
}
};
} // namespace
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
new file mode 100644
index 0000000000000..98a87158daf02
--- /dev/null
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
@@ -0,0 +1,17 @@
+// RUN: mlir-opt -convert-memref-to-emitc="lower-to-cpp=true" %s -split-input-file | FileCheck %s
+
+func.func @alloc() {
+ %alloc = memref.alloc() : memref<999xi32>
+ return
+}
+
+// CHECK:module {
+// CHECK-NEXT: emitc.include <"cstdlib">
+// CHECK-LABEL: alloc()
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CHECK-NEXT: %[[ALLOC:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> index
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.mul %0, %1 : (!emitc.size_t, index) -> !emitc.size_t
+// CHECK-NEXT: %[[ALLOC:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> !emitc.size_t
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "aligned_alloc"(%3, %2) : (!emitc.size_t, !emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+// CHECK-NEXT: return
\ No newline at end of file
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
index 60cf47330169d..d37fd1de90add 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
@@ -8,17 +8,6 @@ func.func @alloca() {
return
}
-// CHECK-LABEL: alloc()
-func.func @alloc() {
- // CHECK-NEXT: %0 = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
- // CHECK-NEXT: %1 = "emitc.constant"() <{value = 32 : index}> : () -> index
- // CHECK-NEXT: %2 = emitc.mul %0, %1 : (!emitc.size_t, index) -> !emitc.size_t
- // CHECK-NEXT: %3 = emitc.call_opaque "malloc"(%2) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
- // CHECK-NEXT: %4 = emitc.cast %3 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
- %alloc = memref.alloc() : memref<999xi32>
- return
-}
-
// -----
// CHECK-LABEL: memref_store
>From 15a01f2948e3d3000e621779b95a9782304908b2 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Tue, 22 Jul 2025 22:01:11 +0000
Subject: [PATCH 06/11] Correct end of line
---
mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
index 98a87158daf02..e5d6566f2ed05 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
@@ -14,4 +14,4 @@ func.func @alloc() {
// CHECK-NEXT: %[[ALLOC:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> !emitc.size_t
// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "aligned_alloc"(%3, %2) : (!emitc.size_t, !emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
// CHECK-NEXT: %[[ALLOC:.*]] = emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
-// CHECK-NEXT: return
\ No newline at end of file
+// CHECK-NEXT: return
>From a6dde301fd9161b9a28a50af2b3cac1e1d1aad73 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Wed, 23 Jul 2025 17:20:05 +0000
Subject: [PATCH 07/11] Allow for both malloc and alloc_aligned
---
.../MemRefToEmitC/MemRefToEmitC.cpp | 30 ++++++++++++++-----
.../MemRefToEmitC/MemRefToEmitCPass.cpp | 21 ++++++-------
.../MemRefToEmitC/memref-to-emitc-alloc.mlir | 20 +++++++++++--
3 files changed, 50 insertions(+), 21 deletions(-)
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index ffb456f743618..349718d4eec3a 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -116,20 +116,34 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
mlir::Value totalSizeBytes = rewriter.create<emitc::MulOp>(
loc, sizeTType, sizeofElement, numElements);
- int64_t alignment = alignedAllocationGetAlignment(allocOp, elementWidth);
- mlir::Value alignmentValue = rewriter.create<emitc::ConstantOp>(
- loc, sizeTType,
- rewriter.getIntegerAttr(rewriter.getIndexType(), alignment));
+ emitc::CallOpaqueOp allocCall;
+ StringAttr allocFunctionName = allocOp.getAlignment()
+ ? rewriter.getStringAttr("aligned_alloc")
+ : rewriter.getStringAttr("malloc");
+ mlir::Value alignmentValue;
+ if (allocOp.getAlignment()) {
+ alignmentValue = rewriter.create<emitc::ConstantOp>(
+ loc, sizeTType,
+ rewriter.getIntegerAttr(
+ rewriter.getIndexType(),
+ alignedAllocationGetAlignment(allocOp, elementWidth)));
+ }
+
+ SmallVector<mlir::Value, 2> argsVec;
+ if (allocOp.getAlignment())
+ argsVec.push_back(alignmentValue);
+ argsVec.push_back(totalSizeBytes);
+ mlir::ValueRange args(argsVec);
- emitc::CallOpaqueOp alignedAllocCall = rewriter.create<emitc::CallOpaqueOp>(
+ allocCall = rewriter.create<emitc::CallOpaqueOp>(
loc,
emitc::PointerType::get(
mlir::emitc::OpaqueType::get(rewriter.getContext(), "void")),
- rewriter.getStringAttr("aligned_alloc"),
- mlir::ValueRange{alignmentValue, totalSizeBytes});
+ allocFunctionName, args);
+
emitc::PointerType targetPointerType = emitc::PointerType::get(elementType);
emitc::CastOp castOp = rewriter.create<emitc::CastOp>(
- loc, targetPointerType, alignedAllocCall.getResult(0));
+ loc, targetPointerType, allocCall.getResult(0));
rewriter.replaceOp(allocOp, castOp);
return success();
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
index d2fb448fe38ff..8e2d3d906abc3 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
@@ -31,9 +31,7 @@ struct ConvertMemRefToEmitCPass
: public impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass> {
using Base = impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass>;
ConvertMemRefToEmitCPass() = default;
- ConvertMemRefToEmitCPass(ConvertMemRefToEmitCOptions options) {
- this->lowerToCpp = options.lowerToCpp;
- }
+ ConvertMemRefToEmitCPass(ConvertMemRefToEmitCOptions options) {}
void runOnOperation() override {
TypeConverter converter;
ConvertMemRefToEmitCOptions options;
@@ -60,17 +58,20 @@ struct ConvertMemRefToEmitCPass
mlir::ModuleOp module = getOperation();
module.walk([&](mlir::emitc::CallOpaqueOp callOp) {
- if (callOp.getCallee() != "aligned_alloc") {
+ if (callOp.getCallee() != "aligned_alloc" &&
+ callOp.getCallee() != "malloc") {
return mlir::WalkResult::advance();
}
for (auto &op : *module.getBody()) {
- if (auto includeOp = llvm::dyn_cast<mlir::emitc::IncludeOp>(op)) {
- if (includeOp.getIsStandardInclude() &&
- ((options.lowerToCpp && includeOp.getInclude() == "cstdlib") ||
- (!options.lowerToCpp && includeOp.getInclude() == "stdlib.h"))) {
- return mlir::WalkResult::interrupt();
- }
+ auto includeOp = llvm::dyn_cast<mlir::emitc::IncludeOp>(op);
+ if (!includeOp) {
+ continue;
+ }
+ if (includeOp.getIsStandardInclude() &&
+ ((options.lowerToCpp && includeOp.getInclude() == "cstdlib") ||
+ (!options.lowerToCpp && includeOp.getInclude() == "stdlib.h"))) {
+ return mlir::WalkResult::interrupt();
}
}
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
index e5d6566f2ed05..6a9327aedd082 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
@@ -11,7 +11,21 @@ func.func @alloc() {
// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
// CHECK-NEXT: %[[ALLOC:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> index
// CHECK-NEXT: %[[ALLOC:.*]] = emitc.mul %0, %1 : (!emitc.size_t, index) -> !emitc.size_t
-// CHECK-NEXT: %[[ALLOC:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> !emitc.size_t
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "aligned_alloc"(%3, %2) : (!emitc.size_t, !emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "malloc"(%2) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.cast %3 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
// CHECK-NEXT: return
+
+func.func @alloc_aligned() {
+ %alloc = memref.alloc() {alignment = 64 : i64} : memref<999xf32>
+ return
+}
+
+// CHECK-LABEL: alloc_aligned
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+// CHECK-NEXT: %[[ALLOC:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> index
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.mul %0, %1 : (!emitc.size_t, index) -> !emitc.size_t
+// CHECK-NEXT: %[[ALIGNMENT:.*]] = "emitc.constant"() <{value = 64 : index}> : () -> !emitc.size_t
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "aligned_alloc"(%3, %2) : (!emitc.size_t, !emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+// CHECK-NEXT: %[[ALLOC:.*]] = emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<f32>
+// CHECK-NEXT: return
+
>From feb651e246bfb7e26ce57e4fe83d0f01ca65fb86 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Wed, 23 Jul 2025 17:22:24 +0000
Subject: [PATCH 08/11] Remove unnecessary auto
---
mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
index 8e2d3d906abc3..f6af461dc93f4 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
@@ -64,7 +64,7 @@ struct ConvertMemRefToEmitCPass
}
for (auto &op : *module.getBody()) {
- auto includeOp = llvm::dyn_cast<mlir::emitc::IncludeOp>(op);
+ emitc::IncludeOp includeOp = llvm::dyn_cast<mlir::emitc::IncludeOp>(op);
if (!includeOp) {
continue;
}
>From f1e7b286a6d35d647934e92288f5459cbf7fffbf Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Wed, 23 Jul 2025 21:47:09 +0000
Subject: [PATCH 09/11] derived constructors
---
mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp | 4 +---
1 file changed, 1 insertion(+), 3 deletions(-)
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
index f6af461dc93f4..b03cc928d9e7d 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
@@ -29,9 +29,7 @@ using namespace mlir;
namespace {
struct ConvertMemRefToEmitCPass
: public impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass> {
- using Base = impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass>;
- ConvertMemRefToEmitCPass() = default;
- ConvertMemRefToEmitCPass(ConvertMemRefToEmitCOptions options) {}
+ using Base::Base;
void runOnOperation() override {
TypeConverter converter;
ConvertMemRefToEmitCOptions options;
>From 67db465bef1c0d45ff65586070418dbca20abc54 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Fri, 25 Jul 2025 04:41:52 +0000
Subject: [PATCH 10/11] Check cpp true and false
---
.../MemRefToEmitC/MemRefToEmitC.cpp | 48 +++++-----------
.../MemRefToEmitC/MemRefToEmitCPass.cpp | 18 ++++--
.../MemRefToEmitC/memref-to-emitc-alloc.mlir | 55 +++++++++++++------
3 files changed, 64 insertions(+), 57 deletions(-)
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 349718d4eec3a..cbf6432de3aea 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -107,31 +107,29 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
{mlir::TypeAttr::get(elementType)}));
mlir::Value sizeofElement = sizeofElementOp.getResult(0);
- unsigned int elementWidth = elementType.getIntOrFloatBitWidth();
- IntegerAttr indexAttr = rewriter.getIndexAttr(elementWidth);
+ long val = memrefType.getShape().front();
+ IntegerAttr valAttr = rewriter.getIntegerAttr(rewriter.getIndexType(), val);
- mlir::Value numElements;
- numElements = rewriter.create<emitc::ConstantOp>(
- loc, rewriter.getIndexType(), indexAttr);
+ mlir::Value numElements = rewriter.create<emitc::ConstantOp>(
+ loc, rewriter.getIndexType(), valAttr);
mlir::Value totalSizeBytes = rewriter.create<emitc::MulOp>(
loc, sizeTType, sizeofElement, numElements);
emitc::CallOpaqueOp allocCall;
- StringAttr allocFunctionName = allocOp.getAlignment()
- ? rewriter.getStringAttr("aligned_alloc")
- : rewriter.getStringAttr("malloc");
+ StringAttr allocFunctionName;
mlir::Value alignmentValue;
+ SmallVector<mlir::Value, 2> argsVec;
if (allocOp.getAlignment()) {
+ allocFunctionName = rewriter.getStringAttr(kAlignedAllocFunctionName);
alignmentValue = rewriter.create<emitc::ConstantOp>(
loc, sizeTType,
- rewriter.getIntegerAttr(
- rewriter.getIndexType(),
- alignedAllocationGetAlignment(allocOp, elementWidth)));
+ rewriter.getIntegerAttr(rewriter.getIndexType(),
+ allocOp.getAlignment().value_or(0)));
+ argsVec.push_back(alignmentValue);
+ } else {
+ allocFunctionName = rewriter.getStringAttr(kMallocFunctionName);
}
- SmallVector<mlir::Value, 2> argsVec;
- if (allocOp.getAlignment())
- argsVec.push_back(alignmentValue);
argsVec.push_back(totalSizeBytes);
mlir::ValueRange args(argsVec);
@@ -148,26 +146,8 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
rewriter.replaceOp(allocOp, castOp);
return success();
}
-
- /// The minimum alignment to use with aligned_alloc (has to be a power of 2).
- static constexpr uint64_t kMinAlignedAllocAlignment = 16UL;
-
- /// Computes the alignment for aligned_alloc used to allocate the buffer for
- /// the memory allocation op.
- ///
- /// Aligned_alloc requires the allocation size to be a power of two, and the
- /// allocation size to be a multiple of the alignment.
- int64_t alignedAllocationGetAlignment(memref::AllocOp op,
- unsigned int elementWidth) const {
- if (std::optional<uint64_t> alignment = op.getAlignment())
- return *alignment;
-
- // Whenever we don't have alignment set, we will use an alignment
- // consistent with the element type; since the allocation size has to be a
- // power of two, we will bump to the next power of two if it isn't.
- return std::max(kMinAlignedAllocAlignment,
- llvm::PowerOf2Ceil(elementWidth));
- }
+ static constexpr const char *kAlignedAllocFunctionName = "aligned_alloc";
+ static constexpr const char *kMallocFunctionName = "malloc";
};
struct ConvertGlobal final : public OpConversionPattern<memref::GlobalOp> {
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
index b03cc928d9e7d..7cdd1293cab71 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
@@ -27,6 +27,11 @@ namespace mlir {
using namespace mlir;
namespace {
+constexpr const char *kAlignedAllocFunctionName = "aligned_alloc";
+constexpr const char *kMallocFunctionName = "malloc";
+constexpr const char *kCppStandardLibraryHeader = "cstdlib";
+constexpr const char *kCStandardLibraryHeader = "stdlib.h";
+
struct ConvertMemRefToEmitCPass
: public impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass> {
using Base::Base;
@@ -56,8 +61,8 @@ struct ConvertMemRefToEmitCPass
mlir::ModuleOp module = getOperation();
module.walk([&](mlir::emitc::CallOpaqueOp callOp) {
- if (callOp.getCallee() != "aligned_alloc" &&
- callOp.getCallee() != "malloc") {
+ if (callOp.getCallee() != kAlignedAllocFunctionName &&
+ callOp.getCallee() != kMallocFunctionName) {
return mlir::WalkResult::advance();
}
@@ -67,15 +72,18 @@ struct ConvertMemRefToEmitCPass
continue;
}
if (includeOp.getIsStandardInclude() &&
- ((options.lowerToCpp && includeOp.getInclude() == "cstdlib") ||
- (!options.lowerToCpp && includeOp.getInclude() == "stdlib.h"))) {
+ ((options.lowerToCpp &&
+ includeOp.getInclude() == kCppStandardLibraryHeader) ||
+ (!options.lowerToCpp &&
+ includeOp.getInclude() == kCStandardLibraryHeader))) {
return mlir::WalkResult::interrupt();
}
}
mlir::OpBuilder builder(module.getBody(), module.getBody()->begin());
StringAttr includeAttr =
- builder.getStringAttr(options.lowerToCpp ? "cstdlib" : "stdlib.h");
+ builder.getStringAttr(options.lowerToCpp ? kCppStandardLibraryHeader
+ : kCStandardLibraryHeader);
builder.create<mlir::emitc::IncludeOp>(
module.getLoc(), includeAttr,
/*is_standard_include=*/builder.getUnitAttr());
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
index 6a9327aedd082..19cb76ec325fe 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
@@ -1,31 +1,50 @@
-// RUN: mlir-opt -convert-memref-to-emitc="lower-to-cpp=true" %s -split-input-file | FileCheck %s
+// RUN: mlir-opt -convert-memref-to-emitc="lower-to-cpp=true" %s -split-input-file | FileCheck %s --check-prefix=CPP
+// RUN: mlir-opt -convert-memref-to-emitc="lower-to-cpp=false" %s -split-input-file | FileCheck %s --check-prefix=NOCPP
func.func @alloc() {
%alloc = memref.alloc() : memref<999xi32>
return
}
-// CHECK:module {
-// CHECK-NEXT: emitc.include <"cstdlib">
-// CHECK-LABEL: alloc()
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
-// CHECK-NEXT: %[[ALLOC:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> index
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.mul %0, %1 : (!emitc.size_t, index) -> !emitc.size_t
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "malloc"(%2) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.cast %3 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
-// CHECK-NEXT: return
+// CPP: module {
+// CPP-NEXT: emitc.include <"cstdlib">
+// CPP-LABEL: alloc()
+// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 999 : 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: return
+
+// NOCPP: module {
+// NOCPP-NEXT: emitc.include <"stdlib.h">
+// NOCPP-LABEL: alloc()
+// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 999 : 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: return
func.func @alloc_aligned() {
%alloc = memref.alloc() {alignment = 64 : i64} : memref<999xf32>
return
}
-// CHECK-LABEL: alloc_aligned
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
-// CHECK-NEXT: %[[ALLOC:.*]] = "emitc.constant"() <{value = 32 : index}> : () -> index
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.mul %0, %1 : (!emitc.size_t, index) -> !emitc.size_t
-// CHECK-NEXT: %[[ALIGNMENT:.*]] = "emitc.constant"() <{value = 64 : index}> : () -> !emitc.size_t
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "aligned_alloc"(%3, %2) : (!emitc.size_t, !emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
-// CHECK-NEXT: %[[ALLOC:.*]] = emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<f32>
-// CHECK-NEXT: return
+// CPP-LABEL: alloc_aligned
+// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
+// CPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
+// CPP-NEXT: %[[ALIGNMENT:.*]] = "emitc.constant"() <{value = 64 : index}> : () -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "aligned_alloc"(%[[ALIGNMENT]], %[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t, !emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+// CPP-NEXT: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<f32>
+// CPP-NEXT: return
+// NOCPP-LABEL: alloc_aligned
+// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 999 : index}> : () -> index
+// NOCPP-NEXT: %[[ALLOC_TOTAL_SIZE:.*]] = emitc.mul %[[ALLOC]], %[[ALLOC_SIZE]] : (!emitc.size_t, index) -> !emitc.size_t
+// NOCPP-NEXT: %[[ALIGNMENT:.*]] = "emitc.constant"() <{value = 64 : index}> : () -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "aligned_alloc"(%[[ALIGNMENT]], %[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t, !emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+// NOCPP-NEXT: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<f32>
+// NOCPP-NEXT: return
>From 0260fd4aea5eb43f2b1824adee3ce0ff5b8268f9 Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Fri, 25 Jul 2025 18:01:08 +0000
Subject: [PATCH 11/11] modify the header instead
---
.../Conversion/MemRefToEmitC/MemRefToEmitC.h | 5 ++
.../MemRefToEmitC/MemRefToEmitC.cpp | 67 +++++++++----------
.../MemRefToEmitC/MemRefToEmitCPass.cpp | 17 ++---
.../MemRefToEmitC/memref-to-emitc-alloc.mlir | 22 ++++++
4 files changed, 65 insertions(+), 46 deletions(-)
diff --git a/mlir/include/mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h b/mlir/include/mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h
index 364a70ce6469b..b595b6a308bea 100644
--- a/mlir/include/mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h
+++ b/mlir/include/mlir/Conversion/MemRefToEmitC/MemRefToEmitC.h
@@ -8,6 +8,11 @@
#ifndef MLIR_CONVERSION_MEMREFTOEMITC_MEMREFTOEMITC_H
#define MLIR_CONVERSION_MEMREFTOEMITC_MEMREFTOEMITC_H
+constexpr const char *alignedAllocFunctionName = "aligned_alloc";
+constexpr const char *mallocFunctionName = "malloc";
+constexpr const char *cppStandardLibraryHeader = "cstdlib";
+constexpr const char *cStandardLibraryHeader = "stdlib.h";
+
namespace mlir {
class DialectRegistry;
class RewritePatternSet;
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index cbf6432de3aea..48993ebb16954 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -25,6 +25,12 @@
using namespace mlir;
+static bool isMemRefTypeLegalForEmitC(MemRefType memRefType) {
+ return memRefType.hasStaticShape() && memRefType.getLayout().isIdentity() &&
+ memRefType.getRank() != 0 &&
+ !llvm::is_contained(memRefType.getShape(), 0);
+}
+
namespace {
/// Implement the interface to convert MemRef to EmitC.
struct MemRefToEmitCDialectInterface : public ConvertToEmitCPatternInterface {
@@ -86,57 +92,52 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
LogicalResult
matchAndRewrite(memref::AllocOp allocOp, OpAdaptor operands,
ConversionPatternRewriter &rewriter) const override {
- mlir::Location loc = allocOp.getLoc();
+ Location loc = allocOp.getLoc();
MemRefType memrefType = allocOp.getType();
- if (!memrefType.hasStaticShape()) {
- // TODO: Handle Dynamic shapes in the future. If the size
- // of the allocation is the result of some function, we could
- // potentially evaluate the function and use the result in the call to
- // allocate.
+ if (!isMemRefTypeLegalForEmitC(memrefType)) {
return rewriter.notifyMatchFailure(
- loc, "cannot transform alloc with dynamic shape");
+ loc, "incompatible memref type for EmitC conversion");
}
- mlir::Type sizeTType = mlir::emitc::SizeTType::get(rewriter.getContext());
+ Type sizeTType = emitc::SizeTType::get(rewriter.getContext());
Type elementType = memrefType.getElementType();
- mlir::emitc::CallOpaqueOp sizeofElementOp =
- rewriter.create<mlir::emitc::CallOpaqueOp>(
- loc, sizeTType, rewriter.getStringAttr("sizeof"),
- mlir::ValueRange{},
- mlir::ArrayAttr::get(rewriter.getContext(),
- {mlir::TypeAttr::get(elementType)}));
- mlir::Value sizeofElement = sizeofElementOp.getResult(0);
-
- long val = memrefType.getShape().front();
- IntegerAttr valAttr = rewriter.getIntegerAttr(rewriter.getIndexType(), val);
-
- mlir::Value numElements = rewriter.create<emitc::ConstantOp>(
- loc, rewriter.getIndexType(), valAttr);
- mlir::Value totalSizeBytes = rewriter.create<emitc::MulOp>(
- loc, sizeTType, sizeofElement, numElements);
+ IndexType indexType = rewriter.getIndexType();
+ emitc::CallOpaqueOp sizeofElementOp = rewriter.create<emitc::CallOpaqueOp>(
+ 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;
+ }
+ Value numElementsValue = rewriter.create<emitc::ConstantOp>(
+ loc, indexType, rewriter.getIndexAttr(numElements));
+
+ Value totalSizeBytes = rewriter.create<emitc::MulOp>(
+ loc, sizeTType, sizeofElementOp.getResult(0), numElementsValue);
emitc::CallOpaqueOp allocCall;
StringAttr allocFunctionName;
- mlir::Value alignmentValue;
- SmallVector<mlir::Value, 2> argsVec;
+ Value alignmentValue;
+ SmallVector<Value, 2> argsVec;
if (allocOp.getAlignment()) {
- allocFunctionName = rewriter.getStringAttr(kAlignedAllocFunctionName);
+ allocFunctionName = rewriter.getStringAttr(alignedAllocFunctionName);
alignmentValue = rewriter.create<emitc::ConstantOp>(
loc, sizeTType,
- rewriter.getIntegerAttr(rewriter.getIndexType(),
+ rewriter.getIntegerAttr(indexType,
allocOp.getAlignment().value_or(0)));
argsVec.push_back(alignmentValue);
} else {
- allocFunctionName = rewriter.getStringAttr(kMallocFunctionName);
+ allocFunctionName = rewriter.getStringAttr(mallocFunctionName);
}
argsVec.push_back(totalSizeBytes);
- mlir::ValueRange args(argsVec);
+ ValueRange args(argsVec);
allocCall = rewriter.create<emitc::CallOpaqueOp>(
loc,
emitc::PointerType::get(
- mlir::emitc::OpaqueType::get(rewriter.getContext(), "void")),
+ emitc::OpaqueType::get(rewriter.getContext(), "void")),
allocFunctionName, args);
emitc::PointerType targetPointerType = emitc::PointerType::get(elementType);
@@ -146,8 +147,6 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
rewriter.replaceOp(allocOp, castOp);
return success();
}
- static constexpr const char *kAlignedAllocFunctionName = "aligned_alloc";
- static constexpr const char *kMallocFunctionName = "malloc";
};
struct ConvertGlobal final : public OpConversionPattern<memref::GlobalOp> {
@@ -266,9 +265,7 @@ struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
void mlir::populateMemRefToEmitCTypeConversion(TypeConverter &typeConverter) {
typeConverter.addConversion(
[&](MemRefType memRefType) -> std::optional<Type> {
- if (!memRefType.hasStaticShape() ||
- !memRefType.getLayout().isIdentity() || memRefType.getRank() == 0 ||
- llvm::is_contained(memRefType.getShape(), 0)) {
+ if (!isMemRefTypeLegalForEmitC(memRefType)) {
return {};
}
Type convertedElementType =
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
index 7cdd1293cab71..e78dd76d6e256 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitCPass.cpp
@@ -27,11 +27,6 @@ namespace mlir {
using namespace mlir;
namespace {
-constexpr const char *kAlignedAllocFunctionName = "aligned_alloc";
-constexpr const char *kMallocFunctionName = "malloc";
-constexpr const char *kCppStandardLibraryHeader = "cstdlib";
-constexpr const char *kCStandardLibraryHeader = "stdlib.h";
-
struct ConvertMemRefToEmitCPass
: public impl::ConvertMemRefToEmitCBase<ConvertMemRefToEmitCPass> {
using Base::Base;
@@ -61,8 +56,8 @@ struct ConvertMemRefToEmitCPass
mlir::ModuleOp module = getOperation();
module.walk([&](mlir::emitc::CallOpaqueOp callOp) {
- if (callOp.getCallee() != kAlignedAllocFunctionName &&
- callOp.getCallee() != kMallocFunctionName) {
+ if (callOp.getCallee() != alignedAllocFunctionName &&
+ callOp.getCallee() != mallocFunctionName) {
return mlir::WalkResult::advance();
}
@@ -73,17 +68,17 @@ struct ConvertMemRefToEmitCPass
}
if (includeOp.getIsStandardInclude() &&
((options.lowerToCpp &&
- includeOp.getInclude() == kCppStandardLibraryHeader) ||
+ includeOp.getInclude() == cppStandardLibraryHeader) ||
(!options.lowerToCpp &&
- includeOp.getInclude() == kCStandardLibraryHeader))) {
+ includeOp.getInclude() == cStandardLibraryHeader))) {
return mlir::WalkResult::interrupt();
}
}
mlir::OpBuilder builder(module.getBody(), module.getBody()->begin());
StringAttr includeAttr =
- builder.getStringAttr(options.lowerToCpp ? kCppStandardLibraryHeader
- : kCStandardLibraryHeader);
+ builder.getStringAttr(options.lowerToCpp ? cppStandardLibraryHeader
+ : cStandardLibraryHeader);
builder.create<mlir::emitc::IncludeOp>(
module.getLoc(), includeAttr,
/*is_standard_include=*/builder.getUnitAttr());
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
index 19cb76ec325fe..e391a893bc44a 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
@@ -48,3 +48,25 @@ func.func @alloc_aligned() {
// NOCPP-NEXT: %[[ALLOC_PTR:.*]] = emitc.call_opaque "aligned_alloc"(%[[ALIGNMENT]], %[[ALLOC_TOTAL_SIZE]]) : (!emitc.size_t, !emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
// NOCPP-NEXT: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<f32>
// NOCPP-NEXT: return
+
+func.func @allocating_multi() {
+ %alloc_5 = memref.alloc() : memref<7x999xi32>
+ return
+}
+
+// CPP-LABEL: allocating_multi
+// CPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// CPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 6993 : 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: return
+
+// NOCPP-LABEL: allocating_multi
+// NOCPP-NEXT: %[[ALLOC:.*]] = emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
+// NOCPP-NEXT: %[[ALLOC_SIZE:.*]] = "emitc.constant"() <{value = 6993 : 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: return
+
More information about the Mlir-commits
mailing list