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.