On Mon, Apr 16, 2018 at 11:53:13AM -0500, Segher Boessenkool wrote:
> Hi!
> 
> Thank you for working on this.
> 
> On Sun, Apr 15, 2018 at 03:50:44PM -0400, Michael Meissner wrote:
> > PR target/85075 shows that there are some problems with the types for the 3
> > 128-bit floating point types on the PowerPC:
> > 
> >     __float128      (and _Float128 in C, IEEE 128-bit)
> >     __ieee128       (IBM extended double)
> 
> (You mean __ibm128, right?)

Yes.

> >     long double     (either IEEE 128-bit or IBM extended double)
> 
> > In developing this patch, Segher noticed that the mangling for __float128
> > violated the mangling standards.  This patch includes a change to use a more
> > official mangling (u10__float128).
> 
> To use a mangling that works *at all*, yeah.
> 
> > This means that GCC 8 will not be able to
> > link with C++ functions that pass or return __float128 values compiled with 
> > GCC
> > 6 or GCC 7.  I have put in a warning if __float128 is mangled.  The warning 
> > can
> > be silenced by using -Wno-psabi.
> 
> It's a note, not a warning (so -Werror won't fail builds, etc.)
> 
> > In addition, when I built this on big endian system, the changes exposed a
> > latent bug with the way __builtin_packlongdouble was done when it tried to
> > support the first argument overlapping with the result.  I have removed the
> > code to support overlapping input/output for this builtin.  I imagine that 
> > we
> > will need to add __builtin_packieee128 and __builtin_unpackieee128 as well 
> > in
> > the future (or make __builtin_{,un}packlongdouble support all three types).
> 
> Please send this part as a separate patch.  It will need backports, too.

I opened up PR 85424, and submitted this patch:
https://gcc.gnu.org/ml/gcc-patches/2018-04/msg00767.html

Here is the PR 85075 patch without the rs6000.md bits:

[gcc]
2018-04-16  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        PR target/85075
        * config/rs6000/rs6000-c.c (rs6000_cpu_cpp_builtins): __ibm128 is
        now a separate type, don't #define __ibm128 as long double.
        * config/rs6000/rs6000.c (rs6000_init_builtins): Make __ibm128 a
        separate type on systems that support IEEE 128-bit floating point.
        (rs6000_mangle_type): Use separate manglings for __ibm128 and
        __float128.  Change __float128 mangling from U10__float128 to
        u10__float128.  Issue a warning that the mangling has changed in
        GCC 8.

[gcc/testsuite]
2018-04-16  Michael Meissner  <meiss...@linux.vnet.ibm.com>

        PR target/85075
        * g++.dg/pr85075-1.C: New tests.  Make sure that __float128,
        __ibm128, and long double are different types, and that you can
        mix them in templates and with overloaded functions.  Test all 3
        different long dobule variants (IEEE 128 bit, IBM 128 bit, and 64
        bit).
        * g++.dg/pr85075-2.C: Likewise.
        * g++.dg/pr85075-3.C: Likewise.

