===================================================================
@@ -114,8 +114,6 @@
#define RELOCATABLE_NEEDS_FIXUP \
(target_flags & target_flags_explicit & MASK_RELOCATABLE)
-#define TARGET_ASM_FILE_END file_end_indicate_exec_stack
-
#define TARGET_POSIX_IO
#define MD_UNWIND_SUPPORT "config/rs6000/linux-unwind.h"
===================================================================
@@ -537,8 +537,6 @@ extern int dot_symbols;
#undef DRAFT_V4_STRUCT_RET
#define DRAFT_V4_STRUCT_RET (!TARGET_64BIT)
-#define TARGET_ASM_FILE_END rs6000_elf_end_indicate_exec_stack
-
#define TARGET_POSIX_IO
#define LINK_GCC_C_SEQUENCE_SPEC \
===================================================================
@@ -1031,6 +1031,8 @@ ncrtn.o%s"
/* Generate entries in .fixup for relocatable addresses. */
#define RELOCATABLE_NEEDS_FIXUP 1
+#define TARGET_ASM_FILE_END rs6000_elf_file_end
+
/* This target uses the sysv4.opt file. */
#define TARGET_USES_SYSV4_OPT 1
===================================================================
@@ -28,7 +28,8 @@
#ifdef RTX_CODE
#ifdef TREE_CODE
-extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, int, int, int);
+extern void init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx, int, int, int,
+ tree, enum machine_mode);
#endif /* TREE_CODE */
extern bool easy_altivec_constant (rtx, enum machine_mode);
===================================================================
@@ -1570,25 +1598,29 @@ typedef struct rs6000_args
int floats_in_gpr; /* count of SFmode floats taking up
GPR space (darwin64) */
int named; /* false for varargs params */
+ int escapes; /* if function visible outside tu */
} CUMULATIVE_ARGS;
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
For a library call, FNTYPE is 0. */
-#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
- init_cumulative_args (&CUM, FNTYPE, LIBNAME, FALSE, FALSE, N_NAMED_ARGS)
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
+ init_cumulative_args (&CUM, FNTYPE, LIBNAME, FALSE, FALSE, \
+ N_NAMED_ARGS, FNDECL, VOIDmode)
/* Similar, but when scanning the definition of a procedure. We always
set NARGS_PROTOTYPE large so we never return an EXPR_LIST. */
#define INIT_CUMULATIVE_INCOMING_ARGS(CUM, FNTYPE, LIBNAME) \
- init_cumulative_args (&CUM, FNTYPE, LIBNAME, TRUE, FALSE, 1000)
+ init_cumulative_args (&CUM, FNTYPE, LIBNAME, TRUE, FALSE, \
+ 1000, current_function_decl, VOIDmode)
/* Like INIT_CUMULATIVE_ARGS' but only used for outgoing libcalls. */
#define INIT_CUMULATIVE_LIBCALL_ARGS(CUM, MODE, LIBNAME) \
- init_cumulative_args (&CUM, NULL_TREE, LIBNAME, FALSE, TRUE, 0)
+ init_cumulative_args (&CUM, NULL_TREE, LIBNAME, FALSE, TRUE, \
+ 0, NULL_TREE, MODE)
/* If defined, a C expression which determines whether, and in which
direction, to pad out an argument with extra space. The value
===================================================================
@@ -184,6 +184,14 @@ unsigned rs6000_pmode;
/* Width in bits of a pointer. */
unsigned rs6000_pointer_size;
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+/* Flag whether floating point values have been passed/returned. */
+static bool rs6000_passes_float;
+/* Flag whether vector values have been passed/returned. */
+static bool rs6000_passes_vector;
+/* Flag whether small (<= 8 byte) structures have been returned. */
+static bool rs6000_returns_struct;
+#endif
/* Value is TRUE if register/mode pair is acceptable. */
bool rs6000_hard_regno_mode_ok_p[NUM_MACHINE_MODES][FIRST_PSEUDO_REGISTER];
@@ -940,7 +948,7 @@ static void rs6000_file_start (void);
static int rs6000_elf_reloc_rw_mask (void);
static void rs6000_elf_asm_out_constructor (rtx, int) ATTRIBUTE_UNUSED;
static void rs6000_elf_asm_out_destructor (rtx, int) ATTRIBUTE_UNUSED;
-static void rs6000_elf_end_indicate_exec_stack (void) ATTRIBUTE_UNUSED;
+static void rs6000_elf_file_end (void) ATTRIBUTE_UNUSED;
static void rs6000_elf_asm_init_sections (void);
static section *rs6000_elf_select_rtx_section (enum machine_mode, rtx,
unsigned HOST_WIDE_INT);
@@ -4695,23 +4703,6 @@ rs6000_file_start (void)
putc ('\n', file);
}
-#ifdef HAVE_AS_GNU_ATTRIBUTE
- if (TARGET_32BIT && DEFAULT_ABI == ABI_V4)
- {
- fprintf (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));
- fprintf (file, "\t.gnu_attribute 8, %d\n",
- (TARGET_ALTIVEC_ABI ? 2
- : TARGET_SPE_ABI ? 3
- : 1));
- fprintf (file, "\t.gnu_attribute 12, %d\n",
- aix_struct_return ? 2 : 1);
-
- }
-#endif
-
if (DEFAULT_ABI == ABI_AIX || (TARGET_ELF && flag_pic == 2))
{
switch_to_section (toc_section);
@@ -7859,9 +7849,36 @@ rs6000_return_in_memory (const_tree type
return false;
}
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+/* Return TRUE if a call to function FNDECL may be one that
+ potentially affects the function calling ABI of the object file. */
+
+static bool
+call_ABI_of_interest (tree fndecl)
+{
+ if (cgraph_state == CGRAPH_STATE_EXPANSION)
+ {
+ struct cgraph_node *c_node;
+
+ /* Libcalls are always interesting. */
+ if (fndecl == NULL_TREE)
+ return true;
+
+ /* Any call to an external function is interesting. */
+ if (DECL_EXTERNAL (fndecl))
+ return true;
+
+ /* Interesting functions that we are emitting in this object file. */
+ c_node = cgraph_node (fndecl);
+ return !cgraph_only_called_directly_p (c_node);
+ }
+ return false;
+}
+#endif
+
/* Initialize a variable CUM of type CUMULATIVE_ARGS
for a call to a function whose data type is FNTYPE.
- For a library call, FNTYPE is 0.
+ For a library call, FNTYPE is 0 and RETURN_MODE the return value mode.
For incoming args we set the number of arguments in the prototype large
so we never return a PARALLEL. */
@@ -7869,7 +7886,9 @@ rs6000_return_in_memory (const_tree type
void
init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
rtx libname ATTRIBUTE_UNUSED, int incoming,
- int libcall, int n_named_args)
+ int libcall, int n_named_args,
+ tree fndecl ATTRIBUTE_UNUSED,
+ enum machine_mode return_mode ATTRIBUTE_UNUSED)
{
static CUMULATIVE_ARGS zero_cumulative;
@@ -7911,6 +7930,45 @@ init_cumulative_args (CUMULATIVE_ARGS *c
cum->prototype, cum->nargs_prototype);
}
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+ if (DEFAULT_ABI == ABI_V4)
+ {
+ cum->escapes = call_ABI_of_interest (fndecl);
+ if (cum->escapes)
+ {
+ tree return_type;
+
+ if (fntype)
+ {
+ return_type = TREE_TYPE (fntype);
+ return_mode = TYPE_MODE (return_type);
+ }
+ else
+ return_type = lang_hooks.types.type_for_mode (return_mode, 0);
+
+ if (return_type != NULL)
+ {
+ if (TREE_CODE (return_type) == RECORD_TYPE
+ && TYPE_TRANSPARENT_AGGR (return_type))
+ {
+ return_type = TREE_TYPE (first_field (return_type));
+ return_mode = TYPE_MODE (return_type);
+ }
+ if (AGGREGATE_TYPE_P (return_type)
+ && ((unsigned HOST_WIDE_INT) int_size_in_bytes (return_type)
+ <= 8))
+ rs6000_returns_struct = true;
+ }
+ if (SCALAR_FLOAT_MODE_P (return_mode))
+ rs6000_passes_float = true;
+ else if (ALTIVEC_VECTOR_MODE (return_mode)
+ || VSX_VECTOR_MODE (return_mode)
+ || SPE_VECTOR_MODE (return_mode))
+ rs6000_passes_vector = true;
+ }
+ }
+#endif
+
if (fntype
&& !TARGET_ALTIVEC
&& TARGET_ALTIVEC_ABI
@@ -8229,11 +8287,25 @@ static void
rs6000_function_arg_advance_1 (CUMULATIVE_ARGS *cum, enum machine_mode mode,
const_tree type, bool named, int depth)
{
-
/* Only tick off an argument if we're not recursing. */
if (depth == 0)
cum->nargs_prototype--;
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+ if (DEFAULT_ABI == ABI_V4
+ && cum->escapes)
+ {
+ if (SCALAR_FLOAT_MODE_P (mode))
+ rs6000_passes_float = true;
+ else if (named && (ALTIVEC_VECTOR_MODE (mode) || VSX_VECTOR_MODE (mode)))
+ rs6000_passes_vector = true;
+ else if (SPE_VECTOR_MODE (mode)
+ && !cum->stdarg
+ && cum->sysv_gregno <= GP_ARG_MAX_REG)
+ rs6000_passes_vector = true;
+ }
+#endif
+
if (TARGET_ALTIVEC_ABI
&& (ALTIVEC_VECTOR_MODE (mode)
|| VSX_VECTOR_MODE (mode)
@@ -9498,6 +9570,11 @@ rs6000_va_start (tree valist, rtx nextar
build_int_cst (NULL_TREE, n_fpr));
TREE_SIDE_EFFECTS (t) = 1;
expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
+
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+ if (call_ABI_of_interest (cfun->decl))
+ rs6000_passes_float = true;
+#endif
}
/* Find the overflow area. */
@@ -25780,10 +25868,30 @@ rs6000_elf_declare_function_name (FILE *
}
static void
-rs6000_elf_end_indicate_exec_stack (void)
+rs6000_elf_file_end (void)
{
+#ifdef HAVE_AS_GNU_ATTRIBUTE
+ 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
+ : TARGET_SPE_ABI ? 3
+ : 1));
+ if (rs6000_returns_struct)
+ fprintf (asm_out_file, "\t.gnu_attribute 12, %d\n",
+ aix_struct_return ? 2 : 1);
+ }
+#endif
+#ifdef POWERPC_LINUX
if (TARGET_32BIT)
file_end_indicate_exec_stack ();
+#endif
}
#endif