diff mbox series

, PowerPC: Use <math>f128 for long double built-ins if we have changed to use IEEE 128-bit floating point

Message ID 20181023201211.GA5010@ibm-toto.the-meissners.org
State New
Headers show
Series , PowerPC: Use <math>f128 for long double built-ins if we have changed to use IEEE 128-bit floating point | expand

Commit Message

Michael Meissner Oct. 23, 2018, 8:12 p.m. UTC
This patch changes the name used by the <math>l built-in functions that return
or are passed long double if the long double type is changed from the current
IBM long double format to the IEEE 128-bit format.

I have done a bootstrap and make check with no regressions on a little endian
power8 system.  Is it ok to check into the trunk?  This will need to be back
ported to the GCC 8.x branch.

[gcc]
2018-10-23  Michael Meissner  <meissner@linux.ibm.com>

	* config/rs6000/rs6000.c (TARGET_MANGLE_DECL_ASSEMBLER_NAME):
	Define as rs6000_mangle_decl_assembler_name.
	(rs6000_mangle_decl_assembler_name): If the user switched from IBM
	long double to IEEE long double, switch the names of the long
	double built-in functions to be <func>f128 instead of <func>l.

[gcc/testsuite]
2018-10-23  Michael Meissner  <meissner@linux.ibm.com>

	* gcc.target/powerpc/float128-math.c: New test to make sure the
	long double built-in function names use the f128 form if the user
	switched from IBM long double to IEEE long double.
	* gcc.target/powerpc/ppc-fortran/ieee128-math.f90: Likewise.

Comments

Segher Boessenkool Oct. 23, 2018, 9:18 p.m. UTC | #1
Hi Mike,

On Tue, Oct 23, 2018 at 04:12:11PM -0400, Michael Meissner wrote:
> This patch changes the name used by the <math>l built-in functions that return
> or are passed long double if the long double type is changed from the current
> IBM long double format to the IEEE 128-bit format.
> 
> I have done a bootstrap and make check with no regressions on a little endian
> power8 system.  Is it ok to check into the trunk?  This will need to be back
> ported to the GCC 8.x branch.

Could you test it on the usual assortment of systems instead of just one?
BE 7 and 8, LE 8 and 9.  Or wait for possible fallout :-)

A backport to 8 is wanted yes, but please wait as usual.  It's fine after
a week or so of no problems.


> +/* On 64-bit Linux and Freebsd systems, possibly switch the long double library
> +   function names from <foo>l to <foo>f128 if the default long double type is
> +   IEEE 128-bit.  Typically, with the C and C++ languages, the standard math.h
> +   include file switches the names on systems that support long double as IEEE
> +   128-bit, but that doesn't work if the user uses __builtin_<foo>l directly or
> +   if they use Fortran.  Use the TARGET_MANGLE_DECL_ASSEMBLER_NAME hook to
> +   change this name.  We only do this if the default is long double is not IEEE
> +   128-bit, and the user asked for IEEE 128-bit.  */

s/default is/default/

Does this need some synchronisation with the libm headers?  I guess things
will just work out, but it is desirable if libm stops doing this with
compilers that have this change?