-- 
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.c
===================================================================
--- gcc/config/rs6000/rs6000-c.c        (revision 259376)
+++ gcc/config/rs6000/rs6000-c.c        (working copy)
@@ -617,8 +617,6 @@ rs6000_cpu_cpp_builtins (cpp_reader *pfi
     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: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c  (revision 259376)
+++ gcc/config/rs6000/rs6000.c  (working copy)
@@ -16994,28 +16994,22 @@ rs6000_init_builtins (void)
      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.  */
@@ -32902,24 +32896,32 @@ rs6000_mangle_type (const_tree type)
   if (type == bool_int_type_node) return "U6__booli";
   if (type == bool_long_long_type_node) return "U6__boolx";
 
-  /* Use a unique name for __float128 rather than trying to use "e" or "g". Use
-     "g" for IBM extended double, no matter whether it is long double (using
-     -mabi=ibmlongdouble) or the distinct __ibm128 type.  */
-  if (TARGET_FLOAT128_TYPE)
-    {
-      if (type == ieee128_float_type_node)
-       return "U10__float128";
+  /* Use a unique name for __float128/__ibm128 rather than trying to use "e" or
+     "g".  While, "g" in theory should be used for __float128, the PowerPC
+     compiler has used "g" for IBM extended double for a long time.  Use
+     u10__float128 for the separate __float128 type (_Float128 in C), and
+     u9__ieee128 for long double when -mabi=ieeelongdouble is used.
 
-      if (TARGET_LONG_DOUBLE_128)
+     GCC 6/7 used U10__float128 instead of u10__float128.  */
+  if (type == ieee128_float_type_node)
+    {
+      static bool warned;
+      if (!warned && warn_psabi)
        {
-         if (type == long_double_type_node)
-           return (TARGET_IEEEQUAD) ? "U10__float128" : "g";
-
-         if (type == ibm128_float_type_node)
-           return "g";
+         warned = true;
+         inform (input_location,
+                 "the name mangling for __float128 types changed in GCC 8");
        }
+      return "u10__float128";
     }
 
+  if (type == ibm128_float_type_node)
+    return "u8__ibm128";
+
+  if (TARGET_FLOAT128_TYPE && TARGET_LONG_DOUBLE_128
+      && type == long_double_type_node)
+    return (TARGET_IEEEQUAD) ? "u9__ieee128" : "g";
+
   /* Mangle IBM extended float long double as `g' (__float128) on
      powerpc*-linux where long-double-64 previously was the default.  */
   if (TYPE_MAIN_VARIANT (type) == long_double_type_node
Index: gcc/testsuite/g++.dg/pr85075-1.C
===================================================================
--- gcc/testsuite/g++.dg/pr85075-1.C    (revision 0)
+++ gcc/testsuite/g++.dg/pr85075-1.C    (revision 0)
@@ -0,0 +1,58 @@
+// { dg-do compile { target { powerpc*-*-linux* } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -O2 -mabi=ieeelongdouble -Wno-psabi" } */
+
+// PR 85075
+// If you used a template for both long double and __float128, it would
+// complain that the same mangling was used for different types.  Previously,
+// __float128 was defined to __ieee128 (the keyword where the the _Float128
+// type is defined).  Note, __float128 is defined to be 'long double' if
+// -mabi=ieeelongdouble is used.
+
+template <class __T> inline bool
+iszero (__T __val)
+{
+  return __val == 0;
+}
+
+#ifdef _ARCH_PWR7
+#ifdef __LONG_DOUBLE_IEEE128__
+#define LD_CONSTRAINT "wa"
+#else
+#define LD_CONSTRAINT "d"
+#endif
+#endif
+
+int
+use_template (void)
+{
+  long double q1 = 0.0l;
+  __float128 q = 0.0q;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+" LD_CONSTRAINT (q1), "+wa" (q));
+#endif
+
+  return iszero (q1) + iszero (q);
+}
+
+class foo {
+public:
+  foo () {}
+  ~foo () {}
+  inline bool iszero (long double ld) { return ld == 0.0L; }
+  inline bool iszero (__float128 f128) { return f128 == 0.0Q; }
+} st;
+
+int
+use_class (void)
+{
+  long double q1 = 0.0l;
+  __float128 q = 0.0q;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+" LD_CONSTRAINT (q1), "+wa" (q));
+#endif
+
+  return st.iszero (q1) + st.iszero (q);
+}
Index: gcc/testsuite/g++.dg/pr85075-2.C
===================================================================
--- gcc/testsuite/g++.dg/pr85075-2.C    (revision 0)
+++ gcc/testsuite/g++.dg/pr85075-2.C    (revision 0)
@@ -0,0 +1,58 @@
+// { dg-do compile { target { powerpc*-*-linux* } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -O2 -mabi=ibmlongdouble -Wno-psabi" } */
+
+// PR 85075
+// If you used a template for both long double and __float128, it would
+// complain that the same mangling was used for different types.  Previously,
+// __float128 was defined to __ieee128 (the keyword where the the _Float128
+// type is defined).  Note, __float128 is defined to be 'long double' if
+// -mabi=ieeelongdouble is used.
+
+template <class __T> inline bool
+iszero (__T __val)
+{
+  return __val == 0;
+}
+
+#ifdef _ARCH_PWR7
+#ifdef __LONG_DOUBLE_IEEE128__
+#define LD_CONSTRAINT "wa"
+#else
+#define LD_CONSTRAINT "d"
+#endif
+#endif
+
+int
+use_template (void)
+{
+  long double q1 = 0.0l;
+  __float128 q = 0.0q;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+" LD_CONSTRAINT (q1), "+wa" (q));
+#endif
+
+  return iszero (q1) + iszero (q);
+}
+
+class foo {
+public:
+  foo () {}
+  ~foo () {}
+  inline bool iszero (long double ld) { return ld == 0.0L; }
+  inline bool iszero (__float128 f128) { return f128 == 0.0Q; }
+} st;
+
+int
+use_class (void)
+{
+  long double q1 = 0.0l;
+  __float128 q = 0.0q;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+" LD_CONSTRAINT (q1), "+wa" (q));
+#endif
+
+  return st.iszero (q1) + st.iszero (q);
+}
Index: gcc/testsuite/g++.dg/pr85075-3.C
===================================================================
--- gcc/testsuite/g++.dg/pr85075-3.C    (revision 0)
+++ gcc/testsuite/g++.dg/pr85075-3.C    (revision 0)
@@ -0,0 +1,58 @@
+// { dg-do compile { target { powerpc*-*-linux* } } }
+// { dg-require-effective-target ppc_float128_sw }
+// { dg-options "-mvsx -mfloat128 -O2 -mlong-double-64 -Wno-psabi" } */
+
+// PR 85075
+// If you used a template for both long double and __float128, it would
+// complain that the same mangling was used for different types.  Previously,
+// __float128 was defined to __ieee128 (the keyword where the the _Float128
+// type is defined).  Note, __float128 is defined to be 'long double' if
+// -mabi=ieeelongdouble is used.
+
+template <class __T> inline bool
+iszero (__T __val)
+{
+  return __val == 0;
+}
+
+#ifdef _ARCH_PWR7
+#ifdef __LONG_DOUBLE_IEEE128__
+#define LD_CONSTRAINT "wa"
+#else
+#define LD_CONSTRAINT "d"
+#endif
+#endif
+
+int
+use_template (void)
+{
+  long double q1 = 0.0l;
+  __float128 q = 0.0q;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+" LD_CONSTRAINT (q1), "+wa" (q));
+#endif
+
+  return iszero (q1) + iszero (q);
+}
+
+class foo {
+public:
+  foo () {}
+  ~foo () {}
+  inline bool iszero (long double ld) { return ld == 0.0L; }
+  inline bool iszero (__float128 f128) { return f128 == 0.0Q; }
+} st;
+
+int
+use_class (void)
+{
+  long double q1 = 0.0l;
+  __float128 q = 0.0q;
+
+#ifdef _ARCH_PWR7
+  __asm__ (" # %x0, %x1" : "+" LD_CONSTRAINT (q1), "+wa" (q));
+#endif
+
+  return st.iszero (q1) + st.iszero (q);
+}

Reply via email to