00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "config.h"
00026 #include "system.h"
00027 #include "coretypes.h"
00028 #include "tm.h"
00029 #include "rtl.h"
00030 #include "tree.h"
00031 #include "obstack.h"
00032 #include "regs.h"
00033 #include "hard-reg-set.h"
00034 #include "real.h"
00035 #include "insn-config.h"
00036 #include "conditions.h"
00037 #include "output.h"
00038 #include "insn-attr.h"
00039 #include "flags.h"
00040 #include "reload.h"
00041 #include "function.h"
00042 #include "expr.h"
00043 #include "optabs.h"
00044 #include "toplev.h"
00045 #include "recog.h"
00046 #include "ggc.h"
00047 #include "except.h"
00048 #include "c-pragma.h"
00049 #include "integrate.h"
00050 #include "tm_p.h"
00051 #include "target.h"
00052 #include "target-def.h"
00053 #include "debug.h"
00054 #include "langhooks.h"
00055
00056
00057 typedef struct minipool_node Mnode;
00058 typedef struct minipool_fixup Mfix;
00059
00060 const struct attribute_spec arm_attribute_table[];
00061
00062
00063 static arm_stack_offsets *arm_get_frame_offsets (void);
00064 static void arm_add_gc_roots (void);
00065 static int arm_gen_constant (enum rtx_code, enum machine_mode, rtx,
00066 HOST_WIDE_INT, rtx, rtx, int, int);
00067 static unsigned bit_count (unsigned long);
00068 static int arm_address_register_rtx_p (rtx, int);
00069 static int arm_legitimate_index_p (enum machine_mode, rtx, RTX_CODE, int);
00070 static int thumb_base_register_rtx_p (rtx, enum machine_mode, int);
00071 inline static int thumb_index_register_rtx_p (rtx, int);
00072 static int thumb_far_jump_used_p (void);
00073 static bool thumb_force_lr_save (void);
00074 static int const_ok_for_op (HOST_WIDE_INT, enum rtx_code);
00075 static rtx emit_sfm (int, int);
00076 static int arm_size_return_regs (void);
00077 #ifndef AOF_ASSEMBLER
00078 static bool arm_assemble_integer (rtx, unsigned int, int);
00079 #endif
00080 static const char *fp_const_from_val (REAL_VALUE_TYPE *);
00081 static arm_cc get_arm_condition_code (rtx);
00082 static HOST_WIDE_INT int_log2 (HOST_WIDE_INT);
00083 static rtx is_jump_table (rtx);
00084 static const char *output_multi_immediate (rtx *, const char *, const char *,
00085 int, HOST_WIDE_INT);
00086 static const char *shift_op (rtx, HOST_WIDE_INT *);
00087 static struct machine_function *arm_init_machine_status (void);
00088 static void thumb_exit (FILE *, int);
00089 static rtx is_jump_table (rtx);
00090 static HOST_WIDE_INT get_jump_table_size (rtx);
00091 static Mnode *move_minipool_fix_forward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
00092 static Mnode *add_minipool_forward_ref (Mfix *);
00093 static Mnode *move_minipool_fix_backward_ref (Mnode *, Mnode *, HOST_WIDE_INT);
00094 static Mnode *add_minipool_backward_ref (Mfix *);
00095 static void assign_minipool_offsets (Mfix *);
00096 static void arm_print_value (FILE *, rtx);
00097 static void dump_minipool (rtx);
00098 static int arm_barrier_cost (rtx);
00099 static Mfix *create_fix_barrier (Mfix *, HOST_WIDE_INT);
00100 static void push_minipool_barrier (rtx, HOST_WIDE_INT);
00101 static void push_minipool_fix (rtx, HOST_WIDE_INT, rtx *, enum machine_mode,
00102 rtx);
00103 static void arm_reorg (void);
00104 static bool note_invalid_constants (rtx, HOST_WIDE_INT, int);
00105 static int current_file_function_operand (rtx);
00106 static unsigned long arm_compute_save_reg0_reg12_mask (void);
00107 static unsigned long arm_compute_save_reg_mask (void);
00108 static unsigned long arm_isr_value (tree);
00109 static unsigned long arm_compute_func_type (void);
00110 static tree arm_handle_fndecl_attribute (tree *, tree, tree, int, bool *);
00111 static tree arm_handle_isr_attribute (tree *, tree, tree, int, bool *);
00112 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
00113 static tree arm_handle_notshared_attribute (tree *, tree, tree, int, bool *);
00114 #endif
00115 static void arm_output_function_epilogue (FILE *, HOST_WIDE_INT);
00116 static void arm_output_function_prologue (FILE *, HOST_WIDE_INT);
00117 static void thumb_output_function_prologue (FILE *, HOST_WIDE_INT);
00118 static int arm_comp_type_attributes (tree, tree);
00119 static void arm_set_default_type_attributes (tree);
00120 static int arm_adjust_cost (rtx, rtx, rtx, int);
00121 static int count_insns_for_constant (HOST_WIDE_INT, int);
00122 static int arm_get_strip_length (int);
00123 static bool arm_function_ok_for_sibcall (tree, tree);
00124 static void arm_internal_label (FILE *, const char *, unsigned long);
00125 static void arm_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT,
00126 tree);
00127 static int arm_rtx_costs_1 (rtx, enum rtx_code, enum rtx_code);
00128 static bool arm_size_rtx_costs (rtx, int, int, int *);
00129 static bool arm_slowmul_rtx_costs (rtx, int, int, int *);
00130 static bool arm_fastmul_rtx_costs (rtx, int, int, int *);
00131 static bool arm_xscale_rtx_costs (rtx, int, int, int *);
00132 static bool arm_9e_rtx_costs (rtx, int, int, int *);
00133 static int arm_address_cost (rtx);
00134 static bool arm_memory_load_p (rtx);
00135 static bool arm_cirrus_insn_p (rtx);
00136 static void cirrus_reorg (rtx);
00137 static void arm_init_builtins (void);
00138 static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
00139 static void arm_init_iwmmxt_builtins (void);
00140 static rtx safe_vector_operand (rtx, enum machine_mode);
00141 static rtx arm_expand_binop_builtin (enum insn_code, tree, rtx);
00142 static rtx arm_expand_unop_builtin (enum insn_code, tree, rtx, int);
00143 static rtx arm_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
00144 static void emit_constant_insn (rtx cond, rtx pattern);
00145 static rtx emit_set_insn (rtx, rtx);
00146 static int arm_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
00147 tree, bool);
00148
00149 #ifdef OBJECT_FORMAT_ELF
00150 static void arm_elf_asm_constructor (rtx, int);
00151 #endif
00152 #ifndef ARM_PE
00153 static void arm_encode_section_info (tree, rtx, int);
00154 #endif
00155
00156 static void arm_file_end (void);
00157
00158 #ifdef AOF_ASSEMBLER
00159 static void aof_globalize_label (FILE *, const char *);
00160 static void aof_dump_imports (FILE *);
00161 static void aof_dump_pic_table (FILE *);
00162 static void aof_file_start (void);
00163 static void aof_file_end (void);
00164 static void aof_asm_init_sections (void);
00165 #endif
00166 static void arm_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
00167 tree, int *, int);
00168 static bool arm_pass_by_reference (CUMULATIVE_ARGS *,
00169 enum machine_mode, tree, bool);
00170 static bool arm_promote_prototypes (tree);
00171 static bool arm_default_short_enums (void);
00172 static bool arm_align_anon_bitfield (void);
00173 static bool arm_return_in_msb (tree);
00174 static bool arm_must_pass_in_stack (enum machine_mode, tree);
00175 #ifdef TARGET_UNWIND_INFO
00176 static void arm_unwind_emit (FILE *, rtx);
00177 static bool arm_output_ttype (rtx);
00178 #endif
00179
00180 static tree arm_cxx_guard_type (void);
00181 static bool arm_cxx_guard_mask_bit (void);
00182 static tree arm_get_cookie_size (tree);
00183 static bool arm_cookie_has_size (void);
00184 static bool arm_cxx_cdtor_returns_this (void);
00185 static bool arm_cxx_key_method_may_be_inline (void);
00186 static void arm_cxx_determine_class_data_visibility (tree);
00187 static bool arm_cxx_class_data_always_comdat (void);
00188 static bool arm_cxx_use_aeabi_atexit (void);
00189 static void arm_init_libfuncs (void);
00190 static bool arm_handle_option (size_t, const char *, int);
00191 static unsigned HOST_WIDE_INT arm_shift_truncation_mask (enum machine_mode);
00192 static bool arm_cannot_copy_insn_p (rtx);
00193 static bool arm_tls_symbol_p (rtx x);
00194
00195
00196
00197 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
00198 #undef TARGET_MERGE_DECL_ATTRIBUTES
00199 #define TARGET_MERGE_DECL_ATTRIBUTES merge_dllimport_decl_attributes
00200 #endif
00201
00202 #undef TARGET_ATTRIBUTE_TABLE
00203 #define TARGET_ATTRIBUTE_TABLE arm_attribute_table
00204
00205 #undef TARGET_ASM_FILE_END
00206 #define TARGET_ASM_FILE_END arm_file_end
00207
00208 #ifdef AOF_ASSEMBLER
00209 #undef TARGET_ASM_BYTE_OP
00210 #define TARGET_ASM_BYTE_OP "\tDCB\t"
00211 #undef TARGET_ASM_ALIGNED_HI_OP
00212 #define TARGET_ASM_ALIGNED_HI_OP "\tDCW\t"
00213 #undef TARGET_ASM_ALIGNED_SI_OP
00214 #define TARGET_ASM_ALIGNED_SI_OP "\tDCD\t"
00215 #undef TARGET_ASM_GLOBALIZE_LABEL
00216 #define TARGET_ASM_GLOBALIZE_LABEL aof_globalize_label
00217 #undef TARGET_ASM_FILE_START
00218 #define TARGET_ASM_FILE_START aof_file_start
00219 #undef TARGET_ASM_FILE_END
00220 #define TARGET_ASM_FILE_END aof_file_end
00221 #else
00222 #undef TARGET_ASM_ALIGNED_SI_OP
00223 #define TARGET_ASM_ALIGNED_SI_OP NULL
00224 #undef TARGET_ASM_INTEGER
00225 #define TARGET_ASM_INTEGER arm_assemble_integer
00226 #endif
00227
00228 #undef TARGET_ASM_FUNCTION_PROLOGUE
00229 #define TARGET_ASM_FUNCTION_PROLOGUE arm_output_function_prologue
00230
00231 #undef TARGET_ASM_FUNCTION_EPILOGUE
00232 #define TARGET_ASM_FUNCTION_EPILOGUE arm_output_function_epilogue
00233
00234 #undef TARGET_DEFAULT_TARGET_FLAGS
00235 #define TARGET_DEFAULT_TARGET_FLAGS (TARGET_DEFAULT | MASK_SCHED_PROLOG)
00236 #undef TARGET_HANDLE_OPTION
00237 #define TARGET_HANDLE_OPTION arm_handle_option
00238
00239 #undef TARGET_COMP_TYPE_ATTRIBUTES
00240 #define TARGET_COMP_TYPE_ATTRIBUTES arm_comp_type_attributes
00241
00242 #undef TARGET_SET_DEFAULT_TYPE_ATTRIBUTES
00243 #define TARGET_SET_DEFAULT_TYPE_ATTRIBUTES arm_set_default_type_attributes
00244
00245 #undef TARGET_SCHED_ADJUST_COST
00246 #define TARGET_SCHED_ADJUST_COST arm_adjust_cost
00247
00248 #undef TARGET_ENCODE_SECTION_INFO
00249 #ifdef ARM_PE
00250 #define TARGET_ENCODE_SECTION_INFO arm_pe_encode_section_info
00251 #else
00252 #define TARGET_ENCODE_SECTION_INFO arm_encode_section_info
00253 #endif
00254
00255 #undef TARGET_STRIP_NAME_ENCODING
00256 #define TARGET_STRIP_NAME_ENCODING arm_strip_name_encoding
00257
00258 #undef TARGET_ASM_INTERNAL_LABEL
00259 #define TARGET_ASM_INTERNAL_LABEL arm_internal_label
00260
00261 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
00262 #define TARGET_FUNCTION_OK_FOR_SIBCALL arm_function_ok_for_sibcall
00263
00264 #undef TARGET_ASM_OUTPUT_MI_THUNK
00265 #define TARGET_ASM_OUTPUT_MI_THUNK arm_output_mi_thunk
00266 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
00267 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK default_can_output_mi_thunk_no_vcall
00268
00269
00270 #undef TARGET_RTX_COSTS
00271 #define TARGET_RTX_COSTS arm_slowmul_rtx_costs
00272 #undef TARGET_ADDRESS_COST
00273 #define TARGET_ADDRESS_COST arm_address_cost
00274
00275 #undef TARGET_SHIFT_TRUNCATION_MASK
00276 #define TARGET_SHIFT_TRUNCATION_MASK arm_shift_truncation_mask
00277 #undef TARGET_VECTOR_MODE_SUPPORTED_P
00278 #define TARGET_VECTOR_MODE_SUPPORTED_P arm_vector_mode_supported_p
00279
00280 #undef TARGET_MACHINE_DEPENDENT_REORG
00281 #define TARGET_MACHINE_DEPENDENT_REORG arm_reorg
00282
00283 #undef TARGET_INIT_BUILTINS
00284 #define TARGET_INIT_BUILTINS arm_init_builtins
00285 #undef TARGET_EXPAND_BUILTIN
00286 #define TARGET_EXPAND_BUILTIN arm_expand_builtin
00287
00288 #undef TARGET_INIT_LIBFUNCS
00289 #define TARGET_INIT_LIBFUNCS arm_init_libfuncs
00290
00291 #undef TARGET_PROMOTE_FUNCTION_ARGS
00292 #define TARGET_PROMOTE_FUNCTION_ARGS hook_bool_tree_true
00293 #undef TARGET_PROMOTE_FUNCTION_RETURN
00294 #define TARGET_PROMOTE_FUNCTION_RETURN hook_bool_tree_true
00295 #undef TARGET_PROMOTE_PROTOTYPES
00296 #define TARGET_PROMOTE_PROTOTYPES arm_promote_prototypes
00297 #undef TARGET_PASS_BY_REFERENCE
00298 #define TARGET_PASS_BY_REFERENCE arm_pass_by_reference
00299 #undef TARGET_ARG_PARTIAL_BYTES
00300 #define TARGET_ARG_PARTIAL_BYTES arm_arg_partial_bytes
00301
00302 #undef TARGET_SETUP_INCOMING_VARARGS
00303 #define TARGET_SETUP_INCOMING_VARARGS arm_setup_incoming_varargs
00304
00305 #undef TARGET_DEFAULT_SHORT_ENUMS
00306 #define TARGET_DEFAULT_SHORT_ENUMS arm_default_short_enums
00307
00308 #undef TARGET_ALIGN_ANON_BITFIELD
00309 #define TARGET_ALIGN_ANON_BITFIELD arm_align_anon_bitfield
00310
00311 #undef TARGET_NARROW_VOLATILE_BITFIELD
00312 #define TARGET_NARROW_VOLATILE_BITFIELD hook_bool_void_false
00313
00314 #undef TARGET_CXX_GUARD_TYPE
00315 #define TARGET_CXX_GUARD_TYPE arm_cxx_guard_type
00316
00317 #undef TARGET_CXX_GUARD_MASK_BIT
00318 #define TARGET_CXX_GUARD_MASK_BIT arm_cxx_guard_mask_bit
00319
00320 #undef TARGET_CXX_GET_COOKIE_SIZE
00321 #define TARGET_CXX_GET_COOKIE_SIZE arm_get_cookie_size
00322
00323 #undef TARGET_CXX_COOKIE_HAS_SIZE
00324 #define TARGET_CXX_COOKIE_HAS_SIZE arm_cookie_has_size
00325
00326 #undef TARGET_CXX_CDTOR_RETURNS_THIS
00327 #define TARGET_CXX_CDTOR_RETURNS_THIS arm_cxx_cdtor_returns_this
00328
00329 #undef TARGET_CXX_KEY_METHOD_MAY_BE_INLINE
00330 #define TARGET_CXX_KEY_METHOD_MAY_BE_INLINE arm_cxx_key_method_may_be_inline
00331
00332 #undef TARGET_CXX_USE_AEABI_ATEXIT
00333 #define TARGET_CXX_USE_AEABI_ATEXIT arm_cxx_use_aeabi_atexit
00334
00335 #undef TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY
00336 #define TARGET_CXX_DETERMINE_CLASS_DATA_VISIBILITY \
00337 arm_cxx_determine_class_data_visibility
00338
00339 #undef TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT
00340 #define TARGET_CXX_CLASS_DATA_ALWAYS_COMDAT arm_cxx_class_data_always_comdat
00341
00342 #undef TARGET_RETURN_IN_MSB
00343 #define TARGET_RETURN_IN_MSB arm_return_in_msb
00344
00345 #undef TARGET_MUST_PASS_IN_STACK
00346 #define TARGET_MUST_PASS_IN_STACK arm_must_pass_in_stack
00347
00348 #ifdef TARGET_UNWIND_INFO
00349 #undef TARGET_UNWIND_EMIT
00350 #define TARGET_UNWIND_EMIT arm_unwind_emit
00351
00352
00353 #undef TARGET_ASM_TTYPE
00354 #define TARGET_ASM_TTYPE arm_output_ttype
00355
00356 #undef TARGET_ARM_EABI_UNWINDER
00357 #define TARGET_ARM_EABI_UNWINDER true
00358 #endif
00359
00360 #undef TARGET_CANNOT_COPY_INSN_P
00361 #define TARGET_CANNOT_COPY_INSN_P arm_cannot_copy_insn_p
00362
00363 #ifdef HAVE_AS_TLS
00364 #undef TARGET_HAVE_TLS
00365 #define TARGET_HAVE_TLS true
00366 #endif
00367
00368 #undef TARGET_CANNOT_FORCE_CONST_MEM
00369 #define TARGET_CANNOT_FORCE_CONST_MEM arm_tls_referenced_p
00370
00371 struct gcc_target targetm = TARGET_INITIALIZER;
00372
00373
00374 static struct obstack minipool_obstack;
00375 static char * minipool_startobj;
00376
00377
00378
00379 static int max_insns_skipped = 5;
00380
00381 extern FILE * asm_out_file;
00382
00383
00384 int making_const_table;
00385
00386
00387
00388 rtx arm_compare_op0, arm_compare_op1;
00389
00390
00391 enum processor_type arm_tune = arm_none;
00392
00393
00394 enum arm_fp_model arm_fp_model;
00395
00396
00397 enum fputype arm_fpu_arch;
00398
00399
00400 enum fputype arm_fpu_tune;
00401
00402
00403 enum float_abi_type arm_float_abi;
00404
00405
00406 enum arm_abi_type arm_abi;
00407
00408
00409 enum arm_tp_type target_thread_pointer = TP_AUTO;
00410
00411
00412 int arm_structure_size_boundary = DEFAULT_STRUCTURE_SIZE_BOUNDARY;
00413
00414
00415 rtx thumb_call_via_label[14];
00416 static int thumb_call_reg_needed;
00417
00418
00419 #define FL_CO_PROC (1 << 0)
00420 #define FL_ARCH3M (1 << 1)
00421 #define FL_MODE26 (1 << 2)
00422 #define FL_MODE32 (1 << 3)
00423 #define FL_ARCH4 (1 << 4)
00424 #define FL_ARCH5 (1 << 5)
00425 #define FL_THUMB (1 << 6)
00426 #define FL_LDSCHED (1 << 7)
00427 #define FL_STRONG (1 << 8)
00428 #define FL_ARCH5E (1 << 9)
00429 #define FL_XSCALE (1 << 10)
00430 #define FL_CIRRUS (1 << 11)
00431 #define FL_ARCH6 (1 << 12)
00432
00433 #define FL_VFPV2 (1 << 13)
00434 #define FL_WBUF (1 << 14)
00435
00436 #define FL_ARCH6K (1 << 15)
00437
00438 #define FL_IWMMXT (1 << 29)
00439
00440 #define FL_FOR_ARCH2 0
00441 #define FL_FOR_ARCH3 FL_MODE32
00442 #define FL_FOR_ARCH3M (FL_FOR_ARCH3 | FL_ARCH3M)
00443 #define FL_FOR_ARCH4 (FL_FOR_ARCH3M | FL_ARCH4)
00444 #define FL_FOR_ARCH4T (FL_FOR_ARCH4 | FL_THUMB)
00445 #define FL_FOR_ARCH5 (FL_FOR_ARCH4 | FL_ARCH5)
00446 #define FL_FOR_ARCH5T (FL_FOR_ARCH5 | FL_THUMB)
00447 #define FL_FOR_ARCH5E (FL_FOR_ARCH5 | FL_ARCH5E)
00448 #define FL_FOR_ARCH5TE (FL_FOR_ARCH5E | FL_THUMB)
00449 #define FL_FOR_ARCH5TEJ FL_FOR_ARCH5TE
00450 #define FL_FOR_ARCH6 (FL_FOR_ARCH5TE | FL_ARCH6)
00451 #define FL_FOR_ARCH6J FL_FOR_ARCH6
00452 #define FL_FOR_ARCH6K (FL_FOR_ARCH6 | FL_ARCH6K)
00453 #define FL_FOR_ARCH6Z FL_FOR_ARCH6
00454 #define FL_FOR_ARCH6ZK FL_FOR_ARCH6K
00455
00456
00457
00458 static unsigned long insn_flags = 0;
00459
00460
00461
00462 static unsigned long tune_flags = 0;
00463
00464
00465
00466
00467
00468 int arm_arch3m = 0;
00469
00470
00471 int arm_arch4 = 0;
00472
00473
00474 int arm_arch4t = 0;
00475
00476
00477 int arm_arch5 = 0;
00478
00479
00480 int arm_arch5e = 0;
00481
00482
00483 int arm_arch6 = 0;
00484
00485
00486 int arm_arch6k = 0;
00487
00488
00489 int arm_ld_sched = 0;
00490
00491
00492 int arm_tune_strongarm = 0;
00493
00494
00495 int arm_arch_cirrus = 0;
00496
00497
00498 int arm_arch_iwmmxt = 0;
00499
00500
00501 int arm_arch_xscale = 0;
00502
00503
00504 int arm_tune_xscale = 0;
00505
00506
00507
00508 int arm_tune_wbuf = 0;
00509
00510
00511 int thumb_code = 0;
00512
00513
00514
00515
00516
00517
00518 int arm_cpp_interwork = 0;
00519
00520
00521
00522
00523 enum machine_mode output_memory_reference_mode;
00524
00525
00526 unsigned arm_pic_register = INVALID_REGNUM;
00527
00528
00529
00530 int return_used_this_function;
00531
00532
00533
00534 static int after_arm_reorg = 0;
00535
00536
00537 static int arm_constant_limit = 3;
00538
00539
00540 int arm_ccfsm_state;
00541 enum arm_cond_code arm_current_cc;
00542 rtx arm_target_insn;
00543 int arm_target_label;
00544
00545
00546 static const char * const arm_condition_codes[] =
00547 {
00548 "eq", "ne", "cs", "cc", "mi", "pl", "vs", "vc",
00549 "hi", "ls", "ge", "lt", "gt", "le", "al", "nv"
00550 };
00551
00552 #define streq(string1, string2) (strcmp (string1, string2) == 0)
00553
00554
00555
00556 struct processors
00557 {
00558 const char *const name;
00559 enum processor_type core;
00560 const char *arch;
00561 const unsigned long flags;
00562 bool (* rtx_costs) (rtx, int, int, int *);
00563 };
00564
00565
00566
00567 static const struct processors all_cores[] =
00568 {
00569
00570 #define ARM_CORE(NAME, IDENT, ARCH, FLAGS, COSTS) \
00571 {NAME, arm_none, #ARCH, FLAGS | FL_FOR_ARCH##ARCH, arm_##COSTS##_rtx_costs},
00572 #include "arm-cores.def"
00573 #undef ARM_CORE
00574 {NULL, arm_none, NULL, 0, NULL}
00575 };
00576
00577 static const struct processors all_architectures[] =
00578 {
00579
00580
00581
00582
00583 {"armv2", arm2, "2", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
00584 {"armv2a", arm2, "2", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH2, NULL},
00585 {"armv3", arm6, "3", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3, NULL},
00586 {"armv3m", arm7m, "3M", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH3M, NULL},
00587 {"armv4", arm7tdmi, "4", FL_CO_PROC | FL_MODE26 | FL_FOR_ARCH4, NULL},
00588
00589
00590 {"armv4t", arm7tdmi, "4T", FL_CO_PROC | FL_FOR_ARCH4T, NULL},
00591 {"armv5", arm10tdmi, "5", FL_CO_PROC | FL_FOR_ARCH5, NULL},
00592 {"armv5t", arm10tdmi, "5T", FL_CO_PROC | FL_FOR_ARCH5T, NULL},
00593 {"armv5e", arm1026ejs, "5E", FL_CO_PROC | FL_FOR_ARCH5E, NULL},
00594 {"armv5te", arm1026ejs, "5TE", FL_CO_PROC | FL_FOR_ARCH5TE, NULL},
00595 {"armv6", arm1136js, "6", FL_CO_PROC | FL_FOR_ARCH6, NULL},
00596 {"armv6j", arm1136js, "6J", FL_CO_PROC | FL_FOR_ARCH6J, NULL},
00597 {"armv6k", mpcore, "6K", FL_CO_PROC | FL_FOR_ARCH6K, NULL},
00598 {"armv6z", arm1176jzs, "6Z", FL_CO_PROC | FL_FOR_ARCH6Z, NULL},
00599 {"armv6zk", arm1176jzs, "6ZK", FL_CO_PROC | FL_FOR_ARCH6ZK, NULL},
00600 {"ep9312", ep9312, "4T", FL_LDSCHED | FL_CIRRUS | FL_FOR_ARCH4, NULL},
00601 {"iwmmxt", iwmmxt, "5TE", FL_LDSCHED | FL_STRONG | FL_FOR_ARCH5TE | FL_XSCALE | FL_IWMMXT , NULL},
00602 {NULL, arm_none, NULL, 0 , NULL}
00603 };
00604
00605 struct arm_cpu_select
00606 {
00607 const char * string;
00608 const char * name;
00609 const struct processors * processors;
00610 };
00611
00612
00613
00614
00615
00616 static struct arm_cpu_select arm_select[] =
00617 {
00618
00619 { NULL, "-mcpu=", all_cores },
00620 { NULL, "-march=", all_architectures },
00621 { NULL, "-mtune=", all_cores }
00622 };
00623
00624
00625 #define ARM_OPT_SET_CPU 0
00626 #define ARM_OPT_SET_ARCH 1
00627 #define ARM_OPT_SET_TUNE 2
00628
00629
00630
00631 char arm_arch_name[] = "__ARM_ARCH_0UNK__";
00632
00633 struct fpu_desc
00634 {
00635 const char * name;
00636 enum fputype fpu;
00637 };
00638
00639
00640
00641
00642 static const struct fpu_desc all_fpus[] =
00643 {
00644 {"fpa", FPUTYPE_FPA},
00645 {"fpe2", FPUTYPE_FPA_EMU2},
00646 {"fpe3", FPUTYPE_FPA_EMU2},
00647 {"maverick", FPUTYPE_MAVERICK},
00648 {"vfp", FPUTYPE_VFP}
00649 };
00650
00651
00652
00653
00654
00655 static const enum fputype fp_model_for_fpu[] =
00656 {
00657
00658 ARM_FP_MODEL_UNKNOWN,
00659 ARM_FP_MODEL_FPA,
00660 ARM_FP_MODEL_FPA,
00661 ARM_FP_MODEL_FPA,
00662 ARM_FP_MODEL_MAVERICK,
00663 ARM_FP_MODEL_VFP
00664 };
00665
00666
00667 struct float_abi
00668 {
00669 const char * name;
00670 enum float_abi_type abi_type;
00671 };
00672
00673
00674
00675
00676 static const struct float_abi all_float_abis[] =
00677 {
00678 {"soft", ARM_FLOAT_ABI_SOFT},
00679 {"softfp", ARM_FLOAT_ABI_SOFTFP},
00680 {"hard", ARM_FLOAT_ABI_HARD}
00681 };
00682
00683
00684 struct abi_name
00685 {
00686 const char *name;
00687 enum arm_abi_type abi_type;
00688 };
00689
00690
00691
00692
00693 static const struct abi_name arm_all_abis[] =
00694 {
00695 {"apcs-gnu", ARM_ABI_APCS},
00696 {"atpcs", ARM_ABI_ATPCS},
00697 {"aapcs", ARM_ABI_AAPCS},
00698 {"iwmmxt", ARM_ABI_IWMMXT},
00699 {"aapcs-linux", ARM_ABI_AAPCS_LINUX}
00700 };
00701
00702
00703
00704 enum tls_reloc {
00705 TLS_GD32,
00706 TLS_LDM32,
00707 TLS_LDO32,
00708 TLS_IE32,
00709 TLS_LE32
00710 };
00711
00712
00713
00714 inline static rtx
00715 emit_set_insn (rtx x, rtx y)
00716 {
00717 return emit_insn (gen_rtx_SET (VOIDmode, x, y));
00718 }
00719
00720
00721 static unsigned
00722 bit_count (unsigned long value)
00723 {
00724 unsigned long count = 0;
00725
00726 while (value)
00727 {
00728 count++;
00729 value &= value - 1;
00730 }
00731
00732 return count;
00733 }
00734
00735
00736
00737 static void
00738 arm_init_libfuncs (void)
00739 {
00740
00741
00742 if (!TARGET_BPABI)
00743 return;
00744
00745
00746
00747
00748
00749 set_optab_libfunc (add_optab, DFmode, "__aeabi_dadd");
00750 set_optab_libfunc (sdiv_optab, DFmode, "__aeabi_ddiv");
00751 set_optab_libfunc (smul_optab, DFmode, "__aeabi_dmul");
00752 set_optab_libfunc (neg_optab, DFmode, "__aeabi_dneg");
00753 set_optab_libfunc (sub_optab, DFmode, "__aeabi_dsub");
00754
00755
00756 set_optab_libfunc (eq_optab, DFmode, "__aeabi_dcmpeq");
00757 set_optab_libfunc (ne_optab, DFmode, NULL);
00758 set_optab_libfunc (lt_optab, DFmode, "__aeabi_dcmplt");
00759 set_optab_libfunc (le_optab, DFmode, "__aeabi_dcmple");
00760 set_optab_libfunc (ge_optab, DFmode, "__aeabi_dcmpge");
00761 set_optab_libfunc (gt_optab, DFmode, "__aeabi_dcmpgt");
00762 set_optab_libfunc (unord_optab, DFmode, "__aeabi_dcmpun");
00763
00764
00765 set_optab_libfunc (add_optab, SFmode, "__aeabi_fadd");
00766 set_optab_libfunc (sdiv_optab, SFmode, "__aeabi_fdiv");
00767 set_optab_libfunc (smul_optab, SFmode, "__aeabi_fmul");
00768 set_optab_libfunc (neg_optab, SFmode, "__aeabi_fneg");
00769 set_optab_libfunc (sub_optab, SFmode, "__aeabi_fsub");
00770
00771
00772 set_optab_libfunc (eq_optab, SFmode, "__aeabi_fcmpeq");
00773 set_optab_libfunc (ne_optab, SFmode, NULL);
00774 set_optab_libfunc (lt_optab, SFmode, "__aeabi_fcmplt");
00775 set_optab_libfunc (le_optab, SFmode, "__aeabi_fcmple");
00776 set_optab_libfunc (ge_optab, SFmode, "__aeabi_fcmpge");
00777 set_optab_libfunc (gt_optab, SFmode, "__aeabi_fcmpgt");
00778 set_optab_libfunc (unord_optab, SFmode, "__aeabi_fcmpun");
00779
00780
00781 set_conv_libfunc (sfix_optab, SImode, DFmode, "__aeabi_d2iz");
00782 set_conv_libfunc (ufix_optab, SImode, DFmode, "__aeabi_d2uiz");
00783 set_conv_libfunc (sfix_optab, DImode, DFmode, "__aeabi_d2lz");
00784 set_conv_libfunc (ufix_optab, DImode, DFmode, "__aeabi_d2ulz");
00785 set_conv_libfunc (sfix_optab, SImode, SFmode, "__aeabi_f2iz");
00786 set_conv_libfunc (ufix_optab, SImode, SFmode, "__aeabi_f2uiz");
00787 set_conv_libfunc (sfix_optab, DImode, SFmode, "__aeabi_f2lz");
00788 set_conv_libfunc (ufix_optab, DImode, SFmode, "__aeabi_f2ulz");
00789
00790
00791 set_conv_libfunc (trunc_optab, SFmode, DFmode, "__aeabi_d2f");
00792 set_conv_libfunc (sext_optab, DFmode, SFmode, "__aeabi_f2d");
00793
00794
00795 set_conv_libfunc (sfloat_optab, DFmode, SImode, "__aeabi_i2d");
00796 set_conv_libfunc (ufloat_optab, DFmode, SImode, "__aeabi_ui2d");
00797 set_conv_libfunc (sfloat_optab, DFmode, DImode, "__aeabi_l2d");
00798 set_conv_libfunc (ufloat_optab, DFmode, DImode, "__aeabi_ul2d");
00799 set_conv_libfunc (sfloat_optab, SFmode, SImode, "__aeabi_i2f");
00800 set_conv_libfunc (ufloat_optab, SFmode, SImode, "__aeabi_ui2f");
00801 set_conv_libfunc (sfloat_optab, SFmode, DImode, "__aeabi_l2f");
00802 set_conv_libfunc (ufloat_optab, SFmode, DImode, "__aeabi_ul2f");
00803
00804
00805 set_optab_libfunc (smul_optab, DImode, "__aeabi_lmul");
00806 set_optab_libfunc (sdivmod_optab, DImode, "__aeabi_ldivmod");
00807 set_optab_libfunc (udivmod_optab, DImode, "__aeabi_uldivmod");
00808 set_optab_libfunc (ashl_optab, DImode, "__aeabi_llsl");
00809 set_optab_libfunc (lshr_optab, DImode, "__aeabi_llsr");
00810 set_optab_libfunc (ashr_optab, DImode, "__aeabi_lasr");
00811 set_optab_libfunc (cmp_optab, DImode, "__aeabi_lcmp");
00812 set_optab_libfunc (ucmp_optab, DImode, "__aeabi_ulcmp");
00813
00814
00815 set_optab_libfunc (sdivmod_optab, SImode, "__aeabi_idivmod");
00816 set_optab_libfunc (udivmod_optab, SImode, "__aeabi_uidivmod");
00817
00818
00819
00820
00821
00822
00823
00824
00825
00826
00827 set_optab_libfunc (sdiv_optab, DImode, "__aeabi_ldivmod");
00828 set_optab_libfunc (udiv_optab, DImode, "__aeabi_uldivmod");
00829
00830
00831
00832 set_optab_libfunc (sdiv_optab, SImode, "__aeabi_idiv");
00833 set_optab_libfunc (udiv_optab, SImode, "__aeabi_uidiv");
00834
00835
00836
00837 set_optab_libfunc (smod_optab, DImode, NULL);
00838 set_optab_libfunc (umod_optab, DImode, NULL);
00839 set_optab_libfunc (smod_optab, SImode, NULL);
00840 set_optab_libfunc (umod_optab, SImode, NULL);
00841 }
00842
00843
00844
00845 static bool
00846 arm_handle_option (size_t code, const char *arg, int value ATTRIBUTE_UNUSED)
00847 {
00848 switch (code)
00849 {
00850 case OPT_march_:
00851 arm_select[1].string = arg;
00852 return true;
00853
00854 case OPT_mcpu_:
00855 arm_select[0].string = arg;
00856 return true;
00857
00858 case OPT_mhard_float:
00859 target_float_abi_name = "hard";
00860 return true;
00861
00862 case OPT_msoft_float:
00863 target_float_abi_name = "soft";
00864 return true;
00865
00866 case OPT_mtune_:
00867 arm_select[2].string = arg;
00868 return true;
00869
00870 default:
00871 return true;
00872 }
00873 }
00874
00875
00876
00877 void
00878 arm_override_options (void)
00879 {
00880 unsigned i;
00881 enum processor_type target_arch_cpu = arm_none;
00882
00883
00884 for (i = ARRAY_SIZE (arm_select); i--;)
00885 {
00886 struct arm_cpu_select * ptr = arm_select + i;
00887
00888 if (ptr->string != NULL && ptr->string[0] != '\0')
00889 {
00890 const struct processors * sel;
00891
00892 for (sel = ptr->processors; sel->name != NULL; sel++)
00893 if (streq (ptr->string, sel->name))
00894 {
00895
00896 if (i != ARM_OPT_SET_TUNE)
00897 sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
00898
00899
00900
00901 if (
00902 i == ARM_OPT_SET_CPU
00903
00904 || i == ARM_OPT_SET_TUNE)
00905 arm_tune = (enum processor_type) (sel - ptr->processors);
00906
00907
00908
00909
00910
00911 if (i == ARM_OPT_SET_ARCH)
00912 target_arch_cpu = sel->core;
00913
00914 if (i != ARM_OPT_SET_TUNE)
00915 {
00916
00917
00918
00919
00920 if (insn_flags != 0 && (insn_flags ^ sel->flags))
00921 warning (0, "switch -mcpu=%s conflicts with -march= switch",
00922 ptr->string);
00923
00924 insn_flags = sel->flags;
00925 }
00926
00927 break;
00928 }
00929
00930 if (sel->name == NULL)
00931 error ("bad value (%s) for %s switch", ptr->string, ptr->name);
00932 }
00933 }
00934
00935
00936 if (arm_tune == arm_none)
00937 arm_tune = target_arch_cpu;
00938
00939
00940 if (insn_flags == 0)
00941 {
00942 const struct processors * sel;
00943 unsigned int sought;
00944 enum processor_type cpu;
00945
00946 cpu = TARGET_CPU_DEFAULT;
00947 if (cpu == arm_none)
00948 {
00949 #ifdef SUBTARGET_CPU_DEFAULT
00950
00951
00952 cpu = SUBTARGET_CPU_DEFAULT;
00953 #endif
00954
00955 if (cpu == arm_none)
00956 cpu = arm6;
00957 }
00958 sel = &all_cores[cpu];
00959
00960 insn_flags = sel->flags;
00961
00962
00963
00964 sought = 0;
00965
00966 if (TARGET_INTERWORK || TARGET_THUMB)
00967 {
00968 sought |= (FL_THUMB | FL_MODE32);
00969
00970
00971
00972
00973
00974 insn_flags &= ~FL_MODE26;
00975 }
00976
00977 if (sought != 0 && ((sought & insn_flags) != sought))
00978 {
00979
00980
00981
00982 for (sel = all_cores; sel->name != NULL; sel++)
00983 if ((sel->flags & sought) == (sought | insn_flags))
00984 break;
00985
00986 if (sel->name == NULL)
00987 {
00988 unsigned current_bit_count = 0;
00989 const struct processors * best_fit = NULL;
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002 for (sel = all_cores; sel->name != NULL; sel++)
01003 if ((sel->flags & sought) == sought)
01004 {
01005 unsigned count;
01006
01007 count = bit_count (sel->flags & insn_flags);
01008
01009 if (count >= current_bit_count)
01010 {
01011 best_fit = sel;
01012 current_bit_count = count;
01013 }
01014 }
01015
01016 gcc_assert (best_fit);
01017 sel = best_fit;
01018 }
01019
01020 insn_flags = sel->flags;
01021 }
01022 sprintf (arm_arch_name, "__ARM_ARCH_%s__", sel->arch);
01023 if (arm_tune == arm_none)
01024 arm_tune = (enum processor_type) (sel - all_cores);
01025 }
01026
01027
01028
01029 gcc_assert (arm_tune != arm_none);
01030
01031 tune_flags = all_cores[(int)arm_tune].flags;
01032 if (optimize_size)
01033 targetm.rtx_costs = arm_size_rtx_costs;
01034 else
01035 targetm.rtx_costs = all_cores[(int)arm_tune].rtx_costs;
01036
01037
01038
01039 if (TARGET_INTERWORK && !(insn_flags & FL_THUMB))
01040 {
01041 warning (0, "target CPU does not support interworking" );
01042 target_flags &= ~MASK_INTERWORK;
01043 }
01044
01045 if (TARGET_THUMB && !(insn_flags & FL_THUMB))
01046 {
01047 warning (0, "target CPU does not support THUMB instructions");
01048 target_flags &= ~MASK_THUMB;
01049 }
01050
01051 if (TARGET_APCS_FRAME && TARGET_THUMB)
01052 {
01053
01054 target_flags &= ~MASK_APCS_FRAME;
01055 }
01056
01057
01058
01059 if (TARGET_THUMB && TARGET_CALLEE_INTERWORKING)
01060 target_flags |= MASK_INTERWORK;
01061
01062
01063
01064 if ((TARGET_TPCS_FRAME || TARGET_TPCS_LEAF_FRAME) && TARGET_ARM)
01065 warning (0, "enabling backtrace support is only meaningful when compiling for the Thumb");
01066
01067 if (TARGET_ARM && TARGET_CALLEE_INTERWORKING)
01068 warning (0, "enabling callee interworking support is only meaningful when compiling for the Thumb");
01069
01070 if (TARGET_ARM && TARGET_CALLER_INTERWORKING)
01071 warning (0, "enabling caller interworking support is only meaningful when compiling for the Thumb");
01072
01073 if (TARGET_APCS_STACK && !TARGET_APCS_FRAME)
01074 {
01075 warning (0, "-mapcs-stack-check incompatible with -mno-apcs-frame");
01076 target_flags |= MASK_APCS_FRAME;
01077 }
01078
01079 if (TARGET_POKE_FUNCTION_NAME)
01080 target_flags |= MASK_APCS_FRAME;
01081
01082 if (TARGET_APCS_REENT && flag_pic)
01083 error ("-fpic and -mapcs-reent are incompatible");
01084
01085 if (TARGET_APCS_REENT)
01086 warning (0, "APCS reentrant code not supported. Ignored");
01087
01088
01089
01090 if (TARGET_ARM
01091 && write_symbols != NO_DEBUG
01092 && !TARGET_APCS_FRAME
01093 && (TARGET_DEFAULT & MASK_APCS_FRAME))
01094 warning (0, "-g with -mno-apcs-frame may not give sensible debugging");
01095
01096
01097
01098 if (flag_pic && TARGET_SINGLE_PIC_BASE)
01099 arm_pic_register = TARGET_APCS_STACK ? 9 : 10;
01100
01101 if (TARGET_APCS_FLOAT)
01102 warning (0, "passing floating point arguments in fp regs not yet supported");
01103
01104
01105 arm_arch3m = (insn_flags & FL_ARCH3M) != 0;
01106 arm_arch4 = (insn_flags & FL_ARCH4) != 0;
01107 arm_arch4t = arm_arch4 & ((insn_flags & FL_THUMB) != 0);
01108 arm_arch5 = (insn_flags & FL_ARCH5) != 0;
01109 arm_arch5e = (insn_flags & FL_ARCH5E) != 0;
01110 arm_arch6 = (insn_flags & FL_ARCH6) != 0;
01111 arm_arch6k = (insn_flags & FL_ARCH6K) != 0;
01112 arm_arch_xscale = (insn_flags & FL_XSCALE) != 0;
01113 arm_arch_cirrus = (insn_flags & FL_CIRRUS) != 0;
01114
01115 arm_ld_sched = (tune_flags & FL_LDSCHED) != 0;
01116 arm_tune_strongarm = (tune_flags & FL_STRONG) != 0;
01117 thumb_code = (TARGET_ARM == 0);
01118 arm_tune_wbuf = (tune_flags & FL_WBUF) != 0;
01119 arm_tune_xscale = (tune_flags & FL_XSCALE) != 0;
01120 arm_arch_iwmmxt = (insn_flags & FL_IWMMXT) != 0;
01121
01122
01123
01124
01125
01126
01127 if (TARGET_INTERWORK)
01128 arm_cpp_interwork = 1;
01129
01130 if (arm_arch5)
01131 target_flags &= ~MASK_INTERWORK;
01132
01133 if (target_abi_name)
01134 {
01135 for (i = 0; i < ARRAY_SIZE (arm_all_abis); i++)
01136 {
01137 if (streq (arm_all_abis[i].name, target_abi_name))
01138 {
01139 arm_abi = arm_all_abis[i].abi_type;
01140 break;
01141 }
01142 }
01143 if (i == ARRAY_SIZE (arm_all_abis))
01144 error ("invalid ABI option: -mabi=%s", target_abi_name);
01145 }
01146 else
01147 arm_abi = ARM_DEFAULT_ABI;
01148
01149 if (TARGET_IWMMXT && !ARM_DOUBLEWORD_ALIGN)
01150 error ("iwmmxt requires an AAPCS compatible ABI for proper operation");
01151
01152 if (TARGET_IWMMXT_ABI && !TARGET_IWMMXT)
01153 error ("iwmmxt abi requires an iwmmxt capable cpu");
01154
01155 arm_fp_model = ARM_FP_MODEL_UNKNOWN;
01156 if (target_fpu_name == NULL && target_fpe_name != NULL)
01157 {
01158 if (streq (target_fpe_name, "2"))
01159 target_fpu_name = "fpe2";
01160 else if (streq (target_fpe_name, "3"))
01161 target_fpu_name = "fpe3";
01162 else
01163 error ("invalid floating point emulation option: -mfpe=%s",
01164 target_fpe_name);
01165 }
01166 if (target_fpu_name != NULL)
01167 {
01168
01169 for (i = 0; i < ARRAY_SIZE (all_fpus); i++)
01170 {
01171 if (streq (all_fpus[i].name, target_fpu_name))
01172 {
01173 arm_fpu_arch = all_fpus[i].fpu;
01174 arm_fpu_tune = arm_fpu_arch;
01175 arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
01176 break;
01177 }
01178 }
01179 if (arm_fp_model == ARM_FP_MODEL_UNKNOWN)
01180 error ("invalid floating point option: -mfpu=%s", target_fpu_name);
01181 }
01182 else
01183 {
01184 #ifdef FPUTYPE_DEFAULT
01185
01186 arm_fpu_arch = FPUTYPE_DEFAULT;
01187 arm_fpu_tune = FPUTYPE_DEFAULT;
01188 #else
01189
01190
01191
01192
01193
01194
01195 if (arm_arch_cirrus)
01196 arm_fpu_arch = FPUTYPE_MAVERICK;
01197 else
01198 arm_fpu_arch = FPUTYPE_FPA_EMU2;
01199 #endif
01200 if (tune_flags & FL_CO_PROC && arm_fpu_arch == FPUTYPE_FPA_EMU2)
01201 arm_fpu_tune = FPUTYPE_FPA;
01202 else
01203 arm_fpu_tune = arm_fpu_arch;
01204 arm_fp_model = fp_model_for_fpu[arm_fpu_arch];
01205 gcc_assert (arm_fp_model != ARM_FP_MODEL_UNKNOWN);
01206 }
01207
01208 if (target_float_abi_name != NULL)
01209 {
01210
01211 for (i = 0; i < ARRAY_SIZE (all_float_abis); i++)
01212 {
01213 if (streq (all_float_abis[i].name, target_float_abi_name))
01214 {
01215 arm_float_abi = all_float_abis[i].abi_type;
01216 break;
01217 }
01218 }
01219 if (i == ARRAY_SIZE (all_float_abis))
01220 error ("invalid floating point abi: -mfloat-abi=%s",
01221 target_float_abi_name);
01222 }
01223 else
01224 arm_float_abi = TARGET_DEFAULT_FLOAT_ABI;
01225
01226 if (arm_float_abi == ARM_FLOAT_ABI_HARD && TARGET_VFP)
01227 sorry ("-mfloat-abi=hard and VFP");
01228
01229
01230
01231
01232 if (TARGET_IWMMXT && !TARGET_SOFT_FLOAT)
01233 sorry ("iWMMXt and hardware floating point");
01234
01235
01236 if (TARGET_SOFT_FLOAT)
01237 arm_fpu_arch = FPUTYPE_NONE;
01238
01239
01240
01241 if ((TARGET_SOFT_FLOAT
01242 || arm_fpu_tune == FPUTYPE_FPA_EMU2
01243 || arm_fpu_tune == FPUTYPE_FPA_EMU3)
01244 && (tune_flags & FL_MODE32) == 0)
01245 flag_schedule_insns = flag_schedule_insns_after_reload = 0;
01246
01247 if (target_thread_switch)
01248 {
01249 if (strcmp (target_thread_switch, "soft") == 0)
01250 target_thread_pointer = TP_SOFT;
01251 else if (strcmp (target_thread_switch, "auto") == 0)
01252 target_thread_pointer = TP_AUTO;
01253 else if (strcmp (target_thread_switch, "cp15") == 0)
01254 target_thread_pointer = TP_CP15;
01255 else
01256 error ("invalid thread pointer option: -mtp=%s", target_thread_switch);
01257 }
01258
01259
01260 if (target_thread_pointer == TP_AUTO)
01261 {
01262 if (arm_arch6k && !TARGET_THUMB)
01263 target_thread_pointer = TP_CP15;
01264 else
01265 target_thread_pointer = TP_SOFT;
01266 }
01267
01268 if (TARGET_HARD_TP && TARGET_THUMB)
01269 error ("can not use -mtp=cp15 with -mthumb");
01270
01271
01272 if (TARGET_AAPCS_BASED)
01273 arm_structure_size_boundary = 8;
01274
01275 if (structure_size_string != NULL)
01276 {
01277 int size = strtol (structure_size_string, NULL, 0);
01278
01279 if (size == 8 || size == 32
01280 || (ARM_DOUBLEWORD_ALIGN && size == 64))
01281 arm_structure_size_boundary = size;
01282 else
01283 warning (0, "structure size boundary can only be set to %s",
01284 ARM_DOUBLEWORD_ALIGN ? "8, 32 or 64": "8 or 32");
01285 }
01286
01287 if (arm_pic_register_string != NULL)
01288 {
01289 int pic_register = decode_reg_name (arm_pic_register_string);
01290
01291 if (!flag_pic)
01292 warning (0, "-mpic-register= is useless without -fpic");
01293
01294
01295 else if (pic_register < 0 || call_used_regs[pic_register]
01296 || pic_register == HARD_FRAME_POINTER_REGNUM
01297 || pic_register == STACK_POINTER_REGNUM
01298 || pic_register >= PC_REGNUM)
01299 error ("unable to use '%s' for PIC register", arm_pic_register_string);
01300 else
01301 arm_pic_register = pic_register;
01302 }
01303
01304 if (TARGET_THUMB && flag_schedule_insns)
01305 {
01306
01307 flag_schedule_insns = 0;
01308 }
01309
01310 if (optimize_size)
01311 {
01312 arm_constant_limit = 1;
01313
01314
01315
01316 max_insns_skipped = 6;
01317 }
01318 else
01319 {
01320
01321
01322
01323 if (arm_ld_sched)
01324 arm_constant_limit = 1;
01325
01326
01327
01328
01329 if (arm_tune_xscale)
01330 arm_constant_limit = 2;
01331
01332
01333
01334 if (arm_tune_strongarm)
01335 max_insns_skipped = 3;
01336 }
01337
01338
01339 arm_add_gc_roots ();
01340 }
01341
01342 static void
01343 arm_add_gc_roots (void)
01344 {
01345 gcc_obstack_init(&minipool_obstack);
01346 minipool_startobj = (char *) obstack_alloc (&minipool_obstack, 0);
01347 }
01348
01349
01350
01351
01352 typedef struct
01353 {
01354 const char *const arg;
01355 const unsigned long return_value;
01356 }
01357 isr_attribute_arg;
01358
01359 static const isr_attribute_arg isr_attribute_args [] =
01360 {
01361 { "IRQ", ARM_FT_ISR },
01362 { "irq", ARM_FT_ISR },
01363 { "FIQ", ARM_FT_FIQ },
01364 { "fiq", ARM_FT_FIQ },
01365 { "ABORT", ARM_FT_ISR },
01366 { "abort", ARM_FT_ISR },
01367 { "ABORT", ARM_FT_ISR },
01368 { "abort", ARM_FT_ISR },
01369 { "UNDEF", ARM_FT_EXCEPTION },
01370 { "undef", ARM_FT_EXCEPTION },
01371 { "SWI", ARM_FT_EXCEPTION },
01372 { "swi", ARM_FT_EXCEPTION },
01373 { NULL, ARM_FT_NORMAL }
01374 };
01375
01376
01377
01378
01379 static unsigned long
01380 arm_isr_value (tree argument)
01381 {
01382 const isr_attribute_arg * ptr;
01383 const char * arg;
01384
01385
01386 if (argument == NULL_TREE)
01387 return ARM_FT_ISR;
01388
01389
01390 if (TREE_VALUE (argument) == NULL_TREE
01391 || TREE_CODE (TREE_VALUE (argument)) != STRING_CST)
01392 return ARM_FT_UNKNOWN;
01393
01394 arg = TREE_STRING_POINTER (TREE_VALUE (argument));
01395
01396
01397 for (ptr = isr_attribute_args; ptr->arg != NULL; ptr++)
01398 if (streq (arg, ptr->arg))
01399 return ptr->return_value;
01400
01401
01402 return ARM_FT_UNKNOWN;
01403 }
01404
01405
01406
01407 static unsigned long
01408 arm_compute_func_type (void)
01409 {
01410 unsigned long type = ARM_FT_UNKNOWN;
01411 tree a;
01412 tree attr;
01413
01414 gcc_assert (TREE_CODE (current_function_decl) == FUNCTION_DECL);
01415
01416
01417
01418
01419
01420 if (optimize > 0
01421 && (TREE_NOTHROW (current_function_decl)
01422 || !(flag_unwind_tables
01423 || (flag_exceptions && !USING_SJLJ_EXCEPTIONS)))
01424 && TREE_THIS_VOLATILE (current_function_decl))
01425 type |= ARM_FT_VOLATILE;
01426
01427 if (cfun->static_chain_decl != NULL)
01428 type |= ARM_FT_NESTED;
01429
01430 attr = DECL_ATTRIBUTES (current_function_decl);
01431
01432 a = lookup_attribute ("naked", attr);
01433 if (a != NULL_TREE)
01434 type |= ARM_FT_NAKED;
01435
01436 a = lookup_attribute ("isr", attr);
01437 if (a == NULL_TREE)
01438 a = lookup_attribute ("interrupt", attr);
01439
01440 if (a == NULL_TREE)
01441 type |= TARGET_INTERWORK ? ARM_FT_INTERWORKED : ARM_FT_NORMAL;
01442 else
01443 type |= arm_isr_value (TREE_VALUE (a));
01444
01445 return type;
01446 }
01447
01448
01449
01450 unsigned long
01451 arm_current_func_type (void)
01452 {
01453 if (ARM_FUNC_TYPE (cfun->machine->func_type) == ARM_FT_UNKNOWN)
01454 cfun->machine->func_type = arm_compute_func_type ();
01455
01456 return cfun->machine->func_type;
01457 }
01458
01459
01460
01461
01462
01463 int
01464 use_return_insn (int iscond, rtx sibling)
01465 {
01466 int regno;
01467 unsigned int func_type;
01468 unsigned long saved_int_regs;
01469 unsigned HOST_WIDE_INT stack_adjust;
01470 arm_stack_offsets *offsets;
01471
01472
01473 if (!reload_completed)
01474 return 0;
01475
01476 func_type = arm_current_func_type ();
01477
01478
01479
01480 if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED))
01481 return 0;
01482
01483
01484 if (IS_INTERRUPT (func_type) && frame_pointer_needed)
01485 return 0;
01486
01487 offsets = arm_get_frame_offsets ();
01488 stack_adjust = offsets->outgoing_args - offsets->saved_regs;
01489
01490
01491 if (current_function_pretend_args_size
01492 || cfun->machine->uses_anonymous_args
01493
01494 || current_function_calls_eh_return
01495
01496 || current_function_calls_alloca
01497
01498
01499 || !(stack_adjust == 0 || (frame_pointer_needed && stack_adjust == 4)))
01500 return 0;
01501
01502 saved_int_regs = arm_compute_save_reg_mask ();
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517 if (stack_adjust == 4 && !arm_arch5)
01518 {
01519
01520
01521 if (!call_used_regs[3])
01522 return 0;
01523
01524
01525 if (arm_size_return_regs () >= (4 * UNITS_PER_WORD))
01526 return 0;
01527
01528
01529 if (sibling)
01530 {
01531 gcc_assert (GET_CODE (sibling) == CALL_INSN);
01532
01533 if (find_regno_fusage (sibling, USE, 3))
01534 return 0;
01535 }
01536
01537
01538
01539 if (saved_int_regs & 0x7)
01540 return 0;
01541 }
01542
01543
01544
01545 if (TARGET_INTERWORK && saved_int_regs != 0)
01546 return 0;
01547
01548
01549
01550 if (iscond && arm_tune_strongarm)
01551 {
01552
01553
01554 if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM))
01555 return 0;
01556
01557 if (flag_pic
01558 && arm_pic_register != INVALID_REGNUM
01559 && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
01560 return 0;
01561 }
01562
01563
01564
01565 if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM)))
01566 return 0;
01567
01568
01569
01570 if (TARGET_HARD_FLOAT && TARGET_FPA)
01571 for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
01572 if (regs_ever_live[regno] && !call_used_regs[regno])
01573 return 0;
01574
01575
01576 if (TARGET_HARD_FLOAT && TARGET_VFP)
01577 for (regno = FIRST_VFP_REGNUM; regno <= LAST_VFP_REGNUM; regno++)
01578 if (regs_ever_live[regno] && !call_used_regs[regno])
01579 return 0;
01580
01581 if (TARGET_REALLY_IWMMXT)
01582 for (regno = FIRST_IWMMXT_REGNUM; regno <= LAST_IWMMXT_REGNUM; regno++)
01583 if (regs_ever_live[regno] && ! call_used_regs [regno])
01584 return 0;
01585
01586 return 1;
01587 }
01588
01589
01590
01591 int
01592 const_ok_for_arm (HOST_WIDE_INT i)
01593 {
01594 int lowbit;
01595
01596
01597
01598 if ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff) != 0
01599 && ((i & ~(unsigned HOST_WIDE_INT) 0xffffffff)
01600 != ((~(unsigned HOST_WIDE_INT) 0)
01601 & ~(unsigned HOST_WIDE_INT) 0xffffffff)))
01602 return FALSE;
01603
01604 i &= (unsigned HOST_WIDE_INT) 0xffffffff;
01605
01606
01607
01608 if ((i & ~(unsigned HOST_WIDE_INT) 0xff) == 0)
01609 return TRUE;
01610
01611
01612
01613 lowbit = (ffs ((int) i) - 1) & ~1;
01614
01615 if ((i & ~(((unsigned HOST_WIDE_INT) 0xff) << lowbit)) == 0)
01616 return TRUE;
01617 else if (lowbit <= 4
01618 && ((i & ~0xc000003f) == 0
01619 || (i & ~0xf000000f) == 0
01620 || (i & ~0xfc000003) == 0))
01621 return TRUE;
01622
01623 return FALSE;
01624 }
01625
01626
01627 static int
01628 const_ok_for_op (HOST_WIDE_INT i, enum rtx_code code)
01629 {
01630 if (const_ok_for_arm (i))
01631 return 1;
01632
01633 switch (code)
01634 {
01635 case PLUS:
01636 return const_ok_for_arm (ARM_SIGN_EXTEND (-i));
01637
01638 case MINUS:
01639 case XOR:
01640 case IOR:
01641 return 0;
01642
01643 case AND:
01644 return const_ok_for_arm (ARM_SIGN_EXTEND (~i));
01645
01646 default:
01647 gcc_unreachable ();
01648 }
01649 }
01650
01651
01652
01653
01654
01655
01656
01657
01658
01659
01660
01661 int
01662 arm_split_constant (enum rtx_code code, enum machine_mode mode, rtx insn,
01663 HOST_WIDE_INT val, rtx target, rtx source, int subtargets)
01664 {
01665 rtx cond;
01666
01667 if (insn && GET_CODE (PATTERN (insn)) == COND_EXEC)
01668 cond = COND_EXEC_TEST (PATTERN (insn));
01669 else
01670 cond = NULL_RTX;
01671
01672 if (subtargets || code == SET
01673 || (GET_CODE (target) == REG && GET_CODE (source) == REG
01674 && REGNO (target) != REGNO (source)))
01675 {
01676
01677
01678
01679
01680
01681
01682
01683
01684
01685 if (!after_arm_reorg
01686 && !cond
01687 && (arm_gen_constant (code, mode, NULL_RTX, val, target, source,
01688 1, 0)
01689 > arm_constant_limit + (code != SET)))
01690 {
01691 if (code == SET)
01692 {
01693
01694
01695 emit_set_insn (target, GEN_INT (val));
01696 return 1;
01697 }
01698 else
01699 {
01700 rtx temp = subtargets ? gen_reg_rtx (mode) : target;
01701
01702 emit_set_insn (temp, GEN_INT (val));
01703
01704
01705 if (code == MINUS)
01706 emit_set_insn (target, gen_rtx_MINUS (mode, temp, source));
01707 else
01708 emit_set_insn (target,
01709 gen_rtx_fmt_ee (code, mode, source, temp));
01710 return 2;
01711 }
01712 }
01713 }
01714
01715 return arm_gen_constant (code, mode, cond, val, target, source, subtargets,
01716 1);
01717 }
01718
01719 static int
01720 count_insns_for_constant (HOST_WIDE_INT remainder, int i)
01721 {
01722 HOST_WIDE_INT temp1;
01723 int num_insns = 0;
01724 do
01725 {
01726 int end;
01727
01728 if (i <= 0)
01729 i += 32;
01730 if (remainder & (3 << (i - 2)))
01731 {
01732 end = i - 8;
01733 if (end < 0)
01734 end += 32;
01735 temp1 = remainder & ((0x0ff << end)
01736 | ((i < end) ? (0xff >> (32 - end)) : 0));
01737 remainder &= ~temp1;
01738 num_insns++;
01739 i -= 6;
01740 }
01741 i -= 2;
01742 } while (remainder);
01743 return num_insns;
01744 }
01745
01746
01747
01748
01749
01750 static void
01751 emit_constant_insn (rtx cond, rtx pattern)
01752 {
01753 if (cond)
01754 pattern = gen_rtx_COND_EXEC (VOIDmode, copy_rtx (cond), pattern);
01755 emit_insn (pattern);
01756 }
01757
01758
01759
01760
01761 static int
01762 arm_gen_constant (enum rtx_code code, enum machine_mode mode, rtx cond,
01763 HOST_WIDE_INT val, rtx target, rtx source, int subtargets,
01764 int generate)
01765 {
01766 int can_invert = 0;
01767 int can_negate = 0;
01768 int can_negate_initial = 0;
01769 int can_shift = 0;
01770 int i;
01771 int num_bits_set = 0;
01772 int set_sign_bit_copies = 0;
01773 int clear_sign_bit_copies = 0;
01774 int clear_zero_bit_copies = 0;
01775 int set_zero_bit_copies = 0;
01776 int insns = 0;
01777 unsigned HOST_WIDE_INT temp1, temp2;
01778 unsigned HOST_WIDE_INT remainder = val & 0xffffffff;
01779
01780
01781
01782
01783 switch (code)
01784 {
01785 case SET:
01786 can_invert = 1;
01787 can_shift = 1;
01788 can_negate = 1;
01789 break;
01790
01791 case PLUS:
01792 can_negate = 1;
01793 can_negate_initial = 1;
01794 break;
01795
01796 case IOR:
01797 if (remainder == 0xffffffff)
01798 {
01799 if (generate)
01800 emit_constant_insn (cond,
01801 gen_rtx_SET (VOIDmode, target,
01802 GEN_INT (ARM_SIGN_EXTEND (val))));
01803 return 1;
01804 }
01805 if (remainder == 0)
01806 {
01807 if (reload_completed && rtx_equal_p (target, source))
01808 return 0;
01809 if (generate)
01810 emit_constant_insn (cond,
01811 gen_rtx_SET (VOIDmode, target, source));
01812 return 1;
01813 }
01814 break;
01815
01816 case AND:
01817 if (remainder == 0)
01818 {
01819 if (generate)
01820 emit_constant_insn (cond,
01821 gen_rtx_SET (VOIDmode, target, const0_rtx));
01822 return 1;
01823 }
01824 if (remainder == 0xffffffff)
01825 {
01826 if (reload_completed && rtx_equal_p (target, source))
01827 return 0;
01828 if (generate)
01829 emit_constant_insn (cond,
01830 gen_rtx_SET (VOIDmode, target, source));
01831 return 1;
01832 }
01833 can_invert = 1;
01834 break;
01835
01836 case XOR:
01837 if (remainder == 0)
01838 {
01839 if (reload_completed && rtx_equal_p (target, source))
01840 return 0;
01841 if (generate)
01842 emit_constant_insn (cond,
01843 gen_rtx_SET (VOIDmode, target, source));
01844 return 1;
01845 }
01846
01847
01848 gcc_assert (remainder == 0xffffffff);
01849
01850 if (generate)
01851 emit_constant_insn (cond,
01852 gen_rtx_SET (VOIDmode, target,
01853 gen_rtx_NOT (mode, source)));
01854 return 1;
01855
01856 case MINUS:
01857
01858
01859 if (remainder == 0)
01860 {
01861 if (generate)
01862 emit_constant_insn (cond,
01863 gen_rtx_SET (VOIDmode, target,
01864 gen_rtx_NEG (mode, source)));
01865 return 1;
01866 }
01867 if (const_ok_for_arm (val))
01868 {
01869 if (generate)
01870 emit_constant_insn (cond,
01871 gen_rtx_SET (VOIDmode, target,
01872 gen_rtx_MINUS (mode, GEN_INT (val),
01873 source)));
01874 return 1;
01875 }
01876 can_negate = 1;
01877
01878 break;
01879
01880 default:
01881 gcc_unreachable ();
01882 }
01883
01884
01885 if (const_ok_for_arm (val)
01886 || (can_negate_initial && const_ok_for_arm (-val))
01887 || (can_invert && const_ok_for_arm (~val)))
01888 {
01889 if (generate)
01890 emit_constant_insn (cond,
01891 gen_rtx_SET (VOIDmode, target,
01892 (source
01893 ? gen_rtx_fmt_ee (code, mode, source,
01894 GEN_INT (val))
01895 : GEN_INT (val))));
01896 return 1;
01897 }
01898
01899
01900
01901 for (i = 31; i >= 0; i--)
01902 {
01903 if ((remainder & (1 << i)) == 0)
01904 clear_sign_bit_copies++;
01905 else
01906 break;
01907 }
01908
01909 for (i = 31; i >= 0; i--)
01910 {
01911 if ((remainder & (1 << i)) != 0)
01912 set_sign_bit_copies++;
01913 else
01914 break;
01915 }
01916
01917 for (i = 0; i <= 31; i++)
01918 {
01919 if ((remainder & (1 << i)) == 0)
01920 clear_zero_bit_copies++;
01921 else
01922 break;
01923 }
01924
01925 for (i = 0; i <= 31; i++)
01926 {
01927 if ((remainder & (1 << i)) != 0)
01928 set_zero_bit_copies++;
01929 else
01930 break;
01931 }
01932
01933 switch (code)
01934 {
01935 case SET:
01936
01937
01938
01939 if (set_sign_bit_copies > 1)
01940 {
01941 if (const_ok_for_arm
01942 (temp1 = ARM_SIGN_EXTEND (remainder
01943 << (set_sign_bit_copies - 1))))
01944 {
01945 if (generate)
01946 {
01947 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01948 emit_constant_insn (cond,
01949 gen_rtx_SET (VOIDmode, new_src,
01950 GEN_INT (temp1)));
01951 emit_constant_insn (cond,
01952 gen_ashrsi3 (target, new_src,
01953 GEN_INT (set_sign_bit_copies - 1)));
01954 }
01955 return 2;
01956 }
01957
01958
01959 temp1 |= (1 << (set_sign_bit_copies - 1)) - 1;
01960 if (const_ok_for_arm (~temp1))
01961 {
01962 if (generate)
01963 {
01964 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01965 emit_constant_insn (cond,
01966 gen_rtx_SET (VOIDmode, new_src,
01967 GEN_INT (temp1)));
01968 emit_constant_insn (cond,
01969 gen_ashrsi3 (target, new_src,
01970 GEN_INT (set_sign_bit_copies - 1)));
01971 }
01972 return 2;
01973 }
01974 }
01975
01976
01977
01978 if (clear_sign_bit_copies + clear_zero_bit_copies <= 16)
01979 {
01980 int topshift = clear_sign_bit_copies & ~1;
01981
01982 temp1 = ARM_SIGN_EXTEND ((remainder + (0x00800000 >> topshift))
01983 & (0xff000000 >> topshift));
01984
01985
01986
01987
01988
01989 if (temp1 == 0 && topshift != 0)
01990 temp1 = 0x80000000 >> (topshift - 1);
01991
01992 temp2 = ARM_SIGN_EXTEND (temp1 - remainder);
01993
01994 if (const_ok_for_arm (temp2))
01995 {
01996 if (generate)
01997 {
01998 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
01999 emit_constant_insn (cond,
02000 gen_rtx_SET (VOIDmode, new_src,
02001 GEN_INT (temp1)));
02002 emit_constant_insn (cond,
02003 gen_addsi3 (target, new_src,
02004 GEN_INT (-temp2)));
02005 }
02006
02007 return 2;
02008 }
02009 }
02010
02011
02012
02013
02014
02015
02016 if (val & 0xffff0000)
02017 {
02018 temp1 = remainder & 0xffff0000;
02019 temp2 = remainder & 0x0000ffff;
02020
02021
02022 for (i = 9; i < 24; i++)
02023 {
02024 if ((((temp2 | (temp2 << i)) & 0xffffffff) == remainder)
02025 && !const_ok_for_arm (temp2))
02026 {
02027 rtx new_src = (subtargets
02028 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
02029 : target);
02030 insns = arm_gen_constant (code, mode, cond, temp2, new_src,
02031 source, subtargets, generate);
02032 source = new_src;
02033 if (generate)
02034 emit_constant_insn
02035 (cond,
02036 gen_rtx_SET
02037 (VOIDmode, target,
02038 gen_rtx_IOR (mode,
02039 gen_rtx_ASHIFT (mode, source,
02040 GEN_INT (i)),
02041 source)));
02042 return insns + 1;
02043 }
02044 }
02045
02046
02047 for (i = 17; i < 24; i++)
02048 {
02049 if (((temp1 | (temp1 >> i)) == remainder)
02050 && !const_ok_for_arm (temp1))
02051 {
02052 rtx new_src = (subtargets
02053 ? (generate ? gen_reg_rtx (mode) : NULL_RTX)
02054 : target);
02055 insns = arm_gen_constant (code, mode, cond, temp1, new_src,
02056 source, subtargets, generate);
02057 source = new_src;
02058 if (generate)
02059 emit_constant_insn
02060 (cond,
02061 gen_rtx_SET (VOIDmode, target,
02062 gen_rtx_IOR
02063 (mode,
02064 gen_rtx_LSHIFTRT (mode, source,
02065 GEN_INT (i)),
02066 source)));
02067 return insns + 1;
02068 }
02069 }
02070 }
02071 break;
02072
02073 case IOR:
02074 case XOR:
02075
02076
02077
02078 if (subtargets
02079
02080 || (reload_completed && !reg_mentioned_p (target, source)))
02081 {
02082 if (const_ok_for_arm (ARM_SIGN_EXTEND (~val)))
02083 {
02084 if (generate)
02085 {
02086 rtx sub = subtargets ? gen_reg_rtx (mode) : target;
02087
02088 emit_constant_insn (cond,
02089 gen_rtx_SET (VOIDmode, sub,
02090 GEN_INT (val)));
02091 emit_constant_insn (cond,
02092 gen_rtx_SET (VOIDmode, target,
02093 gen_rtx_fmt_ee (code, mode,
02094 source, sub)));
02095 }
02096 return 2;
02097 }
02098 }
02099
02100 if (code == XOR)
02101 break;
02102
02103 if (set_sign_bit_copies > 8
02104 && (val & (-1 << (32 - set_sign_bit_copies))) == val)
02105 {
02106 if (generate)
02107 {
02108 rtx sub = subtargets ? gen_reg_rtx (mode) : target;
02109 rtx shift = GEN_INT (set_sign_bit_copies);
02110
02111 emit_constant_insn
02112 (cond,
02113 gen_rtx_SET (VOIDmode, sub,
02114 gen_rtx_NOT (mode,
02115 gen_rtx_ASHIFT (mode,
02116 source,
02117 shift))));
02118 emit_constant_insn
02119 (cond,
02120 gen_rtx_SET (VOIDmode, target,
02121 gen_rtx_NOT (mode,
02122 gen_rtx_LSHIFTRT (mode, sub,
02123 shift))));
02124 }
02125 return 2;
02126 }
02127
02128 if (set_zero_bit_copies > 8
02129 && (remainder & ((1 << set_zero_bit_copies) - 1)) == remainder)
02130 {
02131 if (generate)
02132 {
02133 rtx sub = subtargets ? gen_reg_rtx (mode) : target;
02134 rtx shift = GEN_INT (set_zero_bit_copies);
02135
02136 emit_constant_insn
02137 (cond,
02138 gen_rtx_SET (VOIDmode, sub,
02139 gen_rtx_NOT (mode,
02140 gen_rtx_LSHIFTRT (mode,
02141 source,
02142 shift))));
02143 emit_constant_insn
02144 (cond,
02145 gen_rtx_SET (VOIDmode, target,
02146 gen_rtx_NOT (mode,
02147 gen_rtx_ASHIFT (mode, sub,
02148 shift))));
02149 }
02150 return 2;
02151 }
02152
02153 if (const_ok_for_arm (temp1 = ARM_SIGN_EXTEND (~val)))
02154 {
02155 if (generate)
02156 {
02157 rtx sub = subtargets ? gen_reg_rtx (mode) : target;
02158 emit_constant_insn (cond,
02159 gen_rtx_SET (VOIDmode, sub,
02160 gen_rtx_NOT (mode, source)));
02161 source = sub;
02162 if (subtargets)
02163 sub = gen_reg_rtx (mode);
02164 emit_constant_insn (cond,
02165 gen_rtx_SET (VOIDmode, sub,
02166 gen_rtx_AND (mode, source,
02167 GEN_INT (temp1))));
02168 emit_constant_insn (cond,
02169 gen_rtx_SET (VOIDmode, target,
02170 gen_rtx_NOT (mode, sub)));
02171 }
02172 return 3;
02173 }
02174 break;
02175
02176 case AND:
02177
02178 if (clear_sign_bit_copies >= 16 && clear_sign_bit_copies < 24)
02179 {
02180 HOST_WIDE_INT shift_mask = ((0xffffffff
02181 << (32 - clear_sign_bit_copies))
02182 & 0xffffffff);
02183
02184 if ((remainder | shift_mask) != 0xffffffff)
02185 {
02186 if (generate)
02187 {
02188 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
02189 insns = arm_gen_constant (AND, mode, cond,
02190 remainder | shift_mask,
02191 new_src, source, subtargets, 1);
02192 source = new_src;
02193 }
02194 else
02195 {
02196 rtx targ = subtargets ? NULL_RTX : target;
02197 insns = arm_gen_constant (AND, mode, cond,
02198 remainder | shift_mask,
02199 targ, source, subtargets, 0);
02200 }
02201 }
02202
02203 if (generate)
02204 {
02205 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
02206 rtx shift = GEN_INT (clear_sign_bit_copies);
02207
02208 emit_insn (gen_ashlsi3 (new_src, source, shift));
02209 emit_insn (gen_lshrsi3 (target, new_src, shift));
02210 }
02211
02212 return insns + 2;
02213 }
02214
02215 if (clear_zero_bit_copies >= 16 && clear_zero_bit_copies < 24)
02216 {
02217 HOST_WIDE_INT shift_mask = (1 << clear_zero_bit_copies) - 1;
02218
02219 if ((remainder | shift_mask) != 0xffffffff)
02220 {
02221 if (generate)
02222 {
02223 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
02224
02225 insns = arm_gen_constant (AND, mode, cond,
02226 remainder | shift_mask,
02227 new_src, source, subtargets, 1);
02228 source = new_src;
02229 }
02230 else
02231 {
02232 rtx targ = subtargets ? NULL_RTX : target;
02233
02234 insns = arm_gen_constant (AND, mode, cond,
02235 remainder | shift_mask,
02236 targ, source, subtargets, 0);
02237 }
02238 }
02239
02240 if (generate)
02241 {
02242 rtx new_src = subtargets ? gen_reg_rtx (mode) : target;
02243 rtx shift = GEN_INT (clear_zero_bit_copies);
02244
02245 emit_insn (gen_lshrsi3 (new_src, source, shift));
02246 emit_insn (gen_ashlsi3 (target, new_src, shift));
02247 }
02248
02249 return insns + 2;
02250 }
02251
02252 break;
02253
02254 default:
02255 break;
02256 }
02257
02258 for (i = 0; i < 32; i++)
02259 if (remainder & (1 << i))
02260 num_bits_set++;
02261
02262 if (code == AND || (can_invert && num_bits_set > 16))
02263 remainder = (~remainder) & 0xffffffff;
02264 else if (code == PLUS && num_bits_set > 16)
02265 remainder = (-remainder) & 0xffffffff;
02266 else
02267 {
02268 can_invert = 0;
02269 can_negate = 0;
02270 }
02271
02272
02273
02274
02275
02276
02277
02278 {
02279 int best_start = 0;
02280 int best_consecutive_zeros = 0;
02281
02282 for (i = 0; i < 32; i += 2)
02283 {
02284 int consecutive_zeros = 0;
02285
02286 if (!(remainder & (3 << i)))
02287 {
02288 while ((i < 32) && !(remainder & (3 << i)))
02289 {
02290 consecutive_zeros += 2;
02291 i += 2;
02292 }
02293 if (consecutive_zeros > best_consecutive_zeros)
02294 {
02295 best_consecutive_zeros = consecutive_zeros;
02296 best_start = i - consecutive_zeros;
02297 }
02298 i -= 2;
02299 }
02300 }
02301
02302
02303
02304
02305
02306
02307
02308
02309
02310
02311
02312
02313
02314
02315
02316
02317
02318
02319
02320
02321
02322
02323
02324
02325 if (best_start != 0
02326 && ((((unsigned HOST_WIDE_INT) 1) << best_start) < remainder)
02327 && (count_insns_for_constant (remainder, 0) <=
02328 count_insns_for_constant (remainder, best_start)))
02329 best_start = 0;
02330
02331
02332 i = best_start;
02333 do
02334 {
02335 int end;
02336
02337 if (i <= 0)
02338 i += 32;
02339 if (remainder & (3 << (i - 2)))
02340 {
02341 end = i - 8;
02342 if (end < 0)
02343 end += 32;
02344 temp1 = remainder & ((0x0ff << end)
02345 | ((i < end) ? (0xff >> (32 - end)) : 0));
02346 remainder &= ~temp1;
02347
02348 if (generate)
02349 {
02350 rtx new_src, temp1_rtx;
02351
02352 if (code == SET || code == MINUS)
02353 {
02354 new_src = (subtargets ? gen_reg_rtx (mode) : target);
02355 if (can_invert && code != MINUS)
02356 temp1 = ~temp1;
02357 }
02358 else
02359 {
02360 if (remainder && subtargets)
02361 new_src = gen_reg_rtx (mode);
02362 else
02363 new_src = target;
02364 if (can_invert)
02365 temp1 = ~temp1;
02366 else if (can_negate)
02367 temp1 = -temp1;
02368 }
02369
02370 temp1 = trunc_int_for_mode (temp1, mode);
02371 temp1_rtx = GEN_INT (temp1);
02372
02373 if (code == SET)
02374 ;
02375 else if (code == MINUS)
02376 temp1_rtx = gen_rtx_MINUS (mode, temp1_rtx, source);
02377 else
02378 temp1_rtx = gen_rtx_fmt_ee (code, mode, source, temp1_rtx);
02379
02380 emit_constant_insn (cond,
02381 gen_rtx_SET (VOIDmode, new_src,
02382 temp1_rtx));
02383 source = new_src;
02384 }
02385
02386 if (code == SET)
02387 {
02388 can_invert = 0;
02389 code = PLUS;
02390 }
02391 else if (code == MINUS)
02392 code = PLUS;
02393
02394 insns++;
02395 i -= 6;
02396 }
02397 i -= 2;
02398 }
02399 while (remainder);
02400 }
02401
02402 return insns;
02403 }
02404
02405
02406
02407
02408
02409 enum rtx_code
02410 arm_canonicalize_comparison (enum rtx_code code, enum machine_mode mode,
02411 rtx * op1)
02412 {
02413 unsigned HOST_WIDE_INT i = INTVAL (*op1);
02414 unsigned HOST_WIDE_INT maxval;
02415 maxval = (((unsigned HOST_WIDE_INT) 1) << (GET_MODE_BITSIZE(mode) - 1)) - 1;
02416
02417 switch (code)
02418 {
02419 case EQ:
02420 case NE:
02421 return code;
02422
02423 case GT:
02424 case LE:
02425 if (i != maxval
02426 && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
02427 {
02428 *op1 = GEN_INT (i + 1);
02429 return code == GT ? GE : LT;
02430 }
02431 break;
02432
02433 case GE:
02434 case LT:
02435 if (i != ~maxval
02436 && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
02437 {
02438 *op1 = GEN_INT (i - 1);
02439 return code == GE ? GT : LE;
02440 }
02441 break;
02442
02443 case GTU:
02444 case LEU:
02445 if (i != ~((unsigned HOST_WIDE_INT) 0)
02446 && (const_ok_for_arm (i + 1) || const_ok_for_arm (-(i + 1))))
02447 {
02448 *op1 = GEN_INT (i + 1);
02449 return code == GTU ? GEU : LTU;
02450 }
02451 break;
02452
02453 case GEU:
02454 case LTU:
02455 if (i != 0
02456 && (const_ok_for_arm (i - 1) || const_ok_for_arm (-(i - 1))))
02457 {
02458 *op1 = GEN_INT (i - 1);
02459 return code == GEU ? GTU : LEU;
02460 }
02461 break;
02462
02463 default:
02464 gcc_unreachable ();
02465 }
02466
02467 return code;
02468 }
02469
02470
02471
02472
02473 rtx
02474 arm_function_value(tree type, tree func ATTRIBUTE_UNUSED)
02475 {
02476 enum machine_mode mode;
02477 int unsignedp ATTRIBUTE_UNUSED;
02478 rtx r ATTRIBUTE_UNUSED;
02479
02480 mode = TYPE_MODE (type);
02481
02482 if (INTEGRAL_TYPE_P (type))
02483 PROMOTE_FUNCTION_MODE (mode, unsignedp, type);
02484
02485
02486
02487 if (arm_return_in_msb (type))
02488 {
02489 HOST_WIDE_INT size = int_size_in_bytes (type);
02490 if (size % UNITS_PER_WORD != 0)
02491 {
02492 size += UNITS_PER_WORD - size % UNITS_PER_WORD;
02493 mode = mode_for_size (size * BITS_PER_UNIT, MODE_INT, 0);
02494 }
02495 }
02496
02497 return LIBCALL_VALUE(mode);
02498 }
02499
02500
02501
02502 int
02503 arm_apply_result_size (void)
02504 {
02505 int size = 16;
02506
02507 if (TARGET_ARM)
02508 {
02509 if (TARGET_HARD_FLOAT_ABI)
02510 {
02511 if (TARGET_FPA)
02512 size += 12;
02513 if (TARGET_MAVERICK)
02514 size += 8;
02515 }
02516 if (TARGET_IWMMXT_ABI)
02517 size += 8;
02518 }
02519
02520 return size;
02521 }
02522
02523
02524
02525
02526 int
02527 arm_return_in_memory (tree type)
02528 {
02529 HOST_WIDE_INT size;
02530
02531 if (!AGGREGATE_TYPE_P (type) &&
02532 (TREE_CODE (type) != VECTOR_TYPE) &&
02533 !(TARGET_AAPCS_BASED && TREE_CODE (type) == COMPLEX_TYPE))
02534
02535
02536 return 0;
02537
02538 size = int_size_in_bytes (type);
02539
02540 if (arm_abi != ARM_ABI_APCS)
02541 {
02542
02543
02544 return (size < 0 || size > UNITS_PER_WORD);
02545 }
02546
02547
02548
02549 if (TREE_CODE (type) == VECTOR_TYPE)
02550 return (size < 0 || size > (4 * UNITS_PER_WORD));
02551
02552
02553
02554 #ifndef ARM_WINCE
02555
02556
02557
02558
02559 if (size < 0 || size > UNITS_PER_WORD)
02560 return 1;
02561
02562 if (TREE_CODE (type) == RECORD_TYPE)
02563 {
02564 tree field;
02565
02566
02567
02568
02569
02570
02571
02572
02573
02574 for (field = TYPE_FIELDS (type);
02575 field && TREE_CODE (field) != FIELD_DECL;
02576 field = TREE_CHAIN (field))
02577 continue;
02578
02579 if (field == NULL)
02580 return 0;
02581
02582
02583
02584
02585 if (FLOAT_TYPE_P (TREE_TYPE (field)))
02586 return 1;
02587
02588
02589
02590 if (RETURN_IN_MEMORY (TREE_TYPE (field)))
02591 return 1;
02592
02593
02594
02595 for (field = TREE_CHAIN (field);
02596 field;
02597 field = TREE_CHAIN (field))
02598 {
02599 if (TREE_CODE (field) != FIELD_DECL)
02600 continue;
02601
02602 if (!DECL_BIT_FIELD_TYPE (field))
02603 return 1;
02604 }
02605
02606 return 0;
02607 }
02608
02609 if (TREE_CODE (type) == UNION_TYPE)
02610 {
02611 tree field;
02612
02613
02614
02615 for (field = TYPE_FIELDS (type);
02616 field;
02617 field = TREE_CHAIN (field))
02618 {
02619 if (TREE_CODE (field) != FIELD_DECL)
02620 continue;
02621
02622 if (FLOAT_TYPE_P (TREE_TYPE (field)))
02623 return 1;
02624
02625 if (RETURN_IN_MEMORY (TREE_TYPE (field)))
02626 return 1;
02627 }
02628
02629 return 0;
02630 }
02631 #endif
02632
02633
02634 return 1;
02635 }
02636
02637
02638
02639 int
02640 arm_float_words_big_endian (void)
02641 {
02642 if (TARGET_MAVERICK)
02643 return 0;
02644
02645
02646
02647
02648 if (TARGET_FPA)
02649 {
02650 return 1;
02651 }
02652
02653 if (TARGET_VFP)
02654 return (TARGET_BIG_END ? 1 : 0);
02655
02656 return 1;
02657 }
02658
02659
02660
02661
02662 void
02663 arm_init_cumulative_args (CUMULATIVE_ARGS *pcum, tree fntype,
02664 rtx libname ATTRIBUTE_UNUSED,
02665 tree fndecl ATTRIBUTE_UNUSED)
02666 {
02667
02668 pcum->nregs = 0;
02669 pcum->iwmmxt_nregs = 0;
02670 pcum->can_split = true;
02671
02672 pcum->call_cookie = CALL_NORMAL;
02673
02674 if (TARGET_LONG_CALLS)
02675 pcum->call_cookie = CALL_LONG;
02676
02677
02678
02679 if (fntype)
02680 {
02681 if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (fntype)))
02682 pcum->call_cookie = CALL_SHORT;
02683 else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (fntype)))
02684 pcum->call_cookie = CALL_LONG;
02685 }
02686
02687
02688
02689 pcum->named_count = 0;
02690 pcum->nargs = 0;
02691
02692 if (TARGET_REALLY_IWMMXT && fntype)
02693 {
02694 tree fn_arg;
02695
02696 for (fn_arg = TYPE_ARG_TYPES (fntype);
02697 fn_arg;
02698 fn_arg = TREE_CHAIN (fn_arg))
02699 pcum->named_count += 1;
02700
02701 if (! pcum->named_count)
02702 pcum->named_count = INT_MAX;
02703 }
02704 }
02705
02706
02707
02708 bool
02709 arm_needs_doubleword_align (enum machine_mode mode, tree type)
02710 {
02711 return (GET_MODE_ALIGNMENT (mode) > PARM_BOUNDARY
02712 || (type && TYPE_ALIGN (type) > PARM_BOUNDARY));
02713 }
02714
02715
02716
02717
02718
02719
02720
02721
02722
02723
02724
02725
02726
02727
02728
02729 rtx
02730 arm_function_arg (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
02731 tree type, int named)
02732 {
02733 int nregs;
02734
02735
02736
02737 if (TARGET_IWMMXT_ABI
02738 && arm_vector_mode_supported_p (mode)
02739 && pcum->named_count > pcum->nargs + 1)
02740 {
02741 if (pcum->iwmmxt_nregs <= 9)
02742 return gen_rtx_REG (mode, pcum->iwmmxt_nregs + FIRST_IWMMXT_REGNUM);
02743 else
02744 {
02745 pcum->can_split = false;
02746 return NULL_RTX;
02747 }
02748 }
02749
02750
02751 if (pcum->nregs & 1
02752 && ARM_DOUBLEWORD_ALIGN
02753 && arm_needs_doubleword_align (mode, type))
02754 pcum->nregs++;
02755
02756 if (mode == VOIDmode)
02757
02758 return GEN_INT (pcum->call_cookie);
02759
02760
02761
02762
02763 if (pcum->can_split)
02764 nregs = 1;
02765 else
02766 nregs = ARM_NUM_REGS2 (mode, type);
02767
02768 if (!named || pcum->nregs + nregs > NUM_ARG_REGS)
02769 return NULL_RTX;
02770
02771 return gen_rtx_REG (mode, pcum->nregs);
02772 }
02773
02774 static int
02775 arm_arg_partial_bytes (CUMULATIVE_ARGS *pcum, enum machine_mode mode,
02776 tree type, bool named ATTRIBUTE_UNUSED)
02777 {
02778 int nregs = pcum->nregs;
02779
02780 if (arm_vector_mode_supported_p (mode))
02781 return 0;
02782
02783 if (NUM_ARG_REGS > nregs
02784 && (NUM_ARG_REGS < nregs + ARM_NUM_REGS2 (mode, type))
02785 && pcum->can_split)
02786 return (NUM_ARG_REGS - nregs) * UNITS_PER_WORD;
02787
02788 return 0;
02789 }
02790
02791
02792
02793
02794 static bool
02795 arm_pass_by_reference (CUMULATIVE_ARGS *cum ATTRIBUTE_UNUSED,
02796 enum machine_mode mode ATTRIBUTE_UNUSED,
02797 tree type, bool named ATTRIBUTE_UNUSED)
02798 {
02799 return type && TREE_CODE (TYPE_SIZE (type)) != INTEGER_CST;
02800 }
02801
02802
02803 typedef enum
02804 {
02805 OFF,
02806 LONG,
02807 SHORT
02808 } arm_pragma_enum;
02809
02810 static arm_pragma_enum arm_pragma_long_calls = OFF;
02811
02812 void
02813 arm_pr_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
02814 {
02815 arm_pragma_long_calls = LONG;
02816 }
02817
02818 void
02819 arm_pr_no_long_calls (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
02820 {
02821 arm_pragma_long_calls = SHORT;
02822 }
02823
02824 void
02825 arm_pr_long_calls_off (struct cpp_reader * pfile ATTRIBUTE_UNUSED)
02826 {
02827 arm_pragma_long_calls = OFF;
02828 }
02829
02830
02831 const struct attribute_spec arm_attribute_table[] =
02832 {
02833
02834
02835
02836
02837 { "long_call", 0, 0, false, true, true, NULL },
02838
02839
02840 { "short_call", 0, 0, false, true, true, NULL },
02841
02842 { "isr", 0, 1, false, false, false, arm_handle_isr_attribute },
02843 { "interrupt", 0, 1, false, false, false, arm_handle_isr_attribute },
02844 { "naked", 0, 0, true, false, false, arm_handle_fndecl_attribute },
02845 #ifdef ARM_PE
02846
02847
02848
02849
02850
02851
02852
02853
02854
02855 { "dllimport", 0, 0, true, false, false, NULL },
02856 { "dllexport", 0, 0, true, false, false, NULL },
02857 { "interfacearm", 0, 0, true, false, false, arm_handle_fndecl_attribute },
02858 #elif TARGET_DLLIMPORT_DECL_ATTRIBUTES
02859 { "dllimport", 0, 0, false, false, false, handle_dll_attribute },
02860 { "dllexport", 0, 0, false, false, false, handle_dll_attribute },
02861 { "notshared", 0, 0, false, true, false, arm_handle_notshared_attribute },
02862 #endif
02863 { NULL, 0, 0, false, false, false, NULL }
02864 };
02865
02866
02867
02868 static tree
02869 arm_handle_fndecl_attribute (tree *node, tree name, tree args ATTRIBUTE_UNUSED,
02870 int flags ATTRIBUTE_UNUSED, bool *no_add_attrs)
02871 {
02872 if (TREE_CODE (*node) != FUNCTION_DECL)
02873 {
02874 warning (OPT_Wattributes, "%qs attribute only applies to functions",
02875 IDENTIFIER_POINTER (name));
02876 *no_add_attrs = true;
02877 }
02878
02879 return NULL_TREE;
02880 }
02881
02882
02883
02884 static tree
02885 arm_handle_isr_attribute (tree *node, tree name, tree args, int flags,
02886 bool *no_add_attrs)
02887 {
02888 if (DECL_P (*node))
02889 {
02890 if (TREE_CODE (*node) != FUNCTION_DECL)
02891 {
02892 warning (OPT_Wattributes, "%qs attribute only applies to functions",
02893 IDENTIFIER_POINTER (name));
02894 *no_add_attrs = true;
02895 }
02896
02897
02898 }
02899 else
02900 {
02901 if (TREE_CODE (*node) == FUNCTION_TYPE
02902 || TREE_CODE (*node) == METHOD_TYPE)
02903 {
02904 if (arm_isr_value (args) == ARM_FT_UNKNOWN)
02905 {
02906 warning (OPT_Wattributes, "%qs attribute ignored",
02907 IDENTIFIER_POINTER (name));
02908 *no_add_attrs = true;
02909 }
02910 }
02911 else if (TREE_CODE (*node) == POINTER_TYPE
02912 && (TREE_CODE (TREE_TYPE (*node)) == FUNCTION_TYPE
02913 || TREE_CODE (TREE_TYPE (*node)) == METHOD_TYPE)
02914 && arm_isr_value (args) != ARM_FT_UNKNOWN)
02915 {
02916 *node = build_variant_type_copy (*node);
02917 TREE_TYPE (*node) = build_type_attribute_variant
02918 (TREE_TYPE (*node),
02919 tree_cons (name, args, TYPE_ATTRIBUTES (TREE_TYPE (*node))));
02920 *no_add_attrs = true;
02921 }
02922 else
02923 {
02924
02925 if (flags & ((int) ATTR_FLAG_DECL_NEXT
02926 | (int) ATTR_FLAG_FUNCTION_NEXT
02927 | (int) ATTR_FLAG_ARRAY_NEXT))
02928 {
02929 *no_add_attrs = true;
02930 return tree_cons (name, args, NULL_TREE);
02931 }
02932 else
02933 {
02934 warning (OPT_Wattributes, "%qs attribute ignored",
02935 IDENTIFIER_POINTER (name));
02936 }
02937 }
02938 }
02939
02940 return NULL_TREE;
02941 }
02942
02943 #if TARGET_DLLIMPORT_DECL_ATTRIBUTES
02944
02945
02946
02947
02948
02949 static tree
02950 arm_handle_notshared_attribute (tree *node,
02951 tree name ATTRIBUTE_UNUSED,
02952 tree args ATTRIBUTE_UNUSED,
02953 int flags ATTRIBUTE_UNUSED,
02954 bool *no_add_attrs)
02955 {
02956 tree decl = TYPE_NAME (*node);
02957
02958 if (decl)
02959 {
02960 DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
02961 DECL_VISIBILITY_SPECIFIED (decl) = 1;
02962 *no_add_attrs = false;
02963 }
02964 return NULL_TREE;
02965 }
02966 #endif
02967
02968
02969
02970
02971 static int
02972 arm_comp_type_attributes (tree type1, tree type2)
02973 {
02974 int l1, l2, s1, s2;
02975
02976
02977 if (TREE_CODE (type1) != FUNCTION_TYPE)
02978 return 1;
02979
02980
02981 l1 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type1)) != NULL;
02982 l2 = lookup_attribute ("long_call", TYPE_ATTRIBUTES (type2)) != NULL;
02983 s1 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type1)) != NULL;
02984 s2 = lookup_attribute ("short_call", TYPE_ATTRIBUTES (type2)) != NULL;
02985
02986
02987 if (l1 | l2 | s1 | s2)
02988 {
02989
02990 if ((l1 != l2) || (s1 != s2))
02991 return 0;
02992
02993
02994 if ((l1 & s2) || (l2 & s1))
02995 return 0;
02996 }
02997
02998
02999 l1 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type1)) != NULL;
03000 if (! l1)
03001 l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type1)) != NULL;
03002 l2 = lookup_attribute ("isr", TYPE_ATTRIBUTES (type2)) != NULL;
03003 if (! l2)
03004 l1 = lookup_attribute ("interrupt", TYPE_ATTRIBUTES (type2)) != NULL;
03005 if (l1 != l2)
03006 return 0;
03007
03008 return 1;
03009 }
03010
03011
03012
03013 void
03014 arm_encode_call_attribute (tree decl, int flag)
03015 {
03016 const char * str = XSTR (XEXP (DECL_RTL (decl), 0), 0);
03017 int len = strlen (str);
03018 char * newstr;
03019
03020
03021 if (DECL_WEAK (decl) && flag == SHORT_CALL_FLAG_CHAR)
03022 return;
03023
03024 newstr = alloca (len + 2);
03025 newstr[0] = flag;
03026 strcpy (newstr + 1, str);
03027
03028 newstr = (char *) ggc_alloc_string (newstr, len + 1);
03029 XSTR (XEXP (DECL_RTL (decl), 0), 0) = newstr;
03030 }
03031
03032
03033
03034
03035 static void
03036 arm_set_default_type_attributes (tree type)
03037 {
03038
03039
03040
03041 if (TREE_CODE (type) == FUNCTION_TYPE || TREE_CODE (type) == METHOD_TYPE)
03042 {
03043 tree type_attr_list, attr_name;
03044 type_attr_list = TYPE_ATTRIBUTES (type);
03045
03046 if (arm_pragma_long_calls == LONG)
03047 attr_name = get_identifier ("long_call");
03048 else if (arm_pragma_long_calls == SHORT)
03049 attr_name = get_identifier ("short_call");
03050 else
03051 return;
03052
03053 type_attr_list = tree_cons (attr_name, NULL_TREE, type_attr_list);
03054 TYPE_ATTRIBUTES (type) = type_attr_list;
03055 }
03056 }
03057
03058
03059
03060
03061 static int
03062 current_file_function_operand (rtx sym_ref)
03063 {
03064
03065
03066
03067 if (ENCODED_SHORT_CALL_ATTR_P (XSTR (sym_ref, 0)))
03068 return 1;
03069
03070
03071
03072
03073 if (sym_ref == XEXP (DECL_RTL (current_function_decl), 0)
03074 && !DECL_WEAK (current_function_decl))
03075 return 1;
03076
03077
03078 return 0;
03079 }
03080
03081
03082
03083
03084
03085
03086
03087
03088
03089
03090
03091
03092
03093
03094
03095
03096
03097
03098
03099
03100
03101
03102
03103
03104
03105 int
03106 arm_is_longcall_p (rtx sym_ref, int call_cookie, int call_symbol)
03107 {
03108 if (!call_symbol)
03109 {
03110 if (GET_CODE (sym_ref) != MEM)
03111 return 0;
03112
03113 sym_ref = XEXP (sym_ref, 0);
03114 }
03115
03116 if (GET_CODE (sym_ref) != SYMBOL_REF)
03117 return 0;
03118
03119 if (call_cookie & CALL_SHORT)
03120 return 0;
03121
03122 if (TARGET_LONG_CALLS)
03123 {
03124 if (flag_function_sections
03125 || DECL_SECTION_NAME (current_function_decl))
03126
03127
03128 return 1;
03129 }
03130
03131 if (current_file_function_operand (sym_ref))
03132 return 0;
03133
03134 return (call_cookie & CALL_LONG)
03135 || ENCODED_LONG_CALL_ATTR_P (XSTR (sym_ref, 0))
03136 || TARGET_LONG_CALLS;
03137 }
03138
03139
03140 static bool
03141 arm_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
03142 {
03143 int call_type = TARGET_LONG_CALLS ? CALL_LONG : CALL_NORMAL;
03144
03145 if (cfun->machine->sibcall_blocked)
03146 return false;
03147
03148
03149
03150 if (decl == NULL || TARGET_THUMB)
03151 return false;
03152
03153
03154 if (lookup_attribute ("short_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
03155 call_type = CALL_SHORT;
03156 else if (lookup_attribute ("long_call", TYPE_ATTRIBUTES (TREE_TYPE (decl))))
03157 call_type = CALL_LONG;
03158
03159
03160
03161
03162 if (call_type == CALL_LONG && (flag_pic || !TREE_ASM_WRITTEN (decl)))
03163 return false;
03164
03165
03166
03167
03168 if (TARGET_INTERWORK && TREE_PUBLIC (decl) && !TREE_ASM_WRITTEN (decl))
03169 return false;
03170
03171
03172 if (IS_INTERRUPT (arm_current_func_type ()))
03173 return false;
03174
03175
03176 return true;
03177 }
03178
03179
03180
03181
03182
03183
03184 int
03185 legitimate_pic_operand_p (rtx x)
03186 {
03187 if (GET_CODE (x) == SYMBOL_REF
03188 || (GET_CODE (x) == CONST
03189 && GET_CODE (XEXP (x, 0)) == PLUS
03190 && GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF))
03191 return 0;
03192
03193 return 1;
03194 }
03195
03196 rtx
03197 legitimize_pic_address (rtx orig, enum machine_mode mode, rtx reg)
03198 {
03199 if (GET_CODE (orig) == SYMBOL_REF
03200 || GET_CODE (orig) == LABEL_REF)
03201 {
03202 #ifndef AOF_ASSEMBLER
03203 rtx pic_ref, address;
03204 #endif
03205 rtx insn;
03206 int subregs = 0;
03207
03208
03209
03210
03211
03212
03213
03214
03215 if (!current_function_uses_pic_offset_table)
03216 {
03217 gcc_assert (!no_new_pseudos);
03218 if (arm_pic_register != INVALID_REGNUM)
03219 {
03220 cfun->machine->pic_reg = gen_rtx_REG (Pmode, arm_pic_register);
03221
03222
03223
03224
03225 if (!ir_type())
03226 current_function_uses_pic_offset_table = 1;
03227 }
03228 else
03229 {
03230 rtx seq;
03231
03232 cfun->machine->pic_reg = gen_reg_rtx (Pmode);
03233
03234
03235
03236
03237 if (!ir_type())
03238 {
03239 current_function_uses_pic_offset_table = 1;
03240 start_sequence ();
03241
03242 arm_load_pic_register (0UL);
03243
03244 seq = get_insns ();
03245 end_sequence ();
03246 emit_insn_after (seq, entry_of_function ());
03247 }
03248 }
03249 }
03250
03251 if (reg == 0)
03252 {
03253 gcc_assert (!no_new_pseudos);
03254 reg = gen_reg_rtx (Pmode);
03255
03256 subregs = 1;
03257 }
03258
03259 #ifdef AOF_ASSEMBLER
03260
03261
03262 insn = emit_insn (gen_pic_load_addr_based (reg, orig));
03263 #else
03264 if (subregs)
03265 address = gen_reg_rtx (Pmode);
03266 else
03267 address = reg;
03268
03269 if (TARGET_ARM)
03270 emit_insn (gen_pic_load_addr_arm (address, orig));
03271 else
03272 emit_insn (gen_pic_load_addr_thumb (address, orig));
03273
03274 if ((GET_CODE (orig) == LABEL_REF
03275 || (GET_CODE (orig) == SYMBOL_REF &&
03276 SYMBOL_REF_LOCAL_P (orig)))
03277 && NEED_GOT_RELOC)
03278 pic_ref = gen_rtx_PLUS (Pmode, cfun->machine->pic_reg, address);
03279 else
03280 {
03281 pic_ref = gen_const_mem (Pmode,
03282 gen_rtx_PLUS (Pmode, cfun->machine->pic_reg,
03283 address));
03284 }
03285
03286 insn = emit_move_insn (reg, pic_ref);
03287 #endif
03288
03289
03290 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_EQUAL, orig,
03291 REG_NOTES (insn));
03292 return reg;
03293 }
03294 else if (GET_CODE (orig) == CONST)
03295 {
03296 rtx base, offset;
03297
03298 if (GET_CODE (XEXP (orig, 0)) == PLUS
03299 && XEXP (XEXP (orig, 0), 0) == cfun->machine->pic_reg)
03300 return orig;
03301
03302 if (GET_CODE (XEXP (orig, 0)) == UNSPEC
03303 && XINT (XEXP (orig, 0), 1) == UNSPEC_TLS)
03304 return orig;
03305
03306 if (reg == 0)
03307 {
03308 gcc_assert (!no_new_pseudos);
03309 reg = gen_reg_rtx (Pmode);
03310 }
03311
03312 gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
03313
03314 base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
03315 offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
03316 base == reg ? 0 : reg);
03317
03318 if (GET_CODE (offset) == CONST_INT)
03319 {
03320
03321
03322 if (!arm_legitimate_index_p (mode, offset, SET, 0))
03323 {
03324 gcc_assert (!no_new_pseudos);
03325 offset = force_reg (Pmode, offset);
03326 }
03327
03328 if (GET_CODE (offset) == CONST_INT)
03329 return plus_constant (base, INTVAL (offset));
03330 }
03331
03332 if (GET_MODE_SIZE (mode) > 4
03333 && (GET_MODE_CLASS (mode) == MODE_INT
03334 || TARGET_SOFT_FLOAT))
03335 {
03336 emit_insn (gen_addsi3 (reg, base, offset));
03337 return reg;
03338 }
03339
03340 return gen_rtx_PLUS (Pmode, base, offset);
03341 }
03342
03343 return orig;
03344 }
03345
03346
03347
03348
03349 static int
03350 thumb_find_work_register (unsigned long pushed_regs_mask)
03351 {
03352 int reg;
03353
03354
03355
03356
03357 for (reg = LAST_ARG_REGNUM; reg >= 0; reg --)
03358 if (!regs_ever_live[reg])
03359 return reg;
03360
03361
03362
03363
03364
03365
03366
03367
03368
03369 if (cfun->machine->uses_anonymous_args
03370 && current_function_pretend_args_size > 0)
03371 return LAST_ARG_REGNUM;
03372
03373
03374
03375
03376
03377
03378
03379
03380
03381
03382
03383
03384
03385 if (! cfun->machine->uses_anonymous_args
03386 && current_function_args_size >= 0
03387 && current_function_args_size <= (LAST_ARG_REGNUM * UNITS_PER_WORD)
03388 && cfun->args_info.nregs < 4)
03389 return LAST_ARG_REGNUM;
03390
03391
03392 for (reg = LAST_LO_REGNUM; reg > LAST_ARG_REGNUM; reg --)
03393 if (pushed_regs_mask & (1 << reg))
03394 return reg;
03395
03396
03397
03398 gcc_unreachable ();
03399 }
03400
03401 static GTY(()) int pic_labelno;
03402
03403
03404
03405
03406 void
03407 arm_load_pic_register (unsigned long saved_regs ATTRIBUTE_UNUSED)
03408 {
03409 #ifndef AOF_ASSEMBLER
03410 rtx l1, labelno, pic_tmp, pic_tmp2, pic_rtx;
03411 rtx global_offset_table;
03412
03413 if (current_function_uses_pic_offset_table == 0 || TARGET_SINGLE_PIC_BASE)
03414 return;
03415
03416 gcc_assert (flag_pic);
03417
03418
03419
03420
03421 labelno = GEN_INT (pic_labelno++);
03422 l1 = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
03423 l1 = gen_rtx_CONST (VOIDmode, l1);
03424
03425 global_offset_table = gen_rtx_SYMBOL_REF (Pmode, "_GLOBAL_OFFSET_TABLE_");
03426
03427
03428 pic_tmp = plus_constant (l1, TARGET_ARM ? 8 : 4);
03429 if (GOT_PCREL)
03430 pic_tmp2 = gen_rtx_CONST (VOIDmode,
03431 gen_rtx_PLUS (Pmode, global_offset_table, pc_rtx));
03432 else
03433 pic_tmp2 = gen_rtx_CONST (VOIDmode, global_offset_table);
03434
03435 pic_rtx = gen_rtx_CONST (Pmode, gen_rtx_MINUS (Pmode, pic_tmp2, pic_tmp));
03436
03437 if (TARGET_ARM)
03438 {
03439 emit_insn (gen_pic_load_addr_arm (cfun->machine->pic_reg, pic_rtx));
03440 emit_insn (gen_pic_add_dot_plus_eight (cfun->machine->pic_reg,
03441 cfun->machine->pic_reg, labelno));
03442 }
03443 else
03444 {
03445 if (arm_pic_register != INVALID_REGNUM
03446 && REGNO (cfun->machine->pic_reg) > LAST_LO_REGNUM)
03447 {
03448
03449
03450 pic_tmp = gen_rtx_REG (SImode,
03451 thumb_find_work_register (saved_regs));
03452 emit_insn (gen_pic_load_addr_thumb (pic_tmp, pic_rtx));
03453 emit_insn (gen_movsi (pic_offset_table_rtx, pic_tmp));
03454 }
03455 else
03456 emit_insn (gen_pic_load_addr_thumb (cfun->machine->pic_reg, pic_rtx));
03457 emit_insn (gen_pic_add_dot_plus_four (cfun->machine->pic_reg,
03458 cfun->machine->pic_reg, labelno));
03459 }
03460
03461
03462
03463 emit_insn (gen_rtx_USE (VOIDmode, cfun->machine->pic_reg));
03464 #endif
03465 }
03466
03467
03468
03469 static int
03470 arm_address_register_rtx_p (rtx x, int strict_p)
03471 {
03472 int regno;
03473
03474 if (GET_CODE (x) != REG)
03475 return 0;
03476
03477 regno = REGNO (x);
03478
03479 if (strict_p)
03480 return ARM_REGNO_OK_FOR_BASE_P (regno);
03481
03482 return (regno <= LAST_ARM_REGNUM
03483 || regno >= FIRST_PSEUDO_REGISTER
03484 || regno == FRAME_POINTER_REGNUM
03485 || regno == ARG_POINTER_REGNUM);
03486 }
03487
03488
03489
03490
03491
03492 static int
03493 pcrel_constant_p (rtx x)
03494 {
03495 if (GET_CODE (x) == MINUS)
03496 return symbol_mentioned_p (XEXP (x, 0)) && label_mentioned_p (XEXP (x, 1));
03497
03498 return FALSE;
03499 }
03500
03501
03502 int
03503 arm_legitimate_address_p (enum machine_mode mode, rtx x, RTX_CODE outer,
03504 int strict_p)
03505 {
03506 bool use_ldrd;
03507 enum rtx_code code = GET_CODE (x);
03508
03509 if (arm_address_register_rtx_p (x, strict_p))
03510 return 1;
03511
03512 use_ldrd = (TARGET_LDRD
03513 && (mode == DImode
03514 || (mode == DFmode && (TARGET_SOFT_FLOAT || TARGET_VFP))));
03515
03516 if (code == POST_INC || code == PRE_DEC
03517 || ((code == PRE_INC || code == POST_DEC)
03518 && (use_ldrd || GET_MODE_SIZE (mode) <= 4)))
03519 return arm_address_register_rtx_p (XEXP (x, 0), strict_p);
03520
03521 else if ((code == POST_MODIFY || code == PRE_MODIFY)
03522 && arm_address_register_rtx_p (XEXP (x, 0), strict_p)
03523 && GET_CODE (XEXP (x, 1)) == PLUS
03524 && rtx_equal_p (XEXP (XEXP (x, 1), 0), XEXP (x, 0)))
03525 {
03526 rtx addend = XEXP (XEXP (x, 1), 1);
03527
03528
03529
03530 if (use_ldrd
03531 && GET_CODE (x) == POST_MODIFY
03532 && GET_CODE (addend) == REG)
03533 return 0;
03534
03535 return ((use_ldrd || GET_MODE_SIZE (mode) <= 4)
03536 && arm_legitimate_index_p (mode, addend, outer, strict_p));
03537 }
03538
03539
03540
03541 else if (reload_completed
03542 && (code == LABEL_REF
03543 || (code == CONST
03544 && GET_CODE (XEXP (x, 0)) == PLUS
03545 && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
03546 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
03547 return 1;
03548
03549 else if (mode == TImode)
03550 return 0;
03551
03552 else if (code == PLUS)
03553 {
03554 rtx xop0 = XEXP (x, 0);
03555 rtx xop1 = XEXP (x, 1);
03556
03557 return ((arm_address_register_rtx_p (xop0, strict_p)
03558 && arm_legitimate_index_p (mode, xop1, outer, strict_p))
03559 || (arm_address_register_rtx_p (xop1, strict_p)
03560 && arm_legitimate_index_p (mode, xop0, outer, strict_p)));
03561 }
03562
03563 #if 0
03564
03565 else if (GET_CODE (x) == MINUS)
03566 {
03567 rtx xop0 = XEXP (x, 0);
03568 rtx xop1 = XEXP (x, 1);
03569
03570 return (arm_address_register_rtx_p (xop0, strict_p)
03571 && arm_legitimate_index_p (mode, xop1, outer, strict_p));
03572 }
03573 #endif
03574
03575 else if (GET_MODE_CLASS (mode) != MODE_FLOAT
03576 && code == SYMBOL_REF
03577 && CONSTANT_POOL_ADDRESS_P (x)
03578 && ! (flag_pic
03579 && symbol_mentioned_p (get_pool_constant (x))
03580 && ! pcrel_constant_p (get_pool_constant (x))))
03581 return 1;
03582
03583 return 0;
03584 }
03585
03586
03587
03588 static int
03589 arm_legitimate_index_p (enum machine_mode mode, rtx index, RTX_CODE outer,
03590 int strict_p)
03591 {
03592 HOST_WIDE_INT range;
03593 enum rtx_code code = GET_CODE (index);
03594
03595
03596 if (TARGET_HARD_FLOAT
03597 && (TARGET_FPA || TARGET_MAVERICK)
03598 && (GET_MODE_CLASS (mode) == MODE_FLOAT
03599 || (TARGET_MAVERICK && mode == DImode)))
03600 return (code == CONST_INT && INTVAL (index) < 1024
03601 && INTVAL (index) > -1024
03602 && (INTVAL (index) & 3) == 0);
03603
03604 if (TARGET_REALLY_IWMMXT && VALID_IWMMXT_REG_MODE (mode))
03605 {
03606
03607
03608 if (!TARGET_LDRD || mode != DImode)
03609 return (code == CONST_INT
03610 && INTVAL (index) < 1024
03611 && INTVAL (index) > -1024
03612 && (INTVAL (index) & 3) == 0);
03613 }
03614
03615 if (arm_address_register_rtx_p (index, strict_p)
03616 && (GET_MODE_SIZE (mode) <= 4))
03617 return 1;
03618
03619 if (mode == DImode || mode == DFmode)
03620 {
03621 if (code == CONST_INT)
03622 {
03623 HOST_WIDE_INT val = INTVAL (index);
03624
03625 if (TARGET_LDRD)
03626 return val > -256 && val < 256;
03627 else
03628 return val > -4096 && val < 4092;
03629 }
03630
03631 return TARGET_LDRD && arm_address_register_rtx_p (index, strict_p);
03632 }
03633
03634 if (GET_MODE_SIZE (mode) <= 4
03635 && ! (arm_arch4
03636 && (mode == HImode
03637 || (mode == QImode && outer == SIGN_EXTEND))))
03638 {
03639 if (code == MULT)
03640 {
03641 rtx xiop0 = XEXP (index, 0);
03642 rtx xiop1 = XEXP (index, 1);
03643
03644 return ((arm_address_register_rtx_p (xiop0, strict_p)
03645 && power_of_two_operand (xiop1, SImode))
03646 || (arm_address_register_rtx_p (xiop1, strict_p)
03647 && power_of_two_operand (xiop0, SImode)));
03648 }
03649 else if (code == LSHIFTRT || code == ASHIFTRT
03650 || code == ASHIFT || code == ROTATERT)
03651 {
03652 rtx op = XEXP (index, 1);
03653
03654 return (arm_address_register_rtx_p (XEXP (index, 0), strict_p)
03655 && GET_CODE (op) == CONST_INT
03656 && INTVAL (op) > 0
03657 && INTVAL (op) <= 31);
03658 }
03659 }
03660
03661
03662
03663 if (arm_arch4)
03664 {
03665 if (mode == HImode || (outer == SIGN_EXTEND && mode == QImode))
03666 range = 256;
03667 else
03668 range = 4096;
03669 }
03670 else
03671 range = (mode == HImode) ? 4095 : 4096;
03672
03673 return (code == CONST_INT
03674 && INTVAL (index) < range
03675 && INTVAL (index) > -range);
03676 }
03677
03678
03679 static int
03680 thumb_base_register_rtx_p (rtx x, enum machine_mode mode, int strict_p)
03681 {
03682 int regno;
03683
03684 if (GET_CODE (x) != REG)
03685 return 0;
03686
03687 regno = REGNO (x);
03688
03689 if (strict_p)
03690 return THUMB_REGNO_MODE_OK_FOR_BASE_P (regno, mode);
03691
03692 return (regno <= LAST_LO_REGNUM
03693 || regno > LAST_VIRTUAL_REGISTER
03694 || regno == FRAME_POINTER_REGNUM
03695 || (GET_MODE_SIZE (mode) >= 4
03696 && (regno == STACK_POINTER_REGNUM
03697 || regno >= FIRST_PSEUDO_REGISTER
03698 || x == hard_frame_pointer_rtx
03699 || x == arg_pointer_rtx)));
03700 }
03701
03702
03703
03704 inline static int
03705 thumb_index_register_rtx_p (rtx x, int strict_p)
03706 {
03707 return thumb_base_register_rtx_p (x, QImode, strict_p);
03708 }
03709
03710
03711
03712
03713
03714
03715
03716
03717
03718
03719
03720
03721
03722
03723
03724
03725
03726
03727 int
03728 thumb_legitimate_address_p (enum machine_mode mode, rtx x, int strict_p)
03729 {
03730
03731 if (GET_MODE_SIZE (mode) < 4
03732 && !(reload_in_progress || reload_completed)
03733 && (reg_mentioned_p (frame_pointer_rtx, x)
03734 || reg_mentioned_p (arg_pointer_rtx, x)
03735 || reg_mentioned_p (virtual_incoming_args_rtx, x)
03736 || reg_mentioned_p (virtual_outgoing_args_rtx, x)
03737 || reg_mentioned_p (virtual_stack_dynamic_rtx, x)
03738 || reg_mentioned_p (virtual_stack_vars_rtx, x)))
03739 return 0;
03740
03741
03742 else if (thumb_base_register_rtx_p (x, mode, strict_p))
03743 return 1;
03744
03745
03746 else if (GET_MODE_SIZE (mode) >= 4 && CONSTANT_P (x)
03747 && GET_CODE (x) == SYMBOL_REF
03748 && CONSTANT_POOL_ADDRESS_P (x) && !flag_pic)
03749 return 1;
03750
03751
03752 else if (GET_MODE_SIZE (mode) >= 4 && reload_completed
03753 && (GET_CODE (x) == LABEL_REF
03754 || (GET_CODE (x) == CONST
03755 && GET_CODE (XEXP (x, 0)) == PLUS
03756 && GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF
03757 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT)))
03758 return 1;
03759
03760
03761 else if (GET_CODE (x) == POST_INC && GET_MODE_SIZE (mode) >= 4
03762 && thumb_index_register_rtx_p (XEXP (x, 0), strict_p))
03763 return 1;
03764
03765 else if (GET_CODE (x) == PLUS)
03766 {
03767
03768
03769
03770
03771 if (GET_MODE_SIZE (mode) <= 4
03772 && XEXP (x, 0) != frame_pointer_rtx
03773 && XEXP (x, 1) != frame_pointer_rtx
03774 && thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
03775 && thumb_index_register_rtx_p (XEXP (x, 1), strict_p))
03776 return 1;
03777
03778
03779 else if ((thumb_index_register_rtx_p (XEXP (x, 0), strict_p)
03780 || XEXP (x, 0) == arg_pointer_rtx)
03781 && GET_CODE (XEXP (x, 1)) == CONST_INT
03782 && thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
03783 return 1;
03784
03785
03786
03787
03788
03789 else if (GET_CODE (XEXP (x, 0)) == REG
03790 && REGNO (XEXP (x, 0)) == STACK_POINTER_REGNUM
03791 && GET_MODE_SIZE (mode) >= 4
03792 && GET_CODE (XEXP (x, 1)) == CONST_INT
03793 && INTVAL (XEXP (x, 1)) >= 0
03794 && INTVAL (XEXP (x, 1)) + GET_MODE_SIZE (mode) <= 1024
03795 && (INTVAL (XEXP (x, 1)) & 3) == 0)
03796 return 1;
03797
03798 else if (GET_CODE (XEXP (x, 0)) == REG
03799 && REGNO (XEXP (x, 0)) == FRAME_POINTER_REGNUM
03800 && GET_MODE_SIZE (mode) >= 4
03801 && GET_CODE (XEXP (x, 1)) == CONST_INT
03802 && (INTVAL (XEXP (x, 1)) & 3) == 0)
03803 return 1;
03804 }
03805
03806 else if (GET_MODE_CLASS (mode) != MODE_FLOAT
03807 && GET_MODE_SIZE (mode) == 4
03808 && GET_CODE (x) == SYMBOL_REF
03809 && CONSTANT_POOL_ADDRESS_P (x)
03810 && ! (flag_pic
03811 && symbol_mentioned_p (get_pool_constant (x))
03812 && ! pcrel_constant_p (get_pool_constant (x))))
03813 return 1;
03814
03815 return 0;
03816 }
03817
03818
03819
03820 int
03821 thumb_legitimate_offset_p (enum machine_mode mode, HOST_WIDE_INT val)
03822 {
03823 switch (GET_MODE_SIZE (mode))
03824 {
03825 case 1:
03826 return val >= 0 && val < 32;
03827
03828 case 2:
03829 return val >= 0 && val < 64 && (val & 1) == 0;
03830
03831 default:
03832 return (val >= 0
03833 && (val + GET_MODE_SIZE (mode)) <= 128
03834 && (val & 3) == 0);
03835 }
03836 }
03837
03838
03839
03840 static GTY(()) rtx tls_get_addr_libfunc;
03841
03842 static rtx
03843 get_tls_get_addr (void)
03844 {
03845 if (!tls_get_addr_libfunc)
03846 tls_get_addr_libfunc = init_one_libfunc ("__tls_get_addr");
03847 return tls_get_addr_libfunc;
03848 }
03849
03850 static rtx
03851 arm_load_tp (rtx target)
03852 {
03853 if (!target)
03854 target = gen_reg_rtx (SImode);
03855
03856 if (TARGET_HARD_TP)
03857 {
03858
03859 emit_insn (gen_load_tp_hard (target));
03860 }
03861 else
03862 {
03863
03864
03865
03866
03867 rtx tmp;
03868
03869 emit_insn (gen_load_tp_soft ());
03870
03871 tmp = gen_rtx_REG (SImode, 0);
03872 emit_move_insn (target, tmp);
03873 }
03874 return target;
03875 }
03876
03877 static rtx
03878 load_tls_operand (rtx x, rtx reg)
03879 {
03880 rtx tmp;
03881
03882 if (reg == NULL_RTX)
03883 reg = gen_reg_rtx (SImode);
03884
03885 tmp = gen_rtx_CONST (SImode, x);
03886
03887 emit_move_insn (reg, tmp);
03888
03889 return reg;
03890 }
03891
03892 static rtx
03893 arm_call_tls_get_addr (rtx x, rtx reg, rtx *valuep, int reloc)
03894 {
03895 rtx insns, label, labelno, sum;
03896
03897 start_sequence ();
03898
03899 labelno = GEN_INT (pic_labelno++);
03900 label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
03901 label = gen_rtx_CONST (VOIDmode, label);
03902
03903 sum = gen_rtx_UNSPEC (Pmode,
03904 gen_rtvec (4, x, GEN_INT (reloc), label,
03905 GEN_INT (TARGET_ARM ? 8 : 4)),
03906 UNSPEC_TLS);
03907 reg = load_tls_operand (sum, reg);
03908
03909 if (TARGET_ARM)
03910 emit_insn (gen_pic_add_dot_plus_eight (reg, reg, labelno));
03911 else
03912 emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
03913
03914 *valuep = emit_library_call_value (get_tls_get_addr (), NULL_RTX, LCT_PURE,
03915 Pmode, 1, reg, Pmode);
03916
03917 insns = get_insns ();
03918 end_sequence ();
03919
03920 return insns;
03921 }
03922
03923 rtx
03924 legitimize_tls_address (rtx x, rtx reg)
03925 {
03926 rtx dest, tp, label, labelno, sum, insns, ret, eqv, addend;
03927 unsigned int model = SYMBOL_REF_TLS_MODEL (x);
03928
03929 switch (model)
03930 {
03931 case TLS_MODEL_GLOBAL_DYNAMIC:
03932 insns = arm_call_tls_get_addr (x, reg, &ret, TLS_GD32);
03933 dest = gen_reg_rtx (Pmode);
03934 emit_libcall_block (insns, dest, ret, x);
03935 return dest;
03936
03937 case TLS_MODEL_LOCAL_DYNAMIC:
03938 insns = arm_call_tls_get_addr (x, reg, &ret, TLS_LDM32);
03939
03940
03941
03942 eqv = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, const1_rtx),
03943 UNSPEC_TLS);
03944 dest = gen_reg_rtx (Pmode);
03945 emit_libcall_block (insns, dest, ret, eqv);
03946
03947
03948 addend = gen_rtx_UNSPEC (Pmode, gen_rtvec (2, x, GEN_INT (TLS_LDO32)),
03949 UNSPEC_TLS);
03950 addend = force_reg (SImode, gen_rtx_CONST (SImode, addend));
03951 return gen_rtx_PLUS (Pmode, dest, addend);
03952
03953 case TLS_MODEL_INITIAL_EXEC:
03954 labelno = GEN_INT (pic_labelno++);
03955 label = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, labelno), UNSPEC_PIC_LABEL);
03956 label = gen_rtx_CONST (VOIDmode, label);
03957 sum = gen_rtx_UNSPEC (Pmode,
03958 gen_rtvec (4, x, GEN_INT (TLS_IE32), label,
03959 GEN_INT (TARGET_ARM ? 8 : 4)),
03960 UNSPEC_TLS);
03961 reg = load_tls_operand (sum, reg);
03962
03963 if (TARGET_ARM)
03964 emit_insn (gen_tls_load_dot_plus_eight (reg, reg, labelno));
03965 else
03966 {
03967 emit_insn (gen_pic_add_dot_plus_four (reg, reg, labelno));
03968 emit_move_insn (reg, gen_const_mem (SImode, reg));
03969 }
03970
03971 tp = arm_load_tp (NULL_RTX);
03972
03973 return gen_rtx_PLUS (Pmode, tp, reg);
03974
03975 case TLS_MODEL_LOCAL_EXEC:
03976 tp = arm_load_tp (NULL_RTX);
03977
03978 reg = gen_rtx_UNSPEC (Pmode,
03979 gen_rtvec (2, x, GEN_INT (TLS_LE32)),
03980 UNSPEC_TLS);
03981 reg = force_reg (SImode, gen_rtx_CONST (SImode, reg));
03982
03983 return gen_rtx_PLUS (Pmode, tp, reg);
03984
03985 default:
03986 abort ();
03987 }
03988 }
03989
03990
03991
03992 rtx
03993 arm_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
03994 {
03995 if (arm_tls_symbol_p (x))
03996 return legitimize_tls_address (x, NULL_RTX);
03997
03998 if (GET_CODE (x) == PLUS)
03999 {
04000 rtx xop0 = XEXP (x, 0);
04001 rtx xop1 = XEXP (x, 1);
04002
04003 if (CONSTANT_P (xop0) && !symbol_mentioned_p (xop0))
04004 xop0 = force_reg (SImode, xop0);
04005
04006 if (CONSTANT_P (xop1) && !symbol_mentioned_p (xop1))
04007 xop1 = force_reg (SImode, xop1);
04008
04009 if (ARM_BASE_REGISTER_RTX_P (xop0)
04010 && GET_CODE (xop1) == CONST_INT)
04011 {
04012 HOST_WIDE_INT n, low_n;
04013 rtx base_reg, val;
04014 n = INTVAL (xop1);
04015
04016
04017
04018 if (mode == DImode
04019 || ((TARGET_SOFT_FLOAT || TARGET_VFP) && mode == DFmode))
04020 {
04021 low_n = n & 0x0f;
04022 n &= ~0x0f;
04023 if (low_n > 4)
04024 {
04025 n += 16;
04026 low_n -= 16;
04027 }
04028 }
04029 else
04030 {
04031 low_n = ((mode) == TImode ? 0
04032 : n >= 0 ? (n & 0xfff) : -((-n) & 0xfff));
04033 n -= low_n;
04034 }
04035
04036 base_reg = gen_reg_rtx (SImode);
04037 val = force_operand (plus_constant (xop0, n), NULL_RTX);
04038 emit_move_insn (base_reg, val);
04039 x = plus_constant (base_reg, low_n);
04040 }
04041 else if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
04042 x = gen_rtx_PLUS (SImode, xop0, xop1);
04043 }
04044
04045
04046
04047 else if (GET_CODE (x) == MINUS)
04048 {
04049 rtx xop0 = XEXP (x, 0);
04050 rtx xop1 = XEXP (x, 1);
04051
04052 if (CONSTANT_P (xop0))
04053 xop0 = force_reg (SImode, xop0);
04054
04055 if (CONSTANT_P (xop1) && ! symbol_mentioned_p (xop1))
04056 xop1 = force_reg (SImode, xop1);
04057
04058 if (xop0 != XEXP (x, 0) || xop1 != XEXP (x, 1))
04059 x = gen_rtx_MINUS (SImode, xop0, xop1);
04060 }
04061
04062
04063
04064
04065
04066 else if (GET_CODE (x) == CONST_INT && optimize > 0)
04067 {
04068 unsigned int bits;
04069 HOST_WIDE_INT mask, base, index;
04070 rtx base_reg;
04071
04072
04073
04074
04075 bits = (mode == SImode) ? 12 : 8;
04076 mask = (1 << bits) - 1;
04077 base = INTVAL (x) & ~mask;
04078 index = INTVAL (x) & mask;
04079 if (bit_count (base & 0xffffffff) > (32 - bits)/2)
04080 {
04081
04082
04083 base |= mask;
04084 index -= mask;
04085 }
04086 base_reg = force_reg (SImode, GEN_INT (base));
04087 x = plus_constant (base_reg, index);
04088 }
04089
04090 if (flag_pic)
04091 {
04092
04093
04094 rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
04095
04096 if (new_x != orig_x)
04097 x = new_x;
04098 }
04099
04100 return x;
04101 }
04102
04103
04104
04105
04106 rtx
04107 thumb_legitimize_address (rtx x, rtx orig_x, enum machine_mode mode)
04108 {
04109 if (arm_tls_symbol_p (x))
04110 return legitimize_tls_address (x, NULL_RTX);
04111
04112 if (GET_CODE (x) == PLUS
04113 && GET_CODE (XEXP (x, 1)) == CONST_INT
04114 && (INTVAL (XEXP (x, 1)) >= 32 * GET_MODE_SIZE (mode)
04115 || INTVAL (XEXP (x, 1)) < 0))
04116 {
04117 rtx xop0 = XEXP (x, 0);
04118 rtx xop1 = XEXP (x, 1);
04119 HOST_WIDE_INT offset = INTVAL (xop1);
04120
04121
04122
04123
04124 if (optimize_size && offset >= 0
04125 && offset < 256 + 31 * GET_MODE_SIZE (mode))
04126 {
04127 HOST_WIDE_INT delta;
04128
04129 if (offset >= 256)
04130 delta = offset - (256 - GET_MODE_SIZE (mode));
04131 else if (offset < 32 * GET_MODE_SIZE (mode) + 8)
04132 delta = 31 * GET_MODE_SIZE (mode);
04133 else
04134 delta = offset & (~31 * GET_MODE_SIZE (mode));
04135
04136 xop0 = force_operand (plus_constant (xop0, offset - delta),
04137 NULL_RTX);
04138 x = plus_constant (xop0, delta);
04139 }
04140 else if (offset < 0 && offset > -256)
04141
04142
04143
04144 x = force_operand (x, NULL_RTX);
04145 else
04146 {
04147
04148 xop1 = force_reg (SImode, xop1);
04149 x = gen_rtx_PLUS (SImode, xop0, xop1);
04150 }
04151 }
04152 else if (GET_CODE (x) == PLUS
04153 && s_register_operand (XEXP (x, 1), SImode)
04154 && !s_register_operand (XEXP (x, 0), SImode))
04155 {
04156 rtx xop0 = force_operand (XEXP (x, 0), NULL_RTX);
04157
04158 x = gen_rtx_PLUS (SImode, xop0, XEXP (x, 1));
04159 }
04160
04161 if (flag_pic)
04162 {
04163
04164
04165 rtx new_x = legitimize_pic_address (orig_x, mode, NULL_RTX);
04166
04167 if (new_x != orig_x)
04168 x = new_x;
04169 }
04170
04171 return x;
04172 }
04173
04174 rtx
04175 thumb_legitimize_reload_address (rtx *x_p,
04176 enum machine_mode mode,
04177 int opnum, int type,
04178 int ind_levels ATTRIBUTE_UNUSED)
04179 {
04180 rtx x = *x_p;
04181
04182 if (GET_CODE (x) == PLUS
04183 && GET_MODE_SIZE (mode) < 4
04184 && REG_P (XEXP (x, 0))
04185 && XEXP (x, 0) == stack_pointer_rtx
04186 && GET_CODE (XEXP (x, 1)) == CONST_INT
04187 && !thumb_legitimate_offset_p (mode, INTVAL (XEXP (x, 1))))
04188 {
04189 rtx orig_x = x;
04190
04191 x = copy_rtx (x);
04192 push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
04193 Pmode, VOIDmode, 0, 0, opnum, type);
04194 return x;
04195 }
04196
04197
04198
04199
04200 if (GET_CODE (x) == PLUS
04201 && REG_P (XEXP (x, 0))
04202 && REG_P (XEXP (x, 1))
04203 && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 0), mode)
04204 && !REG_MODE_OK_FOR_REG_BASE_P (XEXP (x, 1), mode))
04205 {
04206 rtx orig_x = x;
04207
04208 x = copy_rtx (x);
04209 push_reload (orig_x, NULL_RTX, x_p, NULL, MODE_BASE_REG_CLASS (mode),
04210 Pmode, VOIDmode, 0, 0, opnum, type);
04211 return x;
04212 }
04213
04214 return NULL;
04215 }
04216
04217
04218
04219
04220
04221 static bool
04222 arm_tls_symbol_p (rtx x)
04223 {
04224 if (! TARGET_HAVE_TLS)
04225 return false;
04226
04227 if (GET_CODE (x) != SYMBOL_REF)
04228 return false;
04229
04230 return SYMBOL_REF_TLS_MODEL (x) != 0;
04231 }
04232
04233
04234
04235 static int
04236 arm_tls_operand_p_1 (rtx *x, void *data ATTRIBUTE_UNUSED)
04237 {
04238 if (GET_CODE (*x) == SYMBOL_REF)
04239 return SYMBOL_REF_TLS_MODEL (*x) != 0;
04240
04241
04242
04243 if (GET_CODE (*x) == UNSPEC
04244 && XINT (*x, 1) == UNSPEC_TLS)
04245 return -1;
04246
04247 return 0;
04248 }
04249
04250
04251
04252 bool
04253 arm_tls_referenced_p (rtx x)
04254 {
04255 if (! TARGET_HAVE_TLS)
04256 return false;
04257
04258 return for_each_rtx (&x, arm_tls_operand_p_1, NULL);
04259 }
04260
04261 #define REG_OR_SUBREG_REG(X) \
04262 (GET_CODE (X) == REG \
04263 || (GET_CODE (X) == SUBREG && GET_CODE (SUBREG_REG (X)) == REG))
04264
04265 #define REG_OR_SUBREG_RTX(X) \
04266 (GET_CODE (X) == REG ? (X) : SUBREG_REG (X))
04267
04268 #ifndef COSTS_N_INSNS
04269 #define COSTS_N_INSNS(N) ((N) * 4 - 2)
04270 #endif
04271 static inline int
04272 thumb_rtx_costs (rtx x, enum rtx_code code, enum rtx_code outer)
04273 {
04274 enum machine_mode mode = GET_MODE (x);
04275
04276 switch (code)
04277 {
04278 case ASHIFT:
04279 case ASHIFTRT:
04280 case LSHIFTRT:
04281 case ROTATERT:
04282 case PLUS:
04283 case MINUS:
04284 case COMPARE:
04285 case NEG:
04286 case NOT:
04287 return COSTS_N_INSNS (1);
04288
04289 case MULT:
04290 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
04291 {
04292 int cycles = 0;
04293 unsigned HOST_WIDE_INT i = INTVAL (XEXP (x, 1));
04294
04295 while (i)
04296 {
04297 i >>= 2;
04298 cycles++;
04299 }
04300 return COSTS_N_INSNS (2) + cycles;
04301 }
04302 return COSTS_N_INSNS (1) + 16;
04303
04304 case SET:
04305 return (COSTS_N_INSNS (1)
04306 + 4 * ((GET_CODE (SET_SRC (x)) == MEM)
04307 + GET_CODE (SET_DEST (x)) == MEM));
04308
04309 case CONST_INT:
04310 if (outer == SET)
04311 {
04312 if ((unsigned HOST_WIDE_INT) INTVAL (x) < 256)
04313 return 0;
04314 if (thumb_shiftable_const (INTVAL (x)))
04315 return COSTS_N_INSNS (2);
04316 return COSTS_N_INSNS (3);
04317 }
04318 else if ((outer == PLUS || outer == COMPARE)
04319 && INTVAL (x) < 256 && INTVAL (x) > -256)
04320 return 0;
04321 else if (outer == AND
04322 && INTVAL (x) < 256 && INTVAL (x) >= -256)
04323 return COSTS_N_INSNS (1);
04324 else if (outer == ASHIFT || outer == ASHIFTRT
04325 || outer == LSHIFTRT)
04326 return 0;
04327 return COSTS_N_INSNS (2);
04328
04329 case CONST:
04330 case CONST_DOUBLE:
04331 case LABEL_REF:
04332 case SYMBOL_REF:
04333 return COSTS_N_INSNS (3);
04334
04335 case UDIV:
04336 case UMOD:
04337 case DIV:
04338 case MOD:
04339 return 100;
04340
04341 case TRUNCATE:
04342 return 99;
04343
04344 case AND:
04345 case XOR:
04346 case IOR:
04347
04348 return 8;
04349
04350 case MEM:
04351
04352
04353
04354 return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
04355 + ((GET_CODE (x) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (x))
04356 ? 4 : 0));
04357
04358 case IF_THEN_ELSE:
04359
04360 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
04361 return 14;
04362 return 2;
04363
04364 case ZERO_EXTEND:
04365
04366 switch (GET_MODE (XEXP (x, 0)))
04367 {
04368 case QImode:
04369 return (1 + (mode == DImode ? 4 : 0)
04370 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
04371
04372 case HImode:
04373 return (4 + (mode == DImode ? 4 : 0)
04374 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
04375
04376 case SImode:
04377 return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
04378
04379 default:
04380 return 99;
04381 }
04382
04383 default:
04384 return 99;
04385 }
04386 }
04387
04388
04389
04390 static inline int
04391 arm_rtx_costs_1 (rtx x, enum rtx_code code, enum rtx_code outer)
04392 {
04393 enum machine_mode mode = GET_MODE (x);
04394 enum rtx_code subcode;
04395 int extra_cost;
04396
04397 switch (code)
04398 {
04399 case MEM:
04400
04401
04402 return (10 + 4 * ((GET_MODE_SIZE (mode) - 1) / UNITS_PER_WORD)
04403 + (GET_CODE (x) == SYMBOL_REF
04404 && CONSTANT_POOL_ADDRESS_P (x) ? 4 : 0));
04405
04406 case DIV:
04407 case MOD:
04408 case UDIV:
04409 case UMOD:
04410 return optimize_size ? COSTS_N_INSNS (2) : 100;
04411
04412 case ROTATE:
04413 if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
04414 return 4;
04415
04416 case ROTATERT:
04417 if (mode != SImode)
04418 return 8;
04419
04420 case ASHIFT: case LSHIFTRT: case ASHIFTRT:
04421 if (mode == DImode)
04422 return (8 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : 8)
04423 + ((GET_CODE (XEXP (x, 0)) == REG
04424 || (GET_CODE (XEXP (x, 0)) == SUBREG
04425 && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
04426 ? 0 : 8));
04427 return (1 + ((GET_CODE (XEXP (x, 0)) == REG
04428 || (GET_CODE (XEXP (x, 0)) == SUBREG
04429 && GET_CODE (SUBREG_REG (XEXP (x, 0))) == REG))
04430 ? 0 : 4)
04431 + ((GET_CODE (XEXP (x, 1)) == REG
04432 || (GET_CODE (XEXP (x, 1)) == SUBREG
04433 && GET_CODE (SUBREG_REG (XEXP (x, 1))) == REG)
04434 || (GET_CODE (XEXP (x, 1)) == CONST_INT))
04435 ? 0 : 4));
04436
04437 case MINUS:
04438 if (mode == DImode)
04439 return (4 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 8)
04440 + ((REG_OR_SUBREG_REG (XEXP (x, 0))
04441 || (GET_CODE (XEXP (x, 0)) == CONST_INT
04442 && const_ok_for_arm (INTVAL (XEXP (x, 0)))))
04443 ? 0 : 8));
04444
04445 if (GET_MODE_CLASS (mode) == MODE_FLOAT)
04446 return (2 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
04447 || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
04448 && arm_const_double_rtx (XEXP (x, 1))))
04449 ? 0 : 8)
04450 + ((REG_OR_SUBREG_REG (XEXP (x, 0))
04451 || (GET_CODE (XEXP (x, 0)) == CONST_DOUBLE
04452 && arm_const_double_rtx (XEXP (x, 0))))
04453 ? 0 : 8));
04454
04455 if (((GET_CODE (XEXP (x, 0)) == CONST_INT
04456 && const_ok_for_arm (INTVAL (XEXP (x, 0)))
04457 && REG_OR_SUBREG_REG (XEXP (x, 1))))
04458 || (((subcode = GET_CODE (XEXP (x, 1))) == ASHIFT
04459 || subcode == ASHIFTRT || subcode == LSHIFTRT
04460 || subcode == ROTATE || subcode == ROTATERT
04461 || (subcode == MULT
04462 && GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT
04463 && ((INTVAL (XEXP (XEXP (x, 1), 1)) &
04464 (INTVAL (XEXP (XEXP (x, 1), 1)) - 1)) == 0)))
04465 && REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 0))
04466 && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 1), 1))
04467 || GET_CODE (XEXP (XEXP (x, 1), 1)) == CONST_INT)
04468 && REG_OR_SUBREG_REG (XEXP (x, 0))))
04469 return 1;
04470
04471
04472 case PLUS:
04473 if (GET_CODE (XEXP (x, 0)) == MULT)
04474 {
04475 extra_cost = rtx_cost (XEXP (x, 0), code);
04476 if (!REG_OR_SUBREG_REG (XEXP (x, 1)))
04477 extra_cost += 4 * ARM_NUM_REGS (mode);
04478 return extra_cost;
04479 }
04480
04481 if (GET_MODE_CLASS (mode) == MODE_FLOAT)
04482 return (2 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
04483 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
04484 || (GET_CODE (XEXP (x, 1)) == CONST_DOUBLE
04485 && arm_const_double_rtx (XEXP (x, 1))))
04486 ? 0 : 8));
04487
04488
04489 case AND: case XOR: case IOR:
04490 extra_cost = 0;
04491
04492
04493
04494
04495
04496
04497 if ((REG_OR_SUBREG_REG (XEXP (x, 0))
04498 && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))
04499 && GET_CODE (XEXP (x, 1)) != CONST_INT)
04500 || (REG_OR_SUBREG_REG (XEXP (x, 0))
04501 && ARM_FRAME_RTX (REG_OR_SUBREG_RTX (XEXP (x, 0)))))
04502 extra_cost = 4;
04503
04504 if (mode == DImode)
04505 return (4 + extra_cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 8)
04506 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
04507 || (GET_CODE (XEXP (x, 1)) == CONST_INT
04508 && const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
04509 ? 0 : 8));
04510
04511 if (REG_OR_SUBREG_REG (XEXP (x, 0)))
04512 return (1 + (GET_CODE (XEXP (x, 1)) == CONST_INT ? 0 : extra_cost)
04513 + ((REG_OR_SUBREG_REG (XEXP (x, 1))
04514 || (GET_CODE (XEXP (x, 1)) == CONST_INT
04515 && const_ok_for_op (INTVAL (XEXP (x, 1)), code)))
04516 ? 0 : 4));
04517
04518 else if (REG_OR_SUBREG_REG (XEXP (x, 1)))
04519 return (1 + extra_cost
04520 + ((((subcode = GET_CODE (XEXP (x, 0))) == ASHIFT
04521 || subcode == LSHIFTRT || subcode == ASHIFTRT
04522 || subcode == ROTATE || subcode == ROTATERT
04523 || (subcode == MULT
04524 && GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT
04525 && ((INTVAL (XEXP (XEXP (x, 0), 1)) &
04526 (INTVAL (XEXP (XEXP (x, 0), 1)) - 1)) == 0)))
04527 && (REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 0)))
04528 && ((REG_OR_SUBREG_REG (XEXP (XEXP (x, 0), 1)))
04529 || GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
04530 ? 0 : 4));
04531
04532 return 8;
04533
04534 case MULT:
04535
04536 gcc_unreachable ();
04537
04538 case TRUNCATE:
04539 if (arm_arch3m && mode == SImode
04540 && GET_CODE (XEXP (x, 0)) == LSHIFTRT
04541 && GET_CODE (XEXP (XEXP (x, 0), 0)) == MULT
04542 && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0))
04543 == GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 1)))
04544 && (GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == ZERO_EXTEND
04545 || GET_CODE (XEXP (XEXP (XEXP (x, 0), 0), 0)) == SIGN_EXTEND))
04546 return 8;
04547 return 99;
04548
04549 case NEG:
04550 if (GET_MODE_CLASS (mode) == MODE_FLOAT)
04551 return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 6);
04552
04553 case NOT:
04554 if (mode == DImode)
04555 return 4 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
04556
04557 return 1 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4);
04558
04559 case IF_THEN_ELSE:
04560 if (GET_CODE (XEXP (x, 1)) == PC || GET_CODE (XEXP (x, 2)) == PC)
04561 return 14;
04562 return 2;
04563
04564 case COMPARE:
04565 return 1;
04566
04567 case ABS:
04568 return 4 + (mode == DImode ? 4 : 0);
04569
04570 case SIGN_EXTEND:
04571 if (GET_MODE (XEXP (x, 0)) == QImode)
04572 return (4 + (mode == DImode ? 4 : 0)
04573 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
04574
04575 case ZERO_EXTEND:
04576 switch (GET_MODE (XEXP (x, 0)))
04577 {
04578 case QImode:
04579 return (1 + (mode == DImode ? 4 : 0)
04580 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
04581
04582 case HImode:
04583 return (4 + (mode == DImode ? 4 : 0)
04584 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
04585
04586 case SImode:
04587 return (1 + (GET_CODE (XEXP (x, 0)) == MEM ? 10 : 0));
04588
04589 case V8QImode:
04590 case V4HImode:
04591 case V2SImode:
04592 case V4QImode:
04593 case V2HImode:
04594 return 1;
04595
04596 default:
04597 gcc_unreachable ();
04598 }
04599 gcc_unreachable ();
04600
04601 case CONST_INT:
04602 if (const_ok_for_arm (INTVAL (x)))
04603 return outer == SET ? 2 : -1;
04604 else if (outer == AND
04605 && const_ok_for_arm (~INTVAL (x)))
04606 return -1;
04607 else if ((outer == COMPARE
04608 || outer == PLUS || outer == MINUS)
04609 && const_ok_for_arm (-INTVAL (x)))
04610 return -1;
04611 else
04612 return 5;
04613
04614 case CONST:
04615 case LABEL_REF:
04616 case SYMBOL_REF:
04617 return 6;
04618
04619 case CONST_DOUBLE:
04620 if (arm_const_double_rtx (x))
04621 return outer == SET ? 2 : -1;
04622 else if ((outer == COMPARE || outer == PLUS)
04623 && neg_const_double_rtx_ok_for_fpa (x))
04624 return -1;
04625 return 7;
04626
04627 default:
04628 return 99;
04629 }
04630 }
04631
04632
04633 static bool
04634 arm_size_rtx_costs (rtx x, int code, int outer_code, int *total)
04635 {
04636 enum machine_mode mode = GET_MODE (x);
04637
04638 if (TARGET_THUMB)
04639 {
04640
04641 *total = thumb_rtx_costs (x, code, outer_code);
04642 return true;
04643 }
04644
04645 switch (code)
04646 {
04647 case MEM:
04648
04649
04650 if (REG_P (XEXP (x, 0)))
04651 *total = COSTS_N_INSNS (1);
04652 else
04653 *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
04654 return true;
04655
04656 case DIV:
04657 case MOD:
04658 case UDIV:
04659 case UMOD:
04660
04661 *total = COSTS_N_INSNS (2);
04662 return false;
04663
04664 case ROTATE:
04665 if (mode == SImode && GET_CODE (XEXP (x, 1)) == REG)
04666 {
04667 *total = COSTS_N_INSNS (2) + rtx_cost (XEXP (x, 0), code);
04668 return true;
04669 }
04670
04671 case ROTATERT:
04672 case ASHIFT:
04673 case LSHIFTRT:
04674 case ASHIFTRT:
04675 if (mode == DImode && GET_CODE (XEXP (x, 1)) == CONST_INT)
04676 {
04677 *total = COSTS_N_INSNS (3) + rtx_cost (XEXP (x, 0), code);
04678 return true;
04679 }
04680 else if (mode == SImode)
04681 {
04682 *total = COSTS_N_INSNS (1) + rtx_cost (XEXP (x, 0), code);
04683
04684 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
04685 *total += 1 + rtx_cost (XEXP (x, 1), code);
04686 return true;
04687 }
04688
04689
04690 *total = COSTS_N_INSNS (2);
04691 return false;
04692
04693 case MINUS:
04694 if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
04695 {
04696 *total = COSTS_N_INSNS (1);
04697 return false;
04698 }
04699
04700 if (mode == SImode)
04701 {
04702 enum rtx_code subcode0 = GET_CODE (XEXP (x, 0));
04703 enum rtx_code subcode1 = GET_CODE (XEXP (x, 1));
04704
04705 if (subcode0 == ROTATE || subcode0 == ROTATERT || subcode0 == ASHIFT
04706 || subcode0 == LSHIFTRT || subcode0 == ASHIFTRT
04707 || subcode1 == ROTATE || subcode1 == ROTATERT
04708 || subcode1 == ASHIFT || subcode1 == LSHIFTRT
04709 || subcode1 == ASHIFTRT)
04710 {
04711
04712 *total = 0;
04713 return false;
04714 }
04715
04716 *total = COSTS_N_INSNS (1);
04717 return false;
04718 }
04719
04720 *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
04721 return false;
04722
04723 case PLUS:
04724 if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
04725 {
04726 *total = COSTS_N_INSNS (1);
04727 return false;
04728 }
04729
04730
04731 case AND: case XOR: case IOR:
04732 if (mode == SImode)
04733 {
04734 enum rtx_code subcode = GET_CODE (XEXP (x, 0));
04735
04736 if (subcode == ROTATE || subcode == ROTATERT || subcode == ASHIFT
04737 || subcode == LSHIFTRT || subcode == ASHIFTRT
04738 || (code == AND && subcode == NOT))
04739 {
04740
04741 *total = 0;
04742 return false;
04743 }
04744 }
04745
04746 *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
04747 return false;
04748
04749 case MULT:
04750 *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
04751 return false;
04752
04753 case NEG:
04754 if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
04755 *total = COSTS_N_INSNS (1);
04756
04757 case NOT:
04758 *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
04759
04760 return false;
04761
04762 case IF_THEN_ELSE:
04763 *total = 0;
04764 return false;
04765
04766 case COMPARE:
04767 if (cc_register (XEXP (x, 0), VOIDmode))
04768 * total = 0;
04769 else
04770 *total = COSTS_N_INSNS (1);
04771 return false;
04772
04773 case ABS:
04774 if (TARGET_HARD_FLOAT && GET_MODE_CLASS (mode) == MODE_FLOAT)
04775 *total = COSTS_N_INSNS (1);
04776 else
04777 *total = COSTS_N_INSNS (1 + ARM_NUM_REGS (mode));
04778 return false;
04779
04780 case SIGN_EXTEND:
04781 *total = 0;
04782 if (GET_MODE_SIZE (GET_MODE (XEXP (x, 0))) < 4)
04783 {
04784 if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
04785 *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
04786 }
04787 if (mode == DImode)
04788 *total += COSTS_N_INSNS (1);
04789 return false;
04790
04791 case ZERO_EXTEND:
04792 *total = 0;
04793 if (!(arm_arch4 && MEM_P (XEXP (x, 0))))
04794 {
04795 switch (GET_MODE (XEXP (x, 0)))
04796 {
04797 case QImode:
04798 *total += COSTS_N_INSNS (1);
04799 break;
04800
04801 case HImode:
04802 *total += COSTS_N_INSNS (arm_arch6 ? 1 : 2);
04803
04804 case SImode:
04805 break;
04806
04807 default:
04808 *total += COSTS_N_INSNS (2);
04809 }
04810 }
04811
04812 if (mode == DImode)
04813 *total += COSTS_N_INSNS (1);
04814
04815 return false;
04816
04817 case CONST_INT:
04818 if (const_ok_for_arm (INTVAL (x)))
04819 *total = COSTS_N_INSNS (outer_code == SET ? 1 : 0);
04820 else if (const_ok_for_arm (~INTVAL (x)))
04821 *total = COSTS_N_INSNS (outer_code == AND ? 0 : 1);
04822 else if (const_ok_for_arm (-INTVAL (x)))
04823 {
04824 if (outer_code == COMPARE || outer_code == PLUS
04825 || outer_code == MINUS)
04826 *total = 0;
04827 else
04828 *total = COSTS_N_INSNS (1);
04829 }
04830 else
04831 *total = COSTS_N_INSNS (2);
04832 return true;
04833
04834 case CONST:
04835 case LABEL_REF:
04836 case SYMBOL_REF:
04837 *total = COSTS_N_INSNS (2);
04838 return true;
04839
04840 case CONST_DOUBLE:
04841 *total = COSTS_N_INSNS (4);
04842 return true;
04843
04844 default:
04845 if (mode != VOIDmode)
04846 *total = COSTS_N_INSNS (ARM_NUM_REGS (mode));
04847 else
04848 *total = COSTS_N_INSNS (4);
04849 return false;
04850 }
04851 }
04852
04853
04854
04855 static bool
04856 arm_slowmul_rtx_costs (rtx x, int code, int outer_code, int *total)
04857 {
04858 enum machine_mode mode = GET_MODE (x);
04859
04860 if (TARGET_THUMB)
04861 {
04862 *total = thumb_rtx_costs (x, code, outer_code);
04863 return true;
04864 }
04865
04866 switch (code)
04867 {
04868 case MULT:
04869 if (GET_MODE_CLASS (mode) == MODE_FLOAT
04870 || mode == DImode)
04871 {
04872 *total = 30;
04873 return true;
04874 }
04875
04876 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
04877 {
04878 unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
04879 & (unsigned HOST_WIDE_INT) 0xffffffff);
04880 int cost, const_ok = const_ok_for_arm (i);
04881 int j, booth_unit_size;
04882
04883
04884 cost = const_ok ? 4 : 8;
04885 booth_unit_size = 2;
04886 for (j = 0; i && j < 32; j += booth_unit_size)
04887 {
04888 i >>= booth_unit_size;
04889 cost += 2;
04890 }
04891
04892 *total = cost;
04893 return true;
04894 }
04895
04896 *total = 30 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
04897 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
04898 return true;
04899
04900 default:
04901 *total = arm_rtx_costs_1 (x, code, outer_code);
04902 return true;
04903 }
04904 }
04905
04906
04907
04908
04909 static bool
04910 arm_fastmul_rtx_costs (rtx x, int code, int outer_code, int *total)
04911 {
04912 enum machine_mode mode = GET_MODE (x);
04913
04914 if (TARGET_THUMB)
04915 {
04916 *total = thumb_rtx_costs (x, code, outer_code);
04917 return true;
04918 }
04919
04920 switch (code)
04921 {
04922 case MULT:
04923
04924
04925 if (mode == DImode
04926 && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
04927 && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
04928 || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
04929 {
04930 *total = 8;
04931 return true;
04932 }
04933
04934
04935 if (GET_MODE_CLASS (mode) == MODE_FLOAT
04936 || mode == DImode)
04937 {
04938 *total = 30;
04939 return true;
04940 }
04941
04942 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
04943 {
04944 unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
04945 & (unsigned HOST_WIDE_INT) 0xffffffff);
04946 int cost, const_ok = const_ok_for_arm (i);
04947 int j, booth_unit_size;
04948
04949
04950 cost = const_ok ? 4 : 8;
04951 booth_unit_size = 8;
04952 for (j = 0; i && j < 32; j += booth_unit_size)
04953 {
04954 i >>= booth_unit_size;
04955 cost += 2;
04956 }
04957
04958 *total = cost;
04959 return true;
04960 }
04961
04962 *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
04963 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
04964 return true;
04965
04966 default:
04967 *total = arm_rtx_costs_1 (x, code, outer_code);
04968 return true;
04969 }
04970 }
04971
04972
04973
04974
04975 static bool
04976 arm_xscale_rtx_costs (rtx x, int code, int outer_code, int *total)
04977 {
04978 enum machine_mode mode = GET_MODE (x);
04979
04980 if (TARGET_THUMB)
04981 {
04982 *total = thumb_rtx_costs (x, code, outer_code);
04983 return true;
04984 }
04985
04986 switch (code)
04987 {
04988 case MULT:
04989
04990
04991 if (mode == DImode
04992 && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
04993 && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
04994 || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
04995 {
04996 *total = 8;
04997 return true;
04998 }
04999
05000
05001 if (GET_MODE_CLASS (mode) == MODE_FLOAT
05002 || mode == DImode)
05003 {
05004 *total = 30;
05005 return true;
05006 }
05007
05008 if (GET_CODE (XEXP (x, 1)) == CONST_INT)
05009 {
05010 unsigned HOST_WIDE_INT i = (INTVAL (XEXP (x, 1))
05011 & (unsigned HOST_WIDE_INT) 0xffffffff);
05012 int cost, const_ok = const_ok_for_arm (i);
05013 unsigned HOST_WIDE_INT masked_const;
05014
05015
05016
05017 cost = 2;
05018 if (! const_ok)
05019 cost += 1;
05020
05021 masked_const = i & 0xffff8000;
05022 if (masked_const != 0 && masked_const != 0xffff8000)
05023 {
05024 masked_const = i & 0xf8000000;
05025 if (masked_const == 0 || masked_const == 0xf8000000)
05026 cost += 1;
05027 else
05028 cost += 2;
05029 }
05030 *total = cost;
05031 return true;
05032 }
05033
05034 *total = 8 + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : 4)
05035 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : 4);
05036 return true;
05037
05038 case COMPARE:
05039
05040
05041 if (GET_CODE (XEXP (x, 0)) == MULT)
05042 *total = 4 + rtx_cost (XEXP (x, 0), code);
05043 else
05044 *total = arm_rtx_costs_1 (x, code, outer_code);
05045 return true;
05046
05047 default:
05048 *total = arm_rtx_costs_1 (x, code, outer_code);
05049 return true;
05050 }
05051 }
05052
05053
05054
05055
05056 static bool
05057 arm_9e_rtx_costs (rtx x, int code, int outer_code, int *total)
05058 {
05059 enum machine_mode mode = GET_MODE (x);
05060 int nonreg_cost;
05061 int cost;
05062
05063 if (TARGET_THUMB)
05064 {
05065 switch (code)
05066 {
05067 case MULT:
05068 *total = COSTS_N_INSNS (3);
05069 return true;
05070
05071 default:
05072 *total = thumb_rtx_costs (x, code, outer_code);
05073 return true;
05074 }
05075 }
05076
05077 switch (code)
05078 {
05079 case MULT:
05080
05081
05082 if (mode == DImode
05083 && (GET_CODE (XEXP (x, 0)) == GET_CODE (XEXP (x, 1)))
05084 && (GET_CODE (XEXP (x, 0)) == ZERO_EXTEND
05085 || GET_CODE (XEXP (x, 0)) == SIGN_EXTEND))
05086 {
05087 *total = 3;
05088 return true;
05089 }
05090
05091
05092 if (GET_MODE_CLASS (mode) == MODE_FLOAT)
05093 {
05094 *total = 30;
05095 return true;
05096 }
05097 if (mode == DImode)
05098 {
05099 cost = 7;
05100 nonreg_cost = 8;
05101 }
05102 else
05103 {
05104 cost = 2;
05105 nonreg_cost = 4;
05106 }
05107
05108
05109 *total = cost + (REG_OR_SUBREG_REG (XEXP (x, 0)) ? 0 : nonreg_cost)
05110 + (REG_OR_SUBREG_REG (XEXP (x, 1)) ? 0 : nonreg_cost);
05111 return true;
05112
05113 default:
05114 *total = arm_rtx_costs_1 (x, code, outer_code);
05115 return true;
05116 }
05117 }
05118
05119
05120
05121
05122 static inline int
05123 arm_arm_address_cost (rtx x)
05124 {
05125 enum rtx_code c = GET_CODE (x);
05126
05127 if (c == PRE_INC || c == PRE_DEC || c == POST_INC || c == POST_DEC)
05128 return 0;
05129 if (c == MEM || c == LABEL_REF || c == SYMBOL_REF)
05130 return 10;
05131
05132 if (c == PLUS || c == MINUS)
05133 {
05134 if (GET_CODE (XEXP (x, 0)) == CONST_INT)
05135 return 2;
05136
05137 if (ARITHMETIC_P (XEXP (x, 0)) || ARITHMETIC_P (XEXP (x, 1)))
05138 return 3;
05139
05140 return 4;
05141 }
05142
05143 return 6;
05144 }
05145
05146 static inline int
05147 arm_thumb_address_cost (rtx x)
05148 {
05149 enum rtx_code c = GET_CODE (x);
05150
05151 if (c == REG)
05152 return 1;
05153 if (c == PLUS
05154 && GET_CODE (XEXP (x, 0)) == REG
05155 && GET_CODE (XEXP (x, 1)) == CONST_INT)
05156 return 1;
05157
05158 return 2;
05159 }
05160
05161 static int
05162 arm_address_cost (rtx x)
05163 {
05164 return TARGET_ARM ? arm_arm_address_cost (x) : arm_thumb_address_cost (x);
05165 }
05166
05167 static int
05168 arm_adjust_cost (rtx insn, rtx link, rtx dep, int cost)
05169 {
05170 rtx i_pat, d_pat;
05171
05172
05173
05174 if (arm_tune_xscale
05175 && REG_NOTE_KIND (link) == 0
05176 && recog_memoized (insn) >= 0
05177 && recog_memoized (dep) >= 0)
05178 {
05179 int shift_opnum = get_attr_shift (insn);
05180 enum attr_type attr_type = get_attr_type (dep);
05181
05182
05183
05184
05185
05186 if (shift_opnum != 0
05187 && (attr_type == TYPE_ALU_SHIFT || attr_type == TYPE_ALU_SHIFT_REG))
05188 {
05189 rtx shifted_operand;
05190 int opno;
05191
05192
05193 extract_insn (insn);
05194 shifted_operand = recog_data.operand[shift_opnum];
05195
05196
05197
05198
05199 extract_insn (dep);
05200 preprocess_constraints ();
05201 for (opno = 0; opno < recog_data.n_operands; opno++)
05202 {
05203
05204 if (recog_data.operand_type[opno] == OP_IN)
05205 continue;
05206
05207 if (reg_overlap_mentioned_p (recog_data.operand[opno],
05208 shifted_operand))
05209 return 2;
05210 }
05211 }
05212 }
05213
05214
05215 if (REG_NOTE_KIND (link) == REG_DEP_ANTI
05216 || REG_NOTE_KIND (link) == REG_DEP_OUTPUT)
05217 return 0;
05218
05219
05220 if (REG_NOTE_KIND (link) == 0
05221 && GET_CODE (insn) == CALL_INSN)
05222 return 1;
05223
05224 if ((i_pat = single_set (insn)) != NULL
05225 && GET_CODE (SET_SRC (i_pat)) == MEM
05226 && (d_pat = single_set (dep)) != NULL
05227 && GET_CODE (SET_DEST (d_pat)) == MEM)
05228 {
05229 rtx src_mem = XEXP (SET_SRC (i_pat), 0);
05230
05231
05232
05233
05234
05235 if ((GET_CODE (src_mem) == SYMBOL_REF && CONSTANT_POOL_ADDRESS_P (src_mem))
05236 || reg_mentioned_p (stack_pointer_rtx, src_mem)
05237 || reg_mentioned_p (frame_pointer_rtx, src_mem)
05238 || reg_mentioned_p (hard_frame_pointer_rtx, src_mem))
05239 return 1;
05240 }
05241
05242 return cost;
05243 }
05244
05245 static int fp_consts_inited = 0;
05246
05247
05248 static const char * const strings_fp[8] =
05249 {
05250 "0", "1", "2", "3",
05251 "4", "5", "0.5", "10"
05252 };
05253
05254 static REAL_VALUE_TYPE values_fp[8];
05255
05256 static void
05257 init_fp_table (void)
05258 {
05259 int i;
05260 REAL_VALUE_TYPE r;
05261
05262 if (TARGET_VFP)
05263 fp_consts_inited = 1;
05264 else
05265 fp_consts_inited = 8;
05266
05267 for (i = 0; i < fp_consts_inited; i++)
05268 {
05269 r = REAL_VALUE_ATOF (strings_fp[i], DFmode);
05270 values_fp[i] = r;
05271 }
05272 }
05273
05274
05275 int
05276 arm_const_double_rtx (rtx x)
05277 {
05278 REAL_VALUE_TYPE r;
05279 int i;
05280
05281 if (!fp_consts_inited)
05282 init_fp_table ();
05283
05284 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
05285 if (REAL_VALUE_MINUS_ZERO (r))
05286 return 0;
05287
05288 for (i = 0; i < fp_consts_inited; i++)
05289 if (REAL_VALUES_EQUAL (r, values_fp[i]))
05290 return 1;
05291
05292 return 0;
05293 }
05294
05295
05296 int
05297 neg_const_double_rtx_ok_for_fpa (rtx x)
05298 {
05299 REAL_VALUE_TYPE r;
05300 int i;
05301
05302 if (!fp_consts_inited)
05303 init_fp_table ();
05304
05305 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
05306 r = REAL_VALUE_NEGATE (r);
05307 if (REAL_VALUE_MINUS_ZERO (r))
05308 return 0;
05309
05310 for (i = 0; i < 8; i++)
05311 if (REAL_VALUES_EQUAL (r, values_fp[i]))
05312 return 1;
05313
05314 return 0;
05315 }
05316
05317
05318
05319
05320 int
05321 cirrus_memory_offset (rtx op)
05322 {
05323
05324 if (! (reload_in_progress || reload_completed)
05325 && ( reg_mentioned_p (frame_pointer_rtx, op)
05326 || reg_mentioned_p (arg_pointer_rtx, op)
05327 || reg_mentioned_p (virtual_incoming_args_rtx, op)
05328 || reg_mentioned_p (virtual_outgoing_args_rtx, op)
05329 || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
05330 || reg_mentioned_p (virtual_stack_vars_rtx, op)))
05331 return 0;
05332
05333 if (GET_CODE (op) == MEM)
05334 {
05335 rtx ind;
05336
05337 ind = XEXP (op, 0);
05338
05339
05340 if (GET_CODE (ind) == REG)
05341 return 1;
05342
05343
05344
05345
05346 if (GET_CODE (ind) == PLUS
05347 && GET_CODE (XEXP (ind, 0)) == REG
05348 && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
05349 && GET_CODE (XEXP (ind, 1)) == CONST_INT)
05350 return 1;
05351 }
05352
05353 return 0;
05354 }
05355
05356
05357
05358
05359 int
05360 arm_coproc_mem_operand (rtx op, bool wb)
05361 {
05362 rtx ind;
05363
05364
05365 if (! (reload_in_progress || reload_completed)
05366 && ( reg_mentioned_p (frame_pointer_rtx, op)
05367 || reg_mentioned_p (arg_pointer_rtx, op)
05368 || reg_mentioned_p (virtual_incoming_args_rtx, op)
05369 || reg_mentioned_p (virtual_outgoing_args_rtx, op)
05370 || reg_mentioned_p (virtual_stack_dynamic_rtx, op)
05371 || reg_mentioned_p (virtual_stack_vars_rtx, op)))
05372 return FALSE;
05373
05374
05375 if (GET_CODE (op) != MEM)
05376 return FALSE;
05377
05378 ind = XEXP (op, 0);
05379
05380 if (reload_completed
05381 && (GET_CODE (ind) == LABEL_REF
05382 || (GET_CODE (ind) == CONST
05383 && GET_CODE (XEXP (ind, 0)) == PLUS
05384 && GET_CODE (XEXP (XEXP (ind, 0), 0)) == LABEL_REF
05385 && GET_CODE (XEXP (XEXP (ind, 0), 1)) == CONST_INT)))
05386 return TRUE;
05387
05388
05389 if (GET_CODE (ind) == REG)
05390 return arm_address_register_rtx_p (ind, 0);
05391
05392
05393 if (wb
05394 && (GET_CODE (ind) == PRE_INC
05395 || GET_CODE (ind) == POST_INC
05396 || GET_CODE (ind) == PRE_DEC
05397 || GET_CODE (ind) == POST_DEC))
05398 return arm_address_register_rtx_p (XEXP (ind, 0), 0);
05399
05400 if (wb
05401 && (GET_CODE (ind) == POST_MODIFY || GET_CODE (ind) == PRE_MODIFY)
05402 && arm_address_register_rtx_p (XEXP (ind, 0), 0)
05403 && GET_CODE (XEXP (ind, 1)) == PLUS
05404 && rtx_equal_p (XEXP (XEXP (ind, 1), 0), XEXP (ind, 0)))
05405 ind = XEXP (ind, 1);
05406
05407
05408
05409
05410 if (GET_CODE (ind) == PLUS
05411 && GET_CODE (XEXP (ind, 0)) == REG
05412 && REG_MODE_OK_FOR_BASE_P (XEXP (ind, 0), VOIDmode)
05413 && GET_CODE (XEXP (ind, 1)) == CONST_INT
05414 && INTVAL (XEXP (ind, 1)) > -1024
05415 && INTVAL (XEXP (ind, 1)) < 1024
05416 && (INTVAL (XEXP (ind, 1)) & 3) == 0)
05417 return TRUE;
05418
05419 return FALSE;
05420 }
05421
05422
05423 int
05424 arm_eliminable_register (rtx x)
05425 {
05426 return REG_P (x) && (REGNO (x) == FRAME_POINTER_REGNUM
05427 || REGNO (x) == ARG_POINTER_REGNUM
05428 || (REGNO (x) >= FIRST_VIRTUAL_REGISTER
05429 && REGNO (x) <= LAST_VIRTUAL_REGISTER));
05430 }
05431
05432
05433
05434
05435 enum reg_class
05436 coproc_secondary_reload_class (enum machine_mode mode, rtx x, bool wb)
05437 {
05438 if (arm_coproc_mem_operand (x, wb) || s_register_operand (x, mode))
05439 return NO_REGS;
05440
05441 return GENERAL_REGS;
05442 }
05443
05444
05445
05446
05447 static bool
05448 arm_return_in_msb (tree valtype)
05449 {
05450 return (TARGET_AAPCS_BASED
05451 && BYTES_BIG_ENDIAN
05452 && (AGGREGATE_TYPE_P (valtype)
05453 || TREE_CODE (valtype) == COMPLEX_TYPE));
05454 }
05455
05456
05457
05458
05459 static bool
05460 arm_memory_load_p (rtx insn)
05461 {
05462 rtx body, lhs, rhs;;
05463
05464 if (insn == NULL_RTX || GET_CODE (insn) != INSN)
05465 return false;
05466
05467 body = PATTERN (insn);
05468
05469 if (GET_CODE (body) != SET)
05470 return false;
05471
05472 lhs = XEXP (body, 0);
05473 rhs = XEXP (body, 1);
05474
05475 lhs = REG_OR_SUBREG_RTX (lhs);
05476
05477
05478
05479 if (GET_CODE (lhs) != REG
05480 || REGNO_REG_CLASS (REGNO (lhs)) != GENERAL_REGS)
05481 return false;
05482
05483
05484
05485
05486 return (GET_CODE (rhs) == MEM
05487 || GET_CODE (rhs) == SYMBOL_REF
05488 || note_invalid_constants (insn, -1, false));
05489 }
05490
05491
05492 static bool
05493 arm_cirrus_insn_p (rtx insn)
05494 {
05495 enum attr_cirrus attr;
05496
05497
05498 if (!insn
05499 || GET_CODE (insn) != INSN
05500 || GET_CODE (PATTERN (insn)) == USE
05501 || GET_CODE (PATTERN (insn)) == CLOBBER)
05502 return 0;
05503
05504 attr = get_attr_cirrus (insn);
05505
05506 return attr != CIRRUS_NOT;
05507 }
05508
05509
05510 static void
05511 cirrus_reorg (rtx first)
05512 {
05513 enum attr_cirrus attr;
05514 rtx body = PATTERN (first);
05515 rtx t;
05516 int nops;
05517
05518
05519 if (GET_CODE (first) == JUMP_INSN && GET_CODE (body) != RETURN)
05520 {
05521 nops = 0;
05522 t = next_nonnote_insn (first);
05523
05524 if (arm_cirrus_insn_p (t))
05525 ++ nops;
05526
05527 if (arm_cirrus_insn_p (next_nonnote_insn (t)))
05528 ++ nops;
05529
05530 while (nops --)
05531 emit_insn_after (gen_nop (), first);
05532
05533 return;
05534 }
05535
05536
05537 if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
05538 body = XVECEXP (body, 0, 0);
05539
05540 if (GET_CODE (body) == SET)
05541 {
05542 rtx lhs = XEXP (body, 0), rhs = XEXP (body, 1);
05543
05544
05545
05546 if (get_attr_cirrus (first) == CIRRUS_DOUBLE)
05547 {
05548 if (arm_cirrus_insn_p (next_nonnote_insn (first)))
05549 emit_insn_after (gen_nop (), first);
05550
05551 return;
05552 }
05553 else if (arm_memory_load_p (first))
05554 {
05555 unsigned int arm_regno;
05556
05557
05558
05559
05560
05561
05562
05563
05564
05565
05566
05567 if (GET_CODE (lhs) == REG)
05568 arm_regno = REGNO (lhs);
05569 else
05570 {
05571 gcc_assert (GET_CODE (rhs) == REG);
05572 arm_regno = REGNO (rhs);
05573 }
05574
05575
05576 first = next_nonnote_insn (first);
05577
05578 if (! arm_cirrus_insn_p (first))
05579 return;
05580
05581 body = PATTERN (first);
05582
05583
05584 if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0))
05585 body = XVECEXP (body, 0, 0);
05586
05587 if (GET_CODE (body) == FLOAT)
05588 body = XEXP (body, 0);
05589
05590 if (get_attr_cirrus (first) == CIRRUS_MOVE
05591 && GET_CODE (XEXP (body, 1)) == REG
05592 && arm_regno == REGNO (XEXP (body, 1)))
05593 emit_insn_after (gen_nop (), first);
05594
05595 return;
05596 }
05597 }
05598
05599
05600 if (!first
05601 || GET_CODE (first) != INSN
05602 || GET_CODE (PATTERN (first)) == USE
05603 || GET_CODE (PATTERN (first)) == CLOBBER)
05604 return;
05605
05606 attr = get_attr_cirrus (first);
05607
05608
05609
05610 if (attr == CIRRUS_COMPARE)
05611 {
05612 nops = 0;
05613
05614 t = next_nonnote_insn (first);
05615
05616 if (arm_cirrus_insn_p (t))
05617 ++ nops;
05618
05619 if (arm_cirrus_insn_p (next_nonnote_insn (t)))
05620 ++ nops;
05621
05622 while (nops --)
05623 emit_insn_after (gen_nop (), first);
05624
05625 return;
05626 }
05627 }
05628
05629
05630 int
05631 symbol_mentioned_p (rtx x)
05632 {
05633 const char * fmt;
05634 int i;
05635
05636 if (GET_CODE (x) == SYMBOL_REF)
05637 return 1;
05638
05639
05640
05641 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
05642 return 0;
05643
05644 fmt = GET_RTX_FORMAT (GET_CODE (x));
05645
05646 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
05647 {
05648 if (fmt[i] == 'E')
05649 {
05650 int j;
05651
05652 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
05653 if (symbol_mentioned_p (XVECEXP (x, i, j)))
05654 return 1;
05655 }
05656 else if (fmt[i] == 'e' && symbol_mentioned_p (XEXP (x, i)))
05657 return 1;
05658 }
05659
05660 return 0;
05661 }
05662
05663
05664 int
05665 label_mentioned_p (rtx x)
05666 {
05667 const char * fmt;
05668 int i;
05669
05670 if (GET_CODE (x) == LABEL_REF)
05671 return 1;
05672
05673
05674
05675 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
05676 return 0;
05677
05678 fmt = GET_RTX_FORMAT (GET_CODE (x));
05679 for (i = GET_RTX_LENGTH (GET_CODE (x)) - 1; i >= 0; i--)
05680 {
05681 if (fmt[i] == 'E')
05682 {
05683 int j;
05684
05685 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
05686 if (label_mentioned_p (XVECEXP (x, i, j)))
05687 return 1;
05688 }
05689 else if (fmt[i] == 'e' && label_mentioned_p (XEXP (x, i)))
05690 return 1;
05691 }
05692
05693 return 0;
05694 }
05695
05696 int
05697 tls_mentioned_p (rtx x)
05698 {
05699 switch (GET_CODE (x))
05700 {
05701 case CONST:
05702 return tls_mentioned_p (XEXP (x, 0));
05703
05704 case UNSPEC:
05705 if (XINT (x, 1) == UNSPEC_TLS)
05706 return 1;
05707
05708 default:
05709 return 0;
05710 }
05711 }
05712
05713
05714
05715 static bool
05716 arm_cannot_copy_insn_p (rtx insn)
05717 {
05718 rtx pat = PATTERN (insn);
05719
05720 if (GET_CODE (pat) == PARALLEL
05721 && GET_CODE (XVECEXP (pat, 0, 0)) == SET)
05722 {
05723 rtx rhs = SET_SRC (XVECEXP (pat, 0, 0));
05724
05725 if (GET_CODE (rhs) == UNSPEC
05726 && XINT (rhs, 1) == UNSPEC_PIC_BASE)
05727 return TRUE;
05728
05729 if (GET_CODE (rhs) == MEM
05730 && GET_CODE (XEXP (rhs, 0)) == UNSPEC
05731 && XINT (XEXP (rhs, 0), 1) == UNSPEC_PIC_BASE)
05732 return TRUE;
05733 }
05734
05735 return FALSE;
05736 }
05737
05738 enum rtx_code
05739 minmax_code (rtx x)
05740 {
05741 enum rtx_code code = GET_CODE (x);
05742
05743 switch (code)
05744 {
05745 case SMAX:
05746 return GE;
05747 case SMIN:
05748 return LE;
05749 case UMIN:
05750 return LEU;
05751 case UMAX:
05752 return GEU;
05753 default:
05754 gcc_unreachable ();
05755 }
05756 }
05757
05758
05759 int
05760 adjacent_mem_locations (rtx a, rtx b)
05761 {
05762
05763 if (volatile_refs_p (a) || volatile_refs_p (b))
05764 return 0;
05765
05766 if ((GET_CODE (XEXP (a, 0)) == REG
05767 || (GET_CODE (XEXP (a, 0)) == PLUS
05768 && GET_CODE (XEXP (XEXP (a, 0), 1)) == CONST_INT))
05769 && (GET_CODE (XEXP (b, 0)) == REG
05770 || (GET_CODE (XEXP (b, 0)) == PLUS
05771 && GET_CODE (XEXP (XEXP (b, 0), 1)) == CONST_INT)))
05772 {
05773 HOST_WIDE_INT val0 = 0, val1 = 0;
05774 rtx reg0, reg1;
05775 int val_diff;
05776
05777 if (GET_CODE (XEXP (a, 0)) == PLUS)
05778 {
05779 reg0 = XEXP (XEXP (a, 0), 0);
05780 val0 = INTVAL (XEXP (XEXP (a, 0), 1));
05781 }
05782 else
05783 reg0 = XEXP (a, 0);
05784
05785 if (GET_CODE (XEXP (b, 0)) == PLUS)
05786 {
05787 reg1 = XEXP (XEXP (b, 0), 0);
05788 val1 = INTVAL (XEXP (XEXP (b, 0), 1));
05789 }
05790 else
05791 reg1 = XEXP (b, 0);
05792
05793
05794
05795
05796 if (!const_ok_for_op (PLUS, val0) || !const_ok_for_op (PLUS, val1))
05797 return 0;
05798
05799
05800
05801 if (arm_eliminable_register (reg0))
05802 return 0;
05803
05804 val_diff = val1 - val0;
05805
05806 if (arm_ld_sched)
05807 {
05808
05809
05810
05811 return (optimize_size && (REGNO (reg0) == REGNO (reg1))
05812 && (val0 == 0 || val1 == 0 || val0 == 4 || val1 == 4)
05813 && (val_diff == 4 || val_diff == -4));
05814 }
05815
05816 return ((REGNO (reg0) == REGNO (reg1))
05817 && (val_diff == 4 || val_diff == -4));
05818 }
05819
05820 return 0;
05821 }
05822
05823 int
05824 load_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
05825 HOST_WIDE_INT *load_offset)
05826 {
05827 int unsorted_regs[4];
05828 HOST_WIDE_INT unsorted_offsets[4];
05829 int order[4];
05830 int base_reg = -1;
05831 int i;
05832
05833
05834
05835 gcc_assert (nops >= 2 && nops <= 4);
05836
05837
05838
05839
05840
05841 for (i = 0; i < nops; i++)
05842 {
05843 rtx reg;
05844 rtx offset;
05845
05846
05847 if (GET_CODE (operands[nops + i]) == SUBREG)
05848 operands[nops + i] = alter_subreg (operands + (nops + i));
05849
05850 gcc_assert (GET_CODE (operands[nops + i]) == MEM);
05851
05852
05853
05854 if (MEM_VOLATILE_P (operands[nops + i]))
05855 return 0;
05856
05857 offset = const0_rtx;
05858
05859 if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
05860 || (GET_CODE (reg) == SUBREG
05861 && GET_CODE (reg = SUBREG_REG (reg)) == REG))
05862 || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
05863 && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
05864 == REG)
05865 || (GET_CODE (reg) == SUBREG
05866 && GET_CODE (reg = SUBREG_REG (reg)) == REG))
05867 && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
05868 == CONST_INT)))
05869 {
05870 if (i == 0)
05871 {
05872 base_reg = REGNO (reg);
05873 unsorted_regs[0] = (GET_CODE (operands[i]) == REG
05874 ? REGNO (operands[i])
05875 : REGNO (SUBREG_REG (operands[i])));
05876 order[0] = 0;
05877 }
05878 else
05879 {
05880 if (base_reg != (int) REGNO (reg))
05881
05882 return 0;
05883
05884 unsorted_regs[i] = (GET_CODE (operands[i]) == REG
05885 ? REGNO (operands[i])
05886 : REGNO (SUBREG_REG (operands[i])));
05887 if (unsorted_regs[i] < unsorted_regs[order[0]])
05888 order[0] = i;
05889 }
05890
05891
05892
05893
05894 if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14
05895 || (i != nops - 1 && unsorted_regs[i] == base_reg))
05896 return 0;
05897
05898 unsorted_offsets[i] = INTVAL (offset);
05899 }
05900 else
05901
05902 return 0;
05903 }
05904
05905
05906
05907
05908
05909
05910
05911 for (i = 1; i < nops; i++)
05912 {
05913 int j;
05914
05915 order[i] = order[i - 1];
05916 for (j = 0; j < nops; j++)
05917 if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
05918 && (order[i] == order[i - 1]
05919 || unsorted_regs[j] < unsorted_regs[order[i]]))
05920 order[i] = j;
05921
05922
05923
05924 if (order[i] == order[i - 1])
05925 return 0;
05926
05927
05928 if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
05929 return 0;
05930 }
05931
05932 if (base)
05933 {
05934 *base = base_reg;
05935
05936 for (i = 0; i < nops; i++)
05937 regs[i] = unsorted_regs[order[i]];
05938
05939 *load_offset = unsorted_offsets[order[0]];
05940 }
05941
05942 if (unsorted_offsets[order[0]] == 0)
05943 return 1;
05944
05945 if (unsorted_offsets[order[0]] == 4)
05946 return 2;
05947
05948 if (unsorted_offsets[order[nops - 1]] == 0)
05949 return 3;
05950
05951 if (unsorted_offsets[order[nops - 1]] == -4)
05952 return 4;
05953
05954
05955
05956
05957
05958
05959
05960
05961
05962
05963
05964
05965
05966
05967
05968
05969
05970
05971
05972
05973
05974
05975
05976
05977
05978
05979
05980
05981
05982
05983 if (nops == 2 && arm_ld_sched)
05984 return 0;
05985
05986
05987
05988 return (const_ok_for_arm (unsorted_offsets[order[0]])
05989 || const_ok_for_arm (-unsorted_offsets[order[0]])) ? 5 : 0;
05990 }
05991
05992 const char *
05993 emit_ldm_seq (rtx *operands, int nops)
05994 {
05995 int regs[4];
05996 int base_reg;
05997 HOST_WIDE_INT offset;
05998 char buf[100];
05999 int i;
06000
06001 switch (load_multiple_sequence (operands, nops, regs, &base_reg, &offset))
06002 {
06003 case 1:
06004 strcpy (buf, "ldm%?ia\t");
06005 break;
06006
06007 case 2:
06008 strcpy (buf, "ldm%?ib\t");
06009 break;
06010
06011 case 3:
06012 strcpy (buf, "ldm%?da\t");
06013 break;
06014
06015 case 4:
06016 strcpy (buf, "ldm%?db\t");
06017 break;
06018
06019 case 5:
06020 if (offset >= 0)
06021 sprintf (buf, "add%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
06022 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
06023 (long) offset);
06024 else
06025 sprintf (buf, "sub%%?\t%s%s, %s%s, #%ld", REGISTER_PREFIX,
06026 reg_names[regs[0]], REGISTER_PREFIX, reg_names[base_reg],
06027 (long) -offset);
06028 output_asm_insn (buf, operands);
06029 base_reg = regs[0];
06030 strcpy (buf, "ldm%?ia\t");
06031 break;
06032
06033 default:
06034 gcc_unreachable ();
06035 }
06036
06037 sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
06038 reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
06039
06040 for (i = 1; i < nops; i++)
06041 sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
06042 reg_names[regs[i]]);
06043
06044 strcat (buf, "}\t%@ phole ldm");
06045
06046 output_asm_insn (buf, operands);
06047 return "";
06048 }
06049
06050 int
06051 store_multiple_sequence (rtx *operands, int nops, int *regs, int *base,
06052 HOST_WIDE_INT * load_offset)
06053 {
06054 int unsorted_regs[4];
06055 HOST_WIDE_INT unsorted_offsets[4];
06056 int order[4];
06057 int base_reg = -1;
06058 int i;
06059
06060
06061
06062 gcc_assert (nops >= 2 && nops <= 4);
06063
06064
06065
06066
06067
06068 for (i = 0; i < nops; i++)
06069 {
06070 rtx reg;
06071 rtx offset;
06072
06073
06074 if (GET_CODE (operands[nops + i]) == SUBREG)
06075 operands[nops + i] = alter_subreg (operands + (nops + i));
06076
06077 gcc_assert (GET_CODE (operands[nops + i]) == MEM);
06078
06079
06080
06081 if (MEM_VOLATILE_P (operands[nops + i]))
06082 return 0;
06083
06084 offset = const0_rtx;
06085
06086 if ((GET_CODE (reg = XEXP (operands[nops + i], 0)) == REG
06087 || (GET_CODE (reg) == SUBREG
06088 && GET_CODE (reg = SUBREG_REG (reg)) == REG))
06089 || (GET_CODE (XEXP (operands[nops + i], 0)) == PLUS
06090 && ((GET_CODE (reg = XEXP (XEXP (operands[nops + i], 0), 0))
06091 == REG)
06092 || (GET_CODE (reg) == SUBREG
06093 && GET_CODE (reg = SUBREG_REG (reg)) == REG))
06094 && (GET_CODE (offset = XEXP (XEXP (operands[nops + i], 0), 1))
06095 == CONST_INT)))
06096 {
06097 if (i == 0)
06098 {
06099 base_reg = REGNO (reg);
06100 unsorted_regs[0] = (GET_CODE (operands[i]) == REG
06101 ? REGNO (operands[i])
06102 : REGNO (SUBREG_REG (operands[i])));
06103 order[0] = 0;
06104 }
06105 else
06106 {
06107 if (base_reg != (int) REGNO (reg))
06108
06109 return 0;
06110
06111 unsorted_regs[i] = (GET_CODE (operands[i]) == REG
06112 ? REGNO (operands[i])
06113 : REGNO (SUBREG_REG (operands[i])));
06114 if (unsorted_regs[i] < unsorted_regs[order[0]])
06115 order[0] = i;
06116 }
06117
06118
06119 if (unsorted_regs[i] < 0 || unsorted_regs[i] > 14)
06120 return 0;
06121
06122 unsorted_offsets[i] = INTVAL (offset);
06123 }
06124 else
06125
06126 return 0;
06127 }
06128
06129
06130
06131
06132
06133
06134
06135 for (i = 1; i < nops; i++)
06136 {
06137 int j;
06138
06139 order[i] = order[i - 1];
06140 for (j = 0; j < nops; j++)
06141 if (unsorted_regs[j] > unsorted_regs[order[i - 1]]
06142 && (order[i] == order[i - 1]
06143 || unsorted_regs[j] < unsorted_regs[order[i]]))
06144 order[i] = j;
06145
06146
06147
06148 if (order[i] == order[i - 1])
06149 return 0;
06150
06151
06152 if (unsorted_offsets[order[i]] != unsorted_offsets[order[i - 1]] + 4)
06153 return 0;
06154 }
06155
06156 if (base)
06157 {
06158 *base = base_reg;
06159
06160 for (i = 0; i < nops; i++)
06161 regs[i] = unsorted_regs[order[i]];
06162
06163 *load_offset = unsorted_offsets[order[0]];
06164 }
06165
06166 if (unsorted_offsets[order[0]] == 0)
06167 return 1;
06168
06169 if (unsorted_offsets[order[0]] == 4)
06170 return 2;
06171
06172 if (unsorted_offsets[order[nops - 1]] == 0)
06173 return 3;
06174
06175 if (unsorted_offsets[order[nops - 1]] == -4)
06176 return 4;
06177
06178 return 0;
06179 }
06180
06181 const char *
06182 emit_stm_seq (rtx *operands, int nops)
06183 {
06184 int regs[4];
06185 int base_reg;
06186 HOST_WIDE_INT offset;
06187 char buf[100];
06188 int i;
06189
06190 switch (store_multiple_sequence (operands, nops, regs, &base_reg, &offset))
06191 {
06192 case 1:
06193 strcpy (buf, "stm%?ia\t");
06194 break;
06195
06196 case 2:
06197 strcpy (buf, "stm%?ib\t");
06198 break;
06199
06200 case 3:
06201 strcpy (buf, "stm%?da\t");
06202 break;
06203
06204 case 4:
06205 strcpy (buf, "stm%?db\t");
06206 break;
06207
06208 default:
06209 gcc_unreachable ();
06210 }
06211
06212 sprintf (buf + strlen (buf), "%s%s, {%s%s", REGISTER_PREFIX,
06213 reg_names[base_reg], REGISTER_PREFIX, reg_names[regs[0]]);
06214
06215 for (i = 1; i < nops; i++)
06216 sprintf (buf + strlen (buf), ", %s%s", REGISTER_PREFIX,
06217 reg_names[regs[i]]);
06218
06219 strcat (buf, "}\t%@ phole stm");
06220
06221 output_asm_insn (buf, operands);
06222 return "";
06223 }
06224
06225
06226
06227 rtx
06228 arm_gen_load_multiple (int base_regno, int count, rtx from, int up,
06229 int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
06230 {
06231 HOST_WIDE_INT offset = *offsetp;
06232 int i = 0, j;
06233 rtx result;
06234 int sign = up ? 1 : -1;
06235 rtx mem, addr;
06236
06237
06238
06239
06240
06241
06242
06243
06244
06245
06246
06247
06248
06249
06250
06251
06252
06253
06254
06255
06256
06257
06258
06259
06260
06261
06262
06263
06264
06265 if (arm_tune_xscale && count <= 2 && ! optimize_size)
06266 {
06267 rtx seq;
06268
06269 start_sequence ();
06270
06271 for (i = 0; i < count; i++)
06272 {
06273 addr = plus_constant (from, i * 4 * sign);
06274 mem = adjust_automodify_address (basemem, SImode, addr, offset);
06275 emit_move_insn (gen_rtx_REG (SImode, base_regno + i), mem);
06276 offset += 4 * sign;
06277 }
06278
06279 if (write_back)
06280 {
06281 emit_move_insn (from, plus_constant (from, count * 4 * sign));
06282 *offsetp = offset;
06283 }
06284
06285 seq = get_insns ();
06286 end_sequence ();
06287
06288 return seq;
06289 }
06290
06291 result = gen_rtx_PARALLEL (VOIDmode,
06292 rtvec_alloc (count + (write_back ? 1 : 0)));
06293 if (write_back)
06294 {
06295 XVECEXP (result, 0, 0)
06296 = gen_rtx_SET (VOIDmode, from, plus_constant (from, count * 4 * sign));
06297 i = 1;
06298 count++;
06299 }
06300
06301 for (j = 0; i < count; i++, j++)
06302 {
06303 addr = plus_constant (from, j * 4 * sign);
06304 mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
06305 XVECEXP (result, 0, i)
06306 = gen_rtx_SET (VOIDmode, gen_rtx_REG (SImode, base_regno + j), mem);
06307 offset += 4 * sign;
06308 }
06309
06310 if (write_back)
06311 *offsetp = offset;
06312
06313 return result;
06314 }
06315
06316 rtx
06317 arm_gen_store_multiple (int base_regno, int count, rtx to, int up,
06318 int write_back, rtx basemem, HOST_WIDE_INT *offsetp)
06319 {
06320 HOST_WIDE_INT offset = *offsetp;
06321 int i = 0, j;
06322 rtx result;
06323 int sign = up ? 1 : -1;
06324 rtx mem, addr;
06325
06326
06327
06328 if (arm_tune_xscale && count <= 2 && ! optimize_size)
06329 {
06330 rtx seq;
06331
06332 start_sequence ();
06333
06334 for (i = 0; i < count; i++)
06335 {
06336 addr = plus_constant (to, i * 4 * sign);
06337 mem = adjust_automodify_address (basemem, SImode, addr, offset);
06338 emit_move_insn (mem, gen_rtx_REG (SImode, base_regno + i));
06339 offset += 4 * sign;
06340 }
06341
06342 if (write_back)
06343 {
06344 emit_move_insn (to, plus_constant (to, count * 4 * sign));
06345 *offsetp = offset;
06346 }
06347
06348 seq = get_insns ();
06349 end_sequence ();
06350
06351 return seq;
06352 }
06353
06354 result = gen_rtx_PARALLEL (VOIDmode,
06355 rtvec_alloc (count + (write_back ? 1 : 0)));
06356 if (write_back)
06357 {
06358 XVECEXP (result, 0, 0)
06359 = gen_rtx_SET (VOIDmode, to,
06360 plus_constant (to, count * 4 * sign));
06361 i = 1;
06362 count++;
06363 }
06364
06365 for (j = 0; i < count; i++, j++)
06366 {
06367 addr = plus_constant (to, j * 4 * sign);
06368 mem = adjust_automodify_address_nv (basemem, SImode, addr, offset);
06369 XVECEXP (result, 0, i)
06370 = gen_rtx_SET (VOIDmode, mem, gen_rtx_REG (SImode, base_regno + j));
06371 offset += 4 * sign;
06372 }
06373
06374 if (write_back)
06375 *offsetp = offset;
06376
06377 return result;
06378 }
06379
06380 int
06381 arm_gen_movmemqi (rtx *operands)
06382 {
06383 HOST_WIDE_INT in_words_to_go, out_words_to_go, last_bytes;
06384 HOST_WIDE_INT srcoffset, dstoffset;
06385 int i;
06386 rtx src, dst, srcbase, dstbase;
06387 rtx part_bytes_reg = NULL;
06388 rtx mem;
06389
06390 if (GET_CODE (operands[2]) != CONST_INT
06391 || GET_CODE (operands[3]) != CONST_INT
06392 || INTVAL (operands[2]) > 64
06393 || INTVAL (operands[3]) & 3)
06394 return 0;
06395
06396 dstbase = operands[0];
06397 srcbase = operands[1];
06398
06399 dst = copy_to_mode_reg (SImode, XEXP (dstbase, 0));
06400 src = copy_to_mode_reg (SImode, XEXP (srcbase, 0));
06401
06402 in_words_to_go = ARM_NUM_INTS (INTVAL (operands[2]));
06403 out_words_to_go = INTVAL (operands[2]) / 4;
06404 last_bytes = INTVAL (operands[2]) & 3;
06405 dstoffset = srcoffset = 0;
06406
06407 if (out_words_to_go != in_words_to_go && ((in_words_to_go - 1) & 3) != 0)
06408 part_bytes_reg = gen_rtx_REG (SImode, (in_words_to_go - 1) & 3);
06409
06410 for (i = 0; in_words_to_go >= 2; i+=4)
06411 {
06412 if (in_words_to_go > 4)
06413 emit_insn (arm_gen_load_multiple (0, 4, src, TRUE, TRUE,
06414 srcbase, &srcoffset));
06415 else
06416 emit_insn (arm_gen_load_multiple (0, in_words_to_go, src, TRUE,
06417 FALSE, srcbase, &srcoffset));
06418
06419 if (out_words_to_go)
06420 {
06421 if (out_words_to_go > 4)
06422 emit_insn (arm_gen_store_multiple (0, 4, dst, TRUE, TRUE,
06423 dstbase, &dstoffset));
06424 else if (out_words_to_go != 1)
06425 emit_insn (arm_gen_store_multiple (0, out_words_to_go,
06426 dst, TRUE,
06427 (last_bytes == 0
06428 ? FALSE : TRUE),
06429 dstbase, &dstoffset));
06430 else
06431 {
06432 mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
06433 emit_move_insn (mem, gen_rtx_REG (SImode, 0));
06434 if (last_bytes != 0)
06435 {
06436 emit_insn (gen_addsi3 (dst, dst, GEN_INT (4)));
06437 dstoffset += 4;
06438 }
06439 }
06440 }
06441
06442 in_words_to_go -= in_words_to_go < 4 ? in_words_to_go : 4;
06443 out_words_to_go -= out_words_to_go < 4 ? out_words_to_go : 4;
06444 }
06445
06446
06447 if (out_words_to_go)
06448 {
06449 rtx sreg;
06450
06451 mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
06452 sreg = copy_to_reg (mem);
06453
06454 mem = adjust_automodify_address (dstbase, SImode, dst, dstoffset);
06455 emit_move_insn (mem, sreg);
06456 in_words_to_go--;
06457
06458 gcc_assert (!in_words_to_go);
06459 }
06460
06461 if (in_words_to_go)
06462 {
06463 gcc_assert (in_words_to_go > 0);
06464
06465 mem = adjust_automodify_address (srcbase, SImode, src, srcoffset);
06466 part_bytes_reg = copy_to_mode_reg (SImode, mem);
06467 }
06468
06469 gcc_assert (!last_bytes || part_bytes_reg);
06470
06471 if (BYTES_BIG_ENDIAN && last_bytes)
06472 {
06473 rtx tmp = gen_reg_rtx (SImode);
06474
06475
06476 emit_insn (gen_lshrsi3 (tmp, part_bytes_reg,
06477 GEN_INT (8 * (4 - last_bytes))));
06478 part_bytes_reg = tmp;
06479
06480 while (last_bytes)
06481 {
06482 mem = adjust_automodify_address (dstbase, QImode,
06483 plus_constant (dst, last_bytes - 1),
06484 dstoffset + last_bytes - 1);
06485 emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
06486
06487 if (--last_bytes)
06488 {
06489 tmp = gen_reg_rtx (SImode);
06490 emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (8)));
06491 part_bytes_reg = tmp;
06492 }
06493 }
06494
06495 }
06496 else
06497 {
06498 if (last_bytes > 1)
06499 {
06500 mem = adjust_automodify_address (dstbase, HImode, dst, dstoffset);
06501 emit_move_insn (mem, gen_lowpart (HImode, part_bytes_reg));
06502 last_bytes -= 2;
06503 if (last_bytes)
06504 {
06505 rtx tmp = gen_reg_rtx (SImode);
06506 emit_insn (gen_addsi3 (dst, dst, const2_rtx));
06507 emit_insn (gen_lshrsi3 (tmp, part_bytes_reg, GEN_INT (16)));
06508 part_bytes_reg = tmp;
06509 dstoffset += 2;
06510 }
06511 }
06512
06513 if (last_bytes)
06514 {
06515 mem = adjust_automodify_address (dstbase, QImode, dst, dstoffset);
06516 emit_move_insn (mem, gen_lowpart (QImode, part_bytes_reg));
06517 }
06518 }
06519
06520 return 1;
06521 }
06522
06523
06524
06525
06526
06527
06528
06529
06530
06531
06532 enum machine_mode
06533 arm_select_dominance_cc_mode (rtx x, rtx y, HOST_WIDE_INT cond_or)
06534 {
06535 enum rtx_code cond1, cond2;
06536 int swapped = 0;
06537
06538
06539
06540
06541 if ((arm_select_cc_mode (cond1 = GET_CODE (x), XEXP (x, 0), XEXP (x, 1))
06542 != CCmode)
06543 || (arm_select_cc_mode (cond2 = GET_CODE (y), XEXP (y, 0), XEXP (y, 1))
06544 != CCmode))
06545 return CCmode;
06546
06547
06548
06549
06550 if (cond_or == DOM_CC_NX_OR_Y)
06551 cond1 = reverse_condition (cond1);
06552
06553
06554
06555 if (cond1 != cond2
06556 && !comparison_dominates_p (cond1, cond2)
06557 && (swapped = 1, !comparison_dominates_p (cond2, cond1)))
06558 return CCmode;
06559
06560 if (swapped)
06561 {
06562 enum rtx_code temp = cond1;
06563 cond1 = cond2;
06564 cond2 = temp;
06565 }
06566
06567 switch (cond1)
06568 {
06569 case EQ:
06570 if (cond_or == DOM_CC_X_AND_Y)
06571 return CC_DEQmode;
06572
06573 switch (cond2)
06574 {
06575 case EQ: return CC_DEQmode;
06576 case LE: return CC_DLEmode;
06577 case LEU: return CC_DLEUmode;
06578 case GE: return CC_DGEmode;
06579 case GEU: return CC_DGEUmode;
06580 default: gcc_unreachable ();
06581 }
06582
06583 case LT:
06584 if (cond_or == DOM_CC_X_AND_Y)
06585 return CC_DLTmode;
06586
06587 switch (cond2)
06588 {
06589 case LT:
06590 return CC_DLTmode;
06591 case LE:
06592 return CC_DLEmode;
06593 case NE:
06594 return CC_DNEmode;
06595 default:
06596 gcc_unreachable ();
06597 }
06598
06599 case GT:
06600 if (cond_or == DOM_CC_X_AND_Y)
06601 return CC_DGTmode;
06602
06603 switch (cond2)
06604 {
06605 case GT:
06606 return CC_DGTmode;
06607 case GE:
06608 return CC_DGEmode;
06609 case NE:
06610 return CC_DNEmode;
06611 default:
06612 gcc_unreachable ();
06613 }
06614
06615 case LTU:
06616 if (cond_or == DOM_CC_X_AND_Y)
06617 return CC_DLTUmode;
06618
06619 switch (cond2)
06620 {
06621 case LTU:
06622 return CC_DLTUmode;
06623 case LEU:
06624 return CC_DLEUmode;
06625 case NE:
06626 return CC_DNEmode;
06627 default:
06628 gcc_unreachable ();
06629 }
06630
06631 case GTU:
06632 if (cond_or == DOM_CC_X_AND_Y)
06633 return CC_DGTUmode;
06634
06635 switch (cond2)
06636 {
06637 case GTU:
06638 return CC_DGTUmode;
06639 case GEU:
06640 return CC_DGEUmode;
06641 case NE:
06642 return CC_DNEmode;
06643 default:
06644 gcc_unreachable ();
06645 }
06646
06647
06648
06649 case NE:
06650 gcc_assert (cond1 == cond2);
06651 return CC_DNEmode;
06652
06653 case LE:
06654 gcc_assert (cond1 == cond2);
06655 return CC_DLEmode;
06656
06657 case GE:
06658 gcc_assert (cond1 == cond2);
06659 return CC_DGEmode;
06660
06661 case LEU:
06662 gcc_assert (cond1 == cond2);
06663 return CC_DLEUmode;
06664
06665 case GEU:
06666 gcc_assert (cond1 == cond2);
06667 return CC_DGEUmode;
06668
06669 default:
06670 gcc_unreachable ();
06671 }
06672 }
06673
06674 enum machine_mode
06675 arm_select_cc_mode (enum rtx_code op, rtx x, rtx y)
06676 {
06677
06678
06679 if (GET_MODE_CLASS (GET_MODE (x)) == MODE_FLOAT)
06680 {
06681 switch (op)
06682 {
06683 case EQ:
06684 case NE:
06685 case UNORDERED:
06686 case ORDERED:
06687 case UNLT:
06688 case UNLE:
06689 case UNGT:
06690 case UNGE:
06691 case UNEQ:
06692 case LTGT:
06693 return CCFPmode;
06694
06695 case LT:
06696 case LE:
06697 case GT:
06698 case GE:
06699 if (TARGET_HARD_FLOAT && TARGET_MAVERICK)
06700 return CCFPmode;
06701 return CCFPEmode;
06702
06703 default:
06704 gcc_unreachable ();
06705 }
06706 }
06707
06708
06709
06710 if (GET_MODE (y) == SImode && GET_CODE (y) == REG
06711 && (GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
06712 || GET_CODE (x) == LSHIFTRT || GET_CODE (x) == ROTATE
06713 || GET_CODE (x) == ROTATERT))
06714 return CC_SWPmode;
06715
06716
06717
06718 if (GET_MODE (y) == SImode && REG_P (y)
06719 && GET_CODE (x) == NEG
06720 && (op == EQ || op == NE))
06721 return CC_Zmode;
06722
06723
06724
06725
06726
06727 if (GET_MODE (x) == SImode
06728 && GET_CODE (x) == ASHIFT
06729 && GET_CODE (XEXP (x, 1)) == CONST_INT && INTVAL (XEXP (x, 1)) == 24
06730 && GET_CODE (XEXP (x, 0)) == SUBREG
06731 && GET_CODE (SUBREG_REG (XEXP (x, 0))) == MEM
06732 && GET_MODE (SUBREG_REG (XEXP (x, 0))) == QImode
06733 && (op == EQ || op == NE
06734 || op == GEU || op == GTU || op == LTU || op == LEU)
06735 && GET_CODE (y) == CONST_INT)
06736 return CC_Zmode;
06737
06738
06739
06740
06741
06742 if (GET_CODE (x) == IF_THEN_ELSE
06743 && (XEXP (x, 2) == const0_rtx
06744 || XEXP (x, 2) == const1_rtx)
06745 && COMPARISON_P (XEXP (x, 0))
06746 && COMPARISON_P (XEXP (x, 1)))
06747 return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
06748 INTVAL (XEXP (x, 2)));
06749
06750
06751 if (GET_CODE (x) == AND
06752 && COMPARISON_P (XEXP (x, 0))
06753 && COMPARISON_P (XEXP (x, 1)))
06754 return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
06755 DOM_CC_X_AND_Y);
06756
06757 if (GET_CODE (x) == IOR
06758 && COMPARISON_P (XEXP (x, 0))
06759 && COMPARISON_P (XEXP (x, 1)))
06760 return arm_select_dominance_cc_mode (XEXP (x, 0), XEXP (x, 1),
06761 DOM_CC_X_OR_Y);
06762
06763
06764
06765
06766 if (TARGET_THUMB
06767 && GET_MODE (x) == SImode
06768 && (op == EQ || op == NE)
06769 && GET_CODE (x) == ZERO_EXTRACT
06770 && XEXP (x, 1) == const1_rtx)
06771 return CC_Nmode;
06772
06773
06774
06775
06776
06777 if (GET_MODE (x) == SImode
06778 && y == const0_rtx
06779 && (op == EQ || op == NE || op == LT || op == GE)
06780 && (GET_CODE (x) == PLUS || GET_CODE (x) == MINUS
06781 || GET_CODE (x) == AND || GET_CODE (x) == IOR
06782 || GET_CODE (x) == XOR || GET_CODE (x) == MULT
06783 || GET_CODE (x) == NOT || GET_CODE (x) == NEG
06784 || GET_CODE (x) == LSHIFTRT
06785 || GET_CODE (x) == ASHIFT || GET_CODE (x) == ASHIFTRT
06786 || GET_CODE (x) == ROTATERT
06787 || (TARGET_ARM && GET_CODE (x) == ZERO_EXTRACT)))
06788 return CC_NOOVmode;
06789
06790 if (GET_MODE (x) == QImode && (op == EQ || op == NE))
06791 return CC_Zmode;
06792
06793 if (GET_MODE (x) == SImode && (op == LTU || op == GEU)
06794 && GET_CODE (x) == PLUS
06795 && (rtx_equal_p (XEXP (x, 0), y) || rtx_equal_p (XEXP (x, 1), y)))
06796 return CC_Cmode;
06797
06798 return CCmode;
06799 }
06800
06801
06802
06803
06804 rtx
06805 arm_gen_compare_reg (enum rtx_code code, rtx x, rtx y)
06806 {
06807 enum machine_mode mode = SELECT_CC_MODE (code, x, y);
06808 rtx cc_reg = gen_rtx_REG (mode, CC_REGNUM);
06809
06810 emit_set_insn (cc_reg, gen_rtx_COMPARE (mode, x, y));
06811
06812 return cc_reg;
06813 }
06814
06815
06816
06817
06818 rtx
06819 arm_gen_return_addr_mask (void)
06820 {
06821 rtx reg = gen_reg_rtx (Pmode);
06822
06823 emit_insn (gen_return_addr_mask (reg));
06824 return reg;
06825 }
06826
06827 void
06828 arm_reload_in_hi (rtx *operands)
06829 {
06830 rtx ref = operands[1];
06831 rtx base, scratch;
06832 HOST_WIDE_INT offset = 0;
06833
06834 if (GET_CODE (ref) == SUBREG)
06835 {
06836 offset = SUBREG_BYTE (ref);
06837 ref = SUBREG_REG (ref);
06838 }
06839
06840 if (GET_CODE (ref) == REG)
06841 {
06842
06843
06844
06845
06846 if (reg_equiv_mem[REGNO (ref)])
06847 {
06848 ref = reg_equiv_mem[REGNO (ref)];
06849 base = find_replacement (&XEXP (ref, 0));
06850 }
06851 else
06852
06853 base = reg_equiv_address[REGNO (ref)];
06854 }
06855 else
06856 base = find_replacement (&XEXP (ref, 0));
06857
06858
06859 if (GET_CODE (base) == MINUS
06860 || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
06861 {
06862 rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
06863
06864 emit_set_insn (base_plus, base);
06865 base = base_plus;
06866 }
06867 else if (GET_CODE (base) == PLUS)
06868 {
06869
06870 HOST_WIDE_INT hi, lo;
06871
06872 offset += INTVAL (XEXP (base, 1));
06873 base = XEXP (base, 0);
06874
06875
06876
06877 lo = (offset >= 0
06878 ? (offset & 0xfff)
06879 : -((-offset) & 0xfff));
06880
06881
06882
06883
06884 if (lo == 4095)
06885 lo &= 0x7ff;
06886
06887 hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
06888 ^ (HOST_WIDE_INT) 0x80000000)
06889 - (HOST_WIDE_INT) 0x80000000);
06890
06891 gcc_assert (hi + lo == offset);
06892
06893 if (hi != 0)
06894 {
06895 rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
06896
06897
06898
06899 emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
06900 base = base_plus;
06901 offset = lo;
06902 }
06903 }
06904
06905
06906
06907
06908 if (REGNO (operands[2]) == REGNO (operands[0]))
06909 scratch = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
06910 else
06911 scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
06912
06913 emit_insn (gen_zero_extendqisi2 (scratch,
06914 gen_rtx_MEM (QImode,
06915 plus_constant (base,
06916 offset))));
06917 emit_insn (gen_zero_extendqisi2 (gen_rtx_SUBREG (SImode, operands[0], 0),
06918 gen_rtx_MEM (QImode,
06919 plus_constant (base,
06920 offset + 1))));
06921 if (!BYTES_BIG_ENDIAN)
06922 emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
06923 gen_rtx_IOR (SImode,
06924 gen_rtx_ASHIFT
06925 (SImode,
06926 gen_rtx_SUBREG (SImode, operands[0], 0),
06927 GEN_INT (8)),
06928 scratch));
06929 else
06930 emit_set_insn (gen_rtx_SUBREG (SImode, operands[0], 0),
06931 gen_rtx_IOR (SImode,
06932 gen_rtx_ASHIFT (SImode, scratch,
06933 GEN_INT (8)),
06934 gen_rtx_SUBREG (SImode, operands[0], 0)));
06935 }
06936
06937
06938
06939
06940
06941
06942
06943 void
06944 arm_reload_out_hi (rtx *operands)
06945 {
06946 rtx ref = operands[0];
06947 rtx outval = operands[1];
06948 rtx base, scratch;
06949 HOST_WIDE_INT offset = 0;
06950
06951 if (GET_CODE (ref) == SUBREG)
06952 {
06953 offset = SUBREG_BYTE (ref);
06954 ref = SUBREG_REG (ref);
06955 }
06956
06957 if (GET_CODE (ref) == REG)
06958 {
06959
06960
06961
06962
06963 if (reg_equiv_mem[REGNO (ref)])
06964 {
06965 ref = reg_equiv_mem[REGNO (ref)];
06966 base = find_replacement (&XEXP (ref, 0));
06967 }
06968 else
06969
06970 base = reg_equiv_address[REGNO (ref)];
06971 }
06972 else
06973 base = find_replacement (&XEXP (ref, 0));
06974
06975 scratch = gen_rtx_REG (SImode, REGNO (operands[2]));
06976
06977
06978 if (GET_CODE (base) == MINUS
06979 || (GET_CODE (base) == PLUS && GET_CODE (XEXP (base, 1)) != CONST_INT))
06980 {
06981 rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
06982
06983
06984 if (reg_overlap_mentioned_p (base_plus, outval))
06985 {
06986
06987
06988 if (!reg_overlap_mentioned_p (scratch, outval))
06989 {
06990 rtx tmp = scratch;
06991 scratch = base_plus;
06992 base_plus = tmp;
06993 }
06994 else
06995 {
06996 rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
06997
06998
06999
07000
07001
07002
07003
07004 emit_insn (gen_movhi (scratch_hi, outval));
07005 outval = scratch_hi;
07006 }
07007 }
07008
07009 emit_set_insn (base_plus, base);
07010 base = base_plus;
07011 }
07012 else if (GET_CODE (base) == PLUS)
07013 {
07014
07015 HOST_WIDE_INT hi, lo;
07016
07017 offset += INTVAL (XEXP (base, 1));
07018 base = XEXP (base, 0);
07019
07020
07021
07022 lo = (offset >= 0
07023 ? (offset & 0xfff)
07024 : -((-offset) & 0xfff));
07025
07026
07027
07028
07029 if (lo == 4095)
07030 lo &= 0x7ff;
07031
07032 hi = ((((offset - lo) & (HOST_WIDE_INT) 0xffffffff)
07033 ^ (HOST_WIDE_INT) 0x80000000)
07034 - (HOST_WIDE_INT) 0x80000000);
07035
07036 gcc_assert (hi + lo == offset);
07037
07038 if (hi != 0)
07039 {
07040 rtx base_plus = gen_rtx_REG (SImode, REGNO (operands[2]) + 1);
07041
07042
07043 if (reg_overlap_mentioned_p (base_plus, outval))
07044 {
07045
07046
07047 if (!reg_overlap_mentioned_p (scratch, outval))
07048 {
07049 rtx tmp = scratch;
07050 scratch = base_plus;
07051 base_plus = tmp;
07052 }
07053 else
07054 {
07055 rtx scratch_hi = gen_rtx_REG (HImode, REGNO (operands[2]));
07056
07057
07058
07059
07060
07061
07062
07063 emit_insn (gen_movhi (scratch_hi, outval));
07064 outval = scratch_hi;
07065 }
07066 }
07067
07068
07069
07070 emit_insn (gen_addsi3 (base_plus, base, GEN_INT (hi)));
07071 base = base_plus;
07072 offset = lo;
07073 }
07074 }
07075
07076 if (BYTES_BIG_ENDIAN)
07077 {
07078 emit_insn (gen_movqi (gen_rtx_MEM (QImode,
07079 plus_constant (base, offset + 1)),
07080 gen_lowpart (QImode, outval)));
07081 emit_insn (gen_lshrsi3 (scratch,
07082 gen_rtx_SUBREG (SImode, outval, 0),
07083 GEN_INT (8)));
07084 emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
07085 gen_lowpart (QImode, scratch)));
07086 }
07087 else
07088 {
07089 emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (base, offset)),
07090 gen_lowpart (QImode, outval)));
07091 emit_insn (gen_lshrsi3 (scratch,
07092 gen_rtx_SUBREG (SImode, outval, 0),
07093 GEN_INT (8)));
07094 emit_insn (gen_movqi (gen_rtx_MEM (QImode,
07095 plus_constant (base, offset + 1)),
07096 gen_lowpart (QImode, scratch)));
07097 }
07098 }
07099
07100
07101
07102
07103 static bool
07104 arm_must_pass_in_stack (enum machine_mode mode, tree type)
07105 {
07106 if (TARGET_AAPCS_BASED)
07107 return must_pass_in_stack_var_size (mode, type);
07108 else
07109 return must_pass_in_stack_var_size_or_pad (mode, type);
07110 }
07111
07112
07113
07114
07115
07116
07117
07118
07119 bool
07120 arm_pad_arg_upward (enum machine_mode mode, tree type)
07121 {
07122 if (!TARGET_AAPCS_BASED)
07123 return DEFAULT_FUNCTION_ARG_PADDING(mode, type) == upward;
07124
07125 if (type && BYTES_BIG_ENDIAN && INTEGRAL_TYPE_P (type))
07126 return false;
07127
07128 return true;
07129 }
07130
07131
07132
07133
07134
07135
07136
07137
07138
07139 bool
07140 arm_pad_reg_upward (enum machine_mode mode ATTRIBUTE_UNUSED,
07141 tree type, int first ATTRIBUTE_UNUSED)
07142 {
07143 if (TARGET_AAPCS_BASED
07144 && BYTES_BIG_ENDIAN
07145 && (AGGREGATE_TYPE_P (type) || TREE_CODE (type) == COMPLEX_TYPE)
07146 && int_size_in_bytes (type) <= 4)
07147 return true;
07148
07149
07150 return !BYTES_BIG_ENDIAN;
07151 }
07152
07153
07154
07155 static void
07156 arm_print_value (FILE *f, rtx x)
07157 {
07158 switch (GET_CODE (x))
07159 {
07160 case CONST_INT:
07161 fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (x));
07162 return;
07163
07164 case CONST_DOUBLE:
07165 fprintf (f, "<0x%lx,0x%lx>", (long)XWINT (x, 2), (long)XWINT (x, 3));
07166 return;
07167
07168 case CONST_VECTOR:
07169 {
07170 int i;
07171
07172 fprintf (f, "<");
07173 for (i = 0; i < CONST_VECTOR_NUNITS (x); i++)
07174 {
07175 fprintf (f, HOST_WIDE_INT_PRINT_HEX, INTVAL (CONST_VECTOR_ELT (x, i)));
07176 if (i < (CONST_VECTOR_NUNITS (x) - 1))
07177 fputc (',', f);
07178 }
07179 fprintf (f, ">");
07180 }
07181 return;
07182
07183 case CONST_STRING:
07184 fprintf (f, "\"%s\"", XSTR (x, 0));
07185 return;
07186
07187 case SYMBOL_REF:
07188 fprintf (f, "`%s'", XSTR (x, 0));
07189 return;
07190
07191 case LABEL_REF:
07192 fprintf (f, "L%d", INSN_UID (XEXP (x, 0)));
07193 return;
07194
07195 case CONST:
07196 arm_print_value (f, XEXP (x, 0));
07197 return;
07198
07199 case PLUS:
07200 arm_print_value (f, XEXP (x, 0));
07201 fprintf (f, "+");
07202 arm_print_value (f, XEXP (x, 1));
07203 return;
07204
07205 case PC:
07206 fprintf (f, "pc");
07207 return;
07208
07209 default:
07210 fprintf (f, "????");
07211 return;
07212 }
07213 }
07214
07215
07216
07217
07218
07219
07220
07221
07222
07223
07224
07225
07226
07227
07228
07229
07230
07231
07232
07233
07234
07235
07236
07237
07238
07239
07240
07241
07242
07243
07244
07245
07246
07247
07248
07249
07250
07251
07252
07253
07254
07255
07256
07257
07258
07259
07260
07261
07262
07263
07264
07265
07266
07267
07268
07269
07270
07271
07272
07273
07274
07275
07276
07277
07278
07279
07280
07281
07282 struct minipool_node
07283 {
07284
07285 Mnode * next;
07286 Mnode * prev;
07287
07288
07289
07290 HOST_WIDE_INT max_address;
07291
07292 HOST_WIDE_INT min_address;
07293
07294
07295
07296 int refcount;
07297
07298 HOST_WIDE_INT offset;
07299
07300 rtx value;
07301
07302 enum machine_mode mode;
07303
07304
07305 int fix_size;
07306 };
07307
07308 struct minipool_fixup
07309 {
07310 Mfix * next;
07311 rtx insn;
07312 HOST_WIDE_INT address;
07313 rtx * loc;
07314 enum machine_mode mode;
07315 int fix_size;
07316 rtx value;
07317 Mnode * minipool;
07318 HOST_WIDE_INT forwards;
07319 HOST_WIDE_INT backwards;
07320 };
07321
07322
07323 #define MINIPOOL_FIX_SIZE(mode) \
07324 (GET_MODE_SIZE ((mode)) >= 4 ? GET_MODE_SIZE ((mode)) : 4)
07325
07326 static Mnode * minipool_vector_head;
07327 static Mnode * minipool_vector_tail;
07328 static rtx minipool_vector_label;
07329 static int minipool_pad;
07330
07331
07332 Mfix * minipool_fix_head;
07333 Mfix * minipool_fix_tail;
07334
07335 Mfix * minipool_barrier;
07336
07337
07338
07339 static rtx
07340 is_jump_table (rtx insn)
07341 {
07342 rtx table;
07343
07344 if (GET_CODE (insn) == JUMP_INSN
07345 && JUMP_LABEL (insn) != NULL
07346 && ((table = next_real_insn (JUMP_LABEL (insn)))
07347 == next_real_insn (insn))
07348 && table != NULL
07349 && GET_CODE (table) == JUMP_INSN
07350 && (GET_CODE (PATTERN (table)) == ADDR_VEC
07351 || GET_CODE (PATTERN (table)) == ADDR_DIFF_VEC))
07352 return table;
07353
07354 return NULL_RTX;
07355 }
07356
07357 #ifndef JUMP_TABLES_IN_TEXT_SECTION
07358 #define JUMP_TABLES_IN_TEXT_SECTION 0
07359 #endif
07360
07361 static HOST_WIDE_INT
07362 get_jump_table_size (rtx insn)
07363 {
07364
07365
07366 if (JUMP_TABLES_IN_TEXT_SECTION || readonly_data_section == text_section)
07367 {
07368 rtx body = PATTERN (insn);
07369 int elt = GET_CODE (body) == ADDR_DIFF_VEC ? 1 : 0;
07370
07371 return GET_MODE_SIZE (GET_MODE (body)) * XVECLEN (body, elt);
07372 }
07373
07374 return 0;
07375 }
07376
07377
07378
07379
07380 static Mnode *
07381 move_minipool_fix_forward_ref (Mnode *mp, Mnode *max_mp,
07382 HOST_WIDE_INT max_address)
07383 {
07384
07385 gcc_assert (mp != max_mp);
07386
07387 if (max_mp == NULL)
07388 {
07389 if (max_address < mp->max_address)
07390 mp->max_address = max_address;
07391 }
07392 else
07393 {
07394 if (max_address > max_mp->max_address - mp->fix_size)
07395 mp->max_address = max_mp->max_address - mp->fix_size;
07396 else
07397 mp->max_address = max_address;
07398
07399
07400
07401 mp->prev->next = mp->next;
07402 if (mp->next != NULL)
07403 mp->next->prev = mp->prev;
07404 else
07405 minipool_vector_tail = mp->prev;
07406
07407
07408 mp->next = max_mp;
07409 mp->prev = max_mp->prev;
07410 max_mp->prev = mp;
07411
07412 if (mp->prev != NULL)
07413 mp->prev->next = mp;
07414 else
07415 minipool_vector_head = mp;
07416 }
07417
07418
07419 max_mp = mp;
07420
07421
07422
07423 while (mp->prev != NULL
07424 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
07425 {
07426 mp->prev->max_address = mp->max_address - mp->prev->fix_size;
07427 mp = mp->prev;
07428 }
07429
07430 return max_mp;
07431 }
07432
07433
07434
07435 static Mnode *
07436 add_minipool_forward_ref (Mfix *fix)
07437 {
07438
07439
07440 Mnode * max_mp = NULL;
07441 HOST_WIDE_INT max_address = fix->address + fix->forwards - minipool_pad;
07442 Mnode * mp;
07443
07444
07445
07446
07447
07448 if (minipool_vector_head &&
07449 (fix->address + get_attr_length (fix->insn)
07450 >= minipool_vector_head->max_address - fix->fix_size))
07451 return NULL;
07452
07453
07454
07455
07456
07457 for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
07458 {
07459 if (GET_CODE (fix->value) == GET_CODE (mp->value)
07460 && fix->mode == mp->mode
07461 && (GET_CODE (fix->value) != CODE_LABEL
07462 || (CODE_LABEL_NUMBER (fix->value)
07463 == CODE_LABEL_NUMBER (mp->value)))
07464 && rtx_equal_p (fix->value, mp->value))
07465 {
07466
07467 mp->refcount++;
07468 return move_minipool_fix_forward_ref (mp, max_mp, max_address);
07469 }
07470
07471
07472 if (max_mp == NULL
07473 && mp->max_address > max_address)
07474 max_mp = mp;
07475
07476
07477
07478
07479
07480 if (ARM_DOUBLEWORD_ALIGN
07481 && max_mp == NULL
07482 && fix->fix_size == 8
07483 && mp->fix_size != 8)
07484 {
07485 max_mp = mp;
07486 max_address = mp->max_address;
07487 }
07488 }
07489
07490
07491
07492
07493
07494
07495
07496 mp = XNEW (Mnode);
07497 mp->fix_size = fix->fix_size;
07498 mp->mode = fix->mode;
07499 mp->value = fix->value;
07500 mp->refcount = 1;
07501
07502 mp->min_address = -65536;
07503
07504 if (max_mp == NULL)
07505 {
07506 mp->max_address = max_address;
07507 mp->next = NULL;
07508 mp->prev = minipool_vector_tail;
07509
07510 if (mp->prev == NULL)
07511 {
07512 minipool_vector_head = mp;
07513 minipool_vector_label = gen_label_rtx ();
07514 }
07515 else
07516 mp->prev->next = mp;
07517
07518 minipool_vector_tail = mp;
07519 }
07520 else
07521 {
07522 if (max_address > max_mp->max_address - mp->fix_size)
07523 mp->max_address = max_mp->max_address - mp->fix_size;
07524 else
07525 mp->max_address = max_address;
07526
07527 mp->next = max_mp;
07528 mp->prev = max_mp->prev;
07529 max_mp->prev = mp;
07530 if (mp->prev != NULL)
07531 mp->prev->next = mp;
07532 else
07533 minipool_vector_head = mp;
07534 }
07535
07536
07537 max_mp = mp;
07538
07539
07540
07541 while (mp->prev != NULL
07542 && mp->prev->max_address > mp->max_address - mp->prev->fix_size)
07543 {
07544 mp->prev->max_address = mp->max_address - mp->prev->fix_size;
07545 mp = mp->prev;
07546 }
07547
07548 return max_mp;
07549 }
07550
07551 static Mnode *
07552 move_minipool_fix_backward_ref (Mnode *mp, Mnode *min_mp,
07553 HOST_WIDE_INT min_address)
07554 {
07555 HOST_WIDE_INT offset;
07556
07557
07558 gcc_assert (mp != min_mp);
07559
07560 if (min_mp == NULL)
07561 {
07562 if (min_address > mp->min_address)
07563 mp->min_address = min_address;
07564 }
07565 else
07566 {
07567
07568 mp->min_address = min_address;
07569
07570
07571
07572 mp->next->prev = mp->prev;
07573 if (mp->prev != NULL)
07574 mp->prev->next = mp->next;
07575 else
07576 minipool_vector_head = mp->next;
07577
07578
07579 mp->prev = min_mp;
07580 mp->next = min_mp->next;
07581 min_mp->next = mp;
07582 if (mp->next != NULL)
07583 mp->next->prev = mp;
07584 else
07585 minipool_vector_tail = mp;
07586 }
07587
07588 min_mp = mp;
07589
07590 offset = 0;
07591 for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
07592 {
07593 mp->offset = offset;
07594 if (mp->refcount > 0)
07595 offset += mp->fix_size;
07596
07597 if (mp->next && mp->next->min_address < mp->min_address + mp->fix_size)
07598 mp->next->min_address = mp->min_address + mp->fix_size;
07599 }
07600
07601 return min_mp;
07602 }
07603
07604
07605
07606
07607
07608
07609
07610
07611 static Mnode *
07612 add_minipool_backward_ref (Mfix *fix)
07613 {
07614
07615
07616 Mnode *min_mp = NULL;
07617
07618 HOST_WIDE_INT min_address = fix->address - fix->backwards;
07619 Mnode *mp;
07620
07621
07622
07623
07624
07625 if (min_address >= minipool_barrier->address
07626 || (minipool_vector_tail->min_address + fix->fix_size
07627 >= minipool_barrier->address))
07628 return NULL;
07629
07630
07631
07632
07633
07634 for (mp = minipool_vector_tail; mp != NULL; mp = mp->prev)
07635 {
07636 if (GET_CODE (fix->value) == GET_CODE (mp->value)
07637 && fix->mode == mp->mode
07638 && (GET_CODE (fix->value) != CODE_LABEL
07639 || (CODE_LABEL_NUMBER (fix->value)
07640 == CODE_LABEL_NUMBER (mp->value)))
07641 && rtx_equal_p (fix->value, mp->value)
07642
07643
07644 && (mp->max_address
07645 > (minipool_barrier->address
07646 + minipool_vector_tail->offset
07647 + minipool_vector_tail->fix_size)))
07648 {
07649 mp->refcount++;
07650 return move_minipool_fix_backward_ref (mp, min_mp, min_address);
07651 }
07652
07653 if (min_mp != NULL)
07654 mp->min_address += fix->fix_size;
07655 else
07656 {
07657
07658 if (mp->min_address < min_address)
07659 {
07660
07661
07662 if (ARM_DOUBLEWORD_ALIGN
07663 && fix->fix_size == 8 && mp->fix_size != 8)
07664 return NULL;
07665 else
07666 min_mp = mp;
07667 }
07668 else if (mp->max_address
07669 < minipool_barrier->address + mp->offset + fix->fix_size)
07670 {
07671
07672
07673
07674
07675 min_mp = mp;
07676 min_address = mp->min_address + fix->fix_size;
07677 }
07678
07679
07680
07681
07682 else if (ARM_DOUBLEWORD_ALIGN
07683 && min_mp == NULL
07684 && fix->fix_size == 8
07685 && mp->fix_size < 8)
07686 {
07687 min_mp = mp;
07688 min_address = mp->min_address + fix->fix_size;
07689 }
07690 }
07691 }
07692
07693
07694 mp = XNEW (Mnode);
07695 mp->fix_size = fix->fix_size;
07696 mp->mode = fix->mode;
07697 mp->value = fix->value;
07698 mp->refcount = 1;
07699 mp->max_address = minipool_barrier->address + 65536;
07700
07701 mp->min_address = min_address;
07702
07703 if (min_mp == NULL)
07704 {
07705 mp->prev = NULL;
07706 mp->next = minipool_vector_head;
07707
07708 if (mp->next == NULL)
07709 {
07710 minipool_vector_tail = mp;
07711 minipool_vector_label = gen_label_rtx ();
07712 }
07713 else
07714 mp->next->prev = mp;
07715
07716 minipool_vector_head = mp;
07717 }
07718 else
07719 {
07720 mp->next = min_mp->next;
07721 mp->prev = min_mp;
07722 min_mp->next = mp;
07723
07724 if (mp->next != NULL)
07725 mp->next->prev = mp;
07726 else
07727 minipool_vector_tail = mp;
07728 }
07729
07730
07731 min_mp = mp;
07732
07733 if (mp->prev)
07734 mp = mp->prev;
07735 else
07736 mp->offset = 0;
07737
07738
07739 while (mp->next != NULL)
07740 {
07741 if (mp->next->min_address < mp->min_address + mp->fix_size)
07742 mp->next->min_address = mp->min_address + mp->fix_size;
07743
07744 if (mp->refcount)
07745 mp->next->offset = mp->offset + mp->fix_size;
07746 else
07747 mp->next->offset = mp->offset;
07748
07749 mp = mp->next;
07750 }
07751
07752 return min_mp;
07753 }
07754
07755 static void
07756 assign_minipool_offsets (Mfix *barrier)
07757 {
07758 HOST_WIDE_INT offset = 0;
07759 Mnode *mp;
07760
07761 minipool_barrier = barrier;
07762
07763 for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
07764 {
07765 mp->offset = offset;
07766
07767 if (mp->refcount > 0)
07768 offset += mp->fix_size;
07769 }
07770 }
07771
07772
07773 static void
07774 dump_minipool (rtx scan)
07775 {
07776 Mnode * mp;
07777 Mnode * nmp;
07778 int align64 = 0;
07779
07780 if (ARM_DOUBLEWORD_ALIGN)
07781 for (mp = minipool_vector_head; mp != NULL; mp = mp->next)
07782 if (mp->refcount > 0 && mp->fix_size == 8)
07783 {
07784 align64 = 1;
07785 break;
07786 }
07787
07788 if (dump_file)
07789 fprintf (dump_file,
07790 ";; Emitting minipool after insn %u; address %ld; align %d (bytes)\n",
07791 INSN_UID (scan), (unsigned long) minipool_barrier->address, align64 ? 8 : 4);
07792
07793 scan = emit_label_after (gen_label_rtx (), scan);
07794 scan = emit_insn_after (align64 ? gen_align_8 () : gen_align_4 (), scan);
07795 scan = emit_label_after (minipool_vector_label, scan);
07796
07797 for (mp = minipool_vector_head; mp != NULL; mp = nmp)
07798 {
07799 if (mp->refcount > 0)
07800 {
07801 if (dump_file)
07802 {
07803 fprintf (dump_file,
07804 ";; Offset %u, min %ld, max %ld ",
07805 (unsigned) mp->offset, (unsigned long) mp->min_address,
07806 (unsigned long) mp->max_address);
07807 arm_print_value (dump_file, mp->value);
07808 fputc ('\n', dump_file);
07809 }
07810
07811 switch (mp->fix_size)
07812 {
07813 #ifdef HAVE_consttable_1
07814 case 1:
07815 scan = emit_insn_after (gen_consttable_1 (mp->value), scan);
07816 break;
07817
07818 #endif
07819 #ifdef HAVE_consttable_2
07820 case 2:
07821 scan = emit_insn_after (gen_consttable_2 (mp->value), scan);
07822 break;
07823
07824 #endif
07825 #ifdef HAVE_consttable_4
07826 case 4:
07827 scan = emit_insn_after (gen_consttable_4 (mp->value), scan);
07828 break;
07829
07830 #endif
07831 #ifdef HAVE_consttable_8
07832 case 8:
07833 scan = emit_insn_after (gen_consttable_8 (mp->value), scan);
07834 break;
07835
07836 #endif
07837 default:
07838 gcc_unreachable ();
07839 }
07840 }
07841
07842 nmp = mp->next;
07843 free (mp);
07844 }
07845
07846 minipool_vector_head = minipool_vector_tail = NULL;
07847 scan = emit_insn_after (gen_consttable_end (), scan);
07848 scan = emit_barrier_after (scan);
07849 }
07850
07851
07852 static int
07853 arm_barrier_cost (rtx insn)
07854 {
07855
07856
07857
07858 int base_cost = 50;
07859 rtx next = next_nonnote_insn (insn);
07860
07861 if (next != NULL && GET_CODE (next) == CODE_LABEL)
07862 base_cost -= 20;
07863
07864 switch (GET_CODE (insn))
07865 {
07866 case CODE_LABEL:
07867
07868
07869 return 50;
07870
07871 case INSN:
07872 case CALL_INSN:
07873 return base_cost;
07874
07875 case JUMP_INSN:
07876 return base_cost - 10;
07877
07878 default:
07879 return base_cost + 10;
07880 }
07881 }
07882
07883
07884
07885
07886
07887 static Mfix *
07888 create_fix_barrier (Mfix *fix, HOST_WIDE_INT max_address)
07889 {
07890 HOST_WIDE_INT count = 0;
07891 rtx barrier;
07892 rtx from = fix->insn;
07893
07894 rtx selected = NULL;
07895 int selected_cost;
07896
07897 HOST_WIDE_INT selected_address;
07898 Mfix * new_fix;
07899 HOST_WIDE_INT max_count = max_address - fix->address;
07900 rtx label = gen_label_rtx ();
07901
07902 selected_cost = arm_barrier_cost (from);
07903 selected_address = fix->address;
07904
07905 while (from && count < max_count)
07906 {
07907 rtx tmp;
07908 int new_cost;
07909
07910
07911
07912 gcc_assert (GET_CODE (from) != BARRIER);
07913
07914
07915 count += get_attr_length (from);
07916
07917
07918 tmp = is_jump_table (from);
07919 if (tmp != NULL)
07920 {
07921 count += get_jump_table_size (tmp);
07922
07923
07924
07925
07926 new_cost = arm_barrier_cost (from);
07927
07928 if (count < max_count
07929 && (!selected || new_cost <= selected_cost))
07930 {
07931 selected = tmp;
07932 selected_cost = new_cost;
07933 selected_address = fix->address + count;
07934 }
07935
07936
07937 from = NEXT_INSN (tmp);
07938 continue;
07939 }
07940
07941 new_cost = arm_barrier_cost (from);
07942
07943 if (count < max_count
07944 && (!selected || new_cost <= selected_cost))
07945 {
07946 selected = from;
07947 selected_cost = new_cost;
07948 selected_address = fix->address + count;
07949 }
07950
07951 from = NEXT_INSN (from);
07952 }
07953
07954
07955 gcc_assert (selected);
07956
07957
07958 from = emit_jump_insn_after (gen_jump (label), selected);
07959 JUMP_LABEL (from) = label;
07960 barrier = emit_barrier_after (from);
07961 emit_label_after (label, barrier);
07962
07963
07964 new_fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* new_fix));
07965 new_fix->insn = barrier;
07966 new_fix->address = selected_address;
07967 new_fix->next = fix->next;
07968 fix->next = new_fix;
07969
07970 return new_fix;
07971 }
07972
07973
07974
07975 static void
07976 push_minipool_barrier (rtx insn, HOST_WIDE_INT address)
07977 {
07978 Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
07979
07980 fix->insn = insn;
07981 fix->address = address;
07982
07983 fix->next = NULL;
07984 if (minipool_fix_head != NULL)
07985 minipool_fix_tail->next = fix;
07986 else
07987 minipool_fix_head = fix;
07988
07989 minipool_fix_tail = fix;
07990 }
07991
07992
07993
07994
07995
07996
07997 static void
07998 push_minipool_fix (rtx insn, HOST_WIDE_INT address, rtx *loc,
07999 enum machine_mode mode, rtx value)
08000 {
08001 Mfix * fix = (Mfix *) obstack_alloc (&minipool_obstack, sizeof (* fix));
08002
08003 #ifdef AOF_ASSEMBLER
08004
08005
08006
08007 if (flag_pic && GET_CODE (value) == SYMBOL_REF)
08008 value = aof_pic_entry (value);
08009 #endif
08010
08011 fix->insn = insn;
08012 fix->address = address;
08013 fix->loc = loc;
08014 fix->mode = mode;
08015 fix->fix_size = MINIPOOL_FIX_SIZE (mode);
08016 fix->value = value;
08017 fix->forwards = get_attr_pool_range (insn);
08018 fix->backwards = get_attr_neg_pool_range (insn);
08019 fix->minipool = NULL;
08020
08021
08022
08023
08024 gcc_assert (fix->forwards || fix->backwards);
08025
08026
08027
08028
08029 if (ARM_DOUBLEWORD_ALIGN && fix->fix_size == 8)
08030 minipool_pad = 4;
08031
08032 if (dump_file)
08033 {
08034 fprintf (dump_file,
08035 ";; %smode fixup for i%d; addr %lu, range (%ld,%ld): ",
08036 GET_MODE_NAME (mode),
08037 INSN_UID (insn), (unsigned long) address,
08038 -1 * (long)fix->backwards, (long)fix->forwards);
08039 arm_print_value (dump_file, fix->value);
08040 fprintf (dump_file, "\n");
08041 }
08042
08043
08044 fix->next = NULL;
08045
08046 if (minipool_fix_head != NULL)
08047 minipool_fix_tail->next = fix;
08048 else
08049 minipool_fix_head = fix;
08050
08051 minipool_fix_tail = fix;
08052 }
08053
08054
08055
08056
08057 int
08058 arm_const_double_inline_cost (rtx val)
08059 {
08060 rtx lowpart, highpart;
08061 enum machine_mode mode;
08062
08063 mode = GET_MODE (val);
08064
08065 if (mode == VOIDmode)
08066 mode = DImode;
08067
08068 gcc_assert (GET_MODE_SIZE (mode) == 8);
08069
08070 lowpart = gen_lowpart (SImode, val);
08071 highpart = gen_highpart_mode (SImode, mode, val);
08072
08073 gcc_assert (GET_CODE (lowpart) == CONST_INT);
08074 gcc_assert (GET_CODE (highpart) == CONST_INT);
08075
08076 return (arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (lowpart),
08077 NULL_RTX, NULL_RTX, 0, 0)
08078 + arm_gen_constant (SET, SImode, NULL_RTX, INTVAL (highpart),
08079 NULL_RTX, NULL_RTX, 0, 0));
08080 }
08081
08082
08083
08084
08085
08086 bool
08087 arm_const_double_by_parts (rtx val)
08088 {
08089 enum machine_mode mode = GET_MODE (val);
08090 rtx part;
08091
08092 if (optimize_size || arm_ld_sched)
08093 return true;
08094
08095 if (mode == VOIDmode)
08096 mode = DImode;
08097
08098 part = gen_highpart_mode (SImode, mode, val);
08099
08100 gcc_assert (GET_CODE (part) == CONST_INT);
08101
08102 if (const_ok_for_arm (INTVAL (part))
08103 || const_ok_for_arm (~INTVAL (part)))
08104 return true;
08105
08106 part = gen_lowpart (SImode, val);
08107
08108 gcc_assert (GET_CODE (part) == CONST_INT);
08109
08110 if (const_ok_for_arm (INTVAL (part))
08111 || const_ok_for_arm (~INTVAL (part)))
08112 return true;
08113
08114 return false;
08115 }
08116
08117
08118
08119
08120
08121
08122 static bool
08123 note_invalid_constants (rtx insn, HOST_WIDE_INT address, int do_pushes)
08124 {
08125 bool result = false;
08126 int opno;
08127
08128 extract_insn (insn);
08129
08130 if (!constrain_operands (1))
08131 fatal_insn_not_found (insn);
08132
08133 if (recog_data.n_alternatives == 0)
08134 return false;
08135
08136
08137
08138 preprocess_constraints ();
08139
08140 for (opno = 0; opno < recog_data.n_operands; opno++)
08141 {
08142
08143 if (recog_data.operand_type[opno] != OP_IN)
08144 continue;
08145
08146
08147
08148
08149
08150 if (recog_op_alt[opno][which_alternative].memory_ok)
08151 {
08152 rtx op = recog_data.operand[opno];
08153
08154 if (CONSTANT_P (op))
08155 {
08156 if (do_pushes)
08157 push_minipool_fix (insn, address, recog_data.operand_loc[opno],
08158 recog_data.operand_mode[opno], op);
08159 result = true;
08160 }
08161 else if (GET_CODE (op) == MEM
08162 && GET_CODE (XEXP (op, 0)) == SYMBOL_REF
08163 && CONSTANT_POOL_ADDRESS_P (XEXP (op, 0)))
08164 {
08165 if (do_pushes)
08166 {
08167 rtx cop = avoid_constant_pool_reference (op);
08168
08169
08170
08171
08172
08173
08174 if (op == cop)
08175 cop = get_pool_constant (XEXP (op, 0));
08176
08177 push_minipool_fix (insn, address,
08178 recog_data.operand_loc[opno],
08179 recog_data.operand_mode[opno], cop);
08180 }
08181
08182 result = true;
08183 }
08184 }
08185 }
08186
08187 return result;
08188 }
08189
08190
08191
08192
08193
08194 static void
08195 arm_reorg (void)
08196 {
08197 rtx insn;
08198 HOST_WIDE_INT address = 0;
08199 Mfix * fix;
08200
08201 minipool_fix_head = minipool_fix_tail = NULL;
08202
08203
08204
08205 insn = get_insns ();
08206 gcc_assert (GET_CODE (insn) == NOTE);
08207 minipool_pad = 0;
08208
08209
08210 for (insn = next_nonnote_insn (insn); insn; insn = next_nonnote_insn (insn))
08211 {
08212 if (TARGET_CIRRUS_FIX_INVALID_INSNS
08213 && (arm_cirrus_insn_p (insn)
08214 || GET_CODE (insn) == JUMP_INSN
08215 || arm_memory_load_p (insn)))
08216 cirrus_reorg (insn);
08217
08218 if (GET_CODE (insn) == BARRIER)
08219 push_minipool_barrier (insn, address);
08220 else if (INSN_P (insn))
08221 {
08222 rtx table;
08223
08224 note_invalid_constants (insn, address, true);
08225 address += get_attr_length (insn);
08226
08227
08228
08229 if ((table = is_jump_table (insn)) != NULL)
08230 {
08231 address += get_jump_table_size (table);
08232 insn = table;
08233 }
08234 }
08235 }
08236
08237 fix = minipool_fix_head;
08238
08239
08240 while (fix)
08241 {
08242 Mfix * ftmp;
08243 Mfix * fdel;
08244 Mfix * last_added_fix;
08245 Mfix * last_barrier = NULL;
08246 Mfix * this_fix;
08247
08248
08249 while (fix && GET_CODE (fix->insn) == BARRIER)
08250 fix = fix->next;
08251
08252
08253 if (fix == NULL)
08254 break;
08255
08256 last_added_fix = NULL;
08257
08258 for (ftmp = fix; ftmp; ftmp = ftmp->next)
08259 {
08260 if (GET_CODE (ftmp->insn) == BARRIER)
08261 {
08262 if (ftmp->address >= minipool_vector_head->max_address)
08263 break;
08264
08265 last_barrier = ftmp;
08266 }
08267 else if ((ftmp->minipool = add_minipool_forward_ref (ftmp)) == NULL)
08268 break;
08269
08270 last_added_fix = ftmp;
08271 }
08272
08273
08274
08275
08276 if (last_barrier != NULL)
08277 {
08278
08279
08280 for (fdel = last_barrier->next;
08281 fdel && fdel != ftmp;
08282 fdel = fdel->next)
08283 {
08284 fdel->minipool->refcount--;
08285 fdel->minipool = NULL;
08286 }
08287
08288 ftmp = last_barrier;
08289 }
08290 else
08291 {
08292
08293
08294
08295
08296 HOST_WIDE_INT max_address;
08297
08298
08299
08300
08301 gcc_assert (ftmp);
08302
08303 max_address = minipool_vector_head->max_address;
08304
08305
08306
08307
08308
08309
08310 if (ftmp->address < max_address)
08311 max_address = ftmp->address + 1;
08312
08313 last_barrier = create_fix_barrier (last_added_fix, max_address);
08314 }
08315
08316 assign_minipool_offsets (last_barrier);
08317
08318 while (ftmp)
08319 {
08320 if (GET_CODE (ftmp->insn) != BARRIER
08321 && ((ftmp->minipool = add_minipool_backward_ref (ftmp))
08322 == NULL))
08323 break;
08324
08325 ftmp = ftmp->next;
08326 }
08327
08328
08329
08330 for (this_fix = fix; this_fix && ftmp != this_fix;
08331 this_fix = this_fix->next)
08332 if (GET_CODE (this_fix->insn) != BARRIER)
08333 {
08334 rtx addr
08335 = plus_constant (gen_rtx_LABEL_REF (VOIDmode,
08336 minipool_vector_label),
08337 this_fix->minipool->offset);
08338 *this_fix->loc = gen_rtx_MEM (this_fix->mode, addr);
08339 }
08340
08341 dump_minipool (last_barrier->insn);
08342 fix = ftmp;
08343 }
08344
08345
08346
08347
08348 after_arm_reorg = 1;
08349
08350
08351 obstack_free (&minipool_obstack, minipool_startobj);
08352 }
08353
08354
08355
08356
08357
08358
08359 const char *
08360 fp_immediate_constant (rtx x)
08361 {
08362 REAL_VALUE_TYPE r;
08363 int i;
08364
08365 if (!fp_consts_inited)
08366 init_fp_table ();
08367
08368 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
08369 for (i = 0; i < 8; i++)
08370 if (REAL_VALUES_EQUAL (r, values_fp[i]))
08371 return strings_fp[i];
08372
08373 gcc_unreachable ();
08374 }
08375
08376
08377 static const char *
08378 fp_const_from_val (REAL_VALUE_TYPE *r)
08379 {
08380 int i;
08381
08382 if (!fp_consts_inited)
08383 init_fp_table ();
08384
08385 for (i = 0; i < 8; i++)
08386 if (REAL_VALUES_EQUAL (*r, values_fp[i]))
08387 return strings_fp[i];
08388
08389 gcc_unreachable ();
08390 }
08391
08392
08393
08394
08395
08396
08397 static void
08398 print_multi_reg (FILE *stream, const char *instr, unsigned reg,
08399 unsigned long mask)
08400 {
08401 unsigned i;
08402 bool not_first = FALSE;
08403
08404 fputc ('\t', stream);
08405 asm_fprintf (stream, instr, reg);
08406 fputs (", {", stream);
08407
08408 for (i = 0; i <= LAST_ARM_REGNUM; i++)
08409 if (mask & (1 << i))
08410 {
08411 if (not_first)
08412 fprintf (stream, ", ");
08413
08414 asm_fprintf (stream, "%r", i);
08415 not_first = TRUE;
08416 }
08417
08418 fprintf (stream, "}\n");
08419 }
08420
08421
08422
08423
08424
08425
08426
08427 static void
08428 arm_output_fldmx (FILE * stream, unsigned int base, int reg, int count)
08429 {
08430 int i;
08431
08432
08433 if (count == 2 && !arm_arch6)
08434 {
08435 if (reg == 15)
08436 reg--;
08437 count++;
08438 }
08439
08440 fputc ('\t', stream);
08441 asm_fprintf (stream, "fldmfdx\t%r!, {", base);
08442
08443 for (i = reg; i < reg + count; i++)
08444 {
08445 if (i > reg)
08446 fputs (", ", stream);
08447 asm_fprintf (stream, "d%d", i);
08448 }
08449 fputs ("}\n", stream);
08450
08451 }
08452
08453
08454
08455
08456 const char *
08457 vfp_output_fstmx (rtx * operands)
08458 {
08459 char pattern[100];
08460 int p;
08461 int base;
08462 int i;
08463
08464 strcpy (pattern, "fstmfdx\t%m0!, {%P1");
08465 p = strlen (pattern);
08466
08467 gcc_assert (GET_CODE (operands[1]) == REG);
08468
08469 base = (REGNO (operands[1]) - FIRST_VFP_REGNUM) / 2;
08470 for (i = 1; i < XVECLEN (operands[2], 0); i++)
08471 {
08472 p += sprintf (&pattern[p], ", d%d", base + i);
08473 }
08474 strcpy (&pattern[p], "}");
08475
08476 output_asm_insn (pattern, operands);
08477 return "";
08478 }
08479
08480
08481
08482
08483
08484 static int
08485 vfp_emit_fstmx (int base_reg, int count)
08486 {
08487 rtx par;
08488 rtx dwarf;
08489 rtx tmp, reg;
08490 int i;
08491
08492
08493
08494
08495 if (count == 2 && !arm_arch6)
08496 {
08497 if (base_reg == LAST_VFP_REGNUM - 3)
08498 base_reg -= 2;
08499 count++;
08500 }
08501
08502
08503
08504
08505
08506 par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
08507 dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
08508
08509 reg = gen_rtx_REG (DFmode, base_reg);
08510 base_reg += 2;
08511
08512 XVECEXP (par, 0, 0)
08513 = gen_rtx_SET (VOIDmode,
08514 gen_frame_mem (BLKmode,
08515 gen_rtx_PRE_DEC (BLKmode,
08516 stack_pointer_rtx)),
08517 gen_rtx_UNSPEC (BLKmode,
08518 gen_rtvec (1, reg),
08519 UNSPEC_PUSH_MULT));
08520
08521 tmp = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
08522 plus_constant (stack_pointer_rtx, -(count * 8 + 4)));
08523 RTX_FRAME_RELATED_P (tmp) = 1;
08524 XVECEXP (dwarf, 0, 0) = tmp;
08525
08526 tmp = gen_rtx_SET (VOIDmode,
08527 gen_frame_mem (DFmode, stack_pointer_rtx),
08528 reg);
08529 RTX_FRAME_RELATED_P (tmp) = 1;
08530 XVECEXP (dwarf, 0, 1) = tmp;
08531
08532 for (i = 1; i < count; i++)
08533 {
08534 reg = gen_rtx_REG (DFmode, base_reg);
08535 base_reg += 2;
08536 XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
08537
08538 tmp = gen_rtx_SET (VOIDmode,
08539 gen_frame_mem (DFmode,
08540 plus_constant (stack_pointer_rtx,
08541 i * 8)),
08542 reg);
08543 RTX_FRAME_RELATED_P (tmp) = 1;
08544 XVECEXP (dwarf, 0, i + 1) = tmp;
08545 }
08546
08547 par = emit_insn (par);
08548 REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
08549 REG_NOTES (par));
08550 RTX_FRAME_RELATED_P (par) = 1;
08551
08552 return count * 8 + 4;
08553 }
08554
08555
08556
08557 const char *
08558 output_call (rtx *operands)
08559 {
08560 gcc_assert (!arm_arch5);
08561
08562
08563 if (REGNO (operands[0]) == LR_REGNUM)
08564 {
08565 operands[0] = gen_rtx_REG (SImode, IP_REGNUM);
08566 output_asm_insn ("mov%?\t%0, %|lr", operands);
08567 }
08568
08569 output_asm_insn ("mov%?\t%|lr, %|pc", operands);
08570
08571 if (TARGET_INTERWORK || arm_arch4t)
08572 output_asm_insn ("bx%?\t%0", operands);
08573 else
08574 output_asm_insn ("mov%?\t%|pc, %0", operands);
08575
08576 return "";
08577 }
08578
08579
08580 const char *
08581 output_call_mem (rtx *operands)
08582 {
08583 if (TARGET_INTERWORK && !arm_arch5)
08584 {
08585 output_asm_insn ("ldr%?\t%|ip, %0", operands);
08586 output_asm_insn ("mov%?\t%|lr, %|pc", operands);
08587 output_asm_insn ("bx%?\t%|ip", operands);
08588 }
08589 else if (regno_use_in (LR_REGNUM, operands[0]))
08590 {
08591
08592
08593
08594 output_asm_insn ("ldr%?\t%|ip, %0", operands);
08595 if (arm_arch5)
08596 output_asm_insn ("blx%?\t%|ip", operands);
08597 else
08598 {
08599 output_asm_insn ("mov%?\t%|lr, %|pc", operands);
08600 if (arm_arch4t)
08601 output_asm_insn ("bx%?\t%|ip", operands);
08602 else
08603 output_asm_insn ("mov%?\t%|pc, %|ip", operands);
08604 }
08605 }
08606 else
08607 {
08608 output_asm_insn ("mov%?\t%|lr, %|pc", operands);
08609 output_asm_insn ("ldr%?\t%|pc, %0", operands);
08610 }
08611
08612 return "";
08613 }
08614
08615
08616
08617
08618
08619 const char *
08620 output_mov_long_double_fpa_from_arm (rtx *operands)
08621 {
08622 int arm_reg0 = REGNO (operands[1]);
08623 rtx ops[3];
08624
08625 gcc_assert (arm_reg0 != IP_REGNUM);
08626
08627 ops[0] = gen_rtx_REG (SImode, arm_reg0);
08628 ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
08629 ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
08630
08631 output_asm_insn ("stm%?fd\t%|sp!, {%0, %1, %2}", ops);
08632 output_asm_insn ("ldf%?e\t%0, [%|sp], #12", operands);
08633
08634 return "";
08635 }
08636
08637
08638
08639
08640 const char *
08641 output_mov_long_double_arm_from_fpa (rtx *operands)
08642 {
08643 int arm_reg0 = REGNO (operands[0]);
08644 rtx ops[3];
08645
08646 gcc_assert (arm_reg0 != IP_REGNUM);
08647
08648 ops[0] = gen_rtx_REG (SImode, arm_reg0);
08649 ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
08650 ops[2] = gen_rtx_REG (SImode, 2 + arm_reg0);
08651
08652 output_asm_insn ("stf%?e\t%1, [%|sp, #-12]!", operands);
08653 output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1, %2}", ops);
08654 return "";
08655 }
08656
08657
08658
08659
08660 const char *
08661 output_mov_long_double_arm_from_arm (rtx *operands)
08662 {
08663
08664 int dest_start = REGNO (operands[0]);
08665 int src_start = REGNO (operands[1]);
08666 rtx ops[2];
08667 int i;
08668
08669 if (dest_start < src_start)
08670 {
08671 for (i = 0; i < 3; i++)
08672 {
08673 ops[0] = gen_rtx_REG (SImode, dest_start + i);
08674 ops[1] = gen_rtx_REG (SImode, src_start + i);
08675 output_asm_insn ("mov%?\t%0, %1", ops);
08676 }
08677 }
08678 else
08679 {
08680 for (i = 2; i >= 0; i--)
08681 {
08682 ops[0] = gen_rtx_REG (SImode, dest_start + i);
08683 ops[1] = gen_rtx_REG (SImode, src_start + i);
08684 output_asm_insn ("mov%?\t%0, %1", ops);
08685 }
08686 }
08687
08688 return "";
08689 }
08690
08691
08692
08693
08694
08695 const char *
08696 output_mov_double_fpa_from_arm (rtx *operands)
08697 {
08698 int arm_reg0 = REGNO (operands[1]);
08699 rtx ops[2];
08700
08701 gcc_assert (arm_reg0 != IP_REGNUM);
08702
08703 ops[0] = gen_rtx_REG (SImode, arm_reg0);
08704 ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
08705 output_asm_insn ("stm%?fd\t%|sp!, {%0, %1}", ops);
08706 output_asm_insn ("ldf%?d\t%0, [%|sp], #8", operands);
08707 return "";
08708 }
08709
08710
08711
08712
08713 const char *
08714 output_mov_double_arm_from_fpa (rtx *operands)
08715 {
08716 int arm_reg0 = REGNO (operands[0]);
08717 rtx ops[2];
08718
08719 gcc_assert (arm_reg0 != IP_REGNUM);
08720
08721 ops[0] = gen_rtx_REG (SImode, arm_reg0);
08722 ops[1] = gen_rtx_REG (SImode, 1 + arm_reg0);
08723 output_asm_insn ("stf%?d\t%1, [%|sp, #-8]!", operands);
08724 output_asm_insn ("ldm%?fd\t%|sp!, {%0, %1}", ops);
08725 return "";
08726 }
08727
08728
08729
08730
08731 const char *
08732 output_move_double (rtx *operands)
08733 {
08734 enum rtx_code code0 = GET_CODE (operands[0]);
08735 enum rtx_code code1 = GET_CODE (operands[1]);
08736 rtx otherops[3];
08737
08738 if (code0 == REG)
08739 {
08740 int reg0 = REGNO (operands[0]);
08741
08742 otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
08743
08744 gcc_assert (code1 == MEM);
08745
08746 switch (GET_CODE (XEXP (operands[1], 0)))
08747 {
08748 case REG:
08749 output_asm_insn ("ldm%?ia\t%m1, %M0", operands);
08750 break;
08751
08752 case PRE_INC:
08753 gcc_assert (TARGET_LDRD);
08754 output_asm_insn ("ldr%?d\t%0, [%m1, #8]!", operands);
08755 break;
08756
08757 case PRE_DEC:
08758 output_asm_insn ("ldm%?db\t%m1!, %M0", operands);
08759 break;
08760
08761 case POST_INC:
08762 output_asm_insn ("ldm%?ia\t%m1!, %M0", operands);
08763 break;
08764
08765 case POST_DEC:
08766 gcc_assert (TARGET_LDRD);
08767 output_asm_insn ("ldr%?d\t%0, [%m1], #-8", operands);
08768 break;
08769
08770 case PRE_MODIFY:
08771 case POST_MODIFY:
08772 otherops[0] = operands[0];
08773 otherops[1] = XEXP (XEXP (XEXP (operands[1], 0), 1), 0);
08774 otherops[2] = XEXP (XEXP (XEXP (operands[1], 0), 1), 1);
08775
08776 if (GET_CODE (XEXP (operands[1], 0)) == PRE_MODIFY)
08777 {
08778 if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
08779 {
08780
08781 output_asm_insn ("add%?\t%1, %1, %2", otherops);
08782 output_asm_insn ("ldr%?d\t%0, [%1] @split", otherops);
08783 }
08784 else
08785 {
08786
08787
08788 if (GET_CODE (otherops[2]) == CONST_INT
08789 && (INTVAL(otherops[2]) <= -256
08790 || INTVAL(otherops[2]) >= 256))
08791 {
08792 output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
08793 otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
08794 output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
08795 }
08796 else
08797 output_asm_insn ("ldr%?d\t%0, [%1, %2]!", otherops);
08798 }
08799 }
08800 else
08801 {
08802
08803
08804 if (GET_CODE (otherops[2]) == CONST_INT
08805 && (INTVAL(otherops[2]) <= -256
08806 || INTVAL(otherops[2]) >= 256))
08807 {
08808 otherops[0] = gen_rtx_REG (SImode, 1 + reg0);
08809 output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
08810 otherops[0] = operands[0];
08811 output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
08812 }
08813 else
08814
08815 output_asm_insn ("ldr%?d\t%0, [%1], %2", otherops);
08816 }
08817 break;
08818
08819 case LABEL_REF:
08820 case CONST:
08821 output_asm_insn ("adr%?\t%0, %1", operands);
08822 output_asm_insn ("ldm%?ia\t%0, %M0", operands);
08823 break;
08824
08825 default:
08826 if (arm_add_operand (XEXP (XEXP (operands[1], 0), 1),
08827 GET_MODE (XEXP (XEXP (operands[1], 0), 1))))
08828 {
08829 otherops[0] = operands[0];
08830 otherops[1] = XEXP (XEXP (operands[1], 0), 0);
08831 otherops[2] = XEXP (XEXP (operands[1], 0), 1);
08832
08833 if (GET_CODE (XEXP (operands[1], 0)) == PLUS)
08834 {
08835 if (GET_CODE (otherops[2]) == CONST_INT)
08836 {
08837 switch ((int) INTVAL (otherops[2]))
08838 {
08839 case -8:
08840 output_asm_insn ("ldm%?db\t%1, %M0", otherops);
08841 return "";
08842 case -4:
08843 output_asm_insn ("ldm%?da\t%1, %M0", otherops);
08844 return "";
08845 case 4:
08846 output_asm_insn ("ldm%?ib\t%1, %M0", otherops);
08847 return "";
08848 }
08849 }
08850 if (TARGET_LDRD
08851 && (GET_CODE (otherops[2]) == REG
08852 || (GET_CODE (otherops[2]) == CONST_INT
08853 && INTVAL (otherops[2]) > -256
08854 && INTVAL (otherops[2]) < 256)))
08855 {
08856 if (reg_overlap_mentioned_p (otherops[0],
08857 otherops[2]))
08858 {
08859
08860
08861 otherops[1] = XEXP (XEXP (operands[1], 0), 1);
08862 otherops[2] = XEXP (XEXP (operands[1], 0), 0);
08863 }
08864
08865
08866 if (reg_overlap_mentioned_p (otherops[0], otherops[2]))
08867 {
08868 output_asm_insn ("add%?\t%1, %1, %2", otherops);
08869 output_asm_insn ("ldr%?d\t%0, [%1]",
08870 otherops);
08871 }
08872 else
08873 output_asm_insn ("ldr%?d\t%0, [%1, %2]", otherops);
08874 return "";
08875 }
08876
08877 if (GET_CODE (otherops[2]) == CONST_INT)
08878 {
08879 if (!(const_ok_for_arm (INTVAL (otherops[2]))))
08880 output_asm_insn ("sub%?\t%0, %1, #%n2", otherops);
08881 else
08882 output_asm_insn ("add%?\t%0, %1, %2", otherops);
08883 }
08884 else
08885 output_asm_insn ("add%?\t%0, %1, %2", otherops);
08886 }
08887 else
08888 output_asm_insn ("sub%?\t%0, %1, %2", otherops);
08889
08890 return "ldm%?ia\t%0, %M0";
08891 }
08892 else
08893 {
08894 otherops[1] = adjust_address (operands[1], SImode, 4);
08895
08896 if (reg_mentioned_p (operands[0], operands[1]))
08897 {
08898 output_asm_insn ("ldr%?\t%0, %1", otherops);
08899 output_asm_insn ("ldr%?\t%0, %1", operands);
08900 }
08901 else
08902 {
08903 output_asm_insn ("ldr%?\t%0, %1", operands);
08904 output_asm_insn ("ldr%?\t%0, %1", otherops);
08905 }
08906 }
08907 }
08908 }
08909 else
08910 {
08911
08912 gcc_assert (code0 == MEM && code1 == REG);
08913 gcc_assert (REGNO (operands[1]) != IP_REGNUM);
08914
08915 switch (GET_CODE (XEXP (operands[0], 0)))
08916 {
08917 case REG:
08918 output_asm_insn ("stm%?ia\t%m0, %M1", operands);
08919 break;
08920
08921 case PRE_INC:
08922 gcc_assert (TARGET_LDRD);
08923 output_asm_insn ("str%?d\t%1, [%m0, #8]!", operands);
08924 break;
08925
08926 case PRE_DEC:
08927 output_asm_insn ("stm%?db\t%m0!, %M1", operands);
08928 break;
08929
08930 case POST_INC:
08931 output_asm_insn ("stm%?ia\t%m0!, %M1", operands);
08932 break;
08933
08934 case POST_DEC:
08935 gcc_assert (TARGET_LDRD);
08936 output_asm_insn ("str%?d\t%1, [%m0], #-8", operands);
08937 break;
08938
08939 case PRE_MODIFY:
08940 case POST_MODIFY:
08941 otherops[0] = operands[1];
08942 otherops[1] = XEXP (XEXP (XEXP (operands[0], 0), 1), 0);
08943 otherops[2] = XEXP (XEXP (XEXP (operands[0], 0), 1), 1);
08944
08945
08946
08947 if (GET_CODE (otherops[2]) == CONST_INT
08948 && (INTVAL(otherops[2]) <= -256
08949 || INTVAL(otherops[2]) >= 256))
08950 {
08951 rtx reg1;
08952 reg1 = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
08953 if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
08954 {
08955 output_asm_insn ("ldr%?\t%0, [%1, %2]!", otherops);
08956 otherops[0] = reg1;
08957 output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
08958 }
08959 else
08960 {
08961 otherops[0] = reg1;
08962 output_asm_insn ("ldr%?\t%0, [%1, #4]", otherops);
08963 otherops[0] = operands[1];
08964 output_asm_insn ("ldr%?\t%0, [%1], %2", otherops);
08965 }
08966 }
08967 else if (GET_CODE (XEXP (operands[0], 0)) == PRE_MODIFY)
08968 output_asm_insn ("str%?d\t%0, [%1, %2]!", otherops);
08969 else
08970 output_asm_insn ("str%?d\t%0, [%1], %2", otherops);
08971 break;
08972
08973 case PLUS:
08974 otherops[2] = XEXP (XEXP (operands[0], 0), 1);
08975 if (GET_CODE (otherops[2]) == CONST_INT)
08976 {
08977 switch ((int) INTVAL (XEXP (XEXP (operands[0], 0), 1)))
08978 {
08979 case -8:
08980 output_asm_insn ("stm%?db\t%m0, %M1", operands);
08981 return "";
08982
08983 case -4:
08984 output_asm_insn ("stm%?da\t%m0, %M1", operands);
08985 return "";
08986
08987 case 4:
08988 output_asm_insn ("stm%?ib\t%m0, %M1", operands);
08989 return "";
08990 }
08991 }
08992 if (TARGET_LDRD
08993 && (GET_CODE (otherops[2]) == REG
08994 || (GET_CODE (otherops[2]) == CONST_INT
08995 && INTVAL (otherops[2]) > -256
08996 && INTVAL (otherops[2]) < 256)))
08997 {
08998 otherops[0] = operands[1];
08999 otherops[1] = XEXP (XEXP (operands[0], 0), 0);
09000 output_asm_insn ("str%?d\t%0, [%1, %2]", otherops);
09001 return "";
09002 }
09003
09004
09005 default:
09006 otherops[0] = adjust_address (operands[0], SImode, 4);
09007 otherops[1] = gen_rtx_REG (SImode, 1 + REGNO (operands[1]));
09008 output_asm_insn ("str%?\t%1, %0", operands);
09009 output_asm_insn ("str%?\t%1, %0", otherops);
09010 }
09011 }
09012
09013 return "";
09014 }
09015
09016
09017
09018 const char *
09019 output_add_immediate (rtx *operands)
09020 {
09021 HOST_WIDE_INT n = INTVAL (operands[2]);
09022
09023 if (n != 0 || REGNO (operands[0]) != REGNO (operands[1]))
09024 {
09025 if (n < 0)
09026 output_multi_immediate (operands,
09027 "sub%?\t%0, %1, %2", "sub%?\t%0, %0, %2", 2,
09028 -n);
09029 else
09030 output_multi_immediate (operands,
09031 "add%?\t%0, %1, %2", "add%?\t%0, %0, %2", 2,
09032 n);
09033 }
09034
09035 return "";
09036 }
09037
09038
09039
09040
09041
09042
09043
09044 static const char *
09045 output_multi_immediate (rtx *operands, const char *instr1, const char *instr2,
09046 int immed_op, HOST_WIDE_INT n)
09047 {
09048 #if HOST_BITS_PER_WIDE_INT > 32
09049 n &= 0xffffffff;
09050 #endif
09051
09052 if (n == 0)
09053 {
09054
09055 operands[immed_op] = const0_rtx;
09056 output_asm_insn (instr1, operands);
09057 }
09058 else
09059 {
09060 int i;
09061 const char * instr = instr1;
09062
09063
09064 for (i = 0; i < 32; i += 2)
09065 {
09066 if (n & (3 << i))
09067 {
09068 operands[immed_op] = GEN_INT (n & (255 << i));
09069 output_asm_insn (instr, operands);
09070 instr = instr2;
09071 i += 6;
09072 }
09073 }
09074 }
09075
09076 return "";
09077 }
09078
09079
09080
09081
09082
09083 const char *
09084 arithmetic_instr (rtx op, int shift_first_arg)
09085 {
09086 switch (GET_CODE (op))
09087 {
09088 case PLUS:
09089 return "add";
09090
09091 case MINUS:
09092 return shift_first_arg ? "rsb" : "sub";
09093
09094 case IOR:
09095 return "orr";
09096
09097 case XOR:
09098 return "eor";
09099
09100 case AND:
09101 return "and";
09102
09103 default:
09104 gcc_unreachable ();
09105 }
09106 }
09107
09108
09109
09110
09111
09112
09113 static const char *
09114 shift_op (rtx op, HOST_WIDE_INT *amountp)
09115 {
09116 const char * mnem;
09117 enum rtx_code code = GET_CODE (op);
09118
09119 switch (GET_CODE (XEXP (op, 1)))
09120 {
09121 case REG:
09122 case SUBREG:
09123 *amountp = -1;
09124 break;
09125
09126 case CONST_INT:
09127 *amountp = INTVAL (XEXP (op, 1));
09128 break;
09129
09130 default:
09131 gcc_unreachable ();
09132 }
09133
09134 switch (code)
09135 {
09136 case ASHIFT:
09137 mnem = "asl";
09138 break;
09139
09140 case ASHIFTRT:
09141 mnem = "asr";
09142 break;
09143
09144 case LSHIFTRT:
09145 mnem = "lsr";
09146 break;
09147
09148 case ROTATE:
09149 gcc_assert (*amountp != -1);
09150 *amountp = 32 - *amountp;
09151
09152
09153
09154 case ROTATERT:
09155 mnem = "ror";
09156 break;
09157
09158 case MULT:
09159
09160
09161 gcc_assert (*amountp != -1);
09162 *amountp = int_log2 (*amountp);
09163 return "asl";
09164
09165 default:
09166 gcc_unreachable ();
09167 }
09168
09169 if (*amountp != -1)
09170 {
09171
09172
09173
09174
09175
09176
09177
09178 if (code == ROTATERT)
09179
09180 *amountp &= 31;
09181 else if (*amountp != (*amountp & 31))
09182 {
09183 if (code == ASHIFT)
09184 mnem = "lsr";
09185 *amountp = 32;
09186 }
09187
09188
09189 if (*amountp == 0)
09190 return NULL;
09191 }
09192
09193 return mnem;
09194 }
09195
09196
09197
09198 static HOST_WIDE_INT
09199 int_log2 (HOST_WIDE_INT power)
09200 {
09201 HOST_WIDE_INT shift = 0;
09202
09203 while ((((HOST_WIDE_INT) 1 << shift) & power) == 0)
09204 {
09205 gcc_assert (shift <= 31);
09206 shift++;
09207 }
09208
09209 return shift;
09210 }
09211
09212
09213
09214
09215
09216
09217
09218
09219
09220 #define MAX_ASCII_LEN 51
09221
09222 void
09223 output_ascii_pseudo_op (FILE *stream, const unsigned char *p, int len)
09224 {
09225 int i;
09226 int len_so_far = 0;
09227
09228 fputs ("\t.ascii\t\"", stream);
09229
09230 for (i = 0; i < len; i++)
09231 {
09232 int c = p[i];
09233
09234 if (len_so_far >= MAX_ASCII_LEN)
09235 {
09236 fputs ("\"\n\t.ascii\t\"", stream);
09237 len_so_far = 0;
09238 }
09239
09240 if (ISPRINT (c))
09241 {
09242 if (c == '\\' || c == '\"')
09243 {
09244 putc ('\\', stream);
09245 len_so_far++;
09246 }
09247 putc (c, stream);
09248 len_so_far++;
09249 }
09250 else
09251 {
09252 fprintf (stream, "\\%03o", c);
09253 len_so_far += 4;
09254 }
09255 }
09256
09257 fputs ("\"\n", stream);
09258 }
09259
09260
09261
09262
09263 static unsigned long
09264 arm_compute_save_reg0_reg12_mask (void)
09265 {
09266 unsigned long func_type = arm_current_func_type ();
09267 unsigned long save_reg_mask = 0;
09268 unsigned int reg;
09269
09270 if (IS_INTERRUPT (func_type))
09271 {
09272 unsigned int max_reg;
09273
09274
09275
09276
09277
09278
09279 if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
09280
09281
09282
09283
09284
09285 max_reg = 7;
09286 else
09287 max_reg = 12;
09288
09289 for (reg = 0; reg <= max_reg; reg++)
09290 if (regs_ever_live[reg]
09291 || (! current_function_is_leaf && call_used_regs [reg]))
09292 save_reg_mask |= (1 << reg);
09293
09294
09295 if (flag_pic
09296 && !TARGET_SINGLE_PIC_BASE
09297 && arm_pic_register != INVALID_REGNUM
09298 && current_function_uses_pic_offset_table)
09299 save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
09300 }
09301 else
09302 {
09303
09304
09305 for (reg = 0; reg <= 10; reg++)
09306 if (regs_ever_live[reg] && ! call_used_regs [reg])
09307 save_reg_mask |= (1 << reg);
09308
09309
09310 if (! TARGET_APCS_FRAME
09311 && ! frame_pointer_needed
09312 && regs_ever_live[HARD_FRAME_POINTER_REGNUM]
09313 && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
09314 save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
09315
09316
09317
09318 if (flag_pic
09319 && !TARGET_SINGLE_PIC_BASE
09320 && arm_pic_register != INVALID_REGNUM
09321 && (regs_ever_live[PIC_OFFSET_TABLE_REGNUM]
09322 || current_function_uses_pic_offset_table))
09323 save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
09324 }
09325
09326
09327 if (current_function_calls_eh_return)
09328 {
09329 unsigned int i;
09330
09331 for (i = 0; ; i++)
09332 {
09333 reg = EH_RETURN_DATA_REGNO (i);
09334 if (reg == INVALID_REGNUM)
09335 break;
09336 save_reg_mask |= 1 << reg;
09337 }
09338 }
09339
09340 return save_reg_mask;
09341 }
09342
09343
09344
09345
09346 static unsigned long
09347 arm_compute_save_reg_mask (void)
09348 {
09349 unsigned int save_reg_mask = 0;
09350 unsigned long func_type = arm_current_func_type ();
09351
09352 if (IS_NAKED (func_type))
09353
09354 return 0;
09355
09356
09357
09358 if (frame_pointer_needed)
09359 save_reg_mask |=
09360 (1 << ARM_HARD_FRAME_POINTER_REGNUM)
09361 | (1 << IP_REGNUM)
09362 | (1 << LR_REGNUM)
09363 | (1 << PC_REGNUM);
09364
09365
09366
09367 if (IS_VOLATILE (func_type))
09368 return save_reg_mask;
09369
09370 save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
09371
09372
09373
09374
09375
09376
09377
09378
09379
09380
09381 if (regs_ever_live [LR_REGNUM]
09382 || (save_reg_mask
09383 && optimize_size
09384 && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
09385 && !current_function_calls_eh_return))
09386 save_reg_mask |= 1 << LR_REGNUM;
09387
09388 if (cfun->machine->lr_save_eliminated)
09389 save_reg_mask &= ~ (1 << LR_REGNUM);
09390
09391 if (TARGET_REALLY_IWMMXT
09392 && ((bit_count (save_reg_mask)
09393 + ARM_NUM_INTS (current_function_pretend_args_size)) % 2) != 0)
09394 {
09395 unsigned int reg;
09396
09397
09398
09399
09400
09401
09402
09403
09404
09405
09406 for (reg = 4; reg <= 12; reg++)
09407 if ((save_reg_mask & (1 << reg)) == 0)
09408 break;
09409
09410 if (reg <= 12)
09411 save_reg_mask |= (1 << reg);
09412 else
09413 {
09414 cfun->machine->sibcall_blocked = 1;
09415 save_reg_mask |= (1 << 3);
09416 }
09417 }
09418
09419 return save_reg_mask;
09420 }
09421
09422
09423
09424
09425 static unsigned long
09426 thumb_compute_save_reg_mask (void)
09427 {
09428 unsigned long mask;
09429 unsigned reg;
09430
09431 mask = 0;
09432 for (reg = 0; reg < 12; reg ++)
09433 if (regs_ever_live[reg] && !call_used_regs[reg])
09434 mask |= 1 << reg;
09435
09436 if (flag_pic
09437 && !TARGET_SINGLE_PIC_BASE
09438 && arm_pic_register != INVALID_REGNUM
09439 && current_function_uses_pic_offset_table)
09440 mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
09441
09442
09443 if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
09444 mask |= 1 << ARM_HARD_FRAME_POINTER_REGNUM;
09445
09446
09447 if (mask & 0xff || thumb_force_lr_save ())
09448 mask |= (1 << LR_REGNUM);
09449
09450
09451
09452
09453 if ((mask & 0xff) == 0
09454 && ((mask & 0x0f00) || TARGET_BACKTRACE))
09455 {
09456
09457
09458
09459
09460 reg = thumb_find_work_register (1 << LAST_LO_REGNUM);
09461
09462 if (! call_used_regs[reg])
09463 mask |= 1 << reg;
09464 }
09465
09466 return mask;
09467 }
09468
09469
09470
09471 static int
09472 arm_get_vfp_saved_size (void)
09473 {
09474 unsigned int regno;
09475 int count;
09476 int saved;
09477
09478 saved = 0;
09479
09480 if (TARGET_HARD_FLOAT && TARGET_VFP)
09481 {
09482 count = 0;
09483 for (regno = FIRST_VFP_REGNUM;
09484 regno < LAST_VFP_REGNUM;
09485 regno += 2)
09486 {
09487 if ((!regs_ever_live[regno] || call_used_regs[regno])
09488 && (!regs_ever_live[regno + 1] || call_used_regs[regno + 1]))
09489 {
09490 if (count > 0)
09491 {
09492
09493 if (count == 2 && !arm_arch6)
09494 count++;
09495 saved += count * 8 + 4;
09496 }
09497 count = 0;
09498 }
09499 else
09500 count++;
09501 }
09502 if (count > 0)
09503 {
09504 if (count == 2 && !arm_arch6)
09505 count++;
09506 saved += count * 8 + 4;
09507 }
09508 }
09509 return saved;
09510 }
09511
09512
09513
09514
09515 const char *
09516 output_return_instruction (rtx operand, int really_return, int reverse)
09517 {
09518 char conditional[10];
09519 char instr[100];
09520 unsigned reg;
09521 unsigned long live_regs_mask;
09522 unsigned long func_type;
09523 arm_stack_offsets *offsets;
09524
09525 func_type = arm_current_func_type ();
09526
09527 if (IS_NAKED (func_type))
09528 return "";
09529
09530 if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
09531 {
09532
09533
09534
09535 if (really_return)
09536 {
09537 rtx ops[2];
09538
09539
09540 ops[0] = operand;
09541 ops[1] = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)"
09542 : "abort");
09543 assemble_external_libcall (ops[1]);
09544 output_asm_insn (reverse ? "bl%D0\t%a1" : "bl%d0\t%a1", ops);
09545 }
09546
09547 return "";
09548 }
09549
09550 gcc_assert (!current_function_calls_alloca || really_return);
09551
09552 sprintf (conditional, "%%?%%%c0", reverse ? 'D' : 'd');
09553
09554 return_used_this_function = 1;
09555
09556 live_regs_mask = arm_compute_save_reg_mask ();
09557
09558 if (live_regs_mask)
09559 {
09560 const char * return_reg;
09561
09562
09563
09564
09565 if (really_return
09566 && ! TARGET_INTERWORK)
09567 return_reg = reg_names[PC_REGNUM];
09568 else
09569 return_reg = reg_names[LR_REGNUM];
09570
09571 if ((live_regs_mask & (1 << IP_REGNUM)) == (1 << IP_REGNUM))
09572 {
09573
09574
09575
09576
09577
09578
09579 if (frame_pointer_needed)
09580 {
09581 live_regs_mask &= ~ (1 << IP_REGNUM);
09582 live_regs_mask |= (1 << SP_REGNUM);
09583 }
09584 else
09585 gcc_assert (IS_INTERRUPT (func_type) || TARGET_REALLY_IWMMXT);
09586 }
09587
09588
09589
09590
09591
09592
09593 for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
09594 if (live_regs_mask == (1U << reg))
09595 break;
09596
09597 if (reg <= LAST_ARM_REGNUM
09598 && (reg != LR_REGNUM
09599 || ! really_return
09600 || ! IS_INTERRUPT (func_type)))
09601 {
09602 sprintf (instr, "ldr%s\t%%|%s, [%%|sp], #4", conditional,
09603 (reg == LR_REGNUM) ? return_reg : reg_names[reg]);
09604 }
09605 else
09606 {
09607 char *p;
09608 int first = 1;
09609
09610
09611
09612
09613
09614 if (live_regs_mask & (1 << SP_REGNUM))
09615 {
09616 unsigned HOST_WIDE_INT stack_adjust;
09617
09618 offsets = arm_get_frame_offsets ();
09619 stack_adjust = offsets->outgoing_args - offsets->saved_regs;
09620 gcc_assert (stack_adjust == 0 || stack_adjust == 4);
09621
09622 if (stack_adjust && arm_arch5)
09623 sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
09624 else
09625 {
09626
09627
09628 if (stack_adjust)
09629 live_regs_mask |= 1 << 3;
09630 sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
09631 }
09632 }
09633 else
09634 sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
09635
09636 p = instr + strlen (instr);
09637
09638 for (reg = 0; reg <= SP_REGNUM; reg++)
09639 if (live_regs_mask & (1 << reg))
09640 {
09641 int l = strlen (reg_names[reg]);
09642
09643 if (first)
09644 first = 0;
09645 else
09646 {
09647 memcpy (p, ", ", 2);
09648 p += 2;
09649 }
09650
09651 memcpy (p, "%|", 2);
09652 memcpy (p + 2, reg_names[reg], l);
09653 p += l + 2;
09654 }
09655
09656 if (live_regs_mask & (1 << LR_REGNUM))
09657 {
09658 sprintf (p, "%s%%|%s}", first ? "" : ", ", return_reg);
09659
09660 if (IS_INTERRUPT (func_type))
09661 strcat (p, "^");
09662 }
09663 else
09664 strcpy (p, "}");
09665 }
09666
09667 output_asm_insn (instr, & operand);
09668
09669
09670
09671 if (really_return
09672 && func_type != ARM_FT_INTERWORKED
09673 && (live_regs_mask & (1 << LR_REGNUM)) != 0)
09674 {
09675
09676
09677 really_return = 0;
09678 }
09679 }
09680
09681 if (really_return)
09682 {
09683 switch ((int) ARM_FUNC_TYPE (func_type))
09684 {
09685 case ARM_FT_ISR:
09686 case ARM_FT_FIQ:
09687 sprintf (instr, "sub%ss\t%%|pc, %%|lr, #4", conditional);
09688 break;
09689
09690 case ARM_FT_INTERWORKED:
09691 sprintf (instr, "bx%s\t%%|lr", conditional);
09692 break;
09693
09694 case ARM_FT_EXCEPTION:
09695 sprintf (instr, "mov%ss\t%%|pc, %%|lr", conditional);
09696 break;
09697
09698 default:
09699
09700 if (arm_arch5 || arm_arch4t)
09701 sprintf (instr, "bx%s\t%%|lr", conditional);
09702 else
09703 sprintf (instr, "mov%s\t%%|pc, %%|lr", conditional);
09704 break;
09705 }
09706
09707 output_asm_insn (instr, & operand);
09708 }
09709
09710 return "";
09711 }
09712
09713
09714
09715
09716
09717
09718
09719
09720
09721
09722
09723
09724
09725
09726
09727
09728
09729
09730
09731
09732
09733
09734
09735
09736
09737
09738
09739 void
09740 arm_poke_function_name (FILE *stream, const char *name)
09741 {
09742 unsigned long alignlength;
09743 unsigned long length;
09744 rtx x;
09745
09746 length = strlen (name) + 1;
09747 alignlength = ROUND_UP_WORD (length);
09748
09749 ASM_OUTPUT_ASCII (stream, name, length);
09750 ASM_OUTPUT_ALIGN (stream, 2);
09751 x = GEN_INT ((unsigned HOST_WIDE_INT) 0xff000000 + alignlength);
09752 assemble_aligned_integer (UNITS_PER_WORD, x);
09753 }
09754
09755
09756
09757 static void
09758 arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
09759 {
09760 unsigned long func_type;
09761
09762 if (!TARGET_ARM)
09763 {
09764 thumb_output_function_prologue (f, frame_size);
09765 return;
09766 }
09767
09768
09769 gcc_assert (!arm_ccfsm_state && !arm_target_insn);
09770
09771 func_type = arm_current_func_type ();
09772
09773 switch ((int) ARM_FUNC_TYPE (func_type))
09774 {
09775 default:
09776 case ARM_FT_NORMAL:
09777 break;
09778 case ARM_FT_INTERWORKED:
09779 asm_fprintf (f, "\t%@ Function supports interworking.\n");
09780 break;
09781 case ARM_FT_ISR:
09782 asm_fprintf (f, "\t%@ Interrupt Service Routine.\n");
09783 break;
09784 case ARM_FT_FIQ:
09785 asm_fprintf (f, "\t%@ Fast Interrupt Service Routine.\n");
09786 break;
09787 case ARM_FT_EXCEPTION:
09788 asm_fprintf (f, "\t%@ ARM Exception Handler.\n");
09789 break;
09790 }
09791
09792 if (IS_NAKED (func_type))
09793 asm_fprintf (f, "\t%@ Naked Function: prologue and epilogue provided by programmer.\n");
09794
09795 if (IS_VOLATILE (func_type))
09796 asm_fprintf (f, "\t%@ Volatile: function does not return.\n");
09797
09798 if (IS_NESTED (func_type))
09799 asm_fprintf (f, "\t%@ Nested: function declared inside another function.\n");
09800
09801 asm_fprintf (f, "\t%@ args = %d, pretend = %d, frame = %wd\n",
09802 current_function_args_size,
09803 current_function_pretend_args_size, frame_size);
09804
09805 asm_fprintf (f, "\t%@ frame_needed = %d, uses_anonymous_args = %d\n",
09806 frame_pointer_needed,
09807 cfun->machine->uses_anonymous_args);
09808
09809 if (cfun->machine->lr_save_eliminated)
09810 asm_fprintf (f, "\t%@ link register save eliminated.\n");
09811
09812 if (current_function_calls_eh_return)
09813 asm_fprintf (f, "\t@ Calls __builtin_eh_return.\n");
09814
09815 #ifdef AOF_ASSEMBLER
09816 if (flag_pic)
09817 asm_fprintf (f, "\tmov\t%r, %r\n", IP_REGNUM, PIC_OFFSET_TABLE_REGNUM);
09818 #endif
09819
09820 return_used_this_function = 0;
09821 }
09822
09823 const char *
09824 arm_output_epilogue (rtx sibling)
09825 {
09826 int reg;
09827 unsigned long saved_regs_mask;
09828 unsigned long func_type;
09829
09830
09831 int floats_offset = 0;
09832 rtx operands[3];
09833 FILE * f = asm_out_file;
09834 unsigned int lrm_count = 0;
09835 int really_return = (sibling == NULL);
09836 int start_reg;
09837 arm_stack_offsets *offsets;
09838
09839
09840
09841 if (use_return_insn (FALSE, sibling) && return_used_this_function)
09842 return "";
09843
09844 func_type = arm_current_func_type ();
09845
09846 if (IS_NAKED (func_type))
09847
09848 return "";
09849
09850 if (IS_VOLATILE (func_type) && TARGET_ABORT_NORETURN)
09851 {
09852 rtx op;
09853
09854
09855 op = gen_rtx_SYMBOL_REF (Pmode, NEED_PLT_RELOC ? "abort(PLT)" : "abort");
09856 assemble_external_libcall (op);
09857 output_asm_insn ("bl\t%a0", &op);
09858
09859 return "";
09860 }
09861
09862
09863
09864 gcc_assert (!current_function_calls_eh_return || really_return);
09865
09866 offsets = arm_get_frame_offsets ();
09867 saved_regs_mask = arm_compute_save_reg_mask ();
09868
09869 if (TARGET_IWMMXT)
09870 lrm_count = bit_count (saved_regs_mask);
09871
09872 floats_offset = offsets->saved_args;
09873
09874 for (reg = 0; reg <= LAST_ARM_REGNUM; reg++)
09875 if (saved_regs_mask & (1 << reg))
09876 floats_offset += 4;
09877
09878 if (frame_pointer_needed)
09879 {
09880
09881 int vfp_offset = offsets->frame;
09882
09883 if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
09884 {
09885 for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
09886 if (regs_ever_live[reg] && !call_used_regs[reg])
09887 {
09888 floats_offset += 12;
09889 asm_fprintf (f, "\tldfe\t%r, [%r, #-%d]\n",
09890 reg, FP_REGNUM, floats_offset - vfp_offset);
09891 }
09892 }
09893 else
09894 {
09895 start_reg = LAST_FPA_REGNUM;
09896
09897 for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
09898 {
09899 if (regs_ever_live[reg] && !call_used_regs[reg])
09900 {
09901 floats_offset += 12;
09902
09903
09904 if (start_reg - reg == 3)
09905 {
09906 asm_fprintf (f, "\tlfm\t%r, 4, [%r, #-%d]\n",
09907 reg, FP_REGNUM, floats_offset - vfp_offset);
09908 start_reg = reg - 1;
09909 }
09910 }
09911 else
09912 {
09913 if (reg != start_reg)
09914 asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
09915 reg + 1, start_reg - reg,
09916 FP_REGNUM, floats_offset - vfp_offset);
09917 start_reg = reg - 1;
09918 }
09919 }
09920
09921
09922 if (reg != start_reg)
09923 asm_fprintf (f, "\tlfm\t%r, %d, [%r, #-%d]\n",
09924 reg + 1, start_reg - reg,
09925 FP_REGNUM, floats_offset - vfp_offset);
09926 }
09927
09928 if (TARGET_HARD_FLOAT && TARGET_VFP)
09929 {
09930 int saved_size;
09931
09932
09933
09934 saved_size = arm_get_vfp_saved_size ();
09935
09936 if (saved_size > 0)
09937 {
09938 floats_offset += saved_size;
09939 asm_fprintf (f, "\tsub\t%r, %r, #%d\n", IP_REGNUM,
09940 FP_REGNUM, floats_offset - vfp_offset);
09941 }
09942 start_reg = FIRST_VFP_REGNUM;
09943 for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
09944 {
09945 if ((!regs_ever_live[reg] || call_used_regs[reg])
09946 && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
09947 {
09948 if (start_reg != reg)
09949 arm_output_fldmx (f, IP_REGNUM,
09950 (start_reg - FIRST_VFP_REGNUM) / 2,
09951 (reg - start_reg) / 2);
09952 start_reg = reg + 2;
09953 }
09954 }
09955 if (start_reg != reg)
09956 arm_output_fldmx (f, IP_REGNUM,
09957 (start_reg - FIRST_VFP_REGNUM) / 2,
09958 (reg - start_reg) / 2);
09959 }
09960
09961 if (TARGET_IWMMXT)
09962 {
09963
09964
09965
09966
09967
09968
09969
09970 lrm_count += (lrm_count % 2 ? 2 : 1);
09971
09972 for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
09973 if (regs_ever_live[reg] && !call_used_regs[reg])
09974 {
09975 asm_fprintf (f, "\twldrd\t%r, [%r, #-%d]\n",
09976 reg, FP_REGNUM, lrm_count * 4);
09977 lrm_count += 2;
09978 }
09979 }
09980
09981
09982
09983
09984
09985 gcc_assert (saved_regs_mask & (1 << IP_REGNUM));
09986 saved_regs_mask &= ~ (1 << IP_REGNUM);
09987 saved_regs_mask |= (1 << SP_REGNUM);
09988
09989
09990
09991
09992
09993 if (really_return
09994 && ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
09995 && !current_function_calls_eh_return)
09996
09997
09998 saved_regs_mask &= ~ (1 << LR_REGNUM);
09999 else
10000 saved_regs_mask &= ~ (1 << PC_REGNUM);
10001
10002
10003
10004
10005
10006
10007
10008
10009
10010
10011 if (offsets->outgoing_args != (1 + (int) bit_count (saved_regs_mask))
10012 || current_function_calls_alloca)
10013 asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
10014 4 * bit_count (saved_regs_mask));
10015 print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
10016
10017 if (IS_INTERRUPT (func_type))
10018
10019
10020 print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, 1 << IP_REGNUM);
10021 }
10022 else
10023 {
10024
10025 if (offsets->outgoing_args != offsets->saved_regs)
10026 {
10027 operands[0] = operands[1] = stack_pointer_rtx;
10028 operands[2] = GEN_INT (offsets->outgoing_args - offsets->saved_regs);
10029 output_add_immediate (operands);
10030 }
10031
10032 if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
10033 {
10034 for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
10035 if (regs_ever_live[reg] && !call_used_regs[reg])
10036 asm_fprintf (f, "\tldfe\t%r, [%r], #12\n",
10037 reg, SP_REGNUM);
10038 }
10039 else
10040 {
10041 start_reg = FIRST_FPA_REGNUM;
10042
10043 for (reg = FIRST_FPA_REGNUM; reg <= LAST_FPA_REGNUM; reg++)
10044 {
10045 if (regs_ever_live[reg] && !call_used_regs[reg])
10046 {
10047 if (reg - start_reg == 3)
10048 {
10049 asm_fprintf (f, "\tlfmfd\t%r, 4, [%r]!\n",
10050 start_reg, SP_REGNUM);
10051 start_reg = reg + 1;
10052 }
10053 }
10054 else
10055 {
10056 if (reg != start_reg)
10057 asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
10058 start_reg, reg - start_reg,
10059 SP_REGNUM);
10060
10061 start_reg = reg + 1;
10062 }
10063 }
10064
10065
10066 if (reg != start_reg)
10067 asm_fprintf (f, "\tlfmfd\t%r, %d, [%r]!\n",
10068 start_reg, reg - start_reg, SP_REGNUM);
10069 }
10070
10071 if (TARGET_HARD_FLOAT && TARGET_VFP)
10072 {
10073 start_reg = FIRST_VFP_REGNUM;
10074 for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
10075 {
10076 if ((!regs_ever_live[reg] || call_used_regs[reg])
10077 && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
10078 {
10079 if (start_reg != reg)
10080 arm_output_fldmx (f, SP_REGNUM,
10081 (start_reg - FIRST_VFP_REGNUM) / 2,
10082 (reg - start_reg) / 2);
10083 start_reg = reg + 2;
10084 }
10085 }
10086 if (start_reg != reg)
10087 arm_output_fldmx (f, SP_REGNUM,
10088 (start_reg - FIRST_VFP_REGNUM) / 2,
10089 (reg - start_reg) / 2);
10090 }
10091 if (TARGET_IWMMXT)
10092 for (reg = FIRST_IWMMXT_REGNUM; reg <= LAST_IWMMXT_REGNUM; reg++)
10093 if (regs_ever_live[reg] && !call_used_regs[reg])
10094 asm_fprintf (f, "\twldrd\t%r, [%r], #8\n", reg, SP_REGNUM);
10095
10096
10097 if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
10098 && really_return
10099 && current_function_pretend_args_size == 0
10100 && saved_regs_mask & (1 << LR_REGNUM)
10101 && !current_function_calls_eh_return)
10102 {
10103 saved_regs_mask &= ~ (1 << LR_REGNUM);
10104 saved_regs_mask |= (1 << PC_REGNUM);
10105 }
10106
10107
10108
10109 if (saved_regs_mask == (1 << LR_REGNUM))
10110 {
10111 asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
10112 }
10113 else if (saved_regs_mask)
10114 {
10115 if (saved_regs_mask & (1 << SP_REGNUM))
10116
10117
10118
10119
10120 print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, saved_regs_mask);
10121 else
10122 print_multi_reg (f, "ldmfd\t%r!", SP_REGNUM, saved_regs_mask);
10123 }
10124
10125 if (current_function_pretend_args_size)
10126 {
10127
10128 operands[0] = operands[1] = stack_pointer_rtx;
10129 operands[2] = GEN_INT (current_function_pretend_args_size);
10130 output_add_immediate (operands);
10131 }
10132 }
10133
10134
10135 if (!really_return || saved_regs_mask & (1 << PC_REGNUM))
10136 return "";
10137
10138
10139 if (current_function_calls_eh_return)
10140 asm_fprintf (f, "\tadd\t%r, %r, %r\n", SP_REGNUM, SP_REGNUM,
10141 ARM_EH_STACKADJ_REGNUM);
10142
10143
10144 switch ((int) ARM_FUNC_TYPE (func_type))
10145 {
10146 case ARM_FT_ISR:
10147 case ARM_FT_FIQ:
10148 asm_fprintf (f, "\tsubs\t%r, %r, #4\n", PC_REGNUM, LR_REGNUM);
10149 break;
10150
10151 case ARM_FT_EXCEPTION:
10152 asm_fprintf (f, "\tmovs\t%r, %r\n", PC_REGNUM, LR_REGNUM);
10153 break;
10154
10155 case ARM_FT_INTERWORKED:
10156 asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
10157 break;
10158
10159 default:
10160 if (arm_arch5 || arm_arch4t)
10161 asm_fprintf (f, "\tbx\t%r\n", LR_REGNUM);
10162 else
10163 asm_fprintf (f, "\tmov\t%r, %r\n", PC_REGNUM, LR_REGNUM);
10164 break;
10165 }
10166
10167 return "";
10168 }
10169
10170 static void
10171 arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
10172 HOST_WIDE_INT frame_size ATTRIBUTE_UNUSED)
10173 {
10174 arm_stack_offsets *offsets;
10175
10176 if (TARGET_THUMB)
10177 {
10178 int regno;
10179
10180
10181
10182 for (regno = 0; regno < LR_REGNUM; regno++)
10183 {
10184 rtx label = cfun->machine->call_via[regno];
10185
10186 if (label != NULL)
10187 {
10188 switch_to_section (function_section (current_function_decl));
10189 targetm.asm_out.internal_label (asm_out_file, "L",
10190 CODE_LABEL_NUMBER (label));
10191 asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
10192 }
10193 }
10194
10195
10196
10197
10198 return_used_this_function = 0;
10199 }
10200 else
10201 {
10202
10203 offsets = arm_get_frame_offsets ();
10204
10205 gcc_assert (!use_return_insn (FALSE, NULL)
10206 || !return_used_this_function
10207 || offsets->saved_regs == offsets->outgoing_args
10208 || frame_pointer_needed);
10209
10210
10211 after_arm_reorg = 0;
10212 }
10213 }
10214
10215
10216
10217
10218
10219 static rtx
10220 emit_multi_reg_push (unsigned long mask)
10221 {
10222 int num_regs = 0;
10223 int num_dwarf_regs;
10224 int i, j;
10225 rtx par;
10226 rtx dwarf;
10227 int dwarf_par_index;
10228 rtx tmp, reg;
10229
10230 for (i = 0; i <= LAST_ARM_REGNUM; i++)
10231 if (mask & (1 << i))
10232 num_regs++;
10233
10234 gcc_assert (num_regs && num_regs <= 16);
10235
10236
10237 num_dwarf_regs = num_regs;
10238 if (mask & (1 << PC_REGNUM))
10239 num_dwarf_regs--;
10240
10241
10242
10243
10244
10245
10246
10247
10248
10249
10250
10251
10252
10253
10254
10255
10256
10257
10258
10259
10260
10261
10262
10263
10264
10265
10266
10267
10268
10269
10270
10271
10272
10273 par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_regs));
10274 dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_dwarf_regs + 1));
10275 dwarf_par_index = 1;
10276
10277 for (i = 0; i <= LAST_ARM_REGNUM; i++)
10278 {
10279 if (mask & (1 << i))
10280 {
10281 reg = gen_rtx_REG (SImode, i);
10282
10283 XVECEXP (par, 0, 0)
10284 = gen_rtx_SET (VOIDmode,
10285 gen_frame_mem (BLKmode,
10286 gen_rtx_PRE_DEC (BLKmode,
10287 stack_pointer_rtx)),
10288 gen_rtx_UNSPEC (BLKmode,
10289 gen_rtvec (1, reg),
10290 UNSPEC_PUSH_MULT));
10291
10292 if (i != PC_REGNUM)
10293 {
10294 tmp = gen_rtx_SET (VOIDmode,
10295 gen_frame_mem (SImode, stack_pointer_rtx),
10296 reg);
10297 RTX_FRAME_RELATED_P (tmp) = 1;
10298 XVECEXP (dwarf, 0, dwarf_par_index) = tmp;
10299 dwarf_par_index++;
10300 }
10301
10302 break;
10303 }
10304 }
10305
10306 for (j = 1, i++; j < num_regs; i++)
10307 {
10308 if (mask & (1 << i))
10309 {
10310 reg = gen_rtx_REG (SImode, i);
10311
10312 XVECEXP (par, 0, j) = gen_rtx_USE (VOIDmode, reg);
10313
10314 if (i != PC_REGNUM)
10315 {
10316 tmp
10317 = gen_rtx_SET (VOIDmode,
10318 gen_frame_mem (SImode,
10319 plus_constant (stack_pointer_rtx,
10320 4 * j)),
10321 reg);
10322 RTX_FRAME_RELATED_P (tmp) = 1;
10323 XVECEXP (dwarf, 0, dwarf_par_index++) = tmp;
10324 }
10325
10326 j++;
10327 }
10328 }
10329
10330 par = emit_insn (par);
10331
10332 tmp = gen_rtx_SET (VOIDmode,
10333 stack_pointer_rtx,
10334 plus_constant (stack_pointer_rtx, -4 * num_regs));
10335 RTX_FRAME_RELATED_P (tmp) = 1;
10336 XVECEXP (dwarf, 0, 0) = tmp;
10337
10338 REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
10339 REG_NOTES (par));
10340 return par;
10341 }
10342
10343
10344 static int
10345 arm_size_return_regs (void)
10346 {
10347 enum machine_mode mode;
10348
10349 if (current_function_return_rtx != 0)
10350 mode = GET_MODE (current_function_return_rtx);
10351 else
10352 mode = DECL_MODE (DECL_RESULT (current_function_decl));
10353
10354 return GET_MODE_SIZE (mode);
10355 }
10356
10357 static rtx
10358 emit_sfm (int base_reg, int count)
10359 {
10360 rtx par;
10361 rtx dwarf;
10362 rtx tmp, reg;
10363 int i;
10364
10365 par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (count));
10366 dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (count + 1));
10367
10368 reg = gen_rtx_REG (XFmode, base_reg++);
10369
10370 XVECEXP (par, 0, 0)
10371 = gen_rtx_SET (VOIDmode,
10372 gen_frame_mem (BLKmode,
10373 gen_rtx_PRE_DEC (BLKmode,
10374 stack_pointer_rtx)),
10375 gen_rtx_UNSPEC (BLKmode,
10376 gen_rtvec (1, reg),
10377 UNSPEC_PUSH_MULT));
10378 tmp = gen_rtx_SET (VOIDmode,
10379 gen_frame_mem (XFmode, stack_pointer_rtx), reg);
10380 RTX_FRAME_RELATED_P (tmp) = 1;
10381 XVECEXP (dwarf, 0, 1) = tmp;
10382
10383 for (i = 1; i < count; i++)
10384 {
10385 reg = gen_rtx_REG (XFmode, base_reg++);
10386 XVECEXP (par, 0, i) = gen_rtx_USE (VOIDmode, reg);
10387
10388 tmp = gen_rtx_SET (VOIDmode,
10389 gen_frame_mem (XFmode,
10390 plus_constant (stack_pointer_rtx,
10391 i * 12)),
10392 reg);
10393 RTX_FRAME_RELATED_P (tmp) = 1;
10394 XVECEXP (dwarf, 0, i + 1) = tmp;
10395 }
10396
10397 tmp = gen_rtx_SET (VOIDmode,
10398 stack_pointer_rtx,
10399 plus_constant (stack_pointer_rtx, -12 * count));
10400
10401 RTX_FRAME_RELATED_P (tmp) = 1;
10402 XVECEXP (dwarf, 0, 0) = tmp;
10403
10404 par = emit_insn (par);
10405 REG_NOTES (par) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
10406 REG_NOTES (par));
10407 return par;
10408 }
10409
10410
10411
10412
10413 static bool
10414 thumb_force_lr_save (void)
10415 {
10416 return !cfun->machine->lr_save_eliminated
10417 && (!leaf_function_p ()
10418 || thumb_far_jump_used_p ()
10419 || regs_ever_live [LR_REGNUM]);
10420 }
10421
10422
10423
10424
10425
10426
10427
10428
10429
10430
10431
10432
10433
10434
10435
10436
10437
10438
10439
10440
10441
10442
10443
10444
10445
10446
10447
10448
10449
10450
10451
10452
10453
10454
10455
10456
10457
10458
10459
10460
10461
10462
10463
10464
10465
10466
10467
10468
10469
10470
10471
10472
10473
10474
10475 static arm_stack_offsets *
10476 arm_get_frame_offsets (void)
10477 {
10478 struct arm_stack_offsets *offsets;
10479 unsigned long func_type;
10480 int leaf;
10481 int saved;
10482 HOST_WIDE_INT frame_size;
10483
10484 offsets = &cfun->machine->stack_offsets;
10485
10486
10487
10488
10489
10490
10491
10492
10493
10494
10495
10496 if (reload_completed)
10497 return offsets;
10498
10499
10500
10501 frame_size = ROUND_UP_WORD (get_frame_size ());
10502
10503 leaf = leaf_function_p ();
10504
10505
10506 offsets->saved_args = current_function_pretend_args_size;
10507
10508 offsets->frame = offsets->saved_args + (frame_pointer_needed ? 4 : 0);
10509
10510 if (TARGET_ARM)
10511 {
10512 unsigned int regno;
10513
10514 saved = bit_count (arm_compute_save_reg_mask ()) * 4;
10515
10516
10517
10518
10519
10520 if (TARGET_REALLY_IWMMXT)
10521 {
10522
10523 for (regno = FIRST_IWMMXT_REGNUM;
10524 regno <= LAST_IWMMXT_REGNUM;
10525 regno++)
10526 if (regs_ever_live [regno] && ! call_used_regs [regno])
10527 saved += 8;
10528 }
10529
10530 func_type = arm_current_func_type ();
10531 if (! IS_VOLATILE (func_type))
10532 {
10533
10534 for (regno = FIRST_FPA_REGNUM; regno <= LAST_FPA_REGNUM; regno++)
10535 if (regs_ever_live[regno] && ! call_used_regs[regno])
10536 saved += 12;
10537
10538
10539 if (TARGET_HARD_FLOAT && TARGET_VFP)
10540 saved += arm_get_vfp_saved_size ();
10541 }
10542 }
10543 else
10544 {
10545 saved = bit_count (thumb_compute_save_reg_mask ()) * 4;
10546 if (TARGET_BACKTRACE)
10547 saved += 16;
10548 }
10549
10550
10551 offsets->saved_regs = offsets->saved_args + saved;
10552 offsets->soft_frame = offsets->saved_regs + CALLER_INTERWORKING_SLOT_SIZE;
10553
10554
10555 if (leaf && frame_size == 0)
10556 {
10557 offsets->outgoing_args = offsets->soft_frame;
10558 return offsets;
10559 }
10560
10561
10562 if (ARM_DOUBLEWORD_ALIGN
10563 && (offsets->soft_frame & 7))
10564 offsets->soft_frame += 4;
10565
10566 offsets->locals_base = offsets->soft_frame + frame_size;
10567 offsets->outgoing_args = (offsets->locals_base
10568 + current_function_outgoing_args_size);
10569
10570 if (ARM_DOUBLEWORD_ALIGN)
10571 {
10572
10573 if (offsets->outgoing_args & 7)
10574 offsets->outgoing_args += 4;
10575 gcc_assert (!(offsets->outgoing_args & 7));
10576 }
10577
10578 return offsets;
10579 }
10580
10581
10582
10583
10584
10585 HOST_WIDE_INT
10586 arm_compute_initial_elimination_offset (unsigned int from, unsigned int to)
10587 {
10588 arm_stack_offsets *offsets;
10589
10590 offsets = arm_get_frame_offsets ();
10591
10592
10593
10594
10595
10596 switch (from)
10597 {
10598 case ARG_POINTER_REGNUM:
10599 switch (to)
10600 {
10601 case THUMB_HARD_FRAME_POINTER_REGNUM:
10602 return 0;
10603
10604 case FRAME_POINTER_REGNUM:
10605
10606
10607 return offsets->soft_frame - offsets->saved_args;
10608
10609 case ARM_HARD_FRAME_POINTER_REGNUM:
10610
10611
10612 if (offsets->frame == offsets->saved_regs)
10613 return 0;
10614
10615 return (frame_pointer_needed
10616 && cfun->static_chain_decl != NULL
10617 && ! cfun->machine->uses_anonymous_args) ? 4 : 0;
10618
10619 case STACK_POINTER_REGNUM:
10620
10621
10622 return offsets->outgoing_args - (offsets->saved_args + 4);
10623
10624 default:
10625 gcc_unreachable ();
10626 }
10627 gcc_unreachable ();
10628
10629 case FRAME_POINTER_REGNUM:
10630 switch (to)
10631 {
10632 case THUMB_HARD_FRAME_POINTER_REGNUM:
10633 return 0;
10634
10635 case ARM_HARD_FRAME_POINTER_REGNUM:
10636
10637
10638
10639
10640
10641 return offsets->frame - offsets->soft_frame;
10642
10643 case STACK_POINTER_REGNUM:
10644 return offsets->outgoing_args - offsets->soft_frame;
10645
10646 default:
10647 gcc_unreachable ();
10648 }
10649 gcc_unreachable ();
10650
10651 default:
10652
10653
10654
10655
10656
10657 gcc_unreachable ();
10658 }
10659 }
10660
10661
10662
10663 void
10664 arm_expand_prologue (void)
10665 {
10666 int reg;
10667 rtx amount;
10668 rtx insn;
10669 rtx ip_rtx;
10670 unsigned long live_regs_mask;
10671 unsigned long func_type;
10672 int fp_offset = 0;
10673 int saved_pretend_args = 0;
10674 int saved_regs = 0;
10675 unsigned HOST_WIDE_INT args_to_push;
10676 arm_stack_offsets *offsets;
10677
10678 func_type = arm_current_func_type ();
10679
10680
10681 if (IS_NAKED (func_type))
10682 return;
10683
10684
10685 args_to_push = current_function_pretend_args_size;
10686
10687
10688 live_regs_mask = arm_compute_save_reg_mask ();
10689
10690 ip_rtx = gen_rtx_REG (SImode, IP_REGNUM);
10691
10692 if (frame_pointer_needed)
10693 {
10694 if (IS_INTERRUPT (func_type))
10695 {
10696
10697
10698
10699 insn = emit_multi_reg_push (1 << IP_REGNUM);
10700
10701
10702
10703
10704
10705
10706
10707
10708
10709
10710
10711
10712 }
10713 else if (IS_NESTED (func_type))
10714 {
10715
10716
10717
10718
10719
10720
10721
10722
10723
10724
10725
10726
10727
10728
10729
10730
10731
10732 if (regs_ever_live[3] == 0)
10733 insn = emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
10734 else if (args_to_push == 0)
10735 {
10736 rtx dwarf;
10737
10738 insn = gen_rtx_PRE_DEC (SImode, stack_pointer_rtx);
10739 insn = emit_set_insn (gen_frame_mem (SImode, insn), ip_rtx);
10740 fp_offset = 4;
10741
10742
10743 dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
10744 plus_constant (stack_pointer_rtx,
10745 -fp_offset));
10746 RTX_FRAME_RELATED_P (insn) = 1;
10747 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR,
10748 dwarf, REG_NOTES (insn));
10749 }
10750 else
10751 {
10752
10753 if (cfun->machine->uses_anonymous_args)
10754 insn = emit_multi_reg_push
10755 ((0xf0 >> (args_to_push / 4)) & 0xf);
10756 else
10757 insn = emit_insn
10758 (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
10759 GEN_INT (- args_to_push)));
10760
10761 RTX_FRAME_RELATED_P (insn) = 1;
10762
10763 saved_pretend_args = 1;
10764 fp_offset = args_to_push;
10765 args_to_push = 0;
10766
10767
10768 emit_set_insn (gen_rtx_REG (SImode, 3), ip_rtx);
10769 }
10770 }
10771
10772 insn = emit_set_insn (ip_rtx,
10773 plus_constant (stack_pointer_rtx, fp_offset));
10774 RTX_FRAME_RELATED_P (insn) = 1;
10775 }
10776
10777 if (args_to_push)
10778 {
10779
10780 if (cfun->machine->uses_anonymous_args)
10781 insn = emit_multi_reg_push
10782 ((0xf0 >> (args_to_push / 4)) & 0xf);
10783 else
10784 insn = emit_insn
10785 (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
10786 GEN_INT (- args_to_push)));
10787 RTX_FRAME_RELATED_P (insn) = 1;
10788 }
10789
10790
10791
10792
10793
10794
10795 if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
10796 && (live_regs_mask & (1 << LR_REGNUM)) != 0
10797 && ! frame_pointer_needed)
10798 {
10799 rtx lr = gen_rtx_REG (SImode, LR_REGNUM);
10800
10801 emit_set_insn (lr, plus_constant (lr, -4));
10802 }
10803
10804 if (live_regs_mask)
10805 {
10806 insn = emit_multi_reg_push (live_regs_mask);
10807 saved_regs += bit_count (live_regs_mask) * 4;
10808 RTX_FRAME_RELATED_P (insn) = 1;
10809 }
10810
10811 if (TARGET_IWMMXT)
10812 for (reg = LAST_IWMMXT_REGNUM; reg >= FIRST_IWMMXT_REGNUM; reg--)
10813 if (regs_ever_live[reg] && ! call_used_regs [reg])
10814 {
10815 insn = gen_rtx_PRE_DEC (V2SImode, stack_pointer_rtx);
10816 insn = gen_frame_mem (V2SImode, insn);
10817 insn = emit_set_insn (insn, gen_rtx_REG (V2SImode, reg));
10818 RTX_FRAME_RELATED_P (insn) = 1;
10819 saved_regs += 8;
10820 }
10821
10822 if (! IS_VOLATILE (func_type))
10823 {
10824 int start_reg;
10825
10826
10827
10828 if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
10829 {
10830 for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
10831 if (regs_ever_live[reg] && !call_used_regs[reg])
10832 {
10833 insn = gen_rtx_PRE_DEC (XFmode, stack_pointer_rtx);
10834 insn = gen_frame_mem (XFmode, insn);
10835 insn = emit_set_insn (insn, gen_rtx_REG (XFmode, reg));
10836 RTX_FRAME_RELATED_P (insn) = 1;
10837 saved_regs += 12;
10838 }
10839 }
10840 else
10841 {
10842 start_reg = LAST_FPA_REGNUM;
10843
10844 for (reg = LAST_FPA_REGNUM; reg >= FIRST_FPA_REGNUM; reg--)
10845 {
10846 if (regs_ever_live[reg] && !call_used_regs[reg])
10847 {
10848 if (start_reg - reg == 3)
10849 {
10850 insn = emit_sfm (reg, 4);
10851 RTX_FRAME_RELATED_P (insn) = 1;
10852 saved_regs += 48;
10853 start_reg = reg - 1;
10854 }
10855 }
10856 else
10857 {
10858 if (start_reg != reg)
10859 {
10860 insn = emit_sfm (reg + 1, start_reg - reg);
10861 RTX_FRAME_RELATED_P (insn) = 1;
10862 saved_regs += (start_reg - reg) * 12;
10863 }
10864 start_reg = reg - 1;
10865 }
10866 }
10867
10868 if (start_reg != reg)
10869 {
10870 insn = emit_sfm (reg + 1, start_reg - reg);
10871 saved_regs += (start_reg - reg) * 12;
10872 RTX_FRAME_RELATED_P (insn) = 1;
10873 }
10874 }
10875 if (TARGET_HARD_FLOAT && TARGET_VFP)
10876 {
10877 start_reg = FIRST_VFP_REGNUM;
10878
10879 for (reg = FIRST_VFP_REGNUM; reg < LAST_VFP_REGNUM; reg += 2)
10880 {
10881 if ((!regs_ever_live[reg] || call_used_regs[reg])
10882 && (!regs_ever_live[reg + 1] || call_used_regs[reg + 1]))
10883 {
10884 if (start_reg != reg)
10885 saved_regs += vfp_emit_fstmx (start_reg,
10886 (reg - start_reg) / 2);
10887 start_reg = reg + 2;
10888 }
10889 }
10890 if (start_reg != reg)
10891 saved_regs += vfp_emit_fstmx (start_reg,
10892 (reg - start_reg) / 2);
10893 }
10894 }
10895
10896 if (frame_pointer_needed)
10897 {
10898
10899 insn = GEN_INT (-(4 + args_to_push + fp_offset));
10900 insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
10901 RTX_FRAME_RELATED_P (insn) = 1;
10902
10903 if (IS_NESTED (func_type))
10904 {
10905
10906 if (regs_ever_live [3] == 0
10907 || saved_pretend_args)
10908 insn = gen_rtx_REG (SImode, 3);
10909 else
10910 {
10911 insn = plus_constant (hard_frame_pointer_rtx, 4);
10912 insn = gen_frame_mem (SImode, insn);
10913 }
10914
10915 emit_set_insn (ip_rtx, insn);
10916
10917 emit_insn (gen_prologue_use (ip_rtx));
10918 }
10919 }
10920
10921 offsets = arm_get_frame_offsets ();
10922 if (offsets->outgoing_args != offsets->saved_args + saved_regs)
10923 {
10924
10925
10926 rtx last = get_last_insn ();
10927
10928 amount = GEN_INT (offsets->saved_args + saved_regs
10929 - offsets->outgoing_args);
10930
10931 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
10932 amount));
10933 do
10934 {
10935 last = last ? NEXT_INSN (last) : get_insns ();
10936 RTX_FRAME_RELATED_P (last) = 1;
10937 }
10938 while (last != insn);
10939
10940
10941
10942
10943 if (frame_pointer_needed)
10944 insn = emit_insn (gen_stack_tie (stack_pointer_rtx,
10945 hard_frame_pointer_rtx));
10946 }
10947
10948
10949 if (flag_pic && arm_pic_register != INVALID_REGNUM)
10950 arm_load_pic_register (0UL);
10951
10952
10953
10954
10955
10956
10957 if (current_function_profile || !TARGET_SCHED_PROLOG
10958 || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
10959 emit_insn (gen_blockage ());
10960
10961
10962
10963 if ((live_regs_mask & (1 << LR_REGNUM)) == 0)
10964 {
10965 emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
10966 cfun->machine->lr_save_eliminated = 1;
10967 }
10968 }
10969
10970
10971
10972
10973
10974
10975
10976
10977
10978
10979
10980
10981
10982
10983 void
10984 arm_print_operand (FILE *stream, rtx x, int code)
10985 {
10986 switch (code)
10987 {
10988 case '@':
10989 fputs (ASM_COMMENT_START, stream);
10990 return;
10991
10992 case '_':
10993 fputs (user_label_prefix, stream);
10994 return;
10995
10996 case '|':
10997 fputs (REGISTER_PREFIX, stream);
10998 return;
10999
11000 case '?':
11001 if (arm_ccfsm_state == 3 || arm_ccfsm_state == 4)
11002 {
11003 if (TARGET_THUMB)
11004 {
11005 output_operand_lossage ("predicated Thumb instruction");
11006 break;
11007 }
11008 if (current_insn_predicate != NULL)
11009 {
11010 output_operand_lossage
11011 ("predicated instruction in conditional sequence");
11012 break;
11013 }
11014
11015 fputs (arm_condition_codes[arm_current_cc], stream);
11016 }
11017 else if (current_insn_predicate)
11018 {
11019 enum arm_cond_code code;
11020
11021 if (TARGET_THUMB)
11022 {
11023 output_operand_lossage ("predicated Thumb instruction");
11024 break;
11025 }
11026
11027 code = get_arm_condition_code (current_insn_predicate);
11028 fputs (arm_condition_codes[code], stream);
11029 }
11030 return;
11031
11032 case 'N':
11033 {
11034 REAL_VALUE_TYPE r;
11035 REAL_VALUE_FROM_CONST_DOUBLE (r, x);
11036 r = REAL_VALUE_NEGATE (r);
11037 fprintf (stream, "%s", fp_const_from_val (&r));
11038 }
11039 return;
11040
11041 case 'B':
11042 if (GET_CODE (x) == CONST_INT)
11043 {
11044 HOST_WIDE_INT val;
11045 val = ARM_SIGN_EXTEND (~INTVAL (x));
11046 fprintf (stream, HOST_WIDE_INT_PRINT_DEC, val);
11047 }
11048 else
11049 {
11050 putc ('~', stream);
11051 output_addr_const (stream, x);
11052 }
11053 return;
11054
11055 case 'i':
11056 fprintf (stream, "%s", arithmetic_instr (x, 1));
11057 return;
11058
11059
11060 case 's':
11061 if (GET_CODE (x) == CONST_INT)
11062 {
11063 fprintf (stream, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) & 0x3f);
11064 return;
11065 }
11066 arm_print_operand (stream, x, 0);
11067 return;
11068
11069 case 'I':
11070 fprintf (stream, "%s", arithmetic_instr (x, 0));
11071 return;
11072
11073 case 'S':
11074 {
11075 HOST_WIDE_INT val;
11076 const char *shift;
11077
11078 if (!shift_operator (x, SImode))
11079 {
11080 output_operand_lossage ("invalid shift operand");
11081 break;
11082 }
11083
11084 shift = shift_op (x, &val);
11085
11086 if (shift)
11087 {
11088 fprintf (stream, ", %s ", shift);
11089 if (val == -1)
11090 arm_print_operand (stream, XEXP (x, 1), 0);
11091 else
11092 fprintf (stream, "#" HOST_WIDE_INT_PRINT_DEC, val);
11093 }
11094 }
11095 return;
11096
11097
11098
11099
11100
11101
11102
11103
11104
11105
11106
11107
11108
11109
11110
11111
11112
11113
11114
11115
11116
11117
11118
11119
11120
11121
11122
11123
11124 case 'Q':
11125 if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11126 {
11127 output_operand_lossage ("invalid operand for code '%c'", code);
11128 return;
11129 }
11130
11131 asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 1 : 0));
11132 return;
11133
11134 case 'R':
11135 if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11136 {
11137 output_operand_lossage ("invalid operand for code '%c'", code);
11138 return;
11139 }
11140
11141 asm_fprintf (stream, "%r", REGNO (x) + (WORDS_BIG_ENDIAN ? 0 : 1));
11142 return;
11143
11144 case 'H':
11145 if (GET_CODE (x) != REG || REGNO (x) > LAST_ARM_REGNUM)
11146 {
11147 output_operand_lossage ("invalid operand for code '%c'", code);
11148 return;
11149 }
11150
11151 asm_fprintf (stream, "%r", REGNO (x) + 1);
11152 return;
11153
11154 case 'm':
11155 asm_fprintf (stream, "%r",
11156 GET_CODE (XEXP (x, 0)) == REG
11157 ? REGNO (XEXP (x, 0)) : REGNO (XEXP (XEXP (x, 0), 0)));
11158 return;
11159
11160 case 'M':
11161 asm_fprintf (stream, "{%r-%r}",
11162 REGNO (x),
11163 REGNO (x) + ARM_NUM_REGS (GET_MODE (x)) - 1);
11164 return;
11165
11166 case 'd':
11167
11168 if (x == const_true_rtx)
11169 return;
11170
11171 if (!COMPARISON_P (x))
11172 {
11173 output_operand_lossage ("invalid operand for code '%c'", code);
11174 return;
11175 }
11176
11177 fputs (arm_condition_codes[get_arm_condition_code (x)],
11178 stream);
11179 return;
11180
11181 case 'D':
11182
11183
11184 if (x == const_true_rtx)
11185 {
11186 output_operand_lossage ("instruction never exectued");
11187 return;
11188 }
11189 if (!COMPARISON_P (x))
11190 {
11191 output_operand_lossage ("invalid operand for code '%c'", code);
11192 return;
11193 }
11194
11195 fputs (arm_condition_codes[ARM_INVERSE_CONDITION_CODE
11196 (get_arm_condition_code (x))],
11197 stream);
11198 return;
11199
11200
11201
11202
11203
11204
11205 case 'W':
11206 case 'X':
11207 case 'Y':
11208 case 'Z':
11209 gcc_assert (GET_CODE (x) == REG
11210 && REGNO_REG_CLASS (REGNO (x)) == CIRRUS_REGS);
11211
11212 fprintf (stream, "mv%s%s",
11213 code == 'W' ? "f"
11214 : code == 'X' ? "d"
11215 : code == 'Y' ? "fx" : "dx", reg_names[REGNO (x)] + 2);
11216
11217 return;
11218
11219
11220 case 'V':
11221 {
11222 int mode = GET_MODE (x);
11223
11224 if (GET_CODE (x) != REG || REGNO_REG_CLASS (REGNO (x)) != CIRRUS_REGS)
11225 {
11226 output_operand_lossage ("invalid operand for code '%c'", code);
11227 return;
11228 }
11229
11230 fprintf (stream, "mv%s%s",
11231 mode == DFmode ? "d"
11232 : mode == SImode ? "fx"
11233 : mode == DImode ? "dx"
11234 : "f", reg_names[REGNO (x)] + 2);
11235
11236 return;
11237 }
11238
11239 case 'U':
11240 if (GET_CODE (x) != REG
11241 || REGNO (x) < FIRST_IWMMXT_GR_REGNUM
11242 || REGNO (x) > LAST_IWMMXT_GR_REGNUM)
11243
11244 {
11245 output_operand_lossage ("invalid operand for code '%c'", code);
11246 return;
11247 }
11248
11249 else
11250 fprintf (stream, "%d", REGNO (x) - FIRST_IWMMXT_GR_REGNUM);
11251 return;
11252
11253
11254 case 'w':
11255 if (GET_CODE (x) != CONST_INT
11256 || INTVAL (x) < 0
11257 || INTVAL (x) >= 16)
11258
11259 {
11260 output_operand_lossage ("invalid operand for code '%c'", code);
11261 return;
11262 }
11263
11264 else
11265 {
11266 static const char * wc_reg_names [16] =
11267 {
11268 "wCID", "wCon", "wCSSF", "wCASF",
11269 "wC4", "wC5", "wC6", "wC7",
11270 "wCGR0", "wCGR1", "wCGR2", "wCGR3",
11271 "wC12", "wC13", "wC14", "wC15"
11272 };
11273
11274 fprintf (stream, wc_reg_names [INTVAL (x)]);
11275 }
11276 return;
11277
11278
11279 case 'P':
11280 {
11281 int mode = GET_MODE (x);
11282 int num;
11283
11284 if (mode != DImode && mode != DFmode)
11285 {
11286 output_operand_lossage ("invalid operand for code '%c'", code);
11287 return;
11288 }
11289
11290 if (GET_CODE (x) != REG
11291 || !IS_VFP_REGNUM (REGNO (x)))
11292 {
11293 output_operand_lossage ("invalid operand for code '%c'", code);
11294 return;
11295 }
11296
11297 num = REGNO(x) - FIRST_VFP_REGNUM;
11298 if (num & 1)
11299 {
11300 output_operand_lossage ("invalid operand for code '%c'", code);
11301 return;
11302 }
11303
11304 fprintf (stream, "d%d", num >> 1);
11305 }
11306 return;
11307
11308 default:
11309 if (x == 0)
11310 {
11311 output_operand_lossage ("missing operand");
11312 return;
11313 }
11314
11315 switch (GET_CODE (x))
11316 {
11317 case REG:
11318 asm_fprintf (stream, "%r", REGNO (x));
11319 break;
11320
11321 case MEM:
11322 output_memory_reference_mode = GET_MODE (x);
11323 output_address (XEXP (x, 0));
11324 break;
11325
11326 case CONST_DOUBLE:
11327 fprintf (stream, "#%s", fp_immediate_constant (x));
11328 break;
11329
11330 default:
11331 gcc_assert (GET_CODE (x) != NEG);
11332 fputc ('#', stream);
11333 output_addr_const (stream, x);
11334 break;
11335 }
11336 }
11337 }
11338
11339 #ifndef AOF_ASSEMBLER
11340
11341
11342 static bool
11343 arm_assemble_integer (rtx x, unsigned int size, int aligned_p)
11344 {
11345 if (size == UNITS_PER_WORD && aligned_p)
11346 {
11347 fputs ("\t.word\t", asm_out_file);
11348 output_addr_const (asm_out_file, x);
11349
11350
11351
11352 if (NEED_GOT_RELOC && flag_pic && making_const_table &&
11353 (GET_CODE (x) == SYMBOL_REF || GET_CODE (x) == LABEL_REF))
11354 {
11355 if (GET_CODE (x) == SYMBOL_REF
11356 && (CONSTANT_POOL_ADDRESS_P (x)
11357 || SYMBOL_REF_LOCAL_P (x)))
11358 fputs ("(GOTOFF)", asm_out_file);
11359 else if (GET_CODE (x) == LABEL_REF)
11360 fputs ("(GOTOFF)", asm_out_file);
11361 else
11362 fputs ("(GOT)", asm_out_file);
11363 }
11364 fputc ('\n', asm_out_file);
11365 return true;
11366 }
11367
11368 if (arm_vector_mode_supported_p (GET_MODE (x)))
11369 {
11370 int i, units;
11371
11372 gcc_assert (GET_CODE (x) == CONST_VECTOR);
11373
11374 units = CONST_VECTOR_NUNITS (x);
11375
11376 switch (GET_MODE (x))
11377 {
11378 case V2SImode: size = 4; break;
11379 case V4HImode: size = 2; break;
11380 case V8QImode: size = 1; break;
11381 default:
11382 gcc_unreachable ();
11383 }
11384
11385 for (i = 0; i < units; i++)
11386 {
11387 rtx elt;
11388
11389 elt = CONST_VECTOR_ELT (x, i);
11390 assemble_integer
11391 (elt, size, i == 0 ? BIGGEST_ALIGNMENT : size * BITS_PER_UNIT, 1);
11392 }
11393
11394 return true;
11395 }
11396
11397 return default_assemble_integer (x, size, aligned_p);
11398 }
11399
11400
11401
11402
11403 static void
11404 arm_elf_asm_constructor (rtx symbol, int priority ATTRIBUTE_UNUSED)
11405 {
11406 if (!TARGET_AAPCS_BASED)
11407 {
11408 default_named_section_asm_out_constructor (symbol, priority);
11409 return;
11410 }
11411
11412
11413 switch_to_section (ctors_section);
11414 assemble_align (POINTER_SIZE);
11415 fputs ("\t.word\t", asm_out_file);
11416 output_addr_const (asm_out_file, symbol);
11417 fputs ("(target1)\n", asm_out_file);
11418 }
11419 #endif
11420
11421
11422
11423
11424
11425
11426
11427
11428
11429
11430
11431
11432
11433
11434
11435
11436
11437
11438
11439
11440
11441
11442
11443
11444
11445
11446
11447
11448
11449
11450
11451
11452
11453
11454
11455 static enum arm_cond_code
11456 get_arm_condition_code (rtx comparison)
11457 {
11458 enum machine_mode mode = GET_MODE (XEXP (comparison, 0));
11459 int code;
11460 enum rtx_code comp_code = GET_CODE (comparison);
11461
11462 if (GET_MODE_CLASS (mode) != MODE_CC)
11463 mode = SELECT_CC_MODE (comp_code, XEXP (comparison, 0),
11464 XEXP (comparison, 1));
11465
11466 switch (mode)
11467 {
11468 case CC_DNEmode: code = ARM_NE; goto dominance;
11469 case CC_DEQmode: code = ARM_EQ; goto dominance;
11470 case CC_DGEmode: code = ARM_GE; goto dominance;
11471 case CC_DGTmode: code = ARM_GT; goto dominance;
11472 case CC_DLEmode: code = ARM_LE; goto dominance;
11473 case CC_DLTmode: code = ARM_LT; goto dominance;
11474 case CC_DGEUmode: code = ARM_CS; goto dominance;
11475 case CC_DGTUmode: code = ARM_HI; goto dominance;
11476 case CC_DLEUmode: code = ARM_LS; goto dominance;
11477 case CC_DLTUmode: code = ARM_CC;
11478
11479 dominance:
11480 gcc_assert (comp_code == EQ || comp_code == NE);
11481
11482 if (comp_code == EQ)
11483 return ARM_INVERSE_CONDITION_CODE (code);
11484 return code;
11485
11486 case CC_NOOVmode:
11487 switch (comp_code)
11488 {
11489 case NE: return ARM_NE;
11490 case EQ: return ARM_EQ;
11491 case GE: return ARM_PL;
11492 case LT: return ARM_MI;
11493 default: gcc_unreachable ();
11494 }
11495
11496 case CC_Zmode:
11497 switch (comp_code)
11498 {
11499 case NE: return ARM_NE;
11500 case EQ: return ARM_EQ;
11501 default: gcc_unreachable ();
11502 }
11503
11504 case CC_Nmode:
11505 switch (comp_code)
11506 {
11507 case NE: return ARM_MI;
11508 case EQ: return ARM_PL;
11509 default: gcc_unreachable ();
11510 }
11511
11512 case CCFPEmode:
11513 case CCFPmode:
11514
11515
11516
11517 switch (comp_code)
11518 {
11519 case GE: return ARM_GE;
11520 case GT: return ARM_GT;
11521 case LE: return ARM_LS;
11522 case LT: return ARM_MI;
11523 case NE: return ARM_NE;
11524 case EQ: return ARM_EQ;
11525 case ORDERED: return ARM_VC;
11526 case UNORDERED: return ARM_VS;
11527 case UNLT: return ARM_LT;
11528 case UNLE: return ARM_LE;
11529 case UNGT: return ARM_HI;
11530 case UNGE: return ARM_PL;
11531
11532 case UNEQ:
11533 case LTGT:
11534 default: gcc_unreachable ();
11535 }
11536
11537 case CC_SWPmode:
11538 switch (comp_code)
11539 {
11540 case NE: return ARM_NE;
11541 case EQ: return ARM_EQ;
11542 case GE: return ARM_LE;
11543 case GT: return ARM_LT;
11544 case LE: return ARM_GE;
11545 case LT: return ARM_GT;
11546 case GEU: return ARM_LS;
11547 case GTU: return ARM_CC;
11548 case LEU: return ARM_CS;
11549 case LTU: return ARM_HI;
11550 default: gcc_unreachable ();
11551 }
11552
11553 case CC_Cmode:
11554 switch (comp_code)
11555 {
11556 case LTU: return ARM_CS;
11557 case GEU: return ARM_CC;
11558 default: gcc_unreachable ();
11559 }
11560
11561 case CCmode:
11562 switch (comp_code)
11563 {
11564 case NE: return ARM_NE;
11565 case EQ: return ARM_EQ;
11566 case GE: return ARM_GE;
11567 case GT: return ARM_GT;
11568 case LE: return ARM_LE;
11569 case LT: return ARM_LT;
11570 case GEU: return ARM_CS;
11571 case GTU: return ARM_HI;
11572 case LEU: return ARM_LS;
11573 case LTU: return ARM_CC;
11574 default: gcc_unreachable ();
11575 }
11576
11577 default: gcc_unreachable ();
11578 }
11579 }
11580
11581 void
11582 arm_final_prescan_insn (rtx insn)
11583 {
11584
11585 rtx body = PATTERN (insn);
11586
11587
11588
11589 int reverse = 0;
11590
11591
11592
11593
11594
11595 int jump_clobbers = 0;
11596
11597
11598 int seeking_return = 0;
11599
11600
11601
11602 rtx start_insn = insn;
11603
11604
11605
11606 if (arm_ccfsm_state == 4)
11607 {
11608 if (insn == arm_target_insn)
11609 {
11610 arm_target_insn = NULL;
11611 arm_ccfsm_state = 0;
11612 }
11613 return;
11614 }
11615
11616
11617
11618
11619
11620 if (arm_ccfsm_state == 3)
11621 {
11622 if (simplejump_p (insn))
11623 {
11624 start_insn = next_nonnote_insn (start_insn);
11625 if (GET_CODE (start_insn) == BARRIER)
11626 {
11627
11628 start_insn = next_nonnote_insn (start_insn);
11629 }
11630 if (GET_CODE (start_insn) == CODE_LABEL
11631 && CODE_LABEL_NUMBER (start_insn) == arm_target_label
11632 && LABEL_NUSES (start_insn) == 1)
11633 reverse = TRUE;
11634 else
11635 return;
11636 }
11637 else if (GET_CODE (body) == RETURN)
11638 {
11639 start_insn = next_nonnote_insn (start_insn);
11640 if (GET_CODE (start_insn) == BARRIER)
11641 start_insn = next_nonnote_insn (start_insn);
11642 if (GET_CODE (start_insn) == CODE_LABEL
11643 && CODE_LABEL_NUMBER (start_insn) == arm_target_label
11644 && LABEL_NUSES (start_insn) == 1)
11645 {
11646 reverse = TRUE;
11647 seeking_return = 1;
11648 }
11649 else
11650 return;
11651 }
11652 else
11653 return;
11654 }
11655
11656 gcc_assert (!arm_ccfsm_state || reverse);
11657 if (GET_CODE (insn) != JUMP_INSN)
11658 return;
11659
11660
11661
11662 if (GET_CODE (body) == PARALLEL && XVECLEN (body, 0) > 0)
11663 body = XVECEXP (body, 0, 0);
11664
11665 if (reverse
11666 || (GET_CODE (body) == SET && GET_CODE (SET_DEST (body)) == PC
11667 && GET_CODE (SET_SRC (body)) == IF_THEN_ELSE))
11668 {
11669 int insns_skipped;
11670 int fail = FALSE, succeed = FALSE;
11671
11672 int then_not_else = TRUE;
11673 rtx this_insn = start_insn, label = 0;
11674
11675
11676
11677 if (get_attr_conds (insn) == CONDS_JUMP_CLOB)
11678 {
11679 jump_clobbers = 1;
11680 return;
11681 }
11682
11683
11684 if (reverse)
11685 {
11686 if (!seeking_return)
11687 label = XEXP (SET_SRC (body), 0);
11688 }
11689 else if (GET_CODE (XEXP (SET_SRC (body), 1)) == LABEL_REF)
11690 label = XEXP (XEXP (SET_SRC (body), 1), 0);
11691 else if (GET_CODE (XEXP (SET_SRC (body), 2)) == LABEL_REF)
11692 {
11693 label = XEXP (XEXP (SET_SRC (body), 2), 0);
11694 then_not_else = FALSE;
11695 }
11696 else if (GET_CODE (XEXP (SET_SRC (body), 1)) == RETURN)
11697 seeking_return = 1;
11698 else if (GET_CODE (XEXP (SET_SRC (body), 2)) == RETURN)
11699 {
11700 seeking_return = 1;
11701 then_not_else = FALSE;
11702 }
11703 else
11704 gcc_unreachable ();
11705
11706
11707
11708
11709 for (insns_skipped = 0;
11710 !fail && !succeed && insns_skipped++ < max_insns_skipped;)
11711 {
11712 rtx scanbody;
11713
11714 this_insn = next_nonnote_insn (this_insn);
11715 if (!this_insn)
11716 break;
11717
11718 switch (GET_CODE (this_insn))
11719 {
11720 case CODE_LABEL:
11721
11722
11723 if (this_insn == label)
11724 {
11725 if (jump_clobbers)
11726 {
11727 arm_ccfsm_state = 2;
11728 this_insn = next_nonnote_insn (this_insn);
11729 }
11730 else
11731 arm_ccfsm_state = 1;
11732 succeed = TRUE;
11733 }
11734 else
11735 fail = TRUE;
11736 break;
11737
11738 case BARRIER:
11739
11740
11741
11742
11743 this_insn = next_nonnote_insn (this_insn);
11744 if (this_insn && this_insn == label)
11745 {
11746 if (jump_clobbers)
11747 {
11748 arm_ccfsm_state = 2;
11749 this_insn = next_nonnote_insn (this_insn);
11750 }
11751 else
11752 arm_ccfsm_state = 1;
11753 succeed = TRUE;
11754 }
11755 else
11756 fail = TRUE;
11757 break;
11758
11759 case CALL_INSN:
11760
11761
11762
11763
11764 if (arm_arch5)
11765 {
11766 fail = TRUE;
11767 break;
11768 }
11769
11770
11771
11772
11773 this_insn = next_nonnote_insn (this_insn);
11774 if (this_insn && GET_CODE (this_insn) == BARRIER)
11775 this_insn = next_nonnote_insn (this_insn);
11776
11777 if (this_insn && this_insn == label
11778 && insns_skipped < max_insns_skipped)
11779 {
11780 if (jump_clobbers)
11781 {
11782 arm_ccfsm_state = 2;
11783 this_insn = next_nonnote_insn (this_insn);
11784 }
11785 else
11786 arm_ccfsm_state = 1;
11787 succeed = TRUE;
11788 }
11789 else
11790 fail = TRUE;
11791 break;
11792
11793 case JUMP_INSN:
11794
11795
11796
11797
11798
11799
11800 scanbody = PATTERN (this_insn);
11801 if (GET_CODE (scanbody) == SET
11802 && GET_CODE (SET_DEST (scanbody)) == PC)
11803 {
11804 if (GET_CODE (SET_SRC (scanbody)) == LABEL_REF
11805 && XEXP (SET_SRC (scanbody), 0) == label && !reverse)
11806 {
11807 arm_ccfsm_state = 2;
11808 succeed = TRUE;
11809 }
11810 else if (GET_CODE (SET_SRC (scanbody)) == IF_THEN_ELSE)
11811 fail = TRUE;
11812 }
11813
11814
11815 else if (GET_CODE (scanbody) == RETURN
11816 && !use_return_insn (TRUE, NULL)
11817 && !optimize_size)
11818 fail = TRUE;
11819 else if (GET_CODE (scanbody) == RETURN
11820 && seeking_return)
11821 {
11822 arm_ccfsm_state = 2;
11823 succeed = TRUE;
11824 }
11825 else if (GET_CODE (scanbody) == PARALLEL)
11826 {
11827 switch (get_attr_conds (this_insn))
11828 {
11829 case CONDS_NOCOND:
11830 break;
11831 default:
11832 fail = TRUE;
11833 break;
11834 }
11835 }
11836 else
11837 fail = TRUE;
11838
11839 break;
11840
11841 case INSN:
11842
11843
11844 scanbody = PATTERN (this_insn);
11845 if (!(GET_CODE (scanbody) == SET
11846 || GET_CODE (scanbody) == PARALLEL)
11847 || get_attr_conds (this_insn) != CONDS_NOCOND)
11848 fail = TRUE;
11849
11850
11851
11852
11853
11854
11855
11856
11857 if (GET_CODE (scanbody) != USE
11858 && GET_CODE (scanbody) != CLOBBER
11859 && get_attr_cirrus (this_insn) != CIRRUS_NOT)
11860 fail = TRUE;
11861 break;
11862
11863 default:
11864 break;
11865 }
11866 }
11867 if (succeed)
11868 {
11869 if ((!seeking_return) && (arm_ccfsm_state == 1 || reverse))
11870 arm_target_label = CODE_LABEL_NUMBER (label);
11871 else
11872 {
11873 gcc_assert (seeking_return || arm_ccfsm_state == 2);
11874
11875 while (this_insn && GET_CODE (PATTERN (this_insn)) == USE)
11876 {
11877 this_insn = next_nonnote_insn (this_insn);
11878 gcc_assert (!this_insn
11879 || (GET_CODE (this_insn) != BARRIER
11880 && GET_CODE (this_insn) != CODE_LABEL));
11881 }
11882 if (!this_insn)
11883 {
11884
11885 recog (PATTERN (insn), insn, NULL);
11886 arm_ccfsm_state = 0;
11887 arm_target_insn = NULL;
11888 return;
11889 }
11890 arm_target_insn = this_insn;
11891 }
11892 if (jump_clobbers)
11893 {
11894 gcc_assert (!reverse);
11895 arm_current_cc =
11896 get_arm_condition_code (XEXP (XEXP (XEXP (SET_SRC (body),
11897 0), 0), 1));
11898 if (GET_CODE (XEXP (XEXP (SET_SRC (body), 0), 0)) == AND)
11899 arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
11900 if (GET_CODE (XEXP (SET_SRC (body), 0)) == NE)
11901 arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
11902 }
11903 else
11904 {
11905
11906
11907 if (!reverse)
11908 arm_current_cc = get_arm_condition_code (XEXP (SET_SRC (body),
11909 0));
11910 }
11911
11912 if (reverse || then_not_else)
11913 arm_current_cc = ARM_INVERSE_CONDITION_CODE (arm_current_cc);
11914 }
11915
11916
11917
11918
11919
11920 recog (PATTERN (insn), insn, NULL);
11921 }
11922 }
11923
11924
11925
11926 int
11927 arm_hard_regno_mode_ok (unsigned int regno, enum machine_mode mode)
11928 {
11929 if (GET_MODE_CLASS (mode) == MODE_CC)
11930 return (regno == CC_REGNUM
11931 || (TARGET_HARD_FLOAT && TARGET_VFP
11932 && regno == VFPCC_REGNUM));
11933
11934 if (TARGET_THUMB)
11935
11936
11937
11938
11939
11940 return (ARM_NUM_REGS (mode) < 2) || (regno < LAST_LO_REGNUM);
11941
11942 if (TARGET_HARD_FLOAT && TARGET_MAVERICK
11943 && IS_CIRRUS_REGNUM (regno))
11944
11945
11946
11947
11948
11949 return (GET_MODE_CLASS (mode) == MODE_FLOAT) || (mode == DImode);
11950
11951 if (TARGET_HARD_FLOAT && TARGET_VFP
11952 && IS_VFP_REGNUM (regno))
11953 {
11954 if (mode == SFmode || mode == SImode)
11955 return TRUE;
11956
11957
11958 if (mode == DFmode)
11959 return ((regno - FIRST_VFP_REGNUM) & 1) == 0;
11960 return FALSE;
11961 }
11962
11963 if (TARGET_REALLY_IWMMXT)
11964 {
11965 if (IS_IWMMXT_GR_REGNUM (regno))
11966 return mode == SImode;
11967
11968 if (IS_IWMMXT_REGNUM (regno))
11969 return VALID_IWMMXT_REG_MODE (mode);
11970 }
11971
11972
11973
11974
11975 if (regno <= LAST_ARM_REGNUM)
11976 return !(TARGET_LDRD && GET_MODE_SIZE (mode) > 4 && (regno & 1) != 0);
11977
11978 if (regno == FRAME_POINTER_REGNUM
11979 || regno == ARG_POINTER_REGNUM)
11980
11981 return GET_MODE_CLASS (mode) == MODE_INT;
11982
11983
11984
11985 return (TARGET_HARD_FLOAT && TARGET_FPA
11986 && GET_MODE_CLASS (mode) == MODE_FLOAT
11987 && regno >= FIRST_FPA_REGNUM
11988 && regno <= LAST_FPA_REGNUM);
11989 }
11990
11991 int
11992 arm_regno_class (int regno)
11993 {
11994 if (TARGET_THUMB)
11995 {
11996 if (regno == STACK_POINTER_REGNUM)
11997 return STACK_REG;
11998 if (regno == CC_REGNUM)
11999 return CC_REG;
12000 if (regno < 8)
12001 return LO_REGS;
12002 return HI_REGS;
12003 }
12004
12005 if ( regno <= LAST_ARM_REGNUM
12006 || regno == FRAME_POINTER_REGNUM
12007 || regno == ARG_POINTER_REGNUM)
12008 return GENERAL_REGS;
12009
12010 if (regno == CC_REGNUM || regno == VFPCC_REGNUM)
12011 return NO_REGS;
12012
12013 if (IS_CIRRUS_REGNUM (regno))
12014 return CIRRUS_REGS;
12015
12016 if (IS_VFP_REGNUM (regno))
12017 return VFP_REGS;
12018
12019 if (IS_IWMMXT_REGNUM (regno))
12020 return IWMMXT_REGS;
12021
12022 if (IS_IWMMXT_GR_REGNUM (regno))
12023 return IWMMXT_GR_REGS;
12024
12025 return FPA_REGS;
12026 }
12027
12028
12029
12030 int
12031 arm_debugger_arg_offset (int value, rtx addr)
12032 {
12033 rtx insn;
12034
12035
12036 if (value != 0)
12037 return 0;
12038
12039
12040 if (GET_CODE (addr) != REG)
12041 return 0;
12042
12043
12044
12045 if (REGNO (addr) == (unsigned) HARD_FRAME_POINTER_REGNUM)
12046 return 0;
12047
12048
12049
12050 if ((TARGET_THUMB || !frame_pointer_needed)
12051 && REGNO (addr) == SP_REGNUM)
12052 return 0;
12053
12054
12055
12056
12057
12058
12059
12060
12061
12062
12063
12064
12065
12066
12067
12068
12069
12070
12071
12072
12073
12074
12075
12076
12077
12078
12079
12080
12081
12082
12083
12084 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
12085 {
12086 if ( GET_CODE (insn) == INSN
12087 && GET_CODE (PATTERN (insn)) == SET
12088 && REGNO (XEXP (PATTERN (insn), 0)) == REGNO (addr)
12089 && GET_CODE (XEXP (PATTERN (insn), 1)) == PLUS
12090 && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 0)) == REG
12091 && REGNO (XEXP (XEXP (PATTERN (insn), 1), 0)) == (unsigned) HARD_FRAME_POINTER_REGNUM
12092 && GET_CODE (XEXP (XEXP (PATTERN (insn), 1), 1)) == CONST_INT
12093 )
12094 {
12095 value = INTVAL (XEXP (XEXP (PATTERN (insn), 1), 1));
12096
12097 break;
12098 }
12099 }
12100
12101 if (value == 0)
12102 {
12103 debug_rtx (addr);
12104 warning (0, "unable to compute real location of stacked parameter");
12105 value = 8;
12106 }
12107
12108 return value;
12109 }
12110
12111 #define def_mbuiltin(MASK, NAME, TYPE, CODE) \
12112 do \
12113 { \
12114 if ((MASK) & insn_flags) \
12115 lang_hooks.builtin_function ((NAME), (TYPE), (CODE), \
12116 BUILT_IN_MD, NULL, NULL_TREE); \
12117 } \
12118 while (0)
12119
12120 struct builtin_description
12121 {
12122 const unsigned int mask;
12123 const enum insn_code icode;
12124 const char * const name;
12125 const enum arm_builtins code;
12126 const enum rtx_code comparison;
12127 const unsigned int flag;
12128 };
12129
12130 static const struct builtin_description bdesc_2arg[] =
12131 {
12132 #define IWMMXT_BUILTIN(code, string, builtin) \
12133 { FL_IWMMXT, CODE_FOR_##code, "__builtin_arm_" string, \
12134 ARM_BUILTIN_##builtin, 0, 0 },
12135
12136 IWMMXT_BUILTIN (addv8qi3, "waddb", WADDB)
12137 IWMMXT_BUILTIN (addv4hi3, "waddh", WADDH)
12138 IWMMXT_BUILTIN (addv2si3, "waddw", WADDW)
12139 IWMMXT_BUILTIN (subv8qi3, "wsubb", WSUBB)
12140 IWMMXT_BUILTIN (subv4hi3, "wsubh", WSUBH)
12141 IWMMXT_BUILTIN (subv2si3, "wsubw", WSUBW)
12142 IWMMXT_BUILTIN (ssaddv8qi3, "waddbss", WADDSSB)
12143 IWMMXT_BUILTIN (ssaddv4hi3, "waddhss", WADDSSH)
12144 IWMMXT_BUILTIN (ssaddv2si3, "waddwss", WADDSSW)
12145 IWMMXT_BUILTIN (sssubv8qi3, "wsubbss", WSUBSSB)
12146 IWMMXT_BUILTIN (sssubv4hi3, "wsubhss", WSUBSSH)
12147 IWMMXT_BUILTIN (sssubv2si3, "wsubwss", WSUBSSW)
12148 IWMMXT_BUILTIN (usaddv8qi3, "waddbus", WADDUSB)
12149 IWMMXT_BUILTIN (usaddv4hi3, "waddhus", WADDUSH)
12150 IWMMXT_BUILTIN (usaddv2si3, "waddwus", WADDUSW)
12151 IWMMXT_BUILTIN (ussubv8qi3, "wsubbus", WSUBUSB)
12152 IWMMXT_BUILTIN (ussubv4hi3, "wsubhus", WSUBUSH)
12153 IWMMXT_BUILTIN (ussubv2si3, "wsubwus", WSUBUSW)
12154 IWMMXT_BUILTIN (mulv4hi3, "wmulul", WMULUL)
12155 IWMMXT_BUILTIN (smulv4hi3_highpart, "wmulsm", WMULSM)
12156 IWMMXT_BUILTIN (umulv4hi3_highpart, "wmulum", WMULUM)
12157 IWMMXT_BUILTIN (eqv8qi3, "wcmpeqb", WCMPEQB)
12158 IWMMXT_BUILTIN (eqv4hi3, "wcmpeqh", WCMPEQH)
12159 IWMMXT_BUILTIN (eqv2si3, "wcmpeqw", WCMPEQW)
12160 IWMMXT_BUILTIN (gtuv8qi3, "wcmpgtub", WCMPGTUB)
12161 IWMMXT_BUILTIN (gtuv4hi3, "wcmpgtuh", WCMPGTUH)
12162 IWMMXT_BUILTIN (gtuv2si3, "wcmpgtuw", WCMPGTUW)
12163 IWMMXT_BUILTIN (gtv8qi3, "wcmpgtsb", WCMPGTSB)
12164 IWMMXT_BUILTIN (gtv4hi3, "wcmpgtsh", WCMPGTSH)
12165 IWMMXT_BUILTIN (gtv2si3, "wcmpgtsw", WCMPGTSW)
12166 IWMMXT_BUILTIN (umaxv8qi3, "wmaxub", WMAXUB)
12167 IWMMXT_BUILTIN (smaxv8qi3, "wmaxsb", WMAXSB)
12168 IWMMXT_BUILTIN (umaxv4hi3, "wmaxuh", WMAXUH)
12169 IWMMXT_BUILTIN (smaxv4hi3, "wmaxsh", WMAXSH)
12170 IWMMXT_BUILTIN (umaxv2si3, "wmaxuw", WMAXUW)
12171 IWMMXT_BUILTIN (smaxv2si3, "wmaxsw", WMAXSW)
12172 IWMMXT_BUILTIN (uminv8qi3, "wminub", WMINUB)
12173 IWMMXT_BUILTIN (sminv8qi3, "wminsb", WMINSB)
12174 IWMMXT_BUILTIN (uminv4hi3, "wminuh", WMINUH)
12175 IWMMXT_BUILTIN (sminv4hi3, "wminsh", WMINSH)
12176 IWMMXT_BUILTIN (uminv2si3, "wminuw", WMINUW)
12177 IWMMXT_BUILTIN (sminv2si3, "wminsw", WMINSW)
12178 IWMMXT_BUILTIN (iwmmxt_anddi3, "wand", WAND)
12179 IWMMXT_BUILTIN (iwmmxt_nanddi3, "wandn", WANDN)
12180 IWMMXT_BUILTIN (iwmmxt_iordi3, "wor", WOR)
12181 IWMMXT_BUILTIN (iwmmxt_xordi3, "wxor", WXOR)
12182 IWMMXT_BUILTIN (iwmmxt_uavgv8qi3, "wavg2b", WAVG2B)
12183 IWMMXT_BUILTIN (iwmmxt_uavgv4hi3, "wavg2h", WAVG2H)
12184 IWMMXT_BUILTIN (iwmmxt_uavgrndv8qi3, "wavg2br", WAVG2BR)
12185 IWMMXT_BUILTIN (iwmmxt_uavgrndv4hi3, "wavg2hr", WAVG2HR)
12186 IWMMXT_BUILTIN (iwmmxt_wunpckilb, "wunpckilb", WUNPCKILB)
12187 IWMMXT_BUILTIN (iwmmxt_wunpckilh, "wunpckilh", WUNPCKILH)
12188 IWMMXT_BUILTIN (iwmmxt_wunpckilw, "wunpckilw", WUNPCKILW)
12189 IWMMXT_BUILTIN (iwmmxt_wunpckihb, "wunpckihb", WUNPCKIHB)
12190 IWMMXT_BUILTIN (iwmmxt_wunpckihh, "wunpckihh", WUNPCKIHH)
12191 IWMMXT_BUILTIN (iwmmxt_wunpckihw, "wunpckihw", WUNPCKIHW)
12192 IWMMXT_BUILTIN (iwmmxt_wmadds, "wmadds", WMADDS)
12193 IWMMXT_BUILTIN (iwmmxt_wmaddu, "wmaddu", WMADDU)
12194
12195 #define IWMMXT_BUILTIN2(code, builtin) \
12196 { FL_IWMMXT, CODE_FOR_##code, NULL, ARM_BUILTIN_##builtin, 0, 0 },
12197
12198 IWMMXT_BUILTIN2 (iwmmxt_wpackhss, WPACKHSS)
12199 IWMMXT_BUILTIN2 (iwmmxt_wpackwss, WPACKWSS)
12200 IWMMXT_BUILTIN2 (iwmmxt_wpackdss, WPACKDSS)
12201 IWMMXT_BUILTIN2 (iwmmxt_wpackhus, WPACKHUS)
12202 IWMMXT_BUILTIN2 (iwmmxt_wpackwus, WPACKWUS)
12203 IWMMXT_BUILTIN2 (iwmmxt_wpackdus, WPACKDUS)
12204 IWMMXT_BUILTIN2 (ashlv4hi3_di, WSLLH)
12205 IWMMXT_BUILTIN2 (ashlv4hi3, WSLLHI)
12206 IWMMXT_BUILTIN2 (ashlv2si3_di, WSLLW)
12207 IWMMXT_BUILTIN2 (ashlv2si3, WSLLWI)
12208 IWMMXT_BUILTIN2 (ashldi3_di, WSLLD)
12209 IWMMXT_BUILTIN2 (ashldi3_iwmmxt, WSLLDI)
12210 IWMMXT_BUILTIN2 (lshrv4hi3_di, WSRLH)
12211 IWMMXT_BUILTIN2 (lshrv4hi3, WSRLHI)
12212 IWMMXT_BUILTIN2 (lshrv2si3_di, WSRLW)
12213 IWMMXT_BUILTIN2 (lshrv2si3, WSRLWI)
12214 IWMMXT_BUILTIN2 (lshrdi3_di, WSRLD)
12215 IWMMXT_BUILTIN2 (lshrdi3_iwmmxt, WSRLDI)
12216 IWMMXT_BUILTIN2 (ashrv4hi3_di, WSRAH)
12217 IWMMXT_BUILTIN2 (ashrv4hi3, WSRAHI)
12218 IWMMXT_BUILTIN2 (ashrv2si3_di, WSRAW)
12219 IWMMXT_BUILTIN2 (ashrv2si3, WSRAWI)
12220 IWMMXT_BUILTIN2 (ashrdi3_di, WSRAD)
12221 IWMMXT_BUILTIN2 (ashrdi3_iwmmxt, WSRADI)
12222 IWMMXT_BUILTIN2 (rorv4hi3_di, WRORH)
12223 IWMMXT_BUILTIN2 (rorv4hi3, WRORHI)
12224 IWMMXT_BUILTIN2 (rorv2si3_di, WRORW)
12225 IWMMXT_BUILTIN2 (rorv2si3, WRORWI)
12226 IWMMXT_BUILTIN2 (rordi3_di, WRORD)
12227 IWMMXT_BUILTIN2 (rordi3, WRORDI)
12228 IWMMXT_BUILTIN2 (iwmmxt_wmacuz, WMACUZ)
12229 IWMMXT_BUILTIN2 (iwmmxt_wmacsz, WMACSZ)
12230 };
12231
12232 static const struct builtin_description bdesc_1arg[] =
12233 {
12234 IWMMXT_BUILTIN (iwmmxt_tmovmskb, "tmovmskb", TMOVMSKB)
12235 IWMMXT_BUILTIN (iwmmxt_tmovmskh, "tmovmskh", TMOVMSKH)
12236 IWMMXT_BUILTIN (iwmmxt_tmovmskw, "tmovmskw", TMOVMSKW)
12237 IWMMXT_BUILTIN (iwmmxt_waccb, "waccb", WACCB)
12238 IWMMXT_BUILTIN (iwmmxt_wacch, "wacch", WACCH)
12239 IWMMXT_BUILTIN (iwmmxt_waccw, "waccw", WACCW)
12240 IWMMXT_BUILTIN (iwmmxt_wunpckehub, "wunpckehub", WUNPCKEHUB)
12241 IWMMXT_BUILTIN (iwmmxt_wunpckehuh, "wunpckehuh", WUNPCKEHUH)
12242 IWMMXT_BUILTIN (iwmmxt_wunpckehuw, "wunpckehuw", WUNPCKEHUW)
12243 IWMMXT_BUILTIN (iwmmxt_wunpckehsb, "wunpckehsb", WUNPCKEHSB)
12244 IWMMXT_BUILTIN (iwmmxt_wunpckehsh, "wunpckehsh", WUNPCKEHSH)
12245 IWMMXT_BUILTIN (iwmmxt_wunpckehsw, "wunpckehsw", WUNPCKEHSW)
12246 IWMMXT_BUILTIN (iwmmxt_wunpckelub, "wunpckelub", WUNPCKELUB)
12247 IWMMXT_BUILTIN (iwmmxt_wunpckeluh, "wunpckeluh", WUNPCKELUH)
12248 IWMMXT_BUILTIN (iwmmxt_wunpckeluw, "wunpckeluw", WUNPCKELUW)
12249 IWMMXT_BUILTIN (iwmmxt_wunpckelsb, "wunpckelsb", WUNPCKELSB)
12250 IWMMXT_BUILTIN (iwmmxt_wunpckelsh, "wunpckelsh", WUNPCKELSH)
12251 IWMMXT_BUILTIN (iwmmxt_wunpckelsw, "wunpckelsw", WUNPCKELSW)
12252 };
12253
12254
12255
12256
12257 static void
12258 arm_init_iwmmxt_builtins (void)
12259 {
12260 const struct builtin_description * d;
12261 size_t i;
12262 tree endlink = void_list_node;
12263
12264 tree V2SI_type_node = build_vector_type_for_mode (intSI_type_node, V2SImode);
12265 tree V4HI_type_node = build_vector_type_for_mode (intHI_type_node, V4HImode);
12266 tree V8QI_type_node = build_vector_type_for_mode (intQI_type_node, V8QImode);
12267
12268 tree int_ftype_int
12269 = build_function_type (integer_type_node,
12270 tree_cons (NULL_TREE, integer_type_node, endlink));
12271 tree v8qi_ftype_v8qi_v8qi_int
12272 = build_function_type (V8QI_type_node,
12273 tree_cons (NULL_TREE, V8QI_type_node,
12274 tree_cons (NULL_TREE, V8QI_type_node,
12275 tree_cons (NULL_TREE,
12276 integer_type_node,
12277 endlink))));
12278 tree v4hi_ftype_v4hi_int
12279 = build_function_type (V4HI_type_node,
12280 tree_cons (NULL_TREE, V4HI_type_node,
12281 tree_cons (NULL_TREE, integer_type_node,
12282 endlink)));
12283 tree v2si_ftype_v2si_int
12284 = build_function_type (V2SI_type_node,
12285 tree_cons (NULL_TREE, V2SI_type_node,
12286 tree_cons (NULL_TREE, integer_type_node,
12287 endlink)));
12288 tree v2si_ftype_di_di
12289 = build_function_type (V2SI_type_node,
12290 tree_cons (NULL_TREE, long_long_integer_type_node,
12291 tree_cons (NULL_TREE, long_long_integer_type_node,
12292 endlink)));
12293 tree di_ftype_di_int
12294 = build_function_type (long_long_integer_type_node,
12295 tree_cons (NULL_TREE, long_long_integer_type_node,
12296 tree_cons (NULL_TREE, integer_type_node,
12297 endlink)));
12298 tree di_ftype_di_int_int
12299 = build_function_type (long_long_integer_type_node,
12300 tree_cons (NULL_TREE, long_long_integer_type_node,
12301 tree_cons (NULL_TREE, integer_type_node,
12302 tree_cons (NULL_TREE,
12303 integer_type_node,
12304 endlink))));
12305 tree int_ftype_v8qi
12306 = build_function_type (integer_type_node,
12307 tree_cons (NULL_TREE, V8QI_type_node,
12308 endlink));
12309 tree int_ftype_v4hi
12310 = build_function_type (integer_type_node,
12311 tree_cons (NULL_TREE, V4HI_type_node,
12312 endlink));
12313 tree int_ftype_v2si
12314 = build_function_type (integer_type_node,
12315 tree_cons (NULL_TREE, V2SI_type_node,
12316 endlink));
12317 tree int_ftype_v8qi_int
12318 = build_function_type (integer_type_node,
12319 tree_cons (NULL_TREE, V8QI_type_node,
12320 tree_cons (NULL_TREE, integer_type_node,
12321 endlink)));
12322 tree int_ftype_v4hi_int
12323 = build_function_type (integer_type_node,
12324 tree_cons (NULL_TREE, V4HI_type_node,
12325 tree_cons (NULL_TREE, integer_type_node,
12326 endlink)));
12327 tree int_ftype_v2si_int
12328 = build_function_type (integer_type_node,
12329 tree_cons (NULL_TREE, V2SI_type_node,
12330 tree_cons (NULL_TREE, integer_type_node,
12331 endlink)));
12332 tree v8qi_ftype_v8qi_int_int
12333 = build_function_type (V8QI_type_node,
12334 tree_cons (NULL_TREE, V8QI_type_node,
12335 tree_cons (NULL_TREE, integer_type_node,
12336 tree_cons (NULL_TREE,
12337 integer_type_node,
12338 endlink))));
12339 tree v4hi_ftype_v4hi_int_int
12340 = build_function_type (V4HI_type_node,
12341 tree_cons (NULL_TREE, V4HI_type_node,
12342 tree_cons (NULL_TREE, integer_type_node,
12343 tree_cons (NULL_TREE,
12344 integer_type_node,
12345 endlink))));
12346 tree v2si_ftype_v2si_int_int
12347 = build_function_type (V2SI_type_node,
12348 tree_cons (NULL_TREE, V2SI_type_node,
12349 tree_cons (NULL_TREE, integer_type_node,
12350 tree_cons (NULL_TREE,
12351 integer_type_node,
12352 endlink))));
12353
12354 tree v8qi_ftype_v4hi_v4hi
12355 = build_function_type (V8QI_type_node,
12356 tree_cons (NULL_TREE, V4HI_type_node,
12357 tree_cons (NULL_TREE, V4HI_type_node,
12358 endlink)));
12359 tree v4hi_ftype_v2si_v2si
12360 = build_function_type (V4HI_type_node,
12361 tree_cons (NULL_TREE, V2SI_type_node,
12362 tree_cons (NULL_TREE, V2SI_type_node,
12363 endlink)));
12364 tree v2si_ftype_v4hi_v4hi
12365 = build_function_type (V2SI_type_node,
12366 tree_cons (NULL_TREE, V4HI_type_node,
12367 tree_cons (NULL_TREE, V4HI_type_node,
12368 endlink)));
12369 tree v2si_ftype_v8qi_v8qi
12370 = build_function_type (V2SI_type_node,
12371 tree_cons (NULL_TREE, V8QI_type_node,
12372 tree_cons (NULL_TREE, V8QI_type_node,
12373 endlink)));
12374 tree v4hi_ftype_v4hi_di
12375 = build_function_type (V4HI_type_node,
12376 tree_cons (NULL_TREE, V4HI_type_node,
12377 tree_cons (NULL_TREE,
12378 long_long_integer_type_node,
12379 endlink)));
12380 tree v2si_ftype_v2si_di
12381 = build_function_type (V2SI_type_node,
12382 tree_cons (NULL_TREE, V2SI_type_node,
12383 tree_cons (NULL_TREE,
12384 long_long_integer_type_node,
12385 endlink)));
12386 tree void_ftype_int_int
12387 = build_function_type (void_type_node,
12388 tree_cons (NULL_TREE, integer_type_node,
12389 tree_cons (NULL_TREE, integer_type_node,
12390 endlink)));
12391 tree di_ftype_void
12392 = build_function_type (long_long_unsigned_type_node, endlink);
12393 tree di_ftype_v8qi
12394 = build_function_type (long_long_integer_type_node,
12395 tree_cons (NULL_TREE, V8QI_type_node,
12396 endlink));
12397 tree di_ftype_v4hi
12398 = build_function_type (long_long_integer_type_node,
12399 tree_cons (NULL_TREE, V4HI_type_node,
12400 endlink));
12401 tree di_ftype_v2si
12402 = build_function_type (long_long_integer_type_node,
12403 tree_cons (NULL_TREE, V2SI_type_node,
12404 endlink));
12405 tree v2si_ftype_v4hi
12406 = build_function_type (V2SI_type_node,
12407 tree_cons (NULL_TREE, V4HI_type_node,
12408 endlink));
12409 tree v4hi_ftype_v8qi
12410 = build_function_type (V4HI_type_node,
12411 tree_cons (NULL_TREE, V8QI_type_node,
12412 endlink));
12413
12414 tree di_ftype_di_v4hi_v4hi
12415 = build_function_type (long_long_unsigned_type_node,
12416 tree_cons (NULL_TREE,
12417 long_long_unsigned_type_node,
12418 tree_cons (NULL_TREE, V4HI_type_node,
12419 tree_cons (NULL_TREE,
12420 V4HI_type_node,
12421 endlink))));
12422
12423 tree di_ftype_v4hi_v4hi
12424 = build_function_type (long_long_unsigned_type_node,
12425 tree_cons (NULL_TREE, V4HI_type_node,
12426 tree_cons (NULL_TREE, V4HI_type_node,
12427 endlink)));
12428
12429
12430 tree v8qi_ftype_v8qi_v8qi
12431 = build_function_type (V8QI_type_node,
12432 tree_cons (NULL_TREE, V8QI_type_node,
12433 tree_cons (NULL_TREE, V8QI_type_node,
12434 endlink)));
12435 tree v4hi_ftype_v4hi_v4hi
12436 = build_function_type (V4HI_type_node,
12437 tree_cons (NULL_TREE, V4HI_type_node,
12438 tree_cons (NULL_TREE, V4HI_type_node,
12439 endlink)));
12440 tree v2si_ftype_v2si_v2si
12441 = build_function_type (V2SI_type_node,
12442 tree_cons (NULL_TREE, V2SI_type_node,
12443 tree_cons (NULL_TREE, V2SI_type_node,
12444 endlink)));
12445 tree di_ftype_di_di
12446 = build_function_type (long_long_unsigned_type_node,
12447 tree_cons (NULL_TREE, long_long_unsigned_type_node,
12448 tree_cons (NULL_TREE,
12449 long_long_unsigned_type_node,
12450 endlink)));
12451
12452
12453
12454 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
12455 {
12456
12457
12458 enum machine_mode mode;
12459 tree type;
12460
12461 if (d->name == 0)
12462 continue;
12463
12464 mode = insn_data[d->icode].operand[1].mode;
12465
12466 switch (mode)
12467 {
12468 case V8QImode:
12469 type = v8qi_ftype_v8qi_v8qi;
12470 break;
12471 case V4HImode:
12472 type = v4hi_ftype_v4hi_v4hi;
12473 break;
12474 case V2SImode:
12475 type = v2si_ftype_v2si_v2si;
12476 break;
12477 case DImode:
12478 type = di_ftype_di_di;
12479 break;
12480
12481 default:
12482 gcc_unreachable ();
12483 }
12484
12485 def_mbuiltin (d->mask, d->name, type, d->code);
12486 }
12487
12488
12489 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wzero", di_ftype_void, ARM_BUILTIN_WZERO);
12490 def_mbuiltin (FL_IWMMXT, "__builtin_arm_setwcx", void_ftype_int_int, ARM_BUILTIN_SETWCX);
12491 def_mbuiltin (FL_IWMMXT, "__builtin_arm_getwcx", int_ftype_int, ARM_BUILTIN_GETWCX);
12492
12493 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSLLH);
12494 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllw", v2si_ftype_v2si_di, ARM_BUILTIN_WSLLW);
12495 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslld", di_ftype_di_di, ARM_BUILTIN_WSLLD);
12496 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSLLHI);
12497 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsllwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSLLWI);
12498 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wslldi", di_ftype_di_int, ARM_BUILTIN_WSLLDI);
12499
12500 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRLH);
12501 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRLW);
12502 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrld", di_ftype_di_di, ARM_BUILTIN_WSRLD);
12503 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRLHI);
12504 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrlwi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRLWI);
12505 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrldi", di_ftype_di_int, ARM_BUILTIN_WSRLDI);
12506
12507 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrah", v4hi_ftype_v4hi_di, ARM_BUILTIN_WSRAH);
12508 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsraw", v2si_ftype_v2si_di, ARM_BUILTIN_WSRAW);
12509 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrad", di_ftype_di_di, ARM_BUILTIN_WSRAD);
12510 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrahi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSRAHI);
12511 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsrawi", v2si_ftype_v2si_int, ARM_BUILTIN_WSRAWI);
12512 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsradi", di_ftype_di_int, ARM_BUILTIN_WSRADI);
12513
12514 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorh", v4hi_ftype_v4hi_di, ARM_BUILTIN_WRORH);
12515 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorw", v2si_ftype_v2si_di, ARM_BUILTIN_WRORW);
12516 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrord", di_ftype_di_di, ARM_BUILTIN_WRORD);
12517 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorhi", v4hi_ftype_v4hi_int, ARM_BUILTIN_WRORHI);
12518 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrorwi", v2si_ftype_v2si_int, ARM_BUILTIN_WRORWI);
12519 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wrordi", di_ftype_di_int, ARM_BUILTIN_WRORDI);
12520
12521 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wshufh", v4hi_ftype_v4hi_int, ARM_BUILTIN_WSHUFH);
12522
12523 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadb", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADB);
12524 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadh", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADH);
12525 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadbz", v2si_ftype_v8qi_v8qi, ARM_BUILTIN_WSADBZ);
12526 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wsadhz", v2si_ftype_v4hi_v4hi, ARM_BUILTIN_WSADHZ);
12527
12528 def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsb", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMSB);
12529 def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMSH);
12530 def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmsw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMSW);
12531 def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmub", int_ftype_v8qi_int, ARM_BUILTIN_TEXTRMUB);
12532 def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuh", int_ftype_v4hi_int, ARM_BUILTIN_TEXTRMUH);
12533 def_mbuiltin (FL_IWMMXT, "__builtin_arm_textrmuw", int_ftype_v2si_int, ARM_BUILTIN_TEXTRMUW);
12534 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrb", v8qi_ftype_v8qi_int_int, ARM_BUILTIN_TINSRB);
12535 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrh", v4hi_ftype_v4hi_int_int, ARM_BUILTIN_TINSRH);
12536 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tinsrw", v2si_ftype_v2si_int_int, ARM_BUILTIN_TINSRW);
12537
12538 def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccb", di_ftype_v8qi, ARM_BUILTIN_WACCB);
12539 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wacch", di_ftype_v4hi, ARM_BUILTIN_WACCH);
12540 def_mbuiltin (FL_IWMMXT, "__builtin_arm_waccw", di_ftype_v2si, ARM_BUILTIN_WACCW);
12541
12542 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskb", int_ftype_v8qi, ARM_BUILTIN_TMOVMSKB);
12543 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskh", int_ftype_v4hi, ARM_BUILTIN_TMOVMSKH);
12544 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmovmskw", int_ftype_v2si, ARM_BUILTIN_TMOVMSKW);
12545
12546 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhss", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHSS);
12547 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackhus", v8qi_ftype_v4hi_v4hi, ARM_BUILTIN_WPACKHUS);
12548 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwus", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWUS);
12549 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackwss", v4hi_ftype_v2si_v2si, ARM_BUILTIN_WPACKWSS);
12550 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdus", v2si_ftype_di_di, ARM_BUILTIN_WPACKDUS);
12551 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wpackdss", v2si_ftype_di_di, ARM_BUILTIN_WPACKDSS);
12552
12553 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHUB);
12554 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHUH);
12555 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehuw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHUW);
12556 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKEHSB);
12557 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKEHSH);
12558 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckehsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKEHSW);
12559 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelub", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELUB);
12560 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELUH);
12561 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckeluw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELUW);
12562 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsb", v4hi_ftype_v8qi, ARM_BUILTIN_WUNPCKELSB);
12563 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsh", v2si_ftype_v4hi, ARM_BUILTIN_WUNPCKELSH);
12564 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wunpckelsw", di_ftype_v2si, ARM_BUILTIN_WUNPCKELSW);
12565
12566 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacs", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACS);
12567 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacsz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACSZ);
12568 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacu", di_ftype_di_v4hi_v4hi, ARM_BUILTIN_WMACU);
12569 def_mbuiltin (FL_IWMMXT, "__builtin_arm_wmacuz", di_ftype_v4hi_v4hi, ARM_BUILTIN_WMACUZ);
12570
12571 def_mbuiltin (FL_IWMMXT, "__builtin_arm_walign", v8qi_ftype_v8qi_v8qi_int, ARM_BUILTIN_WALIGN);
12572 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmia", di_ftype_di_int_int, ARM_BUILTIN_TMIA);
12573 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiaph", di_ftype_di_int_int, ARM_BUILTIN_TMIAPH);
12574 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabb", di_ftype_di_int_int, ARM_BUILTIN_TMIABB);
12575 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiabt", di_ftype_di_int_int, ARM_BUILTIN_TMIABT);
12576 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatb", di_ftype_di_int_int, ARM_BUILTIN_TMIATB);
12577 def_mbuiltin (FL_IWMMXT, "__builtin_arm_tmiatt", di_ftype_di_int_int, ARM_BUILTIN_TMIATT);
12578 }
12579
12580 static void
12581 arm_init_tls_builtins (void)
12582 {
12583 tree ftype;
12584 tree nothrow = tree_cons (get_identifier ("nothrow"), NULL, NULL);
12585 tree const_nothrow = tree_cons (get_identifier ("const"), NULL, nothrow);
12586
12587 ftype = build_function_type (ptr_type_node, void_list_node);
12588 lang_hooks.builtin_function ("__builtin_thread_pointer", ftype,
12589 ARM_BUILTIN_THREAD_POINTER, BUILT_IN_MD,
12590 NULL, const_nothrow);
12591 }
12592
12593 static void
12594 arm_init_builtins (void)
12595 {
12596 arm_init_tls_builtins ();
12597
12598 if (TARGET_REALLY_IWMMXT)
12599 arm_init_iwmmxt_builtins ();
12600 }
12601
12602
12603
12604
12605
12606 static rtx
12607 safe_vector_operand (rtx x, enum machine_mode mode)
12608 {
12609 if (x != const0_rtx)
12610 return x;
12611 x = gen_reg_rtx (mode);
12612
12613 emit_insn (gen_iwmmxt_clrdi (mode == DImode ? x
12614 : gen_rtx_SUBREG (DImode, x, 0)));
12615 return x;
12616 }
12617
12618
12619
12620 static rtx
12621 arm_expand_binop_builtin (enum insn_code icode,
12622 tree arglist, rtx target)
12623 {
12624 rtx pat;
12625 tree arg0 = TREE_VALUE (arglist);
12626 tree arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12627 rtx op0 = expand_normal (arg0);
12628 rtx op1 = expand_normal (arg1);
12629 enum machine_mode tmode = insn_data[icode].operand[0].mode;
12630 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
12631 enum machine_mode mode1 = insn_data[icode].operand[2].mode;
12632
12633 if (VECTOR_MODE_P (mode0))
12634 op0 = safe_vector_operand (op0, mode0);
12635 if (VECTOR_MODE_P (mode1))
12636 op1 = safe_vector_operand (op1, mode1);
12637
12638 if (! target
12639 || GET_MODE (target) != tmode
12640 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12641 target = gen_reg_rtx (tmode);
12642
12643 gcc_assert (GET_MODE (op0) == mode0 && GET_MODE (op1) == mode1);
12644
12645 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12646 op0 = copy_to_mode_reg (mode0, op0);
12647 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12648 op1 = copy_to_mode_reg (mode1, op1);
12649
12650 pat = GEN_FCN (icode) (target, op0, op1);
12651 if (! pat)
12652 return 0;
12653 emit_insn (pat);
12654 return target;
12655 }
12656
12657
12658
12659 static rtx
12660 arm_expand_unop_builtin (enum insn_code icode,
12661 tree arglist, rtx target, int do_load)
12662 {
12663 rtx pat;
12664 tree arg0 = TREE_VALUE (arglist);
12665 rtx op0 = expand_normal (arg0);
12666 enum machine_mode tmode = insn_data[icode].operand[0].mode;
12667 enum machine_mode mode0 = insn_data[icode].operand[1].mode;
12668
12669 if (! target
12670 || GET_MODE (target) != tmode
12671 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12672 target = gen_reg_rtx (tmode);
12673 if (do_load)
12674 op0 = gen_rtx_MEM (mode0, copy_to_mode_reg (Pmode, op0));
12675 else
12676 {
12677 if (VECTOR_MODE_P (mode0))
12678 op0 = safe_vector_operand (op0, mode0);
12679
12680 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12681 op0 = copy_to_mode_reg (mode0, op0);
12682 }
12683
12684 pat = GEN_FCN (icode) (target, op0);
12685 if (! pat)
12686 return 0;
12687 emit_insn (pat);
12688 return target;
12689 }
12690
12691
12692
12693
12694
12695
12696
12697 static rtx
12698 arm_expand_builtin (tree exp,
12699 rtx target,
12700 rtx subtarget ATTRIBUTE_UNUSED,
12701 enum machine_mode mode ATTRIBUTE_UNUSED,
12702 int ignore ATTRIBUTE_UNUSED)
12703 {
12704 const struct builtin_description * d;
12705 enum insn_code icode;
12706 tree fndecl = TREE_OPERAND (TREE_OPERAND (exp, 0), 0);
12707 tree arglist = TREE_OPERAND (exp, 1);
12708 tree arg0;
12709 tree arg1;
12710 tree arg2;
12711 rtx op0;
12712 rtx op1;
12713 rtx op2;
12714 rtx pat;
12715 int fcode = DECL_FUNCTION_CODE (fndecl);
12716 size_t i;
12717 enum machine_mode tmode;
12718 enum machine_mode mode0;
12719 enum machine_mode mode1;
12720 enum machine_mode mode2;
12721
12722 switch (fcode)
12723 {
12724 case ARM_BUILTIN_TEXTRMSB:
12725 case ARM_BUILTIN_TEXTRMUB:
12726 case ARM_BUILTIN_TEXTRMSH:
12727 case ARM_BUILTIN_TEXTRMUH:
12728 case ARM_BUILTIN_TEXTRMSW:
12729 case ARM_BUILTIN_TEXTRMUW:
12730 icode = (fcode == ARM_BUILTIN_TEXTRMSB ? CODE_FOR_iwmmxt_textrmsb
12731 : fcode == ARM_BUILTIN_TEXTRMUB ? CODE_FOR_iwmmxt_textrmub
12732 : fcode == ARM_BUILTIN_TEXTRMSH ? CODE_FOR_iwmmxt_textrmsh
12733 : fcode == ARM_BUILTIN_TEXTRMUH ? CODE_FOR_iwmmxt_textrmuh
12734 : CODE_FOR_iwmmxt_textrmw);
12735
12736 arg0 = TREE_VALUE (arglist);
12737 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12738 op0 = expand_normal (arg0);
12739 op1 = expand_normal (arg1);
12740 tmode = insn_data[icode].operand[0].mode;
12741 mode0 = insn_data[icode].operand[1].mode;
12742 mode1 = insn_data[icode].operand[2].mode;
12743
12744 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12745 op0 = copy_to_mode_reg (mode0, op0);
12746 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12747 {
12748
12749 error ("selector must be an immediate");
12750 return gen_reg_rtx (tmode);
12751 }
12752 if (target == 0
12753 || GET_MODE (target) != tmode
12754 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12755 target = gen_reg_rtx (tmode);
12756 pat = GEN_FCN (icode) (target, op0, op1);
12757 if (! pat)
12758 return 0;
12759 emit_insn (pat);
12760 return target;
12761
12762 case ARM_BUILTIN_TINSRB:
12763 case ARM_BUILTIN_TINSRH:
12764 case ARM_BUILTIN_TINSRW:
12765 icode = (fcode == ARM_BUILTIN_TINSRB ? CODE_FOR_iwmmxt_tinsrb
12766 : fcode == ARM_BUILTIN_TINSRH ? CODE_FOR_iwmmxt_tinsrh
12767 : CODE_FOR_iwmmxt_tinsrw);
12768 arg0 = TREE_VALUE (arglist);
12769 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12770 arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
12771 op0 = expand_normal (arg0);
12772 op1 = expand_normal (arg1);
12773 op2 = expand_normal (arg2);
12774 tmode = insn_data[icode].operand[0].mode;
12775 mode0 = insn_data[icode].operand[1].mode;
12776 mode1 = insn_data[icode].operand[2].mode;
12777 mode2 = insn_data[icode].operand[3].mode;
12778
12779 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12780 op0 = copy_to_mode_reg (mode0, op0);
12781 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12782 op1 = copy_to_mode_reg (mode1, op1);
12783 if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
12784 {
12785
12786 error ("selector must be an immediate");
12787 return const0_rtx;
12788 }
12789 if (target == 0
12790 || GET_MODE (target) != tmode
12791 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12792 target = gen_reg_rtx (tmode);
12793 pat = GEN_FCN (icode) (target, op0, op1, op2);
12794 if (! pat)
12795 return 0;
12796 emit_insn (pat);
12797 return target;
12798
12799 case ARM_BUILTIN_SETWCX:
12800 arg0 = TREE_VALUE (arglist);
12801 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12802 op0 = force_reg (SImode, expand_normal (arg0));
12803 op1 = expand_normal (arg1);
12804 emit_insn (gen_iwmmxt_tmcr (op1, op0));
12805 return 0;
12806
12807 case ARM_BUILTIN_GETWCX:
12808 arg0 = TREE_VALUE (arglist);
12809 op0 = expand_normal (arg0);
12810 target = gen_reg_rtx (SImode);
12811 emit_insn (gen_iwmmxt_tmrc (target, op0));
12812 return target;
12813
12814 case ARM_BUILTIN_WSHUFH:
12815 icode = CODE_FOR_iwmmxt_wshufh;
12816 arg0 = TREE_VALUE (arglist);
12817 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12818 op0 = expand_normal (arg0);
12819 op1 = expand_normal (arg1);
12820 tmode = insn_data[icode].operand[0].mode;
12821 mode1 = insn_data[icode].operand[1].mode;
12822 mode2 = insn_data[icode].operand[2].mode;
12823
12824 if (! (*insn_data[icode].operand[1].predicate) (op0, mode1))
12825 op0 = copy_to_mode_reg (mode1, op0);
12826 if (! (*insn_data[icode].operand[2].predicate) (op1, mode2))
12827 {
12828
12829 error ("mask must be an immediate");
12830 return const0_rtx;
12831 }
12832 if (target == 0
12833 || GET_MODE (target) != tmode
12834 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12835 target = gen_reg_rtx (tmode);
12836 pat = GEN_FCN (icode) (target, op0, op1);
12837 if (! pat)
12838 return 0;
12839 emit_insn (pat);
12840 return target;
12841
12842 case ARM_BUILTIN_WSADB:
12843 return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadb, arglist, target);
12844 case ARM_BUILTIN_WSADH:
12845 return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadh, arglist, target);
12846 case ARM_BUILTIN_WSADBZ:
12847 return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadbz, arglist, target);
12848 case ARM_BUILTIN_WSADHZ:
12849 return arm_expand_binop_builtin (CODE_FOR_iwmmxt_wsadhz, arglist, target);
12850
12851
12852 case ARM_BUILTIN_WMACS:
12853 case ARM_BUILTIN_WMACU:
12854 case ARM_BUILTIN_WALIGN:
12855 case ARM_BUILTIN_TMIA:
12856 case ARM_BUILTIN_TMIAPH:
12857 case ARM_BUILTIN_TMIATT:
12858 case ARM_BUILTIN_TMIATB:
12859 case ARM_BUILTIN_TMIABT:
12860 case ARM_BUILTIN_TMIABB:
12861 icode = (fcode == ARM_BUILTIN_WMACS ? CODE_FOR_iwmmxt_wmacs
12862 : fcode == ARM_BUILTIN_WMACU ? CODE_FOR_iwmmxt_wmacu
12863 : fcode == ARM_BUILTIN_TMIA ? CODE_FOR_iwmmxt_tmia
12864 : fcode == ARM_BUILTIN_TMIAPH ? CODE_FOR_iwmmxt_tmiaph
12865 : fcode == ARM_BUILTIN_TMIABB ? CODE_FOR_iwmmxt_tmiabb
12866 : fcode == ARM_BUILTIN_TMIABT ? CODE_FOR_iwmmxt_tmiabt
12867 : fcode == ARM_BUILTIN_TMIATB ? CODE_FOR_iwmmxt_tmiatb
12868 : fcode == ARM_BUILTIN_TMIATT ? CODE_FOR_iwmmxt_tmiatt
12869 : CODE_FOR_iwmmxt_walign);
12870 arg0 = TREE_VALUE (arglist);
12871 arg1 = TREE_VALUE (TREE_CHAIN (arglist));
12872 arg2 = TREE_VALUE (TREE_CHAIN (TREE_CHAIN (arglist)));
12873 op0 = expand_normal (arg0);
12874 op1 = expand_normal (arg1);
12875 op2 = expand_normal (arg2);
12876 tmode = insn_data[icode].operand[0].mode;
12877 mode0 = insn_data[icode].operand[1].mode;
12878 mode1 = insn_data[icode].operand[2].mode;
12879 mode2 = insn_data[icode].operand[3].mode;
12880
12881 if (! (*insn_data[icode].operand[1].predicate) (op0, mode0))
12882 op0 = copy_to_mode_reg (mode0, op0);
12883 if (! (*insn_data[icode].operand[2].predicate) (op1, mode1))
12884 op1 = copy_to_mode_reg (mode1, op1);
12885 if (! (*insn_data[icode].operand[3].predicate) (op2, mode2))
12886 op2 = copy_to_mode_reg (mode2, op2);
12887 if (target == 0
12888 || GET_MODE (target) != tmode
12889 || ! (*insn_data[icode].operand[0].predicate) (target, tmode))
12890 target = gen_reg_rtx (tmode);
12891 pat = GEN_FCN (icode) (target, op0, op1, op2);
12892 if (! pat)
12893 return 0;
12894 emit_insn (pat);
12895 return target;
12896
12897 case ARM_BUILTIN_WZERO:
12898 target = gen_reg_rtx (DImode);
12899 emit_insn (gen_iwmmxt_clrdi (target));
12900 return target;
12901
12902 case ARM_BUILTIN_THREAD_POINTER:
12903 return arm_load_tp (target);
12904
12905 default:
12906 break;
12907 }
12908
12909 for (i = 0, d = bdesc_2arg; i < ARRAY_SIZE (bdesc_2arg); i++, d++)
12910 if (d->code == (const enum arm_builtins) fcode)
12911 return arm_expand_binop_builtin (d->icode, arglist, target);
12912
12913 for (i = 0, d = bdesc_1arg; i < ARRAY_SIZE (bdesc_1arg); i++, d++)
12914 if (d->code == (const enum arm_builtins) fcode)
12915 return arm_expand_unop_builtin (d->icode, arglist, target, 0);
12916
12917
12918 return NULL_RTX;
12919 }
12920
12921
12922
12923
12924 inline static int
12925 number_of_first_bit_set (unsigned mask)
12926 {
12927 int bit;
12928
12929 for (bit = 0;
12930 (mask & (1 << bit)) == 0;
12931 ++bit)
12932 continue;
12933
12934 return bit;
12935 }
12936
12937
12938
12939
12940
12941
12942
12943
12944
12945 static void
12946 thumb_pushpop (FILE *f, unsigned long mask, int push, int *cfa_offset,
12947 unsigned long real_regs)
12948 {
12949 int regno;
12950 int lo_mask = mask & 0xFF;
12951 int pushed_words = 0;
12952
12953 gcc_assert (mask);
12954
12955 if (lo_mask == 0 && !push && (mask & (1 << PC_REGNUM)))
12956 {
12957
12958
12959 thumb_exit (f, -1);
12960 return;
12961 }
12962
12963 if (ARM_EABI_UNWIND_TABLES && push)
12964 {
12965 fprintf (f, "\t.save\t{");
12966 for (regno = 0; regno < 15; regno++)
12967 {
12968 if (real_regs & (1 << regno))
12969 {
12970 if (real_regs & ((1 << regno) -1))
12971 fprintf (f, ", ");
12972 asm_fprintf (f, "%r", regno);
12973 }
12974 }
12975 fprintf (f, "}\n");
12976 }
12977
12978 fprintf (f, "\t%s\t{", push ? "push" : "pop");
12979
12980
12981 for (regno = 0; regno <= LAST_LO_REGNUM; regno++, lo_mask >>= 1)
12982 {
12983 if (lo_mask & 1)
12984 {
12985 asm_fprintf (f, "%r", regno);
12986
12987 if ((lo_mask & ~1) != 0)
12988 fprintf (f, ", ");
12989
12990 pushed_words++;
12991 }
12992 }
12993
12994 if (push && (mask & (1 << LR_REGNUM)))
12995 {
12996
12997 if (mask & 0xFF)
12998 fprintf (f, ", ");
12999
13000 asm_fprintf (f, "%r", LR_REGNUM);
13001
13002 pushed_words++;
13003 }
13004 else if (!push && (mask & (1 << PC_REGNUM)))
13005 {
13006
13007 if (TARGET_INTERWORK || TARGET_BACKTRACE
13008 || current_function_calls_eh_return)
13009 {
13010
13011
13012 fprintf (f, "}\n");
13013
13014 thumb_exit (f, -1);
13015
13016 return;
13017 }
13018 else
13019 {
13020 if (mask & 0xFF)
13021 fprintf (f, ", ");
13022
13023 asm_fprintf (f, "%r", PC_REGNUM);
13024 }
13025 }
13026
13027 fprintf (f, "}\n");
13028
13029 if (push && pushed_words && dwarf2out_do_frame ())
13030 {
13031 char *l = dwarf2out_cfi_label ();
13032 int pushed_mask = real_regs;
13033
13034 *cfa_offset += pushed_words * 4;
13035 dwarf2out_def_cfa (l, SP_REGNUM, *cfa_offset);
13036
13037 pushed_words = 0;
13038 pushed_mask = real_regs;
13039 for (regno = 0; regno <= 14; regno++, pushed_mask >>= 1)
13040 {
13041 if (pushed_mask & 1)
13042 dwarf2out_reg_save (l, regno, 4 * pushed_words++ - *cfa_offset);
13043 }
13044 }
13045 }
13046
13047
13048
13049
13050 static void
13051 thumb_exit (FILE *f, int reg_containing_return_addr)
13052 {
13053 unsigned regs_available_for_popping;
13054 unsigned regs_to_pop;
13055 int pops_needed;
13056 unsigned available;
13057 unsigned required;
13058 int mode;
13059 int size;
13060 int restore_a4 = FALSE;
13061
13062
13063 regs_to_pop = 0;
13064 pops_needed = 0;
13065
13066 if (reg_containing_return_addr == -1)
13067 {
13068 regs_to_pop |= 1 << LR_REGNUM;
13069 ++pops_needed;
13070 }
13071
13072 if (TARGET_BACKTRACE)
13073 {
13074
13075 regs_to_pop |= (1 << ARM_HARD_FRAME_POINTER_REGNUM) | (1 << SP_REGNUM);
13076 pops_needed += 2;
13077 }
13078
13079
13080
13081 if (pops_needed == 0)
13082 {
13083 if (current_function_calls_eh_return)
13084 asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
13085
13086 asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
13087 return;
13088 }
13089
13090
13091
13092 else if (!TARGET_INTERWORK
13093 && !TARGET_BACKTRACE
13094 && !is_called_in_ARM_mode (current_function_decl)
13095 && !current_function_calls_eh_return)
13096 {
13097 asm_fprintf (f, "\tpop\t{%r}\n", PC_REGNUM);
13098 return;
13099 }
13100
13101
13102 regs_available_for_popping = 0;
13103
13104
13105
13106 if (current_function_calls_eh_return)
13107 size = 12;
13108 else
13109 {
13110
13111
13112
13113
13114
13115
13116 if (current_function_return_rtx != 0)
13117 mode = GET_MODE (current_function_return_rtx);
13118 else
13119 mode = DECL_MODE (DECL_RESULT (current_function_decl));
13120
13121 size = GET_MODE_SIZE (mode);
13122
13123 if (size == 0)
13124 {
13125
13126
13127
13128 if (mode == VOIDmode)
13129 regs_available_for_popping =
13130 (1 << ARG_REGISTER (1))
13131 | (1 << ARG_REGISTER (2))
13132 | (1 << ARG_REGISTER (3));
13133 else
13134 regs_available_for_popping =
13135 (1 << ARG_REGISTER (2))
13136 | (1 << ARG_REGISTER (3));
13137 }
13138 else if (size <= 4)
13139 regs_available_for_popping =
13140 (1 << ARG_REGISTER (2))
13141 | (1 << ARG_REGISTER (3));
13142 else if (size <= 8)
13143 regs_available_for_popping =
13144 (1 << ARG_REGISTER (3));
13145 }
13146
13147
13148 for (available = regs_available_for_popping,
13149 required = regs_to_pop;
13150 required != 0 && available != 0;
13151 available &= ~(available & - available),
13152 required &= ~(required & - required))
13153 -- pops_needed;
13154
13155
13156 if (available > 0)
13157 regs_available_for_popping &= ~available;
13158
13159
13160
13161 else if (pops_needed)
13162 {
13163
13164
13165 if (regs_available_for_popping == 0
13166 && reg_containing_return_addr == LAST_ARG_REGNUM)
13167 {
13168 asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
13169 reg_containing_return_addr = LR_REGNUM;
13170 }
13171 else if (size > 12)
13172 {
13173
13174
13175 restore_a4 = TRUE;
13176
13177 asm_fprintf (f, "\tmov\t%r, %r\n",IP_REGNUM, LAST_ARG_REGNUM);
13178 }
13179
13180 if (reg_containing_return_addr != LAST_ARG_REGNUM)
13181 {
13182
13183 regs_available_for_popping |= 1 << LAST_ARG_REGNUM;
13184
13185 --pops_needed;
13186 }
13187 }
13188
13189
13190 thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13191 regs_available_for_popping);
13192
13193
13194 if (reg_containing_return_addr == -1)
13195 {
13196
13197 regs_to_pop &= ~(1 << LR_REGNUM);
13198
13199 reg_containing_return_addr =
13200 number_of_first_bit_set (regs_available_for_popping);
13201
13202
13203
13204 regs_available_for_popping &= ~(1 << reg_containing_return_addr);
13205 }
13206
13207
13208 if (regs_available_for_popping)
13209 {
13210 int frame_pointer;
13211
13212
13213 frame_pointer = number_of_first_bit_set (regs_available_for_popping);
13214
13215
13216 asm_fprintf (f, "\tmov\t%r, %r\n",
13217 ARM_HARD_FRAME_POINTER_REGNUM, frame_pointer);
13218
13219
13220 regs_available_for_popping &= ~(1 << frame_pointer);
13221 regs_to_pop &= ~(1 << ARM_HARD_FRAME_POINTER_REGNUM);
13222
13223 if (regs_available_for_popping)
13224 {
13225 int stack_pointer;
13226
13227
13228
13229 stack_pointer = number_of_first_bit_set (regs_available_for_popping);
13230
13231
13232 asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, stack_pointer);
13233
13234
13235
13236
13237
13238
13239
13240
13241 }
13242 else
13243 {
13244
13245
13246
13247 regs_available_for_popping |= (1 << frame_pointer);
13248 }
13249 }
13250
13251
13252
13253
13254
13255 if (regs_available_for_popping == 0 && pops_needed > 0)
13256 {
13257 regs_available_for_popping |= 1 << reg_containing_return_addr;
13258
13259 asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM,
13260 reg_containing_return_addr);
13261
13262 reg_containing_return_addr = LR_REGNUM;
13263 }
13264
13265
13266
13267 if (pops_needed > 0)
13268 {
13269 int popped_into;
13270 int move_to;
13271
13272 thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13273 regs_available_for_popping);
13274
13275
13276
13277 popped_into = number_of_first_bit_set (regs_available_for_popping);
13278 move_to = number_of_first_bit_set (regs_to_pop);
13279
13280 asm_fprintf (f, "\tmov\t%r, %r\n", move_to, popped_into);
13281
13282 regs_to_pop &= ~(1 << move_to);
13283
13284 --pops_needed;
13285 }
13286
13287
13288
13289 if (pops_needed > 0)
13290 {
13291 int popped_into;
13292
13293 thumb_pushpop (f, regs_available_for_popping, FALSE, NULL,
13294 regs_available_for_popping);
13295
13296 popped_into = number_of_first_bit_set (regs_available_for_popping);
13297
13298 asm_fprintf (f, "\tmov\t%r, %r\n", SP_REGNUM, popped_into);
13299
13300
13301
13302
13303 }
13304
13305
13306 if (restore_a4)
13307 {
13308 if (reg_containing_return_addr != LR_REGNUM)
13309 {
13310 asm_fprintf (f, "\tmov\t%r, %r\n", LR_REGNUM, LAST_ARG_REGNUM);
13311 reg_containing_return_addr = LR_REGNUM;
13312 }
13313
13314 asm_fprintf (f, "\tmov\t%r, %r\n", LAST_ARG_REGNUM, IP_REGNUM);
13315 }
13316
13317 if (current_function_calls_eh_return)
13318 asm_fprintf (f, "\tadd\t%r, %r\n", SP_REGNUM, ARM_EH_STACKADJ_REGNUM);
13319
13320
13321 asm_fprintf (f, "\tbx\t%r\n", reg_containing_return_addr);
13322 }
13323
13324
13325 void
13326 thumb_final_prescan_insn (rtx insn)
13327 {
13328 if (flag_print_asm_name)
13329 asm_fprintf (asm_out_file, "%@ 0x%04x\n",
13330 INSN_ADDRESSES (INSN_UID (insn)));
13331 }
13332
13333 int
13334 thumb_shiftable_const (unsigned HOST_WIDE_INT val)
13335 {
13336 unsigned HOST_WIDE_INT mask = 0xff;
13337 int i;
13338
13339 if (val == 0)
13340 return 0;
13341
13342 for (i = 0; i < 25; i++)
13343 if ((val & (mask << i)) == val)
13344 return 1;
13345
13346 return 0;
13347 }
13348
13349
13350
13351 static int
13352 thumb_far_jump_used_p (void)
13353 {
13354 rtx insn;
13355
13356
13357
13358
13359
13360
13361
13362
13363
13364 if (cfun->machine->far_jump_used)
13365 return 1;
13366
13367
13368
13369
13370 if (!(ARM_DOUBLEWORD_ALIGN || reload_completed))
13371 {
13372
13373
13374
13375
13376
13377
13378
13379
13380
13381
13382
13383
13384
13385
13386
13387
13388
13389
13390
13391
13392
13393 if (regs_ever_live [ARG_POINTER_REGNUM])
13394 cfun->machine->arg_pointer_live = 1;
13395 else if (!cfun->machine->arg_pointer_live)
13396 return 0;
13397 }
13398
13399
13400
13401 for (insn = get_insns (); insn; insn = NEXT_INSN (insn))
13402 {
13403 if (GET_CODE (insn) == JUMP_INSN
13404
13405 && GET_CODE (PATTERN (insn)) != ADDR_VEC
13406 && GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC
13407 && get_attr_far_jump (insn) == FAR_JUMP_YES
13408 )
13409 {
13410
13411
13412 cfun->machine->far_jump_used = 1;
13413 return 1;
13414 }
13415 }
13416
13417 return 0;
13418 }
13419
13420
13421 int
13422 is_called_in_ARM_mode (tree func)
13423 {
13424 gcc_assert (TREE_CODE (func) == FUNCTION_DECL);
13425
13426
13427 if (TARGET_CALLEE_INTERWORKING && TREE_PUBLIC (func))
13428 return TRUE;
13429
13430 #ifdef ARM_PE
13431 return lookup_attribute ("interfacearm", DECL_ATTRIBUTES (func)) != NULL_TREE;
13432 #else
13433 return FALSE;
13434 #endif
13435 }
13436
13437
13438 const char *
13439 thumb_unexpanded_epilogue (void)
13440 {
13441 int regno;
13442 unsigned long live_regs_mask = 0;
13443 int high_regs_pushed = 0;
13444 int had_to_push_lr;
13445 int size;
13446
13447 if (return_used_this_function)
13448 return "";
13449
13450 if (IS_NAKED (arm_current_func_type ()))
13451 return "";
13452
13453 live_regs_mask = thumb_compute_save_reg_mask ();
13454 high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
13455
13456
13457
13458
13459
13460 size = arm_size_return_regs ();
13461
13462
13463
13464
13465
13466
13467
13468
13469
13470
13471
13472 if (high_regs_pushed)
13473 {
13474 unsigned long mask = live_regs_mask & 0xff;
13475 int next_hi_reg;
13476
13477
13478
13479 if (size <= 12)
13480 mask |= 1 << 3;
13481 if (size <= 8)
13482 mask |= 1 << 2;
13483
13484 if (mask == 0)
13485
13486
13487 internal_error
13488 ("no low registers available for popping high registers");
13489
13490 for (next_hi_reg = 8; next_hi_reg < 13; next_hi_reg++)
13491 if (live_regs_mask & (1 << next_hi_reg))
13492 break;
13493
13494 while (high_regs_pushed)
13495 {
13496
13497
13498 for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
13499 {
13500 if (mask & (1 << regno))
13501 high_regs_pushed--;
13502 if (high_regs_pushed == 0)
13503 break;
13504 }
13505
13506 mask &= (2 << regno) - 1;
13507
13508
13509 thumb_pushpop (asm_out_file, mask, 0, NULL, mask);
13510
13511
13512 for (regno = 0; regno <= LAST_LO_REGNUM; regno++)
13513 {
13514 if (mask & (1 << regno))
13515 {
13516 asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", next_hi_reg,
13517 regno);
13518
13519 for (next_hi_reg++; next_hi_reg < 13; next_hi_reg++)
13520 if (live_regs_mask & (1 << next_hi_reg))
13521 break;
13522 }
13523 }
13524 }
13525 live_regs_mask &= ~0x0f00;
13526 }
13527
13528 had_to_push_lr = (live_regs_mask & (1 << LR_REGNUM)) != 0;
13529 live_regs_mask &= 0xff;
13530
13531 if (current_function_pretend_args_size == 0 || TARGET_BACKTRACE)
13532 {
13533
13534 if (had_to_push_lr)
13535 live_regs_mask |= 1 << PC_REGNUM;
13536
13537
13538
13539
13540 if (live_regs_mask)
13541 thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
13542 live_regs_mask);
13543
13544
13545
13546 if (!had_to_push_lr)
13547 thumb_exit (asm_out_file, LR_REGNUM);
13548 }
13549 else
13550 {
13551
13552 if (live_regs_mask)
13553 thumb_pushpop (asm_out_file, live_regs_mask, FALSE, NULL,
13554 live_regs_mask);
13555
13556 if (had_to_push_lr)
13557 {
13558 if (size > 12)
13559 {
13560
13561 asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", IP_REGNUM,
13562 LAST_ARG_REGNUM);
13563 }
13564
13565
13566 thumb_pushpop (asm_out_file, 1 << LAST_ARG_REGNUM, 0, NULL,
13567 1 << LAST_ARG_REGNUM);
13568
13569 if (size > 12)
13570 {
13571
13572 asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LR_REGNUM,
13573 LAST_ARG_REGNUM);
13574
13575 asm_fprintf (asm_out_file, "\tmov\t%r, %r\n", LAST_ARG_REGNUM,
13576 IP_REGNUM);
13577 regno = LR_REGNUM;
13578 }
13579 else
13580 regno = LAST_ARG_REGNUM;
13581 }
13582 else
13583 regno = LR_REGNUM;
13584
13585
13586 asm_fprintf (asm_out_file, "\tadd\t%r, %r, #%d\n",
13587 SP_REGNUM, SP_REGNUM,
13588 current_function_pretend_args_size);
13589
13590 thumb_exit (asm_out_file, regno);
13591 }
13592
13593 return "";
13594 }
13595
13596
13597 static struct machine_function *
13598 arm_init_machine_status (void)
13599 {
13600 struct machine_function *machine;
13601 machine = (machine_function *) ggc_alloc_cleared (sizeof (machine_function));
13602
13603 #if ARM_FT_UNKNOWN != 0
13604 machine->func_type = ARM_FT_UNKNOWN;
13605 #endif
13606 return machine;
13607 }
13608
13609
13610
13611 rtx
13612 arm_return_addr (int count, rtx frame ATTRIBUTE_UNUSED)
13613 {
13614 if (count != 0)
13615 return NULL_RTX;
13616
13617 return get_hard_reg_initial_val (Pmode, LR_REGNUM);
13618 }
13619
13620
13621 void
13622 arm_init_expanders (void)
13623 {
13624
13625 init_machine_status = arm_init_machine_status;
13626
13627
13628
13629
13630 if (cfun)
13631 mark_reg_pointer (arg_pointer_rtx, PARM_BOUNDARY);
13632 }
13633
13634
13635
13636
13637
13638
13639
13640 HOST_WIDE_INT
13641 thumb_compute_initial_elimination_offset (unsigned int from, unsigned int to)
13642 {
13643 arm_stack_offsets *offsets;
13644
13645 offsets = arm_get_frame_offsets ();
13646
13647 switch (from)
13648 {
13649 case ARG_POINTER_REGNUM:
13650 switch (to)
13651 {
13652 case STACK_POINTER_REGNUM:
13653 return offsets->outgoing_args - offsets->saved_args;
13654
13655 case FRAME_POINTER_REGNUM:
13656 return offsets->soft_frame - offsets->saved_args;
13657
13658 case ARM_HARD_FRAME_POINTER_REGNUM:
13659 return offsets->saved_regs - offsets->saved_args;
13660
13661 case THUMB_HARD_FRAME_POINTER_REGNUM:
13662 return offsets->locals_base - offsets->saved_args;
13663
13664 default:
13665 gcc_unreachable ();
13666 }
13667 break;
13668
13669 case FRAME_POINTER_REGNUM:
13670 switch (to)
13671 {
13672 case STACK_POINTER_REGNUM:
13673 return offsets->outgoing_args - offsets->soft_frame;
13674
13675 case ARM_HARD_FRAME_POINTER_REGNUM:
13676 return offsets->saved_regs - offsets->soft_frame;
13677
13678 case THUMB_HARD_FRAME_POINTER_REGNUM:
13679 return offsets->locals_base - offsets->soft_frame;
13680
13681 default:
13682 gcc_unreachable ();
13683 }
13684 break;
13685
13686 default:
13687 gcc_unreachable ();
13688 }
13689 }
13690
13691
13692
13693 void
13694 thumb_expand_prologue (void)
13695 {
13696 rtx insn, dwarf;
13697
13698 HOST_WIDE_INT amount;
13699 arm_stack_offsets *offsets;
13700 unsigned long func_type;
13701 int regno;
13702 unsigned long live_regs_mask;
13703
13704 func_type = arm_current_func_type ();
13705
13706
13707 if (IS_NAKED (func_type))
13708 return;
13709
13710 if (IS_INTERRUPT (func_type))
13711 {
13712 error ("interrupt Service Routines cannot be coded in Thumb mode");
13713 return;
13714 }
13715
13716 live_regs_mask = thumb_compute_save_reg_mask ();
13717
13718
13719 if (flag_pic && arm_pic_register != INVALID_REGNUM)
13720 arm_load_pic_register (live_regs_mask);
13721
13722 if (!frame_pointer_needed && CALLER_INTERWORKING_SLOT_SIZE > 0)
13723 emit_move_insn (gen_rtx_REG (Pmode, ARM_HARD_FRAME_POINTER_REGNUM),
13724 stack_pointer_rtx);
13725
13726 offsets = arm_get_frame_offsets ();
13727 amount = offsets->outgoing_args - offsets->saved_regs;
13728 if (amount)
13729 {
13730 if (amount < 512)
13731 {
13732 insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
13733 GEN_INT (- amount)));
13734 RTX_FRAME_RELATED_P (insn) = 1;
13735 }
13736 else
13737 {
13738 rtx reg;
13739
13740
13741
13742
13743
13744
13745
13746
13747
13748
13749
13750
13751
13752
13753
13754 for (regno = LAST_ARG_REGNUM + 1; regno <= LAST_LO_REGNUM; regno++)
13755 if (live_regs_mask & (1 << regno)
13756 && !(frame_pointer_needed
13757 && (regno == THUMB_HARD_FRAME_POINTER_REGNUM)))
13758 break;
13759
13760 if (regno > LAST_LO_REGNUM)
13761 {
13762 rtx spare = gen_rtx_REG (SImode, IP_REGNUM);
13763
13764
13765 reg = gen_rtx_REG (SImode, LAST_LO_REGNUM);
13766
13767
13768 emit_insn (gen_movsi (spare, reg));
13769
13770 emit_insn (gen_prologue_use (spare));
13771
13772
13773 emit_insn (gen_movsi (reg, GEN_INT (- amount)));
13774 insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
13775 stack_pointer_rtx, reg));
13776 RTX_FRAME_RELATED_P (insn) = 1;
13777 dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
13778 plus_constant (stack_pointer_rtx,
13779 -amount));
13780 RTX_FRAME_RELATED_P (dwarf) = 1;
13781 REG_NOTES (insn)
13782 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13783 REG_NOTES (insn));
13784
13785
13786 emit_insn (gen_movsi (reg, spare));
13787
13788
13789
13790
13791
13792 emit_insn (gen_prologue_use (reg));
13793 }
13794 else
13795 {
13796 reg = gen_rtx_REG (SImode, regno);
13797
13798 emit_insn (gen_movsi (reg, GEN_INT (- amount)));
13799
13800 insn = emit_insn (gen_addsi3 (stack_pointer_rtx,
13801 stack_pointer_rtx, reg));
13802 RTX_FRAME_RELATED_P (insn) = 1;
13803 dwarf = gen_rtx_SET (VOIDmode, stack_pointer_rtx,
13804 plus_constant (stack_pointer_rtx,
13805 -amount));
13806 RTX_FRAME_RELATED_P (dwarf) = 1;
13807 REG_NOTES (insn)
13808 = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13809 REG_NOTES (insn));
13810 }
13811 }
13812 }
13813
13814 if (frame_pointer_needed)
13815 {
13816 amount = offsets->outgoing_args - offsets->locals_base;
13817
13818 if (amount < 1024)
13819 insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
13820 stack_pointer_rtx, GEN_INT (amount)));
13821 else
13822 {
13823 emit_insn (gen_movsi (hard_frame_pointer_rtx, GEN_INT (amount)));
13824 insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
13825 hard_frame_pointer_rtx,
13826 stack_pointer_rtx));
13827 dwarf = gen_rtx_SET (VOIDmode, hard_frame_pointer_rtx,
13828 plus_constant (stack_pointer_rtx, amount));
13829 RTX_FRAME_RELATED_P (dwarf) = 1;
13830 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, dwarf,
13831 REG_NOTES (insn));
13832 }
13833
13834 RTX_FRAME_RELATED_P (insn) = 1;
13835 }
13836
13837
13838
13839
13840
13841
13842 if (current_function_profile || !TARGET_SCHED_PROLOG
13843 || (ARM_EABI_UNWIND_TABLES && flag_non_call_exceptions))
13844 emit_insn (gen_blockage ());
13845
13846 cfun->machine->lr_save_eliminated = !thumb_force_lr_save ();
13847 if (live_regs_mask & 0xff)
13848 cfun->machine->lr_save_eliminated = 0;
13849
13850
13851
13852 if (cfun->machine->lr_save_eliminated)
13853 emit_insn (gen_prologue_use (gen_rtx_REG (SImode, LR_REGNUM)));
13854 }
13855
13856
13857 void
13858 thumb_expand_epilogue (void)
13859 {
13860 HOST_WIDE_INT amount;
13861 arm_stack_offsets *offsets;
13862 int regno;
13863
13864
13865 if (IS_NAKED (arm_current_func_type ()))
13866 return;
13867
13868 offsets = arm_get_frame_offsets ();
13869 amount = offsets->outgoing_args - offsets->saved_regs;
13870
13871 if (frame_pointer_needed)
13872 {
13873 emit_insn (gen_movsi (stack_pointer_rtx, hard_frame_pointer_rtx));
13874 amount = offsets->locals_base - offsets->saved_regs;
13875 }
13876
13877 if (amount)
13878 {
13879 if (amount < 512)
13880 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
13881 GEN_INT (amount)));
13882 else
13883 {
13884
13885 rtx reg = gen_rtx_REG (SImode, LAST_ARG_REGNUM);
13886
13887 emit_insn (gen_movsi (reg, GEN_INT (amount)));
13888 emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, reg));
13889 }
13890 }
13891
13892
13893
13894 emit_insn (gen_prologue_use (stack_pointer_rtx));
13895
13896 if (current_function_profile || !TARGET_SCHED_PROLOG)
13897 emit_insn (gen_blockage ());
13898
13899
13900
13901 for (regno = 0; regno < 13; regno++)
13902 if (regs_ever_live[regno] && !call_used_regs[regno])
13903 emit_insn (gen_rtx_CLOBBER (VOIDmode, gen_rtx_REG (SImode, regno)));
13904
13905 if (! regs_ever_live[LR_REGNUM])
13906 emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, LR_REGNUM)));
13907 }
13908
13909 static void
13910 thumb_output_function_prologue (FILE *f, HOST_WIDE_INT size ATTRIBUTE_UNUSED)
13911 {
13912 unsigned long live_regs_mask = 0;
13913 unsigned long l_mask;
13914 unsigned high_regs_pushed = 0;
13915 int cfa_offset = 0;
13916 int regno;
13917
13918 if (IS_NAKED (arm_current_func_type ()))
13919 return;
13920
13921 if (is_called_in_ARM_mode (current_function_decl))
13922 {
13923 const char * name;
13924
13925 gcc_assert (GET_CODE (DECL_RTL (current_function_decl)) == MEM);
13926 gcc_assert (GET_CODE (XEXP (DECL_RTL (current_function_decl), 0))
13927 == SYMBOL_REF);
13928 name = XSTR (XEXP (DECL_RTL (current_function_decl), 0), 0);
13929
13930
13931
13932
13933 asm_fprintf (f, "\torr\t%r, %r, #1\n", IP_REGNUM, PC_REGNUM);
13934 asm_fprintf (f, "\tbx\t%r\n", IP_REGNUM);
13935
13936
13937
13938
13939
13940
13941
13942
13943 #define STUB_NAME ".real_start_of"
13944
13945 fprintf (f, "\t.code\t16\n");
13946 #ifdef ARM_PE
13947 if (arm_dllexport_name_p (name))
13948 name = arm_strip_name_encoding (name);
13949 #endif
13950 asm_fprintf (f, "\t.globl %s%U%s\n", STUB_NAME, name);
13951 fprintf (f, "\t.thumb_func\n");
13952 asm_fprintf (f, "%s%U%s:\n", STUB_NAME, name);
13953 }
13954
13955 if (current_function_pretend_args_size)
13956 {
13957
13958 if (ARM_EABI_UNWIND_TABLES)
13959 fprintf (f, "\t.pad #%d\n",
13960 current_function_pretend_args_size);
13961
13962 if (cfun->machine->uses_anonymous_args)
13963 {
13964 int num_pushes;
13965
13966 fprintf (f, "\tpush\t{");
13967
13968 num_pushes = ARM_NUM_INTS (current_function_pretend_args_size);
13969
13970 for (regno = LAST_ARG_REGNUM + 1 - num_pushes;
13971 regno <= LAST_ARG_REGNUM;
13972 regno++)
13973 asm_fprintf (f, "%r%s", regno,
13974 regno == LAST_ARG_REGNUM ? "" : ", ");
13975
13976 fprintf (f, "}\n");
13977 }
13978 else
13979 asm_fprintf (f, "\tsub\t%r, %r, #%d\n",
13980 SP_REGNUM, SP_REGNUM,
13981 current_function_pretend_args_size);
13982
13983
13984
13985
13986 if (dwarf2out_do_frame ())
13987 {
13988 char *l = dwarf2out_cfi_label ();
13989
13990 cfa_offset = cfa_offset + current_function_pretend_args_size;
13991 dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
13992 }
13993 }
13994
13995
13996 live_regs_mask = thumb_compute_save_reg_mask ();
13997
13998 l_mask = live_regs_mask & 0x40ff;
13999
14000 high_regs_pushed = bit_count (live_regs_mask & 0x0f00);
14001
14002 if (TARGET_BACKTRACE)
14003 {
14004 unsigned offset;
14005 unsigned work_register;
14006
14007
14008
14009
14010
14011
14012
14013
14014
14015
14016
14017
14018
14019
14020
14021
14022
14023
14024
14025 work_register = thumb_find_work_register (live_regs_mask);
14026
14027 if (ARM_EABI_UNWIND_TABLES)
14028 asm_fprintf (f, "\t.pad #16\n");
14029
14030 asm_fprintf
14031 (f, "\tsub\t%r, %r, #16\t%@ Create stack backtrace structure\n",
14032 SP_REGNUM, SP_REGNUM);
14033
14034 if (dwarf2out_do_frame ())
14035 {
14036 char *l = dwarf2out_cfi_label ();
14037
14038 cfa_offset = cfa_offset + 16;
14039 dwarf2out_def_cfa (l, SP_REGNUM, cfa_offset);
14040 }
14041
14042 if (l_mask)
14043 {
14044 thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
14045 offset = bit_count (l_mask) * UNITS_PER_WORD;
14046 }
14047 else
14048 offset = 0;
14049
14050 asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
14051 offset + 16 + current_function_pretend_args_size);
14052
14053 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
14054 offset + 4);
14055
14056
14057
14058 if (l_mask)
14059 {
14060 asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
14061 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
14062 offset + 12);
14063 asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
14064 ARM_HARD_FRAME_POINTER_REGNUM);
14065 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
14066 offset);
14067 }
14068 else
14069 {
14070 asm_fprintf (f, "\tmov\t%r, %r\n", work_register,
14071 ARM_HARD_FRAME_POINTER_REGNUM);
14072 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
14073 offset);
14074 asm_fprintf (f, "\tmov\t%r, %r\n", work_register, PC_REGNUM);
14075 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
14076 offset + 12);
14077 }
14078
14079 asm_fprintf (f, "\tmov\t%r, %r\n", work_register, LR_REGNUM);
14080 asm_fprintf (f, "\tstr\t%r, [%r, #%d]\n", work_register, SP_REGNUM,
14081 offset + 8);
14082 asm_fprintf (f, "\tadd\t%r, %r, #%d\n", work_register, SP_REGNUM,
14083 offset + 12);
14084 asm_fprintf (f, "\tmov\t%r, %r\t\t%@ Backtrace structure created\n",
14085 ARM_HARD_FRAME_POINTER_REGNUM, work_register);
14086 }
14087
14088
14089
14090
14091 else if ((l_mask & 0xff) != 0
14092 || (high_regs_pushed == 0 && l_mask))
14093 thumb_pushpop (f, l_mask, 1, &cfa_offset, l_mask);
14094
14095 if (high_regs_pushed)
14096 {
14097 unsigned pushable_regs;
14098 unsigned next_hi_reg;
14099
14100 for (next_hi_reg = 12; next_hi_reg > LAST_LO_REGNUM; next_hi_reg--)
14101 if (live_regs_mask & (1 << next_hi_reg))
14102 break;
14103
14104 pushable_regs = l_mask & 0xff;
14105
14106 if (pushable_regs == 0)
14107 pushable_regs = 1 << thumb_find_work_register (live_regs_mask);
14108
14109 while (high_regs_pushed > 0)
14110 {
14111 unsigned long real_regs_mask = 0;
14112
14113 for (regno = LAST_LO_REGNUM; regno >= 0; regno --)
14114 {
14115 if (pushable_regs & (1 << regno))
14116 {
14117 asm_fprintf (f, "\tmov\t%r, %r\n", regno, next_hi_reg);
14118
14119 high_regs_pushed --;
14120 real_regs_mask |= (1 << next_hi_reg);
14121
14122 if (high_regs_pushed)
14123 {
14124 for (next_hi_reg --; next_hi_reg > LAST_LO_REGNUM;
14125 next_hi_reg --)
14126 if (live_regs_mask & (1 << next_hi_reg))
14127 break;
14128 }
14129 else
14130 {
14131 pushable_regs &= ~((1 << regno) - 1);
14132 break;
14133 }
14134 }
14135 }
14136
14137
14138
14139 if (l_mask == (1 << LR_REGNUM))
14140 {
14141 thumb_pushpop (f, pushable_regs | (1 << LR_REGNUM),
14142 1, &cfa_offset,
14143 real_regs_mask | (1 << LR_REGNUM));
14144 l_mask = 0;
14145 }
14146 else
14147 thumb_pushpop (f, pushable_regs, 1, &cfa_offset, real_regs_mask);
14148 }
14149 }
14150 }
14151
14152
14153
14154
14155 const char *
14156 thumb_load_double_from_address (rtx *operands)
14157 {
14158 rtx addr;
14159 rtx base;
14160 rtx offset;
14161 rtx arg1;
14162 rtx arg2;
14163
14164 gcc_assert (GET_CODE (operands[0]) == REG);
14165 gcc_assert (GET_CODE (operands[1]) == MEM);
14166
14167
14168 addr = XEXP (operands[1], 0);
14169
14170
14171 switch (GET_CODE (addr))
14172 {
14173 case REG:
14174 operands[2] = adjust_address (operands[1], SImode, 4);
14175
14176 if (REGNO (operands[0]) == REGNO (addr))
14177 {
14178 output_asm_insn ("ldr\t%H0, %2", operands);
14179 output_asm_insn ("ldr\t%0, %1", operands);
14180 }
14181 else
14182 {
14183 output_asm_insn ("ldr\t%0, %1", operands);
14184 output_asm_insn ("ldr\t%H0, %2", operands);
14185 }
14186 break;
14187
14188 case CONST:
14189
14190 operands[2] = adjust_address (operands[1], SImode, 4);
14191
14192 output_asm_insn ("ldr\t%0, %1", operands);
14193 output_asm_insn ("ldr\t%H0, %2", operands);
14194 break;
14195
14196 case PLUS:
14197 arg1 = XEXP (addr, 0);
14198 arg2 = XEXP (addr, 1);
14199
14200 if (CONSTANT_P (arg1))
14201 base = arg2, offset = arg1;
14202 else
14203 base = arg1, offset = arg2;
14204
14205 gcc_assert (GET_CODE (base) == REG);
14206
14207
14208 if (GET_CODE (offset) == REG)
14209 {
14210 int reg_offset = REGNO (offset);
14211 int reg_base = REGNO (base);
14212 int reg_dest = REGNO (operands[0]);
14213
14214
14215
14216 asm_fprintf (asm_out_file, "\tadd\t%r, %r, %r",
14217 reg_dest + 1, reg_base, reg_offset);
14218
14219
14220
14221 asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #0]",
14222 reg_dest, reg_dest + 1);
14223
14224
14225
14226 asm_fprintf (asm_out_file, "\tldr\t%r, [%r, #4]",
14227 reg_dest + 1, reg_dest + 1);
14228 }
14229 else
14230 {
14231
14232 operands[2] = adjust_address (operands[1], SImode, 4);
14233
14234
14235
14236
14237 if (REGNO (operands[0]) == REGNO (base))
14238 {
14239 output_asm_insn ("ldr\t%H0, %2", operands);
14240 output_asm_insn ("ldr\t%0, %1", operands);
14241 }
14242 else
14243 {
14244 output_asm_insn ("ldr\t%0, %1", operands);
14245 output_asm_insn ("ldr\t%H0, %2", operands);
14246 }
14247 }
14248 break;
14249
14250 case LABEL_REF:
14251
14252
14253 operands[2] = adjust_address (operands[1], SImode, 4);
14254
14255 output_asm_insn ("ldr\t%H0, %2", operands);
14256 output_asm_insn ("ldr\t%0, %1", operands);
14257 break;
14258
14259 default:
14260 gcc_unreachable ();
14261 }
14262
14263 return "";
14264 }
14265
14266 const char *
14267 thumb_output_move_mem_multiple (int n, rtx *operands)
14268 {
14269 rtx tmp;
14270
14271 switch (n)
14272 {
14273 case 2:
14274 if (REGNO (operands[4]) > REGNO (operands[5]))
14275 {
14276 tmp = operands[4];
14277 operands[4] = operands[5];
14278 operands[5] = tmp;
14279 }
14280 output_asm_insn ("ldmia\t%1!, {%4, %5}", operands);
14281 output_asm_insn ("stmia\t%0!, {%4, %5}", operands);
14282 break;
14283
14284 case 3:
14285 if (REGNO (operands[4]) > REGNO (operands[5]))
14286 {
14287 tmp = operands[4];
14288 operands[4] = operands[5];
14289 operands[5] = tmp;
14290 }
14291 if (REGNO (operands[5]) > REGNO (operands[6]))
14292 {
14293 tmp = operands[5];
14294 operands[5] = operands[6];
14295 operands[6] = tmp;
14296 }
14297 if (REGNO (operands[4]) > REGNO (operands[5]))
14298 {
14299 tmp = operands[4];
14300 operands[4] = operands[5];
14301 operands[5] = tmp;
14302 }
14303
14304 output_asm_insn ("ldmia\t%1!, {%4, %5, %6}", operands);
14305 output_asm_insn ("stmia\t%0!, {%4, %5, %6}", operands);
14306 break;
14307
14308 default:
14309 gcc_unreachable ();
14310 }
14311
14312 return "";
14313 }
14314
14315
14316 const char *
14317 thumb_call_via_reg (rtx reg)
14318 {
14319 int regno = REGNO (reg);
14320 rtx *labelp;
14321
14322 gcc_assert (regno < LR_REGNUM);
14323
14324
14325
14326
14327 if (in_section == text_section)
14328 {
14329 thumb_call_reg_needed = 1;
14330
14331 if (thumb_call_via_label[regno] == NULL)
14332 thumb_call_via_label[regno] = gen_label_rtx ();
14333 labelp = thumb_call_via_label + regno;
14334 }
14335 else
14336 {
14337 if (cfun->machine->call_via[regno] == NULL)
14338 cfun->machine->call_via[regno] = gen_label_rtx ();
14339 labelp = cfun->machine->call_via + regno;
14340 }
14341
14342 output_asm_insn ("bl\t%a0", labelp);
14343 return "";
14344 }
14345
14346
14347 void
14348 thumb_expand_movmemqi (rtx *operands)
14349 {
14350 rtx out = copy_to_mode_reg (SImode, XEXP (operands[0], 0));
14351 rtx in = copy_to_mode_reg (SImode, XEXP (operands[1], 0));
14352 HOST_WIDE_INT len = INTVAL (operands[2]);
14353 HOST_WIDE_INT offset = 0;
14354
14355 while (len >= 12)
14356 {
14357 emit_insn (gen_movmem12b (out, in, out, in));
14358 len -= 12;
14359 }
14360
14361 if (len >= 8)
14362 {
14363 emit_insn (gen_movmem8b (out, in, out, in));
14364 len -= 8;
14365 }
14366
14367 if (len >= 4)
14368 {
14369 rtx reg = gen_reg_rtx (SImode);
14370 emit_insn (gen_movsi (reg, gen_rtx_MEM (SImode, in)));
14371 emit_insn (gen_movsi (gen_rtx_MEM (SImode, out), reg));
14372 len -= 4;
14373 offset += 4;
14374 }
14375
14376 if (len >= 2)
14377 {
14378 rtx reg = gen_reg_rtx (HImode);
14379 emit_insn (gen_movhi (reg, gen_rtx_MEM (HImode,
14380 plus_constant (in, offset))));
14381 emit_insn (gen_movhi (gen_rtx_MEM (HImode, plus_constant (out, offset)),
14382 reg));
14383 len -= 2;
14384 offset += 2;
14385 }
14386
14387 if (len)
14388 {
14389 rtx reg = gen_reg_rtx (QImode);
14390 emit_insn (gen_movqi (reg, gen_rtx_MEM (QImode,
14391 plus_constant (in, offset))));
14392 emit_insn (gen_movqi (gen_rtx_MEM (QImode, plus_constant (out, offset)),
14393 reg));
14394 }
14395 }
14396
14397 void
14398 thumb_reload_out_hi (rtx *operands)
14399 {
14400 emit_insn (gen_thumb_movhi_clobber (operands[0], operands[1], operands[2]));
14401 }
14402
14403
14404 void
14405 thumb_reload_in_hi (rtx *operands ATTRIBUTE_UNUSED)
14406 {
14407 gcc_unreachable ();
14408 }
14409
14410
14411
14412 static int
14413 arm_get_strip_length (int c)
14414 {
14415 switch (c)
14416 {
14417 ARM_NAME_ENCODING_LENGTHS
14418 default: return 0;
14419 }
14420 }
14421
14422
14423
14424 const char *
14425 arm_strip_name_encoding (const char *name)
14426 {
14427 int skip;
14428
14429 while ((skip = arm_get_strip_length (* name)))
14430 name += skip;
14431
14432 return name;
14433 }
14434
14435
14436
14437
14438 void
14439 arm_asm_output_labelref (FILE *stream, const char *name)
14440 {
14441 int skip;
14442 int verbatim = 0;
14443
14444 while ((skip = arm_get_strip_length (* name)))
14445 {
14446 verbatim |= (*name == '*');
14447 name += skip;
14448 }
14449
14450 if (verbatim)
14451 fputs (name, stream);
14452 else
14453 asm_fprintf (stream, "%U%s", name);
14454 }
14455
14456 static void
14457 arm_file_end (void)
14458 {
14459 int regno;
14460
14461 if (! thumb_call_reg_needed)
14462 return;
14463
14464 switch_to_section (text_section);
14465 asm_fprintf (asm_out_file, "\t.code 16\n");
14466 ASM_OUTPUT_ALIGN (asm_out_file, 1);
14467
14468 for (regno = 0; regno < LR_REGNUM; regno++)
14469 {
14470 rtx label = thumb_call_via_label[regno];
14471
14472 if (label != 0)
14473 {
14474 targetm.asm_out.internal_label (asm_out_file, "L",
14475 CODE_LABEL_NUMBER (label));
14476 asm_fprintf (asm_out_file, "\tbx\t%r\n", regno);
14477 }
14478 }
14479 }
14480
14481 rtx aof_pic_label;
14482
14483 #ifdef AOF_ASSEMBLER
14484
14485
14486 struct pic_chain
14487 {
14488 struct pic_chain * next;
14489 const char * symname;
14490 };
14491
14492 static struct pic_chain * aof_pic_chain = NULL;
14493
14494 rtx
14495 aof_pic_entry (rtx x)
14496 {
14497 struct pic_chain ** chainp;
14498 int offset;
14499
14500 if (aof_pic_label == NULL_RTX)
14501 {
14502 aof_pic_label = gen_rtx_SYMBOL_REF (Pmode, "x$adcons");
14503 }
14504
14505 for (offset = 0, chainp = &aof_pic_chain; *chainp;
14506 offset += 4, chainp = &(*chainp)->next)
14507 if ((*chainp)->symname == XSTR (x, 0))
14508 return plus_constant (aof_pic_label, offset);
14509
14510 *chainp = (struct pic_chain *) xmalloc (sizeof (struct pic_chain));
14511 (*chainp)->next = NULL;
14512 (*chainp)->symname = XSTR (x, 0);
14513 return plus_constant (aof_pic_label, offset);
14514 }
14515
14516 void
14517 aof_dump_pic_table (FILE *f)
14518 {
14519 struct pic_chain * chain;
14520
14521 if (aof_pic_chain == NULL)
14522 return;
14523
14524 asm_fprintf (f, "\tAREA |%r$$adcons|, BASED %r\n",
14525 PIC_OFFSET_TABLE_REGNUM,
14526 PIC_OFFSET_TABLE_REGNUM);
14527 fputs ("|x$adcons|\n", f);
14528
14529 for (chain = aof_pic_chain; chain; chain = chain->next)
14530 {
14531 fputs ("\tDCD\t", f);
14532 assemble_name (f, chain->symname);
14533 fputs ("\n", f);
14534 }
14535 }
14536
14537 int arm_text_section_count = 1;
14538
14539
14540
14541 static void
14542 aof_output_text_section_asm_op (const void *data ATTRIBUTE_UNUSED)
14543 {
14544 fprintf (asm_out_file, "\tAREA |C$$code%d|, CODE, READONLY",
14545 arm_text_section_count++);
14546 if (flag_pic)
14547 fprintf (asm_out_file, ", PIC, REENTRANT");
14548 fprintf (asm_out_file, "\n");
14549 }
14550
14551 static int arm_data_section_count = 1;
14552
14553
14554
14555 static void
14556 aof_output_data_section_asm_op (const void *data ATTRIBUTE_UNUSED)
14557 {
14558 fprintf (asm_out_file, "\tAREA |C$$data%d|, DATA\n",
14559 arm_data_section_count++);
14560 }
14561
14562
14563
14564
14565
14566
14567
14568
14569
14570
14571
14572 static void
14573 aof_asm_init_sections (void)
14574 {
14575 text_section = get_unnamed_section (SECTION_CODE,
14576 aof_output_text_section_asm_op, NULL);
14577 data_section = get_unnamed_section (SECTION_WRITE,
14578 aof_output_data_section_asm_op, NULL);
14579 readonly_data_section = text_section;
14580 }
14581
14582 void
14583 zero_init_section (void)
14584 {
14585 static int zero_init_count = 1;
14586
14587 fprintf (asm_out_file, "\tAREA |C$$zidata%d|,NOINIT\n", zero_init_count++);
14588 in_section = NULL;
14589 }
14590
14591
14592
14593
14594
14595
14596
14597
14598
14599
14600
14601 struct import
14602 {
14603 struct import * next;
14604 const char * name;
14605 };
14606
14607 static struct import * imports_list = NULL;
14608
14609 void
14610 aof_add_import (const char *name)
14611 {
14612 struct import * new;
14613
14614 for (new = imports_list; new; new = new->next)
14615 if (new->name == name)
14616 return;
14617
14618 new = (struct import *) xmalloc (sizeof (struct import));
14619 new->next = imports_list;
14620 imports_list = new;
14621 new->name = name;
14622 }
14623
14624 void
14625 aof_delete_import (const char *name)
14626 {
14627 struct import ** old;
14628
14629 for (old = &imports_list; *old; old = & (*old)->next)
14630 {
14631 if ((*old)->name == name)
14632 {
14633 *old = (*old)->next;
14634 return;
14635 }
14636 }
14637 }
14638
14639 int arm_main_function = 0;
14640
14641 static void
14642 aof_dump_imports (FILE *f)
14643 {
14644
14645
14646
14647 if (arm_main_function)
14648 {
14649 switch_to_section (text_section);
14650 fputs ("\tIMPORT __main\n", f);
14651 fputs ("\tDCD __main\n", f);
14652 }
14653
14654
14655 while (imports_list)
14656 {
14657 fprintf (f, "\tIMPORT\t");
14658 assemble_name (f, imports_list->name);
14659 fputc ('\n', f);
14660 imports_list = imports_list->next;
14661 }
14662 }
14663
14664 static void
14665 aof_globalize_label (FILE *stream, const char *name)
14666 {
14667 default_globalize_label (stream, name);
14668 if (! strcmp (name, "main"))
14669 arm_main_function = 1;
14670 }
14671
14672 static void
14673 aof_file_start (void)
14674 {
14675 fputs ("__r0\tRN\t0\n", asm_out_file);
14676 fputs ("__a1\tRN\t0\n", asm_out_file);
14677 fputs ("__a2\tRN\t1\n", asm_out_file);
14678 fputs ("__a3\tRN\t2\n", asm_out_file);
14679 fputs ("__a4\tRN\t3\n", asm_out_file);
14680 fputs ("__v1\tRN\t4\n", asm_out_file);
14681 fputs ("__v2\tRN\t5\n", asm_out_file);
14682 fputs ("__v3\tRN\t6\n", asm_out_file);
14683 fputs ("__v4\tRN\t7\n", asm_out_file);
14684 fputs ("__v5\tRN\t8\n", asm_out_file);
14685 fputs ("__v6\tRN\t9\n", asm_out_file);
14686 fputs ("__sl\tRN\t10\n", asm_out_file);
14687 fputs ("__fp\tRN\t11\n", asm_out_file);
14688 fputs ("__ip\tRN\t12\n", asm_out_file);
14689 fputs ("__sp\tRN\t13\n", asm_out_file);
14690 fputs ("__lr\tRN\t14\n", asm_out_file);
14691 fputs ("__pc\tRN\t15\n", asm_out_file);
14692 fputs ("__f0\tFN\t0\n", asm_out_file);
14693 fputs ("__f1\tFN\t1\n", asm_out_file);
14694 fputs ("__f2\tFN\t2\n", asm_out_file);
14695 fputs ("__f3\tFN\t3\n", asm_out_file);
14696 fputs ("__f4\tFN\t4\n", asm_out_file);
14697 fputs ("__f5\tFN\t5\n", asm_out_file);
14698 fputs ("__f6\tFN\t6\n", asm_out_file);
14699 fputs ("__f7\tFN\t7\n", asm_out_file);
14700 switch_to_section (text_section);
14701 }
14702
14703 static void
14704 aof_file_end (void)
14705 {
14706 if (flag_pic)
14707 aof_dump_pic_table (asm_out_file);
14708 arm_file_end ();
14709 aof_dump_imports (asm_out_file);
14710 fputs ("\tEND\n", asm_out_file);
14711 }
14712 #endif
14713
14714 #ifndef ARM_PE
14715
14716
14717
14718
14719
14720
14721 static void
14722 arm_encode_section_info (tree decl, rtx rtl, int first)
14723 {
14724
14725
14726 #ifndef AOF_ASSEMBLER
14727 if (optimize > 0 && TREE_CONSTANT (decl))
14728 SYMBOL_REF_FLAG (XEXP (rtl, 0)) = 1;
14729 #endif
14730
14731
14732
14733
14734 if (first && DECL_P (decl))
14735 {
14736 if (TREE_CODE (decl) == FUNCTION_DECL && DECL_WEAK (decl))
14737 arm_encode_call_attribute (decl, LONG_CALL_FLAG_CHAR);
14738 else if (! TREE_PUBLIC (decl))
14739 arm_encode_call_attribute (decl, SHORT_CALL_FLAG_CHAR);
14740 }
14741
14742 default_encode_section_info (decl, rtl, first);
14743 }
14744 #endif
14745
14746 static void
14747 arm_internal_label (FILE *stream, const char *prefix, unsigned long labelno)
14748 {
14749 if (arm_ccfsm_state == 3 && (unsigned) arm_target_label == labelno
14750 && !strcmp (prefix, "L"))
14751 {
14752 arm_ccfsm_state = 0;
14753 arm_target_insn = NULL;
14754 }
14755 default_internal_label (stream, prefix, labelno);
14756 }
14757
14758
14759
14760 static void
14761 arm_output_mi_thunk (FILE *file, tree thunk ATTRIBUTE_UNUSED,
14762 HOST_WIDE_INT delta,
14763 HOST_WIDE_INT vcall_offset ATTRIBUTE_UNUSED,
14764 tree function)
14765 {
14766 static int thunk_label = 0;
14767 char label[256];
14768 char labelpc[256];
14769 int mi_delta = delta;
14770 const char *const mi_op = mi_delta < 0 ? "sub" : "add";
14771 int shift = 0;
14772 int this_regno = (aggregate_value_p (TREE_TYPE (TREE_TYPE (function)), function)
14773 ? 1 : 0);
14774 if (mi_delta < 0)
14775 mi_delta = - mi_delta;
14776 if (TARGET_THUMB)
14777 {
14778 int labelno = thunk_label++;
14779 ASM_GENERATE_INTERNAL_LABEL (label, "LTHUMBFUNC", labelno);
14780 fputs ("\tldr\tr12, ", file);
14781 assemble_name (file, label);
14782 fputc ('\n', file);
14783 if (flag_pic)
14784 {
14785
14786
14787
14788
14789
14790
14791
14792
14793
14794
14795 ASM_GENERATE_INTERNAL_LABEL (labelpc, "LTHUNKPC", labelno);
14796 assemble_name (file, labelpc);
14797 fputs (":\n", file);
14798 fputs ("\tadd\tr12, pc, r12\n", file);
14799 }
14800 }
14801 while (mi_delta != 0)
14802 {
14803 if ((mi_delta & (3 << shift)) == 0)
14804 shift += 2;
14805 else
14806 {
14807 asm_fprintf (file, "\t%s\t%r, %r, #%d\n",
14808 mi_op, this_regno, this_regno,
14809 mi_delta & (0xff << shift));
14810 mi_delta &= ~(0xff << shift);
14811 shift += 8;
14812 }
14813 }
14814 if (TARGET_THUMB)
14815 {
14816 fprintf (file, "\tbx\tr12\n");
14817 ASM_OUTPUT_ALIGN (file, 2);
14818 assemble_name (file, label);
14819 fputs (":\n", file);
14820 if (flag_pic)
14821 {
14822
14823 rtx tem = XEXP (DECL_RTL (function), 0);
14824 tem = gen_rtx_PLUS (GET_MODE (tem), tem, GEN_INT (-7));
14825 tem = gen_rtx_MINUS (GET_MODE (tem),
14826 tem,
14827 gen_rtx_SYMBOL_REF (Pmode,
14828 ggc_strdup (labelpc)));
14829 assemble_integer (tem, 4, BITS_PER_WORD, 1);
14830 }
14831 else
14832
14833 assemble_integer (XEXP (DECL_RTL (function), 0), 4, BITS_PER_WORD, 1);
14834 }
14835 else
14836 {
14837 fputs ("\tb\t", file);
14838 assemble_name (file, XSTR (XEXP (DECL_RTL (function), 0), 0));
14839 if (NEED_PLT_RELOC)
14840 fputs ("(PLT)", file);
14841 fputc ('\n', file);
14842 }
14843 }
14844
14845 int
14846 arm_emit_vector_const (FILE *file, rtx x)
14847 {
14848 int i;
14849 const char * pattern;
14850
14851 gcc_assert (GET_CODE (x) == CONST_VECTOR);
14852
14853 switch (GET_MODE (x))
14854 {
14855 case V2SImode: pattern = "%08x"; break;
14856 case V4HImode: pattern = "%04x"; break;
14857 case V8QImode: pattern = "%02x"; break;
14858 default: gcc_unreachable ();
14859 }
14860
14861 fprintf (file, "0x");
14862 for (i = CONST_VECTOR_NUNITS (x); i--;)
14863 {
14864 rtx element;
14865
14866 element = CONST_VECTOR_ELT (x, i);
14867 fprintf (file, pattern, INTVAL (element));
14868 }
14869
14870 return 1;
14871 }
14872
14873 const char *
14874 arm_output_load_gr (rtx *operands)
14875 {
14876 rtx reg;
14877 rtx offset;
14878 rtx wcgr;
14879 rtx sum;
14880
14881 if (GET_CODE (operands [1]) != MEM
14882 || GET_CODE (sum = XEXP (operands [1], 0)) != PLUS
14883 || GET_CODE (reg = XEXP (sum, 0)) != REG
14884 || GET_CODE (offset = XEXP (sum, 1)) != CONST_INT
14885 || ((INTVAL (offset) < 1024) && (INTVAL (offset) > -1024)))
14886 return "wldrw%?\t%0, %1";
14887
14888
14889 output_asm_insn ("str%?\t%0, [sp, #-4]!\t@ Start of GR load expansion", & reg);
14890 wcgr = operands[0];
14891 operands[0] = reg;
14892 output_asm_insn ("ldr%?\t%0, %1", operands);
14893
14894 operands[0] = wcgr;
14895 operands[1] = reg;
14896 output_asm_insn ("tmcr%?\t%0, %1", operands);
14897 output_asm_insn ("ldr%?\t%0, [sp], #4\t@ End of GR load expansion", & reg);
14898
14899 return "";
14900 }
14901
14902
14903
14904
14905
14906
14907
14908
14909 static void
14910 arm_setup_incoming_varargs (CUMULATIVE_ARGS *cum,
14911 enum machine_mode mode ATTRIBUTE_UNUSED,
14912 tree type ATTRIBUTE_UNUSED,
14913 int *pretend_size,
14914 int second_time ATTRIBUTE_UNUSED)
14915 {
14916 cfun->machine->uses_anonymous_args = 1;
14917 if (cum->nregs < NUM_ARG_REGS)
14918 *pretend_size = (NUM_ARG_REGS - cum->nregs) * UNITS_PER_WORD;
14919 }
14920
14921
14922
14923
14924 int
14925 arm_no_early_store_addr_dep (rtx producer, rtx consumer)
14926 {
14927 rtx value = PATTERN (producer);
14928 rtx addr = PATTERN (consumer);
14929
14930 if (GET_CODE (value) == COND_EXEC)
14931 value = COND_EXEC_CODE (value);
14932 if (GET_CODE (value) == PARALLEL)
14933 value = XVECEXP (value, 0, 0);
14934 value = XEXP (value, 0);
14935 if (GET_CODE (addr) == COND_EXEC)
14936 addr = COND_EXEC_CODE (addr);
14937 if (GET_CODE (addr) == PARALLEL)
14938 addr = XVECEXP (addr, 0, 0);
14939 addr = XEXP (addr, 0);
14940
14941 return !reg_overlap_mentioned_p (value, addr);
14942 }
14943
14944
14945
14946
14947
14948 int
14949 arm_no_early_alu_shift_dep (rtx producer, rtx consumer)
14950 {
14951 rtx value = PATTERN (producer);
14952 rtx op = PATTERN (consumer);
14953 rtx early_op;
14954
14955 if (GET_CODE (value) == COND_EXEC)
14956 value = COND_EXEC_CODE (value);
14957 if (GET_CODE (value) == PARALLEL)
14958 value = XVECEXP (value, 0, 0);
14959 value = XEXP (value, 0);
14960 if (GET_CODE (op) == COND_EXEC)
14961 op = COND_EXEC_CODE (op);
14962 if (GET_CODE (op) == PARALLEL)
14963 op = XVECEXP (op, 0, 0);
14964 op = XEXP (op, 1);
14965
14966 early_op = XEXP (op, 0);
14967
14968
14969
14970 if (GET_CODE (early_op) == REG)
14971 early_op = op;
14972
14973 return !reg_overlap_mentioned_p (value, early_op);
14974 }
14975
14976
14977
14978
14979
14980 int
14981 arm_no_early_alu_shift_value_dep (rtx producer, rtx consumer)
14982 {
14983 rtx value = PATTERN (producer);
14984 rtx op = PATTERN (consumer);
14985 rtx early_op;
14986
14987 if (GET_CODE (value) == COND_EXEC)
14988 value = COND_EXEC_CODE (value);
14989 if (GET_CODE (value) == PARALLEL)
14990 value = XVECEXP (value, 0, 0);
14991 value = XEXP (value, 0);
14992 if (GET_CODE (op) == COND_EXEC)
14993 op = COND_EXEC_CODE (op);
14994 if (GET_CODE (op) == PARALLEL)
14995 op = XVECEXP (op, 0, 0);
14996 op = XEXP (op, 1);
14997
14998 early_op = XEXP (op, 0);
14999
15000
15001
15002
15003 if (GET_CODE (early_op) != REG)
15004 early_op = XEXP (early_op, 0);
15005
15006 return !reg_overlap_mentioned_p (value, early_op);
15007 }
15008
15009
15010
15011
15012
15013 int
15014 arm_no_early_mul_dep (rtx producer, rtx consumer)
15015 {
15016 rtx value = PATTERN (producer);
15017 rtx op = PATTERN (consumer);
15018
15019 if (GET_CODE (value) == COND_EXEC)
15020 value = COND_EXEC_CODE (value);
15021 if (GET_CODE (value) == PARALLEL)
15022 value = XVECEXP (value, 0, 0);
15023 value = XEXP (value, 0);
15024 if (GET_CODE (op) == COND_EXEC)
15025 op = COND_EXEC_CODE (op);
15026 if (GET_CODE (op) == PARALLEL)
15027 op = XVECEXP (op, 0, 0);
15028 op = XEXP (op, 1);
15029
15030 return (GET_CODE (op) == PLUS
15031 && !reg_overlap_mentioned_p (value, XEXP (op, 0)));
15032 }
15033
15034
15035
15036
15037
15038 static bool
15039 arm_promote_prototypes (tree t ATTRIBUTE_UNUSED)
15040 {
15041 return !TARGET_AAPCS_BASED;
15042 }
15043
15044
15045
15046
15047 static bool
15048 arm_default_short_enums (void)
15049 {
15050 return TARGET_AAPCS_BASED && arm_abi != ARM_ABI_AAPCS_LINUX;
15051 }
15052
15053
15054
15055
15056 static bool
15057 arm_align_anon_bitfield (void)
15058 {
15059 return TARGET_AAPCS_BASED;
15060 }
15061
15062
15063
15064
15065 static tree
15066 arm_cxx_guard_type (void)
15067 {
15068 return TARGET_AAPCS_BASED ? integer_type_node : long_long_integer_type_node;
15069 }
15070
15071
15072
15073
15074 static bool
15075 arm_cxx_guard_mask_bit (void)
15076 {
15077 return TARGET_AAPCS_BASED;
15078 }
15079
15080
15081
15082
15083 static tree
15084 arm_get_cookie_size (tree type)
15085 {
15086 tree size;
15087
15088 if (!TARGET_AAPCS_BASED)
15089 return default_cxx_get_cookie_size (type);
15090
15091 size = build_int_cst (sizetype, 8);
15092 return size;
15093 }
15094
15095
15096
15097
15098 static bool
15099 arm_cookie_has_size (void)
15100 {
15101 return TARGET_AAPCS_BASED;
15102 }
15103
15104
15105
15106
15107
15108 static bool
15109 arm_cxx_cdtor_returns_this (void)
15110 {
15111 return TARGET_AAPCS_BASED;
15112 }
15113
15114
15115
15116
15117 static bool
15118 arm_cxx_key_method_may_be_inline (void)
15119 {
15120 return !TARGET_AAPCS_BASED;
15121 }
15122
15123 static void
15124 arm_cxx_determine_class_data_visibility (tree decl)
15125 {
15126 if (!TARGET_AAPCS_BASED)
15127 return;
15128
15129
15130
15131
15132 if (!TARGET_ARM_DYNAMIC_VAGUE_LINKAGE_P && DECL_COMDAT (decl))
15133 DECL_VISIBILITY (decl) = VISIBILITY_HIDDEN;
15134 else
15135 DECL_VISIBILITY (decl) = VISIBILITY_DEFAULT;
15136 DECL_VISIBILITY_SPECIFIED (decl) = 1;
15137 }
15138
15139 static bool
15140 arm_cxx_class_data_always_comdat (void)
15141 {
15142
15143
15144 return !TARGET_AAPCS_BASED;
15145 }
15146
15147
15148
15149
15150
15151 static bool
15152 arm_cxx_use_aeabi_atexit (void)
15153 {
15154 return TARGET_AAPCS_BASED;
15155 }
15156
15157
15158 void
15159 arm_set_return_address (rtx source, rtx scratch)
15160 {
15161 arm_stack_offsets *offsets;
15162 HOST_WIDE_INT delta;
15163 rtx addr;
15164 unsigned long saved_regs;
15165
15166 saved_regs = arm_compute_save_reg_mask ();
15167
15168 if ((saved_regs & (1 << LR_REGNUM)) == 0)
15169 emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
15170 else
15171 {
15172 if (frame_pointer_needed)
15173 addr = plus_constant(hard_frame_pointer_rtx, -4);
15174 else
15175 {
15176
15177 offsets = arm_get_frame_offsets ();
15178 delta = offsets->outgoing_args - (offsets->frame + 4);
15179
15180
15181 if (delta >= 4096)
15182 {
15183 emit_insn (gen_addsi3 (scratch, stack_pointer_rtx,
15184 GEN_INT (delta & ~4095)));
15185 addr = scratch;
15186 delta &= 4095;
15187 }
15188 else
15189 addr = stack_pointer_rtx;
15190
15191 addr = plus_constant (addr, delta);
15192 }
15193 emit_move_insn (gen_frame_mem (Pmode, addr), source);
15194 }
15195 }
15196
15197
15198 void
15199 thumb_set_return_address (rtx source, rtx scratch)
15200 {
15201 arm_stack_offsets *offsets;
15202 HOST_WIDE_INT delta;
15203 int reg;
15204 rtx addr;
15205 unsigned long mask;
15206
15207 emit_insn (gen_rtx_USE (VOIDmode, source));
15208
15209 mask = thumb_compute_save_reg_mask ();
15210 if (mask & (1 << LR_REGNUM))
15211 {
15212 offsets = arm_get_frame_offsets ();
15213
15214
15215 if (frame_pointer_needed)
15216 {
15217 delta = offsets->soft_frame - offsets->saved_args;
15218 reg = THUMB_HARD_FRAME_POINTER_REGNUM;
15219 }
15220 else
15221 {
15222 delta = offsets->outgoing_args - offsets->saved_args;
15223 reg = SP_REGNUM;
15224 }
15225
15226 if (TARGET_BACKTRACE)
15227 delta -= 16;
15228
15229 delta -= 4;
15230
15231
15232 addr = gen_rtx_REG (SImode, reg);
15233 if ((reg != SP_REGNUM && delta >= 128)
15234 || delta >= 1024)
15235 {
15236 emit_insn (gen_movsi (scratch, GEN_INT (delta)));
15237 emit_insn (gen_addsi3 (scratch, scratch, stack_pointer_rtx));
15238 addr = scratch;
15239 }
15240 else
15241 addr = plus_constant (addr, delta);
15242
15243 emit_move_insn (gen_frame_mem (Pmode, addr), source);
15244 }
15245 else
15246 emit_move_insn (gen_rtx_REG (Pmode, LR_REGNUM), source);
15247 }
15248
15249
15250 bool
15251 arm_vector_mode_supported_p (enum machine_mode mode)
15252 {
15253 if ((mode == V2SImode)
15254 || (mode == V4HImode)
15255 || (mode == V8QImode))
15256 return true;
15257
15258 return false;
15259 }
15260
15261
15262
15263
15264
15265
15266 static unsigned HOST_WIDE_INT
15267 arm_shift_truncation_mask (enum machine_mode mode)
15268 {
15269 return mode == SImode ? 255 : 0;
15270 }
15271
15272
15273
15274
15275 unsigned int
15276 arm_dbx_register_number (unsigned int regno)
15277 {
15278 if (regno < 16)
15279 return regno;
15280
15281
15282
15283 if (IS_FPA_REGNUM (regno))
15284 return (TARGET_AAPCS_BASED ? 96 : 16) + regno - FIRST_FPA_REGNUM;
15285
15286 if (IS_VFP_REGNUM (regno))
15287 return 64 + regno - FIRST_VFP_REGNUM;
15288
15289 if (IS_IWMMXT_GR_REGNUM (regno))
15290 return 104 + regno - FIRST_IWMMXT_GR_REGNUM;
15291
15292 if (IS_IWMMXT_REGNUM (regno))
15293 return 112 + regno - FIRST_IWMMXT_REGNUM;
15294
15295 gcc_unreachable ();
15296 }
15297
15298
15299 #ifdef TARGET_UNWIND_INFO
15300
15301
15302
15303
15304 static void
15305 arm_unwind_emit_stm (FILE * asm_out_file, rtx p)
15306 {
15307 int i;
15308 HOST_WIDE_INT offset;
15309 HOST_WIDE_INT nregs;
15310 int reg_size;
15311 unsigned reg;
15312 unsigned lastreg;
15313 rtx e;
15314
15315
15316 e = XVECEXP (p, 0, 0);
15317 if (GET_CODE (e) != SET
15318 || GET_CODE (XEXP (e, 0)) != REG
15319 || REGNO (XEXP (e, 0)) != SP_REGNUM
15320 || GET_CODE (XEXP (e, 1)) != PLUS)
15321 abort ();
15322
15323 offset = -INTVAL (XEXP (XEXP (e, 1), 1));
15324 nregs = XVECLEN (p, 0) - 1;
15325
15326 reg = REGNO (XEXP (XVECEXP (p, 0, 1), 1));
15327 if (reg < 16)
15328 {
15329
15330
15331 if (nregs * 4 == offset - 4)
15332 {
15333 fprintf (asm_out_file, "\t.pad #4\n");
15334 offset -= 4;
15335 }
15336 reg_size = 4;
15337 }
15338 else if (IS_VFP_REGNUM (reg))
15339 {
15340
15341 offset -= 4;
15342 reg_size = 8;
15343 }
15344 else if (reg >= FIRST_FPA_REGNUM && reg <= LAST_FPA_REGNUM)
15345 {
15346
15347 asm_fprintf (asm_out_file, "\t.save %r, %wd\n", reg, nregs);
15348 return;
15349 }
15350 else
15351
15352 abort ();
15353
15354
15355
15356 if (offset != nregs * reg_size)
15357 abort ();
15358
15359 fprintf (asm_out_file, "\t.save {");
15360
15361 offset = 0;
15362 lastreg = 0;
15363
15364 for (i = 1; i <= nregs; i++)
15365 {
15366
15367
15368 e = XVECEXP (p, 0, i);
15369 if (GET_CODE (e) != SET
15370 || GET_CODE (XEXP (e, 0)) != MEM
15371 || GET_CODE (XEXP (e, 1)) != REG)
15372 abort ();
15373
15374 reg = REGNO (XEXP (e, 1));
15375 if (reg < lastreg)
15376 abort ();
15377
15378 if (i != 1)
15379 fprintf (asm_out_file, ", ");
15380
15381
15382 if (IS_VFP_REGNUM (reg))
15383 asm_fprintf (asm_out_file, "d%d", (reg - FIRST_VFP_REGNUM) / 2);
15384 else
15385 asm_fprintf (asm_out_file, "%r", reg);
15386
15387 #ifdef ENABLE_CHECKING
15388
15389 e = XEXP (XEXP (e, 0), 0);
15390 if (GET_CODE (e) == PLUS)
15391 {
15392 offset += reg_size;
15393 if (GET_CODE (XEXP (e, 0)) != REG
15394 || REGNO (XEXP (e, 0)) != SP_REGNUM
15395 || GET_CODE (XEXP (e, 1)) != CONST_INT
15396 || offset != INTVAL (XEXP (e, 1)))
15397 abort ();
15398 }
15399 else if (i != 1
15400 || GET_CODE (e) != REG
15401 || REGNO (e) != SP_REGNUM)
15402 abort ();
15403 #endif
15404 }
15405 fprintf (asm_out_file, "}\n");
15406 }
15407
15408
15409
15410 static void
15411 arm_unwind_emit_set (FILE * asm_out_file, rtx p)
15412 {
15413 rtx e0;
15414 rtx e1;
15415
15416 e0 = XEXP (p, 0);
15417 e1 = XEXP (p, 1);
15418 switch (GET_CODE (e0))
15419 {
15420 case MEM:
15421
15422 if (GET_CODE (XEXP (e0, 0)) != PRE_DEC
15423 || GET_CODE (XEXP (XEXP (e0, 0), 0)) != REG
15424 || REGNO (XEXP (XEXP (e0, 0), 0)) != SP_REGNUM)
15425 abort ();
15426
15427 asm_fprintf (asm_out_file, "\t.save ");
15428 if (IS_VFP_REGNUM (REGNO (e1)))
15429 asm_fprintf(asm_out_file, "{d%d}\n",
15430 (REGNO (e1) - FIRST_VFP_REGNUM) / 2);
15431 else
15432 asm_fprintf(asm_out_file, "{%r}\n", REGNO (e1));
15433 break;
15434
15435 case REG:
15436 if (REGNO (e0) == SP_REGNUM)
15437 {
15438
15439 if (GET_CODE (e1) != PLUS
15440 || GET_CODE (XEXP (e1, 0)) != REG
15441 || REGNO (XEXP (e1, 0)) != SP_REGNUM
15442 || GET_CODE (XEXP (e1, 1)) != CONST_INT)
15443 abort ();
15444
15445 asm_fprintf (asm_out_file, "\t.pad #%wd\n",
15446 -INTVAL (XEXP (e1, 1)));
15447 }
15448 else if (REGNO (e0) == HARD_FRAME_POINTER_REGNUM)
15449 {
15450 HOST_WIDE_INT offset;
15451 unsigned reg;
15452
15453 if (GET_CODE (e1) == PLUS)
15454 {
15455 if (GET_CODE (XEXP (e1, 0)) != REG
15456 || GET_CODE (XEXP (e1, 1)) != CONST_INT)
15457 abort ();
15458 reg = REGNO (XEXP (e1, 0));
15459 offset = INTVAL (XEXP (e1, 1));
15460 asm_fprintf (asm_out_file, "\t.setfp %r, %r, #%wd\n",
15461 HARD_FRAME_POINTER_REGNUM, reg,
15462 INTVAL (XEXP (e1, 1)));
15463 }
15464 else if (GET_CODE (e1) == REG)
15465 {
15466 reg = REGNO (e1);
15467 asm_fprintf (asm_out_file, "\t.setfp %r, %r\n",
15468 HARD_FRAME_POINTER_REGNUM, reg);
15469 }
15470 else
15471 abort ();
15472 }
15473 else if (GET_CODE (e1) == REG && REGNO (e1) == SP_REGNUM)
15474 {
15475
15476 asm_fprintf (asm_out_file, "\t.movsp %r\n", REGNO (e0));
15477 }
15478 else if (GET_CODE (e1) == PLUS
15479 && GET_CODE (XEXP (e1, 0)) == REG
15480 && REGNO (XEXP (e1, 0)) == SP_REGNUM
15481 && GET_CODE (XEXP (e1, 1)) == CONST_INT)
15482 {
15483
15484 asm_fprintf (asm_out_file, "\t.movsp %r, #%d\n",
15485 REGNO (e0), (int)INTVAL(XEXP (e1, 1)));
15486 }
15487 else
15488 abort ();
15489 break;
15490
15491 default:
15492 abort ();
15493 }
15494 }
15495
15496
15497
15498
15499 static void
15500 arm_unwind_emit (FILE * asm_out_file, rtx insn)
15501 {
15502 rtx pat;
15503
15504 if (!ARM_EABI_UNWIND_TABLES)
15505 return;
15506
15507 if (GET_CODE (insn) == NOTE || !RTX_FRAME_RELATED_P (insn))
15508 return;
15509
15510 pat = find_reg_note (insn, REG_FRAME_RELATED_EXPR, NULL_RTX);
15511 if (pat)
15512 pat = XEXP (pat, 0);
15513 else
15514 pat = PATTERN (insn);
15515
15516 switch (GET_CODE (pat))
15517 {
15518 case SET:
15519 arm_unwind_emit_set (asm_out_file, pat);
15520 break;
15521
15522 case SEQUENCE:
15523
15524 arm_unwind_emit_stm (asm_out_file, pat);
15525 break;
15526
15527 default:
15528 abort();
15529 }
15530 }
15531
15532
15533
15534
15535
15536
15537 static bool
15538 arm_output_ttype (rtx x)
15539 {
15540 fputs ("\t.word\t", asm_out_file);
15541 output_addr_const (asm_out_file, x);
15542
15543 if (GET_CODE (x) != CONST_INT)
15544 fputs ("(TARGET2)", asm_out_file);
15545 fputc ('\n', asm_out_file);
15546
15547 return TRUE;
15548 }
15549 #endif
15550
15551
15552
15553
15554 void
15555 arm_output_fn_unwind (FILE * f, bool prologue)
15556 {
15557 if (!ARM_EABI_UNWIND_TABLES)
15558 return;
15559
15560 if (prologue)
15561 fputs ("\t.fnstart\n", f);
15562 else
15563 fputs ("\t.fnend\n", f);
15564 }
15565
15566 static bool
15567 arm_emit_tls_decoration (FILE *fp, rtx x)
15568 {
15569 enum tls_reloc reloc;
15570 rtx val;
15571
15572 val = XVECEXP (x, 0, 0);
15573 reloc = INTVAL (XVECEXP (x, 0, 1));
15574
15575 output_addr_const (fp, val);
15576
15577 switch (reloc)
15578 {
15579 case TLS_GD32:
15580 fputs ("(tlsgd)", fp);
15581 break;
15582 case TLS_LDM32:
15583 fputs ("(tlsldm)", fp);
15584 break;
15585 case TLS_LDO32:
15586 fputs ("(tlsldo)", fp);
15587 break;
15588 case TLS_IE32:
15589 fputs ("(gottpoff)", fp);
15590 break;
15591 case TLS_LE32:
15592 fputs ("(tpoff)", fp);
15593 break;
15594 default:
15595 gcc_unreachable ();
15596 }
15597
15598 switch (reloc)
15599 {
15600 case TLS_GD32:
15601 case TLS_LDM32:
15602 case TLS_IE32:
15603 fputs (" + (. - ", fp);
15604 output_addr_const (fp, XVECEXP (x, 0, 2));
15605 fputs (" - ", fp);
15606 output_addr_const (fp, XVECEXP (x, 0, 3));
15607 fputc (')', fp);
15608 break;
15609 default:
15610 break;
15611 }
15612
15613 return TRUE;
15614 }
15615
15616 bool
15617 arm_output_addr_const_extra (FILE *fp, rtx x)
15618 {
15619 if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_TLS)
15620 return arm_emit_tls_decoration (fp, x);
15621 else if (GET_CODE (x) == UNSPEC && XINT (x, 1) == UNSPEC_PIC_LABEL)
15622 {
15623 char label[256];
15624 int labelno = INTVAL (XVECEXP (x, 0, 0));
15625
15626 ASM_GENERATE_INTERNAL_LABEL (label, "LPIC", labelno);
15627 assemble_name_raw (fp, label);
15628
15629 return TRUE;
15630 }
15631 else if (GET_CODE (x) == CONST_VECTOR)
15632 return arm_emit_vector_const (fp, x);
15633
15634 return FALSE;
15635 }
15636
15637 #include "gt-arm.h"