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.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.  I've
added a runtime testcase showing we do have to swap both to
get signed zeros correct.  UNGT, etc. do not appear with
-ffinite-math-only, at least I failed to create a testcase.
We could invert UNGT to LE and then do the same trick as for LE.

Bootstrap and regtest running on x86_64-unknown-linux-gnu.

OK if that succeeds?

Thanks,
Richard.

        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.
---
 gcc/config/i386/i386-expand.cc           |  9 +++++++--
 gcc/testsuite/gcc.dg/torture/pr123027.c  | 20 ++++++++++++++++++++
 gcc/testsuite/gcc.target/i386/pr123027.c | 15 +++++++++++++++
 3 files changed, 42 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/torture/pr123027.c
 create mode 100644 gcc/testsuite/gcc.target/i386/pr123027.c

diff --git a/gcc/config/i386/i386-expand.cc b/gcc/config/i386/i386-expand.cc
index fd9bcaa8541..438fa4e4b6a 100644
--- a/gcc/config/i386/i386-expand.cc
+++ b/gcc/config/i386/i386-expand.cc
@@ -4159,12 +4159,18 @@ 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;
+  machine_mode mode = GET_MODE (dest);
   bool is_min;
   rtx tmp;
 
   if (code == LT)
     ;
+  else if (code == LE && !HONOR_NANS (mode))
+    {
+      /* We can swap LE to GE and then invert to LT.  */
+      std::swap (cmp_op0, cmp_op1);
+      std::swap (if_true, if_false);
+    }
   else if (code == UNGE)
     std::swap (if_true, if_false);
   else
@@ -4177,7 +4183,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))
diff --git a/gcc/testsuite/gcc.dg/torture/pr123027.c 
b/gcc/testsuite/gcc.dg/torture/pr123027.c
new file mode 100644
index 00000000000..cba4cc9792e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/torture/pr123027.c
@@ -0,0 +1,20 @@
+/* { dg-do run } */
+/* { dg-options "-ffinite-math-only" } */
+/* { dg-add-options ieee } */
+
+double a = 0.0;
+double b = -0.0;
+
+int main()
+{
+  double min1 = a < b ? a : b;
+  double max1 = a > b ? a : b;
+  double min2 = b < a ? b : a;
+  double max2 = b > a ? b : a;
+  if (__builtin_copysign (1., min1) != -1.
+      || __builtin_copysign (1., max1) != -1.
+      || __builtin_copysign (1., min2) != 1.
+      || __builtin_copysign (1., max2) != 1.)
+    __builtin_abort ();
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/pr123027.c 
b/gcc/testsuite/gcc.target/i386/pr123027.c
new file mode 100644
index 00000000000..e04fc807a07
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/pr123027.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -msse -ffinite-math-only" } */
+
+float foo (float a, float b)
+{
+  return a < b ? a : b;
+}
+
+float bar (float a, float b)
+{
+  return a > b ? a : b;
+}
+
+/* { dg-final { scan-assembler-times "minss" 1 } } */
+/* { dg-final { scan-assembler-times "maxss" 1 } } */
-- 
2.51.0

Reply via email to