[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
Fri Jan 9 04:04:29 PST 2026


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/6] 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/6] 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/6] 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 23acdcedcde2f11895139ae0453f377adab68434 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/6] 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           | 143 ++++++++++++------
 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, 170 insertions(+), 118 deletions(-)

diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 3f24b5b407f62..814723aa05826 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, pointerType, rewriter.getStringAttr("&"), globalLValue.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]];

>From 496481fd13e492524c86152e8e1cbe2ccc7f0a93 Mon Sep 17 00:00:00 2001
From: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
Date: Thu, 8 Jan 2026 22:28:43 +0530
Subject: [PATCH 5/6] Use flattened pointer indexing for memref load/store

Signed-off-by: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
---
 .../MemRefToEmitC/MemRefToEmitC.cpp           | 133 ++++++++++++------
 mlir/lib/Target/Cpp/TranslateToCpp.cpp        | 119 +---------------
 mlir/test/Conversion/ConvertToEmitC/tosa.mlir |  33 +++--
 .../memref-to-emitc-alloc-copy.mlir           |  18 +--
 .../MemRefToEmitC/memref-to-emitc.mlir        |  41 +++---
 mlir/test/Target/Cpp/common-cpp.mlir          |   8 +-
 mlir/test/Target/Cpp/lvalue.mlir              |  11 +-
 7 files changed, 156 insertions(+), 207 deletions(-)

diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 814723aa05826..6b9f49755bbef 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -98,27 +98,26 @@ struct ConvertAlloca final : public OpConversionPattern<memref::AllocaOp> {
 
     auto noInit = emitc::OpaqueAttr::get(getContext(), "");
     auto arrayVar =
-        rewriter.create<emitc::VariableOp>(op.getLoc(), arrayTy, noInit);
+    emitc::VariableOp::create(rewriter,      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>(
+      auto zero = emitc::ConstantOp::create(rewriter,
           op.getLoc(), rewriter.getIndexType(), rewriter.getIndexAttr(0));
       indices.push_back(zero);
     }
 
-    auto current = rewriter.create<emitc::SubscriptOp>(
+    auto current = emitc::SubscriptOp::create(rewriter,
         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("&"),
+    auto addrOf = emitc::AddressOfOp::create(rewriter, op.getLoc(), ptrElemTy,
                                                   current.getResult());
 
     auto ptrArrayTy = emitc::PointerType::get(arrayTy);
-    auto casted = rewriter.create<emitc::CastOp>(op.getLoc(), ptrArrayTy,
+    auto casted = emitc::CastOp::create(rewriter,op.getLoc(), ptrArrayTy,
                                                  addrOf.getResult());
 
     rewriter.replaceOp(op, casted.getResult());
@@ -345,8 +344,8 @@ struct ConvertGetGlobal final
       emitc::GetGlobalOp globalLValue = emitc::GetGlobalOp::create(
           rewriter, op.getLoc(), lvalueType, operands.getNameAttr());
       emitc::PointerType pointerType = emitc::PointerType::get(globalType);
-      auto addrOf = rewriter.create<emitc::ApplyOp>(
-          loc, pointerType, rewriter.getStringAttr("&"), globalLValue.getResult());
+      auto addrOf = emitc::AddressOfOp::create(rewriter,
+          loc, pointerType, globalLValue.getResult());
 
       auto arrayTy = emitc::ArrayType::get({1}, globalType);
       auto ptrArrayTy = emitc::PointerType::get(arrayTy);
@@ -356,55 +355,110 @@ struct ConvertGetGlobal final
       return success();
     }
 
-    auto getGlobal = rewriter.create<emitc::GetGlobalOp>(
+    auto getGlobal = emitc::GetGlobalOp::create(rewriter,
         loc, globalType, operands.getNameAttr());
 
     SmallVector<Value> indices;
     for (unsigned i = 0; i < opTy.getRank(); ++i) {
-      auto zero = rewriter.create<emitc::ConstantOp>(
+      auto zero = emitc::ConstantOp::create(rewriter,
           loc, rewriter.getIndexType(), rewriter.getIndexAttr(0));
       indices.push_back(zero);
     }
 
-    auto current = rewriter.create<emitc::SubscriptOp>(
+    auto current = emitc::SubscriptOp::create(rewriter,
         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 addrOf = emitc::AddressOfOp::create(rewriter,
+        loc, ptrElemTy,  current.getResult());
 
     auto casted =
-        rewriter.create<emitc::CastOp>(loc, resultTy, addrOf.getResult());
+        emitc::CastOp::create(rewriter, loc, resultTy, addrOf.getResult());
 
     rewriter.replaceOp(op, casted.getResult());
     return success();
   }
 };
 
+
+// Helper to compute a flattened linear index for multi-dimensional memrefs
+// and generate a single subscript access in EmitC.
+
+static Value getFlattenedSubscript(ConversionPatternRewriter &rewriter,
+                                   Location loc,
+                                   Value memrefVal,
+                                   ValueRange indices,
+                                   Type elementTy) {
+    auto module = memrefVal.getDefiningOp() ? memrefVal.getDefiningOp()->getParentOfType<ModuleOp>()
+                                            : rewriter.getBlock()->getParentOp()->getParentOfType<ModuleOp>();
+
+    // Inject mt_index template once per module to compute flattened indices.
+    if (module && !module->getAttr("emitc.macros_inserted")) {
+        OpBuilder::InsertionGuard guard(rewriter);
+        rewriter.setInsertionPointToStart(module.getBody());
+        // The template is used to avoid emitting repeated
+        // index arithmetic and keeps the generated C/C++ code readable and reusable.
+        std::string templateDef =
+            "\n/* Generalized Indexing Template */\n"
+            "template <typename T> constexpr T mt_index(T i_last) { return i_last; }\n"
+            "template <typename T, typename... Args>\n"
+            "constexpr T mt_index(T idx, T stride, Args... rest) {\n"
+            "    return (idx * stride) + mt_index(rest...);\n"
+            "}\n";
+
+        emitc::VerbatimOp::create(rewriter, loc, rewriter.getStringAttr(templateDef));
+        module->setAttr("emitc.macros_inserted", rewriter.getUnitAttr());
+    }
+
+    auto ptrTy = cast<emitc::PointerType>(memrefVal.getType());
+    auto arrayTy = cast<emitc::ArrayType>(ptrTy.getPointee());
+    ArrayRef<int64_t> shape = arrayTy.getShape();
+    unsigned rank = indices.size();
+
+    // Compute static row-major strides from the array shape.
+    SmallVector<int64_t> strideValues(rank, 1);
+    for (int i = (int)rank - 2; i >= 0; --i) {
+        strideValues[i] = strideValues[i + 1] * shape[i + 1];
+    }
+    // build the argument list (index, stride, …) used to invoke it for a given
+    // memref access.
+    SmallVector<Value> macroArgs;
+    for (unsigned i = 0; i < rank; ++i) {
+        macroArgs.push_back(indices[i]);
+        if (i < rank - 1) {
+            auto sVal = emitc::ConstantOp::create(rewriter, loc,
+                                                  rewriter.getIndexType(),
+                                                  rewriter.getIndexAttr(strideValues[i]));
+            macroArgs.push_back(sVal.getResult());
+        }
+    }
+
+    auto flatIndex = emitc::CallOpaqueOp::create(rewriter, loc,
+                                                 rewriter.getIndexType(),
+                                                 "mt_index", macroArgs);
+
+    auto elemPtrTy = emitc::PointerType::get(elementTy);
+    auto flatPtr = emitc::CastOp::create(rewriter, loc, elemPtrTy, memrefVal);
+    auto lvalueTy = emitc::LValueType::get(elementTy);
+    auto subscript = emitc::SubscriptOp::create(rewriter, loc,
+                                                lvalueTy, flatPtr.getResult(),
+                                                flatIndex.getResult(0));
+
+    return subscript.getResult();
+}
 struct ConvertLoad final : public OpConversionPattern<memref::LoadOp> {
   using OpConversionPattern::OpConversionPattern;
 
   LogicalResult
   matchAndRewrite(memref::LoadOp op, OpAdaptor operands,
                   ConversionPatternRewriter &rewriter) const override {
-
     auto resultTy = getTypeConverter()->convertType(op.getType());
-    if (!resultTy) {
-      return rewriter.notifyMatchFailure(op.getLoc(), "cannot convert 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);
-    }
+    if (!resultTy) return failure();
 
-    auto arrayValue = dyn_cast<TypedValue<emitc::ArrayType>>(deref);
-    auto subscript = emitc::SubscriptOp::create(
-        rewriter, op.getLoc(), arrayValue, operands.getIndices());
+    Value subscript = getFlattenedSubscript(rewriter, op.getLoc(),
+                                            operands.getMemref(),
+                                            operands.getIndices(),
+                                            resultTy);
 
     rewriter.replaceOpWithNewOp<emitc::LoadOp>(op, resultTy, subscript);
     return success();
@@ -417,20 +471,13 @@ struct ConvertStore final : public OpConversionPattern<memref::StoreOp> {
   LogicalResult
   matchAndRewrite(memref::StoreOp op, OpAdaptor operands,
                   ConversionPatternRewriter &rewriter) const override {
-    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());
-    Value valueToStore = operands.getOperands()[0];
 
+    Value valueToStore = operands.getValue();
+    Type elementTy = valueToStore.getType();
+    Value subscript = getFlattenedSubscript(rewriter, op.getLoc(),
+                                            operands.getMemref(),
+                                            operands.getIndices(),
+                                            elementTy);
     rewriter.replaceOpWithNewOp<emitc::AssignOp>(op, subscript, valueToStore);
     return success();
   }
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 2d15e3966d8b6..5eea08ec3cc82 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -195,18 +195,6 @@ struct CppEmitter {
   /// emitc::ForOp.
   StringRef getOrCreateInductionVarName(Value val);
 
-  // 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);
-
-  // Returns the textual representation of a member of pointer operation.
-  std::string createMemberAccess(emitc::MemberOfPtrOp op);
-
   /// Return the existing or a new label of a Block.
   StringRef getOrCreateName(Block &block);
 
@@ -1421,70 +1409,6 @@ CppEmitter::CppEmitter(raw_ostream &os, bool declareVariablesAtTop,
   labelInScopeCount.push(0);
 }
 
-std::string CppEmitter::getSubscriptName(emitc::SubscriptOp op) {
-  std::string out;
-  llvm::raw_string_ostream ss(out);
-  Value baseValue = op.getValue();
-
-  if (auto applyOp = baseValue.getDefiningOp<emitc::ApplyOp>()) {
-    if (applyOp.getApplicableOperator() == "*")
-      ss << "(*" << getOrCreateName(applyOp.getOperand()) << ")";
-    else
-      ss << getOrCreateName(baseValue);
-  } else {
-    ss << getOrCreateName(baseValue);
-  }
-
-  for (auto index : op.getIndices()) {
-    ss << "[" << getOrCreateName(index) << "]";
-  }
-  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();
-
-  if (opStr == "&") {
-    ss << "&" << getOrCreateName(operand);
-    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();
-}
-
-std::string CppEmitter::createMemberAccess(emitc::MemberOp op) {
-  std::string out;
-  llvm::raw_string_ostream ss(out);
-  ss << getOrCreateName(op.getOperand());
-  ss << "." << op.getMember();
-  return out;
-}
-
-std::string CppEmitter::createMemberAccess(emitc::MemberOfPtrOp op) {
-  std::string out;
-  llvm::raw_string_ostream ss(out);
-  ss << getOrCreateName(op.getOperand());
-  ss << "->" << op.getMember();
-  return out;
-}
 
 void CppEmitter::cacheDeferredOpResult(Value value, StringRef str) {
   if (!valueMapper.count(value))
@@ -1886,46 +1810,6 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
           // Func ops.
           .Case<func::CallOp, func::FuncOp, func::ReturnOp>(
               [&](auto op) { return printOperation(*this, op); })
-          .Case<emitc::GetGlobalOp>([&](auto op) {
-            cacheDeferredOpResult(op.getResult(), op.getName());
-            return success();
-          })
-          .Case<emitc::GetFieldOp>([&](auto op) {
-            cacheDeferredOpResult(op.getResult(), op.getFieldName());
-            return success();
-          })
-          .Case<emitc::LiteralOp>([&](auto op) {
-            cacheDeferredOpResult(op.getResult(), op.getValue());
-            return success();
-          })
-          .Case<emitc::MemberOp>([&](auto op) {
-            cacheDeferredOpResult(op.getResult(), createMemberAccess(op));
-            return success();
-          })
-          .Case<emitc::MemberOfPtrOp>([&](auto op) {
-            cacheDeferredOpResult(op.getResult(), createMemberAccess(op));
-            return success();
-          })
-          .Case<emitc::SubscriptOp>([&](auto op) {
-            cacheDeferredOpResult(op.getResult(), getSubscriptName(op));
-            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.
-            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");
           });
@@ -1945,8 +1829,7 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
   // `}`.
   trailingSemicolon &=
       !isa<cf::CondBranchOp, emitc::DeclareFuncOp, emitc::FileOp, emitc::ForOp,
-           emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp, emitc::VerbatimOp,
-           emitc::ApplyOp>(op);
+           emitc::IfOp, emitc::IncludeOp, emitc::SwitchOp, emitc::VerbatimOp>(op);
 
   os << (trailingSemicolon ? ";\n" : "\n");
 
diff --git a/mlir/test/Conversion/ConvertToEmitC/tosa.mlir b/mlir/test/Conversion/ConvertToEmitC/tosa.mlir
index a314efd3547db..d4d20f74429a8 100644
--- a/mlir/test/Conversion/ConvertToEmitC/tosa.mlir
+++ b/mlir/test/Conversion/ConvertToEmitC/tosa.mlir
@@ -19,25 +19,34 @@
 
 // RUN: mlir-opt --pass-pipeline=%{pipeline} %s | FileCheck %s
 // -----
-
-// CHECK: emitc.func private @main(%[[ARG0:.*]]: !emitc.ptr<!emitc.array<2xf32>>, %[[ARG1:.*]]: !emitc.ptr<!emitc.array<2xf32>>, %[[RES:.*]]: !emitc.ptr<!emitc.array<2xf32>>)
+// CHECK:         emitc.verbatim "\0A/* Generalized Indexing Template */
+// CHECK-SAME: template <typename T> constexpr T mt_index(T i_last)
+// CHECK-SAME:{ return i_last; }\0Atemplate <typename T, typename... Args>
+// CHECK-SAME: \0Aconstexpr T mt_index(T idx, T stride, Args... rest)
+// CHECK-SAME: {\0A    return (idx * stride) + mt_index(rest...);\0A}\0A"
+// CHECK:         emitc.func private @main(%[[ARG0:.*]]: !emitc.ptr<!emitc.array<2xf32>>, %[[ARG1:.*]]: !emitc.ptr<!emitc.array<2xf32>>,
+// CHECK-SAME:      %[[ARG2:.*]]: !emitc.ptr<!emitc.array<2xf32>>) attributes {specifiers = ["static"]} {
 // 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-DAG:         [[OPAQUE_INDEX_1:%.+]] = call_opaque "mt_index"([[I_0_]]) : (!emitc.size_t) -> index
+// CHECK-DAG:         [[VAR_9_:%.+]] = cast %[[ARG0]] : !emitc.ptr<!emitc.array<2xf32>> to !emitc.ptr<f32>
+// CHECK:             [[SUBSCRIPT_1:%.+]] = subscript [[VAR_9_]]{{.}}[[OPAQUE_INDEX_1]]{{.}} : (!emitc.ptr<f32>, index) -> !emitc.lvalue<f32>
+// CHECK-DAG:         [[LOAD_MEM_1:%.+]] = load [[SUBSCRIPT_1]] : <f32>
+// CHECK-DAG:         [[OPAQUE_INDEX_2:%.+]] = call_opaque "mt_index"([[I_0_]]) : (!emitc.size_t) -> index
+// CHECK-DAG:         [[CAST_1:%.+]] = cast %[[ARG1]] : !emitc.ptr<!emitc.array<2xf32>> to !emitc.ptr<f32>
+// CHECK:             [[SUBSCRIPT_2:%.+]] = subscript [[CAST_1]]{{.}}[[OPAQUE_INDEX_2]]{{.}} : (!emitc.ptr<f32>, index) -> !emitc.lvalue<f32>
+// CHECK:             [[LOAD_MEM_2:%.+]] = load [[SUBSCRIPT_2]] : <f32>
+// CHECK-DAG:         [[ADD:%.+]] = add [[LOAD_MEM_1]], [[LOAD_MEM_2]] : (f32, f32) -> f32
+// CHECK-DAG:         [[OPAQUE_INDEX_3:%.+]] = call_opaque "mt_index"([[I_0_]]) : (!emitc.size_t) -> index
+// CHECK-DAG:         [[CAST_2:%.+]] = cast %[[ARG2]] : !emitc.ptr<!emitc.array<2xf32>> to !emitc.ptr<f32>
+// CHECK:             [[SUBSCRIPT_3:%.+]] = subscript [[CAST_2]]{{.}}[[OPAQUE_INDEX_3]]{{.}} : (!emitc.ptr<f32>, index) -> !emitc.lvalue<f32>
+// CHECK:             assign [[ADD]] : f32 to [[SUBSCRIPT_3]] : <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 b8a7cac5964df..4d2b596ccd012 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc-alloc-copy.mlir
@@ -7,7 +7,7 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
   %alloc_1 = memref.alloc() : memref<999xi32>
   memref.copy %arg0, %alloc_1 : memref<999xi32> to memref<999xi32>
   return
-} 
+}
 
 // NOCPP:  emitc.include <"stdlib.h">
 // NOCPP-NEXT:  emitc.include <"string.h">
@@ -17,16 +17,16 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
 
 // CHECK-LABEL: alloc_copy
 // CHECK-SAME: %[[arg0:.*]]: memref<999xi32>
-// CHECK-NEXT:  builtin.unrealized_conversion_cast %arg0 : memref<999xi32> to !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 %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<!emitc.array<999xi32>>  
+// CHECK:  builtin.unrealized_conversion_cast %arg0 : memref<999xi32> 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 %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<!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 %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 "memcpy"(%5, %0, %8) : (!emitc.ptr<!emitc.array<999xi32>>, !emitc.ptr<!emitc.array<999xi32>>, !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 %9, %10 : (!emitc.size_t, index) -> !emitc.size_t
@@ -35,5 +35,5 @@ func.func @alloc_copy(%arg0: memref<999xi32>) {
 // CHECK-NEXT:  emitc.call_opaque "sizeof"() {args = [i32]} : () -> !emitc.size_t
 // CHECK-NEXT:  "emitc.constant"() <{value = 999 : index}> : () -> index
 // 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:  emitc.call_opaque "memcpy"(%13, %0, %16) : (!emitc.ptr<!emitc.array<999xi32>>, !emitc.ptr<!emitc.array<999xi32>>, !emitc.size_t) -> ()
 // CHECK-NEXT:    return
diff --git a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
index b80f3a23c4a91..61e27014127ae 100644
--- a/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
+++ b/mlir/test/Conversion/MemRefToEmitC/memref-to-emitc.mlir
@@ -3,25 +3,32 @@
 
 // CHECK-LABEL: alloca()
 func.func @alloca() {
-  // CHECK-NEXT: %[[ALLOCA:.*]] = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.array<2xf32>
+  // CHECK: %[[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>>
+  // CHECK-NEXT: [[ADDR_OF:%.+]] = emitc.address_of [[SUBSCRIPT]] : !emitc.lvalue<f32>
+  // CHECK-NEXT: [[CAST:%.+]] = emitc.cast [[ADDR_OF]] : !emitc.ptr<f32> to !emitc.ptr<!emitc.array<2xf32>>
   %0 = memref.alloca() : memref<2xf32>
   return
 }
 
 // -----
+// CHECK:         emitc.verbatim "\0A/* Generalized Indexing Template */
+// CHECK-SAME:\0Atemplate <typename T> constexpr T mt_index(T i_last)
+// CHECK-SAME: { return i_last; }\0Atemplate <typename T, typename... Args>
+// CHECK-SAME: \0Aconstexpr T mt_index(T idx, T stride, Args... rest)
+// CHECK-SAME: {\0A    return (idx * stride) + mt_index(rest...);\0A}\0A"
 
 // CHECK-LABEL: memref_store
-// CHECK-SAME:  %[[buff:.*]]: memref<4x8xf32>, %[[v:.*]]: f32, %[[i:.*]]: index, %[[j:.*]]: index
+// CHECK-SAME:   ([[BUFF:%.+]]: memref<4x8xf32>, [[PARAM_1_:%.+]]: f32, [[INDEX_1_:%.+]]: index, [[INDEX_2_:%.+]]: 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.ptr<!emitc.array<4x8xf32>>
-  
-  // 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>
+// CHECK-DAG:       [[BUFFER:%.+]] = builtin.unrealized_conversion_cast [[BUFF]] : memref<4x8xf32> to !emitc.ptr<!emitc.array<4x8xf32>>
+// CHECK-DAG:       [[CONST_1:%.+]] = "emitc.constant"() <{value = 8 : index}> : () -> index
+// CHECK-DAG:       [[CALL_OPAQUE:%.+]] = emitc.call_opaque "mt_index"([[INDEX_1_]], [[CONST_1]], [[INDEX_2_]]) : (index, index, index) -> index
+// CHECK-DAG:       [[CAST:%.+]] = emitc.cast [[BUFFER]] : !emitc.ptr<!emitc.array<4x8xf32>> to !emitc.ptr<f32>
+// CHECK:           [[SUBSCRIPT:%.+]] = emitc.subscript [[CAST]]{{.}}[[CALL_OPAQUE]]{{.}} : (!emitc.ptr<f32>, index) -> !emitc.lvalue<f32>
+// CHECK:           emitc.assign [[PARAM_1_]] : f32 to [[SUBSCRIPT]] : <f32>
+
   memref.store %v, %buff[%i, %j] : memref<4x8xf32>
   return
 }
@@ -31,13 +38,13 @@ 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.ptr<!emitc.array<4x8xf32>>
-  
-  // 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>
+// CHECK-DAG:       [[BUFFER:%.+]] = builtin.unrealized_conversion_cast %[[buff]] : memref<4x8xf32> to !emitc.ptr<!emitc.array<4x8xf32>>
+// CHECK-DAG:       [[CONST_1:%.+]] = "emitc.constant"() <{value = 8 : index}> : () -> index
+// CHECK-DAG:       [[CALL_OPAQUE:%.+]] = emitc.call_opaque "mt_index"(%[[i]], [[CONST_1]], %[[j]]) : (index, index, index) -> index
+// CHECK-DAG:       [[CAST:%.+]] = emitc.cast [[BUFFER]] : !emitc.ptr<!emitc.array<4x8xf32>> to !emitc.ptr<f32>
+// CHECK:           [[SUBSCRIPT:%.+]] = emitc.subscript [[CAST]]{{.}}[[CALL_OPAQUE]]{{.}} : (!emitc.ptr<f32>, index) -> !emitc.lvalue<f32>
+// CHECK:           [[LOAD_SUBSCRIPT:%.+]] = emitc.load [[SUBSCRIPT]] : <f32>
   %1 = memref.load %buff[%i, %j] : memref<4x8xf32>
-  // CHECK-NEXT: return %[[LOAD]] : f32
   return %1 : f32
 }
 
@@ -60,11 +67,11 @@ module @globals {
     // 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.address_of %3 : !emitc.lvalue<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 "&"(%6) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
+    // CHECK-NEXT: emitc.address_of %6 : !emitc.lvalue<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 1981a2ea3f34c..67b946d42a33f 100644
--- a/mlir/test/Target/Cpp/common-cpp.mlir
+++ b/mlir/test/Target/Cpp/common-cpp.mlir
@@ -93,13 +93,15 @@ 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: int32_t [[V2:[^ ]*]];
+  // CHECK-NEXT: int32_t* [[V2:[^ ]*]] = &[[V1]]
   %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: [[V2]] = *(&[[V1]]);
+  // CHECK-NEXT: [[V3]] = [[V4]];
   emitc.assign %3 : i32 to %2 : !emitc.lvalue<i32>
-  // CHECK-NEXT: return &[[V1]];
+  // CHECK-NEXT: return [[V2]];
   return %1 : !emitc.ptr<i32>
 }
 
diff --git a/mlir/test/Target/Cpp/lvalue.mlir b/mlir/test/Target/Cpp/lvalue.mlir
index 6197754a9faae..2f3f2cbdfb965 100644
--- a/mlir/test/Target/Cpp/lvalue.mlir
+++ b/mlir/test/Target/Cpp/lvalue.mlir
@@ -2,7 +2,7 @@
 
 emitc.func @lvalue_variables(%v1: i32, %v2: i32) -> i32 {
   %val = emitc.mul %v1, %v2 : (i32, i32) -> i32
-  %variable = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue<i32> 
+  %variable = "emitc.variable"() {value = #emitc.opaque<"">} : () -> !emitc.lvalue<i32>
   emitc.assign %val : i32 to %variable : !emitc.lvalue<i32>
   %addr = emitc.apply "&"(%variable) : (!emitc.lvalue<i32>) -> !emitc.ptr<i32>
   emitc.call @zero (%addr) : (!emitc.ptr<i32>) -> ()
@@ -16,11 +16,12 @@ 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: zero(&[[VAR]]);
-// CHECK-NEXT: int32_t [[VAR_LOAD:[^ ]*]] = [[VAR]]; 
-// CHECK-NEXT: int32_t [[NEG_ONE:[^ ]*]] = -1; 
+// CHECK: int32_t* [[VAR_PTR:.*]] = &[[VAR:.*]]
+// CHECK-NEXT: zero([[VAR_PTR]]);
+// CHECK: int32_t [[V6:[^ ]*]] = [[VAR:.*]];
+// CHECK-NEXT: int32_t [[NEG_ONE:[^ ]*]] = -1;
 // CHECK-NEXT: [[VAR]] = [[NEG_ONE]];
-// CHECK-NEXT: return [[VAR_LOAD]];
+// CHECK-NEXT: return [[V6]];
 
 
 emitc.func @zero(%arg0: !emitc.ptr<i32>) attributes {specifiers = ["extern"]}

>From 517e65ff58706fc262db29132f1126eb3f52c0da Mon Sep 17 00:00:00 2001
From: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
Date: Fri, 9 Jan 2026 17:33:09 +0530
Subject: [PATCH 6/6] modified the test file

Signed-off-by: LekkalaSravya3 <lekkala.sravya at multicorewareinc.com>
---
 mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp | 2 +-
 mlir/test/Target/Cpp/common-cpp.mlir                | 4 ++--
 mlir/test/Target/Cpp/lvalue.mlir                    | 6 +++---
 3 files changed, 6 insertions(+), 6 deletions(-)

diff --git a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
index 6b9f49755bbef..7f7f4025f1c0d 100644
--- a/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
+++ b/mlir/lib/Conversion/MemRefToEmitC/MemRefToEmitC.cpp
@@ -350,7 +350,7 @@ struct ConvertGetGlobal final
       auto arrayTy = emitc::ArrayType::get({1}, globalType);
       auto ptrArrayTy = emitc::PointerType::get(arrayTy);
       auto casted =
-          rewriter.create<emitc::CastOp>(loc, ptrArrayTy, addrOf.getResult());
+          emitc::CastOp::create(rewriter,loc, ptrArrayTy, addrOf.getResult());
       rewriter.replaceOp(op, casted.getResult());
       return success();
     }
diff --git a/mlir/test/Target/Cpp/common-cpp.mlir b/mlir/test/Target/Cpp/common-cpp.mlir
index 67b946d42a33f..ff6487defa96d 100644
--- a/mlir/test/Target/Cpp/common-cpp.mlir
+++ b/mlir/test/Target/Cpp/common-cpp.mlir
@@ -93,11 +93,11 @@ 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-NEXT: int32_t* [[V2:[^ ]*]] = &[[V1]];
   %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]]
+  // CHECK-NEXT: int32_t [[V4:[^ ]+]] = *[[V2]];
   %3 = emitc.apply "*"(%1) : (!emitc.ptr<i32>) -> i32
   // CHECK-NEXT: [[V3]] = [[V4]];
   emitc.assign %3 : i32 to %2 : !emitc.lvalue<i32>
diff --git a/mlir/test/Target/Cpp/lvalue.mlir b/mlir/test/Target/Cpp/lvalue.mlir
index 2f3f2cbdfb965..3cd36305e2d73 100644
--- a/mlir/test/Target/Cpp/lvalue.mlir
+++ b/mlir/test/Target/Cpp/lvalue.mlir
@@ -16,12 +16,12 @@ 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: int32_t* [[VAR_PTR:.*]] = &[[VAR:.*]]
+// CHECK: int32_t* [[VAR_PTR:.*]] = &[[VAR:.*]];
 // CHECK-NEXT: zero([[VAR_PTR]]);
-// CHECK: int32_t [[V6:[^ ]*]] = [[VAR:.*]];
+// CHECK: int32_t [[VAR_LOAD:[^ ]*]] = [[VAR:.*]];
 // CHECK-NEXT: int32_t [[NEG_ONE:[^ ]*]] = -1;
 // CHECK-NEXT: [[VAR]] = [[NEG_ONE]];
-// CHECK-NEXT: return [[V6]];
+// CHECK-NEXT: return [[VAR_LOAD]];
 
 
 emitc.func @zero(%arg0: !emitc.ptr<i32>) attributes {specifiers = ["extern"]}



More information about the Mlir-commits mailing list