[Mlir-commits] [mlir] 8ae7803 - [mlir][emitc] Add compound assignment ops (#210233)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Jul 22 11:52:45 PDT 2026
Author: Jianjian Guan
Date: 2026-07-22T11:52:41-07:00
New Revision: 8ae7803bede98cca73e6fd6a8fabbf95da9d0b46
URL: https://github.com/llvm/llvm-project/commit/8ae7803bede98cca73e6fd6a8fabbf95da9d0b46
DIFF: https://github.com/llvm/llvm-project/commit/8ae7803bede98cca73e6fd6a8fabbf95da9d0b46.diff
LOG: [mlir][emitc] Add compound assignment ops (#210233)
Added:
Modified:
mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
mlir/lib/Dialect/EmitC/IR/EmitC.cpp
mlir/lib/Target/Cpp/TranslateToCpp.cpp
mlir/test/Dialect/EmitC/invalid_ops.mlir
mlir/test/Dialect/EmitC/ops.mlir
mlir/test/Target/Cpp/common-cpp.mlir
Removed:
################################################################################
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index b6604cf45139f..49412d1dfb01c 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -88,6 +88,20 @@ class EmitC_IncDecOp<string mnemonic, string summaryStr>
}];
}
+// Base class for compound assignment operations.
+class EmitC_CompoundAssignOp<string mnemonic, string summaryStr>
+ : EmitC_Op<mnemonic, []> {
+ let summary = summaryStr;
+ let arguments = (ins
+ Res<EmitC_LValueType, "",
+ [MemRead<DefaultResource, 0, FullEffect>,
+ MemWrite<DefaultResource, 0, FullEffect>]>:$var,
+ EmitCType:$value);
+ let results = (outs);
+ let hasVerifier = 1;
+ let assemblyFormat = "$value `:` type($value) `to` $var `:` type($var) attr-dict";
+}
+
// Types only used in binary arithmetic operations.
def IntegerIndexOrOpaqueType : Type<CPred<"emitc::isIntegerIndexOrOpaqueType($_self)">,
"integer, index or opaque type supported by EmitC">;
@@ -1591,6 +1605,76 @@ def EmitC_AssignOp : EmitC_Op<"assign", []> {
let assemblyFormat = "$value `:` type($value) `to` $var `:` type($var) attr-dict";
}
+def EmitC_AddAssignOp
+ : EmitC_CompoundAssignOp<"add_assign", "Addition assignment operation"> {
+ let description = [{
+ The `emitc.add_assign` operation applies the C/C++ `+=` operator to an
+ lvalue.
+
+ Example:
+
+ ```mlir
+ emitc.add_assign %value : i32 to %var : !emitc.lvalue<i32>
+ ```
+ }];
+}
+
+def EmitC_SubAssignOp
+ : EmitC_CompoundAssignOp<"sub_assign", "Subtraction assignment operation"> {
+ let description = [{
+ The `emitc.sub_assign` operation applies the C/C++ `-=` operator to an
+ lvalue.
+
+ Example:
+
+ ```mlir
+ emitc.sub_assign %value : i32 to %var : !emitc.lvalue<i32>
+ ```
+ }];
+}
+
+def EmitC_MulAssignOp
+ : EmitC_CompoundAssignOp<"mul_assign", "Multiplication assignment operation"> {
+ let description = [{
+ The `emitc.mul_assign` operation applies the C/C++ `*=` operator to an
+ lvalue.
+
+ Example:
+
+ ```mlir
+ emitc.mul_assign %value : i32 to %var : !emitc.lvalue<i32>
+ ```
+ }];
+}
+
+def EmitC_DivAssignOp
+ : EmitC_CompoundAssignOp<"div_assign", "Division assignment operation"> {
+ let description = [{
+ The `emitc.div_assign` operation applies the C/C++ `/=` operator to an
+ lvalue.
+
+ Example:
+
+ ```mlir
+ emitc.div_assign %value : i32 to %var : !emitc.lvalue<i32>
+ ```
+ }];
+}
+
+def EmitC_RemAssignOp
+ : EmitC_CompoundAssignOp<"rem_assign", "Remainder assignment operation"> {
+ let description = [{
+ The `emitc.rem_assign` operation applies the C/C++ `%=` operator to an
+ lvalue.
+
+ Example:
+
+ ```mlir
+ emitc.rem_assign %value : i32 to %var : !emitc.lvalue<i32>
+ ```
+ }];
+}
+
def EmitC_YieldOp : EmitC_Op<"yield",
[Pure, Terminator, ParentOneOf<["DoOp", "ExpressionOp", "ForOp", "IfOp", "SwitchOp"]>]> {
let summary = "Block termination operation";
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index 6e68a3d0c5a41..820c4ad578a9e 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -263,27 +263,38 @@ LogicalResult AddOp::verify() {
}
//===----------------------------------------------------------------------===//
-// AssignOp
+// Assignment operations
//===----------------------------------------------------------------------===//
-/// The assign op requires that the assigned value's type matches the
-/// assigned-to variable type.
-LogicalResult emitc::AssignOp::verify() {
- TypedValue<emitc::LValueType> variable = getVar();
+template <typename AssignmentOp>
+static LogicalResult verifyAssignmentOp(AssignmentOp op) {
+ TypedValue<emitc::LValueType> variable = op.getVar();
if (!variable.getDefiningOp())
- return emitOpError() << "cannot assign to block argument";
+ return op.emitOpError() << "cannot assign to block argument";
- Type valueType = getValue().getType();
+ Type valueType = op.getValue().getType();
Type variableType = variable.getType().getValueType();
if (variableType != valueType)
- return emitOpError() << "requires value's type (" << valueType
- << ") to match variable's type (" << variableType
- << ")\n variable: " << variable
- << "\n value: " << getValue() << "\n";
+ return op.emitOpError() << "requires value's type (" << valueType
+ << ") to match variable's type (" << variableType
+ << ")\n variable: " << variable
+ << "\n value: " << op.getValue() << "\n";
return success();
}
+LogicalResult emitc::AssignOp::verify() { return verifyAssignmentOp(*this); }
+
+LogicalResult emitc::AddAssignOp::verify() { return verifyAssignmentOp(*this); }
+
+LogicalResult emitc::SubAssignOp::verify() { return verifyAssignmentOp(*this); }
+
+LogicalResult emitc::MulAssignOp::verify() { return verifyAssignmentOp(*this); }
+
+LogicalResult emitc::DivAssignOp::verify() { return verifyAssignmentOp(*this); }
+
+LogicalResult emitc::RemAssignOp::verify() { return verifyAssignmentOp(*this); }
+
//===----------------------------------------------------------------------===//
// CastOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 5ae51bd580d31..d5815fafcd6a7 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -608,6 +608,42 @@ static LogicalResult printOperation(CppEmitter &emitter,
return emitter.emitOperand(assignOp.getValue());
}
+static LogicalResult
+printCompoundAssignmentOperation(CppEmitter &emitter, Operation *operation,
+ StringRef compoundAssignmentOperator) {
+ if (failed(emitter.emitOperand(operation->getOperand(0))))
+ return failure();
+
+ emitter.ostream() << " " << compoundAssignmentOperator << " ";
+
+ return emitter.emitOperand(operation->getOperand(1));
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+ emitc::AddAssignOp addAssignOp) {
+ return printCompoundAssignmentOperation(emitter, addAssignOp, "+=");
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+ emitc::SubAssignOp subAssignOp) {
+ return printCompoundAssignmentOperation(emitter, subAssignOp, "-=");
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+ emitc::MulAssignOp mulAssignOp) {
+ return printCompoundAssignmentOperation(emitter, mulAssignOp, "*=");
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+ emitc::DivAssignOp divAssignOp) {
+ return printCompoundAssignmentOperation(emitter, divAssignOp, "/=");
+}
+
+static LogicalResult printOperation(CppEmitter &emitter,
+ emitc::RemAssignOp remAssignOp) {
+ return printCompoundAssignmentOperation(emitter, remAssignOp, "%=");
+}
+
static LogicalResult printOperation(CppEmitter &emitter, emitc::LoadOp loadOp) {
if (failed(emitter.emitAssignPrefix(*loadOp)))
return failure();
@@ -1927,25 +1963,26 @@ LogicalResult CppEmitter::emitOperation(Operation &op, bool trailingSemicolon) {
.Case<cf::BranchOp, cf::CondBranchOp>(
[&](auto op) { return printOperation(*this, op); })
// EmitC ops.
- .Case<emitc::AddressOfOp, emitc::AddOp, emitc::AssignOp,
- emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
+ .Case<emitc::AddAssignOp, emitc::AddressOfOp, emitc::AddOp,
+ emitc::AssignOp, emitc::BitwiseAndOp, emitc::BitwiseLeftShiftOp,
emitc::BitwiseNotOp, emitc::BitwiseOrOp,
emitc::BitwiseRightShiftOp, emitc::BitwiseXorOp, emitc::CallOp,
emitc::CallOpaqueOp, emitc::CastOp, emitc::ClassOp,
emitc::CmpOp, emitc::ConditionalOp, emitc::ConstantOp,
- emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivOp,
- emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp, emitc::FileOp,
- emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
+ emitc::DeclareFuncOp, emitc::DereferenceOp, emitc::DivAssignOp,
+ emitc::DivOp, emitc::DoOp, emitc::ExpressionOp, emitc::FieldOp,
+ emitc::FileOp, emitc::ForOp, emitc::FuncOp, emitc::GetFieldOp,
emitc::GetGlobalOp, emitc::GlobalOp, emitc::IfOp,
emitc::IncludeOp, emitc::LiteralOp, emitc::LoadOp,
emitc::LogicalAndOp, emitc::LogicalNotOp, emitc::LogicalOrOp,
emitc::MemberCallOpaqueOp, emitc::MemberOfPtrOp,
- 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>(
+ emitc::MemberOp, emitc::MulAssignOp, emitc::MulOp,
+ emitc::PostDecrementOp, emitc::PostIncrementOp,
+ emitc::PreDecrementOp, emitc::PreIncrementOp,
+ emitc::RemAssignOp, emitc::RemOp, emitc::ReturnOp,
+ emitc::SubAssignOp, emitc::SubscriptOp, emitc::SubOp,
+ emitc::SwitchOp, emitc::UnaryMinusOp, emitc::UnaryPlusOp,
+ emitc::VariableOp, emitc::VerbatimOp>(
[&](auto op) { return printOperation(*this, op); })
// Func ops.
diff --git a/mlir/test/Dialect/EmitC/invalid_ops.mlir b/mlir/test/Dialect/EmitC/invalid_ops.mlir
index 3048160d1590c..889138a22ede3 100644
--- a/mlir/test/Dialect/EmitC/invalid_ops.mlir
+++ b/mlir/test/Dialect/EmitC/invalid_ops.mlir
@@ -997,3 +997,20 @@ func.func @post_decrement_unmatch_type(%arg0: !emitc.lvalue<i32>) {
%1 = "emitc.post_decrement"(%arg0) : (!emitc.lvalue<i32>) -> i8
return
}
+
+// -----
+
+func.func @add_assign_to_block_argument(%arg0: i32, %arg1: !emitc.lvalue<i32>) {
+ // expected-error @+1 {{'emitc.add_assign' op cannot assign to block argument}}
+ emitc.add_assign %arg0 : i32 to %arg1 : !emitc.lvalue<i32>
+ return
+}
+
+// -----
+
+func.func @sub_assign_type_mismatch(%arg0: f32) {
+ %v = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue<i32>
+ // expected-error @+1 {{'emitc.sub_assign' op requires value's type ('f32') to match variable's type ('i32')}}
+ emitc.sub_assign %arg0 : f32 to %v : !emitc.lvalue<i32>
+ return
+}
diff --git a/mlir/test/Dialect/EmitC/ops.mlir b/mlir/test/Dialect/EmitC/ops.mlir
index e5c4af67c4896..3261b2fa467da 100644
--- a/mlir/test/Dialect/EmitC/ops.mlir
+++ b/mlir/test/Dialect/EmitC/ops.mlir
@@ -187,6 +187,23 @@ func.func @test_assign(%arg1: f32) {
return
}
+// CHECK-LABEL: func.func @compound_assign
+// CHECK: emitc.add_assign
+// CHECK: emitc.sub_assign
+// CHECK: emitc.mul_assign
+// CHECK: emitc.div_assign
+// CHECK: emitc.rem_assign
+func.func @compound_assign(%arg0: i32, %arg1: !emitc.opaque<"number">) {
+ %v = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
+ %opaque = "emitc.variable"() <{value = #emitc.opaque<"">}> : () -> !emitc.lvalue<!emitc.opaque<"number">>
+ emitc.add_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ emitc.sub_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ emitc.mul_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ emitc.div_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ emitc.rem_assign %arg1 : !emitc.opaque<"number"> to %opaque : !emitc.lvalue<!emitc.opaque<"number">>
+ return
+}
+
func.func @test_expression(%arg0: i32, %arg1: i32, %arg2: i32, %arg3: f32, %arg4: f32) -> i32 {
%c7 = "emitc.constant"() {value = 7 : i32} : () -> i32
%q = emitc.expression %arg1, %c7 : (i32, i32) -> i32 {
diff --git a/mlir/test/Target/Cpp/common-cpp.mlir b/mlir/test/Target/Cpp/common-cpp.mlir
index 1bffd59d4d44c..041321db46290 100644
--- a/mlir/test/Target/Cpp/common-cpp.mlir
+++ b/mlir/test/Target/Cpp/common-cpp.mlir
@@ -122,6 +122,24 @@ func.func @inc_dec() {
return
}
+// CHECK-LABEL: void compound_assign(
+// CHECK-SAME: int32_t [[ARG0:[^ ]*]]) {
+func.func @compound_assign(%arg0: i32) {
+ // CHECK-NEXT: int32_t [[V1:[^ ]*]] = 0;
+ %v = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
+ // CHECK-NEXT: [[V1]] += [[ARG0]];
+ emitc.add_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ // CHECK-NEXT: [[V1]] -= [[ARG0]];
+ emitc.sub_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ // CHECK-NEXT: [[V1]] *= [[ARG0]];
+ emitc.mul_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ // CHECK-NEXT: [[V1]] /= [[ARG0]];
+ emitc.div_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ // CHECK-NEXT: [[V1]] %= [[ARG0]];
+ emitc.rem_assign %arg0 : i32 to %v : !emitc.lvalue<i32>
+ return
+}
+
// CHECK-LABEL: int32_t inc_dec_expression() {
func.func @inc_dec_expression() -> i32 {
// CHECK-NEXT: int32_t [[V1:[^ ]*]] = 0;
More information about the Mlir-commits
mailing list