[Mlir-commits] [mlir] [mlir][emitc] Add increment and decrement ops (PR #208648)
Jianjian Guan
llvmlistbot at llvm.org
Mon Jul 13 19:06:13 PDT 2026
https://github.com/jacquesguan updated https://github.com/llvm/llvm-project/pull/208648
>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 1/2] [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
>From b87881459866f405e1fa87bae1d024349ed816e3 Mon Sep 17 00:00:00 2001
From: Jianjian GUAN <jacquesguan at me.com>
Date: Tue, 14 Jul 2026 10:05:40 +0800
Subject: [PATCH 2/2] Address comment
---
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td | 58 ++++++++++++++++-----
1 file changed, 44 insertions(+), 14 deletions(-)
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index c52f5b5f909c4..c8417ce2f3de7 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -74,16 +74,6 @@ class EmitC_IncDecOp<string mnemonic, string summaryStr>
"::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>,
@@ -1293,16 +1283,56 @@ def EmitC_ConditionalOp : EmitC_Op<"conditional",
}
def EmitC_PreIncrementOp
- : EmitC_IncDecOp<"pre_increment", "Pre-increment operation">;
+ : EmitC_IncDecOp<"pre_increment", "Pre-increment operation"> {
+ let description = [{
+ This operation models the C/C++ pre-increment operator on an lvalue.
+
+ Example:
+
+ ```mlir
+ %0 = emitc.pre_increment %arg0 : !emitc.lvalue<i32>
+ ```
+ }];
+}
def EmitC_PostIncrementOp
- : EmitC_IncDecOp<"post_increment", "Post-increment operation">;
+ : EmitC_IncDecOp<"post_increment", "Post-increment operation"> {
+ let description = [{
+ This operation models the C/C++ post-increment operator on an lvalue.
+
+ Example:
+
+ ```mlir
+ %0 = emitc.post_increment %arg0 : !emitc.lvalue<i32>
+ ```
+ }];
+}
def EmitC_PreDecrementOp
- : EmitC_IncDecOp<"pre_decrement", "Pre-decrement operation">;
+ : EmitC_IncDecOp<"pre_decrement", "Pre-decrement operation"> {
+ let description = [{
+ This operation models the C/C++ pre-decrement operator on an lvalue.
+
+ Example:
+
+ ```mlir
+ %0 = emitc.pre_decrement %arg0 : !emitc.lvalue<i32>
+ ```
+ }];
+}
def EmitC_PostDecrementOp
- : EmitC_IncDecOp<"post_decrement", "Post-decrement operation">;
+ : EmitC_IncDecOp<"post_decrement", "Post-decrement operation"> {
+ let description = [{
+ This operation models the C/C++ post-decrement operator on an lvalue.
+
+ Example:
+
+ ```mlir
+ %0 = emitc.post_decrement %arg0 : !emitc.lvalue<i32>
+ ```
+ }];
+}
def EmitC_UnaryMinusOp : EmitC_UnaryOp<"unary_minus", []> {
let summary = "Unary minus operation";
More information about the Mlir-commits
mailing list