This patch is the first of two patches to make the __ibm128 type a distict type. Previously, when I impemented __ibm128, I had defined it to be long double on systems where long double used the IBM extended double format. Segher asked that I always create the type as a distinct type. For C++, I have chosen to use u8__ibm128 as the mangling for __ibm128.
I discovered in writing this patch, I needed to tweak the table of the conversion functions, and I had to converting types that have different modes, but have the same representation. The second patch will add new unpack/pack builtin functions for __ibm128. That patch will also give an error if the long double default is changed, and the user uses the pack/unpack long double functions. I have done bootstrap tests on a little endian power8 system, and verified that there were no regressions. I also verified that the new tests run correctly. I also have looked at the code for -mabi=ieeelongdouble, to verify that it is still working when the default for long double is changed. Can I install this in the GCC 9 trunk? This will need to be back ported to GCC 8.2. [gcc] 2018-05-18 Michael Meissner <meiss...@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-18 Michael Meissner <meiss...@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. -- Michael Meissner, IBM IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA email: meiss...@linux.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000-c.c =================================================================== --- gcc/config/rs6000/rs6000-c.c (.../trunk) (revision 260267) +++ gcc/config/rs6000/rs6000-c.c (.../branches/ibm/ieee) (revision 260381) @@ -608,8 +608,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 (.../trunk) (revision 260267) +++ gcc/config/rs6000/rs6000.c (.../branches/ibm/ieee) (revision 260381) @@ -16345,35 +16350,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. */ @@ -17863,13 +17861,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"); @@ -21698,9 +21696,9 @@ rs6000_expand_float128_convert (rtx dest 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) @@ -32126,14 +32124,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: gcc/config/rs6000/rs6000.md =================================================================== --- gcc/config/rs6000/rs6000.md (.../trunk) (revision 260267) +++ gcc/config/rs6000/rs6000.md (.../branches/ibm/ieee) (revision 260381) @@ -422,6 +422,12 @@ (define_mode_iterator FMOVE128_GPR [TI ; 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 "") @@ -8188,6 +8194,32 @@ (define_expand "trunctfif2" 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])); +}) + ;; Reload helper functions used by rs6000_secondary_reload. The patterns all ;; must have 3 arguments, and scratch register constraint must be a single Index: gcc/testsuite/gcc.target/powerpc/pr85657-1.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/pr85657-1.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.target/powerpc/pr85657-1.c (.../branches/ibm/ieee) (revision 260381) @@ -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 Index: gcc/testsuite/gcc.target/powerpc/pr85657-2.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/pr85657-2.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.target/powerpc/pr85657-2.c (.../branches/ibm/ieee) (revision 260381) @@ -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 Index: gcc/testsuite/gcc.target/powerpc/pr85657-3.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/pr85657-3.c (.../trunk) (revision 0) +++ gcc/testsuite/gcc.target/powerpc/pr85657-3.c (.../branches/ibm/ieee) (revision 260381) @@ -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; +} Index: gcc/testsuite/g++.dg/pr85657.C =================================================================== --- gcc/testsuite/g++.dg/pr85657.C (.../trunk) (revision 0) +++ gcc/testsuite/g++.dg/pr85657.C (.../branches/ibm/ieee) (revision 260381) @@ -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); +}