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); +}