Bug 123027 - [14/15 Regression] minss is not used with -ffinite-math-only since r14-2699
Summary: [14/15 Regression] minss is not used with -ffinite-math-only since r14-2699
Status: ASSIGNED
Alias: None
Product: gcc
Classification: Unclassified
Component: target (show other bugs)
Version: 16.0
: P2 normal
Target Milestone: 14.5
Assignee: Richard Biener
URL:
Keywords: missed-optimization
Depends on:
Blocks:
 
Reported: 2025-12-05 21:51 UTC by Drea Pinski
Modified: 2026-06-26 09:28 UTC (History)
3 users (show)

See Also:
Host:
Target: x86_64-*-*
Build:
Known to work: 16.0
Known to fail: 14.3.0, 15.2.0
Last reconfirmed: 2025-12-07 00:00:00


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Drea Pinski 2025-12-05 21:51:05 UTC
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 .
Comment 1 Drea Pinski 2025-12-06 05:32:46 UTC
r14-2699-g9f8f37f5490076
Comment 2 Richard Biener 2025-12-07 10:18:59 UTC
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))
Comment 3 Hongtao Liu 2025-12-08 02:32:39 UTC
(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);
Comment 4 Richard Biener 2025-12-08 08:21:41 UTC
Testing.
Comment 5 GCC Commits 2025-12-09 07:53:43 UTC
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.
Comment 6 Richard Biener 2025-12-09 07:54:26 UTC
Fixed on trunk sofar.
Comment 7 Jakub Jelinek 2026-06-26 09:28:12 UTC
GCC 14.4 is being released, retargeting bugs to GCC 14.5.