[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