aboutsummaryrefslogtreecommitdiff
path: root/gcc/config/rs6000/rs6000.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r--gcc/config/rs6000/rs6000.c965
1 files changed, 918 insertions, 47 deletions
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 73b912cf930..5f5361a8d4d 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -50,12 +50,20 @@
#include "target-def.h"
#include "langhooks.h"
#include "reload.h"
+/* APPLE LOCAL why is this needed? */
+#include "insn-addr.h"
#include "cfglayout.h"
#include "sched-int.h"
#if TARGET_XCOFF
#include "xcoffout.h" /* get declarations of xcoff_*_section_name */
#endif
+/* APPLE LOCAL begin Macintosh alignment */
+#ifndef TARGET_ALIGN_MAC68K
+#define TARGET_ALIGN_MAC68K 0
+#endif
+/* APPLE LOCAL end Macintosh alignment */
+
#ifndef TARGET_NO_PROTOTYPE
#define TARGET_NO_PROTOTYPE 0
#endif
@@ -216,9 +224,16 @@ int rs6000_debug_arg; /* debug argument handling */
static GTY(()) tree opaque_V2SI_type_node;
static GTY(()) tree opaque_V2SF_type_node;
static GTY(()) tree opaque_p_V2SI_type_node;
-
-/* AltiVec requires a few more basic types in addition to the vector
- types already defined in tree.c. */
+static GTY(()) tree V16QI_type_node;
+static GTY(()) tree V2SI_type_node;
+static GTY(()) tree V2SF_type_node;
+static GTY(()) tree V4HI_type_node;
+static GTY(()) tree V4SI_type_node;
+static GTY(()) tree V4SF_type_node;
+static GTY(()) tree V8HI_type_node;
+static GTY(()) tree unsigned_V16QI_type_node;
+static GTY(()) tree unsigned_V8HI_type_node;
+static GTY(()) tree unsigned_V4SI_type_node;
static GTY(()) tree bool_char_type_node; /* __bool char */
static GTY(()) tree bool_short_type_node; /* __bool short */
static GTY(()) tree bool_int_type_node; /* __bool int */
@@ -302,6 +317,7 @@ static void rs6000_assemble_visibility (tree, int);
static int rs6000_ra_ever_killed (void);
static tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *);
static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *);
+static const char *rs6000_mangle_fundamental_type (tree);
extern const struct attribute_spec rs6000_attribute_table[];
static void rs6000_set_default_type_attributes (tree);
static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT);
@@ -410,15 +426,18 @@ static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *,
enum machine_mode, tree);
static rtx rs6000_mixed_function_arg (CUMULATIVE_ARGS *,
enum machine_mode, tree, int);
-static void rs6000_move_block_from_reg(int regno, rtx x, int nregs);
+static void rs6000_move_block_from_reg (int regno, rtx x, int nregs);
static void setup_incoming_varargs (CUMULATIVE_ARGS *,
enum machine_mode, tree,
int *, int);
+/* APPLE LOCAL begin Altivec */
+static bool skip_vec_args (tree, int, int*);
+/* APPLE LOCAL begin Altivec */
#if TARGET_MACHO
static void macho_branch_islands (void);
static void add_compiler_branch_island (tree, tree, int);
-static int no_previous_def (tree function_name);
-static tree get_prev_label (tree function_name);
+static int no_previous_def (tree);
+static tree get_prev_label (tree);
#endif
static tree rs6000_build_builtin_va_list (void);
@@ -575,6 +594,9 @@ static const char alt_reg_names[][8] =
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN rs6000_expand_builtin
+#undef TARGET_MANGLE_FUNDAMENTAL_TYPE
+#define TARGET_MANGLE_FUNDAMENTAL_TYPE rs6000_mangle_fundamental_type
+
#undef TARGET_INIT_LIBFUNCS
#define TARGET_INIT_LIBFUNCS rs6000_init_libfuncs
@@ -616,6 +638,11 @@ static const char alt_reg_names[][8] =
#undef TARGET_SETUP_INCOMING_VARARGS
#define TARGET_SETUP_INCOMING_VARARGS setup_incoming_varargs
+/* APPLE LOCAL begin Altivec */
+#undef TARGET_SKIP_VEC_ARGS
+#define TARGET_SKIP_VEC_ARGS skip_vec_args
+/* APPLE LOCAL end Altivec */
+
/* Always strict argument naming on rs6000. */
#undef TARGET_STRICT_ARGUMENT_NAMING
#define TARGET_STRICT_ARGUMENT_NAMING hook_bool_CUMULATIVE_ARGS_true
@@ -636,6 +663,9 @@ rs6000_override_options (const char *default_cpu)
size_t i, j;
struct rs6000_cpu_select *ptr;
int set_masks;
+/* APPLE LOCAL begin -fast */
+ enum processor_type mcpu_cpu;
+/* APPLE LOCAL end -fast */
/* Simplifications for entries below. */
@@ -746,6 +776,20 @@ rs6000_override_options (const char *default_cpu)
rs6000_select[0].string = default_cpu;
rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT;
+ /* APPLE LOCAL begin -fast */
+ if (flag_fast || flag_fastf || flag_fastcp)
+ {
+ mcpu_cpu = PROCESSOR_POWER4;
+ if (rs6000_select[1].string == (char *)0 && rs6000_select[2].string == (char *)0)
+ {
+ /* -mcpu and -mtune unspecified. Assume both are G5 */
+ set_target_switch ("tune=G5");
+ set_target_switch ("cpu=G5");
+ }
+ }
+ /* APPLE LOCAL end -fast */
+
+
for (i = 0; i < ARRAY_SIZE (rs6000_select); i++)
{
ptr = &rs6000_select[i];
@@ -762,6 +806,9 @@ rs6000_override_options (const char *default_cpu)
target_flags &= ~set_masks;
target_flags |= (processor_target_table[j].target_enable
& set_masks);
+ /* APPLE LOCAL begin -fast */
+ mcpu_cpu = processor_target_table[j].processor;
+ /* APPLE LOCAL end -fast */
}
break;
}
@@ -771,6 +818,48 @@ rs6000_override_options (const char *default_cpu)
}
}
+ /* APPLE LOCAL begin -fast */
+ if (flag_fast || flag_fastf || flag_fastcp)
+ {
+ flag_gcse_sm = 1;
+ flag_loop_transpose = 1;
+ rs6000_sched_insert_nops = sched_finish_regroup_exact;
+ flag_unroll_loops = 1;
+ flag_strict_aliasing = 1;
+ flag_schedule_interblock = 1;
+ align_jumps_max_skip = 15;
+ align_loops_max_skip = 15;
+ align_functions = 16;
+ align_loops = 16;
+ align_jumps = 16;
+ set_fast_math_flags (1);
+ flag_reorder_blocks = 1;
+#if 0
+ if (flag_branch_probabilities && !flag_exceptions)
+ flag_reorder_blocks_and_partition = 1;
+#endif
+ if (!flag_pic)
+ set_target_switch ("dynamic-no-pic");
+
+ if (mcpu_cpu == PROCESSOR_POWER4)
+ {
+ set_target_switch ("powerpc-gpopt");
+ set_target_switch ("powerpc64");
+ }
+ if (flag_fast || flag_fastcp)
+ /* This doesn't work with NAG Fortran output. The gcc 3.5 C++ libraries
+ have been adjusted so that it now works with them. */
+ set_target_switch ("align-natural");
+ if (flag_fastf)
+ /* This applies Fortran argument semantics; for NAG Fortran output only. */
+ flag_argument_noalias = 2;
+ /* IMI flags */
+ disable_typechecking_for_spec_flag = 1;
+ flag_unit_at_a_time = 1;
+ }
+ /* APPLE LOCAL end -fast */
+
+
if (TARGET_E500)
rs6000_isel = 1;
@@ -1070,6 +1159,10 @@ rs6000_parse_alignment_option (void)
{
if (rs6000_alignment_string == 0)
return;
+/* APPLE LOCAL begin Macintosh alignment 2002-2-26 ff */
+ else if (! strcmp (rs6000_alignment_string, "mac68k"))
+ rs6000_alignment_flags = MASK_ALIGN_MAC68K;
+/* APPLE LOCAL end Macintosh alignment 2002-2-26 ff */
else if (! strcmp (rs6000_alignment_string, "power"))
rs6000_alignment_flags = MASK_ALIGN_POWER;
else if (! strcmp (rs6000_alignment_string, "natural"))
@@ -1099,6 +1192,22 @@ rs6000_parse_tls_size_option (void)
void
optimization_options (int level ATTRIBUTE_UNUSED, int size ATTRIBUTE_UNUSED)
{
+ /* APPLE LOCAL begin tweak default optimizations */
+ if (DEFAULT_ABI == ABI_DARWIN)
+ {
+ /* Turn these on only if specifically requested, not with -O* */
+ /* Strict aliasing breaks too much existing code */
+ flag_strict_aliasing = 0;
+ /* Block reordering causes code bloat, and very little speedup */
+ flag_reorder_blocks = 0;
+ /* Multi-basic-block scheduling loses badly when the compiler
+ misguesses which blocks are going to be executed, more than
+ it gains when it guesses correctly. Its guesses for cases
+ where interblock scheduling occurs (if-then-else's) are
+ little better than random, so disable this unless requested. */
+ flag_schedule_interblock = 0;
+ }
+ /* APPLE LOCAL end tweak default optimizations */
}
/* Do anything needed at the start of the asm file. */
@@ -2271,6 +2380,11 @@ call_operand (rtx op, enum machine_mode mode)
return 0;
return (GET_CODE (op) == SYMBOL_REF
+ /* APPLE LOCAL begin accept hard R12 as target reg */
+#ifdef MAGIC_INDIRECT_CALL_REG
+ || (GET_CODE (op) == REG && REGNO (op) == MAGIC_INDIRECT_CALL_REG)
+#endif
+ /* APPLE LOCAL end accept hard R12 as target reg */
|| (GET_CODE (op) == REG
&& (REGNO (op) == LINK_REGISTER_REGNUM
|| REGNO (op) == COUNT_REGISTER_REGNUM
@@ -2356,7 +2470,7 @@ rs6000_special_round_type_align (tree type, int computed, int specified)
tree field = TYPE_FIELDS (type);
/* Skip all the static variables only if ABI is greater than
- 1 or equal to 0. */
+ 1 or equal to 0. */
while (field != NULL && TREE_CODE (field) == VAR_DECL)
field = TREE_CHAIN (field);
@@ -3050,9 +3164,12 @@ rs6000_tls_symbol_ref_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
The Darwin code is inside #if TARGET_MACHO because only then is
machopic_function_base_name() defined. */
rtx
-rs6000_legitimize_reload_address (rtx x, enum machine_mode mode,
+/* APPLE LOCAL pass reload addr by address */
+rs6000_legitimize_reload_address (rtx *addr_x, enum machine_mode mode,
int opnum, int type, int ind_levels ATTRIBUTE_UNUSED, int *win)
{
+ /* APPLE LOCAL pass reload addr by address */
+ rtx x = *addr_x;
/* We must recognize output that we have already generated ourselves. */
if (GET_CODE (x) == PLUS
&& GET_CODE (XEXP (x, 0)) == PLUS
@@ -3408,6 +3525,57 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2)
return dest;
}
+/* APPLE LOCAL begin RTX_COST for multiply */
+int
+rs6000_rtx_mult_cost (rtx x)
+{
+ switch (rs6000_cpu)
+ {
+ case PROCESSOR_RIOS1:
+ case PROCESSOR_PPC405:
+ return (GET_CODE (XEXP (x, 1)) != CONST_INT
+ ? COSTS_N_INSNS (5)
+ : INTVAL (XEXP (x, 1)) >= -256 && INTVAL (XEXP (x, 1)) <= 255
+ ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
+ case PROCESSOR_RS64A:
+ return (GET_CODE (XEXP (x, 1)) != CONST_INT
+ ? GET_MODE (XEXP (x, 1)) != DImode
+ ? COSTS_N_INSNS (20) : COSTS_N_INSNS (34)
+ : INTVAL (XEXP (x, 1)) >= -256 && INTVAL (XEXP (x, 1)) <= 255
+ ? COSTS_N_INSNS (8) : COSTS_N_INSNS (12));
+ case PROCESSOR_RIOS2:
+ case PROCESSOR_MPCCORE:
+ case PROCESSOR_PPC604e:
+ return COSTS_N_INSNS (2);
+ case PROCESSOR_PPC601:
+ return COSTS_N_INSNS (5);
+ case PROCESSOR_PPC603:
+ case PROCESSOR_PPC7400:
+ case PROCESSOR_PPC750:
+ return (GET_CODE (XEXP (x, 1)) != CONST_INT
+ ? COSTS_N_INSNS (5)
+ : INTVAL (XEXP (x, 1)) >= -256 && INTVAL (XEXP (x, 1)) <= 255
+ ? COSTS_N_INSNS (2) : COSTS_N_INSNS (3));
+ case PROCESSOR_PPC7450:
+ return (GET_CODE (XEXP (x, 1)) != CONST_INT
+ ? COSTS_N_INSNS (4)
+ : COSTS_N_INSNS (3));
+ case PROCESSOR_PPC403:
+ case PROCESSOR_PPC604:
+ return COSTS_N_INSNS (4);
+ case PROCESSOR_PPC620:
+ case PROCESSOR_PPC630:
+ return (GET_CODE (XEXP (x, 1)) != CONST_INT
+ ? GET_MODE (XEXP (x, 1)) != DImode
+ ? COSTS_N_INSNS (5) : COSTS_N_INSNS (7)
+ : INTVAL (XEXP (x, 1)) >= -256 && INTVAL (XEXP (x, 1)) <= 255
+ ? COSTS_N_INSNS (3) : COSTS_N_INSNS (4));
+ default:
+ abort ();
+ }
+}
+/* APPLE LOCAL end RTX_COST for multiply */
+
/* Emit a move from SOURCE to DEST in mode MODE. */
void
rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode)
@@ -3845,6 +4013,8 @@ init_cumulative_args (CUMULATIVE_ARGS *cum, tree fntype,
/* Check for a longcall attribute. */
if (fntype
+ /* APPLE LOCAL long-branch */
+ && TARGET_LONG_BRANCH
&& lookup_attribute ("longcall", TYPE_ATTRIBUTES (fntype))
&& !lookup_attribute ("shortcall", TYPE_ATTRIBUTES (fntype)))
cum->call_cookie = CALL_LONG;
@@ -3953,6 +4123,7 @@ function_arg_boundary (enum machine_mode mode, tree type ATTRIBUTE_UNUSED)
else
return PARM_BOUNDARY;
}
+
/* Update the data in CUM to advance over an argument
of mode MODE and data type TYPE.
@@ -4224,7 +4395,49 @@ rs6000_mixed_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
k == 0 ? const0_rtx : GEN_INT (k*4));
return gen_rtx_PARALLEL (BLKmode, gen_rtvec_v (k, rtlvec));
- }
+ }
+ else if (ALTIVEC_VECTOR_MODE(mode) && align_words <= (GP_ARG_NUM_REG - 1))
+ {
+ /* Varargs vector regs must be saved in R5-R8 or R9-R10. */
+ if (align_words == GP_ARG_NUM_REG - 2)
+ {
+ /* R9-R10 */
+ return gen_rtx_PARALLEL (mode,
+ gen_rtvec (3,
+ gen_rtx_EXPR_LIST (VOIDmode,
+ NULL_RTX, const0_rtx),
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (SImode,
+ GP_ARG_MIN_REG
+ + align_words),
+ const0_rtx),
+ gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (SImode,
+ GP_ARG_MIN_REG
+ + align_words+1),
+ GEN_INT(4))));
+ }
+ else
+ {
+ /* R5-R8 */
+ int k;
+ int size = int_size_in_bytes (type);
+ int no_units = ((size - 1) / 4) + 1;
+ int max_no_words = GP_ARG_NUM_REG - align_words;
+ int rtlvec_len = no_units < max_no_words ? no_units : max_no_words;
+ rtx *rtlvec = (rtx *) alloca (rtlvec_len * sizeof (rtx));
+ memset ((char *) rtlvec, 0, rtlvec_len * sizeof (rtx));
+
+ for (k=0; k < rtlvec_len; k++)
+ rtlvec[k] = gen_rtx_EXPR_LIST (VOIDmode,
+ gen_rtx_REG (SImode,
+ GP_ARG_MIN_REG
+ + align_words + k),
+ k == 0 ? const0_rtx : GEN_INT (k*4));
+
+ return gen_rtx_PARALLEL (mode, gen_rtvec_v (k, rtlvec));
+ }
+ }
return NULL_RTX;
}
@@ -4343,7 +4556,11 @@ function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
is either wholly in GPRs or half in GPRs and half not. */
part_mode = DImode;
- return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
+ if (TARGET_32BIT
+ && (TARGET_POWERPC64 || (align_words == GP_ARG_NUM_REG - 2)))
+ return rs6000_mixed_function_arg (cum, part_mode, type, align_words);
+ else
+ return gen_rtx_REG (part_mode, GP_ARG_MIN_REG + align_words);
}
}
else if (TARGET_SPE_ABI && TARGET_SPE && SPE_VECTOR_MODE (mode))
@@ -4619,6 +4836,33 @@ setup_incoming_varargs (CUMULATIVE_ARGS *cum, enum machine_mode mode,
}
}
+/* APPLE LOCAL begin Altivec */
+
+/* This routine determins if an extra pass over argument list is needed
+ for vector aruments. It returns true, if current argument need be
+ skipped. This depends on if we are in the first iteration (to skip
+ vectors), or 2nd iteration (to skip non-vectors).
+*/
+
+static
+bool skip_vec_args(tree arg_type, int pass, int *last_pass)
+{
+ if (DEFAULT_ABI != ABI_DARWIN)
+ return false;
+
+ if (TREE_CODE (arg_type) == VECTOR_TYPE)
+ {
+ *last_pass = 2;
+ if (pass == 1)
+ return true;
+ }
+ else if (pass == 2)
+ return true;
+ return false;
+}
+/* APPLE LOCAL end Altivec */
+
+
/* Create the va_list data type. */
static tree
@@ -5885,6 +6129,7 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
|| arg2 == error_mark_node)
return const0_rtx;
+ *expandedp = true;
STRIP_NOPS (arg2);
if (TREE_CODE (arg2) != INTEGER_CST
|| TREE_INT_CST_LOW (arg2) & ~0x3)
@@ -5902,7 +6147,6 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED,
if (pat != 0)
emit_insn (pat);
- *expandedp = true;
return NULL_RTX;
}
@@ -6456,6 +6700,18 @@ rs6000_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
static void
rs6000_init_builtins (void)
{
+ V2SI_type_node = build_vector_type (intSI_type_node, 2);
+ V2SF_type_node = build_vector_type (float_type_node, 2);
+ V4HI_type_node = build_vector_type (intHI_type_node, 4);
+ V4SI_type_node = build_vector_type (intSI_type_node, 4);
+ V4SF_type_node = build_vector_type (float_type_node, 4);
+ V8HI_type_node = build_vector_type (intHI_type_node, 8);
+ V16QI_type_node = build_vector_type (intQI_type_node, 16);
+
+ unsigned_V16QI_type_node = build_vector_type (unsigned_intQI_type_node, 16);
+ unsigned_V8HI_type_node = build_vector_type (unsigned_intHI_type_node, 8);
+ unsigned_V4SI_type_node = build_vector_type (unsigned_intSI_type_node, 4);
+
opaque_V2SI_type_node = copy_node (V2SI_type_node);
opaque_V2SF_type_node = copy_node (V2SF_type_node);
opaque_p_V2SI_type_node = build_pointer_type (opaque_V2SI_type_node);
@@ -6486,10 +6742,10 @@ rs6000_init_builtins (void)
get_identifier ("__pixel"),
pixel_type_node));
- bool_V16QI_type_node = make_vector (V16QImode, bool_char_type_node, 1);
- bool_V8HI_type_node = make_vector (V8HImode, bool_short_type_node, 1);
- bool_V4SI_type_node = make_vector (V4SImode, bool_int_type_node, 1);
- pixel_V8HI_type_node = make_vector (V8HImode, pixel_type_node, 1);
+ bool_V16QI_type_node = build_vector_type (bool_char_type_node, 16);
+ bool_V8HI_type_node = build_vector_type (bool_short_type_node, 8);
+ bool_V4SI_type_node = build_vector_type (bool_int_type_node, 4);
+ pixel_V8HI_type_node = build_vector_type (pixel_type_node, 8);
(*lang_hooks.decls.pushdecl) (build_decl (TYPE_DECL,
get_identifier ("__vector unsigned char"),
@@ -6534,6 +6790,12 @@ rs6000_init_builtins (void)
altivec_init_builtins ();
if (TARGET_ALTIVEC || TARGET_SPE)
rs6000_common_init_builtins ();
+
+ /* APPLE LOCAL begin constant cfstrings */
+#ifdef SUBTARGET_INIT_BUILTINS
+ SUBTARGET_INIT_BUILTINS;
+#endif
+ /* APPLE LOCAL end constant cfstrings */
}
/* Search through a set of builtins and enable the mask bits.
@@ -8648,7 +8910,11 @@ rs6000_got_register (rtx value ATTRIBUTE_UNUSED)
static struct machine_function *
rs6000_init_machine_status (void)
{
- return ggc_alloc_cleared (sizeof (machine_function));
+ /* APPLE LOCAL begin volatile pic base reg in leaves */
+ machine_function *mf = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
+ mf->substitute_pic_base_reg = -1;
+ return mf;
+ /* APPLE LOCAL end volatile pic base reg in leaves */
}
/* These macros test for integers and extract the low-order bits. */
@@ -9478,6 +9744,47 @@ print_operand_address (FILE *file, rtx x)
abort ();
}
+/* APPLE LOCAL begin weak import */
+static void
+find_weak_imports (rtx x)
+{
+ /* Patterns accepted here follow output_addr_const in final.c. */
+ switch ( GET_CODE (x))
+ {
+ case CONST:
+ case ZERO_EXTEND:
+ case SIGN_EXTEND:
+ case SUBREG:
+ find_weak_imports (XEXP (x, 0));
+ break;
+
+ case CONST_INT:
+ case CONST_DOUBLE:
+ case CODE_LABEL:
+ case LABEL_REF:
+ default:
+ break;
+
+ case PLUS:
+ case MINUS:
+ find_weak_imports (XEXP (x, 0));
+ find_weak_imports (XEXP (x, 1));
+ break;
+
+ case SYMBOL_REF:
+ if ( SYMBOL_REF_WEAK_IMPORT (x))
+ {
+ fprintf (asm_out_file, "\t.weak_reference ");
+ assemble_name (asm_out_file, XSTR (x, 0));
+ fprintf (asm_out_file, "\n");
+ /* Attempt to prevent multiple weak_reference directives. */
+ SYMBOL_REF_WEAK_IMPORT (x) = 0;
+ }
+ break;
+ }
+}
+/* APPLE LOCAL end weak import */
+
/* Target hook for assembling integer objects. The PowerPC version has
to handle fixup entries for relocatable code if RELOCATABLE_NEEDS_FIXUP
is defined. It also needs to handle DI-mode objects on 64-bit
@@ -9498,6 +9805,9 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
if (TARGET_RELOCATABLE
&& !in_toc_section ()
&& !in_text_section ()
+ /* APPLE LOCAL begin hot/cold partitioning */
+ && !in_text_unlikely_section ()
+ /* APPLE LOCAL end hot/cold partitioning */
&& !recurse
&& GET_CODE (x) != CONST_INT
&& GET_CODE (x) != CONST_DOUBLE
@@ -9536,6 +9846,9 @@ rs6000_assemble_integer (rtx x, unsigned int size, int aligned_p)
}
}
#endif /* RELOCATABLE_NEEDS_FIXUP */
+ /* APPLE LOCAL weak import */
+ if (DEFAULT_ABI == ABI_DARWIN)
+ find_weak_imports (x);
return default_assemble_integer (x, size, aligned_p);
}
@@ -10352,6 +10665,8 @@ first_reg_to_save (void)
#if TARGET_MACHO
if (flag_pic
&& current_function_uses_pic_offset_table
+ /* APPLE LOCAL volatile pic base reg in leaves */
+ && cfun->machine->substitute_pic_base_reg == -1
&& first_reg > RS6000_PIC_OFFSET_TABLE_REGNUM)
return RS6000_PIC_OFFSET_TABLE_REGNUM;
#endif
@@ -10540,7 +10855,7 @@ rs6000_stack_info (void)
{
static rs6000_stack_t info, zero_info;
rs6000_stack_t *info_ptr = &info;
- int reg_size = TARGET_POWERPC64 ? 8 : 4;
+ int reg_size = TARGET_32BIT ? 4 : 8;
int ehrd_size;
HOST_WIDE_INT total_raw_size;
@@ -10652,7 +10967,7 @@ rs6000_stack_info (void)
info_ptr->varargs_size = RS6000_VARARGS_AREA;
info_ptr->vars_size = RS6000_ALIGN (get_frame_size (), 8);
info_ptr->parm_size = RS6000_ALIGN (current_function_outgoing_args_size,
- 8);
+ TARGET_ALTIVEC ? 16 : 8);
if (TARGET_SPE_ABI && info_ptr->spe_64bit_regs_used != 0)
info_ptr->spe_gp_size = 8 * (32 - info_ptr->first_gp_reg_save);
@@ -10689,7 +11004,7 @@ rs6000_stack_info (void)
/* Align stack so vector save area is on a quadword boundary. */
if (info_ptr->altivec_size != 0)
info_ptr->altivec_padding_size
- = 16 - (-info_ptr->vrsave_save_offset % 16);
+ = (16 - (-info_ptr->vrsave_save_offset % 16)) % 16;
else
info_ptr->altivec_padding_size = 0;
@@ -10768,10 +11083,10 @@ rs6000_stack_info (void)
+ ehrd_size
+ info_ptr->cr_size
+ info_ptr->lr_size
- + info_ptr->vrsave_size
+ /* APPLE LOCAL fix redundant add? */
+ info_ptr->toc_size,
- (TARGET_ALTIVEC_ABI || ABI_DARWIN)
- ? 16 : 8);
+ /* APPLE LOCAL darwin native */
+ (TARGET_ALTIVEC_ABI ? 16 : 8));
total_raw_size = (info_ptr->vars_size
+ info_ptr->parm_size
@@ -11055,6 +11370,9 @@ static bool
rs6000_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
{
tree type;
+ /* APPLE LOCAL -mlong-branch */
+ if (TARGET_LONG_BRANCH)
+ return 0;
if (decl)
{
if (TARGET_ALTIVEC_VRSAVE)
@@ -11669,6 +11987,131 @@ generate_set_vrsave (rtx reg, rs6000_stack_t *info, int epiloguep)
return insn;
}
+/* APPLE LOCAL begin special ObjC method use of R12 */
+static int objc_method_using_pic = 0;
+
+/* Determine whether a name is an ObjC method. */
+static int name_encodes_objc_method_p (const char *piclabel_name)
+{
+ return (piclabel_name[0] == '*' && piclabel_name[1] == '"'
+ ? (piclabel_name[2] == 'L'
+ && (piclabel_name[3] == '+' || piclabel_name[3] == '-'))
+ : (piclabel_name[1] == 'L'
+ && (piclabel_name[2] == '+' || piclabel_name[2] == '-')));
+}
+/* APPLE LOCAL end special ObjC method use of R12 */
+
+/* APPLE LOCAL begin recompute PIC register use */
+/* Sometimes a function has references that require the PIC register,
+ but optimization removes them all. To catch this case
+ recompute current_function_uses_pic_offset_table here.
+ This may allow us to eliminate the prologue and epilogue. */
+
+static int
+recompute_PIC_register_use (void)
+{
+ if (DEFAULT_ABI == ABI_DARWIN
+ && flag_pic && current_function_uses_pic_offset_table
+ && !cfun->machine->ra_needs_full_frame)
+ {
+ rtx insn;
+ current_function_uses_pic_offset_table = 0;
+ push_topmost_sequence ();
+ for (insn = get_insns (); insn != NULL; insn = NEXT_INSN (insn))
+ if ( reg_mentioned_p (pic_offset_table_rtx, insn))
+ {
+ current_function_uses_pic_offset_table = 1;
+ break;
+ }
+ pop_topmost_sequence ();
+ }
+ return 0;
+}
+/* APPLE LOCAL end recompute PIC register use */
+
+/* APPLE LOCAL begin volatile pic base reg in leaves */
+/* If this is a leaf function and we used any pic-based references,
+ see if there is an unused volatile reg we can use instead of R31.
+ If so set substitute_pic_base_reg to this reg, set its reg_ever_used
+ bit (to avoid confusing later calls to alloc_volatile_reg), and
+ make a pass through the existing RTL, substituting the new reg for
+ the old one wherever it appears.
+ Logically this is a void function; it is int so it can be used to
+ initialize a dummy variable, thus getting executed ahead of other
+ initializations. Technicolour yawn. */
+
+/* ALLOC_VOLATILE_REG allocates a volatile register AFTER all gcc
+ register allocations have been done; we use it to reserve an
+ unused reg for holding VRsave. Returns -1 in case of failure (all
+ volatile regs are in use.) */
+/* Note, this is called from both the prologue and epilogue code,
+ with the assumption that it will return the same result both
+ times! Since the register arrays are not changed in between
+ this is valid, if a bit fragile. */
+/* In future we may also use this to grab an unused volatile reg to
+ hold the PIC base reg in the event that the current function makes
+ no procedure calls; this was done in 2.95. */
+static int
+alloc_volatile_reg (void)
+{
+ if (current_function_is_leaf
+ && reload_completed
+ && !cfun->machine->ra_needs_full_frame)
+ {
+ int r;
+ for (r = 10; r >= 2; --r)
+ if (! fixed_regs[r] && ! regs_ever_live[r])
+ return r;
+ }
+
+ return -1; /* fail */
+}
+
+static int
+try_leaf_pic_optimization (void)
+{
+ if ( DEFAULT_ABI==ABI_DARWIN
+ && flag_pic && current_function_uses_pic_offset_table
+ && current_function_is_leaf
+ && !cfun->machine->ra_needs_full_frame )
+ {
+ int reg = alloc_volatile_reg ();
+ if ( reg != -1 )
+ {
+ /* Run through the insns, changing references to the original
+ PIC_OFFSET_TABLE_REGNUM to our new one. */
+ rtx insn;
+ const int nregs = PIC_OFFSET_TABLE_REGNUM + 1;
+ rtx *reg_map = (rtx *) xmalloc (nregs * sizeof (rtx));
+ memset (reg_map, 0, nregs * sizeof (rtx));
+ reg_map[PIC_OFFSET_TABLE_REGNUM] = gen_rtx_REG (SImode, reg);
+
+ push_topmost_sequence ();
+ for (insn = get_insns (); insn != NULL; insn = NEXT_INSN (insn))
+ {
+ if (GET_CODE (insn) == INSN || GET_CODE (insn) == JUMP_INSN)
+ {
+ replace_regs (PATTERN (insn), reg_map, nregs, 1);
+ replace_regs (REG_NOTES (insn), reg_map, nregs, 1);
+ }
+ else if (GET_CODE (insn) == CALL_INSN)
+ {
+ if ( !SIBLING_CALL_P (insn))
+ abort ();
+ }
+ }
+ pop_topmost_sequence ();
+ free (reg_map);
+
+ regs_ever_live[reg] = 1;
+ regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 0;
+ cfun->machine->substitute_pic_base_reg = reg;
+ }
+ }
+ return 0;
+}
+/* APPLE LOCAL end volatile pic base reg in leaves */
+
/* Save a register into the frame, and emit RTX_FRAME_RELATED_P notes.
Save REGNO into [FRAME_REG + OFFSET] in mode MODE. */
@@ -11738,9 +12181,13 @@ gen_frame_mem_offset (enum machine_mode mode, rtx reg, int offset)
void
rs6000_emit_prologue (void)
{
+ /* APPLE LOCAL recompute PIC register use */
+ int dummy ATTRIBUTE_UNUSED = recompute_PIC_register_use ();
+ /* APPLE LOCAL volatile pic base reg in leaves */
+ int ignored ATTRIBUTE_UNUSED = try_leaf_pic_optimization ();
rs6000_stack_t *info = rs6000_stack_info ();
enum machine_mode reg_mode = Pmode;
- int reg_size = UNITS_PER_WORD;
+ int reg_size = TARGET_32BIT ? 4 : 8;
rtx sp_reg_rtx = gen_rtx_REG (Pmode, STACK_POINTER_REGNUM);
rtx frame_ptr_rtx = gen_rtx_REG (Pmode, 12);
rtx frame_reg_rtx = sp_reg_rtx;
@@ -11749,7 +12196,24 @@ rs6000_emit_prologue (void)
int saving_FPRs_inline;
int using_store_multiple;
HOST_WIDE_INT sp_offset = 0;
+ /* APPLE LOCAL: callers_lr_already_saved */
+ int callers_lr_already_saved = 0;
+#if TARGET_MACHO
+ int lr_already_set_up_for_pic = 0;
+#endif
+ /* APPLE LOCAL special ObjC method use of R12 */
+ objc_method_using_pic = 0;
+ /* APPLE LOCAL BEGIN fix-and-continue mrs */
+ if (TARGET_FIX_AND_CONTINUE)
+ {
+ emit_insn (gen_nop ());
+ emit_insn (gen_nop ());
+ emit_insn (gen_nop ());
+ emit_insn (gen_nop ());
+ }
+ /* APPLE LOCAL END fix-and-continue mrs */
+
if (TARGET_SPE_ABI && info->spe_64bit_regs_used != 0)
{
reg_mode = V2SImode;
@@ -11785,6 +12249,31 @@ rs6000_emit_prologue (void)
rs6000_emit_stack_tie ();
}
+ /* APPLE LOCAL begin special ObjC method use of R12 */
+#if TARGET_MACHO
+ if (DEFAULT_ABI == ABI_DARWIN
+ && current_function_uses_pic_offset_table && flag_pic)
+ {
+ const char *piclabel_name = machopic_function_base_name ();
+
+ if (name_encodes_objc_method_p (piclabel_name)
+ /* If we're saving vector or FP regs via a function call,
+ then don't bother with this ObjC R12 optimization.
+ This test also eliminates world_save. */
+ && (info->first_altivec_reg_save > LAST_ALTIVEC_REGNO
+ || VECTOR_SAVE_INLINE (info->first_altivec_reg_save))
+ && (info->first_fp_reg_save == 64
+ || FP_SAVE_INLINE (info->first_fp_reg_save)))
+ {
+ /* We cannot output the label now; there seems to be no
+ way to prevent cfgcleanup from deleting it. It is done
+ in rs6000_output_function_prologue with fprintf! */
+ objc_method_using_pic = 1;
+ }
+ }
+#endif /* TARGET_MACHO */
+ /* APPLE LOCAL end special ObjC method use of R12 */
+
/* Save AltiVec registers if needed. */
if (TARGET_ALTIVEC_ABI && info->altivec_size != 0)
{
@@ -11862,7 +12351,12 @@ rs6000_emit_prologue (void)
/* If we need to save CR, put it into r12. */
if (info->cr_save_p && frame_reg_rtx != frame_ptr_rtx)
{
- cr_save_rtx = gen_rtx_REG (SImode, 12);
+ /* APPLE LOCAL begin special ObjC method use of R12 */
+ /* For Darwin, use R2, so we don't clobber the special ObjC
+ method use of R12. R11 has a special meaning for Ada, so we
+ can't use that. */
+ cr_save_rtx = gen_rtx_REG (SImode, DEFAULT_ABI == ABI_DARWIN ? 2 : 12);
+ /* APPLE LOCAL end special ObjC method use of R12 */
emit_insn (gen_movesi_from_cr (cr_save_rtx));
}
@@ -11885,17 +12379,57 @@ rs6000_emit_prologue (void)
char rname[30];
const char *alloc_rname;
rtvec p;
- p = rtvec_alloc (2 + 64 - info->first_fp_reg_save);
+
+ /* APPLE LOCAL begin Reduce code size / improve performance */
+ int gen_following_label = 0;
+ int count = 0;
+
+ if (current_function_uses_pic_offset_table && flag_pic
+#ifdef INSN_SCHEDULING
+ /* Prevent the compiler from crashing
+ while scheduling insns after global_alloc! */
+ && (optimize == 0 || !flag_schedule_insns_after_reload)
+#endif
+ /* If this is the last CALL in the prolog, then we've got our PC.
+ If we're saving AltiVec regs via a function, we're not last. */
+ && (info->first_altivec_reg_save > LAST_ALTIVEC_REGNO
+ || VECTOR_SAVE_INLINE (info->first_altivec_reg_save)))
+ gen_following_label = lr_already_set_up_for_pic = 1;
+
+ /* APPLE LOCAL: +2 (could be conditionalized) */
+ p = rtvec_alloc (2 + 64 - info->first_fp_reg_save + 2
+ + gen_following_label);
- RTVEC_ELT (p, 0) = gen_rtx_CLOBBER (VOIDmode,
+ RTVEC_ELT (p, count++) = gen_rtx_CLOBBER (VOIDmode,
gen_rtx_REG (Pmode,
LINK_REGISTER_REGNUM));
+ /* APPLE LOCAL begin reduce code size */
+#if TARGET_MACHO
+ /* We have to calculate the offset into saveFP to where we must
+ call (!!) SAVEFP also saves the caller's LR -- placed into
+ R0 above -- into 8(R1). SAVEFP/RESTOREFP should never be
+ called to save or restore only F31. */
+
+ if (info->lr_save_offset != 8 || info->first_fp_reg_save == 63)
+ abort ();
+
+ sprintf (rname, "*saveFP%s%.0d ; save f%d-f31",
+ (info->first_fp_reg_save - 32 == 14 ? "" : "+"),
+ (info->first_fp_reg_save - 46) * 4,
+ info->first_fp_reg_save - 32);
+#else
+ /* APPLE LOCAL end reduce code size */
sprintf (rname, "%s%d%s", SAVE_FP_PREFIX,
info->first_fp_reg_save - 32, SAVE_FP_SUFFIX);
+ /* APPLE LOCAL reduce code size */
+#endif /* TARGET_MACHO */
alloc_rname = ggc_strdup (rname);
- RTVEC_ELT (p, 1) = gen_rtx_USE (VOIDmode,
+ RTVEC_ELT (p, count++) = gen_rtx_USE (VOIDmode,
gen_rtx_SYMBOL_REF (Pmode,
alloc_rname));
+ /* APPLE LOCAL reduce code size */
+ if ( gen_following_label )
+ RTVEC_ELT (p, count++) = gen_rtx_USE (VOIDmode, const0_rtx);
for (i = 0; i < 64 - info->first_fp_reg_save; i++)
{
rtx addr, reg, mem;
@@ -11906,11 +12440,31 @@ rs6000_emit_prologue (void)
mem = gen_rtx_MEM (DFmode, addr);
set_mem_alias_set (mem, rs6000_sr_alias_set);
- RTVEC_ELT (p, i + 2) = gen_rtx_SET (VOIDmode, mem, reg);
+ RTVEC_ELT (p, count++) = gen_rtx_SET (VOIDmode, mem, reg);
+ }
+ /* APPLE LOCAL begin fix 2866661 */
+#if TARGET_MACHO
+ /* Darwin version of these functions stores R0. */
+ RTVEC_ELT (p, count++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 0));
+
+ /* If we saved LR, *tell* people about it! */
+ if (info->lr_save_p)
+ {
+ rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
+ GEN_INT (info->lr_save_offset + sp_offset));
+ rtx mem = gen_rtx_MEM (Pmode, addr);
+ /* This should not be of rs6000_sr_alias_set, because of
+ __builtin_return_address. */
+ RTVEC_ELT (p, count++) = gen_rtx_SET (Pmode, mem,
+ gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM));
}
+#endif
+ /* APPLE LOCAL end fix 2866661 */
insn = emit_insn (gen_rtx_PARALLEL (VOIDmode, p));
rs6000_frame_related (insn, frame_ptr_rtx, info->total_size,
NULL_RTX, NULL_RTX);
+ /* APPLE LOCAL: callers_lr_already_saved */
+ callers_lr_already_saved = 1;
}
/* Save GPRs. This is done as a PARALLEL if we are using
@@ -11945,7 +12499,11 @@ rs6000_emit_prologue (void)
&& ! call_used_regs[info->first_gp_reg_save+i])
|| (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
- || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
+ /* APPLE LOCAL begin volatile pic base reg in leaves */
+ || (DEFAULT_ABI == ABI_DARWIN && flag_pic
+ && current_function_uses_pic_offset_table
+ && cfun->machine->substitute_pic_base_reg == -1))))
+ /* APPLE LOCAL end volatile pic base reg in leaves */
{
rtx addr, reg, mem;
reg = gen_rtx_REG (reg_mode, info->first_gp_reg_save + i);
@@ -12027,8 +12585,18 @@ rs6000_emit_prologue (void)
}
}
+ /* APPLE LOCAL special ObjC method use of R12 */
+ if (objc_method_using_pic)
+ rs6000_maybe_dead (
+ emit_move_insn (gen_rtx_REG (Pmode,
+ cfun->machine->substitute_pic_base_reg == -1
+ ? PIC_OFFSET_TABLE_REGNUM
+ : cfun->machine->substitute_pic_base_reg),
+ gen_rtx_REG (Pmode, 12)));
+
/* Save lr if we used it. */
- if (info->lr_save_p)
+ /* APPLE LOCAL: callers_lr_already_saved */
+ if (info->lr_save_p && !callers_lr_already_saved)
{
rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
GEN_INT (info->lr_save_offset + sp_offset));
@@ -12111,17 +12679,38 @@ rs6000_emit_prologue (void)
#if TARGET_MACHO
if (DEFAULT_ABI == ABI_DARWIN
+ /* APPLE LOCAL special ObjC method use of R12 */
+ && !objc_method_using_pic
&& flag_pic && current_function_uses_pic_offset_table)
{
rtx dest = gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM);
const char *picbase = machopic_function_base_name ();
rtx src = gen_rtx_SYMBOL_REF (Pmode, picbase);
- rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
+ /* APPLE LOCAL begin save and restore LR */
+ /* Save and restore LR locally around this call (in R0). */
+ if (!info->lr_save_p)
+ rs6000_maybe_dead (emit_move_insn (gen_rtx_REG (Pmode, 0), dest));
+ /* APPLE LOCAL end save and restore LR */
+ /* APPLE LOCAL begin performance enhancement */
+#if TARGET_MACHO
+ if (!lr_already_set_up_for_pic)
+ rs6000_maybe_dead (emit_insn (gen_load_macho_picbase (dest, src)));
+#endif
+ /* APPLE LOCAL end performance enhancement */
+
+ /* APPLE LOCAL begin volatile pic base reg in leaves */
rs6000_maybe_dead (
- emit_move_insn (gen_rtx_REG (Pmode, RS6000_PIC_OFFSET_TABLE_REGNUM),
- gen_rtx_REG (Pmode, LINK_REGISTER_REGNUM)));
+ emit_move_insn (
+ gen_rtx_REG (Pmode,
+ cfun->machine->substitute_pic_base_reg == -1
+ ? RS6000_PIC_OFFSET_TABLE_REGNUM
+ : cfun->machine->substitute_pic_base_reg),
+ dest));
+ if (!info->lr_save_p)
+ rs6000_maybe_dead (emit_move_insn (dest, gen_rtx_REG (Pmode, 0)));
+ /* APPLE LOCAL end */
}
#endif
}
@@ -12137,6 +12726,8 @@ rs6000_output_function_prologue (FILE *file,
if (TARGET_DEBUG_STACK)
debug_stack_info (info);
+ /* APPLE LOCAL do not extern fp save/restore */
+#if !TARGET_MACHO
/* Write .extern for any function we will call to save and restore
fp values. */
if (info->first_fp_reg_save < 64
@@ -12145,6 +12736,8 @@ rs6000_output_function_prologue (FILE *file,
SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX,
RESTORE_FP_PREFIX, info->first_fp_reg_save - 32,
RESTORE_FP_SUFFIX);
+ /* APPLE LOCAL do not extern fp save/restore */
+#endif /* !TARGET_MACHO */
/* Write .extern for AIX common mode routines, if needed. */
if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined)
@@ -12158,6 +12751,16 @@ rs6000_output_function_prologue (FILE *file,
common_mode_defined = 1;
}
+ /* APPLE LOCAL special ObjC method use of R12 */
+#if TARGET_MACHO
+ if ( HAVE_prologue && DEFAULT_ABI == ABI_DARWIN && objc_method_using_pic )
+ {
+ /* APPLE FIXME isn't there an asm macro to do all this? */
+ const char* piclabel = machopic_function_base_name ();
+ fprintf(file, "%s:\n", (*piclabel == '*') ? piclabel + 1 : piclabel);
+ }
+#endif
+
if (! HAVE_prologue)
{
start_sequence ();
@@ -12207,7 +12810,7 @@ rs6000_emit_epilogue (int sibcall)
rtx sp_reg_rtx = gen_rtx_REG (Pmode, 1);
rtx frame_reg_rtx = sp_reg_rtx;
enum machine_mode reg_mode = Pmode;
- int reg_size = UNITS_PER_WORD;
+ int reg_size = TARGET_32BIT ? 4 : 8;
int i;
info = rs6000_stack_info ();
@@ -12232,6 +12835,8 @@ rs6000_emit_epilogue (int sibcall)
using_mfcr_multiple = (rs6000_cpu == PROCESSOR_PPC601
|| rs6000_cpu == PROCESSOR_PPC603
|| rs6000_cpu == PROCESSOR_PPC750
+ /* APPLE LOCAL ? */
+ || rs6000_cpu == PROCESSOR_PPC7400
|| optimize_size);
/* If we have a frame pointer, a call to alloca, or a large stack
@@ -12324,7 +12929,9 @@ rs6000_emit_epilogue (int sibcall)
set_mem_alias_set (mem, rs6000_sr_alias_set);
- emit_move_insn (gen_rtx_REG (SImode, 12), mem);
+ /* APPLE LOCAL use R11 because of ObjC use of R12 in sibcall to CTR */
+ emit_move_insn (gen_rtx_REG (SImode,
+ DEFAULT_ABI == ABI_DARWIN ? 11 : 12), mem);
}
/* Set LR here to try to overlap restores below. */
@@ -12394,7 +13001,11 @@ rs6000_emit_epilogue (int sibcall)
&& ! call_used_regs[info->first_gp_reg_save+i])
|| (i+info->first_gp_reg_save == RS6000_PIC_OFFSET_TABLE_REGNUM
&& ((DEFAULT_ABI == ABI_V4 && flag_pic != 0)
- || (DEFAULT_ABI == ABI_DARWIN && flag_pic))))
+ /* APPLE LOCAL begin darwin native */
+ || (DEFAULT_ABI == ABI_DARWIN && flag_pic
+ && current_function_uses_pic_offset_table
+ && cfun->machine->substitute_pic_base_reg == -1))))
+ /* APPLE LOCAL end darwin native */
{
rtx addr = gen_rtx_PLUS (Pmode, frame_reg_rtx,
GEN_INT (info->gp_save_offset
@@ -12448,7 +13059,9 @@ rs6000_emit_epilogue (int sibcall)
/* If we saved cr, restore it here. Just those that were used. */
if (info->cr_save_p)
{
- rtx r12_rtx = gen_rtx_REG (SImode, 12);
+ /* APPLE LOCAL use R11 because of ObjC use of R12 in sibcall to CTR */
+ /* APPLE LOCAL silly name retained to minimize deviation from FSF */
+ rtx r12_rtx = gen_rtx_REG (SImode, DEFAULT_ABI == ABI_DARWIN ? 11 : 12);
int count = 0;
if (using_mfcr_multiple)
@@ -12548,8 +13161,25 @@ rs6000_emit_epilogue (int sibcall)
char rname[30];
const char *alloc_rname;
+ /* APPLE LOCAL begin code size reduction / performance enhancement */
+#if TARGET_MACHO
+ /* We have to calculate the offset into RESTFP to where we must
+ call (!!) RESTFP also restores the caller's LR from 8(R1).
+ RESTFP should *never* be called to restore only F31. */
+
+ if (info->lr_save_offset != 8 || info->first_fp_reg_save == 63)
+ abort ();
+
+ sprintf (rname, "*restFP%s%.0d ; restore f%d-f31",
+ (info->first_fp_reg_save - 32 == 14 ? "" : "+"),
+ (info->first_fp_reg_save - 46) * 4,
+ info->first_fp_reg_save - 32);
+#else
+ /* APPLE LOCAL end code size reduction / performance enhancement */
sprintf (rname, "%s%d%s", RESTORE_FP_PREFIX,
info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX);
+ /* APPLE LOCAL code size reduction / performance enhancement */
+#endif /* TARGET_MACHO */
alloc_rname = ggc_strdup (rname);
RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode,
gen_rtx_SYMBOL_REF (Pmode,
@@ -14663,6 +15293,11 @@ rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt)
const struct attribute_spec rs6000_attribute_table[] =
{
/* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler } */
+ /* APPLE LOCAL begin double destructor */
+#ifdef SUBTARGET_ATTRIBUTE_TABLE
+ SUBTARGET_ATTRIBUTE_TABLE
+#endif
+ /* APPLE LOCAL end double destructor */
{ "altivec", 1, 1, false, true, false, rs6000_handle_altivec_attribute },
{ "longcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
{ "shortcall", 0, 0, false, true, true, rs6000_handle_longcall_attribute },
@@ -14756,6 +15391,21 @@ rs6000_handle_altivec_attribute (tree *node, tree name, tree args,
return NULL_TREE;
}
+/* AltiVec defines four built-in scalar types that serve as vector
+ elements; we must teach the compiler how to mangle them. */
+
+static const char *
+rs6000_mangle_fundamental_type (tree type)
+{
+ if (type == bool_char_type_node) return "U6__boolc";
+ if (type == bool_short_type_node) return "U6__bools";
+ if (type == pixel_type_node) return "u7__pixel";
+ if (type == bool_int_type_node) return "U6__booli";
+
+ /* For all other types, use normal C++ mangling. */
+ return NULL;
+}
+
/* Handle a "longcall" or "shortcall" attribute; arguments as in
struct attribute_spec.handler. */
@@ -14998,6 +15648,7 @@ symbolic_operand (rtx op)
#if TARGET_MACHO
static tree branch_island_list = 0;
+static int local_label_unique_number = 0;
/* Remember to generate a branch island for far calls to the given
function. */
@@ -15027,17 +15678,20 @@ macho_branch_islands (void)
{
char tmp_buf[512];
tree branch_island;
+ const char *name;
+ const char *label;
+ char name_buf[512];
+ char *local_label_0;
+ const char *non_lazy_pointer_name, *unencoded_non_lazy_pointer_name;
+ int length;
for (branch_island = branch_island_list;
branch_island;
branch_island = TREE_CHAIN (branch_island))
{
- const char *label =
- IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
- const char *name =
- darwin_strip_name_encoding (
- IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island)));
- char name_buf[512];
+ label = IDENTIFIER_POINTER (BRANCH_ISLAND_LABEL_NAME (branch_island));
+ name = darwin_strip_name_encoding (
+ IDENTIFIER_POINTER (BRANCH_ISLAND_FUNCTION_NAME (branch_island)));
/* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF(). */
if (name[0] == '*' || name[0] == '&')
strcpy (name_buf, name+1);
@@ -15053,15 +15707,66 @@ macho_branch_islands (void)
fprintf (asm_out_file, "\t.stabd 68,0," HOST_WIDE_INT_PRINT_UNSIGNED "\n",
BRANCH_ISLAND_LINE_NUMBER(branch_island));
#endif /* DBX_DEBUGGING_INFO || XCOFF_DEBUGGING_INFO */
- if (flag_pic)
+ /* If PIC and the callee has no stub, do an indirect call through a
+ non-lazy-pointer. 'save_world' expects a parameter in R11;
+ theh dyld_stub_binding_helper (part of the Mach-O stub
+ interface) expects a different parameter in R11. This is
+ effectively a "non-lazy stub." By-the-way, a
+ "non-lazy-pointer" is a .long that gets coalesced with others
+ of the same value, so one NLP suffices for an entire
+ application. */
+ if (flag_pic && (machopic_classify_ident (get_identifier (name)) == MACHOPIC_UNDEFINED))
+ {
+ /* This is the address of the non-lazy pointer; load from it
+ to get the address we want. */
+ non_lazy_pointer_name = machopic_non_lazy_ptr_name (name);
+ machopic_validate_stub_or_non_lazy_ptr (non_lazy_pointer_name,
+ /* non-lazy-pointer */0);
+ unencoded_non_lazy_pointer_name =
+ (*targetm.strip_name_encoding) (non_lazy_pointer_name);
+ length = strlen (name);
+ local_label_0 = alloca (length + 32);
+ /* Cheap copy of the details from the Darwin ASM_OUTPUT_LABELREF(). */
+ if (name[0] == '*' || name[0] == '&')
+ strcpy (name_buf, name+1);
+ else
+ {
+ name_buf[0] = '_';
+ strcpy (name_buf+1, name);
+ }
+
+ sprintf (local_label_0, "%s_%d_pic", name_buf, local_label_unique_number);
+ local_label_unique_number++;
+ strcpy (tmp_buf, "\n");
+ strcat (tmp_buf, label);
+ strcat (tmp_buf, "\tmflr r0\n");
+ strcat (tmp_buf, "\tbcl 20,31,");
+ strcat (tmp_buf, "\tbcl 20,31,%s\n");
+ strcat (tmp_buf, local_label_0);
+ strcat (tmp_buf, ":\n");
+ strcat (tmp_buf, "\tmflr r12\n");
+ strcat (tmp_buf, "\taddis r12,r12,ha16(");
+ strcat (tmp_buf, non_lazy_pointer_name);
+ strcat (tmp_buf, "-");
+ strcat (tmp_buf, local_label_0);
+ strcat (tmp_buf, ")\n\tlwz r12,lo16(");
+ strcat (tmp_buf, non_lazy_pointer_name);
+ strcat (tmp_buf, "-");
+ strcat (tmp_buf, local_label_0);
+ strcat (tmp_buf, ")(r12)\n");
+ strcat (tmp_buf, "\tmtlr r0\n");
+ strcat (tmp_buf, "\tmtctr r12\n");
+ strcat (tmp_buf, "\tbctr\n");
+ }
+ else if (flag_pic)
{
strcat (tmp_buf, ":\n\tmflr r0\n\tbcl 20,31,");
strcat (tmp_buf, label);
strcat (tmp_buf, "_pic\n");
strcat (tmp_buf, label);
- strcat (tmp_buf, "_pic:\n\tmflr r11\n");
+ strcat (tmp_buf, "_pic:\n\tmflr r12\n");
- strcat (tmp_buf, "\taddis r11,r11,ha16(");
+ strcat (tmp_buf, "\taddis r12,r12,ha16(");
strcat (tmp_buf, name_buf);
strcat (tmp_buf, " - ");
strcat (tmp_buf, label);
@@ -15069,7 +15774,7 @@ macho_branch_islands (void)
strcat (tmp_buf, "\tmtlr r0\n");
- strcat (tmp_buf, "\taddi r12,r11,lo16(");
+ strcat (tmp_buf, "\taddi r12,r12,lo16(");
strcat (tmp_buf, name_buf);
strcat (tmp_buf, " - ");
strcat (tmp_buf, label);
@@ -15135,12 +15840,55 @@ char *
output_call (rtx insn, rtx *operands, int dest_operand_number, int cookie_operand_number)
{
static char buf[256];
+ const char *far_call_instr_str=NULL, *near_call_instr_str=NULL;
+ rtx pattern;
+
+ switch (GET_CODE (insn))
+ {
+ case CALL_INSN:
+ far_call_instr_str = "jbsr";
+ near_call_instr_str = "bl";
+ pattern = NULL_RTX;
+ break;
+ case JUMP_INSN:
+ far_call_instr_str = "jmp";
+ near_call_instr_str = "b";
+ pattern = NULL_RTX;
+ break;
+ case INSN:
+ pattern = PATTERN (insn);
+ break;
+ default:
+ abort();
+ break;
+ }
+
if (GET_CODE (operands[dest_operand_number]) == SYMBOL_REF
&& (INTVAL (operands[cookie_operand_number]) & CALL_LONG))
{
tree labelname;
tree funname = get_identifier (XSTR (operands[dest_operand_number], 0));
+ /* This insn represents a prologue or epilogue. */
+ if ((pattern != NULL_RTX) && GET_CODE (pattern) == PARALLEL)
+ {
+ rtx parallel_first_op = XVECEXP (pattern, 0, 0);
+ switch (GET_CODE (parallel_first_op))
+ {
+ case CLOBBER: /* Prologue: a call to save_world. */
+ far_call_instr_str = "jbsr";
+ near_call_instr_str = "bl";
+ break;
+ case RETURN: /* Epilogue: a call to rest_world. */
+ far_call_instr_str = "jmp";
+ near_call_instr_str = "b";
+ break;
+ default:
+ abort();
+ break;
+ }
+ }
+
if (no_previous_def (funname))
{
int line_number = 0;
@@ -15303,6 +16051,129 @@ toc_section (void)
#endif /* TARGET_MACHO */
+/* APPLE LOCAL begin Macintosh alignment 2002-1-22 ff */
+/* Return the alignment of a struct based on the Macintosh PowerPC
+ alignment rules. In general the alignment of a struct is
+ determined by the greatest alignment of its elements. However, the
+ PowerPC rules cause the alignment of a struct to peg at word
+ alignment except when the first field has greater than word
+ (32-bit) alignment, in which case the alignment is determined by
+ the alignment of the first field. */
+
+unsigned
+round_type_align (tree the_struct, unsigned computed, unsigned specified)
+{
+ if (TARGET_ALTIVEC && TREE_CODE (the_struct) == VECTOR_TYPE)
+ {
+ /* All vectors are (at least) 16-byte aligned. A struct or
+ union with a vector element is also 16-byte aligned. */
+ return MAX (RS6000_VECTOR_ALIGNMENT, MAX (computed, specified));
+ }
+
+ if (TREE_CODE (the_struct) == RECORD_TYPE
+ || TREE_CODE (the_struct) == UNION_TYPE
+ || TREE_CODE (the_struct) == QUAL_UNION_TYPE)
+ {
+ tree first_field = TYPE_FIELDS (the_struct);
+
+ /* Skip past static fields, enums, and constant fields that are
+ not really a part of the record layout. */
+ while ((first_field != 0)
+ && (TREE_CODE (first_field) != FIELD_DECL))
+ first_field = TREE_CHAIN (first_field);
+
+ if (first_field != 0)
+ {
+ /* If other-than-default alignment (which includes mac68k
+ mode) is in effect, then no adjustments to the alignment
+ should be necessary. Ditto if the struct has the
+ __packed__ attribute. */
+ if (TYPE_PACKED (the_struct) || TARGET_ALIGN_MAC68K
+ || TARGET_ALIGN_NATURAL || maximum_field_alignment != 0)
+ /* Do nothing */ ;
+ else
+ {
+ /* The following code handles Macintosh PowerPC
+ alignment. The implementation is complicated by the
+ fact that BIGGEST_ALIGNMENT is 128 when AltiVec is
+ enabled and 32 when it is not. So when AltiVec is
+ not enabled, alignment is generally limited to word
+ alignment. Consequently, the alignment of unions has
+ to be recalculated if AltiVec is not enabled.
+
+ Below we explicitly test for fields with greater than
+ word alignment: doubles, long longs, and structs and
+ arrays with greater than word alignment. */
+ unsigned val;
+ tree field_type;
+
+ val = MAX (computed, specified);
+
+ if (TREE_CODE (the_struct) == UNION_TYPE && !TARGET_ALTIVEC)
+ {
+ tree field = first_field;
+
+ while (field != 0)
+ {
+ /* Don't consider statics, enums and constant fields
+ which are not really a part of the record. */
+ if (TREE_CODE (field) != FIELD_DECL)
+ {
+ field = TREE_CHAIN (field);
+ continue;
+ }
+ field_type = TREE_TYPE(field);
+ if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE)
+ field_type = get_inner_array_type (field);
+ else
+ field_type = TREE_TYPE (field);
+ val = MAX (TYPE_ALIGN (field_type), val);
+ if (FLOAT_TYPE_P (field_type)
+ && TYPE_MODE (field_type) == DFmode)
+ val = MAX (RS6000_DOUBLE_ALIGNMENT, val);
+ else if (INTEGRAL_TYPE_P (field_type)
+ && TYPE_MODE (field_type) == DImode)
+ val = MAX (RS6000_LONGLONG_ALIGNMENT, val);
+ field = TREE_CHAIN (field);
+ }
+ }
+ else
+ {
+ if (TREE_CODE (TREE_TYPE (first_field)) == ARRAY_TYPE)
+ field_type = get_inner_array_type (first_field);
+ else
+ field_type = TREE_TYPE (first_field);
+
+ if (field_type == error_mark_node)
+ return val;
+ val = MAX (TYPE_ALIGN (field_type), val);
+
+ if (FLOAT_TYPE_P (field_type)
+ && TYPE_MODE (field_type) == DFmode)
+ val = MAX (RS6000_DOUBLE_ALIGNMENT, val);
+ else if (INTEGRAL_TYPE_P (field_type)
+ && TYPE_MODE (field_type) == DImode)
+ val = MAX (RS6000_LONGLONG_ALIGNMENT, val);
+ }
+
+ return val;
+ }
+ } /* first_field != 0 */
+
+ /* Ensure all MAC68K structs are at least 16-bit aligned.
+ Unless the struct has __attribute__ ((packed)). */
+
+ if (TARGET_ALIGN_MAC68K && ! TYPE_PACKED (the_struct))
+ {
+ if (computed < 16)
+ computed = 16;
+ }
+ } /* RECORD_TYPE, etc */
+
+ return (MAX (computed, specified));
+}
+/* APPLE LOCAL end Macintosh alignment 2002-1-22 ff */
+
#if TARGET_ELF
static unsigned int
rs6000_elf_section_type_flags (tree decl, const char *name, int reloc)