From e9dda04f0760e78c5834b1beddab39cd562ad7c1 Mon Sep 17 00:00:00 2001 From: Alan Modra Date: Thu, 29 Sep 2016 07:31:48 +0930 Subject: [PATCH] [RS6000] .gnu.attributes Tag_GNU_Power_ABI_FP 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 | 20 +++++++++ gcc/config.in | 6 +++ gcc/config/rs6000/rs6000.c | 87 ++++++++++++++++++++++++++++--------- gcc/config/rs6000/sysv4.opt | 4 ++ gcc/configure | 52 ++++++++++++++++++++++ gcc/configure.ac | 45 +++++++++++++++++++ gcc/doc/invoke.texi | 9 ++++ 7 files changed, 203 insertions(+), 20 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 588f2d1f45e..f2c8fe47b99 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,23 @@ +2016-09-29 Alan Modra + + * 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 * gimple-ssa-sprintf.c (pass_sprintf_length::gate): Use x > 0 instead diff --git a/gcc/config.in b/gcc/config.in index a736de3a82b..84704566cf8 100644 --- a/gcc/config.in +++ b/gcc/config.in @@ -1538,6 +1538,12 @@ #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 diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 4d3706c370e..c7ba617d4f0 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -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 diff --git a/gcc/config/rs6000/sysv4.opt b/gcc/config/rs6000/sysv4.opt index 581fcde4c55..cb5d7eabbeb 100644 --- a/gcc/config/rs6000/sysv4.opt +++ b/gcc/config/rs6000/sysv4.opt @@ -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. diff --git a/gcc/configure b/gcc/configure index 96eba9e5776..47f70e6c2f4 100755 --- a/gcc/configure +++ b/gcc/configure @@ -28322,6 +28322,58 @@ fi { $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 < conftest2.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 diff --git a/gcc/configure.ac b/gcc/configure.ac index 534f22e47de..a702f176974 100644 --- a/gcc/configure.ac +++ b/gcc/configure.ac @@ -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 < conftest2.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 diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 676746237e3..8a84e4f4823 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -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 -- 2.30.2