FW from: https://www.reddit.com/r/gcc/comments/1pdjjri/strange_behaviour_of_ffinitemathonly_in_gcc_14/ ``` float min(float a, float b) { return a < b ? a : b; } ``` Compiles down to: minss xmm0, xmm1 Unless you use -ffinite-math-only (and with -ffast-math it works again) and then it does something more complex. It seems that the backend is not able to handle: ``` _4 = a_1(D) < b_2(D); _3 = _4 ? a_1(D) : b_2(D); ``` While does handle the non-cond-expr one in ce1 just fine. Maybe related to PR 106952; especially https://gcc.gnu.org/bugzilla/show_bug.cgi?id=106952#c5 .
r14-2699-g9f8f37f5490076
For "reasons" RTL expansion differs here, using a jumpy sequence w/o -ffinite-math-only, but an if-converted variant if not. IIRC this is the x86 expander which likely fails to recognize equal compare args and thus min/max. IIRC there's another PR for this already. TER should come to the rescue here. The x86 backend gets (ge (reg/v:SF 100 [ a ]) (reg/v:SF 101 [ b ])) ? (reg/v:SF 101 [ b ]) : (reg/v:SF 100 [ a ]) then decides to turn this into (le ...) ? : instead of inverting the compare (which should be valid with -ffinite-math-only) and ix86_expand_sse_fp_minmax does not recognize the LE min(): static bool ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0, rtx cmp_op1, rtx if_true, rtx if_false) { machine_mode mode; bool is_min; rtx tmp; if (code == LT) ; else if (code == UNGE) std::swap (if_true, if_false); else return false; this could add else if (code == LE && !HONOR_NANS (mode)) ; I'll note that we end up with GE only because of prepare_cmp_insn not accepting LT for cbranch but GE is and what reversed_comparison_code_parts does depends on HONOR_NANS. The following works for me: diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc index fd9bcaa8541..da96454a73a 100644 --- a/gcc/config/i386/i386-expand.cc +++ b/gcc/config/i386/i386-expand.cc @@ -4163,7 +4163,8 @@ ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0, bool is_min; rtx tmp; - if (code == LT) + mode = GET_MODE (dest); + if (code == LT || (code == LE && !HONOR_NANS (mode))) ; else if (code == UNGE) std::swap (if_true, if_false); @@ -4177,7 +4178,6 @@ ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0, else return false; - mode = GET_MODE (dest); if (immediate_operand (if_false, mode)) if_false = force_reg (mode, if_false); if (immediate_operand (if_true, mode))
(In reply to Richard Biener from comment #2) > For "reasons" RTL expansion differs here, using a jumpy sequence w/o > -ffinite-math-only, but an if-converted variant if not. IIRC this is the x86 > expander which likely fails to recognize equal compare args and thus > min/max. IIRC there's another PR for this already. > > TER should come to the rescue here. The x86 backend gets > > (ge (reg/v:SF 100 [ a ]) > (reg/v:SF 101 [ b ])) ? (reg/v:SF 101 [ b ]) : (reg/v:SF 100 [ a ]) > > then decides to turn this into (le ...) ? : instead of inverting the compare > (which should be valid with -ffinite-math-only) and ix86_expand_sse_fp_minmax > does not recognize the LE min(): > > static bool > ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code code, rtx cmp_op0, > rtx cmp_op1, rtx if_true, rtx if_false) > { > machine_mode mode; > bool is_min; > rtx tmp; > > if (code == LT) > ; > else if (code == UNGE) > std::swap (if_true, if_false); > else > return false; > > this could add > > else if (code == LE && !HONOR_NANS (mode)) > ; > > I'll note that we end up with GE only because of prepare_cmp_insn not > accepting LT for cbranch but GE is and what reversed_comparison_code_parts > does depends on HONOR_NANS. > > The following works for me: > > diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc > index fd9bcaa8541..da96454a73a 100644 > --- a/gcc/config/i386/i386-expand.cc > +++ b/gcc/config/i386/i386-expand.cc > @@ -4163,7 +4163,8 @@ ix86_expand_sse_fp_minmax (rtx dest, enum rtx_code > code, rtx cmp_op0, > bool is_min; > rtx tmp; > > - if (code == LT) > + mode = GET_MODE (dest); > + if (code == LT || (code == LE && !HONOR_NANS (mode))) > ; Yes, please also add UNGT if !HONOR_NANS (mode) else if (code == UNGE || (code == UNGT && !HONOR_NANS (mode))) std::swap (if_true, if_false);
Testing.
The master branch has been updated by Richard Biener <rguenth@gcc.gnu.org>: https://gcc.gnu.org/g:e3a60357520bc3d14a098ca748c49c44f97b03f5 commit r16-5978-ge3a60357520bc3d14a098ca748c49c44f97b03f5 Author: Richard Biener <rguenther@suse.de> Date: Mon Dec 8 10:14:19 2025 +0100 target/123027 - handle min/max expansion when -ffinite-math-only When we get a <= b ? b : a into ix86_expand_sse_fp_minmax we can swap and invert this with -ffinite-math-only to get a < b ? a : b. PR target/123027 * config/i386/i386-expand.cc (ix86_expand_sse_fp_minmax): With !HONOR_NANS we can handle LE by swapping and inverting. * gcc.target/i386/pr123027.c: New testcase. * gcc.dg/torture/pr123027.c: Likewise.
Fixed on trunk sofar.
GCC 14.4 is being released, retargeting bugs to GCC 14.5.