extern double sqrt (double);
extern void abort (void);

__attribute__((noinline)) double
foo (double a)
{
  double b, c, d = 0.7;
  if (a <= d)
    b = sqrt (d * a);
  else
    {
      c = (1.0 - d) * (1.0 - a);
      b = c > 0 ? 1.0 - sqrt (c) : 1.0;
    }
  return b;
}

int
main (void)
{
  double c = foo (0.5);
  __builtin_printf ("%g %g\n", c, sqrt (0.7 * 0.5));
  if (c > 0.5917)
    abort ();
  return 0;
}

is miscompiled at -O2 -lm on x86_64-linux, works at -O2
-fno-optimize-sibling-calls.  The problem is that expand_errno_check is being
called on a CALL_EXPR with CALL_EXPR_TAILCALL set, and thus the expanded call
doesn't ever return.  In the likely case that the insn didn't return a NaN
the code jumps around the call, but in this case it doesn't jump to code
following the call (as it doesn't return), but to whatever code comes next.
I'll try to find out why this isn't miscompiled in 4.2.
Anyway, either we should simply clear the CALL_EXPR_TAILCALL bit in
expand_errno_check, or we should branch to (return), rather than a label
emitted
after the call if CALL_EXPR_TAILCALL is set.


-- 
           Summary: [4.3/4.4 Regression] Miscompilation of tail call sqrt
           Product: gcc
           Version: 4.3.0
            Status: UNCONFIRMED
          Keywords: wrong-code
          Severity: critical
          Priority: P3
         Component: rtl-optimization
        AssignedTo: unassigned at gcc dot gnu dot org
        ReportedBy: jakub at gcc dot gnu dot org
GCC target triplet: x86_64-linux


http://gcc.gnu.org/bugzilla/show_bug.cgi?id=36017

Reply via email to