[RS6000] .gnu.attributes Tag_GNU_Power_ABI_FP
authorAlan Modra <amodra@gmail.com>
Wed, 28 Sep 2016 22:01:48 +0000 (07:31 +0930)
committerAlan Modra <amodra@gcc.gnu.org>
Wed, 28 Sep 2016 22:01:48 +0000 (07:31 +0930)
Extend this attribute to cover long double ABIs, for 64-bit too.

This patch also corrects an error that crept in to code setting
rs6000_passes_float.  See the added comment.  Passing IEEE128 values
in vsx regs ought to set both Tag_GNU_Power_ABI_FP and
Tag_GNU_Power_ABI_Vector.  Also adds a new option, default on, that
disables output of .gnu_attribute assembly directives.

* config/rs6000/sysv4.opt (mgnu-attribute): New option.
* doc/invoke.texi: Document it.
* config/rs6000/rs6000.c (HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE): Define.
(rs6000_passes_float): Comment.
(rs6000_passes_long_double): New static var.
(call_ABI_of_interest): Return false unless rs6000_gnu_attr is set.
(init_cumulative_args): Set up to emit fp .gnu_attribute for
ELF 64-bit ABIs as well as 32-bit ELF.  Correct rs6000_passes_float
to include fp values returned in vectors.
Set rs6000_passes_long_double.
(rs6000_function_arg_advance_1): Likewise for function args.
(rs6000_elf_file_end): Emit fp .gnu_attribute for ELF 64-bit ABIs,
and SPE.  Emit long double tag value too.
(rs6000_opt_vars): Add gnu-attr.
* configure.ac (HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE): New ppc32 test.
* configure: Regenerate.
* config.in: Regenerate.

From-SVN: r240601

gcc/ChangeLog
gcc/config.in
gcc/config/rs6000/rs6000.c
gcc/config/rs6000/sysv4.opt
gcc/configure
gcc/configure.ac
gcc/doc/invoke.texi

index 588f2d1f45e15b11d5fe9fe72772840d2feef504..f2c8fe47b991224e06ff0da491e46c4b582ba622 100644 (file)
@@ -1,3 +1,23 @@
+2016-09-29  Alan Modra  <amodra@gmail.com>
+
+       * config/rs6000/sysv4.opt (mgnu-attribute): New option.
+       * doc/invoke.texi: Document it.
+       * config/rs6000/rs6000.c (HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE): Define.
+       (rs6000_passes_float): Comment.
+       (rs6000_passes_long_double): New static var.
+       (call_ABI_of_interest): Return false unless rs6000_gnu_attr is set.
+       (init_cumulative_args): Set up to emit fp .gnu_attribute for
+       ELF 64-bit ABIs as well as 32-bit ELF.  Correct rs6000_passes_float
+       to include fp values returned in vectors.
+       Set rs6000_passes_long_double.
+       (rs6000_function_arg_advance_1): Likewise for function args.
+       (rs6000_elf_file_end): Emit fp .gnu_attribute for ELF 64-bit ABIs,
+       and SPE.  Emit long double tag value too.
+       (rs6000_opt_vars): Add gnu-attr.
+       * configure.ac (HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE): New ppc32 test.
+       * configure: Regenerate.
+       * config.in: Regenerate.
+
 2016-09-28  Jakub Jelinek  <jakub@redhat.com>
 
        * gimple-ssa-sprintf.c (pass_sprintf_length::gate): Use x > 0 instead
index a736de3a82be644558beebedbe120b4b5212fb25..84704566cf80f2e5c0806162e1f8697bfbda7ca9 100644 (file)
 #endif
 
 
+/* Define if your PowerPC linker has .gnu.attributes long double support. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE
+#endif
+
+
 /* Define if your linker supports --push-state/--pop-state */
 #ifndef USED_FOR_TARGET
 #undef HAVE_LD_PUSHPOPSTATE_SUPPORT
index 4d3706c370e00face4e254301f861dab66bd4562..c7ba617d4f02f3d0c8274a073a4732ec0c1e9d2d 100644 (file)
@@ -183,8 +183,16 @@ unsigned rs6000_pmode;
 unsigned rs6000_pointer_size;
 
 #ifdef HAVE_AS_GNU_ATTRIBUTE
-/* Flag whether floating point values have been passed/returned.  */
+# ifndef HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE
+# define HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE 0
+# endif
+/* Flag whether floating point values have been passed/returned.
+   Note that this doesn't say whether fprs are used, since the
+   Tag_GNU_Power_ABI_FP .gnu.attributes value this flag controls
+   should be set for soft-float values passed in gprs and ieee128
+   values passed in vsx registers.  */
 static bool rs6000_passes_float;
+static bool rs6000_passes_long_double;
 /* Flag whether vector values have been passed/returned.  */
 static bool rs6000_passes_vector;
 /* Flag whether small (<= 8 byte) structures have been returned.  */
@@ -10920,7 +10928,7 @@ rs6000_return_in_msb (const_tree valtype)
 static bool
 call_ABI_of_interest (tree fndecl)
 {
-  if (symtab->state == EXPANSION)
+  if (rs6000_gnu_attr && symtab->state == EXPANSION)
     {
       struct cgraph_node *c_node;
 
@@ -10997,7 +11005,7 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
     }
 
 #ifdef HAVE_AS_GNU_ATTRIBUTE
-  if (DEFAULT_ABI == ABI_V4)
+  if (TARGET_ELF && (TARGET_64BIT || DEFAULT_ABI == ABI_V4))
     {
       cum->escapes = call_ABI_of_interest (fndecl);
       if (cum->escapes)
@@ -11025,10 +11033,19 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
                      <= 8))
                rs6000_returns_struct = true;
            }
-         if (SCALAR_FLOAT_MODE_NOT_VECTOR_P (return_mode))
-           rs6000_passes_float = true;
-         else if (ALTIVEC_OR_VSX_VECTOR_MODE (return_mode)
-                  || SPE_VECTOR_MODE (return_mode))
+         if (SCALAR_FLOAT_MODE_P (return_mode))
+           {
+             rs6000_passes_float = true;
+             if ((HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE || TARGET_64BIT)
+                 && (FLOAT128_IBM_P (return_mode)
+                     || FLOAT128_IEEE_P (return_mode)
+                     || (return_type != NULL
+                         && (TYPE_MAIN_VARIANT (return_type)
+                             == long_double_type_node))))
+               rs6000_passes_long_double = true;
+           }
+         if (ALTIVEC_OR_VSX_VECTOR_MODE (return_mode)
+             || SPE_VECTOR_MODE (return_mode))
            rs6000_passes_vector = true;
        }
     }
