Skip to content

Read the limit of a C loop on every pass when the loop counts down - #518

Open
j-modernc-org wants to merge 1 commit into
totalspectrum:masterfrom
j-modernc-org:loop-limit-invariant
Open

j-modernc-org wants to merge 1 commit into
totalspectrum:masterfrom
j-modernc-org:loop-limit-invariant

Conversation

@j-modernc-org

Copy link
Copy Markdown

This is the fix suggested in totalspectrum/flexprop#119, limited to C.

CheckSimpleIncrementLoop rewrites for (i = 0; i < n; i++), with i not used in the body, as a count down from n. That reads n once, before the loop. In C the limit is read on every pass, so a local the body changes, a global, and a global that a called function changes all ran the count they had when the loop began.

For C, the rewrite now requires a limit that cannot change in the loop: a constant, or a local whose address is not taken and which the body does not modify, or a sum or difference of those. A loop whose limit is such a local is still counted down. Spin and BASIC loops are rewritten as before, since reading the limit once may be what those languages mean.

Test/cexec07.c has the three loops from the issue and one whose limit the body leaves alone. It prints 5 5 5 5 on master and 3 3 3 5 with this change, as gcc does.

Checked, with flexspin built from this branch (master b5993a8 plus this commit):

  • make test_offline: the same tests pass as on master.
  • The tests Test/runtests_p2.sh runs, built and compared as it does, on a P2-EDGE: all 29 pass, cexec07 included.
  • 1419 C programs, our compiler's test corpus and fuzzer output plus our reproducers: only the reproducer from the issue builds differently from master.

CheckSimpleIncrementLoop rewrites `for (i = 0; i < n; i++)`, with i not
used in the body, as a count down from n. That reads n once, before the
loop. In C the limit is read on every pass, so a local the body changes,
a global, and a global a called function changes all ran the count they
had when the loop began (totalspectrum/flexprop#119).

For C, the rewrite now requires a limit that cannot change in the loop:
a constant, or a local whose address is not taken and which the body
does not modify. Spin and BASIC loops are rewritten as before.

Test/cexec07.c prints 5 5 5 5 on master and 3 3 3 5 with this change,
as gcc does.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant