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  <meiss...@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  <meiss...@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.


-- 
Michael Meissner, IBM
IBM, M/S 2506R, 550 King Street, Littleton, MA 01460-6245, USA
email: meiss...@linux.ibm.com, phone: +1 (978) 899-4797
Index: gcc/config/rs6000/rs6000.c
===================================================================
--- 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} } }

Reply via email to