@@ -11475,16 +11492,23 @@ rs6000_function_arg_advance_1 (CUMULATIVE_ARGS *cum, machine_mode mode,
     cum->nargs_prototype--;
 
 #ifdef HAVE_AS_GNU_ATTRIBUTE
-  if (DEFAULT_ABI == ABI_V4
+  if (TARGET_ELF && (TARGET_64BIT || DEFAULT_ABI == ABI_V4)
       && cum->escapes)
     {
-      if (SCALAR_FLOAT_MODE_NOT_VECTOR_P (mode))
-       rs6000_passes_float = true;
-      else if (named && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
-       rs6000_passes_vector = true;
-      else if (SPE_VECTOR_MODE (mode)
-              && !cum->stdarg
-              && cum->sysv_gregno <= GP_ARG_MAX_REG)
+      if (SCALAR_FLOAT_MODE_P (mode))
+       {
+         rs6000_passes_float = true;
+         if ((HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE || TARGET_64BIT)
+             && (FLOAT128_IBM_P (mode)
+                 || FLOAT128_IEEE_P (mode)
+                 || (type != NULL
+                     && TYPE_MAIN_VARIANT (type) == long_double_type_node)))
+           rs6000_passes_long_double = true;
+       }
+      if ((named && ALTIVEC_OR_VSX_VECTOR_MODE (mode))
+         || (SPE_VECTOR_MODE (mode)
+             && !cum->stdarg
+             && cum->sysv_gregno <= GP_ARG_MAX_REG))
        rs6000_passes_vector = true;
     }
 #endif
@@ -34292,13 +34316,33 @@ static void
 rs6000_elf_file_end (void)
 {
 #ifdef HAVE_AS_GNU_ATTRIBUTE
+  /* ??? The value emitted depends on options active at file end.
+     Assume anyone using #pragma or attributes that might change
+     options knows what they are doing.  */
+  if ((TARGET_64BIT || DEFAULT_ABI == ABI_V4)
+      && rs6000_passes_float)
+    {
+      int fp;
+
+      if (TARGET_DF_FPR | TARGET_DF_SPE)
+       fp = 1;
+      else if (TARGET_SF_FPR | TARGET_SF_SPE)
+       fp = 3;
+      else
+       fp = 2;
+      if (rs6000_passes_long_double)
+       {
+         if (!TARGET_LONG_DOUBLE_128)
+           fp |= 2 * 4;
+         else if (TARGET_IEEEQUAD)
+           fp |= 3 * 4;
+         else
+           fp |= 1 * 4;
+       }
+      fprintf (asm_out_file, "\t.gnu_attribute 4, %d\n", fp);
+    }
   if (TARGET_32BIT && DEFAULT_ABI == ABI_V4)
     {
-      if (rs6000_passes_float)
-       fprintf (asm_out_file, "\t.gnu_attribute 4, %d\n",
-                ((TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_DOUBLE_FLOAT) ? 1 
-                 : (TARGET_HARD_FLOAT && TARGET_FPRS && TARGET_SINGLE_FLOAT) ? 3 
-                 : 2));
       if (rs6000_passes_vector)
        fprintf (asm_out_file, "\t.gnu_attribute 8, %d\n",
                 (TARGET_ALTIVEC_ABI ? 2
@@ -37085,6 +37129,9 @@ static struct rs6000_opt_var const rs6000_opt_vars[] =
   { "warn-cell-microcode",
     offsetof (struct gcc_options, x_rs6000_warn_cell_microcode),
     offsetof (struct cl_target_option, x_rs6000_warn_cell_microcode), },
+  { "gnu-attr",
+    offsetof (struct gcc_options, x_rs6000_gnu_attr),
+    offsetof (struct cl_target_option, x_rs6000_gnu_attr), },
 };
 
 /* Inner function to handle attribute((target("..."))) and #pragma GCC target
index 581fcde4c55543e0eec7cea72403480777641437..cb5d7eabbeb864784fe616de203dd121440f5a46 100644 (file)
@@ -155,3 +155,7 @@ Generate code to use a non-exec PLT and GOT.
 mbss-plt
 Target Report RejectNegative Var(secure_plt, 0) Save
 Generate code for old exec BSS PLT.
+
+mgnu-attribute
+Target Report Var(rs6000_gnu_attr) Init(1) Save
+Emit .gnu_attribute tags.
index 96eba9e5776bfbe8e3d0a12882e0624a6d240c97..47f70e6c2f4e55c29993eb1b571ca0d63c8b4ed5 100755 (executable)
 { $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_clearcap" >&5
 $as_echo "$gcc_cv_ld_clearcap" >&6; }
 
+case "$target" in
+  powerpc*-*-*)
+    case "$target" in
+      *le-*-linux*)
+       emul_name="-melf32lppc"
+       ;;
+      *)
+       emul_name="-melf32ppc"
+       ;;
+    esac
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking linker .gnu.attributes long double support" >&5
+$as_echo_n "checking linker .gnu.attributes long double support... " >&6; }
+if test "${gcc_cv_ld_ppc_attr+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_ld_ppc_attr=no
+    if test x"$ld_is_gold" = xyes; then
+      gcc_cv_ld_ppc_attr=yes
+    elif test $in_tree_ld = yes ; then
+      if test "$gcc_cv_gld_major_version" -eq 2 \
+               -a "$gcc_cv_gld_minor_version" -ge 28 \
+               -o "$gcc_cv_gld_major_version" -gt 2; then
+        gcc_cv_ld_ppc_attr=yes
+      fi
+    elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x ; then
+      # check that merging the long double .gnu_attribute doesn't warn
+      cat > conftest1.s <<EOF
+       .gnu_attribute 4,1
+EOF
+      cat > conftest2.s <<EOF
+       .gnu_attribute 4,9
+EOF
+      if $gcc_cv_as -a32 -o conftest1.o conftest1.s > /dev/null 2>&1 \
+         && $gcc_cv_as -a32 -o conftest2.o conftest2.s > /dev/null 2>&1 \
+         && $gcc_cv_ld $emul_name -r -o conftest.o conftest1.o conftest2.o > /dev/null 2> conftest.err \
+        && test ! -s conftest.err; then
+        gcc_cv_ld_ppc_attr=yes
+      fi
+      rm -f conftest.err conftest.o conftest1.o conftest2.o conftest1.s conftest2.s
+    fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_ld_ppc_attr" >&5
+$as_echo "$gcc_cv_ld_ppc_attr" >&6; }
+    if test x$gcc_cv_ld_ppc_attr = xyes; then
+
+$as_echo "#define HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE 1" >>confdefs.h
+
+    fi
+    ;;
+esac
+
 case "$target:$tm_file" in
   powerpc64-*-freebsd* | powerpc64*-*-linux* | powerpc*-*-linux*rs6000/biarch64.h*)
   case "$target" in
index 534f22e47de1569fb5a5678a723cf8fe30164fa5..a702f176974d34181d0baa70115ee1bac8da696f 100644 (file)
@@ -5322,6 +5322,51 @@ if test "x$gcc_cv_ld_clearcap" = xyes; then
 fi
 AC_MSG_RESULT($gcc_cv_ld_clearcap)
 
+case "$target" in
+  powerpc*-*-*)
+    case "$target" in
+      *le-*-linux*)
+       emul_name="-melf32lppc"
+       ;;
+      *)
+       emul_name="-melf32ppc"
+       ;;
+    esac
+    AC_CACHE_CHECK(linker .gnu.attributes long double support,
+    gcc_cv_ld_ppc_attr,
+    [gcc_cv_ld_ppc_attr=no
+    if test x"$ld_is_gold" = xyes; then
+      gcc_cv_ld_ppc_attr=yes
+    elif test $in_tree_ld = yes ; then
+      if test "$gcc_cv_gld_major_version" -eq 2 \
+               -a "$gcc_cv_gld_minor_version" -ge 28 \
+               -o "$gcc_cv_gld_major_version" -gt 2; then
+        gcc_cv_ld_ppc_attr=yes
+      fi
+    elif test x$gcc_cv_as != x -a x$gcc_cv_ld != x ; then
+      # check that merging the long double .gnu_attribute doesn't warn
+      cat > conftest1.s <<EOF
+       .gnu_attribute 4,1
+EOF
+      cat > conftest2.s <<EOF
+       .gnu_attribute 4,9
+EOF
+      if $gcc_cv_as -a32 -o conftest1.o conftest1.s > /dev/null 2>&1 \
+         && $gcc_cv_as -a32 -o conftest2.o conftest2.s > /dev/null 2>&1 \
+         && $gcc_cv_ld $emul_name -r -o conftest.o conftest1.o conftest2.o > /dev/null 2> conftest.err \
+        && test ! -s conftest.err; then
+        gcc_cv_ld_ppc_attr=yes
+      fi
+      rm -f conftest.err conftest.o conftest1.o conftest2.o conftest1.s conftest2.s
+    fi
+    ])
+    if test x$gcc_cv_ld_ppc_attr = xyes; then
+      AC_DEFINE(HAVE_LD_PPC_GNU_ATTR_LONG_DOUBLE, 1,
+    [Define if your PowerPC linker has .gnu.attributes long double support.])
+    fi
+    ;;
+esac
+
 case "$target:$tm_file" in
   powerpc64-*-freebsd* | powerpc64*-*-linux* | powerpc*-*-linux*rs6000/biarch64.h*)
   case "$target" in
index 676746237e32be7d747a5f6c854376490e58e0d6..8a84e4f4823f5a17a3b62c6f804b1e3bdb7e5b18 100644 (file)
@@ -1017,6 +1017,7 @@ See RS/6000 and PowerPC Options.
 -mupper-regs-di -mno-upper-regs-di @gol
 -mupper-regs -mno-upper-regs @gol
 -mfloat128 -mno-float128 -mfloat128-hardware -mno-float128-hardware @gol
+-mgnu-attribute -mno-gnu-attribute @gol
 -mlra -mno-lra}
 
 @emph{RX Options}
@@ -21299,6 +21300,14 @@ This is the default ABI for little-endian PowerPC 64-bit Linux.
 Overriding the default ABI requires special system support and is
 likely to fail in spectacular ways.
 
+@item -mgnu-attribute
+@itemx -mno-gnu-attribute
+@opindex mgnu-attribute
+@opindex mno-gnu-attribute
+Emit .gnu_attribute assembly directives to set tag/value pairs in a
+.gnu.attributes section that specify ABI variations in function
+parameters or return values.
+
 @item -mprototype
 @itemx -mno-prototype
 @opindex mprototype