[Mlir-commits] [mlir] [mlir][EmitC] Update WrapFunInClassPass pass (PR #203641)

Bhavesh M llvmlistbot at llvm.org
Mon Jun 15 20:06:04 PDT 2026


https://github.com/beamandala updated https://github.com/llvm/llvm-project/pull/203641

>From fd26cea397f33b844ccb36409189bab4a045120c Mon Sep 17 00:00:00 2001
From: Bhavesh Mandalapu <bmandalapu at google.com>
Date: Fri, 12 Jun 2026 13:59:38 -0700
Subject: [PATCH 1/2] [mlir][EmitC] Update WrapFunInClassPass pass

Update the `WrapFuncInClassPass` pass so that `GlobalOp`s are moved into
the `ClassOp` as `FieldOps`. This respects MLIR's behavior of resolving
references to the closest parent operation that defines a symbol table
which is the `ClassOp` that we are creating in this pass.

Details:
- Identify `GlobalOp`s
- Create a `FieldOp` within the `ClassOp` for each `GlobalOp`
- Delete the `GlobalOp`s after all functions have been wrapped in a
  class. Doing this after every function can cause an error when
multiple functions refer to the same `GlobalOp`(s) which would be
deleted after the first function is wrapped in a class.

Also renamed `fName` parameter in `populateWrapFuncInClass` to
`funcName` to match naming in `WrapFuncInClass`.
---
 .../mlir/Dialect/EmitC/Transforms/Passes.td   |  2 +-
 .../Dialect/EmitC/Transforms/Transforms.h     |  3 +-
 .../EmitC/Transforms/WrapFuncInClass.cpp      | 43 +++++++++++++++----
 .../Dialect/EmitC/wrap-func-in-class.mlir     | 22 ++++++++++
 4 files changed, 60 insertions(+), 10 deletions(-)

diff --git a/mlir/include/mlir/Dialect/EmitC/Transforms/Passes.td b/mlir/include/mlir/Dialect/EmitC/Transforms/Passes.td
index 40ecef33448d7..c34c3303a6ab3 100644
--- a/mlir/include/mlir/Dialect/EmitC/Transforms/Passes.td
+++ b/mlir/include/mlir/Dialect/EmitC/Transforms/Passes.td
@@ -20,7 +20,7 @@ def FormExpressionsPass : Pass<"form-expressions"> {
   let dependentDialects = ["emitc::EmitCDialect"];
 }
 
-def WrapFuncInClassPass : Pass<"wrap-emitc-func-in-class"> {
+def WrapFuncInClassPass : Pass<"wrap-emitc-func-in-class", "ModuleOp"> {
   let summary = "Wrap functions in classes, using arguments as fields.";
   let description = [{
     This pass transforms `emitc.func` operations into `emitc.class` operations.
diff --git a/mlir/include/mlir/Dialect/EmitC/Transforms/Transforms.h b/mlir/include/mlir/Dialect/EmitC/Transforms/Transforms.h
index 962bdb3c032bf..117a1ef9e2e61 100644
--- a/mlir/include/mlir/Dialect/EmitC/Transforms/Transforms.h
+++ b/mlir/include/mlir/Dialect/EmitC/Transforms/Transforms.h
@@ -32,7 +32,8 @@ void populateExpressionPatterns(RewritePatternSet &patterns);
 // The WrapFuncInClass pass.
 //===----------------------------------------------------------------------===//
 
-void populateWrapFuncInClass(RewritePatternSet &patterns, StringRef fName);
+void populateWrapFuncInClass(RewritePatternSet &patterns, StringRef funcName,
+                             llvm::SmallVector<emitc::GlobalOp> &globalsToMove);
 
 } // namespace emitc
 } // namespace mlir
diff --git a/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp b/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
index fc8acd616ba70..7f1b9ea95212d 100644
--- a/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
+++ b/mlir/lib/Dialect/EmitC/Transforms/WrapFuncInClass.cpp
@@ -28,12 +28,21 @@ struct WrapFuncInClassPass
     : public impl::WrapFuncInClassPassBase<WrapFuncInClassPass> {
   using WrapFuncInClassPassBase::WrapFuncInClassPassBase;
   void runOnOperation() override {
-    Operation *rootOp = getOperation();
+    mlir::ModuleOp moduleOp = getOperation();
+
+    llvm::SmallVector<emitc::GlobalOp> globalsToMove;
+    moduleOp.walk(
+        [&](mlir::emitc::GlobalOp op) { globalsToMove.push_back(op); });
 
     RewritePatternSet patterns(&getContext());
-    populateWrapFuncInClass(patterns, funcName);
+    populateWrapFuncInClass(patterns, funcName, globalsToMove);
+
+    walkAndApplyPatterns(moduleOp, std::move(patterns));
 
-    walkAndApplyPatterns(rootOp, std::move(patterns));
+    for (GlobalOp globalOp : globalsToMove) {
+      if (globalOp)
+        globalOp.erase();
+    }
   }
 };
 
@@ -43,8 +52,10 @@ struct WrapFuncInClassPass
 
 class WrapFuncInClass : public OpRewritePattern<emitc::FuncOp> {
 public:
-  WrapFuncInClass(MLIRContext *context, StringRef funcName)
-      : OpRewritePattern<emitc::FuncOp>(context), funcName(funcName) {}
+  WrapFuncInClass(MLIRContext *context, StringRef funcName,
+                  llvm::SmallVector<emitc::GlobalOp> &globalsToMove)
+      : OpRewritePattern<emitc::FuncOp>(context), funcName(funcName),
+        globalsToMove(globalsToMove) {}
 
   LogicalResult matchAndRewrite(emitc::FuncOp funcOp,
                                 PatternRewriter &rewriter) const override {
@@ -72,6 +83,12 @@ class WrapFuncInClass : public OpRewritePattern<emitc::FuncOp> {
       }
     }
 
+    for (GlobalOp globalOp : globalsToMove) {
+      emitc::FieldOp::create(rewriter, funcOp->getLoc(),
+                             globalOp.getSymNameAttr(), globalOp.getTypeAttr(),
+                             globalOp.getInitialValueAttr());
+    }
+
     rewriter.setInsertionPointToEnd(&newClassOp.getBody().front());
     FunctionType funcType = funcOp.getFunctionType();
     Location loc = funcOp.getLoc();
@@ -99,6 +116,14 @@ class WrapFuncInClass : public OpRewritePattern<emitc::FuncOp> {
     if (failed(newFuncOp.eraseArguments(argsToErase)))
       newFuncOp->emitOpError("failed to erase all arguments using BitVector");
 
+    newFuncOp.walk([&](emitc::GetGlobalOp getGlobalOp) {
+      rewriter.setInsertionPoint(getGlobalOp);
+      emitc::GetFieldOp getFieldOp = emitc::GetFieldOp::create(
+          rewriter, getGlobalOp.getLoc(), getGlobalOp.getType(),
+          getGlobalOp.getNameAttr());
+      rewriter.replaceOp(getGlobalOp, getFieldOp);
+    });
+
     rewriter.replaceOp(funcOp, newClassOp);
     return success();
   }
@@ -107,9 +132,11 @@ class WrapFuncInClass : public OpRewritePattern<emitc::FuncOp> {
   /// Name of the newly generated member function with body matching the input
   /// function.
   std::string funcName;
+  llvm::SmallVector<emitc::GlobalOp> globalsToMove;
 };
 
-void mlir::emitc::populateWrapFuncInClass(RewritePatternSet &patterns,
-                                          StringRef funcName) {
-  patterns.add<WrapFuncInClass>(patterns.getContext(), funcName);
+void mlir::emitc::populateWrapFuncInClass(
+    RewritePatternSet &patterns, StringRef funcName,
+    llvm::SmallVector<emitc::GlobalOp> &globalsToMove) {
+  patterns.add<WrapFuncInClass>(patterns.getContext(), funcName, globalsToMove);
 }
diff --git a/mlir/test/Dialect/EmitC/wrap-func-in-class.mlir b/mlir/test/Dialect/EmitC/wrap-func-in-class.mlir
index cb5f99d31e9da..bdf13ce4df8a4 100644
--- a/mlir/test/Dialect/EmitC/wrap-func-in-class.mlir
+++ b/mlir/test/Dialect/EmitC/wrap-func-in-class.mlir
@@ -1,5 +1,6 @@
 // RUN: mlir-opt %s -wrap-emitc-func-in-class -split-input-file | FileCheck %s
 // RUN: mlir-opt %s -wrap-emitc-func-in-class=func-name=execute -split-input-file | FileCheck %s --check-prefixes=EXECUTE
+// RUN: mlir-opt %s -wrap-emitc-func-in-class -split-input-file | FileCheck %s
 
 emitc.func @foo(%arg0 : !emitc.array<1xf32>) {
   emitc.call_opaque "bar" (%arg0) : (!emitc.array<1xf32>) -> ()
@@ -58,3 +59,24 @@ module attributes { } {
 
 // EXECUTE-NOT: operator
 // EXECUTE: execute()
+
+// -----
+
+module attributes { } {
+  emitc.global static const @global_arr : !emitc.array<1xi8> = dense<0>
+  emitc.func @foo() {
+    %0 = emitc.get_global @global_arr : !emitc.array<1xi8>
+    emitc.return
+  }
+}
+
+// CHECK:   emitc.class @fooClass {
+// CHECK:     emitc.field @global_arr : !emitc.array<1xi8> = dense<0>
+// CHECK:     emitc.func @"operator()"() {
+// CHECK:       %0 = get_field @global_arr : !emitc.array<1xi8>
+// CHECK:       return
+// CHECK:     }
+// CHECK:   }
+
+// EXECUTE-NOT: operator
+// EXECUTE: execute()

>From 78743f04b2ae5864c5ef01beab7d4dc49a351ee8 Mon Sep 17 00:00:00 2001
From: Bhavesh Mandalapu <bmandalapu at google.com>
Date: Mon, 15 Jun 2026 10:43:03 -0700
Subject: [PATCH 2/2] Remove redundant RUN

---
 mlir/test/Dialect/EmitC/wrap-func-in-class.mlir | 1 -
 1 file changed, 1 deletion(-)

diff --git a/mlir/test/Dialect/EmitC/wrap-func-in-class.mlir b/mlir/test/Dialect/EmitC/wrap-func-in-class.mlir
index bdf13ce4df8a4..fca24c7a1cba1 100644
--- a/mlir/test/Dialect/EmitC/wrap-func-in-class.mlir
+++ b/mlir/test/Dialect/EmitC/wrap-func-in-class.mlir
@@ -1,6 +1,5 @@
 // RUN: mlir-opt %s -wrap-emitc-func-in-class -split-input-file | FileCheck %s
 // RUN: mlir-opt %s -wrap-emitc-func-in-class=func-name=execute -split-input-file | FileCheck %s --check-prefixes=EXECUTE
-// RUN: mlir-opt %s -wrap-emitc-func-in-class -split-input-file | FileCheck %s
 
 emitc.func @foo(%arg0 : !emitc.array<1xf32>) {
   emitc.call_opaque "bar" (%arg0) : (!emitc.array<1xf32>) -> ()



More information about the Mlir-commits mailing list