A for-loop that computes the correct result at optimization levels 0, 1, and 2 reverts at level 3.
name Loop;
storage {
r: uint256;
}
code {
let s = 0;
for (let i = 1; i <= 5; i = i + 1) {
s = s + i;
}
r = s;
}
This stores 15 at levels 0 through 2 and reverts at level 3.
The failure is specific to loops at level 3. Recursion (tail, mutual, tree), if/else diamonds, and multi-predecessor return blocks all execute correctly at every level; only loops regress, and only at 3. The revert, rather than a wrong value, points at a malformed stack.
Level 3 is where the loop is both TCO'd into a back-edge and then run through block-merging and inlining. Levels 0 through 2 lower the same loop correctly, so the defect is in how those passes reshape the loop's CFG. Working hypothesis: block-merging across the TCO loop header and back-edge relocates or drops the phi copies or the stack canonicalization, leaving the runtime stack inconsistent on the back-edge. Pinning the pass needs a level-3 step trace.
This is pre-existing and independent of the canonical stack-discipline change in #283 (verified: the revert reproduces without it), and it has a distinct root from #275. Found while writing the behavioral tests for #283; this is the remaining piece of #275's third checkpoint.
A
for-loop that computes the correct result at optimization levels 0, 1, and 2 reverts at level 3.This stores 15 at levels 0 through 2 and reverts at level 3.
The failure is specific to loops at level 3. Recursion (tail, mutual, tree), if/else diamonds, and multi-predecessor return blocks all execute correctly at every level; only loops regress, and only at 3. The revert, rather than a wrong value, points at a malformed stack.
Level 3 is where the loop is both TCO'd into a back-edge and then run through block-merging and inlining. Levels 0 through 2 lower the same loop correctly, so the defect is in how those passes reshape the loop's CFG. Working hypothesis: block-merging across the TCO loop header and back-edge relocates or drops the phi copies or the stack canonicalization, leaving the runtime stack inconsistent on the back-edge. Pinning the pass needs a level-3 step trace.
This is pre-existing and independent of the canonical stack-discipline change in #283 (verified: the revert reproduces without it), and it has a distinct root from #275. Found while writing the behavioral tests for #283; this is the remaining piece of #275's third checkpoint.