https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103088
--- Comment #19 from Aldy Hernandez <aldyh at gcc dot gnu.org> ---
Ughh, I was nerd sniped. Couldn't let it go ;-).
The problem is this construct in Perl_do_ncmp:
if (lnv < rnv)
return -1;
if (lnv > rnv)
return 1;
if (lnv == rnv)
return 0;
return 2;
These are all doubles. The code is depending on a pair of values that are
neither <, >, nor ==, being a NAN.
For -ffast-math with unsafe optimizations we end up inling Perl_do_ncmp into
pp_ge():
SETs(boolSV(
(SvIOK_notUV(left) && SvIOK_notUV(right))
? (SvIVX(left) >= SvIVX(right))
: ( (do_ncmp(left, right) & 2) == 0)
));
but in doing so we destroy the 3 separate conditionals. At one point we're
making decisions based on <= on the 35->38 edge:
struct OP * Perl_pp_ge ():
...
<bb 35> [local count: 590686791]:
# iftmp.547_110 = PHI <iftmp.547_107(33), iftmp.547_108(34)>
if (iftmp.546_109 > iftmp.547_110)
goto <bb 23>; [1.04%]
else
goto <bb 38>; [98.96%]
<snip>
<snip>
<bb 38> [local count: 644407314]:
<bb 39> [local count: 953267993]:
# iftmp.532_21 = PHI <&PL_sv_yes(38), &PL_sv_no(37)>
MEM[(struct SV * *)sp_27 + -8B] = iftmp.532_21;
PL_stack_sp = sp_30;
PL_op.534_19 = PL_op;
_38 = PL_op.534_19->op_next;
<bb 40> [local count: 1073741826]:
# _20 = PHI <_29(5), _38(39)>
return _20;
For -fno-unsafe-math-optimizations we avoid inlining Perl_no_ncmp, which keeps
the conditionals.
So it looks like we inline the NAN checking code in unsafe mode and the
threader ends can make decisions on the return value for pp_ge(). As I said,
the threads are correct.
If anyone is curious, you can see what's going on by tagging Perl_do_ncmp()
with __attribute__((optimize("O3", "fast-math",
"no-unsafe-math-optimizations")))
and seeing the final pp_ge() output with the munged conditionals versus the
pristine code in the output for Perl_do_ncmp.
I think we can keep this PR closed. Don't use -ffast-math unless followed by
-fno-unsafe-math-optimizations.