public inbox for gcc-cvs@sourceware.org
help / color / mirror / Atom feed
* [gcc(refs/users/meissner/heads/work019)] PowerPC: Map long double built-in functions if IEEE 128-bit long double.
@ 2020-10-08 19:28 Michael Meissner
  0 siblings, 0 replies; 4+ messages in thread
From: Michael Meissner @ 2020-10-08 19:28 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:62758f095c226a976167ddf0ee747cf6d53bb491

commit 62758f095c226a976167ddf0ee747cf6d53bb491
Author: Michael Meissner <meissner@linux.ibm.com>
Date:   Thu Oct 8 15:26:02 2020 -0400

    PowerPC: Map long double built-in functions if IEEE 128-bit long double.
    
    This patch goes through the built-in functions and changes the name that is
    used to the name used for __float128 and _Float128 support in glibc if the
    PowerPC long double type is IEEE 128-bit instead of IBM extended double.
    
    Normally the mapping is done in the math.h and stdio.h files.  However, not
    everybody uses these files, which means we also need to change the external
    name for the built-in function within the compiler.
    
    In addition, changing the name in GCC allows the Fortran compiler to
    automatically use the correct name.
    
    To map the math functions, typically this patch changes <name>l to <name>f128.
    However there are some exceptions that are handled with this patch.
    
    To map the printf functions, <name> is mapped to __<name>ieee128.
    
    To map the scanf functions, <name> is mapped to __isoc99<name>ieee128.
    
    gcc/
    2020-10-08  Michael Meissner  <meissner@linux.ibm.com>
    
            * config/rs6000/rs6000.c (rs6000_mangle_decl_assembler_name): Add
            support for mapping built-in function names for long double
            built-in functions if long double is IEEE 128-bit.
    
    gcc/testsuite/
    2020-10-08  Michael Meissner  <meissner@linux.ibm.com>
    
            * gcc.target/powerpc/float128-longdouble-math.c: New test.
            * gcc.target/powerpc/float128-longdouble-stdio.c: New test.
            * gcc.target/powerpc/float128-math.c: Adjust test for new name
            being generated.

Diff:
---
 gcc/config/rs6000/rs6000.c                         | 163 ++++--
 .../gcc.target/powerpc/float128-longdouble-math.c  | 559 +++++++++++++++++++++
 .../gcc.target/powerpc/float128-longdouble-stdio.c |  37 ++
 gcc/testsuite/gcc.target/powerpc/float128-math.c   |   6 +-
 4 files changed, 731 insertions(+), 34 deletions(-)

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index b28f4adf464..2e3628823a3 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -26897,56 +26897,157 @@ rs6000_globalize_decl_name (FILE * stream, tree decl)
    library before you can switch the real*16 type at compile time.
 
    We use the TARGET_MANGLE_DECL_ASSEMBLER_NAME hook to change this name.  We
-   only do this if the default is that long double is IBM extended double, and
-   the user asked for IEEE 128-bit.  */
+   only do this transformation if the __float128 type is enabled.  This
+   prevents us from doing the transformation on older 32-bit ports that might
+   have enabled using IEEE 128-bit floating point as the default long double
+   type.  */
 
 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) )
+  if (TARGET_FLOAT128_TYPE && TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && fndecl_built_in_p (decl, BUILT_IN_NORMAL))
     {
       size_t len = IDENTIFIER_LENGTH (id);
       const char *name = IDENTIFIER_POINTER (id);
+      const char *newname = NULL;
 
-      if (name[len - 1] == 'l')
+      /* See if it is one of the built-in functions with an unusual name.  */
+      switch (DECL_FUNCTION_CODE (decl))
 	{
-	  bool uses_ieee128_p = false;
-	  tree type = TREE_TYPE (decl);
-	  machine_mode ret_mode = TYPE_MODE (type);
+	default:
+	  break;
 
-	  /* See if the function returns a IEEE 128-bit floating point type or
-	     complex type.  */
-	  if (ret_mode == TFmode || ret_mode == TCmode)
-	    uses_ieee128_p = true;
-	  else
+	case BUILT_IN_DREML:
+	  newname = "__ieee754_remainderf128";
+	  break;
+
+	case BUILT_IN_GAMMAL:
+	  newname = "__lgammaieee128";
+	  break;
+
+	case BUILT_IN_GAMMAL_R:
+	case BUILT_IN_LGAMMAL_R:
+	  newname = "__lgammaieee128_r";
+	  break;
+
+	case BUILT_IN_NEXTTOWARD:
+	  newname = "__nexttoward_to_ieee128";
+	  break;
+
+	case BUILT_IN_NEXTTOWARDF:
+	  newname = "__nexttowardf_to_ieee128";
+	  break;
+
+	case BUILT_IN_NEXTTOWARDL:
+	  newname = "__nexttowardieee128";
+	  break;
+
+	case BUILT_IN_POW10L:
+	  newname = "__ieee754_exp10f128";
+	  break;
+
+	case BUILT_IN_SCALBL:
+	  newname = "__scalbnieee128";
+	  break;
+
+	case BUILT_IN_SIGNIFICANDL:
+	  newname = "__significandieee128";
+	  break;
+
+	case BUILT_IN_SINCOSL:
+	  newname = "__sincosieee128";
+	  break;
+	}
+
+      /* Update the __builtin_*printf && __builtin_*scanf functions.  */
+      if (!newname)
+	{
+	  const size_t printf_len = sizeof ("printf") - 1;
+	  const size_t scanf_len = sizeof ("scanf") - 1;
+	  const size_t printf_extra
+	    = sizeof ("__") - 1 + sizeof ("ieee128") - 1;
+	  const size_t scanf_extra
+	    = sizeof ("__isoc99_") - 1 + sizeof ("ieee128") - 1;
+
+	  if (len >= printf_len
+	      && strcmp (name + len - printf_len, "printf") == 0)
+	    {
+	      char *name2 = (char *) alloca (len + 1 + printf_extra);
+	      strcpy (name2, "__");
+	      memcpy (name2 + 2, name, len);
+	      strcpy (name2 + 2 + len, "ieee128");
+	      newname = (const char *) name2;
+	    }
+
+	  else if (len >= scanf_len
+		   && strcmp (name + len - scanf_len, "scanf") == 0)
 	    {
-	      function_args_iterator args_iter;
-	      tree arg;
+	      char *name2 = (char *) alloca (len + 1 + scanf_extra);
+	      strcpy (name2, "__isoc99_");
+	      memcpy (name2 + sizeof ("__isoc99") - 1, name, len);
+	      strcpy (name2 + sizeof ("__isoc99") - 1 + len, "ieee128");
+	      newname = (const char *) name2;
+	    }
 
-	      /* See if the function passes a IEEE 128-bit floating point type
-		 or complex type.  */
-	      FOREACH_FUNCTION_ARGS (type, arg, args_iter)
+	  else if (name[len - 1] == 'l')
+	    {
+	      bool uses_ieee128_p = false;
+	      tree type = TREE_TYPE (decl);
+	      machine_mode ret_mode = TYPE_MODE (type);
+
+	      /* See if the function returns a IEEE 128-bit floating point type or
+		 complex type.  */
+	      if (ret_mode == TFmode || ret_mode == TCmode)
+		uses_ieee128_p = true;
+	      else
 		{
-		  machine_mode arg_mode = TYPE_MODE (arg);
-		  if (arg_mode == TFmode || arg_mode == TCmode)
+		  function_args_iterator args_iter;
+		  tree arg;
+
+		  /* See if the function passes a IEEE 128-bit floating point type
+		     or complex type.  */
+		  FOREACH_FUNCTION_ARGS (type, arg, args_iter)
 		    {
-		      uses_ieee128_p = true;
-		      break;
+		      machine_mode arg_mode = TYPE_MODE (arg);
+		      if (arg_mode == TFmode || arg_mode == TCmode)
+			{
+			  uses_ieee128_p = true;
+			  break;
+			}
 		    }
 		}
-	    }
 
-	  /* If we passed or returned an IEEE 128-bit floating point type,
-	     change the name.  */
-	  if (uses_ieee128_p)
-	    {
-	      char *name2 = (char *) alloca (len + 4);
-	      memcpy (name2, name, len - 1);
-	      strcpy (name2 + len - 1, "f128");
-	      id = get_identifier (name2);
+	      /* If we passed or returned an IEEE 128-bit floating point type,
+		 change the name.  Use __ieee754_<name>l, instead of
+		 <name>f128.  */
+	      if (uses_ieee128_p)
+		{
+		  size_t prefix_len = sizeof ("__") - 1;
+		  size_t suffix_len = sizeof ("ieee128") - 1;
+		  char *name2 = (char *) alloca (len + prefix_len + suffix_len + 1);
+		  char *name3 = name2;
+
+		  memcpy (name3, "__", prefix_len);
+		  name3 += prefix_len;
+
+		  memcpy (name3, name, len - 1);	/* omit trailing 'l'.  */
+		  name3 += len - 1;
+
+		  memcpy (name3, "ieee128", suffix_len + 1);
+		  newname = (const char *) name2;
+		}
 	    }
 	}
+
+      if (newname)
+	{
+	  if (TARGET_DEBUG_BUILTIN)
+	    fprintf (stderr, "Map %s => %s\n", name, newname);
+
+	  id = get_identifier (newname);
+	}
     }
 
   return id;
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c
new file mode 100644
index 00000000000..4f4c2765278
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c
@@ -0,0 +1,559 @@
+/* { dg-require-effective-target ppc_float128_hw } */
+/* { dg-require-effective-target power10_ok } */
+/* { dg-options "-mdejagnu-cpu=power9 -mno-pcrel -O2 -Wno-psabi -mabi=ieeelongdouble" } */
+
+/* Test if switching long double to IEEE 128-bit maps all of the math built-in
+   function names correctly.  We explicitly turn off PC-relative support to
+   make it simpler to compare the call without having a @notoc qualifier.  */
+
+/* Debugging support to use 'name' instead of '__builtin_name'.  Note if you
+   enable this, you will likely need additional flags to get all of the
+   functions defined.  */
+#ifdef DO_FUNC
+#ifndef DO_MATH_H
+#define DO_MATH_H	1
+#endif
+
+#define BUILTIN0(FUNC)                   FUNC ()
+#define BUILTIN1(FUNC, ARG1)             FUNC (ARG1)
+#define BUILTIN2(FUNC, ARG1, ARG2)       FUNC (ARG1, ARG2)
+#define BUILTIN3(FUNC, ARG1, ARG2, ARG3) FUNC (ARG1, ARG2, ARG3)
+
+#else
+#define BUILTIN0(FUNC)                   __builtin_ ## FUNC ()
+#define BUILTIN1(FUNC, ARG1)             __builtin_ ## FUNC (ARG1)
+#define BUILTIN2(FUNC, ARG1, ARG2)       __builtin_ ## FUNC (ARG1, ARG2)
+#define BUILTIN3(FUNC, ARG1, ARG2, ARG3) __builtin_ ## FUNC (ARG1, ARG2, ARG3)
+#endif
+
+/* Debugging support to compare using math.h with the raw built-in functions.  */
+#ifdef DO_MATH_H
+#define __STDC_WANT_IEC_60559_TYPES_EXT__	1
+#define __STDC_WANT_IEC_60559_FUNCS_EXT__	1
+#define _GNU_SOURCE				1
+#define _XOPEN_SOURCE				1
+
+#include <math.h>
+#include <complex.h>
+#endif
+
+/* Built-in functions that returns a long double and take one long double
+   argument.  */
+
+void
+return_ld_arg_ld (long double *p,
+		  long double *q)
+{
+  /* { dg-final { scan-assembler {\m__acoshieee128\M} } }  */
+  *p++ = BUILTIN1 (acoshl, *q++);
+
+  /* { dg-final { scan-assembler {\m__acosieee128\M} } }  */
+  *p++ = BUILTIN1 (acosl, *q++);
+
+  /* { dg-final { scan-assembler {\m__asinhieee128\M} } }  */
+  *p++ = BUILTIN1 (asinhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__asinieee128\M} } }  */
+  *p++ = BUILTIN1 (asinl, *q++);
+
+  /* { dg-final { scan-assembler {\m__atanhieee128\M} } }  */
+  *p++ = BUILTIN1 (atanhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__atanieee128\M} } }  */
+  *p++ = BUILTIN1 (atanl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cbrtieee128\M} } }  */
+  *p++ = BUILTIN1 (cbrtl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (ceill, *q++);
+
+  /* { dg-final { scan-assembler {\m__coshieee128\M} } }  */
+  *p++ = BUILTIN1 (coshl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cosieee128\M} } }  */
+  *p++ = BUILTIN1 (cosl, *q++);
+
+  /* { dg-final { scan-assembler {\m__erfcieee128\M} } }  */
+  *p++ = BUILTIN1 (erfcl, *q++);
+
+  /* { dg-final { scan-assembler {\m__erfieee128\M} } }  */
+  *p++ = BUILTIN1 (erfl, *q++);
+
+  /* { dg-final { scan-assembler {\m__exp10ieee128\M} } }  */
+  *p++ = BUILTIN1 (exp10l, *q++);
+
+  /* { dg-final { scan-assembler {\m__exp2ieee128\M} } }  */
+  *p++ = BUILTIN1 (exp2l, *q++);
+
+  /* { dg-final { scan-assembler {\m__expieee128\M} } }  */
+  *p++ = BUILTIN1 (expl, *q++);
+
+  /* { dg-final { scan-assembler {\m__expm1ieee128\M} } }  */
+  *p++ = BUILTIN1 (expm1l, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (fabsl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (floorl, *q++);
+
+  /* { dg-final { scan-assembler {\m__lgammaieee128\M} } }  */
+  *p++ = BUILTIN1 (gammal, *q++);
+
+  /* { dg-final { scan-assembler {\m__j0ieee128\M} } }  */
+  *p++ = BUILTIN1 (j0l, *q++);
+
+  /* { dg-final { scan-assembler {\m__j1ieee128\M} } }  */
+  *p++ = BUILTIN1 (j1l, *q++);
+
+  /* lgammaf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lgammal, *q++);
+
+  /* { dg-final { scan-assembler {\m__log10ieee128\M} } }  */
+  *p++ = BUILTIN1 (log10l, *q++);
+
+  /* { dg-final { scan-assembler {\m__log1pieee128\M} } }  */
+  *p++ = BUILTIN1 (log1pl, *q++);
+
+  /* { dg-final { scan-assembler {\m__log2ieee128\M} } }  */
+  *p++ = BUILTIN1 (log2l, *q++);
+
+  /* { dg-final { scan-assembler {\m__logbieee128\M} } }  */
+  *p++ = BUILTIN1 (logbl, *q++);
+
+  /* { dg-final { scan-assembler {\m__logieee128\M} } }  */
+  *p++ = BUILTIN1 (logl, *q++);
+
+  /* { dg-final { scan-assembler {\m__nearbyintieee128\M} } }  */
+  *p++ = BUILTIN1 (nearbyintl, *q++);
+
+  /* { dg-final { scan-assembler {\m__exp10ieee128\M} } }  */
+  *p++ = BUILTIN1 (pow10l, *q++);
+
+  /* { dg-final { scan-assembler {\m__rintieee128\M} } }  */
+  *p++ = BUILTIN1 (rintl, *q++);
+
+  /* { dg-final { scan-assembler {\m__roundevenieee128\M} } }  */
+  *p++ = BUILTIN1 (roundevenl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (roundl, *q++);
+
+  /* { dg-final { scan-assembler {\m__significandieee128\M} } }  */
+  *p++ = BUILTIN1 (significandl, *q++);
+
+  /* { dg-final { scan-assembler {\m__sinhieee128\M} } }  */
+  *p++ = BUILTIN1 (sinhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__sinieee128\M} } }  */
+  *p++ = BUILTIN1 (sinl, *q++);
+
+  /* { dg-final { scan-assembler {\m__sqrtieee128\M} } }  */
+  *p++ = BUILTIN1 (sqrtl, *q++);
+
+  /* { dg-final { scan-assembler {\m__tanhieee128\M} } }  */
+  *p++ = BUILTIN1 (tanhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__tanieee128\M} } }  */
+  *p++ = BUILTIN1 (tanl, *q++);
+
+  /* { dg-final { scan-assembler {\m__tgammaieee128\M} } }  */
+  *p++ = BUILTIN1 (tgammal, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (truncl, *q++);
+
+  /* { dg-final { scan-assembler {\m__y0ieee128\M} } }  */
+  *p++ = BUILTIN1 (y0l, *q++);
+
+  /* { dg-final { scan-assembler {\m__y1ieee128\M} } }  */
+  *p   = BUILTIN1 (y1l, *q);  
+
+}
+
+/* Built-in functions that returns a long double and take two long double
+   arguments.  */
+
+void
+return_ld_arg_ld_ld (long double *p,
+		     long double *q,
+		     long double *r)
+{
+  /* { dg-final { scan-assembler {\m__atan2ieee128\M} } }  */
+  *p++ = BUILTIN2 (atan2l, *q++, *r++);
+
+  /* inline code.  */
+  *p++ = BUILTIN2 (copysignl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__remainderieee128\M} } }  */
+  *p++ = BUILTIN2 (dreml, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__fdimieee128\M} } }  */
+  *p++ = BUILTIN2 (fdiml, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__fmaxieee128\M} } }  */
+  *p++ = BUILTIN2 (fmaxl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__fminieee128\M} } }  */
+  *p++ = BUILTIN2 (fminl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__fmodieee128\M} } }  */
+  *p++ = BUILTIN2 (fmodl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__hypotieee128\M} } }  */
+  *p++ = BUILTIN2 (hypotl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__nextafterieee128\M} } }  */
+  *p++ = BUILTIN2 (nextafterl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__nexttowardieee128\M} } }  */
+  *p++ = BUILTIN2 (nexttowardl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__powieee128\M} } }  */
+  *p++ = BUILTIN2 (powl, *q++, *r++);
+
+  /* remainderf128 mentioned previously.  */
+  *p++ = BUILTIN2 (remainderl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__scalbnieee128\M} } }  */
+  *p   = BUILTIN2 (scalbl, *q, *r);  
+}
+
+/* Built-in function that returns a long double and take three long double
+   arguments.  */
+
+void
+return_ld_arg_ld_ld_ld (long double *p,
+			long double *q,
+			long double *r,
+			long double *s)
+{
+ /* inline code.  */
+  *p = BUILTIN3 (fmal, *q, *r, *s);
+}
+
+/* Built-in functions that returns a long double and take one
+   _Complex long double argument.  */
+
+void
+return_ld_arg_cld (long double *p,
+		   _Complex long double *q)
+{
+  /* { dg-final { scan-assembler {\m__cabsieee128\M} } }  */
+  *p++ = BUILTIN1 (cabsl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (cargl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (cimagl, *q++);
+
+  /* inline code.  */
+  *p   = BUILTIN1 (creall, *q);  
+}
+
+/* Built-in functions that returns a _Complex long double and takes one
+   _Complex long double argument.  */
+
+void
+return_cld_arg_cld (_Complex long double *p,
+		    _Complex long double *q)
+{
+  /* { dg-final { scan-assembler {\m__cacoshieee128\M} } }  */
+  *p++ = BUILTIN1 (cacoshl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cacosieee128\M} } }  */
+  *p++ = BUILTIN1 (cacosl, *q++);
+
+  /* { dg-final { scan-assembler {\m__casinhieee128\M} } }  */
+  *p++ = BUILTIN1 (casinhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__casinieee128\M} } }  */
+  *p++ = BUILTIN1 (casinl, *q++);
+
+  /* { dg-final { scan-assembler {\m__catanhieee128\M} } }  */
+  *p++ = BUILTIN1 (catanhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__catanieee128\M} } }  */
+  *p++ = BUILTIN1 (catanl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ccoshieee128\M} } }  */
+  *p++ = BUILTIN1 (ccoshl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ccosieee128\M} } }  */
+  *p++ = BUILTIN1 (ccosl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cexpieee128\M} } }  */
+  *p++ = BUILTIN1 (cexpl, *q++);
+
+  /* { dg-final { scan-assembler {\m__clogieee128\M} } }  */
+  *p++ = BUILTIN1 (clogl, *q++);
+
+  /* { dg-final { scan-assembler {\m__clog10ieee128\M} } }  */
+  *p++ = BUILTIN1 (clog10l, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (conjl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cprojieee128\M} } }  */
+  *p++ = BUILTIN1 (cprojl, *q++);
+
+  /* { dg-final { scan-assembler {\m__csinhieee128\M} } }  */
+  *p++ = BUILTIN1 (csinhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__csinieee128\M} } }  */
+  *p++ = BUILTIN1 (csinl, *q++);
+
+  /* { dg-final { scan-assembler {\m__csqrtieee128\M} } }  */
+  *p++ = BUILTIN1 (csqrtl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ctanhieee128\M} } }  */
+  *p++ = BUILTIN1 (ctanhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ctanieee128\M} } }  */
+  *p   = BUILTIN1 (ctanl, *q);  
+}
+
+/* Built-in functions that returns a _Complex long double and takes one
+   long double argument.  */
+
+void
+return_cld_arg_ld (_Complex long double *p,
+		   long double *q)
+{
+  /* { dg-final { scan-assembler {\m__sincosieee128\M} } }  */
+  *p = BUILTIN1 (cexpil, *q);
+}
+
+/* Built-in function that returns a _Complex long double and takes two
+   _Complex long double arguments.  */
+
+void
+return_cld_arg_cld_cld (_Complex long double *p,
+			_Complex long double *q,
+			_Complex long double *r)
+{
+  /* { dg-final { scan-assembler {\m__cpowieee128\M} } }  */
+  *p = BUILTIN2 (cpowl, *q, *r);
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   pointer to an int arguments.  */
+
+void
+return_ld_arg_ld_pi (long double *p,
+		     long double *q,
+		     int **r)
+{
+  /* { dg-final { scan-assembler {\m__frexpieee128\M} } }  */
+  *p++ = BUILTIN2 (frexpl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__lgammaieee128_r\M} } }  */
+  *p++ = BUILTIN2 (gammal_r, *q++, *r++);
+
+  /* __lgammaieee128_r mentioned previously.  */
+  *p   = BUILTIN2 (lgammal_r, *q, *r);  
+}
+
+/* Built-in functions that returns a long double and takes a long double and an
+   int arguments.  */
+
+void
+return_ld_arg_ld_i (long double *p,
+		    long double *q,
+		    int *r)
+{
+  /* { dg-final { scan-assembler {\m__ldexpieee128\M} } }  */
+  *p++ = BUILTIN2 (ldexpl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__powikf2\M} } }  */
+  *p++ = BUILTIN2 (powil, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__scalbnieee128\M} } }  */
+  *p   = BUILTIN2 (scalbnl, *q, *r);  
+}
+
+/* Built-in function that returns a long double and takes a long double and a
+   long arguments.  */
+
+void
+return_ld_arg_ld_l (long double *p,
+		    long double *q,
+		    long *r)
+{
+  /* { dg-final { scan-assembler {\m__scalblnieee128\M} } }  */
+  *p = BUILTIN2 (scalblnl, *q, *r);
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   long long arguments.  */
+
+void
+return_ld_arg_i_ld (long double *p,
+		    int *q,
+		    long double *r)
+{
+  /* { dg-final { scan-assembler {\m__jnieee128\M} } }  */
+  *p++ = BUILTIN2 (jnl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__ynieee128\M} } }  */
+  *p   = BUILTIN2 (ynl, *q, *r);  
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   pointer to a long double arguments.  */
+
+void
+return_ld_arg_ld_pld (long double *p,
+		      long double *q,
+		      long double **r)
+{
+  /* { dg-final { scan-assembler {\m__modfieee128\M} } }  */
+  *p = BUILTIN2 (modfl, *q, *r);
+}
+
+/* Built-in function that returns a long double and takes two long double and a
+   pointer to an int arguments.  */
+
+void
+return_ld_arg_ld_ld_pi (long double *p,
+			long double *q,
+			long double *r,
+			int **s)
+{
+  /* { dg-final { scan-assembler {\m__remquoieee128\M} } }  */
+  *p = BUILTIN3 (remquol, *q, *r, *s);
+}
+
+/* Built-in functions that returns a long double and take no arguments.  */
+
+void
+return_ld_no_arg (long double *p)
+{
+  /* inline code.  */
+  *p++ = BUILTIN0 (huge_vall);
+
+  /* inline code.  */
+  *p   = BUILTIN0 (infl);     
+}
+
+/* Built-in functions that return san int and takes one long double argument.  */
+
+void
+return_i_arg_ld (int *p,
+		 long double *q)
+{
+  /* { dg-final { scan-assembler {\m__ceilieee128\M} } }  */
+  *p++ = BUILTIN1 (iceill, *q++);
+
+  /* { dg-final { scan-assembler {\m__floorieee128\M} } }  */
+  *p++ = BUILTIN1 (ifloorl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ilogbieee128\M} } }  */
+  *p++ = BUILTIN1 (ilogbl, *q++);
+
+  /* { dg-final { scan-assembler {\m__lrintieee128\M} } }  */
+  *p++ = BUILTIN1 (irintl, *q++);
+
+  /* { dg-final { scan-assembler {\m__lroundieee128\M} } }  */
+  *p++ = BUILTIN1 (iroundl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (signbitl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (finitel, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (isinfl, *q++);
+
+  /* inline code.  */
+  *p   = BUILTIN1 (isnanl, *q);  
+}
+
+/* Built-in functions that returns a long and takes one long double argument.  */
+
+void
+return_l_arg_ld (long *p,
+		 long double *q)
+{
+  /* ceilf128 mentioned previouly.  */
+  *p++ = BUILTIN1 (lceill, *q++);
+
+  /* floorf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lfloorl, *q++);
+
+  /* lrintf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lrintl, *q++);
+
+  /* lroundf128 mentioned previously.  */
+  *p   = BUILTIN1 (lroundl, *q);  
+}
+
+/* Built-in functions that returns a long long and takes one long double
+   argument.  */
+
+void
+return_ll_arg_ld (long long *p,
+		  long double *r)
+{
+  /* ceilf128 mentioned previous.  */
+  *p++ = BUILTIN1 (llceill, *r++);
+
+  /* floorf128 mentioned previously.  */
+  *p++ = BUILTIN1 (llfloorl, *r++);
+
+  /* llrintf128 mentioned previously.  */
+  *p++ = BUILTIN1 (llrintl, *r++);
+
+  /* llroundf128 mentioned previously.  */
+  *p   = BUILTIN1 (llroundl, *r);  
+}
+
+/* Built-in function that returns a double and takes one double and one long
+   double arguments.  */
+
+void
+return_d_arg_d_ld (double *p,
+		   double *q,
+		   long double *r)
+{
+  /* { dg-final { scan-assembler {\m__nexttoward_to_ieee128\M} } }  */
+  *p = BUILTIN2 (nexttoward, *q, *r);
+}
+
+/* Built-in function that returns a float and takes one float and one long
+   double arguments.  */
+
+void
+return_f_arg_f_ld (float *p,
+		   float *q,
+		   long double *r)
+{
+  /* { dg-final { scan-assembler {\m__nexttowardf_to_ieee128\M} } }  */
+  *p = BUILTIN2 (nexttowardf, *q, *r);
+}
+
+/* Built-in function that returns void and takes one long double and two
+   pointers to long double arguments.  */
+
+void
+return_void_arg_ld_pld_pld (long double *p,
+			    long double **q,
+			    long double **r)
+{
+  /* __sincosieee128 mentioned previously.  */
+  BUILTIN3 (sincosl, *p, *q, *r);
+}
+
+/* Debug main program to determine if the library has all of the mapped
+   external functions.  Note, you need a new enough glibc to provide all of the
+   f128 functions.  */
+#ifdef DO_MAIN
+int
+main (void)
+{
+  return 0;
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c
new file mode 100644
index 00000000000..77c7b41cec9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c
@@ -0,0 +1,37 @@
+/* { dg-require-effective-target ppc_float128_hw } */
+/* { dg-require-effective-target power10_ok } */
+/* { dg-options "-mdejagnu-cpu=power9 -mno-pcrel -O2 -Wno-psabi -mabi=ieeelongdouble" } */
+
+/* Test if switching long double to IEEE 128-bit maps the printf and scanf
+   function names correctly.  We explicitly turn off PC-relative support to
+   make it simpler to compare the call without having a @notoc qualifier.  */
+
+#include <stdlib.h>
+
+volatile long double x = 1.0L;
+volatile long double y, z;
+
+int
+main (void)
+{
+  char buffer[100];
+
+  /* { dg-final { scan-assembler {\m__sprintfieee128\M} } }  */
+  __builtin_sprintf (buffer, "%Lg", x);
+
+  /* { dg-final { scan-assembler {\m__printfieee128\M} } }  */
+  __builtin_printf ("x is %Lg [%s]\n", x, buffer);
+
+  /* { dg-final { scan-assembler {\m__isoc99sscanfieee128\M} } }  */
+  __builtin_sscanf (buffer, "%Lg", &y);
+
+  __builtin_printf ("Type 1.0: ");
+
+  /* { dg-final { scan-assembler {\m__isoc99scanfieee128\M} } }  */
+  __builtin_scanf ("%Lg", &z);
+
+  if (x != y || x != z)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-math.c b/gcc/testsuite/gcc.target/powerpc/float128-math.c
index 4ad3b5b8363..ea5cb43bcf1 100644
--- a/gcc/testsuite/gcc.target/powerpc/float128-math.c
+++ b/gcc/testsuite/gcc.target/powerpc/float128-math.c
@@ -10,11 +10,11 @@
 
 extern __float128 sinf128 (__float128);
 
-void foo (__float128 *p, long double *q, long double *r)
+void foo (__float128 *p, long double *q)
 {
   *p = sinf128 (*p);
   *q = __builtin_sinl (*q);
 }
 
-/* { dg-final { scan-assembler-times {\mbl sinf128\M} 2 } } */
-/* { dg-final { scan-assembler-not   {\mbl sinl\M}      } } */
+/* { dg-final { scan-assembler     {\mbl __sinieee128\M} } } */
+/* { dg-final { scan-assembler-not {\mbl sinl\M}         } } */


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [gcc(refs/users/meissner/heads/work019)] PowerPC: Map long double built-in functions if IEEE 128-bit long double.
@ 2020-10-08 20:05 Michael Meissner
  0 siblings, 0 replies; 4+ messages in thread
From: Michael Meissner @ 2020-10-08 20:05 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:4093e886ebd9e9a3f3d6c33108c0572c180b8cd1

commit 4093e886ebd9e9a3f3d6c33108c0572c180b8cd1
Author: Michael Meissner <meissner@linux.ibm.com>
Date:   Thu Oct 8 16:04:11 2020 -0400

    PowerPC: Map long double built-in functions if IEEE 128-bit long double.
    
    This patch goes through the built-in functions and changes the name that is
    used to the name used for __float128 and _Float128 support in glibc if the
    PowerPC long double type is IEEE 128-bit instead of IBM extended double.
    
    Normally the mapping is done in the math.h and stdio.h files.  However, not
    everybody uses these files, which means we also need to change the external
    name for the built-in function within the compiler.
    
    In addition, changing the name in GCC allows the Fortran compiler to
    automatically use the correct name.
    
    To map the math functions, typically this patch changes <name>l to <name>f128.
    However there are some exceptions that are handled with this patch.
    
    To map the printf functions, <name> is mapped to __<name>ieee128.
    
    To map the scanf functions, <name> is mapped to __isoc99<name>ieee128.
    
    gcc/
    2020-10-08  Michael Meissner  <meissner@linux.ibm.com>
    
            * config/rs6000/rs6000.c (rs6000_mangle_decl_assembler_name): Add
            support for mapping built-in function names for long double
            built-in functions if long double is IEEE 128-bit.
    
    gcc/testsuite/
    2020-10-08  Michael Meissner  <meissner@linux.ibm.com>
    
            * gcc.target/powerpc/float128-longdouble-math.c: New test.
            * gcc.target/powerpc/float128-longdouble-stdio.c: New test.
            * gcc.target/powerpc/float128-math.c: Adjust test for new name
            being generated.

Diff:
---
 gcc/config/rs6000/rs6000.c                         | 162 ++++--
 .../gcc.target/powerpc/float128-longdouble-math.c  | 567 +++++++++++++++++++++
 .../gcc.target/powerpc/float128-longdouble-stdio.c |  37 ++
 gcc/testsuite/gcc.target/powerpc/float128-math.c   |   6 +-
 4 files changed, 738 insertions(+), 34 deletions(-)

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index b28f4adf464..4c141c9f276 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -26897,56 +26897,156 @@ rs6000_globalize_decl_name (FILE * stream, tree decl)
    library before you can switch the real*16 type at compile time.
 
    We use the TARGET_MANGLE_DECL_ASSEMBLER_NAME hook to change this name.  We
-   only do this if the default is that long double is IBM extended double, and
-   the user asked for IEEE 128-bit.  */
+   only do this transformation if the __float128 type is enabled.  This
+   prevents us from doing the transformation on older 32-bit ports that might
+   have enabled using IEEE 128-bit floating point as the default long double
+   type.  */
 
 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) )
+  if (TARGET_FLOAT128_TYPE && TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && fndecl_built_in_p (decl, BUILT_IN_NORMAL))
     {
       size_t len = IDENTIFIER_LENGTH (id);
       const char *name = IDENTIFIER_POINTER (id);
+      const char *newname = NULL;
 
-      if (name[len - 1] == 'l')
+      /* See if it is one of the built-in functions with an unusual name.  */
+      switch (DECL_FUNCTION_CODE (decl))
 	{
-	  bool uses_ieee128_p = false;
-	  tree type = TREE_TYPE (decl);
-	  machine_mode ret_mode = TYPE_MODE (type);
+	default:
+	  break;
 
-	  /* See if the function returns a IEEE 128-bit floating point type or
-	     complex type.  */
-	  if (ret_mode == TFmode || ret_mode == TCmode)
-	    uses_ieee128_p = true;
-	  else
+	case BUILT_IN_DREML:
+	  newname = "__remainderieee128";
+	  break;
+
+	case BUILT_IN_GAMMAL:
+	  newname = "__lgammaieee128";
+	  break;
+
+	case BUILT_IN_GAMMAL_R:
+	case BUILT_IN_LGAMMAL_R:
+	  newname = "__lgammaieee128_r";
+	  break;
+
+	case BUILT_IN_NEXTTOWARD:
+	  newname = "__nexttoward_to_ieee128";
+	  break;
+
+	case BUILT_IN_NEXTTOWARDF:
+	  newname = "__nexttowardf_to_ieee128";
+	  break;
+
+	case BUILT_IN_NEXTTOWARDL:
+	  newname = "__nexttowardieee128";
+	  break;
+
+	case BUILT_IN_POW10L:
+	  newname = "__exp10ieee128";
+	  break;
+
+	case BUILT_IN_SCALBL:
+	  newname = "__scalbnieee128";
+	  break;
+
+	case BUILT_IN_SIGNIFICANDL:
+	  newname = "__significandieee128";
+	  break;
+
+	case BUILT_IN_SINCOSL:
+	  newname = "__sincosieee128";
+	  break;
+	}
+
+      /* Update the __builtin_*printf && __builtin_*scanf functions.  */
+      if (!newname)
+	{
+	  const size_t printf_len = sizeof ("printf") - 1;
+	  const size_t scanf_len = sizeof ("scanf") - 1;
+	  const size_t printf_extra
+	    = sizeof ("__") - 1 + sizeof ("ieee128") - 1;
+	  const size_t scanf_extra
+	    = sizeof ("__isoc99_") - 1 + sizeof ("ieee128") - 1;
+
+	  if (len >= printf_len
+	      && strcmp (name + len - printf_len, "printf") == 0)
+	    {
+	      char *name2 = (char *) alloca (len + 1 + printf_extra);
+	      strcpy (name2, "__");
+	      memcpy (name2 + 2, name, len);
+	      strcpy (name2 + 2 + len, "ieee128");
+	      newname = (const char *) name2;
+	    }
+
+	  else if (len >= scanf_len
+		   && strcmp (name + len - scanf_len, "scanf") == 0)
 	    {
-	      function_args_iterator args_iter;
-	      tree arg;
+	      char *name2 = (char *) alloca (len + 1 + scanf_extra);
+	      strcpy (name2, "__isoc99_");
+	      memcpy (name2 + sizeof ("__isoc99") - 1, name, len);
+	      strcpy (name2 + sizeof ("__isoc99") - 1 + len, "ieee128");
+	      newname = (const char *) name2;
+	    }
 
-	      /* See if the function passes a IEEE 128-bit floating point type
-		 or complex type.  */
-	      FOREACH_FUNCTION_ARGS (type, arg, args_iter)
+	  else if (name[len - 1] == 'l')
+	    {
+	      bool uses_ieee128_p = false;
+	      tree type = TREE_TYPE (decl);
+	      machine_mode ret_mode = TYPE_MODE (type);
+
+	      /* See if the function returns a IEEE 128-bit floating point type or
+		 complex type.  */
+	      if (ret_mode == TFmode || ret_mode == TCmode)
+		uses_ieee128_p = true;
+	      else
 		{
-		  machine_mode arg_mode = TYPE_MODE (arg);
-		  if (arg_mode == TFmode || arg_mode == TCmode)
+		  function_args_iterator args_iter;
+		  tree arg;
+
+		  /* See if the function passes a IEEE 128-bit floating point type
+		     or complex type.  */
+		  FOREACH_FUNCTION_ARGS (type, arg, args_iter)
 		    {
-		      uses_ieee128_p = true;
-		      break;
+		      machine_mode arg_mode = TYPE_MODE (arg);
+		      if (arg_mode == TFmode || arg_mode == TCmode)
+			{
+			  uses_ieee128_p = true;
+			  break;
+			}
 		    }
 		}
-	    }
 
-	  /* If we passed or returned an IEEE 128-bit floating point type,
-	     change the name.  */
-	  if (uses_ieee128_p)
-	    {
-	      char *name2 = (char *) alloca (len + 4);
-	      memcpy (name2, name, len - 1);
-	      strcpy (name2 + len - 1, "f128");
-	      id = get_identifier (name2);
+	      /* If we passed or returned an IEEE 128-bit floating point type,
+		 change the name.  Use __<name>ieee128, instead of <name>l.  */
+	      if (uses_ieee128_p)
+		{
+		  size_t prefix_len = sizeof ("__") - 1;
+		  size_t suffix_len = sizeof ("ieee128") - 1;
+		  char *name2 = (char *) alloca (len + prefix_len + suffix_len + 1);
+		  char *name3 = name2;
+
+		  memcpy (name3, "__", prefix_len);
+		  name3 += prefix_len;
+
+		  memcpy (name3, name, len - 1);	/* omit trailing 'l'.  */
+		  name3 += len - 1;
+
+		  memcpy (name3, "ieee128", suffix_len + 1);
+		  newname = (const char *) name2;
+		}
 	    }
 	}
+
+      if (newname)
+	{
+	  if (TARGET_DEBUG_BUILTIN)
+	    fprintf (stderr, "Map %s => %s\n", name, newname);
+
+	  id = get_identifier (newname);
+	}
     }
 
   return id;
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c
new file mode 100644
index 00000000000..50d40180fdc
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c
@@ -0,0 +1,567 @@
+/* { dg-require-effective-target ppc_float128_hw } */
+/* { dg-require-effective-target power10_ok } */
+/* { dg-options "-mdejagnu-cpu=power9 -mno-pcrel -O2 -Wno-psabi -mabi=ieeelongdouble" } */
+
+/* Test if switching long double to IEEE 128-bit maps all of the math built-in
+   function names correctly.  We explicitly turn off PC-relative support to
+   make it simpler to compare the call without having a @notoc qualifier.  */
+
+/* Debugging support to use 'name' instead of '__builtin_name'.  Note if you
+   enable this, you will likely need additional flags to get all of the
+   functions defined.  */
+#ifdef DO_FUNC
+#ifndef DO_MATH_H
+#define DO_MATH_H	1
+#endif
+
+#define BUILTIN0(FUNC)                   FUNC ()
+#define BUILTIN1(FUNC, ARG1)             FUNC (ARG1)
+#define BUILTIN2(FUNC, ARG1, ARG2)       FUNC (ARG1, ARG2)
+#define BUILTIN3(FUNC, ARG1, ARG2, ARG3) FUNC (ARG1, ARG2, ARG3)
+
+#else
+#define BUILTIN0(FUNC)                   __builtin_ ## FUNC ()
+#define BUILTIN1(FUNC, ARG1)             __builtin_ ## FUNC (ARG1)
+#define BUILTIN2(FUNC, ARG1, ARG2)       __builtin_ ## FUNC (ARG1, ARG2)
+#define BUILTIN3(FUNC, ARG1, ARG2, ARG3) __builtin_ ## FUNC (ARG1, ARG2, ARG3)
+#endif
+
+/* Debugging support to compare using math.h with the raw built-in functions.  */
+#ifdef DO_MATH_H
+#define __STDC_WANT_IEC_60559_TYPES_EXT__	1
+#define __STDC_WANT_IEC_60559_FUNCS_EXT__	1
+#define _GNU_SOURCE				1
+#define _XOPEN_SOURCE				1
+
+#include <math.h>
+#include <complex.h>
+#endif
+
+/* Built-in functions that returns a long double and take one long double
+   argument.  */
+
+void
+return_ld_arg_ld (long double *p,
+		  long double *q)
+{
+  /* { dg-final { scan-assembler {\m__acoshieee128\M} } }  */
+  *p++ = BUILTIN1 (acoshl, *q++);
+
+  /* { dg-final { scan-assembler {\m__acosieee128\M} } }  */
+  *p++ = BUILTIN1 (acosl, *q++);
+
+  /* { dg-final { scan-assembler {\m__asinhieee128\M} } }  */
+  *p++ = BUILTIN1 (asinhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__asinieee128\M} } }  */
+  *p++ = BUILTIN1 (asinl, *q++);
+
+  /* { dg-final { scan-assembler {\m__atanhieee128\M} } }  */
+  *p++ = BUILTIN1 (atanhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__atanieee128\M} } }  */
+  *p++ = BUILTIN1 (atanl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cbrtieee128\M} } }  */
+  *p++ = BUILTIN1 (cbrtl, *q++);
+
+  /* inline code.  */
+  /* { dg-final { scan-assembler {\mxsrqpi +[0-9]+,[0-9]+,[0-9]+,2\M} } }  */
+  *p++ = BUILTIN1 (ceill, *q++);
+
+  /* { dg-final { scan-assembler {\m__coshieee128\M} } }  */
+  *p++ = BUILTIN1 (coshl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cosieee128\M} } }  */
+  *p++ = BUILTIN1 (cosl, *q++);
+
+  /* { dg-final { scan-assembler {\m__erfcieee128\M} } }  */
+  *p++ = BUILTIN1 (erfcl, *q++);
+
+  /* { dg-final { scan-assembler {\m__erfieee128\M} } }  */
+  *p++ = BUILTIN1 (erfl, *q++);
+
+  /* { dg-final { scan-assembler {\m__exp10ieee128\M} } }  */
+  *p++ = BUILTIN1 (exp10l, *q++);
+
+  /* { dg-final { scan-assembler {\m__exp2ieee128\M} } }  */
+  *p++ = BUILTIN1 (exp2l, *q++);
+
+  /* { dg-final { scan-assembler {\m__expieee128\M} } }  */
+  *p++ = BUILTIN1 (expl, *q++);
+
+  /* { dg-final { scan-assembler {\m__expm1ieee128\M} } }  */
+  *p++ = BUILTIN1 (expm1l, *q++);
+
+  /* inline code.  */
+  /* { dg-final { scan-assembler {\mxsabsqp\M} } }  */
+  *p++ = BUILTIN1 (fabsl, *q++);
+
+  /* inline code.  */
+  /* { dg-final { scan-assembler {\mxsrqpi +[0-9]+,[0-9]+,[0-9]+,3\M} } }  */
+  *p++ = BUILTIN1 (floorl, *q++);
+
+  /* { dg-final { scan-assembler {\m__lgammaieee128\M} } }  */
+  *p++ = BUILTIN1 (gammal, *q++);
+
+  /* { dg-final { scan-assembler {\m__j0ieee128\M} } }  */
+  *p++ = BUILTIN1 (j0l, *q++);
+
+  /* { dg-final { scan-assembler {\m__j1ieee128\M} } }  */
+  *p++ = BUILTIN1 (j1l, *q++);
+
+  /* lgammaf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lgammal, *q++);
+
+  /* { dg-final { scan-assembler {\m__log10ieee128\M} } }  */
+  *p++ = BUILTIN1 (log10l, *q++);
+
+  /* { dg-final { scan-assembler {\m__log1pieee128\M} } }  */
+  *p++ = BUILTIN1 (log1pl, *q++);
+
+  /* { dg-final { scan-assembler {\m__log2ieee128\M} } }  */
+  *p++ = BUILTIN1 (log2l, *q++);
+
+  /* { dg-final { scan-assembler {\m__logbieee128\M} } }  */
+  *p++ = BUILTIN1 (logbl, *q++);
+
+  /* { dg-final { scan-assembler {\m__logieee128\M} } }  */
+  *p++ = BUILTIN1 (logl, *q++);
+
+  /* { dg-final { scan-assembler {\m__nearbyintieee128\M} } }  */
+  *p++ = BUILTIN1 (nearbyintl, *q++);
+
+  /* { dg-final { scan-assembler {\m__exp10ieee128\M} } }  */
+  *p++ = BUILTIN1 (pow10l, *q++);
+
+  /* { dg-final { scan-assembler {\m__rintieee128\M} } }  */
+  *p++ = BUILTIN1 (rintl, *q++);
+
+  /* { dg-final { scan-assembler {\m__roundevenieee128\M} } }  */
+  *p++ = BUILTIN1 (roundevenl, *q++);
+
+  /* inline code.  */
+  /* { dg-final { scan-assembler {\mxsrqpi +[0-9]+,[0-9]+,[0-9]+,0\M} } }  */
+  *p++ = BUILTIN1 (roundl, *q++);
+
+  /* { dg-final { scan-assembler {\m__significandieee128\M} } }  */
+  *p++ = BUILTIN1 (significandl, *q++);
+
+  /* { dg-final { scan-assembler {\m__sinhieee128\M} } }  */
+  *p++ = BUILTIN1 (sinhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__sinieee128\M} } }  */
+  *p++ = BUILTIN1 (sinl, *q++);
+
+  /* { dg-final { scan-assembler {\m__sqrtieee128\M} } }  */
+  *p++ = BUILTIN1 (sqrtl, *q++);
+
+  /* { dg-final { scan-assembler {\m__tanhieee128\M} } }  */
+  *p++ = BUILTIN1 (tanhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__tanieee128\M} } }  */
+  *p++ = BUILTIN1 (tanl, *q++);
+
+  /* { dg-final { scan-assembler {\m__tgammaieee128\M} } }  */
+  *p++ = BUILTIN1 (tgammal, *q++);
+
+  /* inline code.  */
+  /* { dg-final { scan-assembler {\mxsrqpi +[0-9]+,[0-9]+,[0-9]+,1\M} } }  */
+  *p++ = BUILTIN1 (truncl, *q++);
+
+  /* { dg-final { scan-assembler {\m__y0ieee128\M} } }  */
+  *p++ = BUILTIN1 (y0l, *q++);
+
+  /* { dg-final { scan-assembler {\m__y1ieee128\M} } }  */
+  *p   = BUILTIN1 (y1l, *q);  
+
+}
+
+/* Built-in functions that returns a long double and take two long double
+   arguments.  */
+
+void
+return_ld_arg_ld_ld (long double *p,
+		     long double *q,
+		     long double *r)
+{
+  /* { dg-final { scan-assembler {\m__atan2ieee128\M} } }  */
+  *p++ = BUILTIN2 (atan2l, *q++, *r++);
+
+  /* inline code.  */
+  /* { dg-final { scan-assembler {\mxscpsgnqp\M} } }  */
+  *p++ = BUILTIN2 (copysignl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__remainderieee128\M} } }  */
+  *p++ = BUILTIN2 (dreml, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__fdimieee128\M} } }  */
+  *p++ = BUILTIN2 (fdiml, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__fmaxieee128\M} } }  */
+  *p++ = BUILTIN2 (fmaxl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__fminieee128\M} } }  */
+  *p++ = BUILTIN2 (fminl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__fmodieee128\M} } }  */
+  *p++ = BUILTIN2 (fmodl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__hypotieee128\M} } }  */
+  *p++ = BUILTIN2 (hypotl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__nextafterieee128\M} } }  */
+  *p++ = BUILTIN2 (nextafterl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__nexttowardieee128\M} } }  */
+  *p++ = BUILTIN2 (nexttowardl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__powieee128\M} } }  */
+  *p++ = BUILTIN2 (powl, *q++, *r++);
+
+  /* remainderf128 mentioned previously.  */
+  *p++ = BUILTIN2 (remainderl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__scalbnieee128\M} } }  */
+  *p   = BUILTIN2 (scalbl, *q, *r);  
+}
+
+/* Built-in function that returns a long double and take three long double
+   arguments.  */
+
+void
+return_ld_arg_ld_ld_ld (long double *p,
+			long double *q,
+			long double *r,
+			long double *s)
+{
+  /* inline code.  */
+  /* { dg-final { scan-assembler {\mxsmaddqp\M} } }  */
+  *p = BUILTIN3 (fmal, *q, *r, *s);
+}
+
+/* Built-in functions that returns a long double and take one
+   _Complex long double argument.  */
+
+void
+return_ld_arg_cld (long double *p,
+		   _Complex long double *q)
+{
+  /* { dg-final { scan-assembler {\m__cabsieee128\M} } }  */
+  *p++ = BUILTIN1 (cabsl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (cargl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (cimagl, *q++);
+
+  /* inline code.  */
+  *p   = BUILTIN1 (creall, *q);  
+}
+
+/* Built-in functions that returns a _Complex long double and takes one
+   _Complex long double argument.  */
+
+void
+return_cld_arg_cld (_Complex long double *p,
+		    _Complex long double *q)
+{
+  /* { dg-final { scan-assembler {\m__cacoshieee128\M} } }  */
+  *p++ = BUILTIN1 (cacoshl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cacosieee128\M} } }  */
+  *p++ = BUILTIN1 (cacosl, *q++);
+
+  /* { dg-final { scan-assembler {\m__casinhieee128\M} } }  */
+  *p++ = BUILTIN1 (casinhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__casinieee128\M} } }  */
+  *p++ = BUILTIN1 (casinl, *q++);
+
+  /* { dg-final { scan-assembler {\m__catanhieee128\M} } }  */
+  *p++ = BUILTIN1 (catanhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__catanieee128\M} } }  */
+  *p++ = BUILTIN1 (catanl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ccoshieee128\M} } }  */
+  *p++ = BUILTIN1 (ccoshl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ccosieee128\M} } }  */
+  *p++ = BUILTIN1 (ccosl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cexpieee128\M} } }  */
+  *p++ = BUILTIN1 (cexpl, *q++);
+
+  /* { dg-final { scan-assembler {\m__clogieee128\M} } }  */
+  *p++ = BUILTIN1 (clogl, *q++);
+
+  /* { dg-final { scan-assembler {\m__clog10ieee128\M} } }  */
+  *p++ = BUILTIN1 (clog10l, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (conjl, *q++);
+
+  /* { dg-final { scan-assembler {\m__cprojieee128\M} } }  */
+  *p++ = BUILTIN1 (cprojl, *q++);
+
+  /* { dg-final { scan-assembler {\m__csinhieee128\M} } }  */
+  *p++ = BUILTIN1 (csinhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__csinieee128\M} } }  */
+  *p++ = BUILTIN1 (csinl, *q++);
+
+  /* { dg-final { scan-assembler {\m__csqrtieee128\M} } }  */
+  *p++ = BUILTIN1 (csqrtl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ctanhieee128\M} } }  */
+  *p++ = BUILTIN1 (ctanhl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ctanieee128\M} } }  */
+  *p   = BUILTIN1 (ctanl, *q);  
+}
+
+/* Built-in functions that returns a _Complex long double and takes one
+   long double argument.  */
+
+void
+return_cld_arg_ld (_Complex long double *p,
+		   long double *q)
+{
+  /* { dg-final { scan-assembler {\m__sincosieee128\M} } }  */
+  *p = BUILTIN1 (cexpil, *q);
+}
+
+/* Built-in function that returns a _Complex long double and takes two
+   _Complex long double arguments.  */
+
+void
+return_cld_arg_cld_cld (_Complex long double *p,
+			_Complex long double *q,
+			_Complex long double *r)
+{
+  /* { dg-final { scan-assembler {\m__cpowieee128\M} } }  */
+  *p = BUILTIN2 (cpowl, *q, *r);
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   pointer to an int arguments.  */
+
+void
+return_ld_arg_ld_pi (long double *p,
+		     long double *q,
+		     int **r)
+{
+  /* { dg-final { scan-assembler {\m__frexpieee128\M} } }  */
+  *p++ = BUILTIN2 (frexpl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__lgammaieee128_r\M} } }  */
+  *p++ = BUILTIN2 (gammal_r, *q++, *r++);
+
+  /* __lgammaieee128_r mentioned previously.  */
+  *p   = BUILTIN2 (lgammal_r, *q, *r);  
+}
+
+/* Built-in functions that returns a long double and takes a long double and an
+   int arguments.  */
+
+void
+return_ld_arg_ld_i (long double *p,
+		    long double *q,
+		    int *r)
+{
+  /* { dg-final { scan-assembler {\m__ldexpieee128\M} } }  */
+  *p++ = BUILTIN2 (ldexpl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__powikf2\M} } }  */
+  *p++ = BUILTIN2 (powil, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__scalbnieee128\M} } }  */
+  *p   = BUILTIN2 (scalbnl, *q, *r);  
+}
+
+/* Built-in function that returns a long double and takes a long double and a
+   long arguments.  */
+
+void
+return_ld_arg_ld_l (long double *p,
+		    long double *q,
+		    long *r)
+{
+  /* { dg-final { scan-assembler {\m__scalblnieee128\M} } }  */
+  *p = BUILTIN2 (scalblnl, *q, *r);
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   long long arguments.  */
+
+void
+return_ld_arg_i_ld (long double *p,
+		    int *q,
+		    long double *r)
+{
+  /* { dg-final { scan-assembler {\m__jnieee128\M} } }  */
+  *p++ = BUILTIN2 (jnl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__ynieee128\M} } }  */
+  *p   = BUILTIN2 (ynl, *q, *r);  
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   pointer to a long double arguments.  */
+
+void
+return_ld_arg_ld_pld (long double *p,
+		      long double *q,
+		      long double **r)
+{
+  /* { dg-final { scan-assembler {\m__modfieee128\M} } }  */
+  *p = BUILTIN2 (modfl, *q, *r);
+}
+
+/* Built-in function that returns a long double and takes two long double and a
+   pointer to an int arguments.  */
+
+void
+return_ld_arg_ld_ld_pi (long double *p,
+			long double *q,
+			long double *r,
+			int **s)
+{
+  /* { dg-final { scan-assembler {\m__remquoieee128\M} } }  */
+  *p = BUILTIN3 (remquol, *q, *r, *s);
+}
+
+/* Built-in functions that returns a long double and take no arguments.  */
+
+void
+return_ld_no_arg (long double *p)
+{
+  /* inline code.  */
+  *p++ = BUILTIN0 (huge_vall);
+
+  /* inline code.  */
+  *p   = BUILTIN0 (infl);     
+}
+
+/* Built-in functions that return san int and takes one long double argument.  */
+
+void
+return_i_arg_ld (int *p,
+		 long double *q)
+{
+  /* { dg-final { scan-assembler {\m__ceilieee128\M} } }  */
+  *p++ = BUILTIN1 (iceill, *q++);
+
+  /* { dg-final { scan-assembler {\m__floorieee128\M} } }  */
+  *p++ = BUILTIN1 (ifloorl, *q++);
+
+  /* { dg-final { scan-assembler {\m__ilogbieee128\M} } }  */
+  *p++ = BUILTIN1 (ilogbl, *q++);
+
+  /* { dg-final { scan-assembler {\m__lrintieee128\M} } }  */
+  *p++ = BUILTIN1 (irintl, *q++);
+
+  /* { dg-final { scan-assembler {\m__lroundieee128\M} } }  */
+  *p++ = BUILTIN1 (iroundl, *q++);
+
+  /* inline code.  */
+  /* { dg-final { scan-assembler {\mxscvqpswz\M} } }  */
+  *p++ = BUILTIN1 (signbitl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (finitel, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (isinfl, *q++);
+
+  /* inline code.  */
+  *p   = BUILTIN1 (isnanl, *q);  
+}
+
+/* Built-in functions that returns a long and takes one long double argument.  */
+
+void
+return_l_arg_ld (long *p,
+		 long double *q)
+{
+  /* ceilf128 mentioned previouly.  */
+  *p++ = BUILTIN1 (lceill, *q++);
+
+  /* floorf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lfloorl, *q++);
+
+  /* lrintf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lrintl, *q++);
+
+  /* lroundf128 mentioned previously.  */
+  *p   = BUILTIN1 (lroundl, *q);  
+}
+
+/* Built-in functions that returns a long long and takes one long double
+   argument.  */
+
+void
+return_ll_arg_ld (long long *p,
+		  long double *r)
+{
+  /* ceilf128 mentioned previous.  */
+  *p++ = BUILTIN1 (llceill, *r++);
+
+  /* floorf128 mentioned previously.  */
+  *p++ = BUILTIN1 (llfloorl, *r++);
+
+  /* llrintf128 mentioned previously.  */
+  *p++ = BUILTIN1 (llrintl, *r++);
+
+  /* llroundf128 mentioned previously.  */
+  *p   = BUILTIN1 (llroundl, *r);  
+}
+
+/* Built-in function that returns a double and takes one double and one long
+   double arguments.  */
+
+void
+return_d_arg_d_ld (double *p,
+		   double *q,
+		   long double *r)
+{
+  /* { dg-final { scan-assembler {\m__nexttoward_to_ieee128\M} } }  */
+  *p = BUILTIN2 (nexttoward, *q, *r);
+}
+
+/* Built-in function that returns a float and takes one float and one long
+   double arguments.  */
+
+void
+return_f_arg_f_ld (float *p,
+		   float *q,
+		   long double *r)
+{
+  /* { dg-final { scan-assembler {\m__nexttowardf_to_ieee128\M} } }  */
+  *p = BUILTIN2 (nexttowardf, *q, *r);
+}
+
+/* Built-in function that returns void and takes one long double and two
+   pointers to long double arguments.  */
+
+void
+return_void_arg_ld_pld_pld (long double *p,
+			    long double **q,
+			    long double **r)
+{
+  /* __sincosieee128 mentioned previously.  */
+  BUILTIN3 (sincosl, *p, *q, *r);
+}
+
+/* Debug main program to determine if the library has all of the mapped
+   external functions.  Note, you need a new enough glibc to provide all of the
+   f128 functions.  */
+#ifdef DO_MAIN
+int
+main (void)
+{
+  return 0;
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c
new file mode 100644
index 00000000000..77c7b41cec9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c
@@ -0,0 +1,37 @@
+/* { dg-require-effective-target ppc_float128_hw } */
+/* { dg-require-effective-target power10_ok } */
+/* { dg-options "-mdejagnu-cpu=power9 -mno-pcrel -O2 -Wno-psabi -mabi=ieeelongdouble" } */
+
+/* Test if switching long double to IEEE 128-bit maps the printf and scanf
+   function names correctly.  We explicitly turn off PC-relative support to
+   make it simpler to compare the call without having a @notoc qualifier.  */
+
+#include <stdlib.h>
+
+volatile long double x = 1.0L;
+volatile long double y, z;
+
+int
+main (void)
+{
+  char buffer[100];
+
+  /* { dg-final { scan-assembler {\m__sprintfieee128\M} } }  */
+  __builtin_sprintf (buffer, "%Lg", x);
+
+  /* { dg-final { scan-assembler {\m__printfieee128\M} } }  */
+  __builtin_printf ("x is %Lg [%s]\n", x, buffer);
+
+  /* { dg-final { scan-assembler {\m__isoc99sscanfieee128\M} } }  */
+  __builtin_sscanf (buffer, "%Lg", &y);
+
+  __builtin_printf ("Type 1.0: ");
+
+  /* { dg-final { scan-assembler {\m__isoc99scanfieee128\M} } }  */
+  __builtin_scanf ("%Lg", &z);
+
+  if (x != y || x != z)
+    abort ();
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-math.c b/gcc/testsuite/gcc.target/powerpc/float128-math.c
index 4ad3b5b8363..ea5cb43bcf1 100644
--- a/gcc/testsuite/gcc.target/powerpc/float128-math.c
+++ b/gcc/testsuite/gcc.target/powerpc/float128-math.c
@@ -10,11 +10,11 @@
 
 extern __float128 sinf128 (__float128);
 
-void foo (__float128 *p, long double *q, long double *r)
+void foo (__float128 *p, long double *q)
 {
   *p = sinf128 (*p);
   *q = __builtin_sinl (*q);
 }
 
-/* { dg-final { scan-assembler-times {\mbl sinf128\M} 2 } } */
-/* { dg-final { scan-assembler-not   {\mbl sinl\M}      } } */
+/* { dg-final { scan-assembler     {\mbl __sinieee128\M} } } */
+/* { dg-final { scan-assembler-not {\mbl sinl\M}         } } */


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [gcc(refs/users/meissner/heads/work019)] PowerPC: Map long double built-in functions if IEEE 128-bit long double.
@ 2020-09-30 21:25 Michael Meissner
  0 siblings, 0 replies; 4+ messages in thread
From: Michael Meissner @ 2020-09-30 21:25 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:51f931b3673201a6e35b36a810238dab680231bb

commit 51f931b3673201a6e35b36a810238dab680231bb
Author: Michael Meissner <meissner@linux.ibm.com>
Date:   Wed Sep 30 17:24:50 2020 -0400

    PowerPC: Map long double built-in functions if IEEE 128-bit long double.
    
    This patch goes through the built-in functions and changes the name that is
    used to the name used for __float128 and _Float128 support in glibc if the
    PowerPC long double type is IEEE 128-bit instead of IBM extended double.
    
    Normally the mapping is done in the math.h and stdio.h files.  However, not
    everybody uses these files, which means we also need to change the external
    name for the built-in function within the compiler.
    
    In addition, changing the name in GCC allows the Fortran compiler to
    automatically use the correct name.
    
    To map the math functions, typically this patch changes <name>l to <name>f128.
    However there are some exceptions that are handled with this patch.
    
    To map the printf functions, <name> is mapped to __<name>ieee128.
    
    To map the scanf functions, <name> is mapped to __isoc99<name>ieee128.
    
    gcc/
    2020-09-30  Michael Meissner  <meissner@linux.ibm.com>
    
            * config/rs6000/rs6000.c (rs6000_mangle_decl_assembler_name): Add
            support for mapping built-in function names for long double
            built-in functions if long double is IEEE 128-bit.
    
    gcc/testsuite/
    2020-09-30  Michael Meissner  <meissner@linux.ibm.com>
    
            * gcc.target/powerpc/float128-longdouble-math.c: New test.
            * gcc.target/powerpc/float128-longdouble-stdio.c: New test.

Diff:
---
 gcc/config/rs6000/rs6000.c                         | 153 ++++--
 .../gcc.target/powerpc/float128-longdouble-math.c  | 559 +++++++++++++++++++++
 .../gcc.target/powerpc/float128-longdouble-stdio.c |  37 ++
 3 files changed, 718 insertions(+), 31 deletions(-)

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 481f0d823cd..958c4ee5e80 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -26909,56 +26909,147 @@ rs6000_globalize_decl_name (FILE * stream, tree decl)
    library before you can switch the real*16 type at compile time.
 
    We use the TARGET_MANGLE_DECL_ASSEMBLER_NAME hook to change this name.  We
-   only do this if the default is that long double is IBM extended double, and
-   the user asked for IEEE 128-bit.  */
+   only do this transformation if the __float128 type is enabled.  This
+   prevents us from doing the transformation on older 32-bit ports that might
+   have enabled using IEEE 128-bit floating point as the default long double
+   type.  */
 
 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) )
+  if (TARGET_FLOAT128_TYPE && TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && fndecl_built_in_p (decl, BUILT_IN_NORMAL))
     {
       size_t len = IDENTIFIER_LENGTH (id);
       const char *name = IDENTIFIER_POINTER (id);
+      const char *newname = NULL;
 
-      if (name[len - 1] == 'l')
+      /* See if it is one of the built-in functions with an unusual name.  */
+      switch (DECL_FUNCTION_CODE (decl))
 	{
-	  bool uses_ieee128_p = false;
-	  tree type = TREE_TYPE (decl);
-	  machine_mode ret_mode = TYPE_MODE (type);
+	default:
+	  break;
 
-	  /* See if the function returns a IEEE 128-bit floating point type or
-	     complex type.  */
-	  if (ret_mode == TFmode || ret_mode == TCmode)
-	    uses_ieee128_p = true;
-	  else
+	case BUILT_IN_DREML:
+	  newname = "remainderf128";
+	  break;
+
+	case BUILT_IN_GAMMAL:
+	  newname = "lgammaf128";
+	  break;
+
+	case BUILT_IN_GAMMAL_R:
+	case BUILT_IN_LGAMMAL_R:
+	  newname = "__lgammaieee128_r";
+	  break;
+
+	case BUILT_IN_NEXTTOWARD:
+	  newname = "__nexttoward_to_ieee128";
+	  break;
+
+	case BUILT_IN_NEXTTOWARDF:
+	  newname = "__nexttowardf_to_ieee128";
+	  break;
+
+	case BUILT_IN_NEXTTOWARDL:
+	  newname = "__nexttowardieee128";
+	  break;
+
+	case BUILT_IN_POW10L:
+	  newname = "exp10f128";
+	  break;
+
+	case BUILT_IN_SCALBL:
+	  newname = "__scalbnieee128";
+	  break;
+
+	case BUILT_IN_SIGNIFICANDL:
+	  newname = "__significandieee128";
+	  break;
+
+	case BUILT_IN_SINCOSL:
+	  newname = "__sincosieee128";
+	  break;
+	}
+
+      /* Update the __builtin_*printf && __builtin_*scanf functions.  */
+      if (!newname)
+	{
+	  const size_t printf_len = sizeof ("printf") - 1;
+	  const size_t scanf_len = sizeof ("scanf") - 1;
+	  const size_t printf_extra
+	    = sizeof ("__") - 1 + sizeof ("ieee128") - 1;
+	  const size_t scanf_extra
+	    = sizeof ("__isoc99_") - 1 + sizeof ("ieee128") - 1;
+
+	  if (len >= printf_len
+	      && strcmp (name + len - printf_len, "printf") == 0)
 	    {
-	      function_args_iterator args_iter;
-	      tree arg;
+	      char *name2 = (char *) alloca (len + 1 + printf_extra);
+	      strcpy (name2, "__");
+	      memcpy (name2 + 2, name, len);
+	      strcpy (name2 + 2 + len, "ieee128");
+	      newname = (const char *) name2;
+	    }
 
-	      /* See if the function passes a IEEE 128-bit floating point type
-		 or complex type.  */
-	      FOREACH_FUNCTION_ARGS (type, arg, args_iter)
+	  else if (len >= scanf_len
+		   && strcmp (name + len - scanf_len, "scanf") == 0)
+	    {
+	      char *name2 = (char *) alloca (len + 1 + scanf_extra);
+	      strcpy (name2, "__isoc99_");
+	      memcpy (name2 + sizeof ("__isoc99") - 1, name, len);
+	      strcpy (name2 + sizeof ("__isoc99") - 1 + len, "ieee128");
+	      newname = (const char *) name2;
+	    }
+
+	  else if (name[len - 1] == 'l')
+	    {
+	      bool uses_ieee128_p = false;
+	      tree type = TREE_TYPE (decl);
+	      machine_mode ret_mode = TYPE_MODE (type);
+
+	      /* See if the function returns a IEEE 128-bit floating point type or
+		 complex type.  */
+	      if (ret_mode == TFmode || ret_mode == TCmode)
+		uses_ieee128_p = true;
+	      else
 		{
-		  machine_mode arg_mode = TYPE_MODE (arg);
-		  if (arg_mode == TFmode || arg_mode == TCmode)
+		  function_args_iterator args_iter;
+		  tree arg;
+
+		  /* See if the function passes a IEEE 128-bit floating point type
+		     or complex type.  */
+		  FOREACH_FUNCTION_ARGS (type, arg, args_iter)
 		    {
-		      uses_ieee128_p = true;
-		      break;
+		      machine_mode arg_mode = TYPE_MODE (arg);
+		      if (arg_mode == TFmode || arg_mode == TCmode)
+			{
+			  uses_ieee128_p = true;
+			  break;
+			}
 		    }
 		}
-	    }
 
-	  /* If we passed or returned an IEEE 128-bit floating point type,
-	     change the name.  */
-	  if (uses_ieee128_p)
-	    {
-	      char *name2 = (char *) alloca (len + 4);
-	      memcpy (name2, name, len - 1);
-	      strcpy (name2 + len - 1, "f128");
-	      id = get_identifier (name2);
+	      /* If we passed or returned an IEEE 128-bit floating point type,
+		 change the name.  */
+	      if (uses_ieee128_p)
+		{
+		  char *name2 = (char *) alloca (len + 4);
+		  memcpy (name2, name, len - 1);
+		  strcpy (name2 + len - 1, "f128");
+		  newname = (const char *) name2;
+		}
 	    }
 	}
+
+      if (newname)
+	{
+	  if (TARGET_DEBUG_BUILTIN)
+	    fprintf (stderr, "Map %s => %s\n", name, newname);
+
+	  id = get_identifier (newname);
+	}
     }
 
   return id;
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c
new file mode 100644
index 00000000000..e7a79f5e4e9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-math.c
@@ -0,0 +1,559 @@
+/* { dg-require-effective-target ppc_float128_hw } */
+/* { dg-require-effective-target power10_ok } */
+/* { dg-options "-mdejagnu-cpu=power9 -mno-pcrel -O2 -Wno-psabi -mabi=ieeelongdouble" } */
+
+/* Test if switching long double to IEEE 128-bit maps all of the math built-in
+   function names correctly.  We explicitly turn off PC-relative support to
+   make it simpler to compare the call without having a @notoc qualifier.  */
+
+/* Debugging support to use 'name' instead of '__builtin_name'.  Note if you
+   enable this, you will likely need additional flags to get all of the
+   functions defined.  */
+#ifdef DO_FUNC
+#ifndef DO_MATH_H
+#define DO_MATH_H	1
+#endif
+
+#define BUILTIN0(FUNC)                   FUNC ()
+#define BUILTIN1(FUNC, ARG1)             FUNC (ARG1)
+#define BUILTIN2(FUNC, ARG1, ARG2)       FUNC (ARG1, ARG2)
+#define BUILTIN3(FUNC, ARG1, ARG2, ARG3) FUNC (ARG1, ARG2, ARG3)
+
+#else
+#define BUILTIN0(FUNC)                   __builtin_ ## FUNC ()
+#define BUILTIN1(FUNC, ARG1)             __builtin_ ## FUNC (ARG1)
+#define BUILTIN2(FUNC, ARG1, ARG2)       __builtin_ ## FUNC (ARG1, ARG2)
+#define BUILTIN3(FUNC, ARG1, ARG2, ARG3) __builtin_ ## FUNC (ARG1, ARG2, ARG3)
+#endif
+
+/* Debugging support to compare using math.h with the raw built-in functions.  */
+#ifdef DO_MATH_H
+#define __STDC_WANT_IEC_60559_TYPES_EXT__	1
+#define __STDC_WANT_IEC_60559_FUNCS_EXT__	1
+#define _GNU_SOURCE				1
+#define _XOPEN_SOURCE				1
+
+#include <math.h>
+#include <complex.h>
+#endif
+
+/* Built-in functions that returns a long double and take one long double
+   argument.  */
+
+void
+return_ld_arg_ld (long double *p,
+		  long double *q)
+{
+  /* { dg-final { scan-assembler {\macoshf128\M} } }  */
+  *p++ = BUILTIN1 (acoshl, *q++);
+
+  /* { dg-final { scan-assembler {\macosf128\M} } }  */
+  *p++ = BUILTIN1 (acosl, *q++);
+
+  /* { dg-final { scan-assembler {\masinhf128\M} } }  */
+  *p++ = BUILTIN1 (asinhl, *q++);
+
+  /* { dg-final { scan-assembler {\masinf128\M} } }  */
+  *p++ = BUILTIN1 (asinl, *q++);
+
+  /* { dg-final { scan-assembler {\matanhf128\M} } }  */
+  *p++ = BUILTIN1 (atanhl, *q++);
+
+  /* { dg-final { scan-assembler {\matanf128\M} } }  */
+  *p++ = BUILTIN1 (atanl, *q++);
+
+  /* { dg-final { scan-assembler {\mcbrtf128\M} } }  */
+  *p++ = BUILTIN1 (cbrtl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (ceill, *q++);
+
+  /* { dg-final { scan-assembler {\mcoshf128\M} } }  */
+  *p++ = BUILTIN1 (coshl, *q++);
+
+  /* { dg-final { scan-assembler {\mcosf128\M} } }  */
+  *p++ = BUILTIN1 (cosl, *q++);
+
+  /* { dg-final { scan-assembler {\merfcf128\M} } }  */
+  *p++ = BUILTIN1 (erfcl, *q++);
+
+  /* { dg-final { scan-assembler {\merff128\M} } }  */
+  *p++ = BUILTIN1 (erfl, *q++);
+
+  /* { dg-final { scan-assembler {\mexp10f128\M} } }  */
+  *p++ = BUILTIN1 (exp10l, *q++);
+
+  /* { dg-final { scan-assembler {\mexp2f128\M} } }  */
+  *p++ = BUILTIN1 (exp2l, *q++);
+
+  /* { dg-final { scan-assembler {\mexpf128\M} } }  */
+  *p++ = BUILTIN1 (expl, *q++);
+
+  /* { dg-final { scan-assembler {\mexpm1f128\M} } }  */
+  *p++ = BUILTIN1 (expm1l, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (fabsl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (floorl, *q++);
+
+  /* { dg-final { scan-assembler {\mlgammaf128\M} } }  */
+  *p++ = BUILTIN1 (gammal, *q++);
+
+  /* { dg-final { scan-assembler {\mj0f128\M} } }  */
+  *p++ = BUILTIN1 (j0l, *q++);
+
+  /* { dg-final { scan-assembler {\mj1f128\M} } }  */
+  *p++ = BUILTIN1 (j1l, *q++);
+
+  /* lgammaf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lgammal, *q++);
+
+  /* { dg-final { scan-assembler {\mlog10f128\M} } }  */
+  *p++ = BUILTIN1 (log10l, *q++);
+
+  /* { dg-final { scan-assembler {\mlog1pf128\M} } }  */
+  *p++ = BUILTIN1 (log1pl, *q++);
+
+  /* { dg-final { scan-assembler {\mlog2f128\M} } }  */
+  *p++ = BUILTIN1 (log2l, *q++);
+
+  /* { dg-final { scan-assembler {\mlogbf128\M} } }  */
+  *p++ = BUILTIN1 (logbl, *q++);
+
+  /* { dg-final { scan-assembler {\mlogf128\M} } }  */
+  *p++ = BUILTIN1 (logl, *q++);
+
+  /* { dg-final { scan-assembler {\mnearbyintf128\M} } }  */
+  *p++ = BUILTIN1 (nearbyintl, *q++);
+
+  /* { dg-final { scan-assembler {\mexp10f128\M} } }  */
+  *p++ = BUILTIN1 (pow10l, *q++);
+
+  /* { dg-final { scan-assembler {\mrintf128\M} } }  */
+  *p++ = BUILTIN1 (rintl, *q++);
+
+  /* { dg-final { scan-assembler {\mroundevenf128\M} } }  */
+  *p++ = BUILTIN1 (roundevenl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (roundl, *q++);
+
+  /* { dg-final { scan-assembler {\m__significandieee128\M} } }  */
+  *p++ = BUILTIN1 (significandl, *q++);
+
+  /* { dg-final { scan-assembler {\msinhf128\M} } }  */
+  *p++ = BUILTIN1 (sinhl, *q++);
+
+  /* { dg-final { scan-assembler {\msinf128\M} } }  */
+  *p++ = BUILTIN1 (sinl, *q++);
+
+  /* { dg-final { scan-assembler {\msqrtf128\M} } }  */
+  *p++ = BUILTIN1 (sqrtl, *q++);
+
+  /* { dg-final { scan-assembler {\mtanhf128\M} } }  */
+  *p++ = BUILTIN1 (tanhl, *q++);
+
+  /* { dg-final { scan-assembler {\mtanf128\M} } }  */
+  *p++ = BUILTIN1 (tanl, *q++);
+
+  /* { dg-final { scan-assembler {\mtgammaf128\M} } }  */
+  *p++ = BUILTIN1 (tgammal, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (truncl, *q++);
+
+  /* { dg-final { scan-assembler {\my0f128\M} } }  */
+  *p++ = BUILTIN1 (y0l, *q++);
+
+  /* { dg-final { scan-assembler {\my1f128\M} } }  */
+  *p   = BUILTIN1 (y1l, *q);  
+
+}
+
+/* Built-in functions that returns a long double and take two long double
+   arguments.  */
+
+void
+return_ld_arg_ld_ld (long double *p,
+		     long double *q,
+		     long double *r)
+{
+  /* { dg-final { scan-assembler {\matan2f128\M} } }  */
+  *p++ = BUILTIN2 (atan2l, *q++, *r++);
+
+  /* inline code.  */
+  *p++ = BUILTIN2 (copysignl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mremainderf128\M} } }  */
+  *p++ = BUILTIN2 (dreml, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mfdimf128\M} } }  */
+  *p++ = BUILTIN2 (fdiml, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mfmaxf128\M} } }  */
+  *p++ = BUILTIN2 (fmaxl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mfminf128\M} } }  */
+  *p++ = BUILTIN2 (fminl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mfmodf128\M} } }  */
+  *p++ = BUILTIN2 (fmodl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mhypotf128\M} } }  */
+  *p++ = BUILTIN2 (hypotl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mnextafterf128\M} } }  */
+  *p++ = BUILTIN2 (nextafterl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__nexttowardieee128\M} } }  */
+  *p++ = BUILTIN2 (nexttowardl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mpowf128\M} } }  */
+  *p++ = BUILTIN2 (powl, *q++, *r++);
+
+  /* remainderf128 mentioned previously.  */
+  *p++ = BUILTIN2 (remainderl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__scalbnieee128\M} } }  */
+  *p   = BUILTIN2 (scalbl, *q, *r);  
+}
+
+/* Built-in function that returns a long double and take three long double
+   arguments.  */
+
+void
+return_ld_arg_ld_ld_ld (long double *p,
+			long double *q,
+			long double *r,
+			long double *s)
+{
+ /* inline code.  */
+  *p = BUILTIN3 (fmal, *q, *r, *s);
+}
+
+/* Built-in functions that returns a long double and take one
+   _Complex long double argument.  */
+
+void
+return_ld_arg_cld (long double *p,
+		   _Complex long double *q)
+{
+  /* { dg-final { scan-assembler {\mcabsf128\M} } }  */
+  *p++ = BUILTIN1 (cabsl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (cargl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (cimagl, *q++);
+
+  /* inline code.  */
+  *p   = BUILTIN1 (creall, *q);  
+}
+
+/* Built-in functions that returns a _Complex long double and takes one
+   _Complex long double argument.  */
+
+void
+return_cld_arg_cld (_Complex long double *p,
+		    _Complex long double *q)
+{
+  /* { dg-final { scan-assembler {\mcacoshf128\M} } }  */
+  *p++ = BUILTIN1 (cacoshl, *q++);
+
+  /* { dg-final { scan-assembler {\mcacosf128\M} } }  */
+  *p++ = BUILTIN1 (cacosl, *q++);
+
+  /* { dg-final { scan-assembler {\mcasinhf128\M} } }  */
+  *p++ = BUILTIN1 (casinhl, *q++);
+
+  /* { dg-final { scan-assembler {\mcasinf128\M} } }  */
+  *p++ = BUILTIN1 (casinl, *q++);
+
+  /* { dg-final { scan-assembler {\mcatanhf128\M} } }  */
+  *p++ = BUILTIN1 (catanhl, *q++);
+
+  /* { dg-final { scan-assembler {\mcatanf128\M} } }  */
+  *p++ = BUILTIN1 (catanl, *q++);
+
+  /* { dg-final { scan-assembler {\mccoshf128\M} } }  */
+  *p++ = BUILTIN1 (ccoshl, *q++);
+
+  /* { dg-final { scan-assembler {\mccosf128\M} } }  */
+  *p++ = BUILTIN1 (ccosl, *q++);
+
+  /* { dg-final { scan-assembler {\mcexpf128\M} } }  */
+  *p++ = BUILTIN1 (cexpl, *q++);
+
+  /* { dg-final { scan-assembler {\mclogf128\M} } }  */
+  *p++ = BUILTIN1 (clogl, *q++);
+
+  /* { dg-final { scan-assembler {\mclog10f128\M} } }  */
+  *p++ = BUILTIN1 (clog10l, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (conjl, *q++);
+
+  /* { dg-final { scan-assembler {\mcprojf128\M} } }  */
+  *p++ = BUILTIN1 (cprojl, *q++);
+
+  /* { dg-final { scan-assembler {\mcsinhf128\M} } }  */
+  *p++ = BUILTIN1 (csinhl, *q++);
+
+  /* { dg-final { scan-assembler {\mcsinf128\M} } }  */
+  *p++ = BUILTIN1 (csinl, *q++);
+
+  /* { dg-final { scan-assembler {\mcsqrtf128\M} } }  */
+  *p++ = BUILTIN1 (csqrtl, *q++);
+
+  /* { dg-final { scan-assembler {\mctanhf128\M} } }  */
+  *p++ = BUILTIN1 (ctanhl, *q++);
+
+  /* { dg-final { scan-assembler {\mctanf128\M} } }  */
+  *p   = BUILTIN1 (ctanl, *q);  
+}
+
+/* Built-in functions that returns a _Complex long double and takes one
+   long double argument.  */
+
+void
+return_cld_arg_ld (_Complex long double *p,
+		   long double *q)
+{
+  /* { dg-final { scan-assembler {\m__sincosieee128\M} } }  */
+  *p = BUILTIN1 (cexpil, *q);
+}
+
+/* Built-in function that returns a _Complex long double and takes two
+   _Complex long double arguments.  */
+
+void
+return_cld_arg_cld_cld (_Complex long double *p,
+			_Complex long double *q,
+			_Complex long double *r)
+{
+  /* { dg-final { scan-assembler {\mcpowf128\M} } }  */
+  *p = BUILTIN2 (cpowl, *q, *r);
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   pointer to an int arguments.  */
+
+void
+return_ld_arg_ld_pi (long double *p,
+		     long double *q,
+		     int **r)
+{
+  /* { dg-final { scan-assembler {\mfrexpf128\M} } }  */
+  *p++ = BUILTIN2 (frexpl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__lgammaieee128_r\M} } }  */
+  *p++ = BUILTIN2 (gammal_r, *q++, *r++);
+
+  /* __lgammaieee128_r mentioned previously.  */
+  *p   = BUILTIN2 (lgammal_r, *q, *r);  
+}
+
+/* Built-in functions that returns a long double and takes a long double and an
+   int arguments.  */
+
+void
+return_ld_arg_ld_i (long double *p,
+		    long double *q,
+		    int *r)
+{
+  /* { dg-final { scan-assembler {\mldexpf128\M} } }  */
+  *p++ = BUILTIN2 (ldexpl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\m__powikf2\M} } }  */
+  *p++ = BUILTIN2 (powil, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mscalbnf128\M} } }  */
+  *p   = BUILTIN2 (scalbnl, *q, *r);  
+}
+
+/* Built-in function that returns a long double and takes a long double and a
+   long arguments.  */
+
+void
+return_ld_arg_ld_l (long double *p,
+		    long double *q,
+		    long *r)
+{
+  /* { dg-final { scan-assembler {\mscalblnf128\M} } }  */
+  *p = BUILTIN2 (scalblnl, *q, *r);
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   long long arguments.  */
+
+void
+return_ld_arg_i_ld (long double *p,
+		    int *q,
+		    long double *r)
+{
+  /* { dg-final { scan-assembler {\mjnf128\M} } }  */
+  *p++ = BUILTIN2 (jnl, *q++, *r++);
+
+  /* { dg-final { scan-assembler {\mynf128\M} } }  */
+  *p   = BUILTIN2 (ynl, *q, *r);  
+}
+
+/* Built-in functions that returns a long double and takes a long double and a
+   pointer to a long double arguments.  */
+
+void
+return_ld_arg_ld_pld (long double *p,
+		      long double *q,
+		      long double **r)
+{
+  /* { dg-final { scan-assembler {\mmodff128\M} } }  */
+  *p = BUILTIN2 (modfl, *q, *r);
+}
+
+/* Built-in function that returns a long double and takes two long double and a
+   pointer to an int arguments.  */
+
+void
+return_ld_arg_ld_ld_pi (long double *p,
+			long double *q,
+			long double *r,
+			int **s)
+{
+  /* { dg-final { scan-assembler {\mremquof128\M} } }  */
+  *p = BUILTIN3 (remquol, *q, *r, *s);
+}
+
+/* Built-in functions that returns a long double and take no arguments.  */
+
+void
+return_ld_no_arg (long double *p)
+{
+  /* inline code.  */
+  *p++ = BUILTIN0 (huge_vall);
+
+  /* inline code.  */
+  *p   = BUILTIN0 (infl);     
+}
+
+/* Built-in functions that return san int and takes one long double argument.  */
+
+void
+return_i_arg_ld (int *p,
+		 long double *q)
+{
+  /* { dg-final { scan-assembler {\mceilf128\M} } }  */
+  *p++ = BUILTIN1 (iceill, *q++);
+
+  /* { dg-final { scan-assembler {\mfloorf128\M} } }  */
+  *p++ = BUILTIN1 (ifloorl, *q++);
+
+  /* { dg-final { scan-assembler {\milogbf128\M} } }  */
+  *p++ = BUILTIN1 (ilogbl, *q++);
+
+  /* { dg-final { scan-assembler {\mlrintf128\M} } }  */
+  *p++ = BUILTIN1 (irintl, *q++);
+
+  /* { dg-final { scan-assembler {\mlroundf128\M} } }  */
+  *p++ = BUILTIN1 (iroundl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (signbitl, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (finitel, *q++);
+
+  /* inline code.  */
+  *p++ = BUILTIN1 (isinfl, *q++);
+
+  /* inline code.  */
+  *p   = BUILTIN1 (isnanl, *q);  
+}
+
+/* Built-in functions that returns a long and takes one long double argument.  */
+
+void
+return_l_arg_ld (long *p,
+		 long double *q)
+{
+  /* ceilf128 mentioned previouly.  */
+  *p++ = BUILTIN1 (lceill, *q++);
+
+  /* floorf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lfloorl, *q++);
+
+  /* lrintf128 mentioned previously.  */
+  *p++ = BUILTIN1 (lrintl, *q++);
+
+  /* lroundf128 mentioned previously.  */
+  *p   = BUILTIN1 (lroundl, *q);  
+}
+
+/* Built-in functions that returns a long long and takes one long double
+   argument.  */
+
+void
+return_ll_arg_ld (long long *p,
+		  long double *r)
+{
+  /* ceilf128 mentioned previous.  */
+  *p++ = BUILTIN1 (llceill, *r++);
+
+  /* floorf128 mentioned previously.  */
+  *p++ = BUILTIN1 (llfloorl, *r++);
+
+  /* llrintf128 mentioned previously.  */
+  *p++ = BUILTIN1 (llrintl, *r++);
+
+  /* llroundf128 mentioned previously.  */
+  *p   = BUILTIN1 (llroundl, *r);  
+}
+
+/* Built-in function that returns a double and takes one double and one long
+   double arguments.  */
+
+void
+return_d_arg_d_ld (double *p,
+		   double *q,
+		   long double *r)
+{
+  /* { dg-final { scan-assembler {\m__nexttoward_to_ieee128\M} } }  */
+  *p = BUILTIN2 (nexttoward, *q, *r);
+}
+
+/* Built-in function that returns a float and takes one float and one long
+   double arguments.  */
+
+void
+return_f_arg_f_ld (float *p,
+		   float *q,
+		   long double *r)
+{
+  /* { dg-final { scan-assembler {\m__nexttowardf_to_ieee128\M} } }  */
+  *p = BUILTIN2 (nexttowardf, *q, *r);
+}
+
+/* Built-in function that returns void and takes one long double and two
+   pointers to long double arguments.  */
+
+void
+return_void_arg_ld_pld_pld (long double *p,
+			    long double **q,
+			    long double **r)
+{
+  /* __sincosieee128 mentioned previously.  */
+  BUILTIN3 (sincosl, *p, *q, *r);
+}
+
+/* Debug main program to determine if the library has all of the mapped
+   external functions.  Note, you need a new enough glibc to provide all of the
+   f128 functions.  */
+#ifdef DO_MAIN
+int
+main (void)
+{
+  return 0;
+}
+#endif
diff --git a/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c
new file mode 100644
index 00000000000..77c7b41cec9
--- /dev/null
+++ b/gcc/testsuite/gcc.target/powerpc/float128-longdouble-stdio.c
@@ -0,0 +1,37 @@
+/* { dg-require-effective-target ppc_float128_hw } */
+/* { dg-require-effective-target power10_ok } */
+/* { dg-options "-mdejagnu-cpu=power9 -mno-pcrel -O2 -Wno-psabi -mabi=ieeelongdouble" } */
+
+/* Test if switching long double to IEEE 128-bit maps the printf and scanf
+   function names correctly.  We explicitly turn off PC-relative support to
+   make it simpler to compare the call without having a @notoc qualifier.  */
+
+#include <stdlib.h>
+
+volatile long double x = 1.0L;
+volatile long double y, z;
+
+int
+main (void)
+{
+  char buffer[100];
+
+  /* { dg-final { scan-assembler {\m__sprintfieee128\M} } }  */
+  __builtin_sprintf (buffer, "%Lg", x);
+
+  /* { dg-final { scan-assembler {\m__printfieee128\M} } }  */
+  __builtin_printf ("x is %Lg [%s]\n", x, buffer);
+
+  /* { dg-final { scan-assembler {\m__isoc99sscanfieee128\M} } }  */
+  __builtin_sscanf (buffer, "%Lg", &y);
+
+  __builtin_printf ("Type 1.0: ");
+
+  /* { dg-final { scan-assembler {\m__isoc99scanfieee128\M} } }  */
+  __builtin_scanf ("%Lg", &z);
+
+  if (x != y || x != z)
+    abort ();
+
+  return 0;
+}


^ permalink raw reply	[flat|nested] 4+ messages in thread

* [gcc(refs/users/meissner/heads/work019)] PowerPC: Map long double built-in functions if IEEE 128-bit long double.
@ 2020-09-30 21:12 Michael Meissner
  0 siblings, 0 replies; 4+ messages in thread
From: Michael Meissner @ 2020-09-30 21:12 UTC (permalink / raw)
  To: gcc-cvs

https://gcc.gnu.org/g:8d1e60d721025187165dd80f329a53dc44cc39d0

commit 8d1e60d721025187165dd80f329a53dc44cc39d0
Author: Michael Meissner <meissner@linux.ibm.com>
Date:   Wed Sep 30 17:11:27 2020 -0400

    PowerPC: Map long double built-in functions if IEEE 128-bit long double.
    
    This patch goes through the built-in functions and changes the name that is
    used to the name used for __float128 and _Float128 support in glibc if the
    PowerPC long double type is IEEE 128-bit instead of IBM extended double.
    
    Normally the mapping is done in the math.h and stdio.h files.  However, not
    everybody uses these files, which means we also need to change the external
    name for the built-in function within the compiler.
    
    In addition, changing the name in GCC allows the Fortran compiler to
    automatically use the correct name.
    
    To map the math functions, typically this patch changes <name>l to <name>f128.
    However there are some exceptions that are handled with this patch.
    
    To map the printf functions, <name> is mapped to __<name>ieee128.
    
    To map the scanf functions, <name> is mapped to __isoc99<name>ieee128.
    
    gcc/
    2020-09-30  Michael Meissner  <meissner@linux.ibm.com>
    
            * config/rs6000/rs6000.c (rs6000_mangle_decl_assembler_name): Add
            support for mapping built-in function names for long double
            built-in functions if long double is IEEE 128-bit.
    
    gcc/testsuite/
    2020-09-30  Michael Meissner  <meissner@linux.ibm.com>
    
            * gcc.target/powerpc/float128-longdouble-math.c: New test.
            * gcc.target/powerpc/float128-longdouble-stdio.c: New test.

Diff:
---
 gcc/config/rs6000/rs6000.c | 153 ++++++++++++++++++++++++++++++++++++---------
 1 file changed, 122 insertions(+), 31 deletions(-)

diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 481f0d823cd..958c4ee5e80 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -26909,56 +26909,147 @@ rs6000_globalize_decl_name (FILE * stream, tree decl)
    library before you can switch the real*16 type at compile time.
 
    We use the TARGET_MANGLE_DECL_ASSEMBLER_NAME hook to change this name.  We
-   only do this if the default is that long double is IBM extended double, and
-   the user asked for IEEE 128-bit.  */
+   only do this transformation if the __float128 type is enabled.  This
+   prevents us from doing the transformation on older 32-bit ports that might
+   have enabled using IEEE 128-bit floating point as the default long double
+   type.  */
 
 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) )
+  if (TARGET_FLOAT128_TYPE && TARGET_IEEEQUAD && TARGET_LONG_DOUBLE_128
+      && TREE_CODE (decl) == FUNCTION_DECL
+      && fndecl_built_in_p (decl, BUILT_IN_NORMAL))
     {
       size_t len = IDENTIFIER_LENGTH (id);
       const char *name = IDENTIFIER_POINTER (id);
+      const char *newname = NULL;
 
-      if (name[len - 1] == 'l')
+      /* See if it is one of the built-in functions with an unusual name.  */
+      switch (DECL_FUNCTION_CODE (decl))
 	{
-	  bool uses_ieee128_p = false;
-	  tree type = TREE_TYPE (decl);
-	  machine_mode ret_mode = TYPE_MODE (type);
+	default:
+	  break;
 
-	  /* See if the function returns a IEEE 128-bit floating point type or
-	     complex type.  */
-	  if (ret_mode == TFmode || ret_mode == TCmode)
-	    uses_ieee128_p = true;
-	  else
+	case BUILT_IN_DREML:
+	  newname = "remainderf128";
+	  break;
+
+	case BUILT_IN_GAMMAL:
+	  newname = "lgammaf128";
+	  break;
+
+	case BUILT_IN_GAMMAL_R:
+	case BUILT_IN_LGAMMAL_R:
+	  newname = "__lgammaieee128_r";
+	  break;
+
+	case BUILT_IN_NEXTTOWARD:
+	  newname = "__nexttoward_to_ieee128";
+	  break;
+
+	case BUILT_IN_NEXTTOWARDF:
+	  newname = "__nexttowardf_to_ieee128";
+	  break;
+
+	case BUILT_IN_NEXTTOWARDL:
+	  newname = "__nexttowardieee128";
+	  break;
+
+	case BUILT_IN_POW10L:
+	  newname = "exp10f128";
+	  break;
+
+	case BUILT_IN_SCALBL:
+	  newname = "__scalbnieee128";
+	  break;
+
+	case BUILT_IN_SIGNIFICANDL:
+	  newname = "__significandieee128";
+	  break;
+
+	case BUILT_IN_SINCOSL:
+	  newname = "__sincosieee128";
+	  break;
+	}
+
+      /* Update the __builtin_*printf && __builtin_*scanf functions.  */
+      if (!newname)
+	{
+	  const size_t printf_len = sizeof ("printf") - 1;
+	  const size_t scanf_len = sizeof ("scanf") - 1;
+	  const size_t printf_extra
+	    = sizeof ("__") - 1 + sizeof ("ieee128") - 1;
+	  const size_t scanf_extra
+	    = sizeof ("__isoc99_") - 1 + sizeof ("ieee128") - 1;
+
+	  if (len >= printf_len
+	      && strcmp (name + len - printf_len, "printf") == 0)
 	    {
-	      function_args_iterator args_iter;
-	      tree arg;
+	      char *name2 = (char *) alloca (len + 1 + printf_extra);
+	      strcpy (name2, "__");
+	      memcpy (name2 + 2, name, len);
+	      strcpy (name2 + 2 + len, "ieee128");
+	      newname = (const char *) name2;
+	    }
 
-	      /* See if the function passes a IEEE 128-bit floating point type
-		 or complex type.  */
-	      FOREACH_FUNCTION_ARGS (type, arg, args_iter)
+	  else if (len >= scanf_len
+		   && strcmp (name + len - scanf_len, "scanf") == 0)
+	    {
+	      char *name2 = (char *) alloca (len + 1 + scanf_extra);
+	      strcpy (name2, "__isoc99_");
+	      memcpy (name2 + sizeof ("__isoc99") - 1, name, len);
+	      strcpy (name2 + sizeof ("__isoc99") - 1 + len, "ieee128");
+	      newname = (const char *) name2;
+	    }
+
+	  else if (name[len - 1] == 'l')
+	    {
+	      bool uses_ieee128_p = false;
+	      tree type = TREE_TYPE (decl);
+	      machine_mode ret_mode = TYPE_MODE (type);
+
+	      /* See if the function returns a IEEE 128-bit floating point type or
+		 complex type.  */
+	      if (ret_mode == TFmode || ret_mode == TCmode)
+		uses_ieee128_p = true;
+	      else
 		{
-		  machine_mode arg_mode = TYPE_MODE (arg);
-		  if (arg_mode == TFmode || arg_mode == TCmode)
+		  function_args_iterator args_iter;
+		  tree arg;
+
+		  /* See if the function passes a IEEE 128-bit floating point type
+		     or complex type.  */
+		  FOREACH_FUNCTION_ARGS (type, arg, args_iter)
 		    {
-		      uses_ieee128_p = true;
-		      break;
+		      machine_mode arg_mode = TYPE_MODE (arg);
+		      if (arg_mode == TFmode || arg_mode == TCmode)
+			{
+			  uses_ieee128_p = true;
+			  break;
+			}
 		    }
 		}
-	    }
 
-	  /* If we passed or returned an IEEE 128-bit floating point type,
-	     change the name.  */
-	  if (uses_ieee128_p)
-	    {
-	      char *name2 = (char *) alloca (len + 4);
-	      memcpy (name2, name, len - 1);
-	      strcpy (name2 + len - 1, "f128");
-	      id = get_identifier (name2);
+	      /* If we passed or returned an IEEE 128-bit floating point type,
+		 change the name.  */
+	      if (uses_ieee128_p)
+		{
+		  char *name2 = (char *) alloca (len + 4);
+		  memcpy (name2, name, len - 1);
+		  strcpy (name2 + len - 1, "f128");
+		  newname = (const char *) name2;
+		}
 	    }
 	}
+
+      if (newname)
+	{
+	  if (TARGET_DEBUG_BUILTIN)
+	    fprintf (stderr, "Map %s => %s\n", name, newname);
+
+	  id = get_identifier (newname);
+	}
     }
 
   return id;


^ permalink raw reply	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2020-10-08 20:05 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-10-08 19:28 [gcc(refs/users/meissner/heads/work019)] PowerPC: Map long double built-in functions if IEEE 128-bit long double Michael Meissner
  -- strict thread matches above, loose matches on Subject: below --
2020-10-08 20:05 Michael Meissner
2020-09-30 21:25 Michael Meissner
2020-09-30 21:12 Michael Meissner

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).