[Mlir-commits] [mlir] [mlir][emitc] Add increment and decrement ops (PR #208648)

Jianjian Guan llvmlistbot at llvm.org
Fri Jul 10 01:22:03 PDT 2026


https://github.com/jacquesguan created https://github.com/llvm/llvm-project/pull/208648

None

>From 8211ec080fa7d8436e533a33caecdc365c6e9d63 Mon Sep 17 00:00:00 2001
From: Jianjian GUAN <jacquesguan at me.com>
Date: Fri, 10 Jul 2026 14:59:57 +0800
Subject: [PATCH] [mlir][emitc] Add increment and decrement ops

---
 mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 45 +++++++++++++++++++
 mlir/lib/Target/Cpp/TranslateToCpp.cpp      | 48 ++++++++++++++++++++-
 mlir/test/Dialect/EmitC/invalid_ops.mlir    | 16 +++++++
 mlir/test/Dialect/EmitC/ops.mlir            |  9 ++++
 mlir/test/Target/Cpp/common-cpp.mlir        | 35 +++++++++++++++
 5 files changed, 152 insertions(+), 1 deletion(-)

diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index d42c74e963769..c52f5b5f909c4 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -65,6 +65,39 @@ class EmitC_BinaryOp<string mnemonic, list<Trait> traits = []> :
   }];
 }
 
+// Base class for increment and decrement operations.
+class EmitC_IncDecOp<string mnemonic, string summaryStr>
+    : EmitC_Op<mnemonic, [
+        CExpressionInterface,
+        TypesMatchWith<"input and result reference the same type",
+                       "operand", "result",
+                       "::llvm::cast<emitc::LValueType>($_self).getValueType()">
+      ]> {
+  let summary = summaryStr;
+  let description = [{
+    This operation models a C/C++ increment or decrement operator on an lvalue.
+
+    Example:
+
+    ```mlir
+    %0 = emitc.pre_increment %arg0 : !emitc.lvalue<i32>
+    ```
+  }];
+
+  let arguments = (ins
+    Res<EmitC_LValueType, "",
+        [MemRead<DefaultResource, 0, FullEffect>,
+         MemWrite<DefaultResource, 0, FullEffect>]>:$operand);
+  let results = (outs EmitCType:$result);
+  let assemblyFormat = "$operand attr-dict `:` type($operand)";
+
+  let extraClassDeclaration = [{
+    bool hasSideEffects() {
+      return true;
+    }
+  }];
+}
+
 // Types only used in binary arithmetic operations.
 def IntegerIndexOrOpaqueType : Type<CPred<"emitc::isIntegerIndexOrOpaqueType($_self)">,
 "integer, index or opaque type supported by EmitC">;
@@ -1259,6 +1292,18 @@ def EmitC_ConditionalOp : EmitC_Op<"conditional",
   }];
 }
 
