Skip to content

Addfinal specifier to the classop #145977

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

Jaddyen
Copy link
Contributor

@Jaddyen Jaddyen commented Jun 26, 2025

In some use cases of the ClassOp, eg MLGO, we would like to be able to declare the class as final. This specifier allows for that.

@@ -1,6 +1,6 @@
// RUN: mlir-translate --mlir-to-cpp %s | FileCheck %s

emitc.class @modelClass {
emitc.class final @modelClass {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd add a separate test for final. Otherwise lgtm

@Jaddyen Jaddyen marked this pull request as ready for review June 26, 2025 22:16
@llvmbot
Copy link
Member

llvmbot commented Jun 26, 2025

@llvm/pr-subscribers-mlir-emitc

@llvm/pr-subscribers-mlir

Author: Jaden Angella (Jaddyen)

Changes

In some use cases of the ClassOp, eg MLGO, we would like to be able to declare the class as final. This specifier allows for that.


Full diff: https://github.com/llvm/llvm-project/pull/145977.diff

3 Files Affected:

  • (modified) mlir/include/mlir/Dialect/EmitC/IR/EmitC.td (+13-2)
  • (modified) mlir/lib/Target/Cpp/TranslateToCpp.cpp (+4-2)
  • (modified) mlir/test/mlir-translate/emitc_classops.mlir (+27-2)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 91ee89919e58e..7fe2da8f7e044 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -1618,10 +1618,20 @@ def EmitC_ClassOp
         return
       }
     }
+    // Class with a final speciferAdd commentMore actions
+    emitc.class final @modelClass {
+      emitc.field @fieldName0 : !emitc.array<1xf32> = {emitc.opaque = "input_tensor"}
+      emitc.func @execute() {
+        %0 = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t
+        %1 = get_field @fieldName0 : !emitc.array<1xf32>
+        %2 = subscript %1[%0] : (!emitc.array<1xf32>, !emitc.size_t) -> !emitc.lvalue<f32>
+        return
+      }
+    }
     ```
   }];
 
-  let arguments = (ins SymbolNameAttr:$sym_name);
+  let arguments = (ins SymbolNameAttr:$sym_name, UnitAttr:$final_specifier);
 
   let regions = (region AnyRegion:$body);
 
@@ -1632,7 +1642,8 @@ def EmitC_ClassOp
 
   let hasCustomAssemblyFormat = 1;
 
-  let assemblyFormat = [{ $sym_name attr-dict-with-keyword $body }];
+  let assemblyFormat =
+      [{ (`final` $final_specifier^)? $sym_name attr-dict-with-keyword $body }];
 }
 
 def EmitC_FieldOp : EmitC_Op<"field", [Symbol]> {
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index c04548688bcf6..ab91b32d7ef43 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -1000,8 +1000,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() << " {\n";
-  os << "public:\n";
+  os << "class " << classOp.getSymName();
+  if (classOp.getFinalSpecifier())
+    os << " final";
+  os << " {\n public:\n";
   os.indent();
 
   for (Operation &op : classOp) {
diff --git a/mlir/test/mlir-translate/emitc_classops.mlir b/mlir/test/mlir-translate/emitc_classops.mlir
index e42844412860e..adaf79313868e 100644
--- a/mlir/test/mlir-translate/emitc_classops.mlir
+++ b/mlir/test/mlir-translate/emitc_classops.mlir
@@ -1,4 +1,4 @@
-// RUN: mlir-translate --mlir-to-cpp %s | FileCheck %s
+// RUN: mlir-translate --mlir-to-cpp -split-input-file %s | FileCheck %s
 
 emitc.class @modelClass {
     emitc.field @fieldName0 : !emitc.array<1xf32> 
@@ -12,7 +12,32 @@ emitc.class @modelClass {
     }
 }
 
-// CHECK: class modelClass {
+// CHECK-LABEL: class modelClass {
+// CHECK-NEXT: public:
+// 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 = fieldName0;
+// CHECK-NEXT:    float[1] v3 = fieldName1;
+// CHECK-NEXT:    return;
+// CHECK-NEXT:  }
+// CHECK-EMPTY:
+// CHECK-NEXT: };
+
+emitc.class final @finalClass {
+    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 @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-LABEL: class finalClass final {
 // CHECK-NEXT: public:
 // CHECK-NEXT:  float[1] fieldName0;
 // CHECK-NEXT:  float[1] fieldName1;

@@ -1,4 +1,4 @@
// RUN: mlir-translate --mlir-to-cpp %s | FileCheck %s
// RUN: mlir-translate --mlir-to-cpp -split-input-file %s | FileCheck %s
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why do you need to split-input-file?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i dont!
thanks for pointing this out.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants