rs6000.c (init_float128_ieee): Remove IEEE 128-bit comparison functions in cmp_optab...
authorMichael Meissner <meissner@linux.vnet.ibm.com>
Tue, 29 Dec 2015 17:15:14 +0000 (17:15 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Tue, 29 Dec 2015 17:15:14 +0000 (17:15 +0000)
2015-12-29  Michael Meissner  <meissner@linux.vnet.ibm.com>

* config/rs6000/rs6000.c (init_float128_ieee): Remove IEEE 128-bit
comparison functions in cmp_optab and ucmp_optab.
(rs6000_generate_compare): Rewrite IEEE 128-bit floating point
software emulation comparisons to only use __eqkf2, __gekf2,
__lekf2, and __unordkf2 functions.
(rs6000_invalid_binary_op): Add support for -mfloat128-convert.

* config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define
__FLOAT128_HARDWARE__ if hardware IEEE 128-bit support is
available.

* config/rs6000/rs6000.opt (-mfloat128-convert): Add debug switch
to allow IBM extended double and IEEE 128-bit floating point to be
converted with default conversions.

* config/rs6000/rs6000.md (extendkftf2): Add converters between
KFmode and TFmode if -mabi=ieeelongdouble.
(trunctfkf2): Likewise.
(ieee128_mfvsrd): Split 64-bit integer conversions into 32-bit and
64-bit insns.
(ieee128_mfvsrd_64bit): Likewise.
(ieee128_mfvsrd_32bit): Likewise.
(ieee128_mtvsrd): Likewise.
(ieee128_mtvsrd_64bit): Likewise.
(ieee128_mtvsrd_32bit): Likewise.

* doc/extend.texi (Floating Types): Document that complex
__float128 does not work currently.

* doc/invoke.texi (RS/6000 and PowerPC Options): Document that
-mfloat128 is only supported on PowerPC 64-bit Linux systems.

From-SVN: r231996

gcc/ChangeLog
gcc/config/rs6000/rs6000-c.c
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
gcc/config/rs6000/rs6000.opt
gcc/doc/extend.texi
gcc/doc/invoke.texi

index 5f7e0009d84c58ca8126e9d99176a107c2bcad93..1643888b2c880935c46e98301e893673e2420067 100644 (file)
@@ -1,3 +1,37 @@
+2015-12-29  Michael Meissner  <meissner@linux.vnet.ibm.com>
+
+       * config/rs6000/rs6000.c (init_float128_ieee): Remove IEEE 128-bit
+       comparison functions in cmp_optab and ucmp_optab.
+       (rs6000_generate_compare): Rewrite IEEE 128-bit floating point
+       software emulation comparisons to only use __eqkf2, __gekf2,
+       __lekf2, and __unordkf2 functions.
+       (rs6000_invalid_binary_op): Add support for -mfloat128-convert.
+
+       * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Define
+       __FLOAT128_HARDWARE__ if hardware IEEE 128-bit support is
+       available.
+
+       * config/rs6000/rs6000.opt (-mfloat128-convert): Add debug switch
+       to allow IBM extended double and IEEE 128-bit floating point to be
+       converted with default conversions.
+
+       * config/rs6000/rs6000.md (extendkftf2): Add converters between
+       KFmode and TFmode if -mabi=ieeelongdouble.
+       (trunctfkf2): Likewise.
+       (ieee128_mfvsrd): Split 64-bit integer conversions into 32-bit and
+       64-bit insns.
+       (ieee128_mfvsrd_64bit): Likewise.
+       (ieee128_mfvsrd_32bit): Likewise.
+       (ieee128_mtvsrd): Likewise.
+       (ieee128_mtvsrd_64bit): Likewise.
+       (ieee128_mtvsrd_32bit): Likewise.
+
+       * doc/extend.texi (Floating Types): Document that complex
+       __float128 does not work currently.
+
+       * doc/invoke.texi (RS/6000 and PowerPC Options): Document that
+       -mfloat128 is only supported on PowerPC 64-bit Linux systems.
+
 2015-12-28  Bill Schmidt  <wschmidt@linux.vnet.ibm.com>
 
        * config/rs6000/rs6000.c (rs6000_emit_le_vsx_move): Verify that
index a1b4fd4d17e98d8add5d41abd33d57abd0fee291..85b4b3cfcb0e6b0ba5f1e2a04720b7dcf0f4a502 100644 (file)
@@ -412,6 +412,8 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfile)
     builtin_define ("__RSQRTEF__");
   if (TARGET_FLOAT128)
     builtin_define ("__FLOAT128__");
