Don't do int cmoves for IEEE comparisons, PR target/104256.

Protect int cmove from raising an assertion if it is trying to do an int
conditional move where the test involves floating point comparisons that
can't easily be reversed due to NaNs.

The code used to generate the condition, and possibly reverse the condition if
ISEL could not handle it by rewriting the OP in the comparison rtx.

Unfortunately there are some conditions like UNLE that can't easily be reversed
due to NaNs.

The patch changes the code so that it does the reversal before generating the
comparison.  If the comparison cannot be reversed, it just returns false,
which indicates that we can't do an int conditional move in this case.

I have tested this on a little endian power9 system doing a bootstrap.  There
were no regressions.  Can I install this in the trunk?  Neither GCC 10 nor GCC
11 seem to generate an assertion faiure, so I don't plan to backport it.

2022-02-17  Michael Meissner  <meiss...@the-meissners.org>

gcc/
        PR target/104256
        * config/rs6000/rs6000.cc (rs6000_emit_int_cmove): Don't do
        integer conditional moves if the test needs to be reversed and
        there isn't a direct reverse comparison.

gcc/testsuite/
        PR target/104256
        * gcc.target/powerpc/ppc-fortran/pr104254.f90: New test.
---
 gcc/config/rs6000/rs6000.cc                   | 36 ++++++++++---------
 .../powerpc/ppc-fortran/pr104254.f90          | 25 +++++++++++++
 2 files changed, 44 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.target/powerpc/ppc-fortran/pr104254.f90

diff --git a/gcc/config/rs6000/rs6000.cc b/gcc/config/rs6000/rs6000.cc
index f56cf66313a..15d324d13aa 100644
--- a/gcc/config/rs6000/rs6000.cc
+++ b/gcc/config/rs6000/rs6000.cc
@@ -16174,18 +16174,35 @@ rs6000_emit_int_cmove (rtx dest, rtx op, rtx 
true_cond, rtx false_cond)
 {
   rtx condition_rtx, cr;
   machine_mode mode = GET_MODE (dest);
-  enum rtx_code cond_code;
   rtx (*isel_func) (rtx, rtx, rtx, rtx, rtx);
   bool signedp;
 
   if (mode != SImode && (!TARGET_POWERPC64 || mode != DImode))
     return false;
 
+  /* Swap the comparison if isel can't handle it directly.  Don't generate int
+     cmoves if we can't swap the condition code due to NaNs.  */
+  enum rtx_code op_code = GET_CODE (op);
+  if (op_code != LT && op_code != GT && op_code != LTU && op_code != GTU
+      && op_code != EQ)
+    {
+      if (!COMPARISON_P (op))
+       return false;
+
+      enum rtx_code rev_code = reverse_condition (op_code);
+      if (rev_code == UNKNOWN)
+       return false;
+
+      std::swap (false_cond, true_cond);
+      op = gen_rtx_fmt_ee (rev_code, GET_MODE (op),
+                          XEXP (op, 0),
+                          XEXP (op, 1));
+    }
+
   /* We still have to do the compare, because isel doesn't do a
      compare, it just looks at the CRx bits set by a previous compare
      instruction.  */
   condition_rtx = rs6000_generate_compare (op, mode);
-  cond_code = GET_CODE (condition_rtx);
   cr = XEXP (condition_rtx, 0);
   signedp = GET_MODE (cr) == CCmode;
 
@@ -16193,21 +16210,6 @@ rs6000_emit_int_cmove (rtx dest, rtx op, rtx 
true_cond, rtx false_cond)
               ? (signedp ? gen_isel_signed_si : gen_isel_unsigned_si)
               : (signedp ? gen_isel_signed_di : gen_isel_unsigned_di));
 
-  switch (cond_code)
-    {
-    case LT: case GT: case LTU: case GTU: case EQ:
-      /* isel handles these directly.  */
-      break;
-
-    default:
-      /* We need to swap the sense of the comparison.  */
-      {
-       std::swap (false_cond, true_cond);
-       PUT_CODE (condition_rtx, reverse_condition (cond_code));
-      }
-      break;
-    }
-
   false_cond = force_reg (mode, false_cond);
   if (true_cond != const0_rtx)
     true_cond = force_reg (mode, true_cond);
diff --git a/gcc/testsuite/gcc.target/powerpc/ppc-fortran/pr104254.f90 
b/gcc/testsuite/gcc.target/powerpc/ppc-fortran/pr104254.f90
new file mode 100644
index 00000000000..d1bfab23482
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/ppc-fortran/pr104254.f90
@@ -0,0 +1,25 @@
+! { dg-do compile }
+! { dg-require-effective-target powerpc_p9vector_ok }
+! { dg-options "-mdejagnu-cpu=power9 -O1 -fnon-call-exceptions" }
+
+! PR target/104254.  GCC would raise an assertion error if this program was
+! compiled with -O1 and -fnon-call-exceptions on a power9 or higher.  The issue
+! occurs because at this optimization level, the compiler is trying to make
+! a conditional move to store integers using a 32-bit floating point compare.
+! It wants to use UNLE, which is not supported for integer modes.
+  
+  real :: a(2), nan
+  real, allocatable :: c(:)
+  integer :: ia(1)
+
+  nan = 0.0
+  nan = 0.0/nan
+
+  a(:) = nan
+  ia = maxloc (a)
+  if (ia(1).ne.1) STOP 1
+
+  allocate (c(1))
+  c(:) = nan
+  deallocate (c)
+end
-- 
2.35.1


-- 
Michael Meissner, IBM
PO Box 98, Ayer, Massachusetts, USA, 01432
email: meiss...@linux.ibm.com

Reply via email to