[Mlir-commits] [mlir] [MLIR][EmitC] Add support for pointer-array types in the TypeConverter and related MemRef-to-EmitC operations, and update the C emitter. (PR #160159)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Tue Oct 28 10:39:27 PDT 2025
https://github.com/LekkalaSravya3 updated https://github.com/llvm/llvm-project/pull/160159
>From a226b5bd4fbc8c92712e06bb54cc43cf12dbb796 Mon Sep 17 00:00:00 2001
From: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
Date: Mon, 22 Sep 2025 23:12:10 +0530
Subject: [PATCH 1/4] Handled UnrealizedConversionCast for C code generation
and validated tests
Signed-off-by: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
---
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 84 ++++++++++++++++++-
.../Cpp/unrealized_conversion_cast.mlir | 15 ++++
2 files changed, 98 insertions(+), 1 deletion(-)
create mode 100644 mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 12435119b98a1..2d6d94af93270 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -830,6 +830,64 @@ static LogicalResult printOperation(CppEmitter &emitter,
return success();
}
+static LogicalResult printOperation(CppEmitter &emitter,
+ mlir::UnrealizedConversionCastOp castOp) {
+ raw_ostream &os = emitter.ostream();
+ Operation &op = *castOp.getOperation();
+
+ if (castOp.getResults().size() != 1 || castOp.getOperands().size() != 1) {
+ return castOp.emitOpError(
+ "expected single result and single operand for conversion cast");
+ }
+
+ Type destType = castOp.getResult(0).getType();
+
+ auto srcPtrType =
+ mlir::dyn_cast<emitc::PointerType>(castOp.getOperand(0).getType());
+ auto destArrayType = mlir::dyn_cast<emitc::ArrayType>(destType);
+
+ if (srcPtrType && destArrayType) {
+
+ // Emit declaration: (*v13)[dims] =
+ if (failed(emitter.emitType(op.getLoc(), destArrayType.getElementType())))
+ return failure();
+ os << " (*" << emitter.getOrCreateName(op.getResult(0)) << ")";
+ for (int64_t dim : destArrayType.getShape())
+ os << "[" << dim << "]";
+ os << " = ";
+
+ os << "(";
+
+ // Emit the C++ type for "datatype (*)[dim1][dim2]..."
+ if (failed(emitter.emitType(op.getLoc(), destArrayType.getElementType())))
+ return failure();
+
+ os << "(*)"; // Pointer to array
+
+ for (int64_t dim : destArrayType.getShape()) {
+ os << "[" << dim << "]";
+ }
+ os << ")";
+ if (failed(emitter.emitOperand(castOp.getOperand(0))))
+ return failure();
+
+ return success();
+ }
+
+ // Fallback to generic C-style cast for other cases
+ if (failed(emitter.emitAssignPrefix(op)))
+ return failure();
+
+ os << "(";
+ if (failed(emitter.emitType(op.getLoc(), destType)))
+ return failure();
+ os << ")";
+ if (failed(emitter.emitOperand(castOp.getOperand(0))))
+ return failure();
+
+ return success();
+}
+
static LogicalResult printOperation(CppEmitter &emitter,
emitc::ApplyOp applyOp) {
raw_ostream &os = emitter.ostream();
@@ -1339,7 +1397,29 @@ CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop,
std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
std::string out;
llvm::raw_string_ostream ss(out);
- ss << getOrCreateName(op.getValue());
+ Value baseValue = op.getValue();
+
+ // Check if the baseValue (%arg1) is a result of UnrealizedConversionCastOp
+ // that converts a pointer to an array type.
+ if (auto castOp = dyn_cast_or_null<mlir::UnrealizedConversionCastOp>(
+ baseValue.getDefiningOp())) {
+ auto destArrayType =
+ mlir::dyn_cast<emitc::ArrayType>(castOp.getResult(0).getType());
+ auto srcPtrType =
+ mlir::dyn_cast<emitc::PointerType>(castOp.getOperand(0).getType());
+
+ // If it's a pointer being cast to an array, emit (*varName)
+ if (srcPtrType && destArrayType) {
+ ss << "(*" << getOrCreateName(baseValue) << ")";
+ } else {
+ // Fallback if the cast is not our specific pointer-to-array case
+ ss << getOrCreateName(baseValue);
+ }
+ } else {
+ // Default behavior for a regular array or other base types
+ ss << getOrCreateName(baseValue);
+ }
+
for (auto index : op.getIndices()) {
ss << "[" << getOrCreateName(index) << "]";
}
@@ -1796,6 +1876,8 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
cacheDeferredOpResult(op.getResult(), getSubscriptName(op));
return success();
})
+ .Case<mlir::UnrealizedConversionCastOp>(
+ [&](auto op) { return printOperation(*this, op); })
.Default([&](Operation *) {
return op.emitOpError("unable to find printer for op");
});
diff --git a/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir b/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
new file mode 100644
index 0000000000000..075a268821fa1
--- /dev/null
+++ b/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
@@ -0,0 +1,15 @@
+// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s
+
+// CHECK-LABEL: void builtin_cast
+func.func @builtin_cast(%arg0: !emitc.ptr<f32>){
+ // CHECK : float (*v2)[1][3][4][4] = (float(*)[1][3][4][4])v1
+ %1 = builtin.unrealized_conversion_cast %arg0 : !emitc.ptr<f32> to !emitc.array<1x3x4x4xf32>
+return
+}
+
+// CHECK-LABEL: void builtin_cast_index
+func.func @builtin_cast_index(%arg0: !emitc.size_t){
+ // CHECK : size_t v2 = (size_t)v1
+ %1 = builtin.unrealized_conversion_cast %arg0 : !emitc.size_t to index
+return
+}
\ No newline at end of file
>From 37db2407478fae6d2705c03c327bd94b6aa65055 Mon Sep 17 00:00:00 2001
From: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
Date: Thu, 25 Sep 2025 15:45:26 +0530
Subject: [PATCH 2/4] added the new line and included space in array to pointer
conversion
Signed-off-by: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
---
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 2 +-
mlir/test/Target/Cpp/unrealized_conversion_cast.mlir | 4 ++--
2 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 2d6d94af93270..ed455535911d0 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -862,7 +862,7 @@ static LogicalResult printOperation(CppEmitter &emitter,
if (failed(emitter.emitType(op.getLoc(), destArrayType.getElementType())))
return failure();
- os << "(*)"; // Pointer to array
+ os << " (*)"; // Pointer to array
for (int64_t dim : destArrayType.getShape()) {
os << "[" << dim << "]";
diff --git a/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir b/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
index 075a268821fa1..3971189218c39 100644
--- a/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
+++ b/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
@@ -2,7 +2,7 @@
// CHECK-LABEL: void builtin_cast
func.func @builtin_cast(%arg0: !emitc.ptr<f32>){
- // CHECK : float (*v2)[1][3][4][4] = (float(*)[1][3][4][4])v1
+ // CHECK : float (*v2)[1][3][4][4] = (float (*)[1][3][4][4])v1
%1 = builtin.unrealized_conversion_cast %arg0 : !emitc.ptr<f32> to !emitc.array<1x3x4x4xf32>
return
}
@@ -12,4 +12,4 @@ func.func @builtin_cast_index(%arg0: !emitc.size_t){
// CHECK : size_t v2 = (size_t)v1
%1 = builtin.unrealized_conversion_cast %arg0 : !emitc.size_t to index
return
-}
\ No newline at end of file
+}
>From a76c5a4218cd96c7b3c2bdc33ec6f9a0ae241235 Mon Sep 17 00:00:00 2001
From: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
Date: Thu, 23 Oct 2025 08:01:43 +0000
Subject: [PATCH 3/4] Added Support pointer-array types in type
converter,modified alloc/load/store and C-emitter
Signed-off-by: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
---
.../MemRefToEmitC/MemRefToEmitC.cpp | 44 +++--
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 177 ++++++++----------
.../MemRefToEmitC/memref-to-emitc-alloc.mlir | 12 +-
.../MemRefToEmitC/memref-to-emitc.mlir | 10 +-
.../Cpp/unrealized_conversion_cast.mlir | 15 --
5 files changed, 122 insertions(+), 136 deletions(-)
delete mode 100644 mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 11f866c103639..3f24b5b407f62 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -194,8 +194,9 @@ struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
emitc::PointerType::get(
emitc::OpaqueType::get(rewriter.getContext(), "void")),
allocFunctionName, args);
-
- emitc::PointerType targetPointerType = emitc::PointerType::get(elementType);
+ emitc::ArrayType arrayType =
+ emitc::ArrayType::get(memrefType.getShape(), elementType);
+ emitc::PointerType targetPointerType = emitc::PointerType::get(arrayType);
emitc::CastOp castOp = emitc::CastOp::create(
rewriter, loc, targetPointerType, allocCall.getResult(0));
@@ -340,13 +341,17 @@ struct ConvertLoad final : public OpConversionPattern<memref::LoadOp> {
if (!resultTy) {
return rewriter.notifyMatchFailure(op.getLoc(), "cannot convert type");
}
-
- auto arrayValue =
- dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
- if (!arrayValue) {
- return rewriter.notifyMatchFailure(op.getLoc(), "expected array type");
+ ImplicitLocOpBuilder b(op.getLoc(), rewriter);
+ Value memrefVal = operands.getMemref();
+ Value deref;
+ if (auto ptrVal = dyn_cast<TypedValue<emitc::PointerType>>(memrefVal)) {
+ auto arrayTy = dyn_cast<emitc::ArrayType>(ptrVal.getType().getPointee());
+ if (!arrayTy)
+ return failure();
+ deref = emitc::ApplyOp::create(b, arrayTy, b.getStringAttr("*"), ptrVal);
}
+ auto arrayValue = dyn_cast<TypedValue<emitc::ArrayType>>(deref);
auto subscript = emitc::SubscriptOp::create(
rewriter, op.getLoc(), arrayValue, operands.getIndices());
@@ -361,16 +366,21 @@ struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
LogicalResult
matchAndRewrite(memref::StoreOp op, OpAdaptor operands,
ConversionPatternRewriter &rewriter) const override {
- auto arrayValue =
- dyn_cast<TypedValue<emitc::ArrayType>>(operands.getMemref());
- if (!arrayValue) {
- return rewriter.notifyMatchFailure(op.getLoc(), "expected array type");
+ ImplicitLocOpBuilder b(op.getLoc(), rewriter);
+ Value memrefVal = operands.getMemref();
+ Value deref;
+ if (auto ptrVal = dyn_cast<TypedValue<emitc::PointerType>>(memrefVal)) {
+ auto arrayTy = dyn_cast<emitc::ArrayType>(ptrVal.getType().getPointee());
+ if (!arrayTy)
+ return failure();
+ deref = emitc::ApplyOp::create(b, arrayTy, b.getStringAttr("*"), ptrVal);
}
-
+ auto arrayValue = dyn_cast<TypedValue<emitc::ArrayType>>(deref);
auto subscript = emitc::SubscriptOp::create(
rewriter, op.getLoc(), arrayValue, operands.getIndices());
- rewriter.replaceOpWithNewOp<emitc::AssignOp>(op, subscript,
- operands.getValue());
+ Value valueToStore = operands.getOperands()[0];
+
+ rewriter.replaceOpWithNewOp<emitc::AssignOp>(op, subscript, valueToStore);
return success();
}
};
@@ -386,8 +396,10 @@ void mlir::populateMemRefToEmitCTypeConversion(TypeConverter &typeConverter) {
typeConverter.convertType(memRefType.getElementType());
if (!convertedElementType)
return {};
- return emitc::ArrayType::get(memRefType.getShape(),
- convertedElementType);
+ Type innerArrayType =
+ emitc::ArrayType::get(memRefType.getShape(), convertedElementType);
+ return emitc::PointerType::get(innerArrayType);
+
});
auto materializeAsUnrealizedCast = [](OpBuilder &builder, Type resultType,
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index ed455535911d0..1f58e20572650 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -192,6 +192,9 @@ struct CppEmitter {
// Returns the textual representation of a subscript operation.
std::string getSubscriptName(emitc::SubscriptOp op);
+ // Returns a string representing the expression of an emitc.apply operation.
+ std::string getApplyName(emitc::ApplyOp op);
+
// Returns the textual representation of a member (of object) operation.
std::string createMemberAccess(emitc::MemberOp op);
@@ -830,64 +833,6 @@ static LogicalResult printOperation(CppEmitter &emitter,
return success();
}
-static LogicalResult printOperation(CppEmitter &emitter,
- mlir::UnrealizedConversionCastOp castOp) {
- raw_ostream &os = emitter.ostream();
- Operation &op = *castOp.getOperation();
-
- if (castOp.getResults().size() != 1 || castOp.getOperands().size() != 1) {
- return castOp.emitOpError(
- "expected single result and single operand for conversion cast");
- }
-
- Type destType = castOp.getResult(0).getType();
-
- auto srcPtrType =
- mlir::dyn_cast<emitc::PointerType>(castOp.getOperand(0).getType());
- auto destArrayType = mlir::dyn_cast<emitc::ArrayType>(destType);
-
- if (srcPtrType && destArrayType) {
-
- // Emit declaration: (*v13)[dims] =
- if (failed(emitter.emitType(op.getLoc(), destArrayType.getElementType())))
- return failure();
- os << " (*" << emitter.getOrCreateName(op.getResult(0)) << ")";
- for (int64_t dim : destArrayType.getShape())
- os << "[" << dim << "]";
- os << " = ";
-
- os << "(";
-
- // Emit the C++ type for "datatype (*)[dim1][dim2]..."
- if (failed(emitter.emitType(op.getLoc(), destArrayType.getElementType())))
- return failure();
-
- os << " (*)"; // Pointer to array
-
- for (int64_t dim : destArrayType.getShape()) {
- os << "[" << dim << "]";
- }
- os << ")";
- if (failed(emitter.emitOperand(castOp.getOperand(0))))
- return failure();
-
- return success();
- }
-
- // Fallback to generic C-style cast for other cases
- if (failed(emitter.emitAssignPrefix(op)))
- return failure();
-
- os << "(";
- if (failed(emitter.emitType(op.getLoc(), destType)))
- return failure();
- os << ")";
- if (failed(emitter.emitOperand(castOp.getOperand(0))))
- return failure();
-
- return success();
-}
-
static LogicalResult printOperation(CppEmitter &emitter,
emitc::ApplyOp applyOp) {
raw_ostream &os = emitter.ostream();
@@ -1399,24 +1344,12 @@ std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
llvm::raw_string_ostream ss(out);
Value baseValue = op.getValue();
- // Check if the baseValue (%arg1) is a result of UnrealizedConversionCastOp
- // that converts a pointer to an array type.
- if (auto castOp = dyn_cast_or_null<mlir::UnrealizedConversionCastOp>(
- baseValue.getDefiningOp())) {
- auto destArrayType =
- mlir::dyn_cast<emitc::ArrayType>(castOp.getResult(0).getType());
- auto srcPtrType =
- mlir::dyn_cast<emitc::PointerType>(castOp.getOperand(0).getType());
-
- // If it's a pointer being cast to an array, emit (*varName)
- if (srcPtrType && destArrayType) {
- ss << "(*" << getOrCreateName(baseValue) << ")";
- } else {
- // Fallback if the cast is not our specific pointer-to-array case
+ if (auto applyOp = baseValue.getDefiningOp<emitc::ApplyOp>()) {
+ if (applyOp.getApplicableOperator() == "*")
+ ss << "(*" << getOrCreateName(applyOp.getOperand()) << ")";
+ else
ss << getOrCreateName(baseValue);
- }
} else {
- // Default behavior for a regular array or other base types
ss << getOrCreateName(baseValue);
}
@@ -1426,6 +1359,26 @@ std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
return out;
}
+std::string CppEmitter::getApplyName(emitc::ApplyOp op) {
+ std::string expr;
+ llvm::raw_string_ostream ss(expr);
+
+ StringRef opStr = op.getApplicableOperator();
+ Value operand = op.getOperand();
+
+ // Handle dereference and address-of operators specially
+ if (opStr == "*") {
+ ss << "(*" << getOrCreateName(operand) << ")";
+ } else if (opStr == "&") {
+ ss << "&" << getOrCreateName(operand);
+ } else {
+ // Generic operator form: operand followed by operator
+ ss << getOrCreateName(operand) << opStr;
+ }
+
+ return ss.str();
+}
+
std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
std::string out;
llvm::raw_string_ostream ss(out);
@@ -1833,20 +1786,19 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
.Case<cf::BranchOp, cf::CondBranchOp>(
[&](auto op) { return printOperation(*this, op); })
// EmitC ops.
- .Case<emitc::AddOp, emitc::ApplyOp, emitc::AssignOp,
- emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
- emitc::BitwiseNotOp, emitc::BitwiseOrOp,
- emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
- emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
- emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
- emitc::DeclareFuncOp, emitc::DivOp, emitc::DoOp,
- emitc::ExpressionOp, emitc::FieldOp, emitc::FileOp,
- emitc::ForOp, emitc::FuncOp, emitc::GlobalOp, emitc::IfOp,
- emitc::IncludeOp, emitc::LoadOp, emitc::LogicalAndOp,
- emitc::LogicalNotOp, emitc::LogicalOrOp, emitc::MulOp,
- emitc::RemOp, emitc::ReturnOp, emitc::SubOp, emitc::SwitchOp,
- emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp,
- emitc::VerbatimOp>(
+ .Case<emitc::AddOp, emitc::AssignOp, emitc::BitwiseAndOp,
+ emitc::BitwiseLeftShiftOp, emitc::BitwiseNotOp,
+ emitc::BitwiseOrOp, emitc::BitwiseRightShiftOp,
+ emitc::BitwiseXorOp, emitc::CallOp, emitc::CallOpaqueOp,
+ emitc::CastOp, emitc::ClassOp, emitc::CmpOp,
+ emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
+ emitc::DivOp, emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp,
+ emitc::FileOp, emitc::ForOp, emitc::FuncOp, emitc::GlobalOp,
+ emitc::IfOp, emitc::IncludeOp, emitc::LoadOp,
+ emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
+ emitc::MulOp, emitc::RemOp, emitc::ReturnOp, emitc::SubOp,
+ emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
+ emitc::VariableOp, emitc::VerbatimOp>(
[&](auto op) { return printOperation(*this, op); })
// Func ops.
@@ -1876,8 +1828,19 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
cacheDeferredOpResult(op.getResult(), getSubscriptName(op));
return success();
})
- .Case<mlir::UnrealizedConversionCastOp>(
- [&](auto op) { return printOperation(*this, op); })
+ .Case<emitc::ApplyOp>([&](emitc::ApplyOp op) {
+ std::string expr = getApplyName(op);
+ cacheDeferredOpResult(op.getResult(), expr);
+ // If the result is unused, emit it as a standalone statement.
+ if (op->use_empty()) {
+ std::string tmpName = "tmp" + std::to_string(++valueCount);
+ if (failed(emitType(op->getLoc(), op.getResult().getType())))
+ return failure();
+ os << " " << tmpName << " = " << expr << ";\n";
+ }
+ return success();
+ })
+
.Default([&](Operation *) {
return op.emitOpError("unable to find printer for op");
});
@@ -1896,9 +1859,9 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
// Never emit a semicolon for some operations, especially if endening with
// `}`.
trailingSemicolon &=
- !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::DoOp, emitc::FileOp,
- emitc::ForOp, emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp,
- emitc::VerbatimOp>(op);
+ !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::FileOp, emitc::ForOp,
+ emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp, emitc::VerbatimOp,
+ emitc::ApplyOp>(op);
os << (trailingSemicolon ? ";\n" : "\n");
@@ -1916,6 +1879,17 @@ LogicalResult CppEmitter::emitVariableDeclaration(Location loc, Type type,
}
return success();
}
+ // Handle pointer-to-array types: e.g., int (*ptr)[4][8];
+ if (auto pType = dyn_cast<emitc::PointerType>(type)) {
+ if (auto arrayPointee = dyn_cast<emitc::ArrayType>(pType.getPointee())) {
+ if (failed(emitType(loc, arrayPointee.getElementType())))
+ return failure();
+ os << " (*" << name << ")";
+ for (auto dim : arrayPointee.getShape())
+ os << "[" << dim << "]";
+ return success();
+ }
+ }
if (failed(emitType(loc, type)))
return failure();
os << " " << name;
@@ -1999,8 +1973,21 @@ LogicalResult CppEmitter::emitType(Location loc, Type type) {
if (auto lType = dyn_cast<emitc::LValueType>(type))
return emitType(loc, lType.getValueType());
if (auto pType = dyn_cast<emitc::PointerType>(type)) {
- if (isa<ArrayType>(pType.getPointee()))
- return emitError(loc, "cannot emit pointer to array type ") << type;
+ if (auto arrayPointee = dyn_cast<emitc::ArrayType>(pType.getPointee())) {
+ if (!arrayPointee.hasStaticShape())
+ return emitError(
+ loc, "cannot emit pointer to array type with non-static shape");
+ if (arrayPointee.getShape().empty())
+ return emitError(loc, "cannot emit pointer to empty array type");
+
+ if (failed(emitType(loc, arrayPointee.getElementType())))
+ return failure();
+
+ os << " (*)";
+ for (int64_t dim : arrayPointee.getShape())
+ os << "[" << dim << "]";
+ return success();
+ }
if (failed(emitType(loc, pType.getPointee())))
return failure();
os << "*";
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
index e391a893bc44a..9336faafb0dfd 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc.mlir
@@ -13,7 +13,7 @@ func.func @alloc() {
// 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: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.array<999xi32>>
// CPP-NEXT: return
// NOCPP: module {
@@ -23,7 +23,7 @@ func.func @alloc() {
// 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: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.array<999xi32>>
// NOCPP-NEXT: return
func.func @alloc_aligned() {
@@ -37,7 +37,7 @@ func.func @alloc_aligned() {
// 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: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.array<999xf32>>
// CPP-NEXT: return
// NOCPP-LABEL: alloc_aligned
@@ -46,7 +46,7 @@ func.func @alloc_aligned() {
// 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: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.array<999xf32>>
// NOCPP-NEXT: return
func.func @allocating_multi() {
@@ -59,7 +59,7 @@ func.func @allocating_multi() {
// 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: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.array<7x999xi32>>
// CPP-NEXT: return
// NOCPP-LABEL: allocating_multi
@@ -67,6 +67,6 @@ func.func @allocating_multi() {
// 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: %[[ALLOC_CAST:.*]] = emitc.cast %[[ALLOC_PTR]] : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.array<7x999xi32>>
// NOCPP-NEXT: return
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
index 2b4eda37903d4..4b02e3fe744f0 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
@@ -13,9 +13,10 @@ func.func @alloca() {
// CHECK-LABEL: memref_store
// CHECK-SAME: %[[buff:.*]]: memref<4x8xf32>, %[[v:.*]]: f32, %[[i:.*]]: index, %[[j:.*]]: index
func.func @memref_store(%buff : memref<4x8xf32>, %v : f32, %i: index, %j: index) {
- // CHECK-NEXT: %[[BUFFER:.*]] = builtin.unrealized_conversion_cast %[[buff]] : memref<4x8xf32> to !emitc.array<4x8xf32>
+ // CHECK-NEXT: %[[BUFFER:.*]] = builtin.unrealized_conversion_cast %[[buff]] : memref<4x8xf32> to !emitc.ptr<!emitc.array<4x8xf32>>
- // CHECK-NEXT: %[[SUBSCRIPT:.*]] = emitc.subscript %[[BUFFER]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue<f32>
+ // CHECK-NEXT: %[[APPLY:.+]] = emitc.apply "*"(%[[BUFFER]]) : (!emitc.ptr<!emitc.array<4x8xf32>>) -> !emitc.array<4x8xf32>
+ // CHECK-NEXT: %[[SUBSCRIPT:.*]] = emitc.subscript %[[APPLY]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue<f32>
// CHECK-NEXT: emitc.assign %[[v]] : f32 to %[[SUBSCRIPT]] : <f32>
memref.store %v, %buff[%i, %j] : memref<4x8xf32>
return
@@ -26,9 +27,10 @@ func.func @memref_store(%buff : memref<4x8xf32>, %v : f32, %i: index, %j: index)
// CHECK-LABEL: memref_load
// CHECK-SAME: %[[buff:.*]]: memref<4x8xf32>, %[[i:.*]]: index, %[[j:.*]]: index
func.func @memref_load(%buff : memref<4x8xf32>, %i: index, %j: index) -> f32 {
- // CHECK-NEXT: %[[BUFFER:.*]] = builtin.unrealized_conversion_cast %[[buff]] : memref<4x8xf32> to !emitc.array<4x8xf32>
+ // CHECK-NEXT: %[[BUFFER:.*]] = builtin.unrealized_conversion_cast %[[buff]] : memref<4x8xf32> to !emitc.ptr<!emitc.array<4x8xf32>>
- // CHECK-NEXT: %[[SUBSCRIPT:.*]] = emitc.subscript %[[BUFFER]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue<f32>
+ // CHECK-NEXT: %[[APPLY:.+]] = emitc.apply "*"(%[[BUFFER]]) : (!emitc.ptr<!emitc.array<4x8xf32>>) -> !emitc.array<4x8xf32>
+ // CHECK-NEXT: %[[SUBSCRIPT:.*]] = emitc.subscript %[[APPLY]][%[[i]], %[[j]]] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue<f32>
// CHECK-NEXT: %[[LOAD:.*]] = emitc.load %[[SUBSCRIPT]] : <f32>
%1 = memref.load %buff[%i, %j] : memref<4x8xf32>
// CHECK-NEXT: return %[[LOAD]] : f32
diff --git a/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir b/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
deleted file mode 100644
index 3971189218c39..0000000000000
--- a/mlir/test/Target/Cpp/unrealized_conversion_cast.mlir
+++ /dev/null
@@ -1,15 +0,0 @@
-// RUN: mlir-translate -mlir-to-cpp %s | FileCheck %s
-
-// CHECK-LABEL: void builtin_cast
-func.func @builtin_cast(%arg0: !emitc.ptr<f32>){
- // CHECK : float (*v2)[1][3][4][4] = (float (*)[1][3][4][4])v1
- %1 = builtin.unrealized_conversion_cast %arg0 : !emitc.ptr<f32> to !emitc.array<1x3x4x4xf32>
-return
-}
-
-// CHECK-LABEL: void builtin_cast_index
-func.func @builtin_cast_index(%arg0: !emitc.size_t){
- // CHECK : size_t v2 = (size_t)v1
- %1 = builtin.unrealized_conversion_cast %arg0 : !emitc.size_t to index
-return
-}
>From 63812c976701d6483627c0ad964421eb58f229e7 Mon Sep 17 00:00:00 2001
From: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
Date: Tue, 28 Oct 2025 17:37:57 +0000
Subject: [PATCH 4/4] Modified the Alloca/Global-Op/Copy ops for pointer-array
type and Test files
Signed-off-by: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
---
.../MemRefToEmitC/MemRefToEmitC.cpp | 145 ++++++++++++------
mlir/lib/Target/Cpp/TranslateToCpp.cpp | 26 +++-
mlir/test/Conversion/ConvertToEmitC/tosa.mlir | 33 ++--
.../memref-to-emitc-alloc-copy.mlir | 26 +---
.../MemRefToEmitC/memref-to-emitc-copy.mlir | 17 +-
.../MemRefToEmitC/memref-to-emitc.mlir | 12 +-
mlir/test/Target/Cpp/common-cpp.mlir | 15 +-
mlir/test/Target/Cpp/invalid.mlir | 13 --
mlir/test/Target/Cpp/lvalue.mlir | 3 +-
9 files changed, 171 insertions(+), 119 deletions(-)
diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 3f24b5b407f62..ee8a803d13528 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -67,7 +67,7 @@ struct ConvertAlloca final : public OpConversionPattern<memref::AllocaOp> {
LogicalResult
matchAndRewrite(memref::AllocaOp op, OpAdaptor operands,
ConversionPatternRewriter &rewriter) const override {
-
+ auto memRefType = op.getType();
if (!op.getType().hasStaticShape()) {
return rewriter.notifyMatchFailure(
op.getLoc(), "cannot transform alloca with dynamic shape");
@@ -80,12 +80,48 @@ struct ConvertAlloca final : public OpConversionPattern<memref::AllocaOp> {
op.getLoc(), "cannot transform alloca with alignment requirement");
}
- auto resultTy = getTypeConverter()->convertType(op.getType());
- if (!resultTy) {
- return rewriter.notifyMatchFailure(op.getLoc(), "cannot convert type");
+ if (op.getType().getRank() == 0 ||
+ llvm::is_contained(memRefType.getShape(), 0)) {
+ return rewriter.notifyMatchFailure(
+ op.getLoc(), "cannot transform alloca with rank 0 or zero-sized dim");
}
+
+ auto convertedTy = getTypeConverter()->convertType(memRefType);
+ if (!convertedTy) {
+ return rewriter.notifyMatchFailure(op.getLoc(),
+ "cannot convert memref type");
+ }
+
+ auto arrayTy = emitc::ArrayType::get(memRefType.getShape(),
+ memRefType.getElementType());
+ auto elemTy = memRefType.getElementType();
+
auto noInit = emitc::OpaqueAttr::get(getContext(), "");
- rewriter.replaceOpWithNewOp<emitc::VariableOp>(op, resultTy, noInit);
+ auto arrayVar =
+ rewriter.create<emitc::VariableOp>(op.getLoc(), arrayTy, noInit);
+
+ // Build zero indices for the base subscript.
+ SmallVector<Value> indices;
+ for (unsigned i = 0; i < memRefType.getRank(); ++i) {
+ auto zero = rewriter.create<emitc::ConstantOp>(
+ op.getLoc(), rewriter.getIndexType(), rewriter.getIndexAttr(0));
+ indices.push_back(zero);
+ }
+
+ auto current = rewriter.create<emitc::SubscriptOp>(
+ op.getLoc(), emitc::LValueType::get(elemTy), arrayVar.getResult(),
+ indices);
+
+ auto ptrElemTy = emitc::PointerType::get(elemTy);
+ auto addrOf = rewriter.create<emitc::ApplyOp>(op.getLoc(), ptrElemTy,
+ rewriter.getStringAttr("&"),
+ current.getResult());
+
+ auto ptrArrayTy = emitc::PointerType::get(arrayTy);
+ auto casted = rewriter.create<emitc::CastOp>(op.getLoc(), ptrArrayTy,
+ addrOf.getResult());
+
+ rewriter.replaceOp(op, casted.getResult());
return success();
}
};
@@ -122,24 +158,6 @@ static Value calculateMemrefTotalSizeBytes(Location loc, MemRefType memrefType,
return totalSizeBytes.getResult();
}
-static emitc::ApplyOp
-createPointerFromEmitcArray(Location loc, OpBuilder &builder,
- TypedValue<emitc::ArrayType> arrayValue) {
-
- emitc::ConstantOp zeroIndex = emitc::ConstantOp::create(
- builder, loc, builder.getIndexType(), builder.getIndexAttr(0));
-
- emitc::ArrayType arrayType = arrayValue.getType();
- llvm::SmallVector<mlir::Value> indices(arrayType.getRank(), zeroIndex);
- emitc::SubscriptOp subPtr =
- emitc::SubscriptOp::create(builder, loc, arrayValue, ValueRange(indices));
- emitc::ApplyOp ptr = emitc::ApplyOp::create(
- builder, loc, emitc::PointerType::get(arrayType.getElementType()),
- builder.getStringAttr("&"), subPtr);
-
- return ptr;
-}
-
struct ConvertAlloc final : public OpConversionPattern<memref::AllocOp> {
using OpConversionPattern::OpConversionPattern;
LogicalResult
@@ -224,20 +242,10 @@ struct ConvertCopy final : public OpConversionPattern<memref::CopyOp> {
return rewriter.notifyMatchFailure(
loc, "incompatible target memref type for EmitC conversion");
- auto srcArrayValue =
- cast<TypedValue<emitc::ArrayType>>(operands.getSource());
- emitc::ApplyOp srcPtr =
- createPointerFromEmitcArray(loc, rewriter, srcArrayValue);
-
- auto targetArrayValue =
- cast<TypedValue<emitc::ArrayType>>(operands.getTarget());
- emitc::ApplyOp targetPtr =
- createPointerFromEmitcArray(loc, rewriter, targetArrayValue);
-
emitc::CallOpaqueOp memCpyCall = emitc::CallOpaqueOp::create(
rewriter, loc, TypeRange{}, "memcpy",
ValueRange{
- targetPtr.getResult(), srcPtr.getResult(),
+ operands.getTarget(), operands.getSource(),
calculateMemrefTotalSizeBytes(loc, srcMemrefType, rewriter)});
rewriter.replaceOp(copyOp, memCpyCall.getResults());
@@ -265,11 +273,14 @@ struct ConvertGlobal final : public OpConversionPattern<memref::GlobalOp> {
"currently not supported");
}
- Type resultTy = convertMemRefType(opTy, getTypeConverter());
-
- if (!resultTy) {
- return rewriter.notifyMatchFailure(op.getLoc(),
- "cannot convert result type");
+ Type elemTy = getTypeConverter()->convertType(opTy.getElementType());
+ Type globalType;
+ if (opTy.getRank() == 0) {
+ globalType = elemTy;
+ } else {
+ SmallVector<int64_t> shape(opTy.getShape().begin(),
+ opTy.getShape().end());
+ globalType = emitc::ArrayType::get(shape, elemTy);
}
SymbolTable::Visibility visibility = SymbolTable::getSymbolVisibility(op);
@@ -293,7 +304,7 @@ struct ConvertGlobal final : public OpConversionPattern<memref::GlobalOp> {
initialValue = {};
rewriter.replaceOpWithNewOp<emitc::GlobalOp>(
- op, operands.getSymName(), resultTy, initialValue, externSpecifier,
+ op, operands.getSymName(), globalType, initialValue, externSpecifier,
staticSpecifier, operands.getConstant());
return success();
}
@@ -308,24 +319,64 @@ struct ConvertGetGlobal final
ConversionPatternRewriter &rewriter) const override {
MemRefType opTy = op.getType();
+ Location loc = op.getLoc();
+
+ Type elemTy = getTypeConverter()->convertType(opTy.getElementType());
+ if (!elemTy)
+ return rewriter.notifyMatchFailure(loc, "cannot convert element type");
+
Type resultTy = convertMemRefType(opTy, getTypeConverter());
if (!resultTy) {
return rewriter.notifyMatchFailure(op.getLoc(),
"cannot convert result type");
- }
+
+ Type globalType;
+ if (opTy.getRank() == 0) {
+ globalType = elemTy;
+ } else {
+ SmallVector<int64_t> shape(opTy.getShape().begin(),
+ opTy.getShape().end());
+ globalType = emitc::ArrayType::get(shape, elemTy);
+ }
if (opTy.getRank() == 0) {
- emitc::LValueType lvalueType = emitc::LValueType::get(resultTy);
+ emitc::LValueType lvalueType = emitc::LValueType::get(globalType);
emitc::GetGlobalOp globalLValue = emitc::GetGlobalOp::create(
rewriter, op.getLoc(), lvalueType, operands.getNameAttr());
- emitc::PointerType pointerType = emitc::PointerType::get(resultTy);
- rewriter.replaceOpWithNewOp<emitc::ApplyOp>(
- op, pointerType, rewriter.getStringAttr("&"), globalLValue);
+ emitc::PointerType pointerType = emitc::PointerType::get(globalType);
+ auto addrOf = rewriter.create<emitc::ApplyOp>(
+ loc, ptrElemTy, rewriter.getStringAttr("&"), globalLVal.getResult());
+
+ auto arrayTy = emitc::ArrayType::get({1}, globalType);
+ auto ptrArrayTy = emitc::PointerType::get(arrayTy);
+ auto casted =
+ rewriter.create<emitc::CastOp>(loc, ptrArrayTy, addrOf.getResult());
+ rewriter.replaceOp(op, casted.getResult());
return success();
}
- rewriter.replaceOpWithNewOp<emitc::GetGlobalOp>(op, resultTy,
- operands.getNameAttr());
+
+ auto getGlobal = rewriter.create<emitc::GetGlobalOp>(
+ loc, globalType, operands.getNameAttr());
+
+ SmallVector<Value> indices;
+ for (unsigned i = 0; i < opTy.getRank(); ++i) {
+ auto zero = rewriter.create<emitc::ConstantOp>(
+ loc, rewriter.getIndexType(), rewriter.getIndexAttr(0));
+ indices.push_back(zero);
+ }
+
+ auto current = rewriter.create<emitc::SubscriptOp>(
+ loc, emitc::LValueType::get(elemTy), getGlobal.getResult(), indices);
+
+ auto ptrElemTy = emitc::PointerType::get(opTy.getElementType());
+ auto addrOf = rewriter.create<emitc::ApplyOp>(
+ loc, ptrElemTy, rewriter.getStringAttr("&"), current.getResult());
+
+ auto casted =
+ rewriter.create<emitc::CastOp>(loc, resultTy, addrOf.getResult());
+
+ rewriter.replaceOp(op, casted.getResult());
return success();
}
};
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 1f58e20572650..228f37cee42b4 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -1366,16 +1366,25 @@ std::string CppEmitter::getApplyName(emitc::ApplyOp op) {
StringRef opStr = op.getApplicableOperator();
Value operand = op.getOperand();
- // Handle dereference and address-of operators specially
- if (opStr == "*") {
- ss << "(*" << getOrCreateName(operand) << ")";
- } else if (opStr == "&") {
+ if (opStr == "&") {
ss << "&" << getOrCreateName(operand);
- } else {
- // Generic operator form: operand followed by operator
- ss << getOrCreateName(operand) << opStr;
+ return ss.str();
+ }
+
+ // Emit '*(&x)' form
+ if (opStr == "*") {
+ if (auto innerApply = operand.getDefiningOp<emitc::ApplyOp>()) {
+ StringRef innerOp = innerApply.getApplicableOperator();
+ if (innerOp == "&") {
+ ss << "*(&" << getOrCreateName(innerApply.getOperand()) << ")";
+ return ss.str();
+ }
+ }
+ ss << "*" << getOrCreateName(operand);
+ return ss.str();
}
+ ss << getOrCreateName(operand) << opStr;
return ss.str();
}
@@ -1829,6 +1838,9 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
return success();
})
.Case<emitc::ApplyOp>([&](emitc::ApplyOp op) {
+ if (emittedExpression) {
+ return printOperation(*this, op);
+ }
std::string expr = getApplyName(op);
cacheDeferredOpResult(op.getResult(), expr);
// If the result is unused, emit it as a standalone statement.
diff --git a/mlir/test/Conversion/ConvertToEmitC/tosa.mlir b/mlir/test/Conversion/ConvertToEmitC/tosa.mlir
index 158018374e72c..a314efd3547db 100644
--- a/mlir/test/Conversion/ConvertToEmitC/tosa.mlir
+++ b/mlir/test/Conversion/ConvertToEmitC/tosa.mlir
@@ -20,21 +20,24 @@
// RUN: mlir-opt --pass-pipeline=%{pipeline} %s | FileCheck %s
// -----
-// CHECK: emitc.func private @main(%[[ARG0:.*]]: !emitc.array<2xf32>, %[[ARG1:.*]]: !emitc.array<2xf32>, %[[RES:.*]]: !emitc.array<2xf32>)
-// CHECK-DAG: %[[C0:.*]] = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t
-// CHECK-DAG: %[[C1:.*]] = "emitc.constant"() <{value = 1 : index}> : () -> !emitc.size_t
-// CHECK-DAG: %[[C2:.*]] = "emitc.constant"() <{value = 2 : index}> : () -> !emitc.size_t
-// CHECK-NEXT: for %[[INDEX:.*]] = %[[C0]] to %[[C2]] step %[[C1]] : !emitc.size_t {
-// CHECK-NEXT: %[[V0_LVALUE:.*]] = subscript %[[ARG0]][%[[INDEX]]] : (!emitc.array<2xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
-// CHECK-NEXT: %[[V0:.*]] = load %[[V0_LVALUE]] : <f32>
-// CHECK-NEXT: %[[V1_LVALUE:.*]] = subscript %[[ARG1]][%[[INDEX]]] : (!emitc.array<2xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
-// CHECK-NEXT: %[[V1:.*]] = load %[[V1_LVALUE]] : <f32>
-// CHECK-NEXT: %[[VADD:.*]] = add %[[V0]], %[[V1]] : (f32, f32) -> f32
-// CHECK-NEXT: %[[RES_LVALUE:.*]] = subscript %[[RES]][%[[INDEX]]] : (!emitc.array<2xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
-// CHECK-NEXT: assign %[[VADD]] : f32 to %[[RES_LVALUE]] : <f32>
-// CHECK-NEXT: }
-// CHECK-NEXT: return
-// CHECK-NEXT: }
+// CHECK: emitc.func private @main(%[[ARG0:.*]]: !emitc.ptr<!emitc.array<2xf32>>, %[[ARG1:.*]]: !emitc.ptr<!emitc.array<2xf32>>, %[[RES:.*]]: !emitc.ptr<!emitc.array<2xf32>>)
+// CHECK-DAG: [[VAR_0_:%.+]] = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t
+// CHECK-DAG: [[VAR_1_:%.+]] = "emitc.constant"() <{value = 2 : index}> : () -> !emitc.size_t
+// CHECK-DAG: [[VAR_2_:%.+]] = "emitc.constant"() <{value = 1 : index}> : () -> !emitc.size_t
+// CHECK: for [[I_0_:%.+]] = [[VAR_0_]] to [[VAR_1_]] step [[VAR_2_]] : !emitc.size_t {
+// CHECK: [[VAR_3_:%.+]] = apply "*"(%[[ARG0]]) : (!emitc.ptr<!emitc.array<2xf32>>) -> !emitc.array<2xf32>
+// CHECK: [[VAR_4_:%.+]] = subscript [[VAR_3_]]{{.}}[[I_0_]]{{.}} : (!emitc.array<2xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
+// CHECK-DAG: [[LOAD_VAR_4_MEM_:%.+]] = load [[VAR_4_]] : <f32>
+// CHECK-DAG: [[VAR_6_:%.+]] = apply "*"(%[[ARG1]]) : (!emitc.ptr<!emitc.array<2xf32>>) -> !emitc.array<2xf32>
+// CHECK: [[VAR_7_:%.+]] = subscript [[VAR_6_]]{{.}}[[I_0_]]{{.}} : (!emitc.array<2xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
+// CHECK: [[LOAD_VAR_7_MEM_:%.+]] = load [[VAR_7_]] : <f32>
+// CHECK-DAG: [[VAR_9_:%.+]] = add [[LOAD_VAR_4_MEM_]], [[LOAD_VAR_7_MEM_]] : (f32, f32) -> f32
+// CHECK-DAG: [[VAR_10_:%.+]] = apply "*"(%[[RES]]) : (!emitc.ptr<!emitc.array<2xf32>>) -> !emitc.array<2xf32>
+// CHECK: [[VAR_11_:%.+]] = subscript [[VAR_10_]]{{.}}[[I_0_]]{{.}} : (!emitc.array<2xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
+// CHECK: assign [[VAR_9_]] : f32 to [[VAR_11_]] : <f32>
+// CHECK: }
+// CHECK: return
+// CHECK: }
func.func private @main(%arg0: tensor<2xf32>, %arg1: tensor<2xf32>) -> tensor<2xf32> {
%0 = tosa.add %arg0, %arg1 : (tensor<2xf32>, tensor<2xf32>) -> tensor<2xf32>
return %0 : tensor<2xf32>
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
index c1627a0d4d023..25987630fa248 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
@@ -23,28 +23,18 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
// CHECK-NEXT: "emitc.constant"() <{value = 999 : index}> : () -> index
// CHECK-NEXT: emitc.mul %1, %2 : (!emitc.size_t, index) -> !emitc.size_t
// CHECK-NEXT: emitc.call_opaque "malloc"(%3) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
-// CHECK-NEXT: emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
-// CHECK-NEXT: builtin.unrealized_conversion_cast %5 : !emitc.ptr<i32> to !emitc.array<999xi32>
-// CHECK-NEXT: "emitc.constant"() <{value = 0 : index}> : () -> index
-// CHECK-NEXT: emitc.subscript %0[%7] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
-// CHECK-NEXT: emitc.apply "&"(%8) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
+// CHECK-NEXT: emitc.cast %4 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.array<999xi32>>
// CHECK-NEXT: emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
// CHECK-NEXT: "emitc.constant"() <{value = 999 : index}> : () -> index
-// CHECK-NEXT: emitc.mul %12, %13 : (!emitc.size_t, index) -> !emitc.size_t
-// CHECK-NEXT: emitc.call_opaque "memcpy"(%11, %9, %14) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
+// CHECK-NEXT: emitc.mul %6, %7 : (!emitc.size_t, index) -> !emitc.size_t
+// CHECK-NEXT: emitc.call_opaque "memcpy"(%5, %0, %8) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
// CHECK-NEXT: emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
// CHECK-NEXT: "emitc.constant"() <{value = 999 : index}> : () -> index
-// CHECK-NEXT: emitc.mul %15, %16 : (!emitc.size_t, index) -> !emitc.size_t
-// CHECK-NEXT: emitc.call_opaque "malloc"(%17) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
-// CHECK-NEXT: emitc.cast %18 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<i32>
-// CHECK-NEXT: builtin.unrealized_conversion_cast %19 : !emitc.ptr<i32> to !emitc.array<999xi32>
-// CHECK-NEXT: "emitc.constant"() <{value = 0 : index}> : () -> index
-// CHECK-NEXT: emitc.subscript %0[%21] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
-// CHECK-NEXT: emitc.apply "&"(%22) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
-// CHECK-NEXT: emitc.subscript %20[%21] : (!emitc.array<999xi32>, index) -> !emitc.lvalue<i32>
-// CHECK-NEXT: emitc.apply "&"(%24) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
+// CHECK-NEXT: emitc.mul %9, %10 : (!emitc.size_t, index) -> !emitc.size_t
+// CHECK-NEXT: emitc.call_opaque "malloc"(%11) : (!emitc.size_t) -> !emitc.ptr<!emitc.opaque<"void">>
+// CHECK-NEXT: emitc.cast %12 : !emitc.ptr<!emitc.opaque<"void">> to !emitc.ptr<!emitc.array<999xi32>>
// CHECK-NEXT: emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
// CHECK-NEXT: "emitc.constant"() <{value = 999 : index}> : () -> index
-// CHECK-NEXT: emitc.mul %26, %27 : (!emitc.size_t, index) -> !emitc.size_t
-// CHECK-NEXT: emitc.call_opaque "memcpy"(%25, %23, %28) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
+// CHECK-NEXT: emitc.mul %14, %15 : (!emitc.size_t, index) -> !emitc.size_t
+// CHECK-NEXT: emitc.call_opaque "memcpy"(%13, %0, %16) : (!emitc.ptr<i32>, !emitc.ptr<i32>, !emitc.size_t) -> ()
// CHECK-NEXT: return
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
index d151d1bd53458..c74dac6a35497 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-copy.mlir
@@ -12,17 +12,12 @@ func.func @copying(%arg0 : memref<9x4x5x7xf32>, %arg1 : memref<9x4x5x7xf32>) {
// CHECK-LABEL: copying
// CHECK-SAME: %[[arg0:.*]]: memref<9x4x5x7xf32>, %[[arg1:.*]]: memref<9x4x5x7xf32>
-// CHECK-NEXT: %0 = builtin.unrealized_conversion_cast %arg1 : memref<9x4x5x7xf32> to !emitc.array<9x4x5x7xf32>
-// CHECK-NEXT: %1 = builtin.unrealized_conversion_cast %arg0 : memref<9x4x5x7xf32> to !emitc.array<9x4x5x7xf32>
-// CHECK-NEXT: %2 = "emitc.constant"() <{value = 0 : index}> : () -> index
-// CHECK-NEXT: %3 = emitc.subscript %1[%2, %2, %2, %2] : (!emitc.array<9x4x5x7xf32>, index, index, index, index) -> !emitc.lvalue<f32>
-// CHECK-NEXT: %4 = emitc.apply "&"(%3) : (!emitc.lvalue<f32>) -> !emitc.ptr<f32>
-// CHECK-NEXT: %5 = emitc.subscript %0[%2, %2, %2, %2] : (!emitc.array<9x4x5x7xf32>, index, index, index, index) -> !emitc.lvalue<f32>
-// CHECK-NEXT: %6 = emitc.apply "&"(%5) : (!emitc.lvalue<f32>) -> !emitc.ptr<f32>
-// CHECK-NEXT: %7 = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
-// CHECK-NEXT: %8 = "emitc.constant"() <{value = 1260 : index}> : () -> index
-// CHECK-NEXT: %9 = emitc.mul %7, %8 : (!emitc.size_t, index) -> !emitc.size_t
-// CHECK-NEXT: emitc.call_opaque "memcpy"(%6, %4, %9) : (!emitc.ptr<f32>, !emitc.ptr<f32>, !emitc.size_t) -> ()
+// CHECK-NEXT: %0 = builtin.unrealized_conversion_cast %arg1 : memref<9x4x5x7xf32> to !emitc.ptr<!emitc.array<9x4x5x7xf32>>
+// CHECK-NEXT: %1 = builtin.unrealized_conversion_cast %arg0 : memref<9x4x5x7xf32> to !emitc.ptr<!emitc.array<9x4x5x7xf32>>
+// CHECK-NEXT: %2 = emitc.call_opaque "sizeof"() {args = [f32]} : () -> !emitc.size_t
+// CHECK-NEXT: %3 = "emitc.constant"() <{value = 1260 : index}> : () -> index
+// CHECK-NEXT: %4 = emitc.mul %2, %3 : (!emitc.size_t, index) -> !emitc.size_t
+// CHECK-NEXT: emitc.call_opaque "memcpy"(%0, %1, %4) : (!emitc.ptr<!emitc.array<9x4x5x7xf32>>, !emitc.ptr<!emitc.array<9x4x5x7xf32>>, !emitc.size_t) -> ()
// CHECK-NEXT: return
// CHECK-NEXT: }
// CHECK-NEXT:}
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
index 4b02e3fe744f0..b80f3a23c4a91 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
@@ -4,6 +4,10 @@
// CHECK-LABEL: alloca()
func.func @alloca() {
// CHECK-NEXT: %[[ALLOCA:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<2xf32>
+ // CHECK-NEXT: [[CONST:%.+]] = "emitc.constant"() <{value = 0 : index}> : () -> index
+ // CHECK-NEXT: [[SUBSCRIPT:%.+]] = emitc.subscript %[[ALLOCA]]{{.}}[[CONST]]{{.}} : (!emitc.array<2xf32>, index) -> !emitc.lvalue<f32>
+ // CHECK-NEXT: [[APPLY:%.+]] = emitc.apply "&"([[SUBSCRIPT]]) : (!emitc.lvalue<f32>) -> !emitc.ptr<f32>
+ // CHECK-NEXT: [[CAST:%.+]] = emitc.cast [[APPLY]] : !emitc.ptr<f32> to !emitc.ptr<!emitc.array<2xf32>>
%0 = memref.alloca() : memref<2xf32>
return
}
@@ -53,9 +57,15 @@ module @globals {
// CHECK-LABEL: use_global
func.func @use_global() {
// CHECK-NEXT: emitc.get_global @public_global : !emitc.array<3x7xf32>
+ // CHECK-NEXT: "emitc.constant"() <{value = 0 : index}> : () -> index
+ // CHECK-NEXT: "emitc.constant"() <{value = 0 : index}> : () -> index
+ // CHECK: emitc.subscript %0[%1, %2] : (!emitc.array<3x7xf32>, index, index) -> !emitc.lvalue<f32>
+ // CHECK-NEXT: emitc.apply "&"(%3) : (!emitc.lvalue<f32>) -> !emitc.ptr<f32>
+ // CHECK-NEXT: emitc.cast %4 : !emitc.ptr<f32> to !emitc.ptr<!emitc.array<3x7xf32>>
%0 = memref.get_global @public_global : memref<3x7xf32>
// CHECK-NEXT: emitc.get_global @__constant_xi32 : !emitc.lvalue<i32>
- // CHECK-NEXT: emitc.apply "&"(%1) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
+ // CHECK-NEXT: emitc.apply "&"(%6) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
+ // CHECK-NEXT: emitc.cast %7 : !emitc.ptr<i32> to !emitc.ptr<!emitc.array<1xi32>>
%1 = memref.get_global @__constant_xi32 : memref<i32>
return
}
diff --git a/mlir/test/Target/Cpp/common-cpp.mlir b/mlir/test/Target/Cpp/common-cpp.mlir
index 294e6af65bf14..a2dcfd068122b 100644
--- a/mlir/test/Target/Cpp/common-cpp.mlir
+++ b/mlir/test/Target/Cpp/common-cpp.mlir
@@ -93,15 +93,13 @@ func.func @opaque_types(%arg0: !emitc.opaque<"bool">, %arg1: !emitc.opaque<"char
func.func @apply() -> !emitc.ptr<i32> {
// CHECK-NEXT: int32_t [[V1:[^ ]*]];
%0 = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue<i32>
- // CHECK-NEXT: int32_t* [[V2:[^ ]*]] = &[[V1]];
+ // CHECK: int32_t [[V2:[^ ]*]];
%1 = emitc.apply "&"(%0) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
- // CHECK-NEXT: int32_t [[V3:[^ ]*]];
%2 = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue<i32>
- // CHECK-NEXT: int32_t [[V4:[^ ]*]] = *[[V2]];
%3 = emitc.apply "*"(%1) : (!emitc.ptr<i32>) -> i32
- // CHECK-NEXT: [[V3]] = [[V4]];
+ // CHECK: [[V2]] = *(&[[V1]]);
emitc.assign %3 : i32 to %2 : !emitc.lvalue<i32>
- // CHECK-NEXT: return [[V2]];
+ // CHECK-NEXT: return &[[V1]];
return %1 : !emitc.ptr<i32>
}
@@ -117,3 +115,10 @@ func.func @call_opaque_with_template_arg() {
// CHECK-NEXT: return
return
}
+
+// CHECK : void ptr_to_array() {
+func.func @ptr_to_array() {
+ // CHECK: int16_t (*)[9] v1 = NULL;
+ %v = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.lvalue<!emitc.ptr<!emitc.array<9xi16>>>
+ return
+}
diff --git a/mlir/test/Target/Cpp/invalid.mlir b/mlir/test/Target/Cpp/invalid.mlir
index df4627a158319..c01869ed6706b 100644
--- a/mlir/test/Target/Cpp/invalid.mlir
+++ b/mlir/test/Target/Cpp/invalid.mlir
@@ -65,12 +65,6 @@ func.func @tensor_of_array(%arg0 : tensor<4x!emitc.array<4xf32>>) {
return
}
-// -----
-
-// expected-error at +1 {{cannot emit pointer to array type}}
-func.func @pointer_to_array(%arg0 : !emitc.ptr<!emitc.array<4xf32>>) {
- return
-}
// -----
@@ -86,10 +80,3 @@ func.func @array_as_result(%arg: !emitc.array<4xi8>) -> (!emitc.array<4xi8>) {
return %arg : !emitc.array<4xi8>
}
-// -----
-
-func.func @ptr_to_array() {
- // expected-error at +1 {{cannot emit pointer to array type '!emitc.ptr<!emitc.array<9xi16>>'}}
- %v = "emitc.variable"(){value = #emitc.opaque<"NULL">} : () -> !emitc.lvalue<!emitc.ptr<!emitc.array<9xi16>>>
- return
-}
diff --git a/mlir/test/Target/Cpp/lvalue.mlir b/mlir/test/Target/Cpp/lvalue.mlir
index 2aa438eb6371c..6197754a9faae 100644
--- a/mlir/test/Target/Cpp/lvalue.mlir
+++ b/mlir/test/Target/Cpp/lvalue.mlir
@@ -16,8 +16,7 @@ emitc.func @lvalue_variables(%v1: i32, %v2: i32) -> i32 {
// CHECK-NEXT: int32_t [[VAL:[^ ]*]] = [[V1]] * [[V2]];
// CHECK-NEXT: int32_t [[VAR:[^ ]*]];
// CHECK-NEXT: [[VAR]] = [[VAL]];
-// CHECK-NEXT: int32_t* [[VAR_PTR:[^ ]*]] = &[[VAR]];
-// CHECK-NEXT: zero([[VAR_PTR]]);
+// CHECK: zero(&[[VAR]]);
// CHECK-NEXT: int32_t [[VAR_LOAD:[^ ]*]] = [[VAR]];
// CHECK-NEXT: int32_t [[NEG_ONE:[^ ]*]] = -1;
// CHECK-NEXT: [[VAR]] = [[NEG_ONE]];
More information about the Mlir-commits
mailing list