[Mlir-commits] [mlir] 0ca2d4d - [mlir][emitc] mark `emitc.load` with `CExpression` (#130802)

llvmlistbot at llvm.org llvmlistbot at llvm.org
Tue Apr 22 00:03:45 PDT 2025


Author: Kirill Chibisov
Date: 2025-04-22T09:03:42+02:00
New Revision: 0ca2d4d10451874b1d107e89c32eb7fd95e1a608

URL: https://github.com/llvm/llvm-project/commit/0ca2d4d10451874b1d107e89c32eb7fd95e1a608
DIFF: https://github.com/llvm/llvm-project/commit/0ca2d4d10451874b1d107e89c32eb7fd95e1a608.diff

LOG: [mlir][emitc] mark `emitc.load` with `CExpression` (#130802)

Follow the `call` and `call_opaque` operations, as well as `apply`,
which already are marked as `CExpression` even though they have side
effects.

Even though `emitc.load` can be included inside the `emitc.expression`,
the inlining and `--form-expression` pass won't actually inline them
inside other expression due to it having a side effect, thus unless the
user manually writes the `emitc.load` inside the `emitc.expression` it
won't appear there.

--

It was brought
https://github.com/llvm/llvm-project/pull/91475#issuecomment-2302529428
and while there was some opposition due to `load` having a side effect,
`emitc` already allows all the rest operations that have it, so for
consistency reasons, enabling it doesn't really hurt from my point of
view. Especially given that `--form-expression` doesn't allow
it to really inline inside other expressions, which makes sense, since
if the users want such behavior, they should explicitly opt-in.

Added: 
    

Modified: 
    mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
    mlir/lib/Target/Cpp/TranslateToCpp.cpp
    mlir/test/Dialect/EmitC/transforms.mlir
    mlir/test/Target/Cpp/expressions.mlir

Removed: 
    


################################################################################
diff  --git a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
index a518e7425956c..d4aea52a0d485 100644
--- a/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
+++ b/mlir/include/mlir/Dialect/EmitC/IR/EmitC.td
@@ -489,12 +489,9 @@ def EmitC_ExpressionOp : EmitC_Op<"expression",
         auto applyOp = dyn_cast<emitc::ApplyOp>(op);
         if (applyOp)
           return applyOp.getApplicableOperator() == "*";
-        // Any operation using variables is assumed to have a side effect of
-        // reading memory mutable by emitc::assign ops.
-        return llvm::any_of(op.getOperands(), [](Value operand) {
-          Operation *def = operand.getDefiningOp();
-          return def && isa<emitc::VariableOp>(def);
-        });
+        // Any load operation is assumed to read from memory and thus perform
+        // a side effect.
+        return isa<emitc::LoadOp>(op);
       };
       return llvm::any_of(getRegion().front().without_terminator(), predicate);
     };
@@ -927,7 +924,7 @@ def EmitC_LogicalOrOp : EmitC_BinaryOp<"logical_or", [CExpression]> {
   let assemblyFormat = "operands attr-dict `:` type(operands)";
 }
 
