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 <[email protected]>
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 <[email protected]>
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: [email protected], 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);
+}