[PATCH], Backport IEEE 128-bit changes to GCC 8.x, Patch #1

Michael Meissner meissner@linux.ibm.com
Mon Jun 18 22:43:00 GMT 2018


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  <meissner@linux.ibm.com>

	Back port from trunk
	2018-05-21  Michael Meissner  <meissner@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  <meissner@linux.ibm.com>

	Back port from trunk
	2018-05-21  Michael Meissner  <meissner@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: meissner@linux.ibm.com, phone: +1 (978) 899-4797
-------------- next part --------------
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;
+}


More information about the Gcc-patches mailing list