-def EmitC_LoadOp : EmitC_Op<"load", [
+def EmitC_LoadOp : EmitC_Op<"load", [CExpression,
   TypesMatchWith<"result type matches value type of 'operand'",
                   "operand", "result",
                   "::llvm::cast<LValueType>($_self).getValueType()">

diff  --git a/mlir/lib/Target/Cpp/TranslateToCpp.cpp b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
index 81016ed2e9a8d..0c4975a13d301 100644
--- a/mlir/lib/Target/Cpp/TranslateToCpp.cpp
+++ b/mlir/lib/Target/Cpp/TranslateToCpp.cpp
@@ -100,6 +100,7 @@ static FailureOr<int> getOperatorPrecedence(Operation *operation) {
       })
       .Case<emitc::ConditionalOp>([&](auto op) { return 2; })
       .Case<emitc::DivOp>([&](auto op) { return 13; })
+      .Case<emitc::LoadOp>([&](auto op) { return 16; })
       .Case<emitc::LogicalAndOp>([&](auto op) { return 4; })
       .Case<emitc::LogicalNotOp>([&](auto op) { return 15; })
       .Case<emitc::LogicalOrOp>([&](auto op) { return 3; })

diff  --git a/mlir/test/Dialect/EmitC/transforms.mlir b/mlir/test/Dialect/EmitC/transforms.mlir
index d204dec70d449..a38f396dad953 100644
--- a/mlir/test/Dialect/EmitC/transforms.mlir
+++ b/mlir/test/Dialect/EmitC/transforms.mlir
@@ -129,3 +129,37 @@ func.func @single_result_requirement() -> (i32, i32) {
   %0:2 = emitc.call_opaque "foo" () : () -> (i32, i32)
   return %0#0, %0#1 : i32, i32
 }
+
+// CHECK-LABEL:   func.func @expression_with_load(
+// CHECK-SAME:                                    %[[VAL_0:.*]]: 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:           }
+// 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:           }
+// 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:         }
+
+
+func.func @expression_with_load(%arg0: i32, %arg1: !emitc.ptr<i32>) -> i1 {
+  %c0 = "emitc.constant"() {value = 0 : i64} : () -> i64
+  %0 = "emitc.variable"() <{value = #emitc.opaque<"42">}> : () -> !emitc.lvalue<i32>
+  %a = emitc.load %0 : !emitc.lvalue<i32>
+  %ptr = emitc.subscript %arg1[%c0] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
+  %ptr_load = emitc.load %ptr : !emitc.lvalue<i32>
+  %b = emitc.add %a, %ptr_load : (i32, i32) -> i32
+  %c = emitc.cmp lt, %b, %arg0 :(i32, i32) -> i1
+  return %c : i1
+}

diff  --git a/mlir/test/Target/Cpp/expressions.mlir b/mlir/test/Target/Cpp/expressions.mlir
index 3a1694e7d15dc..9316d7b77619b 100644
--- a/mlir/test/Target/Cpp/expressions.mlir
+++ b/mlir/test/Target/Cpp/expressions.mlir
@@ -342,3 +342,60 @@ func.func @expression_with_subscript_user(%arg0: !emitc.ptr<!emitc.opaque<"void"
   %res_load = emitc.load %res : !emitc.lvalue<i32>
   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-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-NEXT:   int64_t [[VAL_4:v.+]];
+// CPP-DECLTOP-NEXT:   int32_t [[VAL_5:v.+]];
+// CPP-DECLTOP-NEXT:   bool [[VAL_6:v.+]];
+// CPP-DECLTOP-NEXT:   [[VAL_4]] = 0;
+// CPP-DECLTOP-NEXT:   [[VAL_5]] = 42;
+// 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 {
+  %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>
+  %result = emitc.expression : i1 {
+    %a = emitc.load %0 : !emitc.lvalue<i32>
+    %b = emitc.add %a, %arg1 : (i32, i32) -> i32
+    %c = emitc.load %ptr : !emitc.lvalue<i32>
+    %d = emitc.add %c, %arg0 : (i32, i32) -> i32
+    %e = emitc.cmp lt, %b, %d :(i32, i32) -> i1
+    yield %e : 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]]];
+// CPP-DEFAULT-NEXT:   return [[VAL_3]];
+
+// CPP-DECLTOP: bool expression_with_load_and_call(int32_t* [[VAL_1:v.+]]) {
+// CPP-DECLTOP-NEXT:   int64_t [[VAL_2:v.+]];
+// CPP-DECLTOP-NEXT:   bool [[VAL_3:v.+]];
+// CPP-DECLTOP-NEXT:   [[VAL_2]] = 0;
+// CPP-DECLTOP-NEXT:   [[VAL_3]] = [[VAL_1]][[[VAL_2]]] + bar([[VAL_1]][[[VAL_2]]]) < [[VAL_1]][[[VAL_2]]];
+// CPP-DECLTOP-NEXT:   return [[VAL_3]];
+
+func.func @expression_with_load_and_call(%arg0: !emitc.ptr<i32>) -> i1 {
+  %c0 = "emitc.constant"() {value = 0 : i64} : () -> i64
+  %ptr = emitc.subscript %arg0[%c0] : (!emitc.ptr<i32>, i64) -> !emitc.lvalue<i32>
+  %result = emitc.expression : i1 {
+    %a = emitc.load %ptr : !emitc.lvalue<i32>
+    %b = emitc.load %ptr : !emitc.lvalue<i32>
+    %c = emitc.load %ptr : !emitc.lvalue<i32>
+    %d = emitc.call_opaque "bar" (%a) : (i32) -> (i32)
+    %e = add %c, %d : (i32, i32) -> i32
+    %f = emitc.cmp lt, %e, %b :(i32, i32) -> i1
+    yield %f : i1
+  }
+  return %result : i1
+}


        


More information about the Mlir-commits mailing list