scf.while¶
Condition-controlled loop with explicit before and after regions. The before region terminates with scf.condition, and the after region terminates with scf.yield. The before region runs once before the first body iteration and again after each iteration, including the final false condition. Values forwarded by that false condition become the loop results.
The header and condition payloads are independent tuples. Initial operands enter the before-region block arguments, and scf.yield supplies their next values. scf.condition may forward a different number or type of values: those values enter the after-region block arguments on the true edge and define the loop results on the false edge. This lets the condition expose a loaded payload, decoded tag, or other per-iteration value without carrying it around the backedge. Either tuple may be empty.
When the initial value, invariant bound, and positive increment are known exactly, Loom can infer separate counter ranges for the condition region, body, and exit. The proof requires that the terminal increment cannot wrap the target's index or offset carrier. This allows bounded view accesses without repeating the counter range in an assumption. Compile reports use the same proof: a loop with N body iterations has N + 1 condition-region executions, even when N is zero. Unsupported recurrences keep unknown bounds and counts.
Operation contract¶
| Property | Value |
|---|---|
| Semantic phase | source structure |
| Interfaces | LoopLike |
Signature¶
| Kind | Name | Type | Cardinality | Description |
|---|---|---|---|---|
| Operand | iter_args |
any |
variadic | Initial values for the before-region header tuple. |
| Result | results |
any |
variadic | Values forwarded by the final false scf.condition edge. |
| Region | before |
region | required | Runs before each condition check. Its arguments are initialized by iter_args and updated by scf.yield. Terminated by scf.condition. (single block, terminator scf.condition.) |
| Region | after |
region | required | Runs when the condition is true. Its arguments are the values forwarded by scf.condition. Terminated by scf.yield, whose values update the before-region arguments. (single block, terminator scf.yield.) |
Verification constraints¶
ConditionForwardedCountMatchesBlockArgs(before, after, results)ConditionForwardedTypesMatchBlockArgs(before, after, results)YieldCountMatches(after, before)YieldTypesMatch(after, before)
Examples¶
%begin = index.constant 0 : index
%end = index.constant 4 : index
%step = index.constant 1 : index
%terminal = scf.while(%before = %begin : index) -> (index) {
%more = index.cmp slt, %before, %end : index
scf.condition %more, %before : i1, index
} do(%position: index) {
%value = index.cast %position : index to i32
view.store %value, %output[%position] : i32, view<4xi32>
%next = index.add %position, %step : index
scf.yield %next : index
}
%terminal, %candidate = scf.while(%before = %init : index) -> (index, index) {
%next = index.add %before, %one : index
%keep_going = index.cmp ult, %next, %end : index
scf.condition %keep_going, %before, %next : i1, index, index
} do(%body_state: index, %body_candidate: index) {
scf.yield %body_candidate : index
}