+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
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. */
static bool
call_ABI_of_interest (tree fndecl)
{
- if (symtab->state == EXPANSION)
+ if (rs6000_gnu_attr && symtab->state == EXPANSION)
{
struct cgraph_node *c_node;
}
#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)
<= 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;
}
}
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
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
{ "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
{ $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
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