+def EmitC_PreIncrementOp
+    : EmitC_IncDecOp<"pre_increment", "Pre-increment operation">;
+
+def EmitC_PostIncrementOp
+    : EmitC_IncDecOp<"post_increment", "Post-increment operation">;
+
+def EmitC_PreDecrementOp
+    : EmitC_IncDecOp<"pre_decrement", "Pre-decrement operation">;
+
+def EmitC_PostDecrementOp
+    : EmitC_IncDecOp<"post_decrement", "Post-decrement operation">;
+
 def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", []> {
   let summary = "Unary minus operation";
   let description = [{
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 1bf87e4994d67..5ae51bd580d31 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -112,6 +112,10 @@ static FailureOr<int> getOperatorPrecedence(Operation *operation) {
       .Case([&](emitc::MemberOfPtrOp op) { return 17; })
       .Case([&](emitc::MemberOp op) { return 17; })
       .Case([&](emitc::MulOp op) { return 13; })
+      .Case([&](emitc::PostDecrementOp op) { return 16; })
+      .Case([&](emitc::PostIncrementOp op) { return 16; })
+      .Case([&](emitc::PreDecrementOp op) { return 15; })
+      .Case([&](emitc::PreIncrementOp op) { return 15; })
       .Case([&](emitc::RemOp op) { return 13; })
       .Case([&](emitc::SubOp op) { return 12; })
       .Case([&](emitc::SubscriptOp op) { return 17; })
@@ -646,6 +650,22 @@ static LogicalResult printUnaryOperation(CppEmitter &emitter,
   return success();
 }
 
+static LogicalResult printPostfixUnaryOperation(CppEmitter &emitter,
+                                                Operation *operation,
+                                                StringRef unaryOperator) {
+  raw_ostream &os = emitter.ostream();
+
+  if (failed(emitter.emitAssignPrefix(*operation)))
+    return failure();
+
+  if (failed(emitter.emitOperand(operation->getOperand(0))))
+    return failure();
+
+  os << unaryOperator;
+
+  return success();
+}
+
 static LogicalResult printOperation(CppEmitter &emitter, emitc::AddOp addOp) {
   Operation *operation = addOp.getOperation();
 
@@ -1038,6 +1058,30 @@ static LogicalResult printOperation(CppEmitter &emitter,
   return printBinaryOperation(emitter, operation, "^");
 }
 
+static LogicalResult printOperation(CppEmitter &emitter,
+                                    emitc::PreIncrementOp preIncrementOp) {
+  Operation *operation = preIncrementOp.getOperation();
+  return printUnaryOperation(emitter, operation, "++");
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+                                    emitc::PostIncrementOp postIncrementOp) {
+  Operation *operation = postIncrementOp.getOperation();
+  return printPostfixUnaryOperation(emitter, operation, "++");
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+                                    emitc::PreDecrementOp preDecrementOp) {
+  Operation *operation = preDecrementOp.getOperation();
+  return printUnaryOperation(emitter, operation, "--");
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+                                    emitc::PostDecrementOp postDecrementOp) {
+  Operation *operation = postDecrementOp.getOperation();
+  return printPostfixUnaryOperation(emitter, operation, "--");
+}
+
 static LogicalResult printOperation(CppEmitter &emitter,
                                     emitc::UnaryPlusOp unaryPlusOp) {
   Operation *operation = unaryPlusOp.getOperation();
@@ -1896,7 +1940,9 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
                 emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,
                 emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
                 emitc::MemberCallOpaqueOp, emitc::MemberOfPtrOp,
-                emitc::MemberOp, emitc::MulOp, emitc::RemOp, emitc::ReturnOp,
+                emitc::MemberOp, emitc::MulOp, emitc::PostDecrementOp,
+                emitc::PostIncrementOp, emitc::PreDecrementOp,
+                emitc::PreIncrementOp, emitc::RemOp, emitc::ReturnOp,
                 emitc::SubscriptOp, emitc::SubOp, emitc::SwitchOp,
                 emitc::UnaryMinusOp, emitc::UnaryPlusOp, emitc::VariableOp,
                 emitc::VerbatimOp>(
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index eacf4fdedcbd3..3048160d1590c 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -981,3 +981,19 @@ func.func @dereference(%arg0: !emitc.ptr<i32>) {
   %1 = "emitc.dereference"(%arg0) : (!emitc.ptr<i32>) -> !emitc.lvalue<i8>
   return
 }
+
+// -----
+
+func.func @pre_increment_unmatch_type(%arg0: !emitc.lvalue<i32>) {
+  // expected-error @+1 {{failed to verify that input and result reference the same type}}
+  %1 = "emitc.pre_increment"(%arg0) : (!emitc.lvalue<i32>) -> i8
+  return
+}
+
+// -----
+
+func.func @post_decrement_unmatch_type(%arg0: !emitc.lvalue<i32>) {
+  // expected-error @+1 {{failed to verify that input and result reference the same type}}
+  %1 = "emitc.post_decrement"(%arg0) : (!emitc.lvalue<i32>) -> i8
+  return
+}
diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir
index e456db4634892..e5c4af67c4896 100644
--- a/mlir/test/Dialect/EmitC/ops.mlir
+++ b/mlir/test/Dialect/EmitC/ops.mlir
@@ -148,6 +148,15 @@ func.func @unary(%arg0: i32) {
   return
 }
 
+func.func @inc_dec(%arg0: !emitc.ptr<i32>) {
+  %v = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
+  %0 = emitc.pre_increment %v : !emitc.lvalue<i32>
+  %1 = emitc.post_increment %v : !emitc.lvalue<i32>
+  %2 = emitc.pre_decrement %v : !emitc.lvalue<i32>
+  %3 = emitc.post_decrement %v : !emitc.lvalue<i32>
+  return
+}
+
 func.func @test_if(%arg0: i1, %arg1: f32) {
   emitc.if %arg0 {
      %0 = emitc.call_opaque "func_const"(%arg1) : (f32) -> i32
diff --git a/mlir/test/Target/Cpp/common-cpp.mlir b/mlir/test/Target/Cpp/common-cpp.mlir
index 8e84433eaa2f3..1bffd59d4d44c 100644
--- a/mlir/test/Target/Cpp/common-cpp.mlir
+++ b/mlir/test/Target/Cpp/common-cpp.mlir
@@ -107,6 +107,41 @@ func.func @dereference(%arg0: !emitc.ptr<i32>) {
   return
 }
 
+// CHECK-LABEL: void inc_dec() {
+func.func @inc_dec() {
+  // CHECK-NEXT: int32_t [[V1:[^ ]*]] = 0;
+  %v = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
+  // CHECK-NEXT: int32_t [[V2:[^ ]*]] = ++[[V1]];
+  %0 = emitc.pre_increment %v : !emitc.lvalue<i32>
+  // CHECK-NEXT: int32_t [[V3:[^ ]*]] = [[V1]]++;
+  %1 = emitc.post_increment %v : !emitc.lvalue<i32>
+  // CHECK-NEXT: int32_t [[V4:[^ ]*]] = --[[V1]];
+  %2 = emitc.pre_decrement %v : !emitc.lvalue<i32>
+  // CHECK-NEXT: int32_t [[V5:[^ ]*]] = [[V1]]--;
+  %3 = emitc.post_decrement %v : !emitc.lvalue<i32>
+  return
+}
+
+// CHECK-LABEL: int32_t inc_dec_expression() {
+func.func @inc_dec_expression() -> i32 {
+  // CHECK-NEXT: int32_t [[V1:[^ ]*]] = 0;
+  %v = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
+  %inc = emitc.expression %v : (!emitc.lvalue<i32>) -> i32 {
+    %0 = emitc.post_increment %v : !emitc.lvalue<i32>
+    emitc.yield %0 : i32
+  }
+  // CHECK-NEXT: int32_t [[V2:[^ ]*]] = [[V1]]++;
+  %dec = emitc.expression %v : (!emitc.lvalue<i32>) -> i32 {
+    %0 = emitc.post_decrement %v : !emitc.lvalue<i32>
+    emitc.yield %0 : i32
+  }
+  // CHECK-NEXT: int32_t [[V3:[^ ]*]] = [[V1]]--;
+  %r = emitc.add %inc, %dec : (i32, i32) -> i32
+  // CHECK-NEXT: int32_t [[V4:[^ ]*]] = [[V2]] + [[V3]];
+  // CHECK-NEXT: return [[V4]];
+  return %r : i32
+}
+
 // CHECK: void array_type(int32_t v1[3], float v2[10][20])
 func.func @array_type(%arg0: !emitc.array<3xi32>, %arg1: !emitc.array<10x20xf32>) {
   return



More information about the Mlir-commits mailing list