As we have discussed on the patch submission, I'm going to be back porting the IEEE 128-bit changes that we've made recently in the trunk to the GCC 8.x branch. The motivation is to allow distributions to switch to IEEE 128-bit long double without having to wait for the GCC 9.1 compiler.
I'm sending out these patches in terms of the submission to the FSF trunk. I will probably wait a few days before committing the patches just in case something major was broken. Patch #1 is the May 21st submission. Note, in this patch, we had 3 separate types activelly used (__ibm128, __float128, and long double). However we eventually decided we only wanted to use 2 types, and this changed in Patch #2. Patch #2 is the June 1-8th changes by me (Michael Meissner), Segher Boessenkool and David Edelsohn. In the second set of changed we changed this to the current two active types, one of which is the long double type, and other is the alternate type. We also changed the C++ mangling of the float128 type (and long double if it uses the IEEE 128-bit encoding) from "U10__float128" to "u9__ieee128". We put out weak aliases so that old code could still call functions compiled with the new compiler. Patch #3 is the change committed on June 18th that reworks the internal ordering of the 128-bit binary floating point types. This prevents the machine independent portions of the compiler trying to convert __ibm128 data to __float128 if you are running on a Power9 (ISA 3.0) system that has 128-bit hardware floating point support. Patch #4 will be a collection of small patches to fix some problems that were noticed in running the test suite with the long double default changed to IEEE 128-bit floating point. This is patch #1. Patches #1 and #2 were tested together on a little endian power8 system. I did two runs. The first run used the default long double as IBM extended double, and there were no regressions. The second run changed the default to IEEE 128-bit floating point. The regressions were the same as in the GCC trunk for the same submission level. [gcc] 2018-06-18 Michael Meissner <meiss...@linux.ibm.com> Back port from trunk 2018-05-21 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): Create __ibm128 as a distinct type with IEEE 128-bit floating point is supported. (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-06-18 Michael Meissner <meiss...@linux.ibm.com> Back port from trunk 2018-05-21 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 (revision 261664) +++ 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 261664) +++ gcc/config/rs6000/rs6000.c (working copy) @@ -17027,35 +17027,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. */ @@ -18679,13 +18672,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"); @@ -22514,9 +22507,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) @@ -32951,14 +32944,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 (revision 261664) +++ gcc/config/rs6000/rs6000.md (working copy) @@ -428,6 +428,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 "") @@ -8168,6 +8174,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/g++.dg/pr85657.C =================================================================== --- gcc/testsuite/g++.dg/pr85657.C (revision 0) +++ gcc/testsuite/g++.dg/pr85657.C (working copy) @@ -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); +} Index: gcc/testsuite/gcc.target/powerpc/pr85657-1.c =================================================================== --- gcc/testsuite/gcc.target/powerpc/pr85657-1.c (revision 0) +++ gcc/testsuite/gcc.target/powerpc/pr85657-1.c (working copy) @@ -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 (revision 0) +++ gcc/testsuite/gcc.target/powerpc/pr85657-2.c (working copy) @@ -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 (revision 0) +++ gcc/testsuite/gcc.target/powerpc/pr85657-3.c (working copy) @@ -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; +}