+  if (TARGET_FLOAT128_HW)
+    builtin_define ("__FLOAT128_HARDWARE__");
 
   if (TARGET_EXTRA_BUILTINS && cpp_get_options (pfile)->lang != CLK_ASM)
     {
index a97e47a72ba8addc4fb65bbd7b02a4cf62e7c6ae..a71d0b635448dd8f305555ae300c56e29f246ad7 100644 (file)
@@ -16501,8 +16501,6 @@ init_float128_ieee (machine_mode mode)
       set_optab_libfunc (lt_optab, mode, "__ltkf2");
       set_optab_libfunc (le_optab, mode, "__lekf2");
       set_optab_libfunc (unord_optab, mode, "__unordkf2");
-      set_optab_libfunc (cmp_optab, mode, "__cmpokf2");                /* fcmpo */
-      set_optab_libfunc (ucmp_optab, mode, "__cmpukf2");       /* fcmpu */
 
       set_conv_libfunc (sext_optab, mode, SFmode, "__extendsfkf2");
       set_conv_libfunc (sext_optab, mode, DFmode, "__extenddfkf2");
@@ -20297,7 +20295,9 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
   rtx op0 = XEXP (cmp, 0);
   rtx op1 = XEXP (cmp, 1);
 
-  if (FLOAT_MODE_P (mode))
+  if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode))
+    comp_mode = CCmode;
+  else if (FLOAT_MODE_P (mode))
     comp_mode = CCFPmode;
   else if (code == GTU || code == LTU
           || code == GEU || code == LEU)
@@ -20503,106 +20503,77 @@ rs6000_generate_compare (rtx cmp, machine_mode mode)
       emit_insn (cmp);
     }
 
-  /* IEEE 128-bit support in VSX registers.  If we do not have IEEE 128-bit
-     hardware, 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 (!TARGET_FLOAT128_HW && FLOAT128_IEEE_P (mode))
+  /* IEEE 128-bit support in VSX registers when we do not have hardware
+     support.  */
+  else if (!TARGET_FLOAT128_HW && FLOAT128_VECTOR_P (mode))
     {
-      rtx and_reg = gen_reg_rtx (SImode);
+      rtx libfunc = NULL_RTX;
+      bool uneq_or_ltgt = false;
       rtx dest = gen_reg_rtx (SImode);
-      rtx libfunc = optab_libfunc (ucmp_optab, mode);
-      HOST_WIDE_INT mask_value = 0;
-
-      /* 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.  */
-#define PPC_CMP_LESS_THEN      0x8             /* a < b.  */
 
       switch (code)
        {
        case EQ:
-         mask_value = PPC_CMP_EQUAL;
-         code = NE;
-         break;
-
        case NE:
-         mask_value = PPC_CMP_EQUAL;
-         code = EQ;
+         libfunc = optab_libfunc (eq_optab, mode);
          break;
 
        case GT:
-         mask_value = PPC_CMP_GREATER_THEN;
-         code = NE;
-         break;
-
        case GE:
-         mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
-         code = NE;
+         libfunc = optab_libfunc (ge_optab, mode);
          break;
 
        case LT:
-         mask_value = PPC_CMP_LESS_THEN;
-         code = NE;
-         break;
-
        case LE:
-         mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
-         code = NE;
-         break;
-
-       case UNLE:
-         mask_value = PPC_CMP_GREATER_THEN;
-         code = EQ;
+         libfunc = optab_libfunc (le_optab, mode);
          break;
 
-       case UNLT:
-         mask_value = PPC_CMP_GREATER_THEN | PPC_CMP_EQUAL;
-         code = EQ;
+       case UNORDERED:
+       case ORDERED:
+         libfunc = optab_libfunc (unord_optab, mode);
+         code = (code == UNORDERED) ? NE : EQ;
          break;
 
        case UNGE:
-         mask_value = PPC_CMP_LESS_THEN;
-         code = EQ;
+       case UNGT:
+         libfunc = optab_libfunc (le_optab, mode);
+         code = (code == UNGE) ? GE : GT;
          break;
 
-       case UNGT:
-         mask_value = PPC_CMP_LESS_THEN | PPC_CMP_EQUAL;
-         code = EQ;
+       case UNLE:
+       case UNLT:
+         libfunc = optab_libfunc (ge_optab, mode);
+         code = (code == UNLE) ? LE : LT;
          break;
 
        case UNEQ:
-         mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED;
-         code = NE;
-
        case LTGT:
-         mask_value = PPC_CMP_EQUAL | PPC_CMP_UNORDERED;
-         code = EQ;
-         break;
-
-       case UNORDERED:
-         mask_value = PPC_CMP_UNORDERED;
-         code = NE;
-         break;
-
-       case ORDERED:
-         mask_value = PPC_CMP_UNORDERED;
-         code = EQ;
+         libfunc = optab_libfunc (le_optab, mode);
+         uneq_or_ltgt = true;
+         code = (code = UNEQ) ? NE : EQ;
          break;
 
        default:
          gcc_unreachable ();
        }
 
-      gcc_assert (mask_value != 0);
-      and_reg = emit_library_call_value (libfunc, and_reg, LCT_CONST, SImode, 2,
-                                        op0, mode, op1, mode);
+      gcc_assert (libfunc);
+      dest = emit_library_call_value (libfunc, NULL_RTX, LCT_CONST,
+                                     SImode, 2, op0, mode, op1, mode);
 
-      emit_insn (gen_andsi3 (dest, and_reg, GEN_INT (mask_value)));
-      compare_result = gen_reg_rtx (CCmode);
-      comp_mode = CCmode;
+      /* If this is UNEQ or LTGT, we call __lekf2, which returns -1 for less
+        than, 0 for equal, +1 for greater, and +2 for nan.  We add 1, to give
+        a value of 0..3, and then do and AND immediate of 1 to isolate whether
+        it is 0/Nan (i.e. bottom bit is 0), or less than/greater than
+        (i.e. bottom bit is 1).  */
+      if (uneq_or_ltgt)
+       {
+         rtx add_result = gen_reg_rtx (SImode);
+         rtx and_result = gen_reg_rtx (SImode);
+         emit_insn (gen_addsi3 (add_result, dest, GEN_INT (1)));
+         emit_insn (gen_andsi3 (and_result, add_result, GEN_INT (1)));
+         dest = and_result;
+       }
 
       emit_insn (gen_rtx_SET (compare_result,
                              gen_rtx_COMPARE (comp_mode, dest, const0_rtx)));
@@ -20706,24 +20677,29 @@ rs6000_invalid_binary_op (int op ATTRIBUTE_UNUSED,
     mode2 = GET_MODE_INNER (mode2);
 
   /* Don't allow IEEE 754R 128-bit binary floating point and IBM extended
-     double to intermix.  */
+     double to intermix unless -mfloat128-convert.  */
   if (mode1 == mode2)
     return NULL;
 
-  if ((mode1 == KFmode && mode2 == IFmode)
-      || (mode1 == IFmode && mode2 == KFmode))
-    return N_("__float128 and __ibm128 cannot be used in the same expression");
+  if (!TARGET_FLOAT128_CVT)
+    {
+      if ((mode1 == KFmode && mode2 == IFmode)
+         || (mode1 == IFmode && mode2 == KFmode))
+       return N_("__float128 and __ibm128 cannot be used in the same "
+                 "expression");
 
-  if (TARGET_IEEEQUAD
-      && ((mode1 == IFmode && mode2 == TFmode)
-         || (mode1 == TFmode && mode2 == IFmode)))
-    return N_("__ibm128 and long double cannot be used in the same expression");
+      if (TARGET_IEEEQUAD
+         && ((mode1 == IFmode && mode2 == TFmode)
+             || (mode1 == TFmode && mode2 == IFmode)))
+       return N_("__ibm128 and long double cannot be used in the same "
+                 "expression");
 
-  if (!TARGET_IEEEQUAD
-      && ((mode1 == KFmode && mode2 == TFmode)
-         || (mode1 == TFmode && mode2 == KFmode)))
-    return N_("__float128 and long double cannot be used in the same "
-             "expression");
+      if (!TARGET_IEEEQUAD
+         && ((mode1 == KFmode && mode2 == TFmode)
+             || (mode1 == TFmode && mode2 == KFmode)))
+       return N_("__float128 and long double cannot be used in the same "
+                 "expression");
+    }
 
   return NULL;
 }
index 35685a92e1a21ff26674f1b8a7deaa458ae52e58..0b035ca8f918b0942a929e939c213c1553e0d6bf 100644 (file)
   "xscvdpqp %0,%1"
   [(set_attr "type" "vecfloat")])
 
+;; Conversion between KFmode and TFmode if TFmode is ieee 128-bit floating
+;; point is a simple copy.
+(define_insn_and_split "extendkftf2"
+  [(set (match_operand:TF 0 "vsx_register_operand" "=wa,?wa")
+       (float_extend:TF (match_operand:KF 1 "vsx_register_operand" "0,wa")))]
+  "TARGET_FLOAT128 && TARGET_IEEEQUAD"
+  "@
+   #
+   xxlor %x0,%x1,%x1"
+  "&& reload_completed  && REGNO (operands[0]) == REGNO (operands[1])"
+  [(const_int 0)]
+{
+  emit_note (NOTE_INSN_DELETED);
+  DONE;
+}
+  [(set_attr "type" "*,vecsimple")
+   (set_attr "length" "0,4")])
+
+(define_insn_and_split "trunctfkf2"
+  [(set (match_operand:KF 0 "vsx_register_operand" "=wa,?wa")
+       (float_extend:KF (match_operand:TF 1 "vsx_register_operand" "0,wa")))]
+  "TARGET_FLOAT128 && TARGET_IEEEQUAD"
+  "@
+   #
+   xxlor %x0,%x1,%x1"
+  "&& reload_completed  && REGNO (operands[0]) == REGNO (operands[1])"
+  [(const_int 0)]
+{
+  emit_note (NOTE_INSN_DELETED);
+  DONE;
+}
+  [(set_attr "type" "*,vecsimple")
+   (set_attr "length" "0,4")])
+
 (define_insn "trunc<mode>df2_hw"
   [(set (match_operand:DF 0 "altivec_register_operand" "=v")
        (float_truncate:DF
   "xscv<su>dqp %0,%1"
   [(set_attr "type" "vecfloat")])
 
-(define_insn "*ieee128_mfvsrd"
+(define_insn "*ieee128_mfvsrd_64bit"
   [(set (match_operand:DI 0 "reg_or_indexed_operand" "=wr,Z,wi")
        (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v,v")]
                   UNSPEC_IEEE128_MOVE))]
    xxlor %x0,%x1,%x1"
   [(set_attr "type" "mftgpr,vecsimple,fpstore")])
 
+
+(define_insn "*ieee128_mfvsrd_32bit"
+  [(set (match_operand:DI 0 "reg_or_indexed_operand" "=Z,wi")
+       (unspec:DI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
+                  UNSPEC_IEEE128_MOVE))]
+  "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
+  "@
+   stxsdx %x1,%y0
+   xxlor %x0,%x1,%x1"
+  [(set_attr "type" "vecsimple,fpstore")])
+
 (define_insn "*ieee128_mfvsrwz"
   [(set (match_operand:SI 0 "reg_or_indexed_operand" "=r,Z")
        (unspec:SI [(match_operand:V2DI 1 "altivec_register_operand" "v,v")]
   [(set_attr "type" "mffgpr,fpload,mffgpr,fpload")])
 
 
-(define_insn "*ieee128_mtvsrd"
+(define_insn "*ieee128_mtvsrd_64bit"
   [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v,v")
        (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "wr,Z,wi")]
                     UNSPEC_IEEE128_MOVE))]
-  "TARGET_FLOAT128_HW"
+  "TARGET_FLOAT128_HW && TARGET_POWERPC64"
   "@
    mtvsrd %x0,%1
    lxsdx %x0,%y1
    xxlor %x0,%x1,%x1"
   [(set_attr "type" "mffgpr,fpload,vecsimple")])
 
+(define_insn "*ieee128_mtvsrd_32bit"
+  [(set (match_operand:V2DI 0 "altivec_register_operand" "=v,v")
+       (unspec:V2DI [(match_operand:DI 1 "nonimmediate_operand" "Z,wi")]
+                    UNSPEC_IEEE128_MOVE))]
+  "TARGET_FLOAT128_HW && !TARGET_POWERPC64"
+  "@
+   lxsdx %x0,%y1
+   xxlor %x0,%x1,%x1"
+  [(set_attr "type" "fpload,vecsimple")])
+
 ;; IEEE 128-bit instructions with round to odd semantics
 (define_insn "*trunc<mode>df2_odd"
   [(set (match_operand:DF 0 "vsx_register_operand" "=v")
index 61e3c8a323eaf2ffe31cceae4236fffabe68065e..8064f23a39ccfadee4bf0ba291a073c64851c587 100644 (file)
@@ -632,3 +632,7 @@ Enable/disable IEEE 128-bit floating point via the __float128 keyword.
 mfloat128-hardware
 Target Report Mask(FLOAT128_HW) Var(rs6000_isa_flags)
 Enable/disable using IEEE 128-bit floating point instructions.
+
+mfloat128-convert
+Target Undocumented Mask(FLOAT128_CVT) Var(rs6000_isa_flags)
+Enable/disable default conversions between __float128 & long double.
index 4578925854dbb607ca6ecaea6c2d45f554cd7642..65b6a96f1d69a0b78a70c5d4b6ac2576094a96c9 100644 (file)
@@ -954,22 +954,20 @@ typedef _Complex float __attribute__((mode(TC))) _Complex128;
 typedef _Complex float __attribute__((mode(XC))) _Complex80;
 @end smallexample
 
-On PowerPC Linux, Freebsd and Darwin systems, the default for
-@code{long double} is to use the IBM extended floating point format
-that uses a pair of @code{double} values to extend the precision.
-This means that the mode @code{TCmode} was already used by the
-traditional IBM long double format, and you would need to use the mode
-@code{KCmode}:
+On PowerPC 64-bit Linux systems there are currently problems in using
+the complex @code{__float128} type.  When these problems are fixed,
+you would use:
 
 @smallexample
 typedef _Complex float __attribute__((mode(KC))) _Complex128;
 @end smallexample
 
-Not all targets support additional floating-point types.  @code{__float80}
-and @code{__float128} types are supported on x86 and IA-64 targets.
-The @code{__float128} type is supported on hppa HP-UX.
-The @code{__float128} type is supported on PowerPC systems by default
-if the vector scalar instruction set (VSX) is enabled.
+Not all targets support additional floating-point types.
+@code{__float80} and @code{__float128} types are supported on x86 and
+IA-64 targets.  The @code{__float128} type is supported on hppa HP-UX.
+The @code{__float128} type is supported on PowerPC 64-bit Linux
+systems by default if the vector scalar instruction set (VSX) is
+enabled.
 
 On the PowerPC, @code{__ibm128} provides access to the IBM extended
 double format, and it is intended to be used by the library functions
index 4e2cf8f7beba93ae5e728e59282245ac06b68bd4..b85f9b5942db9adba11939b93db6006687ae1c4c 100644 (file)
@@ -19690,7 +19690,8 @@ hardware instructions.
 
 The VSX instruction set (@option{-mvsx}, @option{-mcpu=power7}, or
 @option{-mcpu=power8}) must be enabled to use the @option{-mfloat128}
-option.
+option.  The @code{-mfloat128} option only works on PowerPC 64-bit
+Linux systems.
 
 @item -mfloat128-hardware
 @itemx -mno-float128-hardware