This patch updates to use the unordered comparison function for IEEE 128-bit
floating point to mimic the behaviour of SFmode/DFmode using the fcmpu
instruction.

It also restructures the code to allow a future change to drop in easier.

I have built the compiler with this patch and the previous subpatches (1-6).  I
have bootstrapped the compiler with all 16 subpatches installed, and there were
no regressions.  Is it ok to install in the trunk?

2015-10-22  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        * config/rs6000/rs6000.c (rs6000_generate_compare): For IEEE
        128-bit floating point comparisons, call the unordered comparison
        function instead of the ordered comparison function.
        (rs6000_expand_float128_convert): Deal with operands that are
        memory operands. Restructure the code to use a switch statement on
        the mode. Add support for TFmode defaulting to either IBM extended
        double or IEEE 128-bit floating point. If the underlying types are
        the same, use a move instead of a conversion function.

-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meiss...@linux.vnet.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 229191)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -20098,17 +20098,18 @@ rs6000_generate_compare (rtx cmp, machin
       emit_insn (cmp);
     }
 
-  /* IEEE 128-bit support in VSX registers.  The comparison function (__cmpkf2)
-     returns 0..15 that is laid out the same way as the PowerPC CR register
-     would for a normal floating point comparison.  */
+  /* IEEE 128-bit support in VSX registers.  The comparison functions
+     (__cmpokf2 and __cmpukf2) returns 0..15 that is laid out the same way as
+     the PowerPC CR register would for a normal floating point comparison from
+     the fcmpo and fcmpu instructions.  */
   else if (FLOAT128_IEEE_P (mode))
     {
       rtx and_reg = gen_reg_rtx (SImode);
       rtx dest = gen_reg_rtx (SImode);
-      rtx libfunc = optab_libfunc (cmp_optab, mode);
+      rtx libfunc = optab_libfunc (ucmp_optab, mode);
       HOST_WIDE_INT mask_value = 0;
 
-      /* Values that __cmpkf2 returns.  */
+      /* Values that __cmpokf2/__cmpukf2 returns.  */
 #define PPC_CMP_UNORDERED      0x1             /* isnan (a) || isnan (b).  */
 #define PPC_CMP_EQUAL          0x2             /* a == b.  */
 #define PPC_CMP_GREATER_THEN   0x4             /* a > b.  */
@@ -20280,6 +20281,7 @@ rs6000_generate_compare (rtx cmp, machin
 }
 
 
+
 /* Expand floating point conversion to/from __float128 and __ibm128.  */
 
 void
@@ -20288,60 +20290,121 @@ rs6000_expand_float128_convert (rtx dest
   machine_mode dest_mode = GET_MODE (dest);
   machine_mode src_mode = GET_MODE (src);
   convert_optab cvt = unknown_optab;
+  bool do_move = false;
   rtx libfunc = NULL_RTX;
   rtx dest2;
 
   if (dest_mode == src_mode)
     gcc_unreachable ();
 
+  /* Eliminate memory operations.  */
+  if (MEM_P (src))
+    src = force_reg (src_mode, src);
+
+  if (MEM_P (dest))
+    {
+      rtx tmp = gen_reg_rtx (dest_mode);
+      rs6000_expand_float128_convert (tmp, src, unsigned_p);
+      rs6000_emit_move (dest, tmp, dest_mode);
+      return;
+    }
+
+  /* Convert to IEEE 128-bit floating point.  */
   if (FLOAT128_IEEE_P (dest_mode))
     {
-      if (src_mode == SFmode
-         || src_mode == DFmode
-         || FLOAT128_IBM_P (src_mode))
-       cvt = sext_optab;
+      switch (src_mode)
+       {
+       case DFmode:
+         cvt = sext_optab;
+         break;
 
-      else if (GET_MODE_CLASS (src_mode) == MODE_INT)
-       cvt = (unsigned_p) ? ufloat_optab : sfloat_optab;
+       case SFmode:
+         cvt = sext_optab;
+         break;
 
-      else if (FLOAT128_IEEE_P (src_mode))
-       emit_move_insn (dest, gen_lowpart (dest_mode, src));
+       case KFmode:
+       case IFmode:
+       case TFmode:
+         if (FLOAT128_IBM_P (src_mode))
+           cvt = sext_optab;
+         else
+           do_move = true;
+         break;
 
-      else
-       gcc_unreachable ();
+       case SImode:
+       case DImode:
+         cvt = (unsigned_p) ? ufloat_optab : sfloat_optab;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
     }
 
+  /* Convert from IEEE 128-bit floating point.  */
   else if (FLOAT128_IEEE_P (src_mode))
     {
-      if (dest_mode == SFmode
-         || dest_mode == DFmode
-         || FLOAT128_IBM_P (dest_mode))
-       cvt = trunc_optab;
+      switch (dest_mode)
+       {
+       case DFmode:
+         cvt = trunc_optab;
+         break;
 
-      else if (GET_MODE_CLASS (dest_mode) == MODE_INT)
-       cvt = (unsigned_p) ? ufix_optab : sfix_optab;
+       case SFmode:
+         cvt = trunc_optab;
+         break;
 
-      else
-       gcc_unreachable ();
+       case KFmode:
+       case IFmode:
+       case TFmode:
+         if (FLOAT128_IBM_P (dest_mode))
+           cvt = trunc_optab;
+         else
+           do_move = true;
+         break;
+
+       case SImode:
+       case DImode:
+         cvt = (unsigned_p) ? ufix_optab : sfix_optab;
+         break;
+
+       default:
+         gcc_unreachable ();
+       }
     }
 
+  /* Both IBM format.  */
+  else if (FLOAT128_IBM_P (dest_mode) && FLOAT128_IBM_P (src_mode))
+    do_move = true;
+
   else
     gcc_unreachable ();
 
-  gcc_assert (cvt != unknown_optab);
-  libfunc = convert_optab_libfunc (cvt, dest_mode, src_mode);
-  gcc_assert (libfunc != NULL_RTX);
-
-  dest2 = emit_library_call_value (libfunc, dest, LCT_CONST, dest_mode, 1, src,
-                                  src_mode);
-
-  gcc_assert (dest != NULL_RTX);
-  if (!rtx_equal_p (dest, dest2))
-    emit_move_insn (dest, dest2);
+  /* Handle conversion between TFmode/KFmode.  */
+  if (do_move)
+    emit_move_insn (dest, gen_lowpart (dest_mode, src));
+
+  /* Call an external function to do the conversion.  */
+  else if (cvt != unknown_optab)
+    {
+      libfunc = convert_optab_libfunc (cvt, dest_mode, src_mode);
+      gcc_assert (libfunc != NULL_RTX);
+
+      dest2 = emit_library_call_value (libfunc, dest, LCT_CONST, dest_mode, 1, 
src,
+                                      src_mode);
+
+      gcc_assert (dest2 != NULL_RTX);
+      if (!rtx_equal_p (dest, dest2))
+       emit_move_insn (dest, dest2);
+    }
+
+  else
+    gcc_unreachable ();
 
   return;
 }
 
+
 /* Emit the RTL for an sISEL pattern.  */
 
 void

Reply via email to