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