[Mlir-commits] [mlir] [mlir][emitc] Add 'emitc.while' and 'emitc.do' ops to the dialect (PR #143008)

Gil Rapaport llvmlistbot at llvm.org
Mon Jun 30 01:16:56 PDT 2025


================
@@ -1572,4 +1572,156 @@ def EmitC_SwitchOp : EmitC_Op<"switch", [RecursiveMemoryEffects,
   let hasVerifier = 1;
 }
 
+def EmitC_WhileOp : EmitC_Op<"while",
+      [HasOnlyGraphRegion, RecursiveMemoryEffects, NoRegionArguments, OpAsmOpInterface, NoTerminator]> {
+  let summary = "While operation";
+ let description = [{
+    The `emitc.while` operation represents a C/C++ while loop construct that
+    repeatedly executes a body region as long as a condition region evaluates to
+    true. The operation has two regions:
+    
+    1. A condition region that must yield a boolean value (i1) 
+    2. A body region that contains the loop body
+
+    The condition region is evaluated before each iteration. If it yields true,
+    the body region is executed. The loop terminates when the condition yields
+    false. The condition region must contain exactly one block that terminates
+    with an `emitc.yield` operation producing an i1 value.
+
+    Example:
+
+    ```mlir
+    emitc.func @foo(%arg0 : !emitc.ptr<i32>) {
+      %var = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue<i32>
+      %0 = emitc.literal "10" : i32
+      %1 = emitc.literal "1" : i32
+
+      emitc.while {
+        %var_load = load %var : <i32>
+        %res = emitc.cmp le, %var_load, %0 : (i32, i32) -> i1
+        emitc.yield %res : i1
+      } do {
+        emitc.verbatim "printf(\"%d\", *{});" args %arg0 : !emitc.ptr<i32>
+        %var_load = load %var : <i32>
+        %tmp_add = add %var_load, %1 : (i32, i32) -> i32
+        "emitc.assign"(%var, %tmp_add) : (!emitc.lvalue<i32>, i32) -> ()
+      }
+
+      return
+    }
+    ```
+
+    ```c++
+    // Code emitted for the operation above.
+    void foo(int32_t* v1) {
+      int32_t v2 = 0;
+      while (v2 <= 10) {
+        printf("%d", *v1);
+        int32_t v3 = v2;
+        int32_t v4 = v3 + 1;
+        v2 = v4;
+      }
+      return;
+    }
+    ```
+  }];
+
+  let arguments = (ins);
+  let results = (outs); 
+  let regions = (region MaxSizedRegion<1>:$conditionRegion,
----------------
aniragil wrote:

>Do you want to nest it one more time?

Yes, since the operations in the condition region must follow the semantics of `emitc.expression` anyway.
Consider for example the following IR
```
emitc.while {
    %a = emitc.call_opaque "foo" (): () -> i32
    %b = emitc.add %a, %a : (i32, i32) -> i32
    %res = emitc.cmp le, %a, %b : (i32, i32) -> i1
    emitc.yield %res : i1
} do {
   // ...
}
```
which the PR currently translates to
```
while (foo() <= foo() + foo()) {
   // ...
}
```
This translation is invalid since the opaque call may have side effects (`emitc.expression` forbids multiple uses of its sub-expressions to avoid duplication during translation).
We can concentrate all expression checks in a single function and call it from multiple places in the code but IMO it's a weaker solution than actually using `emitc.expression`, which both simplifies the code and keeps the IR clear and consistent. In addition, the form-expressions pass would be able to merge `emitc.expression` ops feeding this `emitc.expression`, increasing readability.

https://github.com/llvm/llvm-project/pull/143008


More information about the Mlir-commits mailing list