https://gcc.gnu.org/bugzilla/show_bug.cgi?id=113703

--- Comment #11 from GCC Commits <cvs-commit at gcc dot gnu.org> ---
The master branch has been updated by Richard Biener <[email protected]>:

https://gcc.gnu.org/g:471022256e4705314aedf21c53bc351ece88ff43

commit r17-4520-g471022256e4705314aedf21c53bc351ece88ff43
Author: Richard Biener <[email protected]>
Date:   Mon Sep 21 12:15:02 2026 +0200

    tree-optimization/127515 - ivopts: fix bound when counter wraps on first
increment

    iv_elimination_compare_lt turns a loop with the exit test i < b, entered
    with i = a and a pointer p = base + a stepping in lockstep with i, into a
    loop with the exit test p < p_0 - a + b, so as to eliminate the counter.

    The number of iterations of the loop is (a + 1 > b) ? 0 : b - a - 1 and
    the fix for PR tree-optimization/113703 made sure that the bound is not
    derived from it, since converting b - a to the type of the offsets is not
    value preserving when the loop rolls zero times and b - a is negative.

    But the reasoning also assumes that a + 1 does not wrap around in the type
    of a, which need not be the case: if a is the maximum value of its type,
    then a + 1 is zero, a + 1 > b is false whatever b is, so the loop rolls and
    its number of iterations is b, whereas b - a computed on the offsets is
    b - a and not b + 1.  For example, with

      void f (char *p, unsigned int i, unsigned int n)
      { p -= i; do { *p = 1; p -= 1; i++; } while (i < n); }

    called as f (p, -1, 1), the loop iterates twice but the bound is computed
    as p_0 + ((sizetype) 0xffffffff - (sizetype) 1), i.e. p_0 + 0xfffffffe
    instead of p_0 - 2, so the loop exits at the first test.

    So build the bound out of a + 1 and b + 1 instead of a and b, converting
    a + 1 to the type of the offsets as a whole instead of rewriting it into a
    and 1, and computing b + 1 in the type of the offsets, where it cannot wrap
    around.  The difference of the two offsets is then the number of iterations
    of the loop in the wrapping case too, since a + 1 is zero there.  Require
    the new pair of offsets to be non-negative and to not overflow as well.

    Co-Authored-By: Claude Opus 5 <[email protected]>

            PR tree-optimization/113703
            PR tree-optimization/127515
            * tree-ssa-loop-ivopts.cc (iv_elimination_compare_lt): Also record
            A + 1 when matching the number of iterations.  Convert it to
OFF_TYPE
            as a whole, compute B + 1 in OFF_TYPE and require both to be
            non-negative scaled offsets that do not overflow.  Build the bound
            out of them instead of A and B.

            * gcc.dg/torture/pr113703-5.c: New test.
            * gcc.dg/torture/pr113703-6.c: New test.

Reply via email to