diff options
Diffstat (limited to 'gcc/config/rs6000/rs6000.c')
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 965 |
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) |