[Mlir-commits] [mlir] [mlir][emitc] Fix creating pointer from constant array (PR #162083)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Mon Oct 6 06:07:12 PDT 2025
https://github.com/Jimmy2027 created https://github.com/llvm/llvm-project/pull/162083
When creating a pointer from a constant emitc array, check if it is constant. If it is, create the pointer as opaque<"const {type}">>.
Move out C type string creation logic from TranslateToCpp.cpp to getCTypeString in EmitC.cpp as a shared utility function.
>From 8f72155036be688a55eb32f178389ba4d92babfc Mon Sep 17 00:00:00 2001
From: Hendrik Klug <hendrik.klug at gmail.com>
Date: Mon, 6 Oct 2025 12:13:29 +0000
Subject: [PATCH] [mlir][emitc] Fix creating pointer from constant array
When creating a pointer from a constant emitc array,
check if it is constant. If it is, create the pointer as
opaque<"const {type}">>.
Move out C type string creation logic from TranslateToCpp.cpp
to getCTypeString in EmitC.cpp as a shared utility function.
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.h | 5 ++
.../MemRefToEmitC/MemRefToEmitC.cpp | 21 ++++++++-
mlir/lib/Dialect/EmitC/IR/EmitC.cpp | 37 +++++++++++++++
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 47 ++++---------------
.../MemRefToEmitC/memref-to-emitc.mlir | 22 +++++++++
5 files changed, 93 insertions(+), 39 deletions(-)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.h b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.h
index eb7ddeb3bfc54..614895977588a 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.h
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.h
@@ -27,6 +27,7 @@
#include "mlir/Dialect/EmitC/IR/EmitCDialect.h.inc"
#include "mlir/Dialect/EmitC/IR/EmitCEnums.h.inc"
+#include <string>
#include <variant>
namespace mlir {
@@ -49,6 +50,10 @@ bool isSupportedFloatType(mlir::Type type);
/// Determines whether \p type is a emitc.size_t/ssize_t type.
bool isPointerWideType(mlir::Type type);
+/// Convert an MLIR type to its C type string representation.
+/// Returns an empty string if the type cannot be represented as a C type.
+std::string getCTypeString(Type type);
+
// Either a literal string, or an placeholder for the fmtArgs.
struct Placeholder {};
using ReplacementItem = std::variant<StringRef, Placeholder>;
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 2b7bdc9a7b7f8..7b05284818ecb 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -19,6 +19,7 @@
#include "mlir/IR/BuiltinTypes.h"
#include "mlir/IR/Diagnostics.h"
#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/SymbolTable.h"
#include "mlir/IR/TypeRange.h"
#include "mlir/IR/Value.h"
#include "mlir/Transforms/DialectConversion.h"
@@ -134,8 +135,26 @@ createPointerFromEmitcArray(Location loc, OpBuilder &builder,
llvm::SmallVector<mlir::Value> indices(arrayType.getRank(), zeroIndex);
emitc::SubscriptOp subPtr =
emitc::SubscriptOp::create(builder, loc, arrayValue, ValueRange(indices));
+
+ // Determine the pointer type
+ Type pointerElementType = arrayType.getElementType();
+
+ // Check if the array comes from a const global
+ if (auto getGlobalOp = arrayValue.getDefiningOp<emitc::GetGlobalOp>()) {
+ auto globalOp = SymbolTable::lookupNearestSymbolFrom<emitc::GlobalOp>(
+ getGlobalOp, getGlobalOp.getNameAttr());
+ if (globalOp && globalOp.getConstSpecifier()) {
+ // Create a const pointer type using opaque type
+ std::string cTypeString = emitc::getCTypeString(pointerElementType);
+ if (!cTypeString.empty()) {
+ pointerElementType = emitc::OpaqueType::get(builder.getContext(),
+ "const " + cTypeString);
+ }
+ }
+ }
+
emitc::ApplyOp ptr = emitc::ApplyOp::create(
- builder, loc, emitc::PointerType::get(arrayType.getElementType()),
+ builder, loc, emitc::PointerType::get(pointerElementType),
builder.getStringAttr("&"), subPtr);
return ptr;
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 5c8564bca6f86..d07993fb5a986 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -139,6 +139,43 @@ bool mlir::emitc::isFundamentalType(Type type) {
isa<emitc::PointerType>(type);
}
+std::string mlir::emitc::getCTypeString(Type type) {
+ if (auto intType = dyn_cast<IntegerType>(type)) {
+ switch (intType.getWidth()) {
+ case 1:
+ return "bool";
+ case 8:
+ return intType.isUnsigned() ? "uint8_t" : "int8_t";
+ case 16:
+ return intType.isUnsigned() ? "uint16_t" : "int16_t";
+ case 32:
+ return intType.isUnsigned() ? "uint32_t" : "int32_t";
+ case 64:
+ return intType.isUnsigned() ? "uint64_t" : "int64_t";
+ default:
+ return "";
+ }
+ }
+ if (auto floatType = dyn_cast<FloatType>(type)) {
+ if (floatType.getWidth() == 16) {
+ if (isa<Float16Type>(type))
+ return "_Float16";
+ if (isa<BFloat16Type>(type))
+ return "__bf16";
+ return "";
+ }
+ if (floatType.getWidth() == 32)
+ return "float";
+ if (floatType.getWidth() == 64)
+ return "double";
+ return "";
+ }
+ if (auto opaqueType = dyn_cast<emitc::OpaqueType>(type))
+ return opaqueType.getValue().str();
+
+ return "";
+}
+
/// Check that the type of the initial value is compatible with the operations
/// result type.
static LogicalResult verifyInitializationAttribute(Operation *op,
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index a5bd80e9d6b8b..16db8e1aaa12d 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -1792,40 +1792,15 @@ LogicalResult CppEmitter::emitVariableDeclaration(Location loc, Type type,
}
LogicalResult CppEmitter::emitType(Location loc, Type type) {
- if (auto iType = dyn_cast<IntegerType>(type)) {
- switch (iType.getWidth()) {
- case 1:
- return (os << "bool"), success();
- case 8:
- case 16:
- case 32:
- case 64:
- if (shouldMapToUnsigned(iType.getSignedness()))
- return (os << "uint" << iType.getWidth() << "_t"), success();
- else
- return (os << "int" << iType.getWidth() << "_t"), success();
- default:
- return emitError(loc, "cannot emit integer type ") << type;
- }
- }
- if (auto fType = dyn_cast<FloatType>(type)) {
- switch (fType.getWidth()) {
- case 16: {
- if (llvm::isa<Float16Type>(type))
- return (os << "_Float16"), success();
- if (llvm::isa<BFloat16Type>(type))
- return (os << "__bf16"), success();
- else
- return emitError(loc, "cannot emit float type ") << type;
- }
- case 32:
- return (os << "float"), success();
- case 64:
- return (os << "double"), success();
- default:
- return emitError(loc, "cannot emit float type ") << type;
- }
- }
+ std::string cTypeString = emitc::getCTypeString(type);
+ if (!cTypeString.empty())
+ return (os << cTypeString), success();
+
+ // Handle integer and float cases that failed above
+ if (isa<IntegerType>(type))
+ return emitError(loc, "cannot emit integer type ") << type;
+ if (isa<FloatType>(type))
+ return emitError(loc, "cannot emit float type ") << type;
if (auto iType = dyn_cast<IndexType>(type))
return (os << "size_t"), success();
if (auto sType = dyn_cast<emitc::SizeTType>(type))
@@ -1854,10 +1829,6 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) {
}
if (auto tType = dyn_cast<TupleType>(type))
return emitTupleType(loc, tType.getTypes());
- if (auto oType = dyn_cast<emitc::OpaqueType>(type)) {
- os << oType.getValue();
- return success();
- }
if (auto aType = dyn_cast<emitc::ArrayType>(type)) {
if (failed(emitType(loc, aType.getElementType())))
return failure();
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
index 2b4eda37903d4..97c06639bf35b 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
@@ -58,3 +58,25 @@ module @globals {
return
}
}
+
+// -----
+
+// CHECK-LABEL: const_global_copy
+module @const_global_copy {
+ memref.global "private" constant @const_data : memref<4xi8> = dense<[1, 2, 3, 4]>
+ // CHECK: emitc.global static const @const_data : !emitc.array<4xi8> = dense<[1, 2, 3, 4]>
+
+ func.func @copy_from_const_global() {
+ // CHECK: get_global @const_data : !emitc.array<4xi8>
+ %0 = memref.get_global @const_data : memref<4xi8>
+ // CHECK: "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<4xi8>
+ %1 = memref.alloca() : memref<4xi8>
+
+ // Verify that pointer from const global has const qualifier
+ // CHECK: apply "&"({{.*}}) : (!emitc.lvalue<i8>) -> !emitc.ptr<!emitc.opaque<"const int8_t">>
+ // CHECK: apply "&"({{.*}}) : (!emitc.lvalue<i8>) -> !emitc.ptr<i8>
+ // CHECK: call_opaque "memcpy"({{.*}}, {{.*}}, {{.*}}) : (!emitc.ptr<i8>, !emitc.ptr<!emitc.opaque<"const int8_t">>, !emitc.size_t) -> ()
+ memref.copy %0, %1 : memref<4xi8> to memref<4xi8>
+ return
+ }
+}
More information about the Mlir-commits
mailing list