Summary
When updating a loop-carried ilist in an if body, the branch result can be lowered as a constant payload instead of prev + payload.
This changes semantics (accumulation is lost).
Environment
kirin-toolchain==0.22.6
- Python
3.10.19
- macOS
15.7.3 (arm64)
Reproducer
1) Bad pattern (can collapse accumulation)
# frontend-agnostic kernel pseudocode
@kernel
def helper_const():
return [1] # constant payload
@kernel
def bad(n: int):
xs = []
for i in range(n):
if True:
xs += helper_const()
return len(xs)
print(bad(5)) # can be 1 (expected 5)
2) Good pattern (accumulates as expected)
# frontend-agnostic kernel pseudocode
@kernel
def helper_dynamic(v: int):
return [v] # payload depends on runtime value
@kernel
def good(n: int):
xs = []
v = n
for i in range(n):
if True:
xs += helper_dynamic(v)
return len(xs)
print(good(5)) # 5
Expected behavior
bad(5) should return 5.
good(5) should return 5.
- Semantics should be equivalent to repeated
xs = xs + payload in both cases.
Actual behavior
bad(5) can return 1.
good(5) returns 5.
Why this is a bug (not expected phi/merge behavior)
In SSA/control-flow terms, the branch should compute:
xs_then = xs_prev + const_payload
but observed behavior corresponds to:
This bypasses loop-carried state (xs_prev) and changes program meaning.
IR evidence
Observed risky shape in branch block:
^1(%i, %xs_2):
│ %xs_1 = py.constant.constant IList([1]) : ...
Expected shape:
^1(%i, %xs_2):
│ %tmp = py.constant.constant IList([1]) : ...
│ %xs_1 = py.binop.add(%xs_2, %tmp) : ...
Notes
- This appears in
for + if with loop-carried ilist updates when payload is (or is specialized into) a constant/literal list.
- Non-literal/runtime-dependent payloads often keep correct
py.binop.add form.
- Reproduced through a Kirin-based kernel frontend; issue appears in Kirin IR semantics/optimization shape, not frontend-specific syntax.
Request
Please investigate lowering/optimization around branch outputs for loop-carried values in for + if control flow.
Summary
When updating a loop-carried
ilistin anifbody, the branch result can be lowered as a constant payload instead ofprev + payload.This changes semantics (accumulation is lost).
Environment
kirin-toolchain==0.22.63.10.1915.7.3(arm64)Reproducer
1) Bad pattern (can collapse accumulation)
2) Good pattern (accumulates as expected)
Expected behavior
bad(5)should return5.good(5)should return5.xs = xs + payloadin both cases.Actual behavior
bad(5)can return1.good(5)returns5.Why this is a bug (not expected phi/merge behavior)
In SSA/control-flow terms, the branch should compute:
but observed behavior corresponds to:
This bypasses loop-carried state (
xs_prev) and changes program meaning.IR evidence
Observed risky shape in branch block:
Expected shape:
Notes
for+ifwith loop-carriedilistupdates when payload is (or is specialized into) a constant/literal list.py.binop.addform.Request
Please investigate lowering/optimization around branch outputs for loop-carried values in
for+ifcontrol flow.