[Mlir-commits] [mlir] [MLIR][EmitC] Mark CastOp as Pure (PR #202749)

Andrzej WarzyƄski llvmlistbot at llvm.org
Wed Jun 10 09:48:01 PDT 2026


https://github.com/banach-space updated https://github.com/llvm/llvm-project/pull/202749

>From 36c29b3fe2bfe6581cb4d0a3064056b9fcc89d81 Mon Sep 17 00:00:00 2001
From: Andrzej Warzynski <andrzej.warzynski at arm.com>
Date: Tue, 9 Jun 2026 19:39:51 +0000
Subject: [PATCH 1/2] [MLIR][EmitC] Mark CastOp as Pure

---
 mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 2 +-
 mlir/test/Dialect/EmitC/canonicalize.mlir   | 9 +++++++++
 2 files changed, 10 insertions(+), 1 deletion(-)
 create mode 100644 mlir/test/Dialect/EmitC/canonicalize.mlir

diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 65361a987a08e..09fad02da39b2 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -394,7 +394,7 @@ def EmitC_MemberCallOpaqueOp : EmitC_Op<"member_call_opaque", [CExpressionInterf
 }
 
 def EmitC_CastOp : EmitC_Op<"cast",
-    [CExpressionInterface,
+    [Pure, CExpressionInterface,
      DeclareOpInterfaceMethods<CastOpInterface>]> {
   let summary = "Cast operation";
   let description = [{
diff --git a/mlir/test/Dialect/EmitC/canonicalize.mlir b/mlir/test/Dialect/EmitC/canonicalize.mlir
new file mode 100644
index 0000000000000..a2c41375da398
--- /dev/null
+++ b/mlir/test/Dialect/EmitC/canonicalize.mlir
@@ -0,0 +1,9 @@
+// RUN: mlir-opt %s -canonicalize="test-convergence" -split-input-file | FileCheck %s
+
+// While there is no dedicated folder for CastOp, it is Pure and hence should
+// be "folded away".
+func.func @cast(%arg0: i32) {
+  // CHECK-NOT: emitc.cast
+  %1 = emitc.cast %arg0: i32 to f32
+  return
+}

>From 055d86ac70f53316bae75f4874a1d2cbcac64f54 Mon Sep 17 00:00:00 2001
From: Andrzej Warzynski <andrzej.warzynski at arm.com>
Date: Wed, 10 Jun 2026 16:47:36 +0000
Subject: [PATCH 2/2] Swich from unconditional PURE to opt-in

---
 mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 14 +++++++++++---
 mlir/lib/Dialect/EmitC/IR/EmitC.cpp         | 15 +++++++++++++++
 mlir/test/Dialect/EmitC/canonicalize.mlir   | 12 ++++++++----
 3 files changed, 34 insertions(+), 7 deletions(-)

diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 09fad02da39b2..4527afeedc346 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -394,8 +394,11 @@ def EmitC_MemberCallOpaqueOp : EmitC_Op<"member_call_opaque", [CExpressionInterf
 }
 
 def EmitC_CastOp : EmitC_Op<"cast",
-    [Pure, CExpressionInterface,
-     DeclareOpInterfaceMethods<CastOpInterface>]> {
+    [CExpressionInterface,
+     DeclareOpInterfaceMethods<CastOpInterface>,
+     DeclareOpInterfaceMethods<ConditionallySpeculatable>,
+     DeclareOpInterfaceMethods<MemoryEffectsOpInterface>
+    ]> {
   let summary = "Cast operation";
   let description = [{
     The `emitc.cast` operation performs an explicit type conversion and is emitted
@@ -414,7 +417,10 @@ def EmitC_CastOp : EmitC_Op<"cast",
     ```
   }];
 
-  let arguments = (ins EmitCType:$source);
+  let arguments = (ins EmitCType:$source,
+    UnitAttr:$pure
+  );
+
   let results = (outs EmitCType:$dest);
   let assemblyFormat = "$source attr-dict `:` type($source) `to` type($dest)";
 
@@ -422,6 +428,8 @@ def EmitC_CastOp : EmitC_Op<"cast",
     bool hasSideEffects() {
       return false;
     }
+
+    bool isPure();
   }];
 }
 
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index bab9cb4a91102..288ab0fe5215f 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -336,6 +336,21 @@ bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
        emitc::isSupportedFloatType(output) || isa<emitc::PointerType>(output)));
 }
 
+bool CastOp::isPure() { return static_cast<bool>(getPureAttr()); }
+
+Speculation::Speculatability emitc::CastOp::getSpeculatability() {
+  return getPure() ? Speculation::Speculatable : Speculation::NotSpeculatable;
+}
+
+void emitc::CastOp::getEffects(
+    SmallVectorImpl<MemoryEffects::EffectInstance> &effects) {
+  if (getPure())
+    return;
+
+  effects.emplace_back(MemoryEffects::Read::get());
+  effects.emplace_back(MemoryEffects::Write::get());
+}
+
 //===----------------------------------------------------------------------===//
 // CallOpaqueOp
 //===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/EmitC/canonicalize.mlir b/mlir/test/Dialect/EmitC/canonicalize.mlir
index a2c41375da398..29d2fd157229d 100644
--- a/mlir/test/Dialect/EmitC/canonicalize.mlir
+++ b/mlir/test/Dialect/EmitC/canonicalize.mlir
@@ -1,9 +1,13 @@
 // RUN: mlir-opt %s -canonicalize="test-convergence" -split-input-file | FileCheck %s
 
-// While there is no dedicated folder for CastOp, it is Pure and hence should
-// be "folded away".
-func.func @cast(%arg0: i32) {
-  // CHECK-NOT: emitc.cast
+func.func @no_fold_cast_to_f32(%arg0: i32) {
+  // CHECK: emitc.cast
   %1 = emitc.cast %arg0: i32 to f32
   return
 }
+
+func.func @fold_cast_to_i64(%arg0: i32) {
+  // CHECK-NOT: emitc.cast
+  %1 = emitc.cast %arg0 {pure} : i32 to i64
+  return
+}



More information about the Mlir-commits mailing list