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

            Bug ID: 128089
           Summary: Wrong code for nested floating-point division in
                    reassoc with -ffast-math -fno-reciprocal-math
           Product: gcc
           Version: 17.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: tree-optimization
          Assignee: unassigned at gcc dot gnu.org
          Reporter: xingyushuai at hygon dot cn
  Target Milestone: ---

GCC produces an incorrect result for nested floating-point division when
compiled with -O2 -ffast-math -fno-reciprocal-math. Disabling the reassociation
pass with -fno-tree-reassoc restores
  the correct result.

  The issue was reproduced on x86-64 using GCC 16.2.0 and GCC trunk 17.0.0
20261021 (experimental) through Compiler Explorer.

  Test case (repro.c):

  #include <assert.h>

  __attribute__ ((noipa)) double
  f (double a)
  {
    return (a / 3) / (a / 6) + a * a;
  }

  int
  main (void)
  {
    double result = f (6);
    assert (result == 38);
    return 0;
  }

  Compile and run:

  gcc -O2 -ffast-math -fno-reciprocal-math repro.c -o repro
  ./repro

  Expected behavior: the program exits normally. For a = 6, the expression
evaluates to:

  (6 / 3) / (6 / 6) + 6 * 6
  = 2 / 1 + 36
  = 38

  All intermediate values in this calculation are exactly representable in
double. There is no division by zero, overflow, or underflow.

  Actual behavior: the assertion fails. An equivalent version that prints
result produces:

  expected=38 actual=36.055555555555557

  The observed value is consistent with incorrectly transforming:

  (a / 3) / (a / 6)

  into:

  ((a / 3) / 6) / a

  Adding -fno-tree-reassoc makes the test pass:

  gcc -O2 -ffast-math -fno-reciprocal-math \
      -fno-tree-reassoc repro.c -o repro
  ./repro

  Compiler Explorer reproduction and comparison
(https://godbolt.org/z/9vecr6rG5) — this version prints the actual result for
inspection.

Reply via email to