[Mlir-commits] [mlir] [mlir][emitc] Relax `hasSideEffect` rules for Var/Member (PR #145011)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Fri Jun 20 03:29:32 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-mlir-emitc
Author: Kirill Chibisov (kchibisov)
<details>
<summary>Changes</summary>
The load side effect semantic depends on the operation that was used to declare the load's operand. In case of `VariableOp` and `MemberOp` the operation storage is on the stack, thus can be considered to not have side effects compared to e.g. subscript operation.
--
Not sure whether the logic of https://github.com/llvm/llvm-project/pull/144990 should be applied here, since the `variable`/`member` ops are rather limited iirc. cc @<!-- -->jacquesguan.
---
Full diff: https://github.com/llvm/llvm-project/pull/145011.diff
4 Files Affected:
- (modified) mlir/include/mlir/Dialect/EmitC/IR/EmitC.td (+4)
- (modified) mlir/lib/Dialect/EmitC/IR/EmitC.cpp (+14)
- (modified) mlir/test/Dialect/EmitC/transforms.mlir (+10-13)
- (modified) mlir/test/Target/Cpp/expressions.mlir (+23-3)
``````````diff
diff --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index 9ecdb74f4d82e..d88407a4d6726 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -966,6 +966,10 @@ def EmitC_LoadOp : EmitC_Op<"load", [CExpressionInterface,
let results = (outs AnyType:$result);
let assemblyFormat = "$operand attr-dict `:` type($operand)";
+
+ let extraClassDeclaration = [{
+ bool hasSideEffects();
+ }];
}
def EmitC_MulOp : EmitC_BinaryOp<"mul", []> {
diff --git a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
index e602210c2dc6c..10e0d931e17fd 100644
--- a/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
+++ b/mlir/lib/Dialect/EmitC/IR/EmitC.cpp
@@ -898,6 +898,20 @@ LogicalResult emitc::VariableOp::verify() {
return verifyInitializationAttribute(getOperation(), getValueAttr());
}
+//===----------------------------------------------------------------------===//
+// VariableOp
+//===----------------------------------------------------------------------===//
+
+bool emitc::LoadOp::hasSideEffects() {
+ auto *defOp = this->getOperand().getDefiningOp();
+ // The load side effect semantic depends on the operation that was used to
+ // declare the load's operand, `VariableOp` and `MemberOp` perform loading
+ // from the stack, thus we may consider them as not having side effect to
+ // make end code more readable by letting those loads to get inlined.
+ return !defOp ||
+ !(llvm::isa<VariableOp>(defOp) || llvm::isa<MemberOp>(defOp));
+}
+
//===----------------------------------------------------------------------===//
// YieldOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/EmitC/transforms.mlir b/mlir/test/Dialect/EmitC/transforms.mlir
index a38f396dad953..687ebe2cd3612 100644
--- a/mlir/test/Dialect/EmitC/transforms.mlir
+++ b/mlir/test/Dialect/EmitC/transforms.mlir
@@ -135,21 +135,18 @@ func.func @single_result_requirement() -> (i32, i32) {
// CHECK-SAME: %[[VAL_1:.*]]: !emitc.ptr<i32>) -> i1 {
// CHECK: %[[VAL_2:.*]] = "emitc.constant"() <{value = 0 : i64}> : () -> i64
// CHECK: %[[VAL_3:.*]] = "emitc.variable"() <{value = #emitc.opaque<"42">}> : () -> !emitc.lvalue<i32>
-// CHECK: %[[VAL_4:.*]] = emitc.expression : i32 {
-// CHECK: %[[VAL_5:.*]] = load %[[VAL_3]] : <i32>
-// CHECK: yield %[[VAL_5]] : i32
+// CHECK: %[[VAL_4:.*]] = emitc.subscript %[[VAL_1]]{{\[}}%[[VAL_2]]] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
+// CHECK: %[[VAL_5:.*]] = emitc.expression : i32 {
+// CHECK: %[[VAL_6:.*]] = load %[[VAL_4]] : <i32>
+// CHECK: yield %[[VAL_6]] : i32
// CHECK: }
-// CHECK: %[[VAL_6:.*]] = emitc.subscript %[[VAL_1]]{{\[}}%[[VAL_2]]] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
-// CHECK: %[[VAL_7:.*]] = emitc.expression : i32 {
-// CHECK: %[[VAL_8:.*]] = load %[[VAL_6]] : <i32>
-// CHECK: yield %[[VAL_8]] : i32
+// CHECK: %[[VAL_7:.*]] = emitc.expression : i1 {
+// CHECK: %[[VAL_8:.*]] = load %[[VAL_3]] : <i32>
+// CHECK: %[[VAL_9:.*]] = add %[[VAL_8]], %[[VAL_5]] : (i32, i32) -> i32
+// CHECK: %[[VAL_10:.*]] = cmp lt, %[[VAL_9]], %[[VAL_0]] : (i32, i32) -> i1
+// CHECK: yield %[[VAL_10]] : i1
// CHECK: }
-// CHECK: %[[VAL_9:.*]] = emitc.expression : i1 {
-// CHECK: %[[VAL_10:.*]] = add %[[VAL_4]], %[[VAL_7]] : (i32, i32) -> i32
-// CHECK: %[[VAL_11:.*]] = cmp lt, %[[VAL_10]], %[[VAL_0]] : (i32, i32) -> i1
-// CHECK: yield %[[VAL_11]] : i1
-// CHECK: }
-// CHECK: return %[[VAL_9]] : i1
+// CHECK: return %[[VAL_7]] : i1
// CHECK: }
diff --git a/mlir/test/Target/Cpp/expressions.mlir b/mlir/test/Target/Cpp/expressions.mlir
index 9316d7b77619b..b07c5f1804d38 100644
--- a/mlir/test/Target/Cpp/expressions.mlir
+++ b/mlir/test/Target/Cpp/expressions.mlir
@@ -343,13 +343,13 @@ func.func @expression_with_subscript_user(%arg0: !emitc.ptr<!emitc.opaque<"void"
return %res_load : i32
}
-// CPP-DEFAULT: bool expression_with_load(int32_t [[VAL_1:v.+]], int32_t [[VAL_2:v.+]], int32_t* [[VAL_3:v.+]]) {
+// CPP-DEFAULT: bool expression_with_var_load_and_subscript(int32_t [[VAL_1:v.+]], int32_t [[VAL_2:v.+]], int32_t* [[VAL_3:v.+]]) {
// CPP-DEFAULT-NEXT: int64_t [[VAL_4:v.+]] = 0;
// CPP-DEFAULT-NEXT: int32_t [[VAL_5:v.+]] = 42;
// CPP-DEFAULT-NEXT: bool [[VAL_6:v.+]] = [[VAL_5]] + [[VAL_2]] < [[VAL_3]][[[VAL_4]]] + [[VAL_1]];
// CPP-DEFAULT-NEXT: return [[VAL_6]];
-// CPP-DECLTOP: bool expression_with_load(int32_t [[VAL_1:v.+]], int32_t [[VAL_2:v.+]], int32_t* [[VAL_3:v.+]]) {
+// CPP-DECLTOP: bool expression_with_var_load_and_subscript(int32_t [[VAL_1:v.+]], int32_t [[VAL_2:v.+]], int32_t* [[VAL_3:v.+]]) {
// CPP-DECLTOP-NEXT: int64_t [[VAL_4:v.+]];
// CPP-DECLTOP-NEXT: int32_t [[VAL_5:v.+]];
// CPP-DECLTOP-NEXT: bool [[VAL_6:v.+]];
@@ -358,7 +358,7 @@ func.func @expression_with_subscript_user(%arg0: !emitc.ptr<!emitc.opaque<"void"
// CPP-DECLTOP-NEXT: [[VAL_6]] = [[VAL_5]] + [[VAL_2]] < [[VAL_3]][[[VAL_4]]] + [[VAL_1]];
// CPP-DECLTOP-NEXT: return [[VAL_6]];
-func.func @expression_with_load(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr<i32>) -> i1 {
+func.func @expression_with_var_load_and_subscript(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr<i32>) -> i1 {
%c0 = "emitc.constant"() {value = 0 : i64} : () -> i64
%0 = "emitc.variable"() <{value = #emitc.opaque<"42">}> : () -> !emitc.lvalue<i32>
%ptr = emitc.subscript %arg2[%c0] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
@@ -373,6 +373,26 @@ func.func @expression_with_load(%arg0: i32, %arg1: i32, %arg2: !emitc.ptr<i32>)
return %result : i1
}
+// CPP-DEFAULT: bool expression_with_var_load(int32_t [[VAL_1:v.+]], int32_t [[VAL_2:v.+]]) {
+// CPP-DEFAULT-NEXT: int32_t [[VAL_3:v.+]] = 42;
+// CPP-DEFAULT-NEXT: return [[VAL_3]] + [[VAL_1]] < [[VAL_2]];
+
+// CPP-DECLTOP: bool expression_with_var_load(int32_t [[VAL_1:v.+]], int32_t [[VAL_2:v.+]]) {
+// CPP-DECLTOP-NEXT: int32_t [[VAL_3:v.+]];
+// CPP-DECLTOP-NEXT: [[VAL_3]] = 42;
+// CPP-DECLTOP-NEXT: return [[VAL_3]] + [[VAL_1]] < [[VAL_2]];
+
+func.func @expression_with_var_load(%arg0: i32, %arg1: i32) -> i1 {
+ %0 = "emitc.variable"() <{value = #emitc.opaque<"42">}> : () -> !emitc.lvalue<i32>
+ %result = emitc.expression : i1 {
+ %a = emitc.load %0 : !emitc.lvalue<i32>
+ %b = emitc.add %a, %arg0 : (i32, i32) -> i32
+ %d = emitc.cmp lt, %b, %arg1 :(i32, i32) -> i1
+ yield %d : i1
+ }
+ return %result : i1
+}
+
// CPP-DEFAULT: bool expression_with_load_and_call(int32_t* [[VAL_1:v.+]]) {
// CPP-DEFAULT-NEXT: int64_t [[VAL_2:v.+]] = 0;
// CPP-DEFAULT-NEXT: bool [[VAL_3:v.+]] = [[VAL_1]][[[VAL_2]]] + bar([[VAL_1]][[[VAL_2]]]) < [[VAL_1]][[[VAL_2]]];
``````````
</details>
https://github.com/llvm/llvm-project/pull/145011
More information about the Mlir-commits
mailing list