[Mlir-commits] [mlir] [mlir][emitC] Add support to emitter for `classop`, `fieldop` and `getfieldop` (PR #145605)

Mircea Trofin llvmlistbot at llvm.org
Thu Jun 26 10:13:09 PDT 2025


https://github.com/mtrofin updated https://github.com/llvm/llvm-project/pull/145605

>From 0ab534fc3722b3244df74d0eacf8476087df81bd Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Tue, 24 Jun 2025 21:54:11 +0000
Subject: [PATCH 1/4] add trnalsation for classops, fieldops and getfieldops

---
 mlir/lib/Target/Cpp/TranslateToCpp.cpp       | 58 +++++++++++++++++++-
 mlir/test/mlir-translate/emitc_classops.mlir | 31 +++++++++++
 2 files changed, 88 insertions(+), 1 deletion(-)
 create mode 100644 mlir/test/mlir-translate/emitc_classops.mlir

diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 067a0470b14e4..9cd30eae8d36d 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -997,6 +997,61 @@ static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) {
   return success();
 }
 
+static LogicalResult printOperation(CppEmitter &emitter, ClassOp classOp) {
+  CppEmitter::Scope classScope(emitter);
+  raw_indented_ostream &os = emitter.ostream();
+  os << "class " << classOp.getSymName() << " final {\n";
+  os << "public:\n\n";
+
+  os.indent();
+  os << "const std::map<std::string, char*> _buffer_map {\n";
+  for (Operation &op : classOp) {
+    if (auto fieldOp = dyn_cast<FieldOp>(op))
+      os << "  { \"" << fieldOp.getSymName() << "\", reinterpret_cast<char*>(&"
+         << fieldOp.getAttrs() << ") },\n";
+  }
+  os << "};\n";
+
+  os << "char* getBufferForName(const std::string& name) const {\n";
+  os << "  auto it = _buffer_map.find(name);\n";
+  os << "  return (it == _buffer_map.end()) ? nullptr : it->second;\n";
+  os << "}\n\n";
+  for (Operation &op : classOp) {
+    if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false)))
+      return failure();
+  }
+
+  os.unindent();
+  os << "};";
+  return success();
+}
+
+static LogicalResult printOperation(CppEmitter &emitter, FieldOp fieldOp) {
+  raw_ostream &os = emitter.ostream();
+  if (failed(emitter.emitType(fieldOp->getLoc(), fieldOp.getType())))
+    return failure();
+  os << " " << fieldOp.getSymName() << ";";
+  return success();
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+                                    GetFieldOp getFieldOp) {
+  raw_indented_ostream &os = emitter.ostream();
+  Location loc = getFieldOp->getLoc();
+
+  if (getFieldOp->getNumResults() > 0) {
+    Value result = getFieldOp->getResult(0);
+    if (failed(emitter.emitType(loc, result.getType())))
+      return failure();
+    os << " ";
+    if (failed(emitter.emitOperand(result)))
+      return failure();
+    os << " = ";
+  }
+  os << getFieldOp.getFieldName().str();
+  return success();
+}
+
 static LogicalResult printOperation(CppEmitter &emitter, FileOp file) {
   if (!emitter.shouldEmitFile(file))
     return success();
@@ -1612,7 +1667,8 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
                 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>(
+                emitc::UnaryPlusOp, emitc::VariableOp, emitc::VerbatimOp,
+                emitc::ClassOp, emitc::FieldOp, emitc::GetFieldOp>(
 
               [&](auto op) { return printOperation(*this, op); })
           // Func ops.
diff --git a/mlir/test/mlir-translate/emitc_classops.mlir b/mlir/test/mlir-translate/emitc_classops.mlir
new file mode 100644
index 0000000000000..339eaaeb5d7cd
--- /dev/null
+++ b/mlir/test/mlir-translate/emitc_classops.mlir
@@ -0,0 +1,31 @@
+// RUN: mlir-translate --mlir-to-cpp %s | FileCheck %s
+
+emitc.class @modelClass {
+    emitc.field @input_tensor : !emitc.array<1xf32> 
+    emitc.func @execute() {
+        %0 = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t
+        %1 = get_field @input_tensor : !emitc.array<1xf32>
+        %2 = subscript %1[%0] : (!emitc.array<1xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
+        return
+    }
+}
+
+// CHECK: class modelClass final {
+// CHECK-NEXT: public:
+// CHECK-EMPTY:
+// CHECK-NEXT:  const std::map<std::string, char*> _buffer_map {
+// CHECK-NEXT:    { "input_tensor", reinterpret_cast<char*>(&None) },
+// CHECK-NEXT:  };
+// CHECK-NEXT:  char* getBufferForName(const std::string& name) const {
+// CHECK-NEXT:     auto it = _buffer_map.find(name);
+// CHECK-NEXT:     return (it == _buffer_map.end()) ? nullptr : it->second;
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
+// CHECK-NEXT:  float[1] input_tensor;
+// CHECK-NEXT:  void execute() {
+// CHECK-NEXT:    size_t v1 = 0;
+// CHECK-NEXT:    float[1] v2 = input_tensor;
+// CHECK-NEXT:    return;
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
+// CHECK-NEXT: };

>From 0d0aeb301b5182402f31eb9c852708697923219c Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Tue, 24 Jun 2025 22:10:36 +0000
Subject: [PATCH 2/4] Added arg to test

---
 mlir/test/mlir-translate/emitc_classops.mlir | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/mlir/test/mlir-translate/emitc_classops.mlir b/mlir/test/mlir-translate/emitc_classops.mlir
index 339eaaeb5d7cd..3232954f1149a 100644
--- a/mlir/test/mlir-translate/emitc_classops.mlir
+++ b/mlir/test/mlir-translate/emitc_classops.mlir
@@ -2,10 +2,12 @@
 
 emitc.class @modelClass {
     emitc.field @input_tensor : !emitc.array<1xf32> 
+    emitc.field @some_feature : !emitc.array<1xf32>  {emitc.opaque = ["some_feature"]}
     emitc.func @execute() {
         %0 = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t
         %1 = get_field @input_tensor : !emitc.array<1xf32>
-        %2 = subscript %1[%0] : (!emitc.array<1xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
+        %2 = get_field @some_feature : !emitc.array<1xf32>
+        %3 = subscript %1[%0] : (!emitc.array<1xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
         return
     }
 }
@@ -15,6 +17,7 @@ emitc.class @modelClass {
 // CHECK-EMPTY:
 // CHECK-NEXT:  const std::map<std::string, char*> _buffer_map {
 // CHECK-NEXT:    { "input_tensor", reinterpret_cast<char*>(&None) },
+// CHECK-NEXT:    { "some_feature", reinterpret_cast<char*>(&{emitc.opaque = ["some_feature"]}) }, 
 // CHECK-NEXT:  };
 // CHECK-NEXT:  char* getBufferForName(const std::string& name) const {
 // CHECK-NEXT:     auto it = _buffer_map.find(name);
@@ -22,9 +25,11 @@ emitc.class @modelClass {
 // CHECK-NEXT:  }
 // CHECK-EMPTY:
 // CHECK-NEXT:  float[1] input_tensor;
+// CHECK-NEXT:  float[1] some_feature;
 // CHECK-NEXT:  void execute() {
 // CHECK-NEXT:    size_t v1 = 0;
 // CHECK-NEXT:    float[1] v2 = input_tensor;
+// CHECK-NEXT:    float[1] v3 = some_feature;
 // CHECK-NEXT:    return;
 // CHECK-NEXT:  }
 // CHECK-EMPTY:

>From 812d4783c239963eac96c9934e28ef4d782b7f3d Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Wed, 25 Jun 2025 20:48:34 +0000
Subject: [PATCH 3/4] Simplify the classop translation

---
 mlir/lib/Target/Cpp/TranslateToCpp.cpp       | 38 ++++++++------------
 mlir/test/mlir-translate/emitc_classops.mlir | 28 +++++----------
 2 files changed, 23 insertions(+), 43 deletions(-)

diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 9cd30eae8d36d..f57c47d6b2fa4 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -9,6 +9,7 @@
 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
 #include "mlir/Dialect/EmitC/IR/EmitC.h"
 #include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/IR/Attributes.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/Dialect.h"
@@ -1000,22 +1001,10 @@ static LogicalResult printOperation(CppEmitter &emitter, ModuleOp moduleOp) {
 static LogicalResult printOperation(CppEmitter &emitter, ClassOp classOp) {
   CppEmitter::Scope classScope(emitter);
   raw_indented_ostream &os = emitter.ostream();
-  os << "class " << classOp.getSymName() << " final {\n";
-  os << "public:\n\n";
-
+  os << "class " << classOp.getSymName() << " {\n";
+  os << "public:\n";
   os.indent();
-  os << "const std::map<std::string, char*> _buffer_map {\n";
-  for (Operation &op : classOp) {
-    if (auto fieldOp = dyn_cast<FieldOp>(op))
-      os << "  { \"" << fieldOp.getSymName() << "\", reinterpret_cast<char*>(&"
-         << fieldOp.getAttrs() << ") },\n";
-  }
-  os << "};\n";
-
-  os << "char* getBufferForName(const std::string& name) const {\n";
-  os << "  auto it = _buffer_map.find(name);\n";
-  os << "  return (it == _buffer_map.end()) ? nullptr : it->second;\n";
-  os << "}\n\n";
+  
   for (Operation &op : classOp) {
     if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false)))
       return failure();
@@ -1660,15 +1649,16 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
                 emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
                 emitc::BitwiseNotOp, emitc::BitwiseOrOp,
                 emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
-                emitc::CallOpaqueOp, emitc::CastOp, emitc::CmpOp,
-                emitc::ConditionalOp, emitc::ConstantOp, emitc::DeclareFuncOp,
-                emitc::DivOp, emitc::ExpressionOp, 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,
-                emitc::ClassOp, emitc::FieldOp, emitc::GetFieldOp>(
+                emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
+                emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
+                emitc::DeclareFuncOp, emitc::DivOp, emitc::ExpressionOp,
+                emitc::FieldOp, emitc::FileOp, emitc::ForOp, emitc::FuncOp,
+                emitc::GetFieldOp, 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.
diff --git a/mlir/test/mlir-translate/emitc_classops.mlir b/mlir/test/mlir-translate/emitc_classops.mlir
index 3232954f1149a..e42844412860e 100644
--- a/mlir/test/mlir-translate/emitc_classops.mlir
+++ b/mlir/test/mlir-translate/emitc_classops.mlir
@@ -1,35 +1,25 @@
 // RUN: mlir-translate --mlir-to-cpp %s | FileCheck %s
 
 emitc.class @modelClass {
-    emitc.field @input_tensor : !emitc.array<1xf32> 
-    emitc.field @some_feature : !emitc.array<1xf32>  {emitc.opaque = ["some_feature"]}
+    emitc.field @fieldName0 : !emitc.array<1xf32> 
+    emitc.field @fieldName1 : !emitc.array<1xf32> 
     emitc.func @execute() {
         %0 = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t
-        %1 = get_field @input_tensor : !emitc.array<1xf32>
-        %2 = get_field @some_feature : !emitc.array<1xf32>
+        %1 = get_field @fieldName0 : !emitc.array<1xf32>
+        %2 = get_field @fieldName1 : !emitc.array<1xf32>
         %3 = subscript %1[%0] : (!emitc.array<1xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
         return
     }
 }
 
-// CHECK: class modelClass final {
+// CHECK: class modelClass {
 // CHECK-NEXT: public:
-// CHECK-EMPTY:
-// CHECK-NEXT:  const std::map<std::string, char*> _buffer_map {
-// CHECK-NEXT:    { "input_tensor", reinterpret_cast<char*>(&None) },
-// CHECK-NEXT:    { "some_feature", reinterpret_cast<char*>(&{emitc.opaque = ["some_feature"]}) }, 
-// CHECK-NEXT:  };
-// CHECK-NEXT:  char* getBufferForName(const std::string& name) const {
-// CHECK-NEXT:     auto it = _buffer_map.find(name);
-// CHECK-NEXT:     return (it == _buffer_map.end()) ? nullptr : it->second;
-// CHECK-NEXT:  }
-// CHECK-EMPTY:
-// CHECK-NEXT:  float[1] input_tensor;
-// CHECK-NEXT:  float[1] some_feature;
+// CHECK-NEXT:  float[1] fieldName0;
+// CHECK-NEXT:  float[1] fieldName1;
 // CHECK-NEXT:  void execute() {
 // CHECK-NEXT:    size_t v1 = 0;
-// CHECK-NEXT:    float[1] v2 = input_tensor;
-// CHECK-NEXT:    float[1] v3 = some_feature;
+// CHECK-NEXT:    float[1] v2 = fieldName0;
+// CHECK-NEXT:    float[1] v3 = fieldName1;
 // CHECK-NEXT:    return;
 // CHECK-NEXT:  }
 // CHECK-EMPTY:

>From d1e4a7ee1aff534b42f89b0fd357a14544d929fd Mon Sep 17 00:00:00 2001
From: Jaddyen <ajaden at google.com>
Date: Wed, 25 Jun 2025 20:51:31 +0000
Subject: [PATCH 4/4] Remove unnecessary include

---
 mlir/lib/Target/Cpp/TranslateToCpp.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index f57c47d6b2fa4..15624934687b7 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -9,7 +9,6 @@
 #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h"
 #include "mlir/Dialect/EmitC/IR/EmitC.h"
 #include "mlir/Dialect/Func/IR/FuncOps.h"
-#include "mlir/IR/Attributes.h"
 #include "mlir/IR/BuiltinOps.h"
 #include "mlir/IR/BuiltinTypes.h"
 #include "mlir/IR/Dialect.h"
@@ -1004,7 +1003,7 @@ static LogicalResult printOperation(CppEmitter &emitter, ClassOp classOp) {
   os << "class " << classOp.getSymName() << " {\n";
   os << "public:\n";
   os.indent();
-  
+
   for (Operation &op : classOp) {
     if (failed(emitter.emitOperation(op, /*trailingSemicolon=*/false)))
       return failure();



More information about the Mlir-commits mailing list