> +static tree
> +rs6000_mangle_decl_assembler_name (tree decl, tree id)
> +{
> +  if (!TARGET_IEEEQUAD_DEFAULT && TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128

Write this is in the opposite order?
  if (TARGET_LONG_DOUBLE_128 && TARGET_IEEEQUAD && !TARGET_IEEEQUAD_DEFAULT

> +    {
> +      size_t len = IDENTIFIER_LENGTH (id);
> +      const char *name = IDENTIFIER_POINTER (id);
> +
> +      if (name[len-1] == 'l')
> +	{
> +	  bool has_long_double_p = false;
> +	  tree type = TREE_TYPE (decl);
> +	  machine_mode ret_mode = TYPE_MODE (type);
> +
> +	  /* See if the function returns long double or long double
> +	     complex.  */
> +	  if (ret_mode == TFmode || ret_mode == TCmode)
> +	    has_long_double_p = true;

This comment is a bit misleading I think?  The code checks if it is the
same mode as would be used for long double, not if that is the actual
asked-for type.  The code is fine AFAICS, the comment isn't so great
though.

> +	  else
> +	    {
> +	      function_args_iterator args_iter;
> +	      tree arg;
> +
> +	      /* See if we have a long double or long double complex
> +		 argument.  */

And same here.

> +	      FOREACH_FUNCTION_ARGS (type, arg, args_iter)
> +		{
> +		  machine_mode arg_mode = TYPE_MODE (arg);
> +		  if (arg_mode == TFmode || arg_mode == TCmode)
> +		    {
> +		      has_long_double_p = true;
> +		      break;
> +		    }
> +		}
> +	    }
> +
> +	  /* If we have long double, change the name.  */

And this.

> +	  if (has_long_double_p)
> +	    {
> +	      char *name2 = (char *) alloca (len + 4);
> +	      memcpy (name2, name, len-1);

len - 1


Okay for trunk with those things fixed.  Thanks!


Segher
Michael Meissner Oct. 23, 2018, 9:53 p.m. UTC | #2
On Tue, Oct 23, 2018 at 04:18:55PM -0500, Segher Boessenkool wrote:
> Hi Mike,
> 
> On Tue, Oct 23, 2018 at 04:12:11PM -0400, Michael Meissner wrote:
> > This patch changes the name used by the <math>l built-in functions that return
> > or are passed long double if the long double type is changed from the current
> > IBM long double format to the IEEE 128-bit format.
> > 
> > I have done a bootstrap and make check with no regressions on a little endian
> > power8 system.  Is it ok to check into the trunk?  This will need to be back
> > ported to the GCC 8.x branch.
> 
> Could you test it on the usual assortment of systems instead of just one?
> BE 7 and 8, LE 8 and 9.  Or wait for possible fallout :-)

Ok.

> A backport to 8 is wanted yes, but please wait as usual.  It's fine after
> a week or so of no problems.

Yep.

> 
> > +/* On 64-bit Linux and Freebsd systems, possibly switch the long double library
> > +   function names from <foo>l to <foo>f128 if the default long double type is
> > +   IEEE 128-bit.  Typically, with the C and C++ languages, the standard math.h
> > +   include file switches the names on systems that support long double as IEEE
> > +   128-bit, but that doesn't work if the user uses __builtin_<foo>l directly or
> > +   if they use Fortran.  Use the TARGET_MANGLE_DECL_ASSEMBLER_NAME hook to
> > +   change this name.  We only do this if the default is long double is not IEEE
> > +   128-bit, and the user asked for IEEE 128-bit.  */
> 
> s/default is/default/
> 
> Does this need some synchronisation with the libm headers?  I guess things
> will just work out, but it is desirable if libm stops doing this with
> compilers that have this change?

It should just work out assuming you are using a recent enough GLIBC.  The
patch is more for when you aren't using headers.

> > +static tree
> > +rs6000_mangle_decl_assembler_name (tree decl, tree id)
> > +{
> > +  if (!TARGET_IEEEQUAD_DEFAULT && TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
> 
> Write this is in the opposite order?
>   if (TARGET_LONG_DOUBLE_128 && TARGET_IEEEQUAD && !TARGET_IEEEQUAD_DEFAULT

Because !TARGET_IEEEQUAD_DEFAULT is a constant test.  If you are on a system
that defaults to IEEE 128-bit, the whole code gets deleted.  I would hope the
tests still get deleted if it occurs later in the test, but I tend to put the
things that can be optimized at compile time first.

> > +    {
> > +      size_t len = IDENTIFIER_LENGTH (id);
> > +      const char *name = IDENTIFIER_POINTER (id);
> > +
> > +      if (name[len-1] == 'l')
> > +	{
> > +	  bool has_long_double_p = false;
> > +	  tree type = TREE_TYPE (decl);
> > +	  machine_mode ret_mode = TYPE_MODE (type);
> > +
> > +	  /* See if the function returns long double or long double
> > +	     complex.  */
> > +	  if (ret_mode == TFmode || ret_mode == TCmode)
> > +	    has_long_double_p = true;
> 
> This comment is a bit misleading I think?  The code checks if it is the
> same mode as would be used for long double, not if that is the actual
> asked-for type.  The code is fine AFAICS, the comment isn't so great
> though.

Well the long double type is 'TFmode'.  Though _Float128 does get mapped to
TFmode instead of KFmode also.  But explicit f128 built-ins won't go through
here, since they don't end in 'l'.  I'm just trying to avoid things like CLZL
that take long arguments and not long double.

> > +	  else
> > +	    {
> > +	      function_args_iterator args_iter;
> > +	      tree arg;
> > +
> > +	      /* See if we have a long double or long double complex
> > +		 argument.  */
> 
> And same here.
> 
> > +	      FOREACH_FUNCTION_ARGS (type, arg, args_iter)
> > +		{
> > +		  machine_mode arg_mode = TYPE_MODE (arg);
> > +		  if (arg_mode == TFmode || arg_mode == TCmode)
> > +		    {
> > +		      has_long_double_p = true;
> > +		      break;
> > +		    }
> > +		}
> > +	    }
> > +
> > +	  /* If we have long double, change the name.  */
> 
> And this.
> 
> > +	  if (has_long_double_p)
> > +	    {
> > +	      char *name2 = (char *) alloca (len + 4);
> > +	      memcpy (name2, name, len-1);
> 
> len - 1

Ok.

> Okay for trunk with those things fixed.  Thanks!
> 
> 
> Segher
>
Joseph Myers Oct. 23, 2018, 10:22 p.m. UTC | #3
On Tue, 23 Oct 2018, Michael Meissner wrote:

> 2018-10-23  Michael Meissner  <meissner@linux.ibm.com>
> 
> 	* config/rs6000/rs6000.c (TARGET_MANGLE_DECL_ASSEMBLER_NAME):
> 	Define as rs6000_mangle_decl_assembler_name.
> 	(rs6000_mangle_decl_assembler_name): If the user switched from IBM
> 	long double to IEEE long double, switch the names of the long
> 	double built-in functions to be <func>f128 instead of <func>l.

[This is the issue discussed at the Cauldron of how to get the 
redirections correct in any case that does not involve including the 
standard <math.h> to get the function declarations.]

My understanding was that __<func>ieee128 aliases would be added to glibc 
(indeed, the relevant names are present in 
sysdeps/ieee754/ldbl-128ibm-compat/Versions in glibc, albeit without 
actually being enabled for powerpc64le yet), for two reasons: (a) to be 
namespace-clean for standard C, and (b) because a few libm functions (and 
many libc functions) have no _Float128 analogues but are still part of the 
API for long double (e.g. the nexttoward functions, where nexttowardf, 
nexttoward also need different versions for IEEE 128-bit long double, or 
scalbl, which is somewhat obsolescent but still supported).

Now, you can't use the __<func>ieee128 names with *current* glibc because 
they aren't exported yet.  So is the plan that GCC would later switch to 
using the __<func>ieee128 names when available based on TARGET_GLIBC_MAJOR 
and TARGET_GLIBC_MINOR (as more namespace-correct, and available for some 
functions without <func>f128 variants), with use of <func>f128 only a 
fallback for older glibc versions lacking __<func>ieee128?
Michael Meissner Oct. 23, 2018, 11:40 p.m. UTC | #4
On Tue, Oct 23, 2018 at 10:22:41PM +0000, Joseph Myers wrote:
> On Tue, 23 Oct 2018, Michael Meissner wrote:
> 
> > 2018-10-23  Michael Meissner  <meissner@linux.ibm.com>
> > 
> > 	* config/rs6000/rs6000.c (TARGET_MANGLE_DECL_ASSEMBLER_NAME):
> > 	Define as rs6000_mangle_decl_assembler_name.
> > 	(rs6000_mangle_decl_assembler_name): If the user switched from IBM
> > 	long double to IEEE long double, switch the names of the long
> > 	double built-in functions to be <func>f128 instead of <func>l.
> 
> [This is the issue discussed at the Cauldron of how to get the 
> redirections correct in any case that does not involve including the 
> standard <math.h> to get the function declarations.]
> 
> My understanding was that __<func>ieee128 aliases would be added to glibc 
> (indeed, the relevant names are present in 
> sysdeps/ieee754/ldbl-128ibm-compat/Versions in glibc, albeit without 
> actually being enabled for powerpc64le yet), for two reasons: (a) to be 
> namespace-clean for standard C, and (b) because a few libm functions (and 
> many libc functions) have no _Float128 analogues but are still part of the 
> API for long double (e.g. the nexttoward functions, where nexttowardf, 
> nexttoward also need different versions for IEEE 128-bit long double, or 
> scalbl, which is somewhat obsolescent but still supported).
> 
> Now, you can't use the __<func>ieee128 names with *current* glibc because 
> they aren't exported yet.  So is the plan that GCC would later switch to 
> using the __<func>ieee128 names when available based on TARGET_GLIBC_MAJOR 
> and TARGET_GLIBC_MINOR (as more namespace-correct, and available for some 
> functions without <func>f128 variants), with use of <func>f128 only a 
> fallback for older glibc versions lacking __<func>ieee128?

I suspect the timing may not be right for GCC 9, since I tend to use the
Advance Toolchain to get newer glibc's, and they are on 2.28.  I just tried it,
and as you said, they aren't exported yet.

However, I am somewhat relunctant to do patches if I don't have a glibc that
properly exports them.
Michael Meissner Oct. 24, 2018, 8:22 p.m. UTC | #5
Here is the patch I just committed.

[gcc]
2018-10-24  Michael Meissner  <meissner@linux.ibm.com>

	* config/rs6000/rs6000.c (TARGET_MANGLE_DECL_ASSEMBLER_NAME):
	Define as rs6000_mangle_decl_assembler_name.
	(rs6000_mangle_decl_assembler_name): If the user switched from IBM
	long double to IEEE long double, switch the names of the long
	double built-in functions to be <func>f128 instead of <func>l.

[gcc/testsuite]
2018-10-24  Michael Meissner  <meissner@linux.ibm.com>

	* gcc.target/powerpc/float128-math.c: New test to make sure the
	long double built-in function names use the f128 form if the user
	switched from IBM long double to IEEE long double.
	* gcc.target/powerpc/ppc-fortran/ieee128-math.f90: Likewise.
Segher Boessenkool Oct. 24, 2018, 10:02 p.m. UTC | #6
On Tue, Oct 23, 2018 at 05:53:15PM -0400, Michael Meissner wrote:
> > > +static tree
> > > +rs6000_mangle_decl_assembler_name (tree decl, tree id)
> > > +{
> > > +  if (!TARGET_IEEEQUAD_DEFAULT && TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
> > 
> > Write this is in the opposite order?
> >   if (TARGET_LONG_DOUBLE_128 && TARGET_IEEEQUAD && !TARGET_IEEEQUAD_DEFAULT
> 
> Because !TARGET_IEEEQUAD_DEFAULT is a constant test.  If you are on a system
> that defaults to IEEE 128-bit, the whole code gets deleted.  I would hope the
> tests still get deleted if it occurs later in the test, but I tend to put the
> things that can be optimized at compile time first.

The compiler can work out what is constant by itself just fine ;-)  Please
try to optimise our code for readability, instead.

TARGET_IEEEQUAD_DEFAULT does not make much sense unless TARGET_IEEEQUAD is
set, and that itself not unless TARGET_LONG_DOUBLE is set.

> > This comment is a bit misleading I think?  The code checks if it is the
> > same mode as would be used for long double, not if that is the actual
> > asked-for type.  The code is fine AFAICS, the comment isn't so great
> > though.
> 
> Well the long double type is 'TFmode'.  Though _Float128 does get mapped to
> TFmode instead of KFmode also.  But explicit f128 built-ins won't go through
> here, since they don't end in 'l'.  I'm just trying to avoid things like CLZL
> that take long arguments and not long double.

modes and types are very different things.  A mode is something on the
level of your machine language, while a type is something on the level of
your source language.  "long double" is a type, and it can be DFmode,
TFmode, IFmode, KFmode.  IFmode can also be __ibm128, etc.

Talking about "types" here is very confusing.


Segher
Segher Boessenkool Oct. 24, 2018, 10:11 p.m. UTC | #7
On Tue, Oct 23, 2018 at 07:40:04PM -0400, Michael Meissner wrote:
> On Tue, Oct 23, 2018 at 10:22:41PM +0000, Joseph Myers wrote:
> > Now, you can't use the __<func>ieee128 names with *current* glibc because 
> > they aren't exported yet.  So is the plan that GCC would later switch to 
> > using the __<func>ieee128 names when available based on TARGET_GLIBC_MAJOR 
> > and TARGET_GLIBC_MINOR (as more namespace-correct, and available for some 
> > functions without <func>f128 variants), with use of <func>f128 only a 
> > fallback for older glibc versions lacking __<func>ieee128?
> 
> I suspect the timing may not be right for GCC 9, since I tend to use the
> Advance Toolchain to get newer glibc's, and they are on 2.28.  I just tried it,
> and as you said, they aren't exported yet.

GCC 9 won't be released until half a year from now.


Segher
diff mbox series

Patch

Index: gcc/config/rs6000/rs6000.c
===================================================================
--- gcc/config/rs6000/rs6000.c	(revision 265400)
+++ gcc/config/rs6000/rs6000.c	(working copy)
@@ -1981,6 +1981,9 @@  static const struct attribute_spec rs600
 
 #undef TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P
 #define TARGET_SETJMP_PRESERVES_NONVOLATILE_REGS_P hook_bool_void_true
+
+#undef TARGET_MANGLE_DECL_ASSEMBLER_NAME
+#define TARGET_MANGLE_DECL_ASSEMBLER_NAME rs6000_mangle_decl_assembler_name
 
 
 /* Processor table.  */
@@ -38965,6 +38968,67 @@  rs6000_globalize_decl_name (FILE * strea
 #endif
 
 
+/* On 64-bit Linux and Freebsd systems, possibly switch the long double library
+   function names from <foo>l to <foo>f128 if the default long double type is
+   IEEE 128-bit.  Typically, with the C and C++ languages, the standard math.h
+   include file switches the names on systems that support long double as IEEE
+   128-bit, but that doesn't work if the user uses __builtin_<foo>l directly or
+   if they use Fortran.  Use the TARGET_MANGLE_DECL_ASSEMBLER_NAME hook to
+   change this name.  We only do this if the default is long double is not IEEE
+   128-bit, and the user asked for IEEE 128-bit.  */
+
+static tree
+rs6000_mangle_decl_assembler_name (tree decl, tree id)
+{
+  if (!TARGET_IEEEQUAD_DEFAULT && TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
+      && TREE_CODE (decl) == FUNCTION_DECL && DECL_IS_BUILTIN (decl) )
+    {
+      size_t len = IDENTIFIER_LENGTH (id);
+      const char *name = IDENTIFIER_POINTER (id);
+
+      if (name[len-1] == 'l')
+	{
+	  bool has_long_double_p = false;
+	  tree type = TREE_TYPE (decl);
+	  machine_mode ret_mode = TYPE_MODE (type);
+
+	  /* See if the function returns long double or long double
+	     complex.  */
+	  if (ret_mode == TFmode || ret_mode == TCmode)
+	    has_long_double_p = true;
+	  else
+	    {
+	      function_args_iterator args_iter;
+	      tree arg;
+
+	      /* See if we have a long double or long double complex
+		 argument.  */
+	      FOREACH_FUNCTION_ARGS (type, arg, args_iter)
+		{
+		  machine_mode arg_mode = TYPE_MODE (arg);
+		  if (arg_mode == TFmode || arg_mode == TCmode)
+		    {
+		      has_long_double_p = true;
+		      break;
+		    }
+		}
+	    }
+
+	  /* If we have long double, change the name.  */
+	  if (has_long_double_p)
+	    {
+	      char *name2 = (char *) alloca (len + 4);
+	      memcpy (name2, name, len-1);
+	      strcpy (name2 + len - 1, "f128");
+	      id = get_identifier (name2);
+	    }
+	}
+    }
+
+  return id;
+}
+
+
 struct gcc_target targetm = TARGET_INITIALIZER;
 
 #include "gt-rs6000.h"
Index: gcc/testsuite/gcc.target/powerpc/float128-math.c
===================================================================
--- gcc/testsuite/gcc.target/powerpc/float128-math.c	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/float128-math.c	(working copy)
@@ -0,0 +1,20 @@ 
+/* { dg-do compile { target { powerpc*-*-linux* } } } */
+/* { dg-require-effective-target ppc_float128_sw } */
+/* { dg-require-effective-target vsx_hw } */
+/* { dg-options "-mvsx -O2 -mfloat128 -mabi=ieeelongdouble -Wno-psabi" } */
+
+/* Test whether we convert __builtin_<math>l to __builtin_<math>f128 if the
+   default long double type is IEEE 128-bit.  Also test that using the explicit
+   __builtin_<math>f128 function does not interfere with the __builtin_<math>l
+   function.  */
+
+extern __float128 sinf128 (__float128);
+
+void foo (__float128 *p, long double *q, long double *r)
+{
+  *p = sinf128 (*p);
+  *q = __builtin_sinl (*q);
+}
+
+/* { dg-final { scan-assembler-times {\mbl sinf128\M} 2 } } */
+/* { dg-final { scan-assembler-not   {\mbl sinl\M}      } } */
Index: gcc/testsuite/gcc.target/powerpc/ppc-fortran/ieee128-math.f90
===================================================================
--- gcc/testsuite/gcc.target/powerpc/ppc-fortran/ieee128-math.f90	(revision 0)
+++ gcc/testsuite/gcc.target/powerpc/ppc-fortran/ieee128-math.f90	(working copy)
@@ -0,0 +1,20 @@ 
+! { dg-do compile { target { powerpc*-*-linux* } } }
+! { dg-require-effective-target ppc_float128_sw }
+! { dg-require-effective-target vsx_hw }
+! { dg-options "-mvsx -mabi=ieeelongdouble -mfloat128" }
+! { dg-excess-errors "expect error due to switching long double type" }
+! Since the error message is not associated with a particular line
+! number, we cannot use the dg-error directive and cannot specify a
+! regexp to describe the expected error message.  The expected warning
+! message is:
+!  "Warning: Using IEEE extended precision long double [-Wpsabi]"
+
+program test_qp
+   implicit none
+   real(16), volatile :: fp1, fp2;
+   fp1 = 2.0
+   fp2 = log (fp1)
+end
+
+! { dg-final { scan-assembler-not {\mbl logl\M}    } }
+! { dg-final { scan-assembler     {\mbl logf128\M} } }