X-Git-Url: http://git.sourceforge.jp/view?a=blobdiff_plain;f=gcc%2Fconfig%2Frs6000%2Frs6000.c;h=df7a428b7be7ad15d0735143ada8059d1e28f061;hb=85b6149ccfe15c219485d77d7b616b9c6cfbe699;hp=828506587315e62d11c6596dc1ccad9178ed7ac4;hpb=53d337172925a81f0f6086760c675ac0834d764d;p=pf3gnuchains%2Fgcc-fork.git diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index 82850658731..df7a428b7be 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -27,7 +27,6 @@ #include "rtl.h" #include "regs.h" #include "hard-reg-set.h" -#include "real.h" #include "insn-config.h" #include "conditions.h" #include "insn-attr.h" @@ -42,6 +41,7 @@ #include "output.h" #include "basic-block.h" #include "integrate.h" +#include "diagnostic-core.h" #include "toplev.h" #include "ggc.h" #include "hashtab.h" @@ -51,6 +51,7 @@ #include "langhooks.h" #include "reload.h" #include "cfglayout.h" +#include "cfgloop.h" #include "sched-int.h" #include "gimple.h" #include "tree-flow.h" @@ -73,6 +74,7 @@ /* Structure used to define the rs6000 stack */ typedef struct rs6000_stack { + int reload_completed; /* stack info won't change from here on */ int first_gp_reg_save; /* first callee saved GP register used */ int first_fp_reg_save; /* first callee saved FP register used */ int first_altivec_reg_save; /* first callee saved AltiVec register used */ @@ -109,20 +111,23 @@ typedef struct rs6000_stack { int spe_padding_size; HOST_WIDE_INT total_size; /* total bytes allocated for stack */ int spe_64bit_regs_used; + int savres_strategy; } rs6000_stack_t; /* A C structure for machine-specific, per-function data. This is added to the cfun structure. */ typedef struct GTY(()) machine_function { - /* Flags if __builtin_return_address (n) with n >= 1 was used. */ - int ra_needs_full_frame; /* Some local-dynamic symbol. */ const char *some_ld_name; /* Whether the instruction chain has been scanned already. */ int insn_chain_scanned_p; + /* Flags if __builtin_return_address (n) with n >= 1 was used. */ + int ra_needs_full_frame; /* Flags if __builtin_return_address (0) was used. */ int ra_need_lr; + /* Cache lr_save_p after expansion of builtin_eh_return. */ + int lr_save_state; /* Offset from virtual_stack_vars_rtx to the start of the ABI_V4 varargs save area. */ HOST_WIDE_INT varargs_save_offset; @@ -134,7 +139,6 @@ typedef struct GTY(()) machine_function /* Target cpu type */ -enum processor_type rs6000_cpu; struct rs6000_cpu_select rs6000_select[3] = { /* switch name, tune arch */ @@ -143,86 +147,34 @@ struct rs6000_cpu_select rs6000_select[3] = { (const char *)0, "-mtune=", 1, 0 }, }; -/* Always emit branch hint bits. */ -static GTY(()) bool rs6000_always_hint; +/* String variables to hold the various options. */ +static const char *rs6000_sched_insert_nops_str; +static const char *rs6000_sched_costly_dep_str; +static const char *rs6000_recip_name; -/* Schedule instructions for group formation. */ -static GTY(()) bool rs6000_sched_groups; - -/* Align branch targets. */ -static GTY(()) bool rs6000_align_branch_targets; - -/* Support for -msched-costly-dep option. */ -const char *rs6000_sched_costly_dep_str; -enum rs6000_dependence_cost rs6000_sched_costly_dep; - -/* Support for -minsert-sched-nops option. */ -const char *rs6000_sched_insert_nops_str; -enum rs6000_nop_insertion rs6000_sched_insert_nops; +#ifdef USING_ELFOS_H +static const char *rs6000_abi_name; +static const char *rs6000_sdata_name; +#endif /* Support targetm.vectorize.builtin_mask_for_load. */ static GTY(()) tree altivec_builtin_mask_for_load; -/* Size of long double. */ -int rs6000_long_double_type_size; - -/* IEEE quad extended precision long double. */ -int rs6000_ieeequad; - -/* Nonzero to use AltiVec ABI. */ -int rs6000_altivec_abi; - -/* Nonzero if we want SPE SIMD instructions. */ -int rs6000_spe; - -/* Nonzero if we want SPE ABI extensions. */ -int rs6000_spe_abi; - -/* Nonzero if floating point operations are done in the GPRs. */ -int rs6000_float_gprs = 0; - -/* Nonzero if we want Darwin's struct-by-value-in-regs ABI. */ -int rs6000_darwin64_abi; - /* Set to nonzero once AIX common-mode calls have been defined. */ static GTY(()) int common_mode_defined; /* Label number of label created for -mrelocatable, to call to so we can get the address of the GOT section */ -int rs6000_pic_labelno; +static int rs6000_pic_labelno; #ifdef USING_ELFOS_H -/* Which abi to adhere to */ -const char *rs6000_abi_name; - -/* Semantics of the small data area */ -enum rs6000_sdata_type rs6000_sdata = SDATA_DATA; - -/* Which small data model to use */ -const char *rs6000_sdata_name = (char *)0; - /* Counter for labels which are to be placed in .fixup. */ int fixuplabelno = 0; #endif -/* Bit size of immediate TLS offsets and string from which it is decoded. */ -int rs6000_tls_size = 32; -const char *rs6000_tls_size_string; - -/* ABI enumeration available for subtarget to use. */ -enum rs6000_abi rs6000_current_abi; - /* Whether to use variant of AIX ABI for PowerPC64 Linux. */ int dot_symbols; -/* Debug flags */ -const char *rs6000_debug_name; -int rs6000_debug_stack; /* debug stack applications */ -int rs6000_debug_arg; /* debug argument handling */ -int rs6000_debug_reg; /* debug register classes */ -int rs6000_debug_addr; /* debug memory addressing */ -int rs6000_debug_cost; /* debug rtx_costs */ - /* Specify the machine mode that pointers have. After generation of rtl, the compiler makes no further distinction between pointers and any other objects of this machine mode. The type is unsigned since not all things that @@ -252,14 +204,6 @@ static enum insn_code rs6000_vector_reload[NUM_MACHINE_MODES][2]; tree rs6000_builtin_types[RS6000_BTI_MAX]; tree rs6000_builtin_decls[RS6000_BUILTIN_COUNT]; -const char *rs6000_traceback_name; -static enum { - traceback_default = 0, - traceback_none, - traceback_part, - traceback_full -} rs6000_traceback; - /* Flag to say the TOC is initialized */ int toc_initialized; char toc_label_name[10]; @@ -274,10 +218,6 @@ static GTY(()) section *read_only_private_data_section; static GTY(()) section *sdata2_section; static GTY(()) section *toc_section; -/* Control alignment for fields within structures. */ -/* String from -malign-XXXXX. */ -int rs6000_alignment_flags; - /* True for any options that were explicitly set. */ static struct { bool aix_struct_ret; /* True if -maix-struct-ret was used. */ @@ -289,6 +229,7 @@ static struct { bool long_double; /* True if -mlong-double- was used. */ bool ieee; /* True if -mabi=ieee/ibmlongdouble used. */ bool vrsave; /* True if -mvrsave was used. */ + bool cmodel; /* True if -mcmodel was used. */ } rs6000_explicit_options; struct builtin_description @@ -315,6 +256,58 @@ int rs6000_vector_align[NUM_MACHINE_MODES]; /* Map selected modes to types for builtins. */ static GTY(()) tree builtin_mode_to_type[MAX_MACHINE_MODE][2]; + +/* What modes to automatically generate reciprocal divide estimate (fre) and + reciprocal sqrt (frsqrte) for. */ +unsigned char rs6000_recip_bits[MAX_MACHINE_MODE]; + +/* Masks to determine which reciprocal esitmate instructions to generate + automatically. */ +enum rs6000_recip_mask { + RECIP_SF_DIV = 0x001, /* Use divide estimate */ + RECIP_DF_DIV = 0x002, + RECIP_V4SF_DIV = 0x004, + RECIP_V2DF_DIV = 0x008, + + RECIP_SF_RSQRT = 0x010, /* Use reciprocal sqrt estimate. */ + RECIP_DF_RSQRT = 0x020, + RECIP_V4SF_RSQRT = 0x040, + RECIP_V2DF_RSQRT = 0x080, + + /* Various combination of flags for -mrecip=xxx. */ + RECIP_NONE = 0, + RECIP_ALL = (RECIP_SF_DIV | RECIP_DF_DIV | RECIP_V4SF_DIV + | RECIP_V2DF_DIV | RECIP_SF_RSQRT | RECIP_DF_RSQRT + | RECIP_V4SF_RSQRT | RECIP_V2DF_RSQRT), + + RECIP_HIGH_PRECISION = RECIP_ALL, + + /* On low precision machines like the power5, don't enable double precision + reciprocal square root estimate, since it isn't accurate enough. */ + RECIP_LOW_PRECISION = (RECIP_ALL & ~(RECIP_DF_RSQRT | RECIP_V2DF_RSQRT)) +}; + +/* -mrecip options. */ +static struct +{ + const char *string; /* option name */ + unsigned int mask; /* mask bits to set */ +} recip_options[] = { + { "all", RECIP_ALL }, + { "none", RECIP_NONE }, + { "div", (RECIP_SF_DIV | RECIP_DF_DIV | RECIP_V4SF_DIV + | RECIP_V2DF_DIV) }, + { "divf", (RECIP_SF_DIV | RECIP_V4SF_DIV) }, + { "divd", (RECIP_DF_DIV | RECIP_V2DF_DIV) }, + { "rsqrt", (RECIP_SF_RSQRT | RECIP_DF_RSQRT | RECIP_V4SF_RSQRT + | RECIP_V2DF_RSQRT) }, + { "rsqrtf", (RECIP_SF_RSQRT | RECIP_V4SF_RSQRT) }, + { "rsqrtd", (RECIP_DF_RSQRT | RECIP_V2DF_RSQRT) }, +}; + +/* 2 argument gen function typedef. */ +typedef rtx (*gen_2arg_fn_t) (rtx, rtx, rtx); + /* Target cpu costs. */ @@ -778,6 +771,25 @@ struct processor_costs ppce500mc64_cost = { 1, /* prefetch streams /*/ }; +/* Instruction costs on AppliedMicro Titan processors. */ +static const +struct processor_costs titan_cost = { + COSTS_N_INSNS (5), /* mulsi */ + COSTS_N_INSNS (5), /* mulsi_const */ + COSTS_N_INSNS (5), /* mulsi_const9 */ + COSTS_N_INSNS (5), /* muldi */ + COSTS_N_INSNS (18), /* divsi */ + COSTS_N_INSNS (18), /* divdi */ + COSTS_N_INSNS (10), /* fp */ + COSTS_N_INSNS (10), /* dmul */ + COSTS_N_INSNS (46), /* sdiv */ + COSTS_N_INSNS (72), /* ddiv */ + 32, /* cache line size */ + 32, /* l1 cache */ + 512, /* l2 cache */ + 1, /* prefetch streams /*/ +}; + /* Instruction costs on POWER4 and POWER5 processors. */ static const struct processor_costs power4_cost = { @@ -869,6 +881,9 @@ static const enum rs6000_btc builtin_classify[(int)RS6000_BUILTIN_COUNT] = #undef RS6000_BUILTIN #undef RS6000_BUILTIN_EQUATE +/* Support for -mveclibabi= to control which vector library to use. */ +static tree (*rs6000_veclib_handler) (tree, tree, tree); + static bool rs6000_function_ok_for_sibcall (tree, tree); static const char *rs6000_invalid_within_doloop (const_rtx); @@ -881,7 +896,6 @@ static bool spe_func_has_64bit_regs_p (void); static void emit_frame_save (rtx, rtx, enum machine_mode, unsigned int, int, HOST_WIDE_INT); static rtx gen_frame_mem_offset (enum machine_mode, rtx, int); -static void rs6000_emit_allocate_stack (HOST_WIDE_INT, int, int); static unsigned rs6000_hash_constant (rtx); static unsigned toc_hash_function (const void *); static int toc_hash_eq (const void *, const void *); @@ -897,6 +911,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); @@ -909,9 +924,10 @@ 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 int rs6000_savres_strategy (rs6000_stack_t *, bool, int, int); +static tree rs6000_builtin_vectorized_libmass (tree, tree, tree); +static tree rs6000_builtin_vectorized_function (tree, tree, tree); static void rs6000_restore_saved_cr (rtx, int); +static bool rs6000_output_addr_const_extra (FILE *, rtx); static void rs6000_output_function_prologue (FILE *, HOST_WIDE_INT); static void rs6000_output_function_epilogue (FILE *, HOST_WIDE_INT); static void rs6000_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, @@ -951,6 +967,9 @@ static void rs6000_xcoff_file_start (void); static void rs6000_xcoff_file_end (void); #endif static int rs6000_variable_issue (FILE *, int, rtx, int); +static int rs6000_register_move_cost (enum machine_mode, + reg_class_t, reg_class_t); +static int rs6000_memory_move_cost (enum machine_mode, reg_class_t, bool); static bool rs6000_rtx_costs (rtx, int, int, int *, bool); static bool rs6000_debug_rtx_costs (rtx, int, int, int *, bool); static int rs6000_debug_address_cost (rtx, bool); @@ -990,12 +1009,15 @@ 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, const_tree, int, bool); +static int rs6000_builtin_vectorization_cost (enum vect_cost_for_stmt, + tree, int); +static enum machine_mode rs6000_preferred_simd_mode (enum machine_mode); static void def_builtin (int, const char *, tree, int); static bool rs6000_vector_alignment_reachable (const_tree, bool); @@ -1044,8 +1066,11 @@ static rtx altivec_expand_vec_init_builtin (tree, tree, rtx); static rtx altivec_expand_vec_set_builtin (tree); static rtx altivec_expand_vec_ext_builtin (tree, rtx); static int get_element_number (tree, tree); +static void rs6000_option_override (void); +static void rs6000_option_init_struct (struct gcc_options *); +static void rs6000_option_default_params (void); static bool rs6000_handle_option (size_t, const char *, int); -static void rs6000_parse_tls_size_option (void); +static int rs6000_loop_align_max_skip (rtx); static void rs6000_parse_yes_no_option (const char *, const char *, int *); static int first_altivec_reg_to_save (void); static unsigned int compute_vrsave_mask (void); @@ -1066,20 +1091,27 @@ static int rs6000_tls_symbol_ref_1 (rtx *, void *); static const char *rs6000_get_some_local_dynamic_name (void); static int rs6000_get_some_local_dynamic_name_1 (rtx *, void *); static rtx rs6000_complex_function_value (enum machine_mode); -static rtx rs6000_spe_function_arg (CUMULATIVE_ARGS *, - enum machine_mode, tree); +static rtx rs6000_spe_function_arg (const CUMULATIVE_ARGS *, + enum machine_mode, const_tree); static void rs6000_darwin64_record_arg_advance_flush (CUMULATIVE_ARGS *, - HOST_WIDE_INT); + HOST_WIDE_INT, int); static void rs6000_darwin64_record_arg_advance_recurse (CUMULATIVE_ARGS *, - tree, HOST_WIDE_INT); + const_tree, + HOST_WIDE_INT); static void rs6000_darwin64_record_arg_flush (CUMULATIVE_ARGS *, HOST_WIDE_INT, rtx[], int *); static void rs6000_darwin64_record_arg_recurse (CUMULATIVE_ARGS *, const_tree, HOST_WIDE_INT, rtx[], int *); -static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree, int, bool); -static rtx rs6000_mixed_function_arg (enum machine_mode, tree, int); +static rtx rs6000_darwin64_record_arg (CUMULATIVE_ARGS *, const_tree, bool, bool); +static rtx rs6000_mixed_function_arg (enum machine_mode, const_tree, int); +static void rs6000_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode, + const_tree, bool); +static rtx rs6000_function_arg (CUMULATIVE_ARGS *, enum machine_mode, + const_tree, bool); +static unsigned int rs6000_function_arg_boundary (enum machine_mode, + const_tree); static void rs6000_move_block_from_reg (int regno, rtx x, int nregs); static void setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, @@ -1117,9 +1149,10 @@ rtx (*rs6000_legitimize_reload_address_ptr) (rtx, enum machine_mode, int, int, int, int *) = rs6000_legitimize_reload_address; -static bool rs6000_mode_dependent_address (rtx); -static bool rs6000_debug_mode_dependent_address (rtx); -bool (*rs6000_mode_dependent_address_ptr) (rtx) +static bool rs6000_mode_dependent_address_p (const_rtx); +static bool rs6000_mode_dependent_address (const_rtx); +static bool rs6000_debug_mode_dependent_address (const_rtx); +static bool (*rs6000_mode_dependent_address_ptr) (const_rtx) = rs6000_mode_dependent_address; static enum reg_class rs6000_secondary_reload_class (enum reg_class, @@ -1160,15 +1193,16 @@ bool (*rs6000_cannot_change_mode_class_ptr) (enum machine_mode, enum reg_class) = rs6000_cannot_change_mode_class; -static enum reg_class rs6000_secondary_reload (bool, rtx, enum reg_class, - enum machine_mode, - struct secondary_reload_info *); +static reg_class_t rs6000_secondary_reload (bool, rtx, reg_class_t, + enum machine_mode, + struct secondary_reload_info *); -static const enum reg_class *rs6000_ira_cover_classes (void); +static const reg_class_t *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_conditional_register_usage (void); static void rs6000_trampoline_init (rtx, tree, rtx); /* Hash table stuff for keeping track of TOC entries. */ @@ -1194,6 +1228,15 @@ struct GTY(()) builtin_hash_struct }; static GTY ((param_is (struct builtin_hash_struct))) htab_t builtin_hash_table; + +static bool rs6000_valid_attribute_p (tree, tree, tree, int); +static void rs6000_function_specific_save (struct cl_target_option *); +static void rs6000_function_specific_restore (struct cl_target_option *); +static void rs6000_function_specific_print (FILE *, int, + struct cl_target_option *); +static bool rs6000_can_inline_p (tree, tree); +static void rs6000_set_current_function (tree); + /* Default register names. */ char rs6000_reg_names[][8] = @@ -1208,7 +1251,7 @@ char rs6000_reg_names[][8] = "24", "25", "26", "27", "28", "29", "30", "31", "mq", "lr", "ctr","ap", "0", "1", "2", "3", "4", "5", "6", "7", - "xer", + "ca", /* AltiVec registers. */ "0", "1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", @@ -1234,7 +1277,7 @@ static const char alt_reg_names[][8] = "%f24", "%f25", "%f26", "%f27", "%f28", "%f29", "%f30", "%f31", "mq", "lr", "ctr", "ap", "%cr0", "%cr1", "%cr2", "%cr3", "%cr4", "%cr5", "%cr6", "%cr7", - "xer", + "ca", /* AltiVec registers. */ "%v0", "%v1", "%v2", "%v3", "%v4", "%v5", "%v6", "%v7", "%v8", "%v9", "%v10", "%v11", "%v12", "%v13", "%v14", "%v15", @@ -1263,15 +1306,19 @@ static const struct attribute_spec rs6000_attribute_table[] = #endif { NULL, 0, 0, false, false, false, NULL } }; + +/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */ +static const struct default_options rs6000_option_optimization_table[] = + { + { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 }, + { OPT_LEVELS_NONE, 0, NULL, 0 } + }; #ifndef MASK_STRICT_ALIGN #define MASK_STRICT_ALIGN 0 #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. */ @@ -1282,6 +1329,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 @@ -1335,6 +1384,9 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_ASM_FUNCTION_EPILOGUE #define TARGET_ASM_FUNCTION_EPILOGUE rs6000_output_function_epilogue +#undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA +#define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA rs6000_output_addr_const_extra + #undef TARGET_LEGITIMIZE_ADDRESS #define TARGET_LEGITIMIZE_ADDRESS rs6000_legitimize_address @@ -1383,11 +1435,17 @@ static const struct attribute_spec rs6000_attribute_table[] = #define TARGET_VECTORIZE_BUILTIN_CONVERSION rs6000_builtin_conversion #undef TARGET_VECTORIZE_BUILTIN_VEC_PERM #define TARGET_VECTORIZE_BUILTIN_VEC_PERM rs6000_builtin_vec_perm -#undef TARGET_SUPPORT_VECTOR_MISALIGNMENT -#define TARGET_SUPPORT_VECTOR_MISALIGNMENT \ +#undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT +#define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \ rs6000_builtin_support_vector_misalignment -#undef TARGET_VECTOR_ALIGNMENT_REACHABLE -#define TARGET_VECTOR_ALIGNMENT_REACHABLE rs6000_vector_alignment_reachable +#undef TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE +#define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE rs6000_vector_alignment_reachable +#undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST +#define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST \ + rs6000_builtin_vectorization_cost +#undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE +#define TARGET_VECTORIZE_PREFERRED_SIMD_MODE \ + rs6000_preferred_simd_mode #undef TARGET_INIT_BUILTINS #define TARGET_INIT_BUILTINS rs6000_init_builtins @@ -1423,6 +1481,10 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_INVALID_WITHIN_DOLOOP #define TARGET_INVALID_WITHIN_DOLOOP rs6000_invalid_within_doloop +#undef TARGET_REGISTER_MOVE_COST +#define TARGET_REGISTER_MOVE_COST rs6000_register_move_cost +#undef TARGET_MEMORY_MOVE_COST +#define TARGET_MEMORY_MOVE_COST rs6000_memory_move_cost #undef TARGET_RTX_COSTS #define TARGET_RTX_COSTS rs6000_rtx_costs #undef TARGET_ADDRESS_COST @@ -1458,6 +1520,12 @@ static const struct attribute_spec rs6000_attribute_table[] = #define TARGET_PASS_BY_REFERENCE rs6000_pass_by_reference #undef TARGET_ARG_PARTIAL_BYTES #define TARGET_ARG_PARTIAL_BYTES rs6000_arg_partial_bytes +#undef TARGET_FUNCTION_ARG_ADVANCE +#define TARGET_FUNCTION_ARG_ADVANCE rs6000_function_arg_advance +#undef TARGET_FUNCTION_ARG +#define TARGET_FUNCTION_ARG rs6000_function_arg +#undef TARGET_FUNCTION_ARG_BOUNDARY +#define TARGET_FUNCTION_ARG_BOUNDARY rs6000_function_arg_boundary #undef TARGET_BUILD_BUILTIN_VA_LIST #define TARGET_BUILD_BUILTIN_VA_LIST rs6000_build_builtin_va_list @@ -1483,6 +1551,21 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_HANDLE_OPTION #define TARGET_HANDLE_OPTION rs6000_handle_option +#undef TARGET_ASM_LOOP_ALIGN_MAX_SKIP +#define TARGET_ASM_LOOP_ALIGN_MAX_SKIP rs6000_loop_align_max_skip + +#undef TARGET_OPTION_OVERRIDE +#define TARGET_OPTION_OVERRIDE rs6000_option_override + +#undef TARGET_OPTION_INIT_STRUCT +#define TARGET_OPTION_INIT_STRUCT rs6000_option_init_struct + +#undef TARGET_OPTION_DEFAULT_PARAMS +#define TARGET_OPTION_DEFAULT_PARAMS rs6000_option_default_params + +#undef TARGET_OPTION_OPTIMIZATION_TABLE +#define TARGET_OPTION_OPTIMIZATION_TABLE rs6000_option_optimization_table + #undef TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION #define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION \ rs6000_builtin_vectorized_function @@ -1542,17 +1625,228 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_LEGITIMATE_ADDRESS_P #define TARGET_LEGITIMATE_ADDRESS_P rs6000_legitimate_address_p +#undef TARGET_MODE_DEPENDENT_ADDRESS_P +#define TARGET_MODE_DEPENDENT_ADDRESS_P rs6000_mode_dependent_address_p + #undef TARGET_CAN_ELIMINATE #define TARGET_CAN_ELIMINATE rs6000_can_eliminate +#undef TARGET_CONDITIONAL_REGISTER_USAGE +#define TARGET_CONDITIONAL_REGISTER_USAGE rs6000_conditional_register_usage + #undef TARGET_TRAMPOLINE_INIT #define TARGET_TRAMPOLINE_INIT rs6000_trampoline_init #undef TARGET_FUNCTION_VALUE #define TARGET_FUNCTION_VALUE rs6000_function_value +#undef TARGET_OPTION_VALID_ATTRIBUTE_P +#define TARGET_OPTION_VALID_ATTRIBUTE_P rs6000_valid_attribute_p + +#undef TARGET_OPTION_SAVE +#define TARGET_OPTION_SAVE rs6000_function_specific_save + +#undef TARGET_OPTION_RESTORE +#define TARGET_OPTION_RESTORE rs6000_function_specific_restore + +#undef TARGET_OPTION_PRINT +#define TARGET_OPTION_PRINT rs6000_function_specific_print + +#undef TARGET_CAN_INLINE_P +#define TARGET_CAN_INLINE_P rs6000_can_inline_p + +#undef TARGET_SET_CURRENT_FUNCTION +#define TARGET_SET_CURRENT_FUNCTION rs6000_set_current_function + struct gcc_target targetm = TARGET_INITIALIZER; + +/* Simplifications for entries below. */ + +enum { + POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS, + POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC +}; + +/* Some OSs don't support saving the high part of 64-bit registers on context + switch. Other OSs don't support saving Altivec registers. On those OSs, we + don't touch the MASK_POWERPC64 or MASK_ALTIVEC settings; if the user wants + either, the user must explicitly specify them and we won't interfere with + the user's specification. */ + +enum { + POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING, + POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT | MASK_STRICT_ALIGN + | 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_NO_UPDATE + | MASK_RECIP_PRECISION) +}; + +/* Masks for instructions set at various powerpc ISAs. */ +enum { + ISA_2_1_MASKS = MASK_MFCRF, + ISA_2_2_MASKS = (ISA_2_1_MASKS | MASK_POPCNTB), + ISA_2_4_MASKS = (ISA_2_2_MASKS | MASK_FPRND), + + /* For ISA 2.05, do not add MFPGPR, since it isn't in ISA 2.06, and don't add + ALTIVEC, since in general it isn't a win on power6. In ISA 2.04, fsel, + fre, fsqrt, etc. were no longer documented as optional. Group masks by + server and embedded. */ + ISA_2_5_MASKS_EMBEDDED = (ISA_2_2_MASKS | MASK_CMPB | MASK_RECIP_PRECISION + | MASK_PPC_GFXOPT | MASK_PPC_GPOPT), + ISA_2_5_MASKS_SERVER = (ISA_2_5_MASKS_EMBEDDED | MASK_DFP), + + /* For ISA 2.06, don't add ISEL, since in general it isn't a win, but + altivec is a win so enable it. */ + ISA_2_6_MASKS_EMBEDDED = (ISA_2_5_MASKS_EMBEDDED | MASK_POPCNTD), + ISA_2_6_MASKS_SERVER = (ISA_2_5_MASKS_SERVER | MASK_POPCNTD | MASK_ALTIVEC + | MASK_VSX) +}; + +/* This table occasionally claims that a processor does not support a + particular feature even though it does, but the feature is slower than the + alternative. Thus, it shouldn't be relied on as a complete description of + the processor's support. + + Please keep this list in order, and don't forget to update the documentation + in invoke.texi when adding a new processor or flag. */ + +struct rs6000_ptt +{ + const char *const name; /* Canonical processor name. */ + const enum processor_type processor; /* Processor type enum value. */ + const int target_enable; /* Target flags to enable. */ +}; + +static struct rs6000_ptt const processor_target_table[] = +{ + {"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"403", PROCESSOR_PPC403, + POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN}, + {"405", PROCESSOR_PPC405, + POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB}, + {"405fp", PROCESSOR_PPC405, + POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, + {"440", PROCESSOR_PPC440, + POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB}, + {"440fp", PROCESSOR_PPC440, + POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, + {"464", PROCESSOR_PPC440, + 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}, + {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"620", PROCESSOR_PPC620, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, + {"630", PROCESSOR_PPC630, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, + {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK}, + {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK}, + {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN + | MASK_ISEL}, + /* 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}, + {"cell", PROCESSOR_CELL, + POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64}, + {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS}, + {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, + {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, + {"G4", PROCESSOR_PPC7450, POWERPC_7400_MASK}, + {"G5", PROCESSOR_POWER4, + POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64}, + {"titan", PROCESSOR_TITAN, + POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, + {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"power2", PROCESSOR_POWER, + MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING}, + {"power3", PROCESSOR_PPC630, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, + {"power4", PROCESSOR_POWER4, + POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT + | MASK_MFCRF}, + {"power5", PROCESSOR_POWER5, + POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT + | MASK_MFCRF | MASK_POPCNTB}, + {"power5+", PROCESSOR_POWER5, + POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT + | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND}, + {"power6", PROCESSOR_POWER6, + POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT + | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP + | MASK_RECIP_PRECISION}, + {"power6x", PROCESSOR_POWER6, + POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT + | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP + | MASK_MFPGPR | MASK_RECIP_PRECISION}, + {"power7", PROCESSOR_POWER7, /* Don't add MASK_ISEL by default */ + POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF + | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD + | MASK_VSX | MASK_RECIP_PRECISION}, + {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK}, + {"powerpc64", PROCESSOR_POWERPC64, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, + {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"rios2", PROCESSOR_RIOS2, + MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING}, + {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, + {"rs64", PROCESSOR_RS64A, + POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64} +}; + +/* Look up a processor name for -mcpu=xxx and -mtune=xxx. Return -1 if the + name is invalid. */ + +static int +rs6000_cpu_name_lookup (const char *name) +{ + size_t i; + + if (name != NULL) + { + for (i = 0; i < ARRAY_SIZE (processor_target_table); i++) + if (! strcmp (name, processor_target_table[i].name)) + return (int)i; + } + + return -1; +} + + /* Return number of consecutive hard regs needed starting at reg REGNO to hold something of mode MODE. This is ordinarily the length in words of a value of mode MODE @@ -1645,8 +1939,8 @@ rs6000_hard_regno_mode_ok (int regno, enum machine_mode mode) if (CR_REGNO_P (regno)) return GET_MODE_CLASS (mode) == MODE_CC; - if (XER_REGNO_P (regno)) - return mode == PSImode; + if (CA_REGNO_P (regno)) + return mode == BImode; /* AltiVec only in AldyVec registers. */ if (ALTIVEC_REGNO_P (regno)) @@ -1735,16 +2029,23 @@ rs6000_debug_reg_print (int first_regno, int last_regno, const char *reg_name) } } +#define DEBUG_FMT_D "%-32s= %d\n" +#define DEBUG_FMT_S "%-32s= %s\n" + /* Print various interesting information with -mdebug=reg. */ static void rs6000_debug_reg_global (void) { + static const char *const tf[2] = { "false", "true" }; const char *nl = (const char *)0; int m; char costly_num[20]; char nop_num[20]; const char *costly_str; const char *nop_str; + const char *trace_str; + const char *abi_str; + const char *cmodel_str; /* Map enum rs6000_vector to string. */ static const char *rs6000_debug_vector_unit[] = { @@ -1767,7 +2068,7 @@ rs6000_debug_reg_global (void) rs6000_debug_reg_print (CTR_REGNO, CTR_REGNO, "ctr"); rs6000_debug_reg_print (CR0_REGNO, CR7_REGNO, "cr"); rs6000_debug_reg_print (MQ_REGNO, MQ_REGNO, "mq"); - rs6000_debug_reg_print (XER_REGNO, XER_REGNO, "xer"); + rs6000_debug_reg_print (CA_REGNO, CA_REGNO, "ca"); rs6000_debug_reg_print (VRSAVE_REGNO, VRSAVE_REGNO, "vrsave"); rs6000_debug_reg_print (VSCR_REGNO, VSCR_REGNO, "vscr"); rs6000_debug_reg_print (SPE_ACC_REGNO, SPE_ACC_REGNO, "spe_a"); @@ -1803,6 +2104,35 @@ rs6000_debug_reg_global (void) if (nl) fputs (nl, stderr); + if (rs6000_recip_control) + { + fprintf (stderr, "\nReciprocal mask = 0x%x\n", rs6000_recip_control); + + for (m = 0; m < NUM_MACHINE_MODES; ++m) + if (rs6000_recip_bits[m]) + { + fprintf (stderr, + "Reciprocal estimate mode: %-5s divide: %s rsqrt: %s\n", + GET_MODE_NAME (m), + (RS6000_RECIP_AUTO_RE_P (m) + ? "auto" + : (RS6000_RECIP_HAVE_RE_P (m) ? "have" : "none")), + (RS6000_RECIP_AUTO_RSQRTE_P (m) + ? "auto" + : (RS6000_RECIP_HAVE_RSQRTE_P (m) ? "have" : "none"))); + } + + fputs ("\n", stderr); + } + + if (rs6000_cpu_index >= 0) + fprintf (stderr, DEBUG_FMT_S, "cpu", + processor_target_table[rs6000_cpu_index].name); + + if (rs6000_tune_index >= 0) + fprintf (stderr, DEBUG_FMT_S, "tune", + processor_target_table[rs6000_tune_index].name); + switch (rs6000_sched_costly_dep) { case max_dep_latency: @@ -1831,6 +2161,8 @@ rs6000_debug_reg_global (void) break; } + fprintf (stderr, DEBUG_FMT_S, "sched_costly_dep", costly_str); + switch (rs6000_sched_insert_nops) { case sched_finish_regroup_exact: @@ -1851,21 +2183,85 @@ rs6000_debug_reg_global (void) break; } - fprintf (stderr, - "always_hint = %s\n" - "align_branch_targets = %s\n" - "sched_restricted_insns_priority = %d\n" - "sched_costly_dep = %s\n" - "sched_insert_nops = %s\n\n", - rs6000_always_hint ? "true" : "false", - rs6000_align_branch_targets ? "true" : "false", - (int)rs6000_sched_restricted_insns_priority, - costly_str, nop_str); + fprintf (stderr, DEBUG_FMT_S, "sched_insert_nops", nop_str); + + switch (rs6000_sdata) + { + default: + case SDATA_NONE: + break; + + case SDATA_DATA: + fprintf (stderr, DEBUG_FMT_S, "sdata", "data"); + break; + + case SDATA_SYSV: + fprintf (stderr, DEBUG_FMT_S, "sdata", "sysv"); + break; + + case SDATA_EABI: + fprintf (stderr, DEBUG_FMT_S, "sdata", "eabi"); + break; + + } + + switch (rs6000_traceback) + { + case traceback_default: trace_str = "default"; break; + case traceback_none: trace_str = "none"; break; + case traceback_part: trace_str = "part"; break; + case traceback_full: trace_str = "full"; break; + default: trace_str = "unknown"; break; + } + + fprintf (stderr, DEBUG_FMT_S, "traceback", trace_str); + + switch (rs6000_current_cmodel) + { + case CMODEL_SMALL: cmodel_str = "small"; break; + case CMODEL_MEDIUM: cmodel_str = "medium"; break; + case CMODEL_LARGE: cmodel_str = "large"; break; + default: cmodel_str = "unknown"; break; + } + + fprintf (stderr, DEBUG_FMT_S, "cmodel", cmodel_str); + + switch (rs6000_current_abi) + { + case ABI_NONE: abi_str = "none"; break; + case ABI_AIX: abi_str = "aix"; break; + case ABI_V4: abi_str = "V4"; break; + case ABI_DARWIN: abi_str = "darwin"; break; + default: abi_str = "unknown"; break; + } + + fprintf (stderr, DEBUG_FMT_S, "abi", abi_str); + + if (rs6000_altivec_abi) + fprintf (stderr, DEBUG_FMT_S, "altivec_abi", "true"); + + if (rs6000_spe_abi) + fprintf (stderr, DEBUG_FMT_S, "spe_abi", "true"); + + if (rs6000_darwin64_abi) + fprintf (stderr, DEBUG_FMT_S, "darwin64_abi", "true"); + + if (rs6000_float_gprs) + fprintf (stderr, DEBUG_FMT_S, "float_gprs", "true"); + + fprintf (stderr, DEBUG_FMT_S, "always_hint", tf[!!rs6000_always_hint]); + fprintf (stderr, DEBUG_FMT_S, "align_branch", + tf[!!rs6000_align_branch_targets]); + fprintf (stderr, DEBUG_FMT_D, "tls_size", rs6000_tls_size); + fprintf (stderr, DEBUG_FMT_D, "long_double_size", + rs6000_long_double_type_size); + fprintf (stderr, DEBUG_FMT_D, "sched_restricted_insns_priority", + (int)rs6000_sched_restricted_insns_priority); } /* Initialize the various global tables that are based on register size. */ static void -rs6000_init_hard_regno_mode_ok (void) +rs6000_init_hard_regno_mode_ok (bool global_init_p) { int r, m, c; int align64; @@ -1892,7 +2288,7 @@ rs6000_init_hard_regno_mode_ok (void) rs6000_regno_regclass[MQ_REGNO] = MQ_REGS; rs6000_regno_regclass[LR_REGNO] = LINK_REGS; rs6000_regno_regclass[CTR_REGNO] = CTR_REGS; - rs6000_regno_regclass[XER_REGNO] = XER_REGS; + rs6000_regno_regclass[CA_REGNO] = CA_REGS; rs6000_regno_regclass[VRSAVE_REGNO] = VRSAVE_REGS; rs6000_regno_regclass[VSCR_REGNO] = VRSAVE_REGS; rs6000_regno_regclass[SPE_ACC_REGNO] = SPE_ACC_REGS; @@ -2010,8 +2406,9 @@ rs6000_init_hard_regno_mode_ok (void) rs6000_constraints[RS6000_CONSTRAINT_wa] = VSX_REGS; rs6000_constraints[RS6000_CONSTRAINT_wf] = VSX_REGS; rs6000_constraints[RS6000_CONSTRAINT_wd] = VSX_REGS; - if (TARGET_VSX_SCALAR_DOUBLE) - rs6000_constraints[RS6000_CONSTRAINT_ws] = VSX_REGS; + rs6000_constraints[RS6000_CONSTRAINT_ws] = (TARGET_VSX_SCALAR_MEMORY + ? VSX_REGS + : FLOAT_REGS); } if (TARGET_ALTIVEC) @@ -2089,8 +2486,111 @@ rs6000_init_hard_regno_mode_ok (void) if (TARGET_E500_DOUBLE) rs6000_class_max_nregs[DFmode][GENERAL_REGS] = 1; - if (TARGET_DEBUG_REG) - rs6000_debug_reg_global (); + /* Calculate which modes to automatically generate code to use a the + reciprocal divide and square root instructions. In the future, possibly + automatically generate the instructions even if the user did not specify + -mrecip. The older machines double precision reciprocal sqrt estimate is + not accurate enough. */ + memset (rs6000_recip_bits, 0, sizeof (rs6000_recip_bits)); + if (TARGET_FRES) + rs6000_recip_bits[SFmode] = RS6000_RECIP_MASK_HAVE_RE; + if (TARGET_FRE) + rs6000_recip_bits[DFmode] = RS6000_RECIP_MASK_HAVE_RE; + if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)) + rs6000_recip_bits[V4SFmode] = RS6000_RECIP_MASK_HAVE_RE; + if (VECTOR_UNIT_VSX_P (V2DFmode)) + rs6000_recip_bits[V2DFmode] = RS6000_RECIP_MASK_HAVE_RE; + + if (TARGET_FRSQRTES) + rs6000_recip_bits[SFmode] |= RS6000_RECIP_MASK_HAVE_RSQRTE; + if (TARGET_FRSQRTE) + rs6000_recip_bits[DFmode] |= RS6000_RECIP_MASK_HAVE_RSQRTE; + if (VECTOR_UNIT_ALTIVEC_OR_VSX_P (V4SFmode)) + rs6000_recip_bits[V4SFmode] |= RS6000_RECIP_MASK_HAVE_RSQRTE; + if (VECTOR_UNIT_VSX_P (V2DFmode)) + rs6000_recip_bits[V2DFmode] |= RS6000_RECIP_MASK_HAVE_RSQRTE; + + if (rs6000_recip_control) + { + if (!flag_finite_math_only) + warning (0, "-mrecip requires -ffinite-math or -ffast-math"); + if (flag_trapping_math) + warning (0, "-mrecip requires -fno-trapping-math or -ffast-math"); + if (!flag_reciprocal_math) + warning (0, "-mrecip requires -freciprocal-math or -ffast-math"); + if (flag_finite_math_only && !flag_trapping_math && flag_reciprocal_math) + { + if (RS6000_RECIP_HAVE_RE_P (SFmode) + && (rs6000_recip_control & RECIP_SF_DIV) != 0) + rs6000_recip_bits[SFmode] |= RS6000_RECIP_MASK_AUTO_RE; + + if (RS6000_RECIP_HAVE_RE_P (DFmode) + && (rs6000_recip_control & RECIP_DF_DIV) != 0) + rs6000_recip_bits[DFmode] |= RS6000_RECIP_MASK_AUTO_RE; + + if (RS6000_RECIP_HAVE_RE_P (V4SFmode) + && (rs6000_recip_control & RECIP_V4SF_DIV) != 0) + rs6000_recip_bits[V4SFmode] |= RS6000_RECIP_MASK_AUTO_RE; + + if (RS6000_RECIP_HAVE_RE_P (V2DFmode) + && (rs6000_recip_control & RECIP_V2DF_DIV) != 0) + rs6000_recip_bits[V2DFmode] |= RS6000_RECIP_MASK_AUTO_RE; + + if (RS6000_RECIP_HAVE_RSQRTE_P (SFmode) + && (rs6000_recip_control & RECIP_SF_RSQRT) != 0) + rs6000_recip_bits[SFmode] |= RS6000_RECIP_MASK_AUTO_RSQRTE; + + if (RS6000_RECIP_HAVE_RSQRTE_P (DFmode) + && (rs6000_recip_control & RECIP_DF_RSQRT) != 0) + rs6000_recip_bits[DFmode] |= RS6000_RECIP_MASK_AUTO_RSQRTE; + + if (RS6000_RECIP_HAVE_RSQRTE_P (V4SFmode) + && (rs6000_recip_control & RECIP_V4SF_RSQRT) != 0) + rs6000_recip_bits[V4SFmode] |= RS6000_RECIP_MASK_AUTO_RSQRTE; + + if (RS6000_RECIP_HAVE_RSQRTE_P (V2DFmode) + && (rs6000_recip_control & RECIP_V2DF_RSQRT) != 0) + rs6000_recip_bits[V2DFmode] |= RS6000_RECIP_MASK_AUTO_RSQRTE; + } + } + + if (global_init_p || TARGET_DEBUG_TARGET) + { + if (TARGET_DEBUG_REG) + rs6000_debug_reg_global (); + + if (TARGET_DEBUG_COST || TARGET_DEBUG_REG) + fprintf (stderr, + "SImode variable mult cost = %d\n" + "SImode constant mult cost = %d\n" + "SImode short constant mult cost = %d\n" + "DImode multipliciation cost = %d\n" + "SImode division cost = %d\n" + "DImode division cost = %d\n" + "Simple fp operation cost = %d\n" + "DFmode multiplication cost = %d\n" + "SFmode division cost = %d\n" + "DFmode division cost = %d\n" + "cache line size = %d\n" + "l1 cache size = %d\n" + "l2 cache size = %d\n" + "simultaneous prefetches = %d\n" + "\n", + rs6000_cost->mulsi, + rs6000_cost->mulsi_const, + rs6000_cost->mulsi_const9, + rs6000_cost->muldi, + rs6000_cost->divsi, + rs6000_cost->divdi, + rs6000_cost->fp, + rs6000_cost->dmul, + rs6000_cost->sdiv, + rs6000_cost->ddiv, + rs6000_cost->cache_line_size, + rs6000_cost->l1_cache_size, + rs6000_cost->l2_cache_size, + rs6000_cost->simultaneous_prefetches); + } } #if TARGET_MACHO @@ -2103,19 +2603,11 @@ darwin_rs6000_override_options (void) off. */ rs6000_altivec_abi = 1; TARGET_ALTIVEC_VRSAVE = 1; - if (DEFAULT_ABI == ABI_DARWIN) - { - if (MACHO_DYNAMIC_NO_PIC_P) - { - if (flag_pic) - warning (0, "-mdynamic-no-pic overrides -fpic or -fPIC"); - flag_pic = 0; - } - else if (flag_pic == 1) - { - flag_pic = 2; - } - } + + if (DEFAULT_ABI == ABI_DARWIN + && TARGET_64BIT) + darwin_one_byte_bool = 1; + if (TARGET_64BIT && ! TARGET_POWERPC64) { target_flags |= MASK_POWERPC64; @@ -2155,162 +2647,26 @@ darwin_rs6000_override_options (void) #define RS6000_DEFAULT_LONG_DOUBLE_SIZE 64 #endif -/* Override command line options. Mostly we process the processor - type and sometimes adjust other TARGET_ options. */ +/* Override command line options. Mostly we process the processor type and + sometimes adjust other TARGET_ options. */ -void -rs6000_override_options (const char *default_cpu) +static bool +rs6000_option_override_internal (bool global_init_p) { - size_t i, j; - struct rs6000_cpu_select *ptr; + bool ret = true; + const char *default_cpu = OPTION_TARGET_CPU_DEFAULT; int set_masks; - - /* Simplifications for entries below. */ - - enum { - POWERPC_BASE_MASK = MASK_POWERPC | MASK_NEW_MNEMONICS, - POWERPC_7400_MASK = POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_ALTIVEC - }; - - /* This table occasionally claims that a processor does not support - a particular feature even though it does, but the feature is slower - than the alternative. Thus, it shouldn't be relied on as a - complete description of the processor's support. - - Please keep this list in order, and don't forget to update the - documentation in invoke.texi when adding a new processor or - flag. */ - static struct ptt - { - const char *const name; /* Canonical processor name. */ - const enum processor_type processor; /* Processor type enum value. */ - const int target_enable; /* Target flags to enable. */ - } const processor_target_table[] - = {{"401", PROCESSOR_PPC403, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, - {"403", PROCESSOR_PPC403, - POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_STRICT_ALIGN}, - {"405", PROCESSOR_PPC405, - POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB}, - {"405fp", PROCESSOR_PPC405, - POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, - {"440", PROCESSOR_PPC440, - POWERPC_BASE_MASK | MASK_SOFT_FLOAT | MASK_MULHW | MASK_DLMZB}, - {"440fp", PROCESSOR_PPC440, - POWERPC_BASE_MASK | MASK_MULHW | MASK_DLMZB}, - {"464", PROCESSOR_PPC440, - 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}, - {"602", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, - {"603", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, - {"603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, - {"604", PROCESSOR_PPC604, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, - {"604e", PROCESSOR_PPC604e, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, - {"620", PROCESSOR_PPC620, - POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, - {"630", PROCESSOR_PPC630, - POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, - {"740", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, - {"7400", PROCESSOR_PPC7400, POWERPC_7400_MASK}, - {"7450", PROCESSOR_PPC7450, POWERPC_7400_MASK}, - {"750", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, - {"801", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, - {"821", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, - {"823", PROCESSOR_MPCCORE, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, - {"8540", PROCESSOR_PPC8540, POWERPC_BASE_MASK | MASK_STRICT_ALIGN - | MASK_ISEL}, - /* 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}, - {"cell", PROCESSOR_CELL, - POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64}, - {"common", PROCESSOR_COMMON, MASK_NEW_MNEMONICS}, - {"ec603e", PROCESSOR_PPC603, POWERPC_BASE_MASK | MASK_SOFT_FLOAT}, - {"G3", PROCESSOR_PPC750, POWERPC_BASE_MASK | MASK_PPC_GFXOPT}, - {"G4", PROCESSOR_PPC7450, POWERPC_7400_MASK}, - {"G5", PROCESSOR_POWER4, - POWERPC_7400_MASK | MASK_PPC_GPOPT | MASK_MFCRF | MASK_POWERPC64}, - {"power", PROCESSOR_POWER, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, - {"power2", PROCESSOR_POWER, - MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING}, - {"power3", PROCESSOR_PPC630, - POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, - {"power4", PROCESSOR_POWER4, - POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT - | MASK_MFCRF}, - {"power5", PROCESSOR_POWER5, - POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT - | MASK_MFCRF | MASK_POPCNTB}, - {"power5+", PROCESSOR_POWER5, - POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT - | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND}, - {"power6", PROCESSOR_POWER6, - POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT - | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP}, - {"power6x", PROCESSOR_POWER6, - POWERPC_BASE_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_PPC_GFXOPT - | MASK_MFCRF | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP - | MASK_MFPGPR}, - {"power7", PROCESSOR_POWER7, - POWERPC_7400_MASK | MASK_POWERPC64 | MASK_PPC_GPOPT | MASK_MFCRF - | MASK_POPCNTB | MASK_FPRND | MASK_CMPB | MASK_DFP | MASK_POPCNTD - | MASK_VSX}, /* Don't add MASK_ISEL by default */ - {"powerpc", PROCESSOR_POWERPC, POWERPC_BASE_MASK}, - {"powerpc64", PROCESSOR_POWERPC64, - POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64}, - {"rios", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, - {"rios1", PROCESSOR_RIOS1, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, - {"rios2", PROCESSOR_RIOS2, - MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING}, - {"rsc", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, - {"rsc1", PROCESSOR_PPC601, MASK_POWER | MASK_MULTIPLE | MASK_STRING}, - {"rs64", PROCESSOR_RS64A, - POWERPC_BASE_MASK | MASK_PPC_GFXOPT | MASK_POWERPC64} - }; - - const size_t ptt_size = ARRAY_SIZE (processor_target_table); - - /* Some OSs don't support saving the high part of 64-bit registers on - context switch. Other OSs don't support saving Altivec registers. - On those OSs, we don't touch the MASK_POWERPC64 or MASK_ALTIVEC - settings; if the user wants either, the user must explicitly specify - them and we won't interfere with the user's specification. */ - - enum { - POWER_MASKS = MASK_POWER | MASK_POWER2 | MASK_MULTIPLE | MASK_STRING, - POWERPC_MASKS = (POWERPC_BASE_MASK | MASK_PPC_GPOPT | MASK_STRICT_ALIGN - | 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_NO_UPDATE) - }; + int cpu_index; + int tune_index; + struct cl_target_option *main_target_opt + = ((global_init_p || target_option_default_node == NULL) + ? NULL : TREE_TARGET_OPTION (target_option_default_node)); /* 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) + if (optimize >= 3 && global_init_p) flag_ira_loop_pressure = 1; /* Set the pointer size. */ @@ -2339,41 +2695,50 @@ rs6000_override_options (const char *default_cpu) set_masks &= ~target_flags_explicit; /* Identify the processor type. */ - rs6000_select[0].string = default_cpu; - rs6000_cpu = TARGET_POWERPC64 ? PROCESSOR_DEFAULT64 : PROCESSOR_DEFAULT; - - for (i = 0; i < ARRAY_SIZE (rs6000_select); i++) - { - ptr = &rs6000_select[i]; - if (ptr->string != (char *)0 && ptr->string[0] != '\0') - { - for (j = 0; j < ptt_size; j++) - if (! strcmp (ptr->string, processor_target_table[j].name)) - { - if (ptr->set_tune_p) - rs6000_cpu = processor_target_table[j].processor; + if (!default_cpu) + { + if (TARGET_POWERPC64) + default_cpu = "powerpc64"; + else if (TARGET_POWERPC) + default_cpu = "powerpc"; + } + + /* Process the -mcpu= and -mtune= argument. If the user changed + the cpu in a target attribute or pragma, but did not specify a tuning + option, use the cpu for the tuning option rather than the option specified + with -mtune on the command line. */ + if (rs6000_cpu_index > 0) + cpu_index = rs6000_cpu_index; + else if (main_target_opt != NULL && main_target_opt->x_rs6000_cpu_index > 0) + rs6000_cpu_index = cpu_index = main_target_opt->x_rs6000_cpu_index; + else + rs6000_cpu_index = cpu_index = rs6000_cpu_name_lookup (default_cpu); - if (ptr->set_arch_p) - { - target_flags &= ~set_masks; - target_flags |= (processor_target_table[j].target_enable - & set_masks); - } - break; - } + if (rs6000_tune_index > 0) + tune_index = rs6000_tune_index; + else + rs6000_tune_index = tune_index = cpu_index; - if (j == ptt_size) - error ("bad value (%s) for %s switch", ptr->string, ptr->name); - } + if (cpu_index >= 0) + { + target_flags &= ~set_masks; + target_flags |= (processor_target_table[cpu_index].target_enable + & set_masks); } + rs6000_cpu = ((tune_index >= 0) + ? processor_target_table[tune_index].processor + : (TARGET_POWERPC64 + ? PROCESSOR_DEFAULT64 + : PROCESSOR_DEFAULT)); + if (rs6000_cpu == PROCESSOR_PPCE300C2 || rs6000_cpu == PROCESSOR_PPCE300C3 || rs6000_cpu == PROCESSOR_PPCE500MC || rs6000_cpu == PROCESSOR_PPCE500MC64) { if (TARGET_ALTIVEC) error ("AltiVec not supported in this target"); if (TARGET_SPE) - error ("Spe not supported in this target"); + error ("SPE not supported in this target"); } /* Disable Cell microcode if we are optimizing for the Cell @@ -2444,30 +2809,41 @@ rs6000_override_options (const char *default_cpu) { warning (0, msg); target_flags &= ~ MASK_VSX; + target_flags_explicit |= MASK_VSX; } - else if (TARGET_VSX && !TARGET_ALTIVEC) - target_flags |= MASK_ALTIVEC; - } - - /* Set debug flags */ - if (rs6000_debug_name) - { - if (! strcmp (rs6000_debug_name, "all")) - rs6000_debug_stack = rs6000_debug_arg = rs6000_debug_reg - = rs6000_debug_addr = rs6000_debug_cost = 1; - else if (! strcmp (rs6000_debug_name, "stack")) - rs6000_debug_stack = 1; - else if (! strcmp (rs6000_debug_name, "arg")) - rs6000_debug_arg = 1; - else if (! strcmp (rs6000_debug_name, "reg")) - rs6000_debug_reg = 1; - else if (! strcmp (rs6000_debug_name, "addr")) - rs6000_debug_addr = 1; - else if (! strcmp (rs6000_debug_name, "cost")) - rs6000_debug_cost = 1; - else - error ("unknown -mdebug-%s switch", rs6000_debug_name); + } + /* For the newer switches (vsx, dfp, etc.) set some of the older options, + unless the user explicitly used the -mno-