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