X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;ds=sidebyside;f=gcc%2Fconfig%2Frs6000%2Frs6000.c;h=d1616e523fb8db3b679af6416e533343ed17fc12;hb=47b19b941e0899b3ec4df9868184297c43ed25c2;hp=932a7e31d84372022866bb17e55509b876b0a01f;hpb=c6b19c5f7e30d3fe356989902a35bee01b8ea001;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 932a7e31d84..d1616e523fb 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1,6 +1,6 @@ /* Subroutines used for code generation on IBM RS/6000. Copyright (C) 1991, 1993, 1994, 1995, 1996, 1997, 1998, 1999, - 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 + 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc. Contributed by Richard Kenner (kenner@vlsi1.ultra.nyu.edu) @@ -511,6 +511,25 @@ struct processor_costs ppc440_cost = { 1, /* streams */ }; +/* Instruction costs on PPC476 processors. */ +static const +struct processor_costs ppc476_cost = { + COSTS_N_INSNS (4), /* mulsi */ + COSTS_N_INSNS (4), /* mulsi_const */ + COSTS_N_INSNS (4), /* mulsi_const9 */ + COSTS_N_INSNS (4), /* muldi */ + COSTS_N_INSNS (11), /* divsi */ + COSTS_N_INSNS (11), /* divdi */ + COSTS_N_INSNS (6), /* fp */ + COSTS_N_INSNS (6), /* dmul */ + COSTS_N_INSNS (19), /* sdiv */ + COSTS_N_INSNS (33), /* ddiv */ + 32, /* l1 cache line size */ + 32, /* l1 cache */ + 512, /* l2 cache */ + 1, /* streams */ +}; + /* Instruction costs on PPC601 processors. */ static const struct processor_costs ppc601_cost = { @@ -740,6 +759,25 @@ struct processor_costs ppce500mc_cost = { 1, /* prefetch streams /*/ }; +/* Instruction costs on PPCE500MC64 processors. */ +static const +struct processor_costs ppce500mc64_cost = { + COSTS_N_INSNS (4), /* mulsi */ + COSTS_N_INSNS (4), /* mulsi_const */ + COSTS_N_INSNS (4), /* mulsi_const9 */ + COSTS_N_INSNS (4), /* muldi */ + COSTS_N_INSNS (14), /* divsi */ + COSTS_N_INSNS (14), /* divdi */ + COSTS_N_INSNS (4), /* fp */ + COSTS_N_INSNS (10), /* dmul */ + COSTS_N_INSNS (36), /* sdiv */ + COSTS_N_INSNS (66), /* ddiv */ + 64, /* cache line size */ + 32, /* l1 cache */ + 128, /* l2 cache */ + 1, /* prefetch streams /*/ +}; + /* Instruction costs on POWER4 and POWER5 processors. */ static const struct processor_costs power4_cost = { @@ -797,6 +835,40 @@ struct processor_costs power7_cost = { 12, /* prefetch streams */ }; +/* Instruction costs on POWER A2 processors. */ +static const +struct processor_costs ppca2_cost = { + COSTS_N_INSNS (16), /* mulsi */ + COSTS_N_INSNS (16), /* mulsi_const */ + COSTS_N_INSNS (16), /* mulsi_const9 */ + COSTS_N_INSNS (16), /* muldi */ + COSTS_N_INSNS (22), /* divsi */ + COSTS_N_INSNS (28), /* divdi */ + COSTS_N_INSNS (3), /* fp */ + COSTS_N_INSNS (3), /* dmul */ + COSTS_N_INSNS (59), /* sdiv */ + COSTS_N_INSNS (72), /* ddiv */ + 64, + 16, /* l1 cache */ + 2048, /* l2 cache */ + 16, /* prefetch streams */ +}; + + +/* Table that classifies rs6000 builtin functions (pure, const, etc.). */ +#undef RS6000_BUILTIN +#undef RS6000_BUILTIN_EQUATE +#define RS6000_BUILTIN(NAME, TYPE) TYPE, +#define RS6000_BUILTIN_EQUATE(NAME, VALUE) + +static const enum rs6000_btc builtin_classify[(int)RS6000_BUILTIN_COUNT] = +{ +#include "rs6000-builtin.def" +}; + +#undef RS6000_BUILTIN +#undef RS6000_BUILTIN_EQUATE + static bool rs6000_function_ok_for_sibcall (tree, tree); static const char *rs6000_invalid_within_doloop (const_rtx); @@ -825,6 +897,7 @@ static bool no_global_regs_above (int, bool); static void rs6000_assemble_visibility (tree, int); #endif static int rs6000_ra_ever_killed (void); +static bool rs6000_attribute_takes_identifier_p (const_tree); static tree rs6000_handle_longcall_attribute (tree *, tree, tree, int, bool *); static tree rs6000_handle_altivec_attribute (tree *, tree, tree, int, bool *); static bool rs6000_ms_bitfield_layout_p (const_tree); @@ -837,7 +910,7 @@ static rtx rs6000_emit_stack_reset (rs6000_stack_t *, rtx, rtx, int, bool); static rtx rs6000_make_savres_rtx (rs6000_stack_t *, rtx, int, enum machine_mode, bool, bool, bool); static bool rs6000_reg_live_or_pic_offset_p (int); -static tree rs6000_builtin_vectorized_function (unsigned int, tree, tree); +static tree rs6000_builtin_vectorized_function (tree, tree, tree); static int rs6000_savres_strategy (rs6000_stack_t *, bool, int, int); static void rs6000_restore_saved_cr (rtx, int); static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT); @@ -846,6 +919,7 @@ static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree); static rtx rs6000_emit_set_long_const (rtx, HOST_WIDE_INT, HOST_WIDE_INT); static bool rs6000_return_in_memory (const_tree, const_tree); +static rtx rs6000_function_value (const_tree, const_tree, bool); static void rs6000_file_start (void); #if TARGET_ELF static int rs6000_elf_reloc_rw_mask (void); @@ -917,7 +991,7 @@ static tree rs6000_builtin_reciprocal (unsigned int, bool, bool); static tree rs6000_builtin_mask_for_load (void); static tree rs6000_builtin_mul_widen_even (tree); static tree rs6000_builtin_mul_widen_odd (tree); -static tree rs6000_builtin_conversion (unsigned int, tree); +static tree rs6000_builtin_conversion (unsigned int, tree, tree); static tree rs6000_builtin_vec_perm (tree, tree *); static bool rs6000_builtin_support_vector_misalignment (enum machine_mode, @@ -927,6 +1001,8 @@ static bool rs6000_builtin_support_vector_misalignment (enum static void def_builtin (int, const char *, tree, int); static bool rs6000_vector_alignment_reachable (const_tree, bool); static void rs6000_init_builtins (void); +static tree rs6000_builtin_decl (unsigned, bool); + static rtx rs6000_expand_unop_builtin (enum insn_code, tree, rtx); static rtx rs6000_expand_binop_builtin (enum insn_code, tree, rtx); static rtx rs6000_expand_ternop_builtin (enum insn_code, tree, rtx); @@ -983,8 +1059,8 @@ static void rs6000_init_dwarf_reg_sizes_extra (tree); static rtx rs6000_legitimize_address (rtx, rtx, enum machine_mode); static rtx rs6000_debug_legitimize_address (rtx, rtx, enum machine_mode); static rtx rs6000_legitimize_tls_address (rtx, enum tls_model); -static rtx rs6000_delegitimize_address (rtx); static void rs6000_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; +static rtx rs6000_delegitimize_address (rtx); static rtx rs6000_tls_get_addr (void); static rtx rs6000_got_sym (void); static int rs6000_tls_symbol_ref_1 (rtx *, void *); @@ -1094,6 +1170,7 @@ static const enum reg_class *rs6000_ira_cover_classes (void); const int INSN_NOT_AVAILABLE = -1; static enum machine_mode rs6000_eh_return_filter_mode (void); static bool rs6000_can_eliminate (const int, const int); +static void rs6000_trampoline_init (rtx, tree, rtx); /* Hash table stuff for keeping track of TOC entries. */ @@ -1193,9 +1270,6 @@ static const struct attribute_spec rs6000_attribute_table[] = #endif #ifndef TARGET_PROFILE_KERNEL #define TARGET_PROFILE_KERNEL 0 -#define SET_PROFILE_KERNEL(N) -#else -#define SET_PROFILE_KERNEL(N) TARGET_PROFILE_KERNEL = (N) #endif /* The VRSAVE bitmask puts bit %v0 as the most significant bit. */ @@ -1206,6 +1280,8 @@ static const struct attribute_spec rs6000_attribute_table[] = #define TARGET_ATTRIBUTE_TABLE rs6000_attribute_table #undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES rs6000_set_default_type_attributes +#undef TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P +#define TARGET_ATTRIBUTE_TAKES_IDENTIFIER_P rs6000_attribute_takes_identifier_p #undef TARGET_ASM_ALIGNED_DI_OP #define TARGET_ASM_ALIGNED_DI_OP DOUBLE_INT_ASM_OP @@ -1251,6 +1327,9 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_CANNOT_FORCE_CONST_MEM #define TARGET_CANNOT_FORCE_CONST_MEM rs6000_tls_referenced_p +#undef TARGET_DELEGITIMIZE_ADDRESS +#define TARGET_DELEGITIMIZE_ADDRESS rs6000_delegitimize_address + #undef TARGET_ASM_FUNCTION_PROLOGUE #define TARGET_ASM_FUNCTION_PROLOGUE rs6000_output_function_prologue #undef TARGET_ASM_FUNCTION_EPILOGUE @@ -1312,6 +1391,8 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS rs6000_init_builtins +#undef TARGET_BUILTIN_DECL +#define TARGET_BUILTIN_DECL rs6000_builtin_decl #undef TARGET_EXPAND_BUILTIN #define TARGET_EXPAND_BUILTIN rs6000_expand_builtin @@ -1443,9 +1524,6 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_USE_BLOCKS_FOR_CONSTANT_P #define TARGET_USE_BLOCKS_FOR_CONSTANT_P rs6000_use_blocks_for_constant_p -#undef TARGET_DELEGITIMIZE_ADDRESS -#define TARGET_DELEGITIMIZE_ADDRESS rs6000_delegitimize_address - #undef TARGET_BUILTIN_RECIPROCAL #define TARGET_BUILTIN_RECIPROCAL rs6000_builtin_reciprocal @@ -1467,6 +1545,12 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_CAN_ELIMINATE #define TARGET_CAN_ELIMINATE rs6000_can_eliminate +#undef TARGET_TRAMPOLINE_INIT +#define TARGET_TRAMPOLINE_INIT rs6000_trampoline_init + +#undef TARGET_FUNCTION_VALUE +#define TARGET_FUNCTION_VALUE rs6000_function_value + struct gcc_target targetm = TARGET_INITIALIZER; /* Return number of consecutive hard regs needed starting at reg REGNO @@ -2117,6 +2201,12 @@ rs6000_override_options (const char *default_cpu) POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB}, {"464fp", PROCESSOR_PPC440, POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, + {"476", PROCESSOR_PPC476, + POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_PPC_GFXOPT | MASK_MFCRF + | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_MULHW | MASK_DLMZB}, + {"476fp", PROCESSOR_PPC476, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_MFCRF | MASK_POPCNTB + | MASK_FPRND | MASK_CMPB | MASK_MULHW | MASK_DLMZB}, {"505", PROCESSOR_MPCCORE, POWERPC_BASE_MASK}, {"601", PROCESSOR_PPC601, MASK_POWER | POWERPC_BASE_MASK | MASK_MULTIPLE | MASK_STRING}, @@ -2141,10 +2231,15 @@ rs6000_override_options (const char *default_cpu) /* 8548 has a dummy entry for now. */ {"8548", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN | MASK_ISEL}, + {"a2", PROCESSOR_PPCA2, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_POPCNTB + | MASK_CMPB | MASK_NO_UPDATE }, {"e300c2", PROCESSOR_PPCE300C2, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, {"e300c3", PROCESSOR_PPCE300C3, POWERPC_BASE_MASK}, {"e500mc", PROCESSOR_PPCE500MC, POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ISEL}, + {"e500mc64", PROCESSOR_PPCE500MC64, POWERPC_BASE_MASK | MASK_POWERPC64 + | MASK_PPC_GFXOPT | MASK_ISEL}, {"860", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, {"970", PROCESSOR_POWER4, POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64}, @@ -2208,9 +2303,16 @@ rs6000_override_options (const char *default_cpu) | MASK_PPC_GFXOPT | MASK_POWERPC64 | MASK_ALTIVEC | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_MULHW | MASK_DLMZB | MASK_CMPB | MASK_MFPGPR | MASK_DFP - | MASK_POPCNTD | MASK_VSX | MASK_ISEL) + | MASK_POPCNTD | MASK_VSX | MASK_ISEL | MASK_NO_UPDATE) }; + /* Numerous experiment shows that IRA based loop pressure + calculation works better for RTL loop invariant motion on targets + with enough (>= 32) registers. It is an expensive optimization. + So it is on only for peak performance. */ + if (optimize >= 3) + flag_ira_loop_pressure = 1; + /* Set the pointer size. */ if (TARGET_64BIT) { @@ -2266,7 +2368,7 @@ rs6000_override_options (const char *default_cpu) } if (rs6000_cpu == PROCESSOR_PPCE300C2 || rs6000_cpu == PROCESSOR_PPCE300C3 - || rs6000_cpu == PROCESSOR_PPCE500MC) + || rs6000_cpu == PROCESSOR_PPCE500MC || rs6000_cpu == PROCESSOR_PPCE500MC64) { if (TARGET_ALTIVEC) error ("AltiVec not supported in this target"); @@ -2280,10 +2382,10 @@ rs6000_override_options (const char *default_cpu) rs6000_gen_cell_microcode = !(rs6000_cpu == PROCESSOR_CELL && !optimize_size); - /* If we are optimizing big endian systems for space, use the load/store - multiple and string instructions unless we are not generating - Cell microcode. */ - if (BYTES_BIG_ENDIAN && optimize_size && !rs6000_gen_cell_microcode) + /* If we are optimizing big endian systems for space and it's OK to + use instructions that would be microcoded on the Cell, use the + load/store multiple and string instructions. */ + if (BYTES_BIG_ENDIAN && optimize_size && rs6000_gen_cell_microcode) target_flags |= ~target_flags_explicit & (MASK_MULTIPLE | MASK_STRING); /* Don't allow -mmultiple or -mstring on little endian systems @@ -2309,8 +2411,7 @@ rs6000_override_options (const char *default_cpu) } } - /* Add some warnings for VSX. Enable -maltivec unless the user explicitly - used -mno-altivec */ + /* Add some warnings for VSX. */ if (TARGET_VSX) { const char *msg = NULL; @@ -2331,14 +2432,20 @@ rs6000_override_options (const char *default_cpu) msg = N_("-mvsx used with little endian code"); else if (TARGET_AVOID_XFORM > 0) msg = N_("-mvsx needs indexed addressing"); + else if (!TARGET_ALTIVEC && (target_flags_explicit & MASK_ALTIVEC)) + { + if (target_flags_explicit & MASK_VSX) + msg = N_("-mvsx and -mno-altivec are incompatible"); + else + msg = N_("-mno-altivec disables vsx"); + } if (msg) { warning (0, msg); target_flags &= ~ MASK_VSX; } - else if (TARGET_VSX && !TARGET_ALTIVEC - && (target_flags_explicit & MASK_ALTIVEC) == 0) + else if (TARGET_VSX && !TARGET_ALTIVEC) target_flags |= MASK_ALTIVEC; } @@ -2458,7 +2565,8 @@ rs6000_override_options (const char *default_cpu) SUB3TARGET_OVERRIDE_OPTIONS; #endif - if (TARGET_E500 || rs6000_cpu == PROCESSOR_PPCE500MC) + if (TARGET_E500 || rs6000_cpu == PROCESSOR_PPCE500MC + || rs6000_cpu == PROCESSOR_PPCE500MC64) { /* The e500 and e500mc do not have string instructions, and we set MASK_STRING above when optimizing for size. */ @@ -2487,6 +2595,7 @@ rs6000_override_options (const char *default_cpu) && rs6000_cpu != PROCESSOR_POWER5 && rs6000_cpu != PROCESSOR_POWER6 && rs6000_cpu != PROCESSOR_POWER7 + && rs6000_cpu != PROCESSOR_PPCA2 && rs6000_cpu != PROCESSOR_CELL); rs6000_sched_groups = (rs6000_cpu == PROCESSOR_POWER4 || rs6000_cpu == PROCESSOR_POWER5 @@ -2494,7 +2603,9 @@ rs6000_override_options (const char *default_cpu) rs6000_align_branch_targets = (rs6000_cpu == PROCESSOR_POWER4 || rs6000_cpu == PROCESSOR_POWER5 || rs6000_cpu == PROCESSOR_POWER6 - || rs6000_cpu == PROCESSOR_POWER7); + || rs6000_cpu == PROCESSOR_POWER7 + || rs6000_cpu == PROCESSOR_PPCE500MC + || rs6000_cpu == PROCESSOR_PPCE500MC64); /* Allow debug switches to override the above settings. */ if (TARGET_ALWAYS_HINT > 0) @@ -2642,6 +2753,10 @@ rs6000_override_options (const char *default_cpu) rs6000_cost = &ppc440_cost; break; + case PROCESSOR_PPC476: + rs6000_cost = &ppc476_cost; + break; + case PROCESSOR_PPC601: rs6000_cost = &ppc601_cost; break; @@ -2692,6 +2807,10 @@ rs6000_override_options (const char *default_cpu) rs6000_cost = &ppce500mc_cost; break; + case PROCESSOR_PPCE500MC64: + rs6000_cost = &ppce500mc64_cost; + break; + case PROCESSOR_POWER4: case PROCESSOR_POWER5: rs6000_cost = &power4_cost; @@ -2705,6 +2824,10 @@ rs6000_override_options (const char *default_cpu) rs6000_cost = &power7_cost; break; + case PROCESSOR_PPCA2: + rs6000_cost = &ppca2_cost; + break; + default: gcc_unreachable (); } @@ -2763,24 +2886,24 @@ rs6000_builtin_mask_for_load (void) /* Implement targetm.vectorize.builtin_conversion. Returns a decl of a function that implements conversion of an integer vector - into a floating-point vector, or vice-versa. TYPE is the type of the integer - side of the conversion. + into a floating-point vector, or vice-versa. DEST_TYPE is the + destination type and SRC_TYPE the source type of the conversion. Return NULL_TREE if it is not available. */ static tree -rs6000_builtin_conversion (unsigned int tcode, tree type) +rs6000_builtin_conversion (unsigned int tcode, tree dest_type, tree src_type) { enum tree_code code = (enum tree_code) tcode; switch (code) { case FIX_TRUNC_EXPR: - switch (TYPE_MODE (type)) + switch (TYPE_MODE (dest_type)) { case V2DImode: if (!VECTOR_UNIT_VSX_P (V2DFmode)) return NULL_TREE; - return TYPE_UNSIGNED (type) + return TYPE_UNSIGNED (dest_type) ? rs6000_builtin_decls[VSX_BUILTIN_XVCVDPUXDS_UNS] : rs6000_builtin_decls[VSX_BUILTIN_XVCVDPSXDS]; @@ -2788,7 +2911,7 @@ rs6000_builtin_conversion (unsigned int tcode, tree type) if (VECTOR_UNIT_NONE_P (V4SImode) || VECTOR_UNIT_NONE_P (V4SFmode)) return NULL_TREE; - return TYPE_UNSIGNED (type) + return TYPE_UNSIGNED (dest_type) ? rs6000_builtin_decls[VECTOR_BUILTIN_FIXUNS_V4SF_V4SI] : rs6000_builtin_decls[VECTOR_BUILTIN_FIX_V4SF_V4SI]; @@ -2797,13 +2920,13 @@ rs6000_builtin_conversion (unsigned int tcode, tree type) } case FLOAT_EXPR: - switch (TYPE_MODE (type)) + switch (TYPE_MODE (src_type)) { case V2DImode: if (!VECTOR_UNIT_VSX_P (V2DFmode)) return NULL_TREE; - return TYPE_UNSIGNED (type) + return TYPE_UNSIGNED (src_type) ? rs6000_builtin_decls[VSX_BUILTIN_XVCVUXDDP] : rs6000_builtin_decls[VSX_BUILTIN_XVCVSXDDP]; @@ -2811,7 +2934,7 @@ rs6000_builtin_conversion (unsigned int tcode, tree type) if (VECTOR_UNIT_NONE_P (V4SImode) || VECTOR_UNIT_NONE_P (V4SFmode)) return NULL_TREE; - return TYPE_UNSIGNED (type) + return TYPE_UNSIGNED (src_type) ? rs6000_builtin_decls[VECTOR_BUILTIN_UNSFLOAT_V4SI_V4SF] : rs6000_builtin_decls[VECTOR_BUILTIN_FLOAT_V4SI_V4SF]; @@ -3059,15 +3182,17 @@ rs6000_parse_fpu_option (const char *option) if it is not available. */ static tree -rs6000_builtin_vectorized_function (unsigned int fn, tree type_out, +rs6000_builtin_vectorized_function (tree fndecl, tree type_out, tree type_in) { enum machine_mode in_mode, out_mode; int in_n, out_n; + enum built_in_function fn = DECL_FUNCTION_CODE (fndecl); if (TREE_CODE (type_out) != VECTOR_TYPE || TREE_CODE (type_in) != VECTOR_TYPE - || !TARGET_VECTORIZE_BUILTINS) + || !TARGET_VECTORIZE_BUILTINS + || DECL_BUILT_IN_CLASS (fndecl) != BUILT_IN_NORMAL) return NULL_TREE; out_mode = TYPE_MODE (TREE_TYPE (type_out)); @@ -3680,6 +3805,8 @@ num_insns_constant_wide (HOST_WIDE_INT value) if (low == 0) return num_insns_constant_wide (high) + 1; + else if (high == 0) + return num_insns_constant_wide (low) + 1; else return (num_insns_constant_wide (high) + num_insns_constant_wide (low) + 1); @@ -4059,7 +4186,7 @@ paired_emit_vector_compare (enum rtx_code rcode, rtx cc_op0, rtx cc_op1) { rtx tmp = gen_reg_rtx (V2SFmode); - rtx tmp1, max, min, equal_zero; + rtx tmp1, max, min; gcc_assert (TARGET_PAIRED_FLOAT); gcc_assert (GET_MODE (op0) == GET_MODE (op1)); @@ -4086,8 +4213,8 @@ paired_emit_vector_compare (enum rtx_code rcode, tmp1 = gen_reg_rtx (V2SFmode); max = gen_reg_rtx (V2SFmode); min = gen_reg_rtx (V2SFmode); - equal_zero = gen_reg_rtx (V2SFmode); - + gen_reg_rtx (V2SFmode); + emit_insn (gen_subv2sf3 (tmp, cc_op0, cc_op1)); emit_insn (gen_selv2sf4 (max, tmp, cc_op0, cc_op1, CONST0_RTX (SFmode))); @@ -4531,6 +4658,9 @@ darwin_rs6000_special_round_type_align (tree type, unsigned int computed, field = TREE_CHAIN (field); if (! field) break; + /* A packed field does not contribute any extra alignment. */ + if (DECL_PACKED (field)) + return align; type = TREE_TYPE (field); while (TREE_CODE (type) == ARRAY_TYPE) type = TREE_TYPE (type); @@ -5120,33 +5250,6 @@ rs6000_debug_legitimize_address (rtx x, rtx oldx, enum machine_mode mode) return ret; } -/* If ORIG_X is a constant pool reference, return its known value, - otherwise ORIG_X. */ - -static rtx -rs6000_delegitimize_address (rtx x) -{ - rtx orig_x = delegitimize_mem_from_attrs (x); - - x = orig_x; - - if (!MEM_P (x)) - return orig_x; - - x = XEXP (x, 0); - - if (legitimate_constant_pool_address_p (x) - && GET_CODE (XEXP (x, 1)) == CONST - && GET_CODE (XEXP (XEXP (x, 1), 0)) == MINUS - && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 0)) == SYMBOL_REF - && constant_pool_expr_p (XEXP (XEXP (XEXP (x, 1), 0), 0)) - && GET_CODE (XEXP (XEXP (XEXP (x, 1), 0), 1)) == SYMBOL_REF - && toc_relative_expr_p (XEXP (XEXP (XEXP (x, 1), 0), 1))) - return get_pool_constant (XEXP (XEXP (XEXP (x, 1), 0), 0)); - - return orig_x; -} - /* This is called from dwarf2out.c via TARGET_ASM_OUTPUT_DWARF_DTPREL. We need to emit DTP-relative relocations. */ @@ -5168,6 +5271,51 @@ rs6000_output_dwarf_dtprel (FILE *file, int size, rtx x) fputs ("@dtprel+0x8000", file); } +/* In the name of slightly smaller debug output, and to cater to + general assembler lossage, recognize various UNSPEC sequences + and turn them back into a direct symbol reference. */ + +static rtx +rs6000_delegitimize_address (rtx orig_x) +{ + rtx x, y; + + orig_x = delegitimize_mem_from_attrs (orig_x); + x = orig_x; + if (MEM_P (x)) + x = XEXP (x, 0); + + if (GET_CODE (x) == PLUS + && GET_CODE (XEXP (x, 1)) == CONST + && GET_CODE (XEXP (x, 0)) == REG + && REGNO (XEXP (x, 0)) == TOC_REGISTER) + { + y = XEXP (XEXP (x, 1), 0); + if (GET_CODE (y) == UNSPEC + && XINT (y, 1) == UNSPEC_TOCREL) + { + y = XVECEXP (y, 0, 0); + if (!MEM_P (orig_x)) + return y; + else + return replace_equiv_address_nv (orig_x, y); + } + return orig_x; + } + + if (TARGET_MACHO + && GET_CODE (orig_x) == LO_SUM + && GET_CODE (XEXP (x, 1)) == CONST) + { + y = XEXP (XEXP (x, 1), 0); + if (GET_CODE (y) == UNSPEC + && XINT (y, 1) == UNSPEC_MACHOPIC_OFFSET) + return XVECEXP (y, 0, 0); + } + + return orig_x; +} + /* Construct the SYMBOL_REF for the tls_get_addr function. */ static GTY(()) rtx rs6000_tls_symbol; @@ -5267,14 +5415,14 @@ rs6000_legitimize_tls_address (rtx addr, enum tls_model model) else { rtx tmp3, mem; - rtx first, last; + rtx last; tmp1 = gen_reg_rtx (Pmode); tmp2 = gen_reg_rtx (Pmode); tmp3 = gen_reg_rtx (Pmode); mem = gen_const_mem (Pmode, tmp1); - first = emit_insn (gen_load_toc_v4_PIC_1b (gsym)); + emit_insn (gen_load_toc_v4_PIC_1b (gsym)); emit_move_insn (tmp1, gen_rtx_REG (Pmode, LR_REGNO)); emit_move_insn (tmp2, mem); @@ -5694,12 +5842,6 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict) && legitimate_indexed_address_p (x, reg_ok_strict)) return 1; if (GET_CODE (x) == PRE_MODIFY - && VECTOR_MEM_VSX_P (mode) - && TARGET_UPDATE - && legitimate_indexed_address_p (XEXP (x, 1), reg_ok_strict) - && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0))) - return 1; - if (GET_CODE (x) == PRE_MODIFY && mode != TImode && mode != TFmode && mode != TDmode @@ -5707,7 +5849,7 @@ rs6000_legitimate_address_p (enum machine_mode mode, rtx x, bool reg_ok_strict) || TARGET_POWERPC64 || ((mode != DFmode && mode != DDmode) || TARGET_E500_DOUBLE)) && (TARGET_POWERPC64 || mode != DImode) - && !VECTOR_MEM_ALTIVEC_P (mode) + && !VECTOR_MEM_ALTIVEC_OR_VSX_P (mode) && !SPE_VECTOR_MODE (mode) /* Restrict addressing for DI because of our SUBREG hackery. */ && !(TARGET_E500_DOUBLE @@ -6062,6 +6204,20 @@ rs6000_emit_set_long_const (rtx dest, HOST_WIDE_INT c1, HOST_WIDE_INT c2) gen_rtx_IOR (DImode, copy_rtx (dest), GEN_INT (ud1))); } + else if (ud3 == 0 && ud4 == 0) + { + gcc_assert (ud2 & 0x8000); + emit_move_insn (dest, GEN_INT (((ud2 << 16) ^ 0x80000000) + - 0x80000000)); + if (ud1 != 0) + emit_move_insn (copy_rtx (dest), + gen_rtx_IOR (DImode, copy_rtx (dest), + GEN_INT (ud1))); + emit_move_insn (copy_rtx (dest), + gen_rtx_ZERO_EXTEND (DImode, + gen_lowpart (SImode, + copy_rtx (dest)))); + } else if ((ud4 == 0xffff && (ud3 & 0x8000)) || (ud4 == 0 && ! (ud3 & 0x8000))) { @@ -6195,32 +6351,6 @@ rs6000_emit_move (rtx dest, rtx source, enum machine_mode mode) return; } - /* Fix up invalid (const (plus (symbol_ref) (reg))) that seems to be created - in the secondary_reload phase, which evidently overwrites the CONST_INT - with a register. */ - if (GET_CODE (source) == CONST && GET_CODE (XEXP (source, 0)) == PLUS - && mode == Pmode) - { - rtx add_op0 = XEXP (XEXP (source, 0), 0); - rtx add_op1 = XEXP (XEXP (source, 0), 1); - - if (GET_CODE (add_op0) == SYMBOL_REF && GET_CODE (add_op1) == REG) - { - rtx tmp = (can_create_pseudo_p ()) ? gen_reg_rtx (Pmode) : dest; - - if (TARGET_DEBUG_ADDR) - { - fprintf (stderr, "\nrs6000_emit_move: bad source\n"); - debug_rtx (source); - } - - rs6000_emit_move (tmp, add_op0, Pmode); - emit_insn (gen_rtx_SET (VOIDmode, dest, - gen_rtx_PLUS (Pmode, tmp, add_op1))); - return; - } - } - if (can_create_pseudo_p () && GET_CODE (operands[0]) == MEM && !gpc_reg_operand (operands[1], mode)) operands[1] = force_reg (mode, operands[1]); @@ -8463,13 +8593,54 @@ def_builtin (int mask, const char *name, tree type, int code) { if ((mask & target_flags) || TARGET_PAIRED_FLOAT) { + tree t; if (rs6000_builtin_decls[code]) fatal_error ("internal error: builtin function to %s already processed.", name); - rs6000_builtin_decls[code] = + rs6000_builtin_decls[code] = t = add_builtin_function (name, type, code, BUILT_IN_MD, NULL, NULL_TREE); + + gcc_assert (code >= 0 && code < (int)RS6000_BUILTIN_COUNT); + switch (builtin_classify[code]) + { + default: + gcc_unreachable (); + + /* assume builtin can do anything. */ + case RS6000_BTC_MISC: + break; + + /* const function, function only depends on the inputs. */ + case RS6000_BTC_CONST: + TREE_READONLY (t) = 1; + TREE_NOTHROW (t) = 1; + break; + + /* pure function, function can read global memory. */ + case RS6000_BTC_PURE: + DECL_PURE_P (t) = 1; + TREE_NOTHROW (t) = 1; + break; + + /* Function is a math function. If rounding mode is on, then treat + the function as not reading global memory, but it can have + arbitrary side effects. If it is off, then assume the function is + a const function. This mimics the ATTR_MATHFN_FPROUNDING + attribute in builtin-attribute.def that is used for the math + functions. */ + case RS6000_BTC_FP_PURE: + TREE_NOTHROW (t) = 1; + if (flag_rounding_math) + { + DECL_PURE_P (t) = 1; + DECL_IS_NOVOPS (t) = 1; + } + else + TREE_READONLY (t) = 1; + break; + } } } @@ -8640,10 +8811,10 @@ static struct builtin_description bdesc_2arg[] = { MASK_ALTIVEC, CODE_FOR_vector_eqv4sf, "__builtin_altivec_vcmpeqfp", ALTIVEC_BUILTIN_VCMPEQFP }, { MASK_ALTIVEC, CODE_FOR_vector_gev4sf, "__builtin_altivec_vcmpgefp", ALTIVEC_BUILTIN_VCMPGEFP }, { MASK_ALTIVEC, CODE_FOR_vector_gtuv16qi, "__builtin_altivec_vcmpgtub", ALTIVEC_BUILTIN_VCMPGTUB }, - { MASK_ALTIVEC, CODE_FOR_vector_gtuv8hi, "__builtin_altivec_vcmpgtsb", ALTIVEC_BUILTIN_VCMPGTSB }, - { MASK_ALTIVEC, CODE_FOR_vector_gtuv4si, "__builtin_altivec_vcmpgtuh", ALTIVEC_BUILTIN_VCMPGTUH }, - { MASK_ALTIVEC, CODE_FOR_vector_gtv16qi, "__builtin_altivec_vcmpgtsh", ALTIVEC_BUILTIN_VCMPGTSH }, - { MASK_ALTIVEC, CODE_FOR_vector_gtv8hi, "__builtin_altivec_vcmpgtuw", ALTIVEC_BUILTIN_VCMPGTUW }, + { MASK_ALTIVEC, CODE_FOR_vector_gtv16qi, "__builtin_altivec_vcmpgtsb", ALTIVEC_BUILTIN_VCMPGTSB }, + { MASK_ALTIVEC, CODE_FOR_vector_gtuv8hi, "__builtin_altivec_vcmpgtuh", ALTIVEC_BUILTIN_VCMPGTUH }, + { MASK_ALTIVEC, CODE_FOR_vector_gtv8hi, "__builtin_altivec_vcmpgtsh", ALTIVEC_BUILTIN_VCMPGTSH }, + { MASK_ALTIVEC, CODE_FOR_vector_gtuv4si, "__builtin_altivec_vcmpgtuw", ALTIVEC_BUILTIN_VCMPGTUW }, { MASK_ALTIVEC, CODE_FOR_vector_gtv4si, "__builtin_altivec_vcmpgtsw", ALTIVEC_BUILTIN_VCMPGTSW }, { MASK_ALTIVEC, CODE_FOR_vector_gtv4sf, "__builtin_altivec_vcmpgtfp", ALTIVEC_BUILTIN_VCMPGTFP }, { MASK_ALTIVEC, CODE_FOR_altivec_vctsxs, "__builtin_altivec_vctsxs", ALTIVEC_BUILTIN_VCTSXS }, @@ -8768,6 +8939,10 @@ static struct builtin_description bdesc_2arg[] = { MASK_VSX, CODE_FOR_vsx_xxmrghw_v4si, "__builtin_vsx_xxmrghw_4si", VSX_BUILTIN_XXMRGHW_4SI }, { MASK_VSX, CODE_FOR_vsx_xxmrglw_v4sf, "__builtin_vsx_xxmrglw", VSX_BUILTIN_XXMRGLW_4SF }, { MASK_VSX, CODE_FOR_vsx_xxmrglw_v4si, "__builtin_vsx_xxmrglw_4si", VSX_BUILTIN_XXMRGLW_4SI }, + { MASK_VSX, CODE_FOR_vec_interleave_lowv2df, "__builtin_vsx_mergel_2df", VSX_BUILTIN_VEC_MERGEL_V2DF }, + { MASK_VSX, CODE_FOR_vec_interleave_lowv2di, "__builtin_vsx_mergel_2di", VSX_BUILTIN_VEC_MERGEL_V2DI }, + { MASK_VSX, CODE_FOR_vec_interleave_highv2df, "__builtin_vsx_mergeh_2df", VSX_BUILTIN_VEC_MERGEH_V2DF }, + { MASK_VSX, CODE_FOR_vec_interleave_highv2di, "__builtin_vsx_mergeh_2di", VSX_BUILTIN_VEC_MERGEH_V2DI }, { MASK_ALTIVEC|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_add", ALTIVEC_BUILTIN_VEC_ADD }, { MASK_ALTIVEC|MASK_VSX, CODE_FOR_nothing, "__builtin_vec_vaddfp", ALTIVEC_BUILTIN_VEC_VADDFP }, @@ -8901,10 +9076,10 @@ static struct builtin_description bdesc_2arg[] = { MASK_VSX, CODE_FOR_nothing, "__builtin_vec_mul", VSX_BUILTIN_VEC_MUL }, { MASK_VSX, CODE_FOR_nothing, "__builtin_vec_div", VSX_BUILTIN_VEC_DIV }, - { 0, CODE_FOR_divv2sf3, "__builtin_paired_divv2sf3", PAIRED_BUILTIN_DIVV2SF3 }, - { 0, CODE_FOR_addv2sf3, "__builtin_paired_addv2sf3", PAIRED_BUILTIN_ADDV2SF3 }, - { 0, CODE_FOR_subv2sf3, "__builtin_paired_subv2sf3", PAIRED_BUILTIN_SUBV2SF3 }, - { 0, CODE_FOR_mulv2sf3, "__builtin_paired_mulv2sf3", PAIRED_BUILTIN_MULV2SF3 }, + { 0, CODE_FOR_paired_divv2sf3, "__builtin_paired_divv2sf3", PAIRED_BUILTIN_DIVV2SF3 }, + { 0, CODE_FOR_paired_addv2sf3, "__builtin_paired_addv2sf3", PAIRED_BUILTIN_ADDV2SF3 }, + { 0, CODE_FOR_paired_subv2sf3, "__builtin_paired_subv2sf3", PAIRED_BUILTIN_SUBV2SF3 }, + { 0, CODE_FOR_paired_mulv2sf3, "__builtin_paired_mulv2sf3", PAIRED_BUILTIN_MULV2SF3 }, { 0, CODE_FOR_paired_muls0, "__builtin_paired_muls0", PAIRED_BUILTIN_MULS0 }, { 0, CODE_FOR_paired_muls1, "__builtin_paired_muls1", PAIRED_BUILTIN_MULS1 }, { 0, CODE_FOR_paired_merge00, "__builtin_paired_merge00", PAIRED_BUILTIN_MERGE00 }, @@ -8913,10 +9088,10 @@ static struct builtin_description bdesc_2arg[] = { 0, CODE_FOR_paired_merge11, "__builtin_paired_merge11", PAIRED_BUILTIN_MERGE11 }, /* Place holder, leave as first spe builtin. */ - { 0, CODE_FOR_spe_evaddw, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW }, - { 0, CODE_FOR_spe_evand, "__builtin_spe_evand", SPE_BUILTIN_EVAND }, + { 0, CODE_FOR_addv2si3, "__builtin_spe_evaddw", SPE_BUILTIN_EVADDW }, + { 0, CODE_FOR_andv2si3, "__builtin_spe_evand", SPE_BUILTIN_EVAND }, { 0, CODE_FOR_spe_evandc, "__builtin_spe_evandc", SPE_BUILTIN_EVANDC }, - { 0, CODE_FOR_spe_evdivws, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS }, + { 0, CODE_FOR_divv2si3, "__builtin_spe_evdivws", SPE_BUILTIN_EVDIVWS }, { 0, CODE_FOR_spe_evdivwu, "__builtin_spe_evdivwu", SPE_BUILTIN_EVDIVWU }, { 0, CODE_FOR_spe_eveqv, "__builtin_spe_eveqv", SPE_BUILTIN_EVEQV }, { 0, CODE_FOR_spe_evfsadd, "__builtin_spe_evfsadd", SPE_BUILTIN_EVFSADD }, @@ -9021,7 +9196,7 @@ static struct builtin_description bdesc_2arg[] = { 0, CODE_FOR_spe_evslw, "__builtin_spe_evslw", SPE_BUILTIN_EVSLW }, { 0, CODE_FOR_spe_evsrws, "__builtin_spe_evsrws", SPE_BUILTIN_EVSRWS }, { 0, CODE_FOR_spe_evsrwu, "__builtin_spe_evsrwu", SPE_BUILTIN_EVSRWU }, - { 0, CODE_FOR_spe_evsubfw, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW }, + { 0, CODE_FOR_subv2si3, "__builtin_spe_evsubfw", SPE_BUILTIN_EVSUBFW }, /* SPE binary operations expecting a 5-bit unsigned literal. */ { 0, CODE_FOR_spe_evaddiw, "__builtin_spe_evaddiw", SPE_BUILTIN_EVADDIW }, @@ -9292,7 +9467,7 @@ static struct builtin_description bdesc_1arg[] = /* The SPE unary builtins must start with SPE_BUILTIN_EVABS and end with SPE_BUILTIN_EVSUBFUSIAAW. */ - { 0, CODE_FOR_spe_evabs, "__builtin_spe_evabs", SPE_BUILTIN_EVABS }, + { 0, CODE_FOR_absv2si2, "__builtin_spe_evabs", SPE_BUILTIN_EVABS }, { 0, CODE_FOR_spe_evaddsmiaaw, "__builtin_spe_evaddsmiaaw", SPE_BUILTIN_EVADDSMIAAW }, { 0, CODE_FOR_spe_evaddssiaaw, "__builtin_spe_evaddssiaaw", SPE_BUILTIN_EVADDSSIAAW }, { 0, CODE_FOR_spe_evaddumiaaw, "__builtin_spe_evaddumiaaw", SPE_BUILTIN_EVADDUMIAAW }, @@ -9324,9 +9499,9 @@ static struct builtin_description bdesc_1arg[] = /* Place-holder. Leave as last unary SPE builtin. */ { 0, CODE_FOR_spe_evsubfusiaaw, "__builtin_spe_evsubfusiaaw", SPE_BUILTIN_EVSUBFUSIAAW }, - { 0, CODE_FOR_absv2sf2, "__builtin_paired_absv2sf2", PAIRED_BUILTIN_ABSV2SF2 }, + { 0, CODE_FOR_paired_absv2sf2, "__builtin_paired_absv2sf2", PAIRED_BUILTIN_ABSV2SF2 }, { 0, CODE_FOR_nabsv2sf2, "__builtin_paired_nabsv2sf2", PAIRED_BUILTIN_NABSV2SF2 }, - { 0, CODE_FOR_negv2sf2, "__builtin_paired_negv2sf2", PAIRED_BUILTIN_NEGV2SF2 }, + { 0, CODE_FOR_paired_negv2sf2, "__builtin_paired_negv2sf2", PAIRED_BUILTIN_NEGV2SF2 }, { 0, CODE_FOR_sqrtv2sf2, "__builtin_paired_sqrtv2sf2", PAIRED_BUILTIN_SQRTV2SF2 }, { 0, CODE_FOR_resv2sf2, "__builtin_paired_resv2sf2", PAIRED_BUILTIN_RESV2SF2 } }; @@ -9976,7 +10151,7 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, tree fndecl = TREE_OPERAND (CALL_EXPR_FN (exp), 0); unsigned int fcode = DECL_FUNCTION_CODE (fndecl); tree arg0, arg1, arg2; - enum machine_mode mode0, mode1, mode2; + enum machine_mode mode0, mode1; rtx pat, op0, op1, op2; const struct builtin_description *d; size_t i; @@ -9996,7 +10171,6 @@ altivec_expand_dst_builtin (tree exp, rtx target ATTRIBUTE_UNUSED, op2 = expand_normal (arg2); mode0 = insn_data[d->icode].operand[0].mode; mode1 = insn_data[d->icode].operand[1].mode; - mode2 = insn_data[d->icode].operand[2].mode; /* Invalid arguments, bail out before generating bad rtl. */ if (arg0 == error_mark_node @@ -10904,7 +11078,7 @@ static void rs6000_init_builtins (void) { tree tdecl; - + V2SI_type_node = build_vector_type (intSI_type_node, 2); V2SF_type_node = build_vector_type (float_type_node, 2); V2DI_type_node = build_vector_type (intDI_type_node, 2); @@ -11146,6 +11320,17 @@ rs6000_init_builtins (void) #endif } +/* Returns the rs6000 builtin decl for CODE. */ + +static tree +rs6000_builtin_decl (unsigned code, bool initialize_p ATTRIBUTE_UNUSED) +{ + if (code >= RS6000_BUILTIN_COUNT) + return error_mark_node; + + return rs6000_builtin_decls[code]; +} + /* Search through a set of builtins and enable the mask bits. DESC is an array of builtins. SIZE is the total number of builtins. @@ -15270,6 +15455,53 @@ rs6000_generate_compare (rtx cmp, enum machine_mode mode) /* Emit the RTL for an sCOND pattern. */ void +rs6000_emit_sISEL (enum machine_mode mode, rtx operands[]) +{ + rtx condition_rtx; + enum machine_mode op_mode; + enum rtx_code cond_code; + rtx result = operands[0]; + + condition_rtx = rs6000_generate_compare (operands[1], mode); + cond_code = GET_CODE (condition_rtx); + + op_mode = GET_MODE (XEXP (operands[1], 0)); + if (op_mode == VOIDmode) + op_mode = GET_MODE (XEXP (operands[1], 1)); + + if (TARGET_POWERPC64 && GET_MODE (result) == DImode) + { + PUT_MODE (condition_rtx, DImode); + if (cond_code == GEU || cond_code == GTU || cond_code == LEU + || cond_code == LTU) + emit_insn (gen_isel_unsigned_di (result, condition_rtx, + force_reg (DImode, const1_rtx), + force_reg (DImode, const0_rtx), + XEXP (condition_rtx, 0))); + else + emit_insn (gen_isel_signed_di (result, condition_rtx, + force_reg (DImode, const1_rtx), + force_reg (DImode, const0_rtx), + XEXP (condition_rtx, 0))); + } + else + { + PUT_MODE (condition_rtx, SImode); + if (cond_code == GEU || cond_code == GTU || cond_code == LEU + || cond_code == LTU) + emit_insn (gen_isel_unsigned_si (result, condition_rtx, + force_reg (SImode, const1_rtx), + force_reg (SImode, const0_rtx), + XEXP (condition_rtx, 0))); + else + emit_insn (gen_isel_signed_si (result, condition_rtx, + force_reg (SImode, const1_rtx), + force_reg (SImode, const0_rtx), + XEXP (condition_rtx, 0))); + } +} + +void rs6000_emit_sCOND (enum machine_mode mode, rtx operands[]) { rtx condition_rtx; @@ -15277,6 +15509,12 @@ rs6000_emit_sCOND (enum machine_mode mode, rtx operands[]) enum rtx_code cond_code; rtx result = operands[0]; + if (TARGET_ISEL && (mode == SImode || mode == DImode)) + { + rs6000_emit_sISEL (mode, operands); + return; + } + condition_rtx = rs6000_generate_compare (operands[1], mode); cond_code = GET_CODE (condition_rtx); @@ -15926,7 +16164,7 @@ static int rs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) { rtx condition_rtx, cr; - enum machine_mode mode = GET_MODE (XEXP (op, 0)); + enum machine_mode mode = GET_MODE (dest); if (mode != SImode && (!TARGET_POWERPC64 || mode != DImode)) return 0; @@ -15934,7 +16172,7 @@ rs6000_emit_int_cmove (rtx dest, rtx op, rtx true_cond, rtx false_cond) /* We still have to do the compare, because isel doesn't do a compare, it just looks at the CRx bits set by a previous compare instruction. */ - condition_rtx = rs6000_generate_compare (op, SImode); + condition_rtx = rs6000_generate_compare (op, mode); cr = XEXP (condition_rtx, 0); if (mode == SImode) @@ -16493,6 +16731,7 @@ rs6000_split_multireg_move (rtx dst, rtx src) int i; int j = -1; bool used_update = false; + rtx restore_basereg = NULL_RTX; if (MEM_P (src) && INT_REGNO_P (reg)) { @@ -16511,10 +16750,27 @@ rs6000_split_multireg_move (rtx dst, rtx src) } else if (! rs6000_offsettable_memref_p (src)) { - rtx basereg; - basereg = gen_rtx_REG (Pmode, reg); - emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0))); - src = replace_equiv_address (src, basereg); + if (GET_CODE (XEXP (src, 0)) == PRE_MODIFY) + { + rtx basereg = XEXP (XEXP (src, 0), 0); + if (TARGET_UPDATE) + { + rtx ndst = simplify_gen_subreg (reg_mode, dst, mode, 0); + emit_insn (gen_rtx_SET (VOIDmode, ndst, + gen_rtx_MEM (reg_mode, XEXP (src, 0)))); + used_update = true; + } + else + emit_insn (gen_rtx_SET (VOIDmode, basereg, + XEXP (XEXP (src, 0), 1))); + src = replace_equiv_address (src, basereg); + } + else + { + rtx basereg = gen_rtx_REG (Pmode, reg); + emit_insn (gen_rtx_SET (VOIDmode, basereg, XEXP (src, 0))); + src = replace_equiv_address (src, basereg); + } } breg = XEXP (src, 0); @@ -16528,8 +16784,7 @@ rs6000_split_multireg_move (rtx dst, rtx src) && REGNO (breg) < REGNO (dst) + nregs) j = REGNO (breg) - REGNO (dst); } - - if (GET_CODE (dst) == MEM && INT_REGNO_P (reg)) + else if (MEM_P (dst) && INT_REGNO_P (reg)) { rtx breg; @@ -16559,7 +16814,44 @@ rs6000_split_multireg_move (rtx dst, rtx src) emit_insn (gen_add3_insn (breg, breg, delta_rtx)); dst = replace_equiv_address (dst, breg); } - else + else if (!rs6000_offsettable_memref_p (dst) + && GET_CODE (XEXP (dst, 0)) != LO_SUM) + { + if (GET_CODE (XEXP (dst, 0)) == PRE_MODIFY) + { + rtx basereg = XEXP (XEXP (dst, 0), 0); + if (TARGET_UPDATE) + { + rtx nsrc = simplify_gen_subreg (reg_mode, src, mode, 0); + emit_insn (gen_rtx_SET (VOIDmode, + gen_rtx_MEM (reg_mode, XEXP (dst, 0)), nsrc)); + used_update = true; + } + else + emit_insn (gen_rtx_SET (VOIDmode, basereg, + XEXP (XEXP (dst, 0), 1))); + dst = replace_equiv_address (dst, basereg); + } + else + { + rtx basereg = XEXP (XEXP (dst, 0), 0); + rtx offsetreg = XEXP (XEXP (dst, 0), 1); + gcc_assert (GET_CODE (XEXP (dst, 0)) == PLUS + && REG_P (basereg) + && REG_P (offsetreg) + && REGNO (basereg) != REGNO (offsetreg)); + if (REGNO (basereg) == 0) + { + rtx tmp = offsetreg; + offsetreg = basereg; + basereg = tmp; + } + emit_insn (gen_add3_insn (basereg, basereg, offsetreg)); + restore_basereg = gen_sub3_insn (basereg, basereg, offsetreg); + dst = replace_equiv_address (dst, basereg); + } + } + else if (GET_CODE (XEXP (dst, 0)) != LO_SUM) gcc_assert (rs6000_offsettable_memref_p (dst)); } @@ -16581,6 +16873,8 @@ rs6000_split_multireg_move (rtx dst, rtx src) simplify_gen_subreg (reg_mode, src, mode, j * reg_mode_size))); } + if (restore_basereg != NULL_RTX) + emit_insn (restore_basereg); } } @@ -17708,7 +18002,7 @@ rs6000_aix_emit_builtin_unwind_init (void) do_compare_rtx_and_jump (opcode, tocompare, EQ, 1, SImode, NULL_RTX, NULL_RTX, - no_toc_save_needed); + no_toc_save_needed, -1); mem = gen_frame_mem (Pmode, gen_rtx_PLUS (Pmode, stack_top, @@ -18033,7 +18327,8 @@ static bool no_global_regs_above (int first, bool gpr) { int i; - for (i = first; i < gpr ? 32 : 64 ; i++) + int last = gpr ? 32 : 64; + for (i = first; i < last; i++) if (global_regs[i]) return false; return true; @@ -18050,54 +18345,136 @@ no_global_regs_above (int first, bool gpr) static GTY(()) rtx savres_routine_syms[N_SAVRES_REGISTERS][8]; -/* Return the symbol for an out-of-line register save/restore routine. +/* Temporary holding space for an out-of-line register save/restore + routine name. */ +static char savres_routine_name[30]; + +/* Return the name for an out-of-line register save/restore routine. + We are saving/restoring GPRs if GPR is true. */ + +static char * +rs6000_savres_routine_name (rs6000_stack_t *info, int regno, + bool savep, bool gpr, bool lr) +{ + const char *prefix = ""; + const char *suffix = ""; + + /* Different targets are supposed to define + {SAVE,RESTORE}_FP_{PREFIX,SUFFIX} with the idea that the needed + routine name could be defined with: + + sprintf (name, "%s%d%s", SAVE_FP_PREFIX, regno, SAVE_FP_SUFFIX) + + This is a nice idea in practice, but in reality, things are + complicated in several ways: + + - ELF targets have save/restore routines for GPRs. + + - SPE targets use different prefixes for 32/64-bit registers, and + neither of them fit neatly in the FOO_{PREFIX,SUFFIX} regimen. + + - PPC64 ELF targets have routines for save/restore of GPRs that + differ in what they do with the link register, so having a set + prefix doesn't work. (We only use one of the save routines at + the moment, though.) + + - PPC32 elf targets have "exit" versions of the restore routines + that restore the link register and can save some extra space. + These require an extra suffix. (There are also "tail" versions + of the restore routines and "GOT" versions of the save routines, + but we don't generate those at present. Same problems apply, + though.) + + We deal with all this by synthesizing our own prefix/suffix and + using that for the simple sprintf call shown above. */ + if (TARGET_SPE) + { + /* No floating point saves on the SPE. */ + gcc_assert (gpr); + + if (savep) + prefix = info->spe_64bit_regs_used ? "_save64gpr_" : "_save32gpr_"; + else + prefix = info->spe_64bit_regs_used ? "_rest64gpr_" : "_rest32gpr_"; + + if (lr) + suffix = "_x"; + } + else if (DEFAULT_ABI == ABI_V4) + { + if (TARGET_64BIT) + goto aix_names; + + if (gpr) + prefix = savep ? "_savegpr_" : "_restgpr_"; + else + prefix = savep ? "_savefpr_" : "_restfpr_"; + + if (lr) + suffix = "_x"; + } + else if (DEFAULT_ABI == ABI_AIX) + { +#ifndef POWERPC_LINUX + /* No out-of-line save/restore routines for GPRs on AIX. */ + gcc_assert (!TARGET_AIX || !gpr); +#endif + + aix_names: + if (gpr) + prefix = (savep + ? (lr ? "_savegpr0_" : "_savegpr1_") + : (lr ? "_restgpr0_" : "_restgpr1_")); +#ifdef POWERPC_LINUX + else if (lr) + prefix = (savep ? "_savefpr_" : "_restfpr_"); +#endif + else + { + prefix = savep ? SAVE_FP_PREFIX : RESTORE_FP_PREFIX; + suffix = savep ? SAVE_FP_SUFFIX : RESTORE_FP_SUFFIX; + } + } + else if (DEFAULT_ABI == ABI_DARWIN) + sorry ("Out-of-line save/restore routines not supported on Darwin"); + + sprintf (savres_routine_name, "%s%d%s", prefix, regno, suffix); + + return savres_routine_name; +} + +/* Return an RTL SYMBOL_REF for an out-of-line register save/restore routine. We are saving/restoring GPRs if GPR is true. */ static rtx -rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep, bool gpr, bool exitp) +rs6000_savres_routine_sym (rs6000_stack_t *info, bool savep, + bool gpr, bool lr) { int regno = gpr ? info->first_gp_reg_save : (info->first_fp_reg_save - 32); rtx sym; int select = ((savep ? 1 : 0) << 2 - | (gpr - /* On the SPE, we never have any FPRs, but we do have - 32/64-bit versions of the routines. */ - ? (TARGET_SPE_ABI && info->spe_64bit_regs_used ? 1 : 0) - : 0) << 1 - | (exitp ? 1: 0)); + | ((TARGET_SPE_ABI + /* On the SPE, we never have any FPRs, but we do have + 32/64-bit versions of the routines. */ + ? (info->spe_64bit_regs_used ? 1 : 0) + : (gpr ? 1 : 0)) << 1) + | (lr ? 1: 0)); /* Don't generate bogus routine names. */ - gcc_assert (FIRST_SAVRES_REGISTER <= regno && regno <= LAST_SAVRES_REGISTER); + gcc_assert (FIRST_SAVRES_REGISTER <= regno + && regno <= LAST_SAVRES_REGISTER); sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select]; if (sym == NULL) { - char name[30]; - const char *action; - const char *regkind; - const char *exit_suffix; - - action = savep ? "save" : "rest"; - - /* SPE has slightly different names for its routines depending on - whether we are saving 32-bit or 64-bit registers. */ - if (TARGET_SPE_ABI) - { - /* No floating point saves on the SPE. */ - gcc_assert (gpr); - - regkind = info->spe_64bit_regs_used ? "64gpr" : "32gpr"; - } - else - regkind = gpr ? "gpr" : "fpr"; - - exit_suffix = exitp ? "_x" : ""; + char *name; - sprintf (name, "_%s%s_%d%s", action, regkind, regno, exit_suffix); + name = rs6000_savres_routine_name (info, regno, savep, gpr, lr); sym = savres_routine_syms[regno-FIRST_SAVRES_REGISTER][select] = gen_rtx_SYMBOL_REF (Pmode, ggc_strdup (name)); + SYMBOL_REF_FLAGS (sym) |= SYMBOL_FLAG_FUNCTION; } return sym; @@ -18124,8 +18501,11 @@ rs6000_emit_stack_reset (rs6000_stack_t *info, if (frame_reg_rtx != sp_reg_rtx) { if (sp_offset != 0) - return emit_insn (gen_addsi3 (sp_reg_rtx, frame_reg_rtx, - GEN_INT (sp_offset))); + { + rtx dest_reg = savres ? gen_rtx_REG (Pmode, 11) : sp_reg_rtx; + return emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, + GEN_INT (sp_offset))); + } else if (!savres) return emit_move_insn (sp_reg_rtx, frame_reg_rtx); } @@ -18154,7 +18534,7 @@ static rtx rs6000_make_savres_rtx (rs6000_stack_t *info, rtx frame_reg_rtx, int save_area_offset, enum machine_mode reg_mode, - bool savep, bool gpr, bool exitp) + bool savep, bool gpr, bool lr) { int i; int offset, start_reg, end_reg, n_regs; @@ -18168,20 +18548,21 @@ rs6000_make_savres_rtx (rs6000_stack_t *info, : info->first_fp_reg_save); end_reg = gpr ? 32 : 64; n_regs = end_reg - start_reg; - p = rtvec_alloc ((exitp ? 4 : 3) + n_regs); + p = rtvec_alloc ((lr ? 4 : 3) + n_regs); - /* If we're saving registers, then we should never say we're exiting. */ - gcc_assert ((savep && !exitp) || !savep); - - if (exitp) + if (!savep && lr) RTVEC_ELT (p, offset++) = gen_rtx_RETURN (VOIDmode); RTVEC_ELT (p, offset++) = gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 65)); - sym = rs6000_savres_routine_sym (info, savep, gpr, exitp); + sym = rs6000_savres_routine_sym (info, savep, gpr, lr); RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, sym); - RTVEC_ELT (p, offset++) = gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 11)); + RTVEC_ELT (p, offset++) + = gen_rtx_USE (VOIDmode, + gen_rtx_REG (Pmode, DEFAULT_ABI != ABI_AIX ? 11 + : gpr && !lr ? 12 + : 1)); for (i = 0; i < end_reg - start_reg; i++) { @@ -18196,6 +18577,16 @@ rs6000_make_savres_rtx (rs6000_stack_t *info, savep ? reg : mem); } + if (savep && lr) + { + rtx addr, reg, mem; + reg = gen_rtx_REG (Pmode, 0); + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + GEN_INT (info->lr_save_offset)); + mem = gen_frame_mem (Pmode, addr); + RTVEC_ELT (p, i + offset) = gen_rtx_SET (VOIDmode, mem, reg); + } + return gen_rtx_PARALLEL (VOIDmode, p); } @@ -18216,7 +18607,10 @@ rs6000_reg_live_or_pic_offset_p (int reg) enum { SAVRES_MULTIPLE = 0x1, SAVRES_INLINE_FPRS = 0x2, - SAVRES_INLINE_GPRS = 0x4 + SAVRES_INLINE_GPRS = 0x4, + SAVRES_NOINLINE_GPRS_SAVES_LR = 0x8, + SAVRES_NOINLINE_FPRS_SAVES_LR = 0x10, + SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR = 0x20 }; /* Determine the strategy for savings/restoring registers. */ @@ -18231,6 +18625,7 @@ rs6000_savres_strategy (rs6000_stack_t *info, bool savep, bool savres_gprs_inline; bool noclobber_global_gprs = no_global_regs_above (info->first_gp_reg_save, /*gpr=*/true); + int strategy; using_multiple_p = (TARGET_MULTIPLE && ! TARGET_POWERPC64 && (!TARGET_SPE_ABI @@ -18250,6 +18645,10 @@ rs6000_savres_strategy (rs6000_stack_t *info, bool savep, || info->first_fp_reg_save == 64 || !no_global_regs_above (info->first_fp_reg_save, /*gpr=*/false) + /* The out-of-line FP routines use + double-precision stores; we can't use those + routines if we don't have such stores. */ + || (TARGET_HARD_FLOAT && !TARGET_DOUBLE_FLOAT) || FP_SAVE_INLINE (info->first_fp_reg_save)); savres_gprs_inline = (common /* Saving CR interferes with the exit routines @@ -18287,9 +18686,22 @@ rs6000_savres_strategy (rs6000_stack_t *info, bool savep, savres_gprs_inline = savres_gprs_inline || using_multiple_p; } - return (using_multiple_p - | (savres_fprs_inline << 1) - | (savres_gprs_inline << 2)); + strategy = (using_multiple_p + | (savres_fprs_inline << 1) + | (savres_gprs_inline << 2)); +#ifdef POWERPC_LINUX + if (TARGET_64BIT) + { + if (!savres_fprs_inline) + strategy |= SAVRES_NOINLINE_FPRS_SAVES_LR; + else if (!savres_gprs_inline && info->first_fp_reg_save == 64) + strategy |= SAVRES_NOINLINE_GPRS_SAVES_LR; + } +#else + if (TARGET_AIX && !savres_fprs_inline) + strategy |= SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR; +#endif + return strategy; } /* Emit function prologue as insns. */ @@ -18311,7 +18723,7 @@ rs6000_emit_prologue (void) int using_store_multiple; int using_static_chain_p = (cfun->static_chain_decl != NULL_TREE && df_regs_ever_live_p (STATIC_CHAIN_REGNUM) - && !call_used_regs[STATIC_CHAIN_REGNUM]); + && call_used_regs[STATIC_CHAIN_REGNUM]); HOST_WIDE_INT sp_offset = 0; if (TARGET_FIX_AND_CONTINUE) @@ -18496,24 +18908,30 @@ rs6000_emit_prologue (void) gen_rtx_REG (Pmode, LR_REGNO)); RTX_FRAME_RELATED_P (insn) = 1; - addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, + if (!(strategy & (SAVRES_NOINLINE_GPRS_SAVES_LR + | SAVRES_NOINLINE_FPRS_SAVES_LR))) + { + addr = gen_rtx_PLUS (Pmode, frame_reg_rtx, GEN_INT (info->lr_save_offset + sp_offset)); - reg = gen_rtx_REG (Pmode, 0); - mem = gen_rtx_MEM (Pmode, addr); - /* This should not be of rs6000_sr_alias_set, because of - __builtin_return_address. */ + reg = gen_rtx_REG (Pmode, 0); + mem = gen_rtx_MEM (Pmode, addr); + /* This should not be of rs6000_sr_alias_set, because of + __builtin_return_address. */ - insn = emit_move_insn (mem, reg); - rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, - NULL_RTX, NULL_RTX); + insn = emit_move_insn (mem, reg); + rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, + NULL_RTX, NULL_RTX); + } } - /* If we need to save CR, put it into r12. */ + /* If we need to save CR, put it into r12 or r11. */ if (!WORLD_SAVE_P (info) && info->cr_save_p && frame_reg_rtx != frame_ptr_rtx) { rtx set; - cr_save_rtx = gen_rtx_REG (SImode, 12); + cr_save_rtx + = gen_rtx_REG (SImode, DEFAULT_ABI == ABI_AIX && !saving_GPRs_inline + ? 11 : 12); insn = emit_insn (gen_movesi_from_cr (cr_save_rtx)); RTX_FRAME_RELATED_P (insn) = 1; /* Now, there's no way that dwarf2out_frame_debug_expr is going @@ -18550,7 +18968,9 @@ rs6000_emit_prologue (void) info->fp_save_offset + sp_offset, DFmode, /*savep=*/true, /*gpr=*/false, - /*exitp=*/false); + /*lr=*/(strategy + & SAVRES_NOINLINE_FPRS_SAVES_LR) + != 0); insn = emit_insn (par); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, NULL_RTX, NULL_RTX); @@ -18646,7 +19066,7 @@ rs6000_emit_prologue (void) par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11), 0, reg_mode, /*savep=*/true, /*gpr=*/true, - /*exitp=*/false); + /*lr=*/false); insn = emit_insn (par); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, NULL_RTX, NULL_RTX); @@ -18661,23 +19081,23 @@ rs6000_emit_prologue (void) { rtx par; - /* Need to adjust r11 if we saved any FPRs. */ + /* Need to adjust r11 (r12) if we saved any FPRs. */ if (info->first_fp_reg_save != 64) { - rtx r11 = gen_rtx_REG (reg_mode, 11); - rtx offset = GEN_INT (info->total_size + rtx dest_reg = gen_rtx_REG (reg_mode, DEFAULT_ABI == ABI_AIX + ? 12 : 11); + rtx offset = GEN_INT (sp_offset + (-8 * (64-info->first_fp_reg_save))); - rtx ptr_reg = (sp_reg_rtx == frame_reg_rtx - ? sp_reg_rtx : r11); - - emit_insn (gen_add3_insn (r11, ptr_reg, offset)); + emit_insn (gen_add3_insn (dest_reg, frame_reg_rtx, offset)); } par = rs6000_make_savres_rtx (info, frame_reg_rtx, info->gp_save_offset + sp_offset, reg_mode, /*savep=*/true, /*gpr=*/true, - /*exitp=*/false); + /*lr=*/(strategy + & SAVRES_NOINLINE_GPRS_SAVES_LR) + != 0); insn = emit_insn (par); rs6000_frame_related (insn, frame_ptr_rtx, info->total_size, NULL_RTX, NULL_RTX); @@ -18954,9 +19374,18 @@ rs6000_output_function_prologue (FILE *file, fp values. */ if (info->first_fp_reg_save < 64 && !FP_SAVE_INLINE (info->first_fp_reg_save)) - fprintf (file, "\t.extern %s%d%s\n\t.extern %s%d%s\n", - SAVE_FP_PREFIX, info->first_fp_reg_save - 32, SAVE_FP_SUFFIX, - RESTORE_FP_PREFIX, info->first_fp_reg_save - 32, RESTORE_FP_SUFFIX); + { + char *name; + int regno = info->first_fp_reg_save - 32; + + name = rs6000_savres_routine_name (info, regno, /*savep=*/true, + /*gpr=*/false, /*lr=*/false); + fprintf (file, "\t.extern %s\n", name); + + name = rs6000_savres_routine_name (info, regno, /*savep=*/false, + /*gpr=*/false, /*lr=*/true); + fprintf (file, "\t.extern %s\n", name); + } /* Write .extern for AIX common mode routines, if needed. */ if (! TARGET_POWER && ! TARGET_POWERPC && ! common_mode_defined) @@ -18972,6 +19401,8 @@ rs6000_output_function_prologue (FILE *file, if (! HAVE_prologue) { + rtx prologue; + start_sequence (); /* A NOTE_INSN_DELETED is supposed to be at the start and end of @@ -18991,10 +19422,14 @@ rs6000_output_function_prologue (FILE *file, } } - if (TARGET_DEBUG_STACK) - debug_rtx_list (get_insns (), 100); - final (get_insns (), file, FALSE); + prologue = get_insns (); end_sequence (); + + if (TARGET_DEBUG_STACK) + debug_rtx_list (prologue, 100); + + emit_insn_before_noloc (prologue, BB_HEAD (ENTRY_BLOCK_PTR->next_bb), + ENTRY_BLOCK_PTR); } rs6000_pic_labelno++; @@ -19082,6 +19517,7 @@ rs6000_emit_epilogue (int sibcall) rtx frame_reg_rtx = sp_reg_rtx; rtx cfa_restores = NULL_RTX; rtx insn; + rtx cr_save_reg = NULL_RTX; enum machine_mode reg_mode = Pmode; int reg_size = TARGET_32BIT ? 4 : 8; int i; @@ -19115,8 +19551,10 @@ rs6000_emit_epilogue (int sibcall) || (cfun->calls_alloca && !frame_pointer_needed)); restore_lr = (info->lr_save_p - && restoring_GPRs_inline - && restoring_FPRs_inline); + && (restoring_FPRs_inline + || (strategy & SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR)) + && (restoring_GPRs_inline + || info->first_fp_reg_save < 64)); if (WORLD_SAVE_P (info)) { @@ -19403,7 +19841,7 @@ rs6000_emit_epilogue (int sibcall) /* Get the old lr if we saved it. If we are restoring registers out-of-line, then the out-of-line routines can do this for us. */ - if (restore_lr) + if (restore_lr && restoring_GPRs_inline) { rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, info->lr_save_offset + sp_offset); @@ -19418,12 +19856,17 @@ rs6000_emit_epilogue (int sibcall) GEN_INT (info->cr_save_offset + sp_offset)); rtx mem = gen_frame_mem (SImode, addr); - emit_move_insn (gen_rtx_REG (SImode, 12), mem); + cr_save_reg = gen_rtx_REG (SImode, + DEFAULT_ABI == ABI_AIX + && !restoring_GPRs_inline + && info->first_fp_reg_save < 64 + ? 11 : 12); + emit_move_insn (cr_save_reg, mem); } /* Set LR here to try to overlap restores below. LR is always saved above incoming stack, so it never needs REG_CFA_RESTORE. */ - if (restore_lr) + if (restore_lr && restoring_GPRs_inline) emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO), gen_rtx_REG (Pmode, 0)); @@ -19540,7 +19983,7 @@ rs6000_emit_epilogue (int sibcall) par = rs6000_make_savres_rtx (info, gen_rtx_REG (Pmode, 11), 0, reg_mode, /*savep=*/false, /*gpr=*/true, - /*exitp=*/true); + /*lr=*/true); emit_jump_insn (par); /* We don't want anybody else emitting things after we jumped back. */ @@ -19558,21 +20001,25 @@ rs6000_emit_epilogue (int sibcall) rs6000_emit_stack_reset (info, sp_reg_rtx, frame_reg_rtx, sp_offset, can_use_exit); else - emit_insn (gen_addsi3 (gen_rtx_REG (Pmode, 11), - sp_reg_rtx, - GEN_INT (sp_offset - info->fp_size))); + { + emit_insn (gen_add3_insn (gen_rtx_REG (Pmode, DEFAULT_ABI == ABI_AIX + ? 12 : 11), + frame_reg_rtx, + GEN_INT (sp_offset - info->fp_size))); + if (REGNO (frame_reg_rtx) == 11) + sp_offset += info->fp_size; + } par = rs6000_make_savres_rtx (info, frame_reg_rtx, info->gp_save_offset, reg_mode, /*savep=*/false, /*gpr=*/true, - /*exitp=*/can_use_exit); + /*lr=*/can_use_exit); if (can_use_exit) { if (info->cr_save_p) { - rs6000_restore_saved_cr (gen_rtx_REG (SImode, 12), - using_mtcr_multiple); + rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple); if (DEFAULT_ABI == ABI_V4) cfa_restores = alloc_reg_note (REG_CFA_RESTORE, @@ -19659,6 +20106,16 @@ rs6000_emit_epilogue (int sibcall) } } + if (restore_lr && !restoring_GPRs_inline) + { + rtx mem = gen_frame_mem_offset (Pmode, frame_reg_rtx, + info->lr_save_offset + sp_offset); + + emit_move_insn (gen_rtx_REG (Pmode, 0), mem); + emit_move_insn (gen_rtx_REG (Pmode, LR_REGNO), + gen_rtx_REG (Pmode, 0)); + } + /* Restore fpr's if we need to do it without calling a function. */ if (restoring_FPRs_inline) for (i = 0; i < 64 - info->first_fp_reg_save; i++) @@ -19685,7 +20142,7 @@ rs6000_emit_epilogue (int sibcall) /* If we saved cr, restore it here. Just those that were used. */ if (info->cr_save_p) { - rs6000_restore_saved_cr (gen_rtx_REG (SImode, 12), using_mtcr_multiple); + rs6000_restore_saved_cr (cr_save_reg, using_mtcr_multiple); if (DEFAULT_ABI == ABI_V4) cfa_restores = alloc_reg_note (REG_CFA_RESTORE, gen_rtx_REG (SImode, CR2_REGNO), @@ -19716,13 +20173,14 @@ rs6000_emit_epilogue (int sibcall) if (!sibcall) { rtvec p; + bool lr = (strategy & SAVRES_NOINLINE_FPRS_DOESNT_RESTORE_LR) == 0; if (! restoring_FPRs_inline) p = rtvec_alloc (4 + 64 - info->first_fp_reg_save); else p = rtvec_alloc (2); RTVEC_ELT (p, 0) = gen_rtx_RETURN (VOIDmode); - RTVEC_ELT (p, 1) = (restoring_FPRs_inline + RTVEC_ELT (p, 1) = ((restoring_FPRs_inline || !lr) ? gen_rtx_USE (VOIDmode, gen_rtx_REG (Pmode, 65)) : gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (Pmode, 65))); @@ -19737,10 +20195,12 @@ rs6000_emit_epilogue (int sibcall) sym = rs6000_savres_routine_sym (info, /*savep=*/false, /*gpr=*/false, - /*exitp=*/true); + /*lr=*/lr); RTVEC_ELT (p, 2) = gen_rtx_USE (VOIDmode, sym); RTVEC_ELT (p, 3) = gen_rtx_USE (VOIDmode, - gen_rtx_REG (Pmode, 11)); + gen_rtx_REG (Pmode, + DEFAULT_ABI == ABI_AIX + ? 1 : 11)); for (i = 0; i < 64 - info->first_fp_reg_save; i++) { rtx addr, mem; @@ -19884,8 +20344,10 @@ rs6000_output_function_epilogue (FILE *file, use language_string. C is 0. Fortran is 1. Pascal is 2. Ada is 3. C++ is 9. Java is 13. Objective-C is 14. Objective-C++ isn't assigned - a number, so for now use 9. */ - if (! strcmp (language_string, "GNU C")) + a number, so for now use 9. LTO isn't assigned a number either, + so for now use 0. */ + if (! strcmp (language_string, "GNU C") + || ! strcmp (language_string, "GNU GIMPLE")) i = 0; else if (! strcmp (language_string, "GNU F77") || ! strcmp (language_string, "GNU Fortran")) @@ -20978,9 +21440,7 @@ static int load_store_pendulum; instructions to issue in this cycle. */ static int -rs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED, - int verbose ATTRIBUTE_UNUSED, - rtx insn, int more) +rs6000_variable_issue_1 (rtx insn, int more) { last_scheduled_insn = insn; if (GET_CODE (PATTERN (insn)) == USE @@ -21019,6 +21479,15 @@ rs6000_variable_issue (FILE *stream ATTRIBUTE_UNUSED, return cached_can_issue_more; } +static int +rs6000_variable_issue (FILE *stream, int verbose, rtx insn, int more) +{ + int r = rs6000_variable_issue_1 (insn, more); + if (verbose) + fprintf (stream, "// rs6000_variable_issue (more = %d) = %d\n", more, r); + return r; +} + /* Adjust the cost of a scheduling dependency. Return the new cost of a dependency LINK or INSN on DEP_INSN. COST is the current cost. */ @@ -21592,8 +22061,9 @@ is_nonpipeline_insn (rtx insn) static int rs6000_issue_rate (void) { - /* Use issue rate of 1 for first scheduling pass to decrease degradation. */ - if (!reload_completed) + /* Unless scheduling for register pressure, use issue rate of 1 for + first scheduling pass to decrease degradation. */ + if (!reload_completed && !flag_sched_pressure) return 1; switch (rs6000_cpu_attr) { @@ -21611,8 +22081,10 @@ rs6000_issue_rate (void) case CPU_PPCE300C2: case CPU_PPCE300C3: case CPU_PPCE500MC: + case CPU_PPCE500MC64: return 2; case CPU_RIOS2: + case CPU_PPC476: case CPU_PPC604: case CPU_PPC604E: case CPU_PPC620: @@ -22802,32 +23274,38 @@ rs6000_trampoline_size (void) FNADDR is an RTX for the address of the function's pure code. CXT is an RTX for the static chain value for the function. */ -void -rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt) +static void +rs6000_trampoline_init (rtx m_tramp, tree fndecl, rtx cxt) { int regsize = (TARGET_32BIT) ? 4 : 8; + rtx fnaddr = XEXP (DECL_RTL (fndecl), 0); rtx ctx_reg = force_reg (Pmode, cxt); + rtx addr = force_reg (Pmode, XEXP (m_tramp, 0)); switch (DEFAULT_ABI) { default: gcc_unreachable (); -/* Macros to shorten the code expansions below. */ -#define MEM_DEREF(addr) gen_rtx_MEM (Pmode, memory_address (Pmode, addr)) -#define MEM_PLUS(addr,offset) \ - gen_rtx_MEM (Pmode, memory_address (Pmode, plus_constant (addr, offset))) - /* Under AIX, just build the 3 word function descriptor */ case ABI_AIX: { + rtx fnmem = gen_const_mem (Pmode, force_reg (Pmode, fnaddr)); rtx fn_reg = gen_reg_rtx (Pmode); rtx toc_reg = gen_reg_rtx (Pmode); - emit_move_insn (fn_reg, MEM_DEREF (fnaddr)); - emit_move_insn (toc_reg, MEM_PLUS (fnaddr, regsize)); - emit_move_insn (MEM_DEREF (addr), fn_reg); - emit_move_insn (MEM_PLUS (addr, regsize), toc_reg); - emit_move_insn (MEM_PLUS (addr, 2*regsize), ctx_reg); + + /* Macro to shorten the code expansions below. */ +# define MEM_PLUS(MEM, OFFSET) adjust_address (MEM, Pmode, OFFSET) + + m_tramp = replace_equiv_address (m_tramp, addr); + + emit_move_insn (fn_reg, MEM_PLUS (fnmem, 0)); + emit_move_insn (toc_reg, MEM_PLUS (fnmem, regsize)); + emit_move_insn (MEM_PLUS (m_tramp, 0), fn_reg); + emit_move_insn (MEM_PLUS (m_tramp, regsize), toc_reg); + emit_move_insn (MEM_PLUS (m_tramp, 2*regsize), ctx_reg); + +# undef MEM_PLUS } break; @@ -22842,11 +23320,18 @@ rs6000_initialize_trampoline (rtx addr, rtx fnaddr, rtx cxt) ctx_reg, Pmode); break; } - - return; } +/* Returns TRUE iff the target attribute indicated by ATTR_ID takes a plain + identifier as an argument, so the front end shouldn't look it up. */ + +static bool +rs6000_attribute_takes_identifier_p (const_tree attr_id) +{ + return is_attribute_p ("altivec", attr_id); +} + /* Handle the "altivec" attribute. The attribute may have arguments as follows: @@ -24419,7 +24904,10 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total, { if (XEXP (x, 1) == const0_rtx) { - *total = COSTS_N_INSNS (2); + if (TARGET_ISEL && !TARGET_MFCRF) + *total = COSTS_N_INSNS (8); + else + *total = COSTS_N_INSNS (2); return true; } else if (mode == Pmode) @@ -24435,7 +24923,10 @@ rs6000_rtx_costs (rtx x, int code, int outer_code, int *total, case UNORDERED: if (outer_code == SET && (XEXP (x, 1) == const0_rtx)) { - *total = COSTS_N_INSNS (2); + if (TARGET_ISEL && !TARGET_MFCRF) + *total = COSTS_N_INSNS (8); + else + *total = COSTS_N_INSNS (2); return true; } /* CC COMPARE. */ @@ -24925,10 +25416,7 @@ rs6000_complex_function_value (enum machine_mode mode) return gen_rtx_PARALLEL (mode, gen_rtvec (2, r1, r2)); } -/* Define how to find the value returned by a function. - VALTYPE is the data type of the value (as a tree). - If the precise function being called is known, FUNC is its FUNCTION_DECL; - otherwise, FUNC is 0. +/* Target hook for TARGET_FUNCTION_VALUE. On the SPE, both FPs and vectors are returned in r3. @@ -24936,7 +25424,9 @@ rs6000_complex_function_value (enum machine_mode mode) fp1, unless -msoft-float. */ rtx -rs6000_function_value (const_tree valtype, const_tree func ATTRIBUTE_UNUSED) +rs6000_function_value (const_tree valtype, + const_tree fn_decl_or_type ATTRIBUTE_UNUSED, + bool outgoing ATTRIBUTE_UNUSED) { enum machine_mode mode; unsigned int regno; @@ -25235,7 +25725,7 @@ static bool rs6000_scalar_mode_supported_p (enum machine_mode mode) { if (DECIMAL_FLOAT_MODE_P (mode)) - return true; + return default_decimal_float_supported_p (); else return default_scalar_mode_supported_p (mode); }