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

            Bug ID: 128600
           Summary: Wrong code with product of affine evolutions whose
                    chrec coefficients overflow
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: konstantinos.eleftheriou at vrull dot eu
                CC: ptomsich at gcc dot gnu.org
  Target Milestone: ---
            Target: aarch64-linux-gnu

Created attachment 66128
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=66128&action=edit
testcase

The attached testcase aborts at -O1 and above:

$ gcc -O2 testcase.c && ./a.out
Aborted

It passes at -O0, and with -fwrapv or -fno-aggressive-loop-optimizations.
-fsanitize=undefined reports nothing. Seen with trunk r17-6046-gbccef7957b59
and
with GCC 15.2.1.

For i = 0 and i = 1 the product is -32768 * 32767 = -1073709056 and
32768 * 65535 = 2147450880, both in range. chrec_fold_multiply_poly_poly folds
the product of two affine chrecs in the same loop as

  {a, +, b}_x * {c, +, d}_x  ->  {a*c, +, a*d + b*c + b*d, +, 2*b*d}_x

Here a = -32768, b = 65536, c = 32767 and d = 32768. The step a*d + b*c + b*d
is
3221159936, which does not fit in int and wraps to -1073807360, and 2*b*d is
2^32, which wraps to 0, so the evolution of the product is computed as

  {-1073709056, +, -1073807360(OVF)}_1

This is correct modulo 2^32, but its value for i = 1, -2147516416, is out of
range. The step overflows even though no value of the product does. niter
analysis assumes that the statement does not overflow, so it can only execute
for i = 0. From the -O2 dumps:

  Induction variable (int) -1073709056 + -1073807360(OVF) * iteration does not
wrap in statement _5 = _2 * _4;
  Statement _5 = _2 * _4;
   is executed at most 0(OVF) (bounded by 0) + 1 times in loop 1.

cunrolli then removes the loop after its first iteration:

  testcase.c:9:21: optimized: loop with 1 iterations completely unrolled
(header execution count 268435456)

leaving f as

  if (n_9(D) > 0)
    g = -1073709056;

chrec_fold_plus_poly_poly gives up when a constant step overflows, and
chrec_fold_multiply redoes the product of a chrec and a constant in the
unsigned
type when the step overflows, but chrec_fold_multiply_poly_poly has no such
check.

Proposed fix: when overflow does not wrap and both factors have constant
coefficients, compute the coefficients of the product in a precision wide
enough
that they cannot overflow, and give up if one of them does not fit the type. A
prototype of this fixes the testcase and still folds products whose
coefficients
fit.

Reply via email to