re PR target/85657 (Make __ibm128 a separate type, even if long double uses the IBM...
authorMichael Meissner <meissner@linux.ibm.com>
Mon, 21 May 2018 22:21:40 +0000 (22:21 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Mon, 21 May 2018 22:21:40 +0000 (22:21 +0000)
[gcc]
2018-05-21  Michael Meissner  <meissner@linux.ibm.com>

PR target/85657
* config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Do not
define __ibm128 as long double.
* config/rs6000/rs6000.c (rs6000_init_builtins): Always create
__ibm128 as a distinct type.
(init_float128_ieee): Fix up conversions between IFmode and IEEE
128-bit types to use the correct functions.
(rs6000_expand_float128_convert): Use explicit FLOAT_EXTEND to
convert between 128-bit floating point types that have different
modes but the same representation, instead of using gen_lowpart to
makean alias.
* config/rs6000/rs6000.md (IFKF): New iterator for IFmode and
KFmode.
(IFKF_reg): New attributes to give the register constraints for
IFmode and KFmode.
(extend<mode>tf2_internal): New insns to mark an explicit
conversion between 128-bit floating point types that have a
different mode but share the same representation.

[gcc/testsuite]
2018-05-21  Michael Meissner  <meissner@linux.ibm.com>

PR target/85657
* gcc.target/powerpc/pr85657-1.c: New test for converting between
__float128, __ibm128, and long double.
* gcc.target/powerpc/pr85657-2.c: Likewise.
* gcc.target/powerpc/pr85657-3.c: Likewise.
* g++.dg/pr85667.C: New test to make sure __ibm128 is
implementated as a separate type internally, and is not just an
alias for long double.

From-SVN: r260489

gcc/ChangeLog
gcc/config/rs6000/rs6000-c.c
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.md
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/pr85657.C [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/pr85657-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/pr85657-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/powerpc/pr85657-3.c [new file with mode: 0644]

index db367f7..6aad0d5 100644 (file)
@@ -1,3 +1,24 @@
+2018-05-21  Michael Meissner  <meissner@linux.ibm.com>
+
+       PR target/85657
+       * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): Do not
+       define __ibm128 as long double.
+       * config/rs6000/rs6000.c (rs6000_init_builtins): Always create
+       __ibm128 as a distinct type.
+       (init_float128_ieee): Fix up conversions between IFmode and IEEE
+       128-bit types to use the correct functions.
+       (rs6000_expand_float128_convert): Use explicit FLOAT_EXTEND to
+       convert between 128-bit floating point types that have different
+       modes but the same representation, instead of using gen_lowpart to
+       makean alias.
+       * config/rs6000/rs6000.md (IFKF): New iterator for IFmode and
+       KFmode.
+       (IFKF_reg): New attributes to give the register constraints for
+       IFmode and KFmode.
+       (extend<mode>tf2_internal): New insns to mark an explicit
+       conversion between 128-bit floating point types that have a
+       different mode but share the same representation.
+
 2018-05-21  Richard Sandiford  <richard.sandiford@linaro.org>
 
        PR tree-optimization/85814
index 98a812e..6cf5537 100644 (file)
@@ -608,8 +608,6 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfile)
     builtin_define ("__RSQRTEF__");
   if (TARGET_FLOAT128_TYPE)
     builtin_define ("__FLOAT128_TYPE__");
-  if (TARGET_LONG_DOUBLE_128 && FLOAT128_IBM_P (TFmode))
-    builtin_define ("__ibm128=long double");
 #ifdef TARGET_LIBC_PROVIDES_HWCAP_IN_TCB
   builtin_define ("__BUILTIN_CPU_SUPPORTS__");
 #endif
index d62abdf..26d58fc 100644 (file)
@@ -16347,35 +16347,28 @@ rs6000_init_builtins (void)
      floating point, we need make sure the type is non-zero or else self-test
      fails during bootstrap.
 
-     We don't register a built-in type for __ibm128 if the type is the same as
-     long double.  Instead we add a #define for __ibm128 in
-     rs6000_cpu_cpp_builtins to long double.
+     Always create __ibm128 as a separate type, even if the current long double
+     format is IBM extended double.
 
      For IEEE 128-bit floating point, always create the type __ieee128.  If the
      user used -mfloat128, rs6000-c.c will create a define from __float128 to
      __ieee128.  */
-  if (TARGET_LONG_DOUBLE_128 && FLOAT128_IEEE_P (TFmode))
+  if (TARGET_FLOAT128_TYPE)
     {
       ibm128_float_type_node = make_node (REAL_TYPE);
       TYPE_PRECISION (ibm128_float_type_node) = 128;
       SET_TYPE_MODE (ibm128_float_type_node, IFmode);
       layout_type (ibm128_float_type_node);
-
       lang_hooks.types.register_builtin_type (ibm128_float_type_node,
                                              "__ibm128");
-    }
-  else
-    ibm128_float_type_node = long_double_type_node;
 
-  if (TARGET_FLOAT128_TYPE)
-    {
       ieee128_float_type_node = float128_type_node;
       lang_hooks.types.register_builtin_type (ieee128_float_type_node,
                                              "__ieee128");
     }
 
   else
-    ieee128_float_type_node = long_double_type_node;
+    ieee128_float_type_node = ibm128_float_type_node = long_double_type_node;
 
   /* Initialize the modes for builtin_function_type, mapping a machine mode to
      tree type node.  */
@@ -17865,13 +17858,13 @@ init_float128_ieee (machine_mode mode)
       set_conv_libfunc (trunc_optab, SFmode, mode, "__trunckfsf2");
       set_conv_libfunc (trunc_optab, DFmode, mode, "__trunckfdf2");
 
-      set_conv_libfunc (sext_optab, mode, IFmode, "__extendtfkf2");
+      set_conv_libfunc (sext_optab, mode, IFmode, "__trunctfkf2");
       if (mode != TFmode && FLOAT128_IBM_P (TFmode))
-       set_conv_libfunc (sext_optab, mode, TFmode, "__extendtfkf2");
+       set_conv_libfunc (sext_optab, mode, TFmode, "__trunctfkf2");
 
-      set_conv_libfunc (trunc_optab, IFmode, mode, "__trunckftf2");
+      set_conv_libfunc (trunc_optab, IFmode, mode, "__extendkftf2");
       if (mode != TFmode && FLOAT128_IBM_P (TFmode))
-       set_conv_libfunc (trunc_optab, TFmode, mode, "__trunckftf2");
+       set_conv_libfunc (trunc_optab, TFmode, mode, "__extendkftf2");
 
       set_conv_libfunc (sext_optab, mode, SDmode, "__dpd_extendsdkf2");
       set_conv_libfunc (sext_optab, mode, DDmode, "__dpd_extendddkf2");
@@ -21700,9 +21693,9 @@ rs6000_expand_float128_convert (rtx dest, rtx src, bool unsigned_p)
   else
     gcc_unreachable ();
 
-  /* Handle conversion between TFmode/KFmode.  */
+  /* Handle conversion between TFmode/KFmode/IFmode.  */
   if (do_move)
-    emit_move_insn (dest, gen_lowpart (dest_mode, src));
+    emit_insn (gen_rtx_SET (dest, gen_rtx_FLOAT_EXTEND (dest_mode, src)));
 
   /* Handle conversion if we have hardware support.  */
   else if (TARGET_FLOAT128_HW && hw_convert)
@@ -32128,14 +32121,11 @@ rs6000_mangle_type (const_tree type)
       if (type == ieee128_float_type_node)
        return "U10__float128";
 
-      if (TARGET_LONG_DOUBLE_128)
-       {
-         if (type == long_double_type_node)
-           return (TARGET_IEEEQUAD) ? "U10__float128" : "g";
+      if (type == ibm128_float_type_node)
+       return "u8__ibm128";
 
-         if (type == ibm128_float_type_node)
-           return "g";
-       }
+      if (TARGET_LONG_DOUBLE_128 && type == long_double_type_node)
+       return (TARGET_IEEEQUAD) ? "U10__float128" : "g";
     }
 
   /* Mangle IBM extended float long double as `g' (__float128) on
index 6d8e5e2..68c0f3a 100644 (file)
 ; Iterator for 128-bit VSX types for pack/unpack
 (define_mode_iterator FMOVE128_VSX [V1TI KF])
 
+; Iterators for converting to/from TFmode
+(define_mode_iterator IFKF [IF KF])
+
+; Constraints for moving IF/KFmode.
+(define_mode_attr IFKF_reg [(IF "d") (KF "wa")])
+
 ; Whether a floating point move is ok, don't allow SD without hardware FP
 (define_mode_attr fmove_ok [(SF "")
                            (DF "")
   DONE;
 })
 
+(define_insn_and_split "*extend<mode>tf2_internal"
+  [(set (match_operand:TF 0 "gpc_reg_operand" "=<IFKF_reg>")
+       (float_extend:TF
+        (match_operand:IFKF 1 "gpc_reg_operand" "<IFKF_reg>")))]
+   "TARGET_FLOAT128_TYPE
+    && FLOAT128_IBM_P (TFmode) == FLOAT128_IBM_P (<MODE>mode)"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (match_dup 2))]
+{
+  operands[2] = gen_rtx_REG (TFmode, REGNO (operands[1]));
+})
+
+(define_insn_and_split "*extendtf<mode>2_internal"
+  [(set (match_operand:IFKF 0 "gpc_reg_operand" "=<IFKF_reg>")
+       (float_extend:IFKF
+        (match_operand:TF 1 "gpc_reg_operand" "<IFKF_reg>")))]
+   "TARGET_FLOAT128_TYPE
+    && FLOAT128_IBM_P (TFmode) == FLOAT128_IBM_P (<MODE>mode)"
+  "#"
+  "&& reload_completed"
+  [(set (match_dup 0) (match_dup 2))]
+{
+  operands[2] = gen_rtx_REG (<MODE>mode, REGNO (operands[1]));
+})
+
 \f
 ;; Reload helper functions used by rs6000_secondary_reload.  The patterns all
 ;; must have 3 arguments, and scratch register constraint must be a single
index 10b7572..a115f96 100644 (file)
@@ -1,3 +1,14 @@
+2018-05-21  Michael Meissner  <meissner@linux.ibm.com>
+
+       PR target/85657
+       * gcc.target/powerpc/pr85657-1.c: New test for converting between
+       __float128, __ibm128, and long double.
+       * gcc.target/powerpc/pr85657-2.c: Likewise.
+       * gcc.target/powerpc/pr85657-3.c: Likewise.
+       * g++.dg/pr85667.C: New test to make sure __ibm128 is
+       implementated as a separate type internally, and is not just an
+       alias for long double.
+
 2018-05-21  Richard Sandiford  <richard.sandiford@linaro.org>
 
        PR tree-optimization/85814
diff --git a/gcc/testsuite/g++.dg/pr85657.C b/gcc/testsuite/g++.dg/pr85657.C
new file mode 100644 (file)
index 0000000..6b81bc2
--- /dev/null
@@ -0,0 +1,47 @@
+// { dg-do compile { target { powerpc*-*-linux* } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -O2 -mabi=ibmlongdouble -Wno-psabi" }
+
+// PR 85657
+// Check that __ibm128 and long double are represented as different types, even
+// if long double is currently using the same representation as __ibm128.
+
+template <class __T> inline bool
+iszero (__T __val)
+{
+  return __val == 0;
+}
+
+int
+use_template (void)
+{
+  long double ld = 0.0;
+  __ibm128 ibm = 0.0;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+d" (ld), "+d" (ibm));
+#endif
+
+  return iszero (ld) + iszero (ibm);
+}
+
+class foo {
+public:
+  foo () {}
+  ~foo () {}
+  inline bool iszero (long double ld) { return ld == 0.0; }
+  inline bool iszero (__ibm128 i128) { return i128 == 0.0; }
+} st;
+
+int
+use_class (void)
+{
+  long double ld = 0.0;
+  __ibm128 ibm = 0.0;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+d" (ld), "+d" (ibm));
+#endif
+
+  return st.iszero (ld) + st.iszero (ibm);
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/pr85657-1.c b/gcc/testsuite/gcc.target/powerpc/pr85657-1.c
new file mode 100644 (file)
index 0000000..3337d06
--- /dev/null
@@ -0,0 +1,74 @@
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2 -mabi=ibmlongdouble -Wno-psabi" } */
+
+// PR 85657 -- make sure conversions work between each of the 128-bit floating
+// point types.
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+  return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+  return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+  return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+  return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+  return (long double)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+  return (long double)a;
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+volatile __float128 f128 = 1.2Q;
+volatile __ibm128 i128 = (__ibm128)3.4L;
+volatile long double ld = 5.6L;
+
+int
+main (void)
+{
+  printf ("f128 (1.2) = %g (ld), %g (ibm128)\n",
+         (double) float128_to_ldouble (f128),
+         (double) float128_to_ibm128 (f128));
+
+  printf ("i128 (3.4) = %g (ld), %g (float128)\n",
+         (double) ibm128_to_ldouble (i128),
+         (double) ibm128_to_float128 (i128));
+
+  printf ("long double (5.6) = %g (ibm128), %g (float128)\n",
+         (double) ldouble_to_ibm128 (ld),
+         (double) ldouble_to_float128 (ld));
+
+  return 0;
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/powerpc/pr85657-2.c b/gcc/testsuite/gcc.target/powerpc/pr85657-2.c
new file mode 100644 (file)
index 0000000..33113da
--- /dev/null
@@ -0,0 +1,74 @@
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-options "-mvsx -mfloat128 -O2 -mabi=ieeelongdouble -Wno-psabi" } */
+
+// PR 85657 -- make sure conversions work between each of the 128-bit floating
+// point types.
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+  return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+  return (__float128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+  return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+  return (__ibm128)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+  return (long double)a;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+  return (long double)a;
+}
+
+#ifdef TEST
+#include <stdio.h>
+
+volatile __float128 f128 = 1.2Q;
+volatile __ibm128 i128 = (__ibm128)3.4L;
+volatile long double ld = 5.6L;
+
+int
+main (void)
+{
+  printf ("f128 (1.2) = %g (ld), %g (ibm128)\n",
+         (double) float128_to_ldouble (f128),
+         (double) float128_to_ibm128 (f128));
+
+  printf ("i128 (3.4) = %g (ld), %g (float128)\n",
+         (double) ibm128_to_ldouble (i128),
+         (double) ibm128_to_float128 (i128));
+
+  printf ("long double (5.6) = %g (ibm128), %g (float128)\n",
+         (double) ldouble_to_ibm128 (ld),
+         (double) ldouble_to_float128 (ld));
+
+  return 0;
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/powerpc/pr85657-3.c b/gcc/testsuite/gcc.target/powerpc/pr85657-3.c
new file mode 100644 (file)
index 0000000..1d2e69d
--- /dev/null
@@ -0,0 +1,82 @@
+/* { dg-do run { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-require-effective-target vsx_hw } */
+/* { dg-options "-mvsx -O2" } */
+
+/* PR 85657 -- make __ibm128 a full type.  */
+
+__attribute__ ((__noinline__))
+__float128
+ibm128_to_float128 (__ibm128 a)
+{
+  return (__float128)a + 1.0q;
+}
+
+__attribute__ ((__noinline__))
+__float128
+ldouble_to_float128 (long double a)
+{
+  return (__float128)a + 1.0q;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+float128_to_ibm128 (__float128 a)
+{
+  return (__ibm128)a + (__ibm128)1.0;
+}
+
+__attribute__ ((__noinline__))
+__ibm128
+ldouble_to_ibm128 (long double a)
+{
+  return (__ibm128)a + (__ibm128)1.0;
+}
+
+__attribute__ ((__noinline__))
+long double
+ibm128_to_ldouble (__ibm128 a)
+{
+  return (long double)a + 1.0L;
+}
+
+__attribute__ ((__noinline__))
+long double
+float128_to_ldouble (__float128 a)
+{
+  return (long double)a + 1.0L;
+}
+
+volatile __float128  f128 = 1.25Q;
+volatile __ibm128    i128 = (__ibm128)3.5L;
+volatile long double ld   = 4.75L;
+
+volatile double f128_p1 = 2.25;
+volatile double i128_p1 = 4.5;
+volatile double ld_p1   = 5.75;
+
+extern void abort (void);
+
+int
+main (void)
+{
+  if (((double) float128_to_ldouble (f128)) != f128_p1)
+    abort ();
+
+  if (((double) float128_to_ibm128 (f128)) != f128_p1)
+    abort ();
+
+  if (((double) ibm128_to_ldouble (i128)) != i128_p1)
+    abort ();
+
+  if (((double) ibm128_to_float128 (i128)) != i128_p1)
+    abort ();
+
+  if (((double) ldouble_to_ibm128 (ld)) != ld_p1)
+    abort ();
+
+  if (((double) ldouble_to_float128 (ld)) != ld_p1)
+    abort ();
+
+  return 0;
+}