| /* Output routines for GCC for ARM. |
| Copyright (C) 1991-2015 Free Software Foundation, Inc. |
| Contributed by Pieter `Tiggr' Schoenmakers (rcpieter@win.tue.nl) |
| and Martin Simmons (@harleqn.co.uk). |
| More major hacks by Richard Earnshaw (rearnsha@arm.com). |
| |
| This file is part of GCC. |
| |
| GCC is free software; you can redistribute it and/or modify it |
| under the terms of the GNU General Public License as published |
| by the Free Software Foundation; either version 3, or (at your |
| option) any later version. |
| |
| GCC is distributed in the hope that it will be useful, but WITHOUT |
| ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
| or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public |
| License for more details. |
| |
| You should have received a copy of the GNU General Public License |
| along with GCC; see the file COPYING3. If not see |
| <http://www.gnu.org/licenses/>. */ |
| |
| #include "config.h" |
| #include "system.h" |
| #include "coretypes.h" |
| #include "hash-table.h" |
| #include "tm.h" |
| #include "rtl.h" |
| #include "hash-set.h" |
| #include "machmode.h" |
| #include "vec.h" |
| #include "double-int.h" |
| #include "input.h" |
| #include "alias.h" |
| #include "symtab.h" |
| #include "wide-int.h" |
| #include "inchash.h" |
| #include "tree.h" |
| #include "fold-const.h" |
| #include "stringpool.h" |
| #include "stor-layout.h" |
| #include "calls.h" |
| #include "varasm.h" |
| #include "obstack.h" |
| #include "regs.h" |
| #include "hard-reg-set.h" |
| #include "insn-config.h" |
| #include "conditions.h" |
| #include "output.h" |
| #include "insn-attr.h" |
| #include "flags.h" |
| #include "reload.h" |
| #include "function.h" |
| #include "hashtab.h" |
| #include "statistics.h" |
| #include "real.h" |
| #include "fixed-value.h" |
| #include "expmed.h" |
| #include "dojump.h" |
| #include "explow.h" |
| #include "emit-rtl.h" |
| #include "stmt.h" |
| #include "expr.h" |
| #include "insn-codes.h" |
| #include "optabs.h" |
| #include "diagnostic-core.h" |
| #include "recog.h" |
| #include "predict.h" |
| #include "dominance.h" |
| #include "cfg.h" |
| #include "cfgrtl.h" |
| #include "cfganal.h" |
| #include "lcm.h" |
| #include "cfgbuild.h" |
| #include "cfgcleanup.h" |
| #include "basic-block.h" |
| #include "hash-map.h" |
| #include "is-a.h" |
| #include "plugin-api.h" |
| #include "ipa-ref.h" |
| #include "cgraph.h" |
| #include "ggc.h" |
| #include "except.h" |
| #include "tm_p.h" |
| #include "target.h" |
| #include "sched-int.h" |
| #include "target-def.h" |
| #include "debug.h" |
| #include "langhooks.h" |
| #include "df.h" |
| #include "intl.h" |
| #include "libfuncs.h" |
| #include "params.h" |
| #include "opts.h" |
| #include "dumpfile.h" |
| #include "gimple-expr.h" |
| #include "builtins.h" |
| #include "tm-constrs.h" |
| #include "rtl-iter.h" |
| #include "sched-int.h" |
| |
| /* Forward definitions of types. */ |
| typedef struct minipool_node Mnode; |
| typedef struct minipool_fixup Mfix; |
| |
| void (*arm_lang_output_object_attributes_hook)(void); |
| |
| struct four_ints |
| { |
| int i[4]; |
| }; |
| |
| /* Forward function declarations. */ |
| static bool arm_const_not_ok_for_debug_p (rtx); |
| static bool arm_needs_doubleword_align (machine_mode, const_tree); |
| static int arm_compute_static_chain_stack_bytes (void); |
| static arm_stack_offsets *arm_get_frame_offsets (void); |
| static void arm_add_gc_roots (void); |
| static int arm_gen_constant (enum rtx_code, machine_mode, rtx, |
| HOST_WIDE_INT, rtx, rtx, int, int); |
| static unsigned bit_count (unsigned long); |
| static int arm_address_register_rtx_p (rtx, int); |
| static int arm_legitimate_index_p (machine_mode, rtx, RTX_CODE, int); |
| static int thumb2_legitimate_index_p (machine_mode, rtx, int); |
| static int thumb1_base_register_rtx_p (rtx, machine_mode, int); |
| static rtx arm_legitimize_address (rtx, rtx, machine_mode); |
| static reg_class_t arm_preferred_reload_class (rtx, reg_class_t); |
| static rtx thumb_legitimize_address (rtx, rtx, machine_mode); |
| inline static int thumb1_index_register_rtx_p (rtx, int); |
| static int thumb_far_jump_used_p (void); |
| static bool thumb_force_lr_save (void); |
| static unsigned arm_size_return_regs (void); |
| static bool arm_assemble_integer (rtx, unsigned int, int); |
| static void arm_print_operand (FILE *, rtx, int); |
| static void arm_print_operand_address (FILE *, rtx); |
| static bool arm_print_operand_punct_valid_p (unsigned char code); |
| static const char *fp_const_from_val (REAL_VALUE_TYPE *); |
| static arm_cc get_arm_condition_code (rtx); |
| static HOST_WIDE_INT int_log2 (HOST_WIDE_INT); |
| static const char *output_multi_immediate (rtx *, const char *, const char *, |
| int, HOST_WIDE_INT); |
| static const char *shift_op (rtx, HOST_WIDE_INT *); |
| static struct machine_function *arm_init_machine_status (void); |
| static void thumb_exit (FILE *, int); |
| static HOST_WIDE_INT get_jump_table_size (rtx_jump_table_data *); |
| static Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT); |
| static Mnode *add_minipool_forward_ref (Mfix *); |
| static Mnode *move_minipool_fix_backward_ref (Mnode *, Mnode *, HOST_WIDE_INT); |
| static Mnode *add_minipool_backward_ref (Mfix *); |
| static void assign_minipool_offsets (Mfix *); |
| static void arm_print_value (FILE *, rtx); |
| static void dump_minipool (rtx_insn *); |
| static int arm_barrier_cost (rtx); |
| static Mfix *create_fix_barrier (Mfix *, HOST_WIDE_INT); |
| static void push_minipool_barrier (rtx_insn *, HOST_WIDE_INT); |
| static void push_minipool_fix (rtx_insn *, HOST_WIDE_INT, rtx *, |
| machine_mode, rtx); |
| static void arm_reorg (void); |
| static void note_invalid_constants (rtx_insn *, HOST_WIDE_INT, int); |
| static unsigned long arm_compute_save_reg0_reg12_mask (void); |
| static unsigned long arm_compute_save_reg_mask (void); |
| static unsigned long arm_isr_value (tree); |
| static unsigned long arm_compute_func_type (void); |
| static tree arm_handle_fndecl_attribute (tree *, tree, tree, int, bool *); |
| static tree arm_handle_pcs_attribute (tree *, tree, tree, int, bool *); |
| static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *); |
| #if TARGET_DLLIMPORT_DECL_ATTRIBUTES |
| static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *); |
| #endif |
| static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT); |
| static void arm_output_function_prologue (FILE *, HOST_WIDE_INT); |
| static int arm_comp_type_attributes (const_tree, const_tree); |
| static void arm_set_default_type_attributes (tree); |
| static int arm_adjust_cost (rtx_insn *, rtx, rtx_insn *, int); |
| static int arm_sched_reorder (FILE *, int, rtx_insn **, int *, int); |
| static int optimal_immediate_sequence (enum rtx_code code, |
| unsigned HOST_WIDE_INT val, |
| struct four_ints *return_sequence); |
| static int optimal_immediate_sequence_1 (enum rtx_code code, |
| unsigned HOST_WIDE_INT val, |
| struct four_ints *return_sequence, |
| int i); |
| static int arm_get_strip_length (int); |
| static bool arm_function_ok_for_sibcall (tree, tree); |
| static machine_mode arm_promote_function_mode (const_tree, |
| machine_mode, int *, |
| const_tree, int); |
| static bool arm_return_in_memory (const_tree, const_tree); |
| static rtx arm_function_value (const_tree, const_tree, bool); |
| static rtx arm_libcall_value_1 (machine_mode); |
| static rtx arm_libcall_value (machine_mode, const_rtx); |
| static bool arm_function_value_regno_p (const unsigned int); |
| static void arm_internal_label (FILE *, const char *, unsigned long); |
| static void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, |
| tree); |
| static bool arm_have_conditional_execution (void); |
| static bool arm_cannot_force_const_mem (machine_mode, rtx); |
| static bool arm_legitimate_constant_p (machine_mode, rtx); |
| static bool arm_rtx_costs_1 (rtx, enum rtx_code, int*, bool); |
| static bool arm_size_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *); |
| static bool arm_slowmul_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool); |
| static bool arm_fastmul_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool); |
| static bool arm_xscale_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool); |
| static bool arm_9e_rtx_costs (rtx, enum rtx_code, enum rtx_code, int *, bool); |
| static bool arm_rtx_costs (rtx, int, int, int, int *, bool); |
| static int arm_address_cost (rtx, machine_mode, addr_space_t, bool); |
| static int arm_register_move_cost (machine_mode, reg_class_t, reg_class_t); |
| static int arm_memory_move_cost (machine_mode, reg_class_t, bool); |
| static void emit_constant_insn (rtx cond, rtx pattern); |
| static rtx_insn *emit_set_insn (rtx, rtx); |
| static rtx emit_multi_reg_push (unsigned long, unsigned long); |
| static int arm_arg_partial_bytes (cumulative_args_t, machine_mode, |
| tree, bool); |
| static rtx arm_function_arg (cumulative_args_t, machine_mode, |
| const_tree, bool); |
| static void arm_function_arg_advance (cumulative_args_t, machine_mode, |
| const_tree, bool); |
| static unsigned int arm_function_arg_boundary (machine_mode, const_tree); |
| static rtx aapcs_allocate_return_reg (machine_mode, const_tree, |
| const_tree); |
| static rtx aapcs_libcall_value (machine_mode); |
| static int aapcs_select_return_coproc (const_tree, const_tree); |
| |
| #ifdef OBJECT_FORMAT_ELF |
| static void arm_elf_asm_constructor (rtx, int) ATTRIBUTE_UNUSED; |
| static void arm_elf_asm_destructor (rtx, int) ATTRIBUTE_UNUSED; |
| #endif |
| #ifndef ARM_PE |
| static void arm_encode_section_info (tree, rtx, int); |
| #endif |
| |
| static void arm_file_end (void); |
| static void arm_file_start (void); |
| |
| static void arm_setup_incoming_varargs (cumulative_args_t, machine_mode, |
| tree, int *, int); |
| static bool arm_pass_by_reference (cumulative_args_t, |
| machine_mode, const_tree, bool); |
| static bool arm_promote_prototypes (const_tree); |
| static bool arm_default_short_enums (void); |
| static bool arm_align_anon_bitfield (void); |
| static bool arm_return_in_msb (const_tree); |
| static bool arm_must_pass_in_stack (machine_mode, const_tree); |
| static bool arm_return_in_memory (const_tree, const_tree); |
| #if ARM_UNWIND_INFO |
| static void arm_unwind_emit (FILE *, rtx_insn *); |
| static bool arm_output_ttype (rtx); |
| static void arm_asm_emit_except_personality (rtx); |
| static void arm_asm_init_sections (void); |
| #endif |
| static rtx arm_dwarf_register_span (rtx); |
| |
| static tree arm_cxx_guard_type (void); |
| static bool arm_cxx_guard_mask_bit (void); |
| static tree arm_get_cookie_size (tree); |
| static bool arm_cookie_has_size (void); |
| static bool arm_cxx_cdtor_returns_this (void); |
| static bool arm_cxx_key_method_may_be_inline (void); |
| static void arm_cxx_determine_class_data_visibility (tree); |
| static bool arm_cxx_class_data_always_comdat (void); |
| static bool arm_cxx_use_aeabi_atexit (void); |
| static void arm_init_libfuncs (void); |
| static tree arm_build_builtin_va_list (void); |
| static void arm_expand_builtin_va_start (tree, rtx); |
| static tree arm_gimplify_va_arg_expr (tree, tree, gimple_seq *, gimple_seq *); |
| static void arm_option_override (void); |
| static unsigned HOST_WIDE_INT arm_shift_truncation_mask (machine_mode); |
| static bool arm_macro_fusion_p (void); |
| static bool arm_cannot_copy_insn_p (rtx_insn *); |
| static int arm_issue_rate (void); |
| static int arm_first_cycle_multipass_dfa_lookahead (void); |
| static int arm_first_cycle_multipass_dfa_lookahead_guard (rtx_insn *, int); |
| static void arm_output_dwarf_dtprel (FILE *, int, rtx) ATTRIBUTE_UNUSED; |
| static bool arm_output_addr_const_extra (FILE *, rtx); |
| static bool arm_allocate_stack_slots_for_args (void); |
| static bool arm_warn_func_return (tree); |
| static const char *arm_invalid_parameter_type (const_tree t); |
| static const char *arm_invalid_return_type (const_tree t); |
| static tree arm_promoted_type (const_tree t); |
| static tree arm_convert_to_type (tree type, tree expr); |
| static bool arm_scalar_mode_supported_p (machine_mode); |
| static bool arm_frame_pointer_required (void); |
| static bool arm_can_eliminate (const int, const int); |
| static void arm_asm_trampoline_template (FILE *); |
| static void arm_trampoline_init (rtx, tree, rtx); |
| static rtx arm_trampoline_adjust_address (rtx); |
| static rtx arm_pic_static_addr (rtx orig, rtx reg); |
| static bool cortex_a9_sched_adjust_cost (rtx_insn *, rtx, rtx_insn *, int *); |
| static bool xscale_sched_adjust_cost (rtx_insn *, rtx, rtx_insn *, int *); |
| static bool fa726te_sched_adjust_cost (rtx_insn *, rtx, rtx_insn *, int *); |
| static bool arm_array_mode_supported_p (machine_mode, |
| unsigned HOST_WIDE_INT); |
| static machine_mode arm_preferred_simd_mode (machine_mode); |
| static bool arm_class_likely_spilled_p (reg_class_t); |
| static HOST_WIDE_INT arm_vector_alignment (const_tree type); |
| static bool arm_vector_alignment_reachable (const_tree type, bool is_packed); |
| static bool arm_builtin_support_vector_misalignment (machine_mode mode, |
| const_tree type, |
| int misalignment, |
| bool is_packed); |
| static void arm_conditional_register_usage (void); |
| static reg_class_t arm_preferred_rename_class (reg_class_t rclass); |
| static unsigned int arm_autovectorize_vector_sizes (void); |
| static int arm_default_branch_cost (bool, bool); |
| static int arm_cortex_a5_branch_cost (bool, bool); |
| static int arm_cortex_m_branch_cost (bool, bool); |
| static int arm_cortex_m7_branch_cost (bool, bool); |
| |
| static bool arm_vectorize_vec_perm_const_ok (machine_mode vmode, |
| const unsigned char *sel); |
| |
| static bool aarch_macro_fusion_pair_p (rtx_insn*, rtx_insn*); |
| |
| static int arm_builtin_vectorization_cost (enum vect_cost_for_stmt type_of_cost, |
| tree vectype, |
| int misalign ATTRIBUTE_UNUSED); |
| static unsigned arm_add_stmt_cost (void *data, int count, |
| enum vect_cost_for_stmt kind, |
| struct _stmt_vec_info *stmt_info, |
| int misalign, |
| enum vect_cost_model_location where); |
| |
| static void arm_canonicalize_comparison (int *code, rtx *op0, rtx *op1, |
| bool op0_preserve_value); |
| static unsigned HOST_WIDE_INT arm_asan_shadow_offset (void); |
| |
| static void arm_sched_fusion_priority (rtx_insn *, int, int *, int*); |
| |
| /* Table of machine attributes. */ |
| static const struct attribute_spec arm_attribute_table[] = |
| { |
| /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler, |
| affects_type_identity } */ |
| /* Function calls made to this symbol must be done indirectly, because |
| it may lie outside of the 26 bit addressing range of a normal function |
| call. */ |
| { "long_call", 0, 0, false, true, true, NULL, false }, |
| /* Whereas these functions are always known to reside within the 26 bit |
| addressing range. */ |
| { "short_call", 0, 0, false, true, true, NULL, false }, |
| /* Specify the procedure call conventions for a function. */ |
| { "pcs", 1, 1, false, true, true, arm_handle_pcs_attribute, |
| false }, |
| /* Interrupt Service Routines have special prologue and epilogue requirements. */ |
| { "isr", 0, 1, false, false, false, arm_handle_isr_attribute, |
| false }, |
| { "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute, |
| false }, |
| { "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute, |
| false }, |
| #ifdef ARM_PE |
| /* ARM/PE has three new attributes: |
| interfacearm - ? |
| dllexport - for exporting a function/variable that will live in a dll |
| dllimport - for importing a function/variable from a dll |
| |
| Microsoft allows multiple declspecs in one __declspec, separating |
| them with spaces. We do NOT support this. Instead, use __declspec |
| multiple times. |
| */ |
| { "dllimport", 0, 0, true, false, false, NULL, false }, |
| { "dllexport", 0, 0, true, false, false, NULL, false }, |
| { "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute, |
| false }, |
| #elif TARGET_DLLIMPORT_DECL_ATTRIBUTES |
| { "dllimport", 0, 0, false, false, false, handle_dll_attribute, false }, |
| { "dllexport", 0, 0, false, false, false, handle_dll_attribute, false }, |
| { "notshared", 0, 0, false, true, false, arm_handle_notshared_attribute, |
| false }, |
| #endif |
| { NULL, 0, 0, false, false, false, NULL, false } |
| }; |
| |
| /* Initialize the GCC target structure. */ |
| #if TARGET_DLLIMPORT_DECL_ATTRIBUTES |
| #undef TARGET_MERGE_DECL_ATTRIBUTES |
| #define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes |
| #endif |
| |
| #undef TARGET_LEGITIMIZE_ADDRESS |
| #define TARGET_LEGITIMIZE_ADDRESS arm_legitimize_address |
| |
| #undef TARGET_LRA_P |
| #define TARGET_LRA_P hook_bool_void_true |
| |
| #undef TARGET_ATTRIBUTE_TABLE |
| #define TARGET_ATTRIBUTE_TABLE arm_attribute_table |
| |
| #undef TARGET_ASM_FILE_START |
| #define TARGET_ASM_FILE_START arm_file_start |
| #undef TARGET_ASM_FILE_END |
| #define TARGET_ASM_FILE_END arm_file_end |
| |
| #undef TARGET_ASM_ALIGNED_SI_OP |
| #define TARGET_ASM_ALIGNED_SI_OP NULL |
| #undef TARGET_ASM_INTEGER |
| #define TARGET_ASM_INTEGER arm_assemble_integer |
| |
| #undef TARGET_PRINT_OPERAND |
| #define TARGET_PRINT_OPERAND arm_print_operand |
| #undef TARGET_PRINT_OPERAND_ADDRESS |
| #define TARGET_PRINT_OPERAND_ADDRESS arm_print_operand_address |
| #undef TARGET_PRINT_OPERAND_PUNCT_VALID_P |
| #define TARGET_PRINT_OPERAND_PUNCT_VALID_P arm_print_operand_punct_valid_p |
| |
| #undef TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA |
| #define TARGET_ASM_OUTPUT_ADDR_CONST_EXTRA arm_output_addr_const_extra |
| |
| #undef TARGET_ASM_FUNCTION_PROLOGUE |
| #define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue |
| |
| #undef TARGET_ASM_FUNCTION_EPILOGUE |
| #define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue |
| |
| #undef TARGET_OPTION_OVERRIDE |
| #define TARGET_OPTION_OVERRIDE arm_option_override |
| |
| #undef TARGET_COMP_TYPE_ATTRIBUTES |
| #define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes |
| |
| #undef TARGET_SCHED_MACRO_FUSION_P |
| #define TARGET_SCHED_MACRO_FUSION_P arm_macro_fusion_p |
| |
| #undef TARGET_SCHED_MACRO_FUSION_PAIR_P |
| #define TARGET_SCHED_MACRO_FUSION_PAIR_P aarch_macro_fusion_pair_p |
| |
| #undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES |
| #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes |
| |
| #undef TARGET_SCHED_ADJUST_COST |
| #define TARGET_SCHED_ADJUST_COST arm_adjust_cost |
| |
| #undef TARGET_SCHED_REORDER |
| #define TARGET_SCHED_REORDER arm_sched_reorder |
| |
| #undef TARGET_REGISTER_MOVE_COST |
| #define TARGET_REGISTER_MOVE_COST arm_register_move_cost |
| |
| #undef TARGET_MEMORY_MOVE_COST |
| #define TARGET_MEMORY_MOVE_COST arm_memory_move_cost |
| |
| #undef TARGET_ENCODE_SECTION_INFO |
| #ifdef ARM_PE |
| #define TARGET_ENCODE_SECTION_INFO arm_pe_encode_section_info |
| #else |
| #define TARGET_ENCODE_SECTION_INFO arm_encode_section_info |
| #endif |
| |
| #undef TARGET_STRIP_NAME_ENCODING |
| #define TARGET_STRIP_NAME_ENCODING arm_strip_name_encoding |
| |
| #undef TARGET_ASM_INTERNAL_LABEL |
| #define TARGET_ASM_INTERNAL_LABEL arm_internal_label |
| |
| #undef TARGET_FUNCTION_OK_FOR_SIBCALL |
| #define TARGET_FUNCTION_OK_FOR_SIBCALL arm_function_ok_for_sibcall |
| |
| #undef TARGET_FUNCTION_VALUE |
| #define TARGET_FUNCTION_VALUE arm_function_value |
| |
| #undef TARGET_LIBCALL_VALUE |
| #define TARGET_LIBCALL_VALUE arm_libcall_value |
| |
| #undef TARGET_FUNCTION_VALUE_REGNO_P |
| #define TARGET_FUNCTION_VALUE_REGNO_P arm_function_value_regno_p |
| |
| #undef TARGET_ASM_OUTPUT_MI_THUNK |
| #define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk |
| #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK |
| #define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall |
| |
| #undef TARGET_RTX_COSTS |
| #define TARGET_RTX_COSTS arm_rtx_costs |
| #undef TARGET_ADDRESS_COST |
| #define TARGET_ADDRESS_COST arm_address_cost |
| |
| #undef TARGET_SHIFT_TRUNCATION_MASK |
| #define TARGET_SHIFT_TRUNCATION_MASK arm_shift_truncation_mask |
| #undef TARGET_VECTOR_MODE_SUPPORTED_P |
| #define TARGET_VECTOR_MODE_SUPPORTED_P arm_vector_mode_supported_p |
| #undef TARGET_ARRAY_MODE_SUPPORTED_P |
| #define TARGET_ARRAY_MODE_SUPPORTED_P arm_array_mode_supported_p |
| #undef TARGET_VECTORIZE_PREFERRED_SIMD_MODE |
| #define TARGET_VECTORIZE_PREFERRED_SIMD_MODE arm_preferred_simd_mode |
| #undef TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES |
| #define TARGET_VECTORIZE_AUTOVECTORIZE_VECTOR_SIZES \ |
| arm_autovectorize_vector_sizes |
| |
| #undef TARGET_MACHINE_DEPENDENT_REORG |
| #define TARGET_MACHINE_DEPENDENT_REORG arm_reorg |
| |
| #undef TARGET_INIT_BUILTINS |
| #define TARGET_INIT_BUILTINS arm_init_builtins |
| #undef TARGET_EXPAND_BUILTIN |
| #define TARGET_EXPAND_BUILTIN arm_expand_builtin |
| #undef TARGET_BUILTIN_DECL |
| #define TARGET_BUILTIN_DECL arm_builtin_decl |
| |
| #undef TARGET_INIT_LIBFUNCS |
| #define TARGET_INIT_LIBFUNCS arm_init_libfuncs |
| |
| #undef TARGET_PROMOTE_FUNCTION_MODE |
| #define TARGET_PROMOTE_FUNCTION_MODE arm_promote_function_mode |
| #undef TARGET_PROMOTE_PROTOTYPES |
| #define TARGET_PROMOTE_PROTOTYPES arm_promote_prototypes |
| #undef TARGET_PASS_BY_REFERENCE |
| #define TARGET_PASS_BY_REFERENCE arm_pass_by_reference |
| #undef TARGET_ARG_PARTIAL_BYTES |
| #define TARGET_ARG_PARTIAL_BYTES arm_arg_partial_bytes |
| #undef TARGET_FUNCTION_ARG |
| #define TARGET_FUNCTION_ARG arm_function_arg |
| #undef TARGET_FUNCTION_ARG_ADVANCE |
| #define TARGET_FUNCTION_ARG_ADVANCE arm_function_arg_advance |
| #undef TARGET_FUNCTION_ARG_BOUNDARY |
| #define TARGET_FUNCTION_ARG_BOUNDARY arm_function_arg_boundary |
| |
| #undef TARGET_SETUP_INCOMING_VARARGS |
| #define TARGET_SETUP_INCOMING_VARARGS arm_setup_incoming_varargs |
| |
| #undef TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS |
| #define TARGET_ALLOCATE_STACK_SLOTS_FOR_ARGS arm_allocate_stack_slots_for_args |
| |
| #undef TARGET_ASM_TRAMPOLINE_TEMPLATE |
| #define TARGET_ASM_TRAMPOLINE_TEMPLATE arm_asm_trampoline_template |
| #undef TARGET_TRAMPOLINE_INIT |
| #define TARGET_TRAMPOLINE_INIT arm_trampoline_init |
| #undef TARGET_TRAMPOLINE_ADJUST_ADDRESS |
| #define TARGET_TRAMPOLINE_ADJUST_ADDRESS arm_trampoline_adjust_address |
| |
| #undef TARGET_WARN_FUNC_RETURN |
| #define TARGET_WARN_FUNC_RETURN arm_warn_func_return |
| |
| #undef TARGET_DEFAULT_SHORT_ENUMS |
| #define TARGET_DEFAULT_SHORT_ENUMS arm_default_short_enums |
| |
| #undef TARGET_ALIGN_ANON_BITFIELD |
| #define TARGET_ALIGN_ANON_BITFIELD arm_align_anon_bitfield |
| |
| #undef TARGET_NARROW_VOLATILE_BITFIELD |
| #define TARGET_NARROW_VOLATILE_BITFIELD hook_bool_void_false |
| |
| #undef TARGET_CXX_GUARD_TYPE |
| #define TARGET_CXX_GUARD_TYPE arm_cxx_guard_type |
| |
| #undef TARGET_CXX_GUARD_MASK_BIT |
| #define TARGET_CXX_GUARD_MASK_BIT arm_cxx_guard_mask_bit |
| |
| #undef TARGET_CXX_GET_COOKIE_SIZE |
| #define TARGET_CXX_GET_COOKIE_SIZE arm_get_cookie_size |
| |
| #undef TARGET_CXX_COOKIE_HAS_SIZE |
| #define TARGET_CXX_COOKIE_HAS_SIZE arm_cookie_has_size |
| |
| #undef TARGET_CXX_CDTOR_RETURNS_THIS |
| #define TARGET_CXX_CDTOR_RETURNS_THIS arm_cxx_cdtor_returns_this |
| |
| #undef TARGET_CXX_KEY_METHOD_MAY_BE_INLINE |
| #define TARGET_CXX_KEY_METHOD_MAY_BE_INLINE arm_cxx_key_method_may_be_inline |
| |
| #undef TARGET_CXX_USE_AEABI_ATEXIT |
| #define TARGET_CXX_USE_AEABI_ATEXIT arm_cxx_use_aeabi_atexit |
| |
| #undef TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY |
| #define TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY \ |
| arm_cxx_determine_class_data_visibility |
| |
| #undef TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT |
| #define TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT arm_cxx_class_data_always_comdat |
| |
| #undef TARGET_RETURN_IN_MSB |
| #define TARGET_RETURN_IN_MSB arm_return_in_msb |
| |
| #undef TARGET_RETURN_IN_MEMORY |
| #define TARGET_RETURN_IN_MEMORY arm_return_in_memory |
| |
| #undef TARGET_MUST_PASS_IN_STACK |
| #define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack |
| |
| #if ARM_UNWIND_INFO |
| #undef TARGET_ASM_UNWIND_EMIT |
| #define TARGET_ASM_UNWIND_EMIT arm_unwind_emit |
| |
| /* EABI unwinding tables use a different format for the typeinfo tables. */ |
| #undef TARGET_ASM_TTYPE |
| #define TARGET_ASM_TTYPE arm_output_ttype |
| |
| #undef TARGET_ARM_EABI_UNWINDER |
| #define TARGET_ARM_EABI_UNWINDER true |
| |
| #undef TARGET_ASM_EMIT_EXCEPT_PERSONALITY |
| #define TARGET_ASM_EMIT_EXCEPT_PERSONALITY arm_asm_emit_except_personality |
| |
| #undef TARGET_ASM_INIT_SECTIONS |
| #define TARGET_ASM_INIT_SECTIONS arm_asm_init_sections |
| #endif /* ARM_UNWIND_INFO */ |
| |
| #undef TARGET_DWARF_REGISTER_SPAN |
| #define TARGET_DWARF_REGISTER_SPAN arm_dwarf_register_span |
| |
| #undef TARGET_CANNOT_COPY_INSN_P |
| #define TARGET_CANNOT_COPY_INSN_P arm_cannot_copy_insn_p |
| |
| #ifdef HAVE_AS_TLS |
| #undef TARGET_HAVE_TLS |
| #define TARGET_HAVE_TLS true |
| #endif |
| |
| #undef TARGET_HAVE_CONDITIONAL_EXECUTION |
| #define TARGET_HAVE_CONDITIONAL_EXECUTION arm_have_conditional_execution |
| |
| #undef TARGET_LEGITIMATE_CONSTANT_P |
| #define TARGET_LEGITIMATE_CONSTANT_P arm_legitimate_constant_p |
| |
| #undef TARGET_CANNOT_FORCE_CONST_MEM |
| #define TARGET_CANNOT_FORCE_CONST_MEM arm_cannot_force_const_mem |
| |
| #undef TARGET_MAX_ANCHOR_OFFSET |
| #define TARGET_MAX_ANCHOR_OFFSET 4095 |
| |
| /* The minimum is set such that the total size of the block |
| for a particular anchor is -4088 + 1 + 4095 bytes, which is |
| divisible by eight, ensuring natural spacing of anchors. */ |
| #undef TARGET_MIN_ANCHOR_OFFSET |
| #define TARGET_MIN_ANCHOR_OFFSET -4088 |
| |
| #undef TARGET_SCHED_ISSUE_RATE |
| #define TARGET_SCHED_ISSUE_RATE arm_issue_rate |
| |
| #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD |
| #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD \ |
| arm_first_cycle_multipass_dfa_lookahead |
| |
| #undef TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD |
| #define TARGET_SCHED_FIRST_CYCLE_MULTIPASS_DFA_LOOKAHEAD_GUARD \ |
| arm_first_cycle_multipass_dfa_lookahead_guard |
| |
| #undef TARGET_MANGLE_TYPE |
| #define TARGET_MANGLE_TYPE arm_mangle_type |
| |
| #undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV |
| #define TARGET_ATOMIC_ASSIGN_EXPAND_FENV arm_atomic_assign_expand_fenv |
| |
| #undef TARGET_BUILD_BUILTIN_VA_LIST |
| #define TARGET_BUILD_BUILTIN_VA_LIST arm_build_builtin_va_list |
| #undef TARGET_EXPAND_BUILTIN_VA_START |
| #define TARGET_EXPAND_BUILTIN_VA_START arm_expand_builtin_va_start |
| #undef TARGET_GIMPLIFY_VA_ARG_EXPR |
| #define TARGET_GIMPLIFY_VA_ARG_EXPR arm_gimplify_va_arg_expr |
| |
| #ifdef HAVE_AS_TLS |
| #undef TARGET_ASM_OUTPUT_DWARF_DTPREL |
| #define TARGET_ASM_OUTPUT_DWARF_DTPREL arm_output_dwarf_dtprel |
| #endif |
| |
| #undef TARGET_LEGITIMATE_ADDRESS_P |
| #define TARGET_LEGITIMATE_ADDRESS_P arm_legitimate_address_p |
| |
| #undef TARGET_PREFERRED_RELOAD_CLASS |
| #define TARGET_PREFERRED_RELOAD_CLASS arm_preferred_reload_class |
| |
| #undef TARGET_INVALID_PARAMETER_TYPE |
| #define TARGET_INVALID_PARAMETER_TYPE arm_invalid_parameter_type |
| |
| #undef TARGET_INVALID_RETURN_TYPE |
| #define TARGET_INVALID_RETURN_TYPE arm_invalid_return_type |
| |
| #undef TARGET_PROMOTED_TYPE |
| #define TARGET_PROMOTED_TYPE arm_promoted_type |
| |
| #undef TARGET_CONVERT_TO_TYPE |
| #define TARGET_CONVERT_TO_TYPE arm_convert_to_type |
| |
| #undef TARGET_SCALAR_MODE_SUPPORTED_P |
| #define TARGET_SCALAR_MODE_SUPPORTED_P arm_scalar_mode_supported_p |
| |
| #undef TARGET_FRAME_POINTER_REQUIRED |
| #define TARGET_FRAME_POINTER_REQUIRED arm_frame_pointer_required |
| |
| #undef TARGET_CAN_ELIMINATE |
| #define TARGET_CAN_ELIMINATE arm_can_eliminate |
| |
| #undef TARGET_CONDITIONAL_REGISTER_USAGE |
| #define TARGET_CONDITIONAL_REGISTER_USAGE arm_conditional_register_usage |
| |
| #undef TARGET_CLASS_LIKELY_SPILLED_P |
| #define TARGET_CLASS_LIKELY_SPILLED_P arm_class_likely_spilled_p |
| |
| #undef TARGET_VECTORIZE_BUILTINS |
| #define TARGET_VECTORIZE_BUILTINS |
| |
| #undef TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION |
| #define TARGET_VECTORIZE_BUILTIN_VECTORIZED_FUNCTION \ |
| arm_builtin_vectorized_function |
| |
| #undef TARGET_VECTOR_ALIGNMENT |
| #define TARGET_VECTOR_ALIGNMENT arm_vector_alignment |
| |
| #undef TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE |
| #define TARGET_VECTORIZE_VECTOR_ALIGNMENT_REACHABLE \ |
| arm_vector_alignment_reachable |
| |
| #undef TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT |
| #define TARGET_VECTORIZE_SUPPORT_VECTOR_MISALIGNMENT \ |
| arm_builtin_support_vector_misalignment |
| |
| #undef TARGET_PREFERRED_RENAME_CLASS |
| #define TARGET_PREFERRED_RENAME_CLASS \ |
| arm_preferred_rename_class |
| |
| #undef TARGET_VECTORIZE_VEC_PERM_CONST_OK |
| #define TARGET_VECTORIZE_VEC_PERM_CONST_OK \ |
| arm_vectorize_vec_perm_const_ok |
| |
| #undef TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST |
| #define TARGET_VECTORIZE_BUILTIN_VECTORIZATION_COST \ |
| arm_builtin_vectorization_cost |
| #undef TARGET_VECTORIZE_ADD_STMT_COST |
| #define TARGET_VECTORIZE_ADD_STMT_COST arm_add_stmt_cost |
| |
| #undef TARGET_CANONICALIZE_COMPARISON |
| #define TARGET_CANONICALIZE_COMPARISON \ |
| arm_canonicalize_comparison |
| |
| #undef TARGET_ASAN_SHADOW_OFFSET |
| #define TARGET_ASAN_SHADOW_OFFSET arm_asan_shadow_offset |
| |
| #undef MAX_INSN_PER_IT_BLOCK |
| #define MAX_INSN_PER_IT_BLOCK (arm_restrict_it ? 1 : 4) |
| |
| #undef TARGET_CAN_USE_DOLOOP_P |
| #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost |
| |
| #undef TARGET_CONST_NOT_OK_FOR_DEBUG_P |
| #define TARGET_CONST_NOT_OK_FOR_DEBUG_P arm_const_not_ok_for_debug_p |
| |
| #undef TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS |
| #define TARGET_CALL_FUSAGE_CONTAINS_NON_CALLEE_CLOBBERS true |
| |
| #undef TARGET_SCHED_FUSION_PRIORITY |
| #define TARGET_SCHED_FUSION_PRIORITY arm_sched_fusion_priority |
| |
| struct gcc_target targetm = TARGET_INITIALIZER; |
| |
| /* Obstack for minipool constant handling. */ |
| static struct obstack minipool_obstack; |
| static char * minipool_startobj; |
| |
| /* The maximum number of insns skipped which |
| will be conditionalised if possible. */ |
| static int max_insns_skipped = 5; |
| |
| extern FILE * asm_out_file; |
| |
| /* True if we are currently building a constant table. */ |
| int making_const_table; |
| |
| /* The processor for which instructions should be scheduled. */ |
| enum processor_type arm_tune = arm_none; |
| |
| /* The current tuning set. */ |
| const struct tune_params *current_tune; |
| |
| /* Which floating point hardware to schedule for. */ |
| int arm_fpu_attr; |
| |
| /* Which floating popint hardware to use. */ |
| const struct arm_fpu_desc *arm_fpu_desc; |
| |
| /* Used for Thumb call_via trampolines. */ |
| rtx thumb_call_via_label[14]; |
| static int thumb_call_reg_needed; |
| |
| /* The bits in this mask specify which |
| instructions we are allowed to generate. */ |
| unsigned long insn_flags = 0; |
| |
| /* The bits in this mask specify which instruction scheduling options should |
| be used. */ |
| unsigned long tune_flags = 0; |
| |
| /* The highest ARM architecture version supported by the |
| target. */ |
| enum base_architecture arm_base_arch = BASE_ARCH_0; |
| |
| /* The following are used in the arm.md file as equivalents to bits |
| in the above two flag variables. */ |
| |
| /* Nonzero if this chip supports the ARM Architecture 3M extensions. */ |
| int arm_arch3m = 0; |
| |
| /* Nonzero if this chip supports the ARM Architecture 4 extensions. */ |
| int arm_arch4 = 0; |
| |
| /* Nonzero if this chip supports the ARM Architecture 4t extensions. */ |
| int arm_arch4t = 0; |
| |
| /* Nonzero if this chip supports the ARM Architecture 5 extensions. */ |
| int arm_arch5 = 0; |
| |
| /* Nonzero if this chip supports the ARM Architecture 5E extensions. */ |
| int arm_arch5e = 0; |
| |
| /* Nonzero if this chip supports the ARM Architecture 6 extensions. */ |
| int arm_arch6 = 0; |
| |
| /* Nonzero if this chip supports the ARM 6K extensions. */ |
| int arm_arch6k = 0; |
| |
| /* Nonzero if instructions present in ARMv6-M can be used. */ |
| int arm_arch6m = 0; |
| |
| /* Nonzero if this chip supports the ARM 7 extensions. */ |
| int arm_arch7 = 0; |
| |
| /* Nonzero if instructions not present in the 'M' profile can be used. */ |
| int arm_arch_notm = 0; |
| |
| /* Nonzero if instructions present in ARMv7E-M can be used. */ |
| int arm_arch7em = 0; |
| |
| /* Nonzero if instructions present in ARMv8 can be used. */ |
| int arm_arch8 = 0; |
| |
| /* Nonzero if this chip can benefit from load scheduling. */ |
| int arm_ld_sched = 0; |
| |
| /* Nonzero if this chip is a StrongARM. */ |
| int arm_tune_strongarm = 0; |
| |
| /* Nonzero if this chip supports Intel Wireless MMX technology. */ |
| int arm_arch_iwmmxt = 0; |
| |
| /* Nonzero if this chip supports Intel Wireless MMX2 technology. */ |
| int arm_arch_iwmmxt2 = 0; |
| |
| /* Nonzero if this chip is an XScale. */ |
| int arm_arch_xscale = 0; |
| |
| /* Nonzero if tuning for XScale */ |
| int arm_tune_xscale = 0; |
| |
| /* Nonzero if we want to tune for stores that access the write-buffer. |
| This typically means an ARM6 or ARM7 with MMU or MPU. */ |
| int arm_tune_wbuf = 0; |
| |
| /* Nonzero if tuning for Cortex-A9. */ |
| int arm_tune_cortex_a9 = 0; |
| |
| /* Nonzero if generating Thumb instructions. */ |
| int thumb_code = 0; |
| |
| /* Nonzero if generating Thumb-1 instructions. */ |
| int thumb1_code = 0; |
| |
| /* Nonzero if we should define __THUMB_INTERWORK__ in the |
| preprocessor. |
| XXX This is a bit of a hack, it's intended to help work around |
| problems in GLD which doesn't understand that armv5t code is |
| interworking clean. */ |
| int arm_cpp_interwork = 0; |
| |
| /* Nonzero if chip supports Thumb 2. */ |
| int arm_arch_thumb2; |
| |
| /* Nonzero if chip supports integer division instruction. */ |
| int arm_arch_arm_hwdiv; |
| int arm_arch_thumb_hwdiv; |
| |
| /* Nonzero if this chip supports the Large Physical Address Extension. */ |
| int arm_arch_lpae; |
| |
| /* Nonzero if chip disallows volatile memory access in IT block. */ |
| int arm_arch_no_volatile_ce; |
| |
| /* Nonzero if we should use Neon to handle 64-bits operations rather |
| than core registers. */ |
| int prefer_neon_for_64bits = 0; |
| |
| /* Nonzero if we shouldn't use literal pools. */ |
| bool arm_disable_literal_pool = false; |
| |
| /* In case of a PRE_INC, POST_INC, PRE_DEC, POST_DEC memory reference, |
| we must report the mode of the memory reference from |
| TARGET_PRINT_OPERAND to TARGET_PRINT_OPERAND_ADDRESS. */ |
| machine_mode output_memory_reference_mode; |
| |
| /* The register number to be used for the PIC offset register. */ |
| unsigned arm_pic_register = INVALID_REGNUM; |
| |
| enum arm_pcs arm_pcs_default; |
| |
| /* For an explanation of these variables, see final_prescan_insn below. */ |
| int arm_ccfsm_state; |
| /* arm_current_cc is also used for Thumb-2 cond_exec blocks. */ |
| enum arm_cond_code arm_current_cc; |
| |
| rtx arm_target_insn; |
| int arm_target_label; |
| /* The number of conditionally executed insns, including the current insn. */ |
| int arm_condexec_count = 0; |
| /* A bitmask specifying the patterns for the IT block. |
| Zero means do not output an IT block before this insn. */ |
| int arm_condexec_mask = 0; |
| /* The number of bits used in arm_condexec_mask. */ |
| int arm_condexec_masklen = 0; |
| |
| /* Nonzero if chip supports the ARMv8 CRC instructions. */ |
| int arm_arch_crc = 0; |
| |
| /* Nonzero if the core has a very small, high-latency, multiply unit. */ |
| int arm_m_profile_small_mul = 0; |
| |
| /* The condition codes of the ARM, and the inverse function. */ |
| static const char * const arm_condition_codes[] = |
| { |
| "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc", |
| "hi", "ls", "ge", "lt", "gt", "le", "al", "nv" |
| }; |
| |
| /* The register numbers in sequence, for passing to arm_gen_load_multiple. */ |
| int arm_regs_in_sequence[] = |
| { |
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 |
| }; |
| |
| #define ARM_LSL_NAME (TARGET_UNIFIED_ASM ? "lsl" : "asl") |
| #define streq(string1, string2) (strcmp (string1, string2) == 0) |
| |
| #define THUMB2_WORK_REGS (0xff & ~( (1 << THUMB_HARD_FRAME_POINTER_REGNUM) \ |
| | (1 << SP_REGNUM) | (1 << PC_REGNUM) \ |
| | (1 << PIC_OFFSET_TABLE_REGNUM))) |
| |
| /* Initialization code. */ |
| |
| struct processors |
| { |
| const char *const name; |
| enum processor_type core; |
| const char *arch; |
| enum base_architecture base_arch; |
| const unsigned long flags; |
| const struct tune_params *const tune; |
| }; |
| |
| |
| #define ARM_PREFETCH_NOT_BENEFICIAL 0, -1, -1 |
| #define ARM_PREFETCH_BENEFICIAL(prefetch_slots,l1_size,l1_line_size) \ |
| prefetch_slots, \ |
| l1_size, \ |
| l1_line_size |
| |
| /* arm generic vectorizer costs. */ |
| static const |
| struct cpu_vec_costs arm_default_vec_cost = { |
| 1, /* scalar_stmt_cost. */ |
| 1, /* scalar load_cost. */ |
| 1, /* scalar_store_cost. */ |
| 1, /* vec_stmt_cost. */ |
| 1, /* vec_to_scalar_cost. */ |
| 1, /* scalar_to_vec_cost. */ |
| 1, /* vec_align_load_cost. */ |
| 1, /* vec_unalign_load_cost. */ |
| 1, /* vec_unalign_store_cost. */ |
| 1, /* vec_store_cost. */ |
| 3, /* cond_taken_branch_cost. */ |
| 1, /* cond_not_taken_branch_cost. */ |
| }; |
| |
| /* Cost tables for AArch32 + AArch64 cores should go in aarch-cost-tables.h */ |
| #include "aarch-cost-tables.h" |
| |
| |
| |
| const struct cpu_cost_table cortexa9_extra_costs = |
| { |
| /* ALU */ |
| { |
| 0, /* arith. */ |
| 0, /* logical. */ |
| 0, /* shift. */ |
| COSTS_N_INSNS (1), /* shift_reg. */ |
| COSTS_N_INSNS (1), /* arith_shift. */ |
| COSTS_N_INSNS (2), /* arith_shift_reg. */ |
| 0, /* log_shift. */ |
| COSTS_N_INSNS (1), /* log_shift_reg. */ |
| COSTS_N_INSNS (1), /* extend. */ |
| COSTS_N_INSNS (2), /* extend_arith. */ |
| COSTS_N_INSNS (1), /* bfi. */ |
| COSTS_N_INSNS (1), /* bfx. */ |
| 0, /* clz. */ |
| 0, /* rev. */ |
| 0, /* non_exec. */ |
| true /* non_exec_costs_exec. */ |
| }, |
| { |
| /* MULT SImode */ |
| { |
| COSTS_N_INSNS (3), /* simple. */ |
| COSTS_N_INSNS (3), /* flag_setting. */ |
| COSTS_N_INSNS (2), /* extend. */ |
| COSTS_N_INSNS (3), /* add. */ |
| COSTS_N_INSNS (2), /* extend_add. */ |
| COSTS_N_INSNS (30) /* idiv. No HW div on Cortex A9. */ |
| }, |
| /* MULT DImode */ |
| { |
| 0, /* simple (N/A). */ |
| 0, /* flag_setting (N/A). */ |
| COSTS_N_INSNS (4), /* extend. */ |
| 0, /* add (N/A). */ |
| COSTS_N_INSNS (4), /* extend_add. */ |
| 0 /* idiv (N/A). */ |
| } |
| }, |
| /* LD/ST */ |
| { |
| COSTS_N_INSNS (2), /* load. */ |
| COSTS_N_INSNS (2), /* load_sign_extend. */ |
| COSTS_N_INSNS (2), /* ldrd. */ |
| COSTS_N_INSNS (2), /* ldm_1st. */ |
| 1, /* ldm_regs_per_insn_1st. */ |
| 2, /* ldm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (5), /* loadf. */ |
| COSTS_N_INSNS (5), /* loadd. */ |
| COSTS_N_INSNS (1), /* load_unaligned. */ |
| COSTS_N_INSNS (2), /* store. */ |
| COSTS_N_INSNS (2), /* strd. */ |
| COSTS_N_INSNS (2), /* stm_1st. */ |
| 1, /* stm_regs_per_insn_1st. */ |
| 2, /* stm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (1), /* storef. */ |
| COSTS_N_INSNS (1), /* stored. */ |
| COSTS_N_INSNS (1) /* store_unaligned. */ |
| }, |
| { |
| /* FP SFmode */ |
| { |
| COSTS_N_INSNS (14), /* div. */ |
| COSTS_N_INSNS (4), /* mult. */ |
| COSTS_N_INSNS (7), /* mult_addsub. */ |
| COSTS_N_INSNS (30), /* fma. */ |
| COSTS_N_INSNS (3), /* addsub. */ |
| COSTS_N_INSNS (1), /* fpconst. */ |
| COSTS_N_INSNS (1), /* neg. */ |
| COSTS_N_INSNS (3), /* compare. */ |
| COSTS_N_INSNS (3), /* widen. */ |
| COSTS_N_INSNS (3), /* narrow. */ |
| COSTS_N_INSNS (3), /* toint. */ |
| COSTS_N_INSNS (3), /* fromint. */ |
| COSTS_N_INSNS (3) /* roundint. */ |
| }, |
| /* FP DFmode */ |
| { |
| COSTS_N_INSNS (24), /* div. */ |
| COSTS_N_INSNS (5), /* mult. */ |
| COSTS_N_INSNS (8), /* mult_addsub. */ |
| COSTS_N_INSNS (30), /* fma. */ |
| COSTS_N_INSNS (3), /* addsub. */ |
| COSTS_N_INSNS (1), /* fpconst. */ |
| COSTS_N_INSNS (1), /* neg. */ |
| COSTS_N_INSNS (3), /* compare. */ |
| COSTS_N_INSNS (3), /* widen. */ |
| COSTS_N_INSNS (3), /* narrow. */ |
| COSTS_N_INSNS (3), /* toint. */ |
| COSTS_N_INSNS (3), /* fromint. */ |
| COSTS_N_INSNS (3) /* roundint. */ |
| } |
| }, |
| /* Vector */ |
| { |
| COSTS_N_INSNS (1) /* alu. */ |
| } |
| }; |
| |
| const struct cpu_cost_table cortexa8_extra_costs = |
| { |
| /* ALU */ |
| { |
| 0, /* arith. */ |
| 0, /* logical. */ |
| COSTS_N_INSNS (1), /* shift. */ |
| 0, /* shift_reg. */ |
| COSTS_N_INSNS (1), /* arith_shift. */ |
| 0, /* arith_shift_reg. */ |
| COSTS_N_INSNS (1), /* log_shift. */ |
| 0, /* log_shift_reg. */ |
| 0, /* extend. */ |
| 0, /* extend_arith. */ |
| 0, /* bfi. */ |
| 0, /* bfx. */ |
| 0, /* clz. */ |
| 0, /* rev. */ |
| 0, /* non_exec. */ |
| true /* non_exec_costs_exec. */ |
| }, |
| { |
| /* MULT SImode */ |
| { |
| COSTS_N_INSNS (1), /* simple. */ |
| COSTS_N_INSNS (1), /* flag_setting. */ |
| COSTS_N_INSNS (1), /* extend. */ |
| COSTS_N_INSNS (1), /* add. */ |
| COSTS_N_INSNS (1), /* extend_add. */ |
| COSTS_N_INSNS (30) /* idiv. No HW div on Cortex A8. */ |
| }, |
| /* MULT DImode */ |
| { |
| 0, /* simple (N/A). */ |
| 0, /* flag_setting (N/A). */ |
| COSTS_N_INSNS (2), /* extend. */ |
| 0, /* add (N/A). */ |
| COSTS_N_INSNS (2), /* extend_add. */ |
| 0 /* idiv (N/A). */ |
| } |
| }, |
| /* LD/ST */ |
| { |
| COSTS_N_INSNS (1), /* load. */ |
| COSTS_N_INSNS (1), /* load_sign_extend. */ |
| COSTS_N_INSNS (1), /* ldrd. */ |
| COSTS_N_INSNS (1), /* ldm_1st. */ |
| 1, /* ldm_regs_per_insn_1st. */ |
| 2, /* ldm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (1), /* loadf. */ |
| COSTS_N_INSNS (1), /* loadd. */ |
| COSTS_N_INSNS (1), /* load_unaligned. */ |
| COSTS_N_INSNS (1), /* store. */ |
| COSTS_N_INSNS (1), /* strd. */ |
| COSTS_N_INSNS (1), /* stm_1st. */ |
| 1, /* stm_regs_per_insn_1st. */ |
| 2, /* stm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (1), /* storef. */ |
| COSTS_N_INSNS (1), /* stored. */ |
| COSTS_N_INSNS (1) /* store_unaligned. */ |
| }, |
| { |
| /* FP SFmode */ |
| { |
| COSTS_N_INSNS (36), /* div. */ |
| COSTS_N_INSNS (11), /* mult. */ |
| COSTS_N_INSNS (20), /* mult_addsub. */ |
| COSTS_N_INSNS (30), /* fma. */ |
| COSTS_N_INSNS (9), /* addsub. */ |
| COSTS_N_INSNS (3), /* fpconst. */ |
| COSTS_N_INSNS (3), /* neg. */ |
| COSTS_N_INSNS (6), /* compare. */ |
| COSTS_N_INSNS (4), /* widen. */ |
| COSTS_N_INSNS (4), /* narrow. */ |
| COSTS_N_INSNS (8), /* toint. */ |
| COSTS_N_INSNS (8), /* fromint. */ |
| COSTS_N_INSNS (8) /* roundint. */ |
| }, |
| /* FP DFmode */ |
| { |
| COSTS_N_INSNS (64), /* div. */ |
| COSTS_N_INSNS (16), /* mult. */ |
| COSTS_N_INSNS (25), /* mult_addsub. */ |
| COSTS_N_INSNS (30), /* fma. */ |
| COSTS_N_INSNS (9), /* addsub. */ |
| COSTS_N_INSNS (3), /* fpconst. */ |
| COSTS_N_INSNS (3), /* neg. */ |
| COSTS_N_INSNS (6), /* compare. */ |
| COSTS_N_INSNS (6), /* widen. */ |
| COSTS_N_INSNS (6), /* narrow. */ |
| COSTS_N_INSNS (8), /* toint. */ |
| COSTS_N_INSNS (8), /* fromint. */ |
| COSTS_N_INSNS (8) /* roundint. */ |
| } |
| }, |
| /* Vector */ |
| { |
| COSTS_N_INSNS (1) /* alu. */ |
| } |
| }; |
| |
| const struct cpu_cost_table cortexa5_extra_costs = |
| { |
| /* ALU */ |
| { |
| 0, /* arith. */ |
| 0, /* logical. */ |
| COSTS_N_INSNS (1), /* shift. */ |
| COSTS_N_INSNS (1), /* shift_reg. */ |
| COSTS_N_INSNS (1), /* arith_shift. */ |
| COSTS_N_INSNS (1), /* arith_shift_reg. */ |
| COSTS_N_INSNS (1), /* log_shift. */ |
| COSTS_N_INSNS (1), /* log_shift_reg. */ |
| COSTS_N_INSNS (1), /* extend. */ |
| COSTS_N_INSNS (1), /* extend_arith. */ |
| COSTS_N_INSNS (1), /* bfi. */ |
| COSTS_N_INSNS (1), /* bfx. */ |
| COSTS_N_INSNS (1), /* clz. */ |
| COSTS_N_INSNS (1), /* rev. */ |
| 0, /* non_exec. */ |
| true /* non_exec_costs_exec. */ |
| }, |
| |
| { |
| /* MULT SImode */ |
| { |
| 0, /* simple. */ |
| COSTS_N_INSNS (1), /* flag_setting. */ |
| COSTS_N_INSNS (1), /* extend. */ |
| COSTS_N_INSNS (1), /* add. */ |
| COSTS_N_INSNS (1), /* extend_add. */ |
| COSTS_N_INSNS (7) /* idiv. */ |
| }, |
| /* MULT DImode */ |
| { |
| 0, /* simple (N/A). */ |
| 0, /* flag_setting (N/A). */ |
| COSTS_N_INSNS (1), /* extend. */ |
| 0, /* add. */ |
| COSTS_N_INSNS (2), /* extend_add. */ |
| 0 /* idiv (N/A). */ |
| } |
| }, |
| /* LD/ST */ |
| { |
| COSTS_N_INSNS (1), /* load. */ |
| COSTS_N_INSNS (1), /* load_sign_extend. */ |
| COSTS_N_INSNS (6), /* ldrd. */ |
| COSTS_N_INSNS (1), /* ldm_1st. */ |
| 1, /* ldm_regs_per_insn_1st. */ |
| 2, /* ldm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (2), /* loadf. */ |
| COSTS_N_INSNS (4), /* loadd. */ |
| COSTS_N_INSNS (1), /* load_unaligned. */ |
| COSTS_N_INSNS (1), /* store. */ |
| COSTS_N_INSNS (3), /* strd. */ |
| COSTS_N_INSNS (1), /* stm_1st. */ |
| 1, /* stm_regs_per_insn_1st. */ |
| 2, /* stm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (2), /* storef. */ |
| COSTS_N_INSNS (2), /* stored. */ |
| COSTS_N_INSNS (1) /* store_unaligned. */ |
| }, |
| { |
| /* FP SFmode */ |
| { |
| COSTS_N_INSNS (15), /* div. */ |
| COSTS_N_INSNS (3), /* mult. */ |
| COSTS_N_INSNS (7), /* mult_addsub. */ |
| COSTS_N_INSNS (7), /* fma. */ |
| COSTS_N_INSNS (3), /* addsub. */ |
| COSTS_N_INSNS (3), /* fpconst. */ |
| COSTS_N_INSNS (3), /* neg. */ |
| COSTS_N_INSNS (3), /* compare. */ |
| COSTS_N_INSNS (3), /* widen. */ |
| COSTS_N_INSNS (3), /* narrow. */ |
| COSTS_N_INSNS (3), /* toint. */ |
| COSTS_N_INSNS (3), /* fromint. */ |
| COSTS_N_INSNS (3) /* roundint. */ |
| }, |
| /* FP DFmode */ |
| { |
| COSTS_N_INSNS (30), /* div. */ |
| COSTS_N_INSNS (6), /* mult. */ |
| COSTS_N_INSNS (10), /* mult_addsub. */ |
| COSTS_N_INSNS (7), /* fma. */ |
| COSTS_N_INSNS (3), /* addsub. */ |
| COSTS_N_INSNS (3), /* fpconst. */ |
| COSTS_N_INSNS (3), /* neg. */ |
| COSTS_N_INSNS (3), /* compare. */ |
| COSTS_N_INSNS (3), /* widen. */ |
| COSTS_N_INSNS (3), /* narrow. */ |
| COSTS_N_INSNS (3), /* toint. */ |
| COSTS_N_INSNS (3), /* fromint. */ |
| COSTS_N_INSNS (3) /* roundint. */ |
| } |
| }, |
| /* Vector */ |
| { |
| COSTS_N_INSNS (1) /* alu. */ |
| } |
| }; |
| |
| |
| const struct cpu_cost_table cortexa7_extra_costs = |
| { |
| /* ALU */ |
| { |
| 0, /* arith. */ |
| 0, /* logical. */ |
| COSTS_N_INSNS (1), /* shift. */ |
| COSTS_N_INSNS (1), /* shift_reg. */ |
| COSTS_N_INSNS (1), /* arith_shift. */ |
| COSTS_N_INSNS (1), /* arith_shift_reg. */ |
| COSTS_N_INSNS (1), /* log_shift. */ |
| COSTS_N_INSNS (1), /* log_shift_reg. */ |
| COSTS_N_INSNS (1), /* extend. */ |
| COSTS_N_INSNS (1), /* extend_arith. */ |
| COSTS_N_INSNS (1), /* bfi. */ |
| COSTS_N_INSNS (1), /* bfx. */ |
| COSTS_N_INSNS (1), /* clz. */ |
| COSTS_N_INSNS (1), /* rev. */ |
| 0, /* non_exec. */ |
| true /* non_exec_costs_exec. */ |
| }, |
| |
| { |
| /* MULT SImode */ |
| { |
| 0, /* simple. */ |
| COSTS_N_INSNS (1), /* flag_setting. */ |
| COSTS_N_INSNS (1), /* extend. */ |
| COSTS_N_INSNS (1), /* add. */ |
| COSTS_N_INSNS (1), /* extend_add. */ |
| COSTS_N_INSNS (7) /* idiv. */ |
| }, |
| /* MULT DImode */ |
| { |
| 0, /* simple (N/A). */ |
| 0, /* flag_setting (N/A). */ |
| COSTS_N_INSNS (1), /* extend. */ |
| 0, /* add. */ |
| COSTS_N_INSNS (2), /* extend_add. */ |
| 0 /* idiv (N/A). */ |
| } |
| }, |
| /* LD/ST */ |
| { |
| COSTS_N_INSNS (1), /* load. */ |
| COSTS_N_INSNS (1), /* load_sign_extend. */ |
| COSTS_N_INSNS (3), /* ldrd. */ |
| COSTS_N_INSNS (1), /* ldm_1st. */ |
| 1, /* ldm_regs_per_insn_1st. */ |
| 2, /* ldm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (2), /* loadf. */ |
| COSTS_N_INSNS (2), /* loadd. */ |
| COSTS_N_INSNS (1), /* load_unaligned. */ |
| COSTS_N_INSNS (1), /* store. */ |
| COSTS_N_INSNS (3), /* strd. */ |
| COSTS_N_INSNS (1), /* stm_1st. */ |
| 1, /* stm_regs_per_insn_1st. */ |
| 2, /* stm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (2), /* storef. */ |
| COSTS_N_INSNS (2), /* stored. */ |
| COSTS_N_INSNS (1) /* store_unaligned. */ |
| }, |
| { |
| /* FP SFmode */ |
| { |
| COSTS_N_INSNS (15), /* div. */ |
| COSTS_N_INSNS (3), /* mult. */ |
| COSTS_N_INSNS (7), /* mult_addsub. */ |
| COSTS_N_INSNS (7), /* fma. */ |
| COSTS_N_INSNS (3), /* addsub. */ |
| COSTS_N_INSNS (3), /* fpconst. */ |
| COSTS_N_INSNS (3), /* neg. */ |
| COSTS_N_INSNS (3), /* compare. */ |
| COSTS_N_INSNS (3), /* widen. */ |
| COSTS_N_INSNS (3), /* narrow. */ |
| COSTS_N_INSNS (3), /* toint. */ |
| COSTS_N_INSNS (3), /* fromint. */ |
| COSTS_N_INSNS (3) /* roundint. */ |
| }, |
| /* FP DFmode */ |
| { |
| COSTS_N_INSNS (30), /* div. */ |
| COSTS_N_INSNS (6), /* mult. */ |
| COSTS_N_INSNS (10), /* mult_addsub. */ |
| COSTS_N_INSNS (7), /* fma. */ |
| COSTS_N_INSNS (3), /* addsub. */ |
| COSTS_N_INSNS (3), /* fpconst. */ |
| COSTS_N_INSNS (3), /* neg. */ |
| COSTS_N_INSNS (3), /* compare. */ |
| COSTS_N_INSNS (3), /* widen. */ |
| COSTS_N_INSNS (3), /* narrow. */ |
| COSTS_N_INSNS (3), /* toint. */ |
| COSTS_N_INSNS (3), /* fromint. */ |
| COSTS_N_INSNS (3) /* roundint. */ |
| } |
| }, |
| /* Vector */ |
| { |
| COSTS_N_INSNS (1) /* alu. */ |
| } |
| }; |
| |
| const struct cpu_cost_table cortexa12_extra_costs = |
| { |
| /* ALU */ |
| { |
| 0, /* arith. */ |
| 0, /* logical. */ |
| 0, /* shift. */ |
| COSTS_N_INSNS (1), /* shift_reg. */ |
| COSTS_N_INSNS (1), /* arith_shift. */ |
| COSTS_N_INSNS (1), /* arith_shift_reg. */ |
| COSTS_N_INSNS (1), /* log_shift. */ |
| COSTS_N_INSNS (1), /* log_shift_reg. */ |
| 0, /* extend. */ |
| COSTS_N_INSNS (1), /* extend_arith. */ |
| 0, /* bfi. */ |
| COSTS_N_INSNS (1), /* bfx. */ |
| COSTS_N_INSNS (1), /* clz. */ |
| COSTS_N_INSNS (1), /* rev. */ |
| 0, /* non_exec. */ |
| true /* non_exec_costs_exec. */ |
| }, |
| /* MULT SImode */ |
| { |
| { |
| COSTS_N_INSNS (2), /* simple. */ |
| COSTS_N_INSNS (3), /* flag_setting. */ |
| COSTS_N_INSNS (2), /* extend. */ |
| COSTS_N_INSNS (3), /* add. */ |
| COSTS_N_INSNS (2), /* extend_add. */ |
| COSTS_N_INSNS (18) /* idiv. */ |
| }, |
| /* MULT DImode */ |
| { |
| 0, /* simple (N/A). */ |
| 0, /* flag_setting (N/A). */ |
| COSTS_N_INSNS (3), /* extend. */ |
| 0, /* add (N/A). */ |
| COSTS_N_INSNS (3), /* extend_add. */ |
| 0 /* idiv (N/A). */ |
| } |
| }, |
| /* LD/ST */ |
| { |
| COSTS_N_INSNS (3), /* load. */ |
| COSTS_N_INSNS (3), /* load_sign_extend. */ |
| COSTS_N_INSNS (3), /* ldrd. */ |
| COSTS_N_INSNS (3), /* ldm_1st. */ |
| 1, /* ldm_regs_per_insn_1st. */ |
| 2, /* ldm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (3), /* loadf. */ |
| COSTS_N_INSNS (3), /* loadd. */ |
| 0, /* load_unaligned. */ |
| 0, /* store. */ |
| 0, /* strd. */ |
| 0, /* stm_1st. */ |
| 1, /* stm_regs_per_insn_1st. */ |
| 2, /* stm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (2), /* storef. */ |
| COSTS_N_INSNS (2), /* stored. */ |
| 0 /* store_unaligned. */ |
| }, |
| { |
| /* FP SFmode */ |
| { |
| COSTS_N_INSNS (17), /* div. */ |
| COSTS_N_INSNS (4), /* mult. */ |
| COSTS_N_INSNS (8), /* mult_addsub. */ |
| COSTS_N_INSNS (8), /* fma. */ |
| COSTS_N_INSNS (4), /* addsub. */ |
| COSTS_N_INSNS (2), /* fpconst. */ |
| COSTS_N_INSNS (2), /* neg. */ |
| COSTS_N_INSNS (2), /* compare. */ |
| COSTS_N_INSNS (4), /* widen. */ |
| COSTS_N_INSNS (4), /* narrow. */ |
| COSTS_N_INSNS (4), /* toint. */ |
| COSTS_N_INSNS (4), /* fromint. */ |
| COSTS_N_INSNS (4) /* roundint. */ |
| }, |
| /* FP DFmode */ |
| { |
| COSTS_N_INSNS (31), /* div. */ |
| COSTS_N_INSNS (4), /* mult. */ |
| COSTS_N_INSNS (8), /* mult_addsub. */ |
| COSTS_N_INSNS (8), /* fma. */ |
| COSTS_N_INSNS (4), /* addsub. */ |
| COSTS_N_INSNS (2), /* fpconst. */ |
| COSTS_N_INSNS (2), /* neg. */ |
| COSTS_N_INSNS (2), /* compare. */ |
| COSTS_N_INSNS (4), /* widen. */ |
| COSTS_N_INSNS (4), /* narrow. */ |
| COSTS_N_INSNS (4), /* toint. */ |
| COSTS_N_INSNS (4), /* fromint. */ |
| COSTS_N_INSNS (4) /* roundint. */ |
| } |
| }, |
| /* Vector */ |
| { |
| COSTS_N_INSNS (1) /* alu. */ |
| } |
| }; |
| |
| const struct cpu_cost_table cortexa15_extra_costs = |
| { |
| /* ALU */ |
| { |
| 0, /* arith. */ |
| 0, /* logical. */ |
| 0, /* shift. */ |
| 0, /* shift_reg. */ |
| COSTS_N_INSNS (1), /* arith_shift. */ |
| COSTS_N_INSNS (1), /* arith_shift_reg. */ |
| COSTS_N_INSNS (1), /* log_shift. */ |
| COSTS_N_INSNS (1), /* log_shift_reg. */ |
| 0, /* extend. */ |
| COSTS_N_INSNS (1), /* extend_arith. */ |
| COSTS_N_INSNS (1), /* bfi. */ |
| 0, /* bfx. */ |
| 0, /* clz. */ |
| 0, /* rev. */ |
| 0, /* non_exec. */ |
| true /* non_exec_costs_exec. */ |
| }, |
| /* MULT SImode */ |
| { |
| { |
| COSTS_N_INSNS (2), /* simple. */ |
| COSTS_N_INSNS (3), /* flag_setting. */ |
| COSTS_N_INSNS (2), /* extend. */ |
| COSTS_N_INSNS (2), /* add. */ |
| COSTS_N_INSNS (2), /* extend_add. */ |
| COSTS_N_INSNS (18) /* idiv. */ |
| }, |
| /* MULT DImode */ |
| { |
| 0, /* simple (N/A). */ |
| 0, /* flag_setting (N/A). */ |
| COSTS_N_INSNS (3), /* extend. */ |
| 0, /* add (N/A). */ |
| COSTS_N_INSNS (3), /* extend_add. */ |
| 0 /* idiv (N/A). */ |
| } |
| }, |
| /* LD/ST */ |
| { |
| COSTS_N_INSNS (3), /* load. */ |
| COSTS_N_INSNS (3), /* load_sign_extend. */ |
| COSTS_N_INSNS (3), /* ldrd. */ |
| COSTS_N_INSNS (4), /* ldm_1st. */ |
| 1, /* ldm_regs_per_insn_1st. */ |
| 2, /* ldm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (4), /* loadf. */ |
| COSTS_N_INSNS (4), /* loadd. */ |
| 0, /* load_unaligned. */ |
| 0, /* store. */ |
| 0, /* strd. */ |
| COSTS_N_INSNS (1), /* stm_1st. */ |
| 1, /* stm_regs_per_insn_1st. */ |
| 2, /* stm_regs_per_insn_subsequent. */ |
| 0, /* storef. */ |
| 0, /* stored. */ |
| 0 /* store_unaligned. */ |
| }, |
| { |
| /* FP SFmode */ |
| { |
| COSTS_N_INSNS (17), /* div. */ |
| COSTS_N_INSNS (4), /* mult. */ |
| COSTS_N_INSNS (8), /* mult_addsub. */ |
| COSTS_N_INSNS (8), /* fma. */ |
| COSTS_N_INSNS (4), /* addsub. */ |
| COSTS_N_INSNS (2), /* fpconst. */ |
| COSTS_N_INSNS (2), /* neg. */ |
| COSTS_N_INSNS (5), /* compare. */ |
| COSTS_N_INSNS (4), /* widen. */ |
| COSTS_N_INSNS (4), /* narrow. */ |
| COSTS_N_INSNS (4), /* toint. */ |
| COSTS_N_INSNS (4), /* fromint. */ |
| COSTS_N_INSNS (4) /* roundint. */ |
| }, |
| /* FP DFmode */ |
| { |
| COSTS_N_INSNS (31), /* div. */ |
| COSTS_N_INSNS (4), /* mult. */ |
| COSTS_N_INSNS (8), /* mult_addsub. */ |
| COSTS_N_INSNS (8), /* fma. */ |
| COSTS_N_INSNS (4), /* addsub. */ |
| COSTS_N_INSNS (2), /* fpconst. */ |
| COSTS_N_INSNS (2), /* neg. */ |
| COSTS_N_INSNS (2), /* compare. */ |
| COSTS_N_INSNS (4), /* widen. */ |
| COSTS_N_INSNS (4), /* narrow. */ |
| COSTS_N_INSNS (4), /* toint. */ |
| COSTS_N_INSNS (4), /* fromint. */ |
| COSTS_N_INSNS (4) /* roundint. */ |
| } |
| }, |
| /* Vector */ |
| { |
| COSTS_N_INSNS (1) /* alu. */ |
| } |
| }; |
| |
| const struct cpu_cost_table v7m_extra_costs = |
| { |
| /* ALU */ |
| { |
| 0, /* arith. */ |
| 0, /* logical. */ |
| 0, /* shift. */ |
| 0, /* shift_reg. */ |
| 0, /* arith_shift. */ |
| COSTS_N_INSNS (1), /* arith_shift_reg. */ |
| 0, /* log_shift. */ |
| COSTS_N_INSNS (1), /* log_shift_reg. */ |
| 0, /* extend. */ |
| COSTS_N_INSNS (1), /* extend_arith. */ |
| 0, /* bfi. */ |
| 0, /* bfx. */ |
| 0, /* clz. */ |
| 0, /* rev. */ |
| COSTS_N_INSNS (1), /* non_exec. */ |
| false /* non_exec_costs_exec. */ |
| }, |
| { |
| /* MULT SImode */ |
| { |
| COSTS_N_INSNS (1), /* simple. */ |
| COSTS_N_INSNS (1), /* flag_setting. */ |
| COSTS_N_INSNS (2), /* extend. */ |
| COSTS_N_INSNS (1), /* add. */ |
| COSTS_N_INSNS (3), /* extend_add. */ |
| COSTS_N_INSNS (8) /* idiv. */ |
| }, |
| /* MULT DImode */ |
| { |
| 0, /* simple (N/A). */ |
| 0, /* flag_setting (N/A). */ |
| COSTS_N_INSNS (2), /* extend. */ |
| 0, /* add (N/A). */ |
| COSTS_N_INSNS (3), /* extend_add. */ |
| 0 /* idiv (N/A). */ |
| } |
| }, |
| /* LD/ST */ |
| { |
| COSTS_N_INSNS (2), /* load. */ |
| 0, /* load_sign_extend. */ |
| COSTS_N_INSNS (3), /* ldrd. */ |
| COSTS_N_INSNS (2), /* ldm_1st. */ |
| 1, /* ldm_regs_per_insn_1st. */ |
| 1, /* ldm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (2), /* loadf. */ |
| COSTS_N_INSNS (3), /* loadd. */ |
| COSTS_N_INSNS (1), /* load_unaligned. */ |
| COSTS_N_INSNS (2), /* store. */ |
| COSTS_N_INSNS (3), /* strd. */ |
| COSTS_N_INSNS (2), /* stm_1st. */ |
| 1, /* stm_regs_per_insn_1st. */ |
| 1, /* stm_regs_per_insn_subsequent. */ |
| COSTS_N_INSNS (2), /* storef. */ |
| COSTS_N_INSNS (3), /* stored. */ |
| COSTS_N_INSNS (1) /* store_unaligned. */ |
| }, |
| { |
| /* FP SFmode */ |
| { |
| COSTS_N_INSNS (7), /* div. */ |
| COSTS_N_INSNS (2), /* mult. */ |
| COSTS_N_INSNS (5), /* mult_addsub. */ |
| COSTS_N_INSNS (3), /* fma. */ |
| COSTS_N_INSNS (1), /* addsub. */ |
| 0, /* fpconst. */ |
| 0, /* neg. */ |
| 0, /* compare. */ |
| 0, /* widen. */ |
| 0, /* narrow. */ |
| 0, /* toint. */ |
| 0, /* fromint. */ |
| 0 /* roundint. */ |
| }, |
| /* FP DFmode */ |
| { |
| COSTS_N_INSNS (15), /* div. */ |
| COSTS_N_INSNS (5), /* mult. */ |
| COSTS_N_INSNS (7), /* mult_addsub. */ |
| COSTS_N_INSNS (7), /* fma. */ |
| COSTS_N_INSNS (3), /* addsub. */ |
| 0, /* fpconst. */ |
| 0, /* neg. */ |
| 0, /* compare. */ |
| 0, /* widen. */ |
| 0, /* narrow. */ |
| 0, /* toint. */ |
| 0, /* fromint. */ |
| 0 /* roundint. */ |
| } |
| }, |
| /* Vector */ |
| { |
| COSTS_N_INSNS (1) /* alu. */ |
| } |
| }; |
| |
| #define ARM_FUSE_NOTHING (0) |
| #define ARM_FUSE_MOVW_MOVT (1 << 0) |
| |
| const struct tune_params arm_slowmul_tune = |
| { |
| arm_slowmul_rtx_costs, |
| NULL, |
| NULL, /* Sched adj cost. */ |
| 3, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| true, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_fastmul_tune = |
| { |
| arm_fastmul_rtx_costs, |
| NULL, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| true, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| /* StrongARM has early execution of branches, so a sequence that is worth |
| skipping is shorter. Set max_insns_skipped to a lower value. */ |
| |
| const struct tune_params arm_strongarm_tune = |
| { |
| arm_fastmul_rtx_costs, |
| NULL, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 3, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| true, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_xscale_tune = |
| { |
| arm_xscale_rtx_costs, |
| NULL, |
| xscale_sched_adjust_cost, |
| 2, /* Constant limit. */ |
| 3, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| true, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_9e_tune = |
| { |
| arm_9e_rtx_costs, |
| NULL, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| true, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_v6t2_tune = |
| { |
| arm_9e_rtx_costs, |
| NULL, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| /* Generic Cortex tuning. Use more specific tunings if appropriate. */ |
| const struct tune_params arm_cortex_tune = |
| { |
| arm_9e_rtx_costs, |
| &generic_extra_costs, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_cortex_a8_tune = |
| { |
| arm_9e_rtx_costs, |
| &cortexa8_extra_costs, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| true, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_cortex_a7_tune = |
| { |
| arm_9e_rtx_costs, |
| &cortexa7_extra_costs, |
| NULL, |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| true, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_cortex_a15_tune = |
| { |
| arm_9e_rtx_costs, |
| &cortexa15_extra_costs, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 2, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| true, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| true, true, /* Prefer 32-bit encodings. */ |
| true, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_FULL /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_cortex_a53_tune = |
| { |
| arm_9e_rtx_costs, |
| &cortexa53_extra_costs, |
| NULL, /* Scheduler cost adjustment. */ |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| true, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_MOVW_MOVT, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_cortex_a57_tune = |
| { |
| arm_9e_rtx_costs, |
| &cortexa57_extra_costs, |
| NULL, /* Scheduler cost adjustment. */ |
| 1, /* Constant limit. */ |
| 2, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| true, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| true, true, /* Prefer 32-bit encodings. */ |
| true, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_MOVW_MOVT, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_FULL /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_xgene1_tune = |
| { |
| arm_9e_rtx_costs, |
| &xgene1_extra_costs, |
| NULL, /* Scheduler cost adjustment. */ |
| 1, /* Constant limit. */ |
| 2, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| true, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| true, true, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 32, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| /* Branches can be dual-issued on Cortex-A5, so conditional execution is |
| less appealing. Set max_insns_skipped to a low value. */ |
| |
| const struct tune_params arm_cortex_a5_tune = |
| { |
| arm_9e_rtx_costs, |
| &cortexa5_extra_costs, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 1, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_cortex_a5_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {false, false}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| true, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_cortex_a9_tune = |
| { |
| arm_9e_rtx_costs, |
| &cortexa9_extra_costs, |
| cortex_a9_sched_adjust_cost, |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_BENEFICIAL(4,32,32), |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_cortex_a12_tune = |
| { |
| arm_9e_rtx_costs, |
| &cortexa12_extra_costs, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 2, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| true, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| true, true, /* Prefer 32-bit encodings. */ |
| true, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_MOVW_MOVT, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| /* armv7m tuning. On Cortex-M4 cores for example, MOVW/MOVT take a single |
| cycle to execute each. An LDR from the constant pool also takes two cycles |
| to execute, but mildly increases pipelining opportunity (consecutive |
| loads/stores can be pipelined together, saving one cycle), and may also |
| improve icache utilisation. Hence we prefer the constant pool for such |
| processors. */ |
| |
| const struct tune_params arm_v7m_tune = |
| { |
| arm_9e_rtx_costs, |
| &v7m_extra_costs, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 2, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| true, /* Prefer constant pool. */ |
| arm_cortex_m_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {false, false}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| /* Cortex-M7 tuning. */ |
| |
| const struct tune_params arm_cortex_m7_tune = |
| { |
| arm_9e_rtx_costs, |
| &v7m_extra_costs, |
| NULL, /* Sched adj cost. */ |
| 0, /* Constant limit. */ |
| 1, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| true, /* Prefer constant pool. */ |
| arm_cortex_m7_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| /* The arm_v6m_tune is duplicated from arm_cortex_tune, rather than |
| arm_v6t2_tune. It is used for cortex-m0, cortex-m1 and cortex-m0plus. */ |
| const struct tune_params arm_v6m_tune = |
| { |
| arm_9e_rtx_costs, |
| NULL, |
| NULL, /* Sched adj cost. */ |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| false, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {false, false}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| const struct tune_params arm_fa726te_tune = |
| { |
| arm_9e_rtx_costs, |
| NULL, |
| fa726te_sched_adjust_cost, |
| 1, /* Constant limit. */ |
| 5, /* Max cond insns. */ |
| ARM_PREFETCH_NOT_BENEFICIAL, |
| true, /* Prefer constant pool. */ |
| arm_default_branch_cost, |
| false, /* Prefer LDRD/STRD. */ |
| {true, true}, /* Prefer non short circuit. */ |
| &arm_default_vec_cost, /* Vectorizer costs. */ |
| false, /* Prefer Neon for 64-bits bitops. */ |
| false, false, /* Prefer 32-bit encodings. */ |
| false, /* Prefer Neon for stringops. */ |
| 8, /* Maximum insns to inline memset. */ |
| ARM_FUSE_NOTHING, /* Fuseable pairs of instructions. */ |
| ARM_SCHED_AUTOPREF_OFF /* Sched L2 autopref. */ |
| }; |
| |
| |
| /* Not all of these give usefully different compilation alternatives, |
| but there is no simple way of generalizing them. */ |
| static const struct processors all_cores[] = |
| { |
| /* ARM Cores */ |
| #define ARM_CORE(NAME, X, IDENT, ARCH, FLAGS, COSTS) \ |
| {NAME, IDENT, #ARCH, BASE_ARCH_##ARCH, \ |
| FLAGS | FL_FOR_ARCH##ARCH, &arm_##COSTS##_tune}, |
| #include "arm-cores.def" |
| #undef ARM_CORE |
| {NULL, arm_none, NULL, BASE_ARCH_0, 0, NULL} |
| }; |
| |
| static const struct processors all_architectures[] = |
| { |
| /* ARM Architectures */ |
| /* We don't specify tuning costs here as it will be figured out |
| from the core. */ |
| |
| #define ARM_ARCH(NAME, CORE, ARCH, FLAGS) \ |
| {NAME, CORE, #ARCH, BASE_ARCH_##ARCH, FLAGS, NULL}, |
| #include "arm-arches.def" |
| #undef ARM_ARCH |
| {NULL, arm_none, NULL, BASE_ARCH_0, 0, NULL} |
| }; |
| |
| |
| /* These are populated as commandline arguments are processed, or NULL |
| if not specified. */ |
| static const struct processors *arm_selected_arch; |
| static const struct processors *arm_selected_cpu; |
| static const struct processors *arm_selected_tune; |
| |
| /* The name of the preprocessor macro to define for this architecture. */ |
| |
| char arm_arch_name[] = "__ARM_ARCH_0UNK__"; |
| |
| /* Available values for -mfpu=. */ |
| |
| static const struct arm_fpu_desc all_fpus[] = |
| { |
| #define ARM_FPU(NAME, MODEL, REV, VFP_REGS, NEON, FP16, CRYPTO) \ |
| { NAME, MODEL, REV, VFP_REGS, NEON, FP16, CRYPTO }, |
| #include "arm-fpus.def" |
| #undef ARM_FPU |
| }; |
| |
| |
| /* Supported TLS relocations. */ |
| |
| enum tls_reloc { |
| TLS_GD32, |
| TLS_LDM32, |
| TLS_LDO32, |
| TLS_IE32, |
| TLS_LE32, |
| TLS_DESCSEQ /* GNU scheme */ |
| }; |
| |
| /* The maximum number of insns to be used when loading a constant. */ |
| inline static int |
| arm_constant_limit (bool size_p) |
| { |
| return size_p ? 1 : current_tune->constant_limit; |
| } |
| |
| /* Emit an insn that's a simple single-set. Both the operands must be known |
| to be valid. */ |
| inline static rtx_insn * |
| emit_set_insn (rtx x, rtx y) |
| { |
| return emit_insn (gen_rtx_SET (VOIDmode, x, y)); |
| } |
| |
| /* Return the number of bits set in VALUE. */ |
| static unsigned |
| bit_count (unsigned long value) |
| { |
| unsigned long count = 0; |
| |
| while (value) |
| { |
| count++; |
| value &= value - 1; /* Clear the least-significant set bit. */ |
| } |
| |
| return count; |
| } |
| |
| typedef struct |
| { |
| machine_mode mode; |
| const char *name; |
| } arm_fixed_mode_set; |
| |
| /* A small helper for setting fixed-point library libfuncs. */ |
| |
| static void |
| arm_set_fixed_optab_libfunc (optab optable, machine_mode mode, |
| const char *funcname, const char *modename, |
| int num_suffix) |
| { |
| char buffer[50]; |
| |
| if (num_suffix == 0) |
| sprintf (buffer, "__gnu_%s%s", funcname, modename); |
| else |
| sprintf (buffer, "__gnu_%s%s%d", funcname, modename, num_suffix); |
| |
| set_optab_libfunc (optable, mode, buffer); |
| } |
| |
| static void |
| arm_set_fixed_conv_libfunc (convert_optab optable, machine_mode to, |
| machine_mode from, const char *funcname, |
| const char *toname, const char *fromname) |
| { |
| char buffer[50]; |
| const char *maybe_suffix_2 = ""; |
| |
| /* Follow the logic for selecting a "2" suffix in fixed-bit.h. */ |
| if (ALL_FIXED_POINT_MODE_P (from) && ALL_FIXED_POINT_MODE_P (to) |
| && UNSIGNED_FIXED_POINT_MODE_P (from) == UNSIGNED_FIXED_POINT_MODE_P (to) |
| && ALL_FRACT_MODE_P (from) == ALL_FRACT_MODE_P (to)) |
| maybe_suffix_2 = "2"; |
| |
| sprintf (buffer, "__gnu_%s%s%s%s", funcname, fromname, toname, |
| maybe_suffix_2); |
| |
| set_conv_libfunc (optable, to, from, buffer); |
| } |
| |
| /* Set up library functions unique to ARM. */ |
| |
| static void |
| arm_init_libfuncs (void) |
| { |
| /* For Linux, we have access to kernel support for atomic operations. */ |
| if (arm_abi == ARM_ABI_AAPCS_LINUX) |
| init_sync_libfuncs (MAX_SYNC_LIBFUNC_SIZE); |
| |
| /* There are no special library functions unless we are using the |
| ARM BPABI. */ |
| if (!TARGET_BPABI) |
| return; |
| |
| /* The functions below are described in Section 4 of the "Run-Time |
| ABI for the ARM architecture", Version 1.0. */ |
| |
| /* Double-precision floating-point arithmetic. Table 2. */ |
| set_optab_libfunc (add_optab, DFmode, "__aeabi_dadd"); |
| set_optab_libfunc (sdiv_optab, DFmode, "__aeabi_ddiv"); |
| set_optab_libfunc (smul_optab, DFmode, "__aeabi_dmul"); |
| set_optab_libfunc (neg_optab, DFmode, "__aeabi_dneg"); |
| set_optab_libfunc (sub_optab, DFmode, "__aeabi_dsub"); |
| |
| /* Double-precision comparisons. Table 3. */ |
| set_optab_libfunc (eq_optab, DFmode, "__aeabi_dcmpeq"); |
| set_optab_libfunc (ne_optab, DFmode, NULL); |
| set_optab_libfunc (lt_optab, DFmode, "__aeabi_dcmplt"); |
| set_optab_libfunc (le_optab, DFmode, "__aeabi_dcmple"); |
| set_optab_libfunc (ge_optab, DFmode, "__aeabi_dcmpge"); |
| set_optab_libfunc (gt_optab, DFmode, "__aeabi_dcmpgt"); |
| set_optab_libfunc (unord_optab, DFmode, "__aeabi_dcmpun"); |
| |
| /* Single-precision floating-point arithmetic. Table 4. */ |
| set_optab_libfunc (add_optab, SFmode, "__aeabi_fadd"); |
| set_optab_libfunc (sdiv_optab, SFmode, "__aeabi_fdiv"); |
| set_optab_libfunc (smul_optab, SFmode, "__aeabi_fmul"); |
| set_optab_libfunc (neg_optab, SFmode, "__aeabi_fneg"); |
| set_optab_libfunc (sub_optab, SFmode, "__aeabi_fsub"); |
| |
| /* Single-precision comparisons. Table 5. */ |
| set_optab_libfunc (eq_optab, SFmode, "__aeabi_fcmpeq"); |
| set_optab_libfunc (ne_optab, SFmode, NULL); |
| set_optab_libfunc (lt_optab, SFmode, "__aeabi_fcmplt"); |
| set_optab_libfunc (le_optab, SFmode, "__aeabi_fcmple"); |
| set_optab_libfunc (ge_optab, SFmode, "__aeabi_fcmpge"); |
| set_optab_libfunc (gt_optab, SFmode, "__aeabi_fcmpgt"); |
| set_optab_libfunc (unord_optab, SFmode, "__aeabi_fcmpun"); |
| |
| /* Floating-point to integer conversions. Table 6. */ |
| set_conv_libfunc (sfix_optab, SImode, DFmode, "__aeabi_d2iz"); |
| set_conv_libfunc (ufix_optab, SImode, DFmode, "__aeabi_d2uiz"); |
| set_conv_libfunc (sfix_optab, DImode, DFmode, "__aeabi_d2lz"); |
| set_conv_libfunc (ufix_optab, DImode, DFmode, "__aeabi_d2ulz"); |
| set_conv_libfunc (sfix_optab, SImode, SFmode, "__aeabi_f2iz"); |
| set_conv_libfunc (ufix_optab, SImode, SFmode, "__aeabi_f2uiz"); |
| set_conv_libfunc (sfix_optab, DImode, SFmode, "__aeabi_f2lz"); |
| set_conv_libfunc (ufix_optab, DImode, SFmode, "__aeabi_f2ulz"); |
| |
| /* Conversions between floating types. Table 7. */ |
| set_conv_libfunc (trunc_optab, SFmode, DFmode, "__aeabi_d2f"); |
| set_conv_libfunc (sext_optab, DFmode, SFmode, "__aeabi_f2d"); |
| |
| /* Integer to floating-point conversions. Table 8. */ |
| set_conv_libfunc (sfloat_optab, DFmode, SImode, "__aeabi_i2d"); |
| set_conv_libfunc (ufloat_optab, DFmode, SImode, "__aeabi_ui2d"); |
| set_conv_libfunc (sfloat_optab, DFmode, DImode, "__aeabi_l2d"); |
| set_conv_libfunc (ufloat_optab, DFmode, DImode, "__aeabi_ul2d"); |
| set_conv_libfunc (sfloat_optab, SFmode, SImode, "__aeabi_i2f"); |
| set_conv_libfunc (ufloat_optab, SFmode, SImode, "__aeabi_ui2f"); |
| set_conv_libfunc (sfloat_optab, SFmode, DImode, "__aeabi_l2f"); |
| set_conv_libfunc (ufloat_optab, SFmode, DImode, "__aeabi_ul2f"); |
| |
| /* Long long. Table 9. */ |
| set_optab_libfunc (smul_optab, DImode, "__aeabi_lmul"); |
| set_optab_libfunc (sdivmod_optab, DImode, "__aeabi_ldivmod"); |
| set_optab_libfunc (udivmod_optab, DImode, "__aeabi_uldivmod"); |
| set_optab_libfunc (ashl_optab, DImode, "__aeabi_llsl"); |
| set_optab_libfunc (lshr_optab, DImode, "__aeabi_llsr"); |
| set_optab_libfunc (ashr_optab, DImode, "__aeabi_lasr"); |
| set_optab_libfunc (cmp_optab, DImode, "__aeabi_lcmp"); |
| set_optab_libfunc (ucmp_optab, DImode, "__aeabi_ulcmp"); |
| |
| /* Integer (32/32->32) division. \S 4.3.1. */ |
| set_optab_libfunc (sdivmod_optab, SImode, "__aeabi_idivmod"); |
| set_optab_libfunc (udivmod_optab, SImode, "__aeabi_uidivmod"); |
| |
| /* The divmod functions are designed so that they can be used for |
| plain division, even though they return both the quotient and the |
| remainder. The quotient is returned in the usual location (i.e., |
| r0 for SImode, {r0, r1} for DImode), just as would be expected |
| for an ordinary division routine. Because the AAPCS calling |
| conventions specify that all of { r0, r1, r2, r3 } are |
| callee-saved registers, there is no need to tell the compiler |
| explicitly that those registers are clobbered by these |
| routines. */ |
| set_optab_libfunc (sdiv_optab, DImode, "__aeabi_ldivmod"); |
| set_optab_libfunc (udiv_optab, DImode, "__aeabi_uldivmod"); |
| |
| /* For SImode division the ABI provides div-without-mod routines, |
| which are faster. */ |
| set_optab_libfunc (sdiv_optab, SImode, "__aeabi_idiv"); |
| set_optab_libfunc (udiv_optab, SImode, "__aeabi_uidiv"); |
| |
| /* We don't have mod libcalls. Fortunately gcc knows how to use the |
| divmod libcalls instead. */ |
| set_optab_libfunc (smod_optab, DImode, NULL); |
| set_optab_libfunc (umod_optab, DImode, NULL); |
| set_optab_libfunc (smod_optab, SImode, NULL); |
| set_optab_libfunc (umod_optab, SImode, NULL); |
| |
| /* Half-precision float operations. The compiler handles all operations |
| with NULL libfuncs by converting the SFmode. */ |
| switch (arm_fp16_format) |
| { |
| case ARM_FP16_FORMAT_IEEE: |
| case ARM_FP16_FORMAT_ALTERNATIVE: |
| |
| /* Conversions. */ |
| set_conv_libfunc (trunc_optab, HFmode, SFmode, |
| (arm_fp16_format == ARM_FP16_FORMAT_IEEE |
| ? "__gnu_f2h_ieee" |
| : "__gnu_f2h_alternative")); |
| set_conv_libfunc (sext_optab, SFmode, HFmode, |
| (arm_fp16_format == ARM_FP16_FORMAT_IEEE |
| ? "__gnu_h2f_ieee" |
| : "__gnu_h2f_alternative")); |
| |
| /* Arithmetic. */ |
| set_optab_libfunc (add_optab, HFmode, NULL); |
| set_optab_libfunc (sdiv_optab, HFmode, NULL); |
| set_optab_libfunc (smul_optab, HFmode, NULL); |
| set_optab_libfunc (neg_optab, HFmode, NULL); |
| set_optab_libfunc (sub_optab, HFmode, NULL); |
| |
| /* Comparisons. */ |
| set_optab_libfunc (eq_optab, HFmode, NULL); |
| set_optab_libfunc (ne_optab, HFmode, NULL); |
| set_optab_libfunc (lt_optab, HFmode, NULL); |
| set_optab_libfunc (le_optab, HFmode, NULL); |
| set_optab_libfunc (ge_optab, HFmode, NULL); |
| set_optab_libfunc (gt_optab, HFmode, NULL); |
| set_optab_libfunc (unord_optab, HFmode, NULL); |
| break; |
| |
| default: |
| break; |
| } |
| |
| /* Use names prefixed with __gnu_ for fixed-point helper functions. */ |
| { |
| const arm_fixed_mode_set fixed_arith_modes[] = |
| { |
| { QQmode, "qq" }, |
| { UQQmode, "uqq" }, |
| { HQmode, "hq" }, |
| { UHQmode, "uhq" }, |
| { SQmode, "sq" }, |
| { USQmode, "usq" }, |
| { DQmode, "dq" }, |
| { UDQmode, "udq" }, |
| { TQmode, "tq" }, |
| { UTQmode, "utq" }, |
| { HAmode, "ha" }, |
| { UHAmode, "uha" }, |
| { SAmode, "sa" }, |
| { USAmode, "usa" }, |
| { DAmode, "da" }, |
| { UDAmode, "uda" }, |
| { TAmode, "ta" }, |
| { UTAmode, "uta" } |
| }; |
| const arm_fixed_mode_set fixed_conv_modes[] = |
| { |
| { QQmode, "qq" }, |
| { UQQmode, "uqq" }, |
| { HQmode, "hq" }, |
| { UHQmode, "uhq" }, |
| { SQmode, "sq" }, |
| { USQmode, "usq" }, |
| { DQmode, "dq" }, |
| { UDQmode, "udq" }, |
| { TQmode, "tq" }, |
| { UTQmode, "utq" }, |
| { HAmode, "ha" }, |
| { UHAmode, "uha" }, |
| { SAmode, "sa" }, |
| { USAmode, "usa" }, |
| { DAmode, "da" }, |
| { UDAmode, "uda" }, |
| { TAmode, "ta" }, |
| { UTAmode, "uta" }, |
| { QImode, "qi" }, |
| { HImode, "hi" }, |
| { SImode, "si" }, |
| { DImode, "di" }, |
| { TImode, "ti" }, |
| { SFmode, "sf" }, |
| { DFmode, "df" } |
| }; |
| unsigned int i, j; |
| |
| for (i = 0; i < ARRAY_SIZE (fixed_arith_modes); i++) |
| { |
| arm_set_fixed_optab_libfunc (add_optab, fixed_arith_modes[i].mode, |
| "add", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (ssadd_optab, fixed_arith_modes[i].mode, |
| "ssadd", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (usadd_optab, fixed_arith_modes[i].mode, |
| "usadd", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (sub_optab, fixed_arith_modes[i].mode, |
| "sub", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (sssub_optab, fixed_arith_modes[i].mode, |
| "sssub", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (ussub_optab, fixed_arith_modes[i].mode, |
| "ussub", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (smul_optab, fixed_arith_modes[i].mode, |
| "mul", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (ssmul_optab, fixed_arith_modes[i].mode, |
| "ssmul", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (usmul_optab, fixed_arith_modes[i].mode, |
| "usmul", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (sdiv_optab, fixed_arith_modes[i].mode, |
| "div", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (udiv_optab, fixed_arith_modes[i].mode, |
| "udiv", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (ssdiv_optab, fixed_arith_modes[i].mode, |
| "ssdiv", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (usdiv_optab, fixed_arith_modes[i].mode, |
| "usdiv", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (neg_optab, fixed_arith_modes[i].mode, |
| "neg", fixed_arith_modes[i].name, 2); |
| arm_set_fixed_optab_libfunc (ssneg_optab, fixed_arith_modes[i].mode, |
| "ssneg", fixed_arith_modes[i].name, 2); |
| arm_set_fixed_optab_libfunc (usneg_optab, fixed_arith_modes[i].mode, |
| "usneg", fixed_arith_modes[i].name, 2); |
| arm_set_fixed_optab_libfunc (ashl_optab, fixed_arith_modes[i].mode, |
| "ashl", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (ashr_optab, fixed_arith_modes[i].mode, |
| "ashr", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (lshr_optab, fixed_arith_modes[i].mode, |
| "lshr", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (ssashl_optab, fixed_arith_modes[i].mode, |
| "ssashl", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (usashl_optab, fixed_arith_modes[i].mode, |
| "usashl", fixed_arith_modes[i].name, 3); |
| arm_set_fixed_optab_libfunc (cmp_optab, fixed_arith_modes[i].mode, |
| "cmp", fixed_arith_modes[i].name, 2); |
| } |
| |
| for (i = 0; i < ARRAY_SIZE (fixed_conv_modes); i++) |
| for (j = 0; j < ARRAY_SIZE (fixed_conv_modes); j++) |
| { |
| if (i == j |
| || (!ALL_FIXED_POINT_MODE_P (fixed_conv_modes[i].mode) |
| && !ALL_FIXED_POINT_MODE_P (fixed_conv_modes[j].mode))) |
| continue; |
| |
| arm_set_fixed_conv_libfunc (fract_optab, fixed_conv_modes[i].mode, |
| fixed_conv_modes[j].mode, "fract", |
| fixed_conv_modes[i].name, |
| fixed_conv_modes[j].name); |
| arm_set_fixed_conv_libfunc (satfract_optab, |
| fixed_conv_modes[i].mode, |
| fixed_conv_modes[j].mode, "satfract", |
| fixed_conv_modes[i].name, |
| fixed_conv_modes[j].name); |
| arm_set_fixed_conv_libfunc (fractuns_optab, |
| fixed_conv_modes[i].mode, |
| fixed_conv_modes[j].mode, "fractuns", |
| fixed_conv_modes[i].name, |
| fixed_conv_modes[j].name); |
| arm_set_fixed_conv_libfunc (satfractuns_optab, |
| fixed_conv_modes[i].mode, |
| fixed_conv_modes[j].mode, "satfractuns", |
| fixed_conv_modes[i].name, |
| fixed_conv_modes[j].name); |
| } |
| } |
| |
| if (TARGET_AAPCS_BASED) |
| synchronize_libfunc = init_one_libfunc ("__sync_synchronize"); |
| } |
| |
| /* On AAPCS systems, this is the "struct __va_list". */ |
| static GTY(()) tree va_list_type; |
| |
| /* Return the type to use as __builtin_va_list. */ |
| static tree |
| arm_build_builtin_va_list (void) |
| { |
| tree va_list_name; |
| tree ap_field; |
| |
| if (!TARGET_AAPCS_BASED) |
| return std_build_builtin_va_list (); |
| |
| /* AAPCS \S 7.1.4 requires that va_list be a typedef for a type |
| defined as: |
| |
| struct __va_list |
| { |
| void *__ap; |
| }; |
| |
| The C Library ABI further reinforces this definition in \S |
| 4.1. |
| |
| We must follow this definition exactly. The structure tag |
| name is visible in C++ mangled names, and thus forms a part |
| of the ABI. The field name may be used by people who |
| #include <stdarg.h>. */ |
| /* Create the type. */ |
| va_list_type = lang_hooks.types.make_type (RECORD_TYPE); |
| /* Give it the required name. */ |
| va_list_name = build_decl (BUILTINS_LOCATION, |
| TYPE_DECL, |
| get_identifier ("__va_list"), |
| va_list_type); |
| DECL_ARTIFICIAL (va_list_name) = 1; |
| TYPE_NAME (va_list_type) = va_list_name; |
| TYPE_STUB_DECL (va_list_type) = va_list_name; |
| /* Create the __ap field. */ |
| ap_field = build_decl (BUILTINS_LOCATION, |
| FIELD_DECL, |
| get_identifier ("__ap"), |
| ptr_type_node); |
| DECL_ARTIFICIAL (ap_field) = 1; |
| DECL_FIELD_CONTEXT (ap_field) = va_list_type; |
| TYPE_FIELDS (va_list_type) = ap_field; |
| /* Compute its layout. */ |
| layout_type (va_list_type); |
| |
| return va_list_type; |
| } |
| |
| /* Return an expression of type "void *" pointing to the next |
| available argument in a variable-argument list. VALIST is the |
| user-level va_list object, of type __builtin_va_list. */ |
| static tree |
| arm_extract_valist_ptr (tree valist) |
| { |
| if (TREE_TYPE (valist) == error_mark_node) |
| return error_mark_node; |
| |
| /* On an AAPCS target, the pointer is stored within "struct |
| va_list". */ |
| if (TARGET_AAPCS_BASED) |
| { |
| tree ap_field = TYPE_FIELDS (TREE_TYPE (valist)); |
| valist = build3 (COMPONENT_REF, TREE_TYPE (ap_field), |
| valist, ap_field, NULL_TREE); |
| } |
| |
| return valist; |
| } |
| |
| /* Implement TARGET_EXPAND_BUILTIN_VA_START. */ |
| static void |
| arm_expand_builtin_va_start (tree valist, rtx nextarg) |
| { |
| valist = arm_extract_valist_ptr (valist); |
| std_expand_builtin_va_start (valist, nextarg); |
| } |
| |
| /* Implement TARGET_GIMPLIFY_VA_ARG_EXPR. */ |
| static tree |
| arm_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, |
| gimple_seq *post_p) |
| { |
| valist = arm_extract_valist_ptr (valist); |
| return std_gimplify_va_arg_expr (valist, type, pre_p, post_p); |
| } |
| |
| /* Fix up any incompatible options that the user has specified. */ |
| static void |
| arm_option_override (void) |
| { |
| arm_selected_arch = NULL; |
| arm_selected_cpu = NULL; |
| arm_selected_tune = NULL; |
| |
| if (global_options_set.x_arm_arch_option) |
| arm_selected_arch = &all_architectures[arm_arch_option]; |
| |
| if (global_options_set.x_arm_cpu_option) |
| { |
| arm_selected_cpu = &all_cores[(int) arm_cpu_option]; |
| arm_selected_tune = &all_cores[(int) arm_cpu_option]; |
| } |
| |
| if (global_options_set.x_arm_tune_option) |
| arm_selected_tune = &all_cores[(int) arm_tune_option]; |
| |
| #ifdef SUBTARGET_OVERRIDE_OPTIONS |
| SUBTARGET_OVERRIDE_OPTIONS; |
| #endif |
| |
| if (arm_selected_arch) |
| { |
| if (arm_selected_cpu) |
| { |
| /* Check for conflict between mcpu and march. */ |
| if ((arm_selected_cpu->flags ^ arm_selected_arch->flags) & ~FL_TUNE) |
| { |
| warning (0, "switch -mcpu=%s conflicts with -march=%s switch", |
| arm_selected_cpu->name, arm_selected_arch->name); |
| /* -march wins for code generation. |
| -mcpu wins for default tuning. */ |
| if (!arm_selected_tune) |
| arm_selected_tune = arm_selected_cpu; |
| |
| arm_selected_cpu = arm_selected_arch; |
| } |
| else |
| /* -mcpu wins. */ |
| arm_selected_arch = NULL; |
| } |
| else |
| /* Pick a CPU based on the architecture. */ |
| arm_selected_cpu = arm_selected_arch; |
| } |
| |
| /* If the user did not specify a processor, choose one for them. */ |
| if (!arm_selected_cpu) |
| { |
| const struct processors * sel; |
| unsigned int sought; |
| |
| arm_selected_cpu = &all_cores[TARGET_CPU_DEFAULT]; |
| if (!arm_selected_cpu->name) |
| { |
| #ifdef SUBTARGET_CPU_DEFAULT |
| /* Use the subtarget default CPU if none was specified by |
| configure. */ |
| arm_selected_cpu = &all_cores[SUBTARGET_CPU_DEFAULT]; |
| #endif |
| /* Default to ARM6. */ |
| if (!arm_selected_cpu->name) |
| arm_selected_cpu = &all_cores[arm6]; |
| } |
| |
| sel = arm_selected_cpu; |
| insn_flags = sel->flags; |
| |
| /* Now check to see if the user has specified some command line |
| switch that require certain abilities from the cpu. */ |
| sought = 0; |
| |
| if (TARGET_INTERWORK || TARGET_THUMB) |
| { |
| sought |= (FL_THUMB | FL_MODE32); |
| |
| /* There are no ARM processors that support both APCS-26 and |
| interworking. Therefore we force FL_MODE26 to be removed |
| from insn_flags here (if it was set), so that the search |
| below will always be able to find a compatible processor. */ |
| insn_flags &= ~FL_MODE26; |
| } |
| |
| if (sought != 0 && ((sought & insn_flags) != sought)) |
| { |
| /* Try to locate a CPU type that supports all of the abilities |
| of the default CPU, plus the extra abilities requested by |
| the user. */ |
| for (sel = all_cores; sel->name != NULL; sel++) |
| if ((sel->flags & sought) == (sought | insn_flags)) |
| break; |
| |
| if (sel->name == NULL) |
| { |
| unsigned current_bit_count = 0; |
| const struct processors * best_fit = NULL; |
| |
| /* Ideally we would like to issue an error message here |
| saying that it was not possible to find a CPU compatible |
| with the default CPU, but which also supports the command |
| line options specified by the programmer, and so they |
| ought to use the -mcpu=<name> command line option to |
| override the default CPU type. |
| |
| If we cannot find a cpu that has both the |
| characteristics of the default cpu and the given |
| command line options we scan the array again looking |
| for a best match. */ |
| for (sel = all_cores; sel->name != NULL; sel++) |
| if ((sel->flags & sought) == sought) |
| { |
| unsigned count; |
| |
| count = bit_count (sel->flags & insn_flags); |
| |
| if (count >= current_bit_count) |
| { |
| best_fit = sel; |
| current_bit_count = count; |
| } |
| } |
| |
| gcc_assert (best_fit); |
| sel = best_fit; |
| } |
| |
| arm_selected_cpu = sel; |
| } |
| } |
| |
| gcc_assert (arm_selected_cpu); |
| /* The selected cpu may be an architecture, so lookup tuning by core ID. */ |
| if (!arm_selected_tune) |
| arm_selected_tune = &all_cores[arm_selected_cpu->core]; |
| |
| sprintf (arm_arch_name, "__ARM_ARCH_%s__", arm_selected_cpu->arch); |
| insn_flags = arm_selected_cpu->flags; |
| arm_base_arch = arm_selected_cpu->base_arch; |
| |
| arm_tune = arm_selected_tune->core; |
| tune_flags = arm_selected_tune->flags; |
| current_tune = arm_selected_tune->tune; |
| |
| /* Make sure that the processor choice does not conflict with any of the |
| other command line choices. */ |
| if (TARGET_ARM && !(insn_flags & FL_NOTM)) |
| error ("target CPU does not support ARM mode"); |
| |
| /* BPABI targets use linker tricks to allow interworking on cores |
| without thumb support. */ |
| if (TARGET_INTERWORK && !((insn_flags & FL_THUMB) || TARGET_BPABI)) |
| { |
| warning (0, "target CPU does not support interworking" ); |
| target_flags &= ~MASK_INTERWORK; |
| } |
| |
| if (TARGET_THUMB && !(insn_flags & FL_THUMB)) |
| { |
| warning (0, "target CPU does not support THUMB instructions"); |
| target_flags &= ~MASK_THUMB; |
| } |
| |
| if (TARGET_APCS_FRAME && TARGET_THUMB) |
| { |
| /* warning (0, "ignoring -mapcs-frame because -mthumb was used"); */ |
| target_flags &= ~MASK_APCS_FRAME; |
| } |
| |
| /* Callee super interworking implies thumb interworking. Adding |
| this to the flags here simplifies the logic elsewhere. */ |
| if (TARGET_THUMB && TARGET_CALLEE_INTERWORKING) |
| target_flags |= MASK_INTERWORK; |
| |
| /* TARGET_BACKTRACE calls leaf_function_p, which causes a crash if done |
| from here where no function is being compiled currently. */ |
| if ((TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) && TARGET_ARM) |
| warning (0, "enabling backtrace support is only meaningful when compiling for the Thumb"); |
| |
| if (TARGET_ARM && TARGET_CALLEE_INTERWORKING) |
| warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb"); |
| |
| if (TARGET_APCS_STACK && !TARGET_APCS_FRAME) |
| { |
| warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame"); |
| target_flags |= MASK_APCS_FRAME; |
| } |
| |
| if (TARGET_POKE_FUNCTION_NAME) |
| target_flags |= MASK_APCS_FRAME; |
| |
| if (TARGET_APCS_REENT && flag_pic) |
| error ("-fpic and -mapcs-reent are incompatible"); |
| |
| if (TARGET_APCS_REENT) |
| warning (0, "APCS reentrant code not supported. Ignored"); |
| |
| /* If this target is normally configured to use APCS frames, warn if they |
| are turned off and debugging is turned on. */ |
| if (TARGET_ARM |
| && write_symbols != NO_DEBUG |
| && !TARGET_APCS_FRAME |
| && (TARGET_DEFAULT & MASK_APCS_FRAME)) |
| warning (0, "-g with -mno-apcs-frame may not give sensible debugging"); |
| |
| if (TARGET_APCS_FLOAT) |
| warning (0, "passing floating point arguments in fp regs not yet supported"); |
| |
| /* Initialize boolean versions of the flags, for use in the arm.md file. */ |
| arm_arch3m = (insn_flags & FL_ARCH3M) != 0; |
| arm_arch4 = (insn_flags & FL_ARCH4) != 0; |
| arm_arch4t = arm_arch4 & ((insn_flags & FL_THUMB) != 0); |
| arm_arch5 = (insn_flags & FL_ARCH5) != 0; |
| arm_arch5e = (insn_flags & FL_ARCH5E) != 0; |
| arm_arch6 = (insn_flags & FL_ARCH6) != 0; |
| arm_arch6k = (insn_flags & FL_ARCH6K) != 0; |
| arm_arch_notm = (insn_flags & FL_NOTM) != 0; |
| arm_arch6m = arm_arch6 && !arm_arch_notm; |
| arm_arch7 = (insn_flags & FL_ARCH7) != 0; |
| arm_arch7em = (insn_flags & FL_ARCH7EM) != 0; |
| arm_arch8 = (insn_flags & FL_ARCH8) != 0; |
| arm_arch_thumb2 = (insn_flags & FL_THUMB2) != 0; |
| arm_arch_xscale = (insn_flags & FL_XSCALE) != 0; |
| |
| arm_ld_sched = (tune_flags & FL_LDSCHED) != 0; |
| arm_tune_strongarm = (tune_flags & FL_STRONG) != 0; |
| thumb_code = TARGET_ARM == 0; |
| thumb1_code = TARGET_THUMB1 != 0; |
| arm_tune_wbuf = (tune_flags & FL_WBUF) != 0; |
| arm_tune_xscale = (tune_flags & FL_XSCALE) != 0; |
| arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0; |
| arm_arch_iwmmxt2 = (insn_flags & FL_IWMMXT2) != 0; |
| arm_arch_thumb_hwdiv = (insn_flags & FL_THUMB_DIV) != 0; |
| arm_arch_arm_hwdiv = (insn_flags & FL_ARM_DIV) != 0; |
| arm_arch_lpae = (insn_flags & FL_LPAE) != 0; |
| arm_arch_no_volatile_ce = (insn_flags & FL_NO_VOLATILE_CE) != 0; |
| arm_tune_cortex_a9 = (arm_tune == cortexa9) != 0; |
| arm_arch_crc = (insn_flags & FL_CRC32) != 0; |
| arm_m_profile_small_mul = (insn_flags & FL_SMALLMUL) != 0; |
| if (arm_restrict_it == 2) |
| arm_restrict_it = arm_arch8 && TARGET_THUMB2; |
| |
| if (!TARGET_THUMB2) |
| arm_restrict_it = 0; |
| |
| /* If we are not using the default (ARM mode) section anchor offset |
| ranges, then set the correct ranges now. */ |
| if (TARGET_THUMB1) |
| { |
| /* Thumb-1 LDR instructions cannot have negative offsets. |
| Permissible positive offset ranges are 5-bit (for byte loads), |
| 6-bit (for halfword loads), or 7-bit (for word loads). |
| Empirical results suggest a 7-bit anchor range gives the best |
| overall code size. */ |
| targetm.min_anchor_offset = 0; |
| targetm.max_anchor_offset = 127; |
| } |
| else if (TARGET_THUMB2) |
| { |
| /* The minimum is set such that the total size of the block |
| for a particular anchor is 248 + 1 + 4095 bytes, which is |
| divisible by eight, ensuring natural spacing of anchors. */ |
| targetm.min_anchor_offset = -248; |
| targetm.max_anchor_offset = 4095; |
| } |
| |
| /* V5 code we generate is completely interworking capable, so we turn off |
| TARGET_INTERWORK here to avoid many tests later on. */ |
| |
| /* XXX However, we must pass the right pre-processor defines to CPP |
| or GLD can get confused. This is a hack. */ |
| if (TARGET_INTERWORK) |
| arm_cpp_interwork = 1; |
| |
| if (arm_arch5) |
| target_flags &= ~MASK_INTERWORK; |
| |
| if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN) |
| error ("iwmmxt requires an AAPCS compatible ABI for proper operation"); |
| |
| if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT) |
| error ("iwmmxt abi requires an iwmmxt capable cpu"); |
| |
| if (!global_options_set.x_arm_fpu_index) |
| { |
| const char *target_fpu_name; |
| bool ok; |
| |
| #ifdef FPUTYPE_DEFAULT |
| target_fpu_name = FPUTYPE_DEFAULT; |
| #else |
| target_fpu_name = "vfp"; |
| #endif |
| |
| ok = opt_enum_arg_to_value (OPT_mfpu_, target_fpu_name, &arm_fpu_index, |
| CL_TARGET); |
| gcc_assert (ok); |
| } |
| |
| arm_fpu_desc = &all_fpus[arm_fpu_index]; |
| |
| switch (arm_fpu_desc->model) |
| { |
| case ARM_FP_MODEL_VFP: |
| arm_fpu_attr = FPU_VFP; |
| break; |
| |
| default: |
| gcc_unreachable(); |
| } |
| |
| if (TARGET_AAPCS_BASED) |
| { |
| if (TARGET_CALLER_INTERWORKING) |
| error ("AAPCS does not support -mcaller-super-interworking"); |
| else |
| if (TARGET_CALLEE_INTERWORKING) |
| error ("AAPCS does not support -mcallee-super-interworking"); |
| } |
| |
| /* iWMMXt and NEON are incompatible. */ |
| if (TARGET_IWMMXT && TARGET_NEON) |
| error ("iWMMXt and NEON are incompatible"); |
| |
| /* iWMMXt unsupported under Thumb mode. */ |
| if (TARGET_THUMB && TARGET_IWMMXT) |
| error ("iWMMXt unsupported under Thumb mode"); |
| |
| /* __fp16 support currently assumes the core has ldrh. */ |
| if (!arm_arch4 && arm_fp16_format != ARM_FP16_FORMAT_NONE) |
| sorry ("__fp16 and no ldrh"); |
| |
| /* If soft-float is specified then don't use FPU. */ |
| if (TARGET_SOFT_FLOAT) |
| arm_fpu_attr = FPU_NONE; |
| |
| if (TARGET_AAPCS_BASED) |
| { |
| if (arm_abi == ARM_ABI_IWMMXT) |
| arm_pcs_default = ARM_PCS_AAPCS_IWMMXT; |
| else if (arm_float_abi == ARM_FLOAT_ABI_HARD |
| && TARGET_HARD_FLOAT |
| && TARGET_VFP) |
| arm_pcs_default = ARM_PCS_AAPCS_VFP; |
| else |
| arm_pcs_default = ARM_PCS_AAPCS; |
| } |
| else |
| { |
| if (arm_float_abi == ARM_FLOAT_ABI_HARD && TARGET_VFP) |
| sorry ("-mfloat-abi=hard and VFP"); |
| |
| if (arm_abi == ARM_ABI_APCS) |
| arm_pcs_default = ARM_PCS_APCS; |
| else |
| arm_pcs_default = ARM_PCS_ATPCS; |
| } |
| |
| /* For arm2/3 there is no need to do any scheduling if we are doing |
| software floating-point. */ |
| if (TARGET_SOFT_FLOAT && (tune_flags & FL_MODE32) == 0) |
| flag_schedule_insns = flag_schedule_insns_after_reload = 0; |
| |
| /* Use the cp15 method if it is available. */ |
| if (target_thread_pointer == TP_AUTO) |
| { |
| if (arm_arch6k && !TARGET_THUMB1) |
| target_thread_pointer = TP_CP15; |
| else |
| target_thread_pointer = TP_SOFT; |
| } |
| |
| if (TARGET_HARD_TP && TARGET_THUMB1) |
| error ("can not use -mtp=cp15 with 16-bit Thumb"); |
| |
| /* Override the default structure alignment for AAPCS ABI. */ |
| if (!global_options_set.x_arm_structure_size_boundary) |
| { |
| if (TARGET_AAPCS_BASED) |
| arm_structure_size_boundary = 8; |
| } |
| else |
| { |
| if (arm_structure_size_boundary != 8 |
| && arm_structure_size_boundary != 32 |
| && !(ARM_DOUBLEWORD_ALIGN && arm_structure_size_boundary == 64)) |
| { |
| if (ARM_DOUBLEWORD_ALIGN) |
| warning (0, |
| "structure size boundary can only be set to 8, 32 or 64"); |
| else |
| warning (0, "structure size boundary can only be set to 8 or 32"); |
| arm_structure_size_boundary |
| = (TARGET_AAPCS_BASED ? 8 : DEFAULT_STRUCTURE_SIZE_BOUNDARY); |
| } |
| } |
| |
| if (!TARGET_ARM && TARGET_VXWORKS_RTP && flag_pic) |
| { |
| error ("RTP PIC is incompatible with Thumb"); |
| flag_pic = 0; |
| } |
| |
| /* If stack checking is disabled, we can use r10 as the PIC register, |
| which keeps r9 available. The EABI specifies r9 as the PIC register. */ |
| if (flag_pic && TARGET_SINGLE_PIC_BASE) |
| { |
| if (TARGET_VXWORKS_RTP) |
| warning (0, "RTP PIC is incompatible with -msingle-pic-base"); |
| arm_pic_register = (TARGET_APCS_STACK || TARGET_AAPCS_BASED) ? 9 : 10; |
| } |
| |
| if (flag_pic && TARGET_VXWORKS_RTP) |
| arm_pic_register = 9; |
| |
| if (arm_pic_register_string != NULL) |
| { |
| int pic_register = decode_reg_name (arm_pic_register_string); |
| |
| if (!flag_pic) |
| warning (0, "-mpic-register= is useless without -fpic"); |
| |
| /* Prevent the user from choosing an obviously stupid PIC register. */ |
| else if (pic_register < 0 || call_used_regs[pic_register] |
| || pic_register == HARD_FRAME_POINTER_REGNUM |
| || pic_register == STACK_POINTER_REGNUM |
| || pic_register >= PC_REGNUM |
| || (TARGET_VXWORKS_RTP |
| && (unsigned int) pic_register != arm_pic_register)) |
| error ("unable to use '%s' for PIC register", arm_pic_register_string); |
| else |
| arm_pic_register = pic_register; |
| } |
| |
| if (TARGET_VXWORKS_RTP |
| && !global_options_set.x_arm_pic_data_is_text_relative) |
| arm_pic_data_is_text_relative = 0; |
| |
| /* Enable -mfix-cortex-m3-ldrd by default for Cortex-M3 cores. */ |
| if (fix_cm3_ldrd == 2) |
| { |
| if (arm_selected_cpu->core == cortexm3) |
| fix_cm3_ldrd = 1; |
| else |
| fix_cm3_ldrd = 0; |
| } |
| |
| /* Enable -munaligned-access by default for |
| - all ARMv6 architecture-based processors |
| - ARMv7-A, ARMv7-R, and ARMv7-M architecture-based processors. |
| - ARMv8 architecture-base processors. |
| |
| Disable -munaligned-access by default for |
| - all pre-ARMv6 architecture-based processors |
| - ARMv6-M architecture-based processors. */ |
| |
| if (unaligned_access == 2) |
| { |
| if (arm_arch6 && (arm_arch_notm || arm_arch7)) |
| unaligned_access = 1; |
| else |
| unaligned_access = 0; |
| } |
| else if (unaligned_access == 1 |
| && !(arm_arch6 && (arm_arch_notm || arm_arch7))) |
| { |
| warning (0, "target CPU does not support unaligned accesses"); |
| unaligned_access = 0; |
| } |
| |
| if (TARGET_THUMB1 && flag_schedule_insns) |
| { |
| /* Don't warn since it's on by default in -O2. */ |
| flag_schedule_insns = 0; |
| } |
| |
| if (optimize_size) |
| { |
| /* If optimizing for size, bump the number of instructions that we |
| are prepared to conditionally execute (even on a StrongARM). */ |
| max_insns_skipped = 6; |
| |
| /* For THUMB2, we limit the conditional sequence to one IT block. */ |
| if (TARGET_THUMB2) |
| max_insns_skipped = MAX_INSN_PER_IT_BLOCK; |
| } |
| else |
| max_insns_skipped = current_tune->max_insns_skipped; |
| |
| /* Hot/Cold partitioning is not currently supported, since we can't |
| handle literal pool placement in that case. */ |
| if (flag_reorder_blocks_and_partition) |
| { |
| inform (input_location, |
| "-freorder-blocks-and-partition not supported on this architecture"); |
| flag_reorder_blocks_and_partition = 0; |
| flag_reorder_blocks = 1; |
| } |
| |
| if (flag_pic) |
| /* Hoisting PIC address calculations more aggressively provides a small, |
| but measurable, size reduction for PIC code. Therefore, we decrease |
| the bar for unrestricted expression hoisting to the cost of PIC address |
| calculation, which is 2 instructions. */ |
| maybe_set_param_value (PARAM_GCSE_UNRESTRICTED_COST, 2, |
| global_options.x_param_values, |
| global_options_set.x_param_values); |
| |
| /* ARM EABI defaults to strict volatile bitfields. */ |
| if (TARGET_AAPCS_BASED && flag_strict_volatile_bitfields < 0 |
| && abi_version_at_least(2)) |
| flag_strict_volatile_bitfields = 1; |
| |
| /* Enable sw prefetching at -O3 for CPUS that have prefetch, and we have deemed |
| it beneficial (signified by setting num_prefetch_slots to 1 or more.) */ |
| if (flag_prefetch_loop_arrays < 0 |
| && HAVE
|