00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #include "system.h"
00026 #include "coretypes.h"
00027 #include "tm.h"
00028 #include "insn-config.h"
00029 #include "rtl.h"
00030 #include "tree.h"
00031 #include "flags.h"
00032 #include "expr.h"
00033 #include "optabs.h"
00034 #include "function.h"
00035 #include "regs.h"
00036 #include "hard-reg-set.h"
00037 #include "output.h"
00038 #include "insn-attr.h"
00039 #include "toplev.h"
00040 #include "recog.h"
00041 #include "c-pragma.h"
00042 #include "integrate.h"
00043 #include "dwarf2.h"
00044 #include "tm_p.h"
00045 #include "target.h"
00046 #include "target-def.h"
00047 #include "real.h"
00048 #include "langhooks.h"
00049 #include "basic-block.h"
00050 #include "cfglayout.h"
00051 #include "intl.h"
00052 #include "sched-int.h"
00053 #include "ggc.h"
00054 #include "tree-gimple.h"
00055 #include "cfgloop.h"
00056 #include "alloc-pool.h"
00057
00058
00059 int code_for_indirect_jump_scratch = CODE_FOR_indirect_jump_scratch;
00060
00061 #define MSW (TARGET_LITTLE_ENDIAN ? 1 : 0)
00062 #define LSW (TARGET_LITTLE_ENDIAN ? 0 : 1)
00063
00064
00065 #define CONST_OK_FOR_ADD(size) \
00066 (TARGET_SHMEDIA ? CONST_OK_FOR_I10 (size) : CONST_OK_FOR_I08 (size))
00067 #define GEN_MOV (*(TARGET_SHMEDIA64 ? gen_movdi : gen_movsi))
00068 #define GEN_ADD3 (*(TARGET_SHMEDIA64 ? gen_adddi3 : gen_addsi3))
00069 #define GEN_SUB3 (*(TARGET_SHMEDIA64 ? gen_subdi3 : gen_subsi3))
00070
00071
00072 int current_function_interrupt;
00073
00074 tree sh_deferred_function_attributes;
00075 tree *sh_deferred_function_attributes_tail = &sh_deferred_function_attributes;
00076
00077
00078
00079
00080 enum processor_type sh_cpu;
00081
00082
00083
00084
00085 static short *regmode_weight[2];
00086
00087
00088 static int curr_regmode_pressure[2];
00089
00090
00091 static int skip_cycles = 0;
00092
00093
00094
00095 static short cached_can_issue_more;
00096
00097
00098
00099
00100 rtx sh_compare_op0;
00101 rtx sh_compare_op1;
00102
00103
00104
00105
00106 enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER] =
00107 {
00108 R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00109 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00110 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00111 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00112 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00113 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00114 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00115 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00116 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00117 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00118 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00119 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00120 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00121 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00122 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00123 GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
00124 FP0_REGS,FP_REGS, FP_REGS, FP_REGS,
00125 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00126 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00127 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00128 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00129 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00130 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00131 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00132 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00133 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00134 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00135 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00136 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00137 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00138 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00139 FP_REGS, FP_REGS, FP_REGS, FP_REGS,
00140 TARGET_REGS, TARGET_REGS, TARGET_REGS, TARGET_REGS,
00141 TARGET_REGS, TARGET_REGS, TARGET_REGS, TARGET_REGS,
00142 DF_REGS, DF_REGS, DF_REGS, DF_REGS,
00143 DF_REGS, DF_REGS, DF_REGS, DF_REGS,
00144 NO_REGS, GENERAL_REGS, PR_REGS, T_REGS,
00145 MAC_REGS, MAC_REGS, FPUL_REGS, FPSCR_REGS,
00146 GENERAL_REGS, GENERAL_REGS,
00147 };
00148
00149 char sh_register_names[FIRST_PSEUDO_REGISTER] \
00150 [MAX_REGISTER_NAME_LENGTH + 1] = SH_REGISTER_NAMES_INITIALIZER;
00151
00152 char sh_additional_register_names[ADDREGNAMES_SIZE] \
00153 [MAX_ADDITIONAL_REGISTER_NAME_LENGTH + 1]
00154 = SH_ADDITIONAL_REGISTER_NAMES_INITIALIZER;
00155
00156
00157
00158
00159
00160 enum reg_class reg_class_from_letter[] =
00161 {
00162 ALL_REGS, TARGET_REGS, FPSCR_REGS, DF_REGS,
00163 FP_REGS, FP_REGS, NO_REGS, NO_REGS,
00164 NO_REGS, NO_REGS, SIBCALL_REGS, PR_REGS,
00165 NO_REGS, NO_REGS, NO_REGS, NO_REGS,
00166 NO_REGS, NO_REGS, NO_REGS, T_REGS,
00167 NO_REGS, NO_REGS, FP0_REGS, MAC_REGS,
00168 FPUL_REGS, R0_REGS
00169 };
00170
00171 int assembler_dialect;
00172
00173 static bool shmedia_space_reserved_for_target_registers;
00174
00175 static bool sh_handle_option (size_t, const char *, int);
00176 static void split_branches (rtx);
00177 static int branch_dest (rtx);
00178 static void force_into (rtx, rtx);
00179 static void print_slot (rtx);
00180 static rtx add_constant (rtx, enum machine_mode, rtx);
00181 static void dump_table (rtx, rtx);
00182 static int hi_const (rtx);
00183 static int broken_move (rtx);
00184 static int mova_p (rtx);
00185 static rtx find_barrier (int, rtx, rtx);
00186 static int noncall_uses_reg (rtx, rtx, rtx *);
00187 static rtx gen_block_redirect (rtx, int, int);
00188 static void sh_reorg (void);
00189 static void output_stack_adjust (int, rtx, int, HARD_REG_SET *);
00190 static rtx frame_insn (rtx);
00191 static rtx push (int);
00192 static void pop (int);
00193 static void push_regs (HARD_REG_SET *, int);
00194 static int calc_live_regs (HARD_REG_SET *);
00195 static void mark_use (rtx, rtx *);
00196 static HOST_WIDE_INT rounded_frame_size (int);
00197 static rtx mark_constant_pool_use (rtx);
00198 const struct attribute_spec sh_attribute_table[];
00199 static tree sh_handle_interrupt_handler_attribute (tree *, tree, tree, int, bool *);
00200 static tree sh_handle_sp_switch_attribute (tree *, tree, tree, int, bool *);
00201 static tree sh_handle_trap_exit_attribute (tree *, tree, tree, int, bool *);
00202 static tree sh_handle_renesas_attribute (tree *, tree, tree, int, bool *);
00203 static void sh_output_function_epilogue (FILE *, HOST_WIDE_INT);
00204 static void sh_insert_attributes (tree, tree *);
00205 static const char *sh_check_pch_target_flags (int);
00206 static int sh_adjust_cost (rtx, rtx, rtx, int);
00207 static int sh_issue_rate (void);
00208 static int sh_dfa_new_cycle (FILE *, int, rtx, int, int, int *sort_p);
00209 static short find_set_regmode_weight (rtx, enum machine_mode);
00210 static short find_insn_regmode_weight (rtx, enum machine_mode);
00211 static void find_regmode_weight (basic_block, enum machine_mode);
00212 static void sh_md_init_global (FILE *, int, int);
00213 static void sh_md_finish_global (FILE *, int);
00214 static int rank_for_reorder (const void *, const void *);
00215 static void swap_reorder (rtx *, int);
00216 static void ready_reorder (rtx *, int);
00217 static short high_pressure (enum machine_mode);
00218 static int sh_reorder (FILE *, int, rtx *, int *, int);
00219 static int sh_reorder2 (FILE *, int, rtx *, int *, int);
00220 static void sh_md_init (FILE *, int, int);
00221 static int sh_variable_issue (FILE *, int, rtx, int);
00222
00223 static bool sh_function_ok_for_sibcall (tree, tree);
00224
00225 static bool sh_cannot_modify_jumps_p (void);
00226 static int sh_target_reg_class (void);
00227 static bool sh_optimize_target_register_callee_saved (bool);
00228 static bool sh_ms_bitfield_layout_p (tree);
00229
00230 static void sh_init_builtins (void);
00231 static void sh_media_init_builtins (void);
00232 static rtx sh_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
00233 static void sh_output_mi_thunk (FILE *, tree, HOST_WIDE_INT, HOST_WIDE_INT, tree);
00234 static void sh_file_start (void);
00235 static int flow_dependent_p (rtx, rtx);
00236 static void flow_dependent_p_1 (rtx, rtx, void *);
00237 static int shiftcosts (rtx);
00238 static int andcosts (rtx);
00239 static int addsubcosts (rtx);
00240 static int multcosts (rtx);
00241 static bool unspec_caller_rtx_p (rtx);
00242 static bool sh_cannot_copy_insn_p (rtx);
00243 static bool sh_rtx_costs (rtx, int, int, int *);
00244 static int sh_address_cost (rtx);
00245 #ifdef TARGET_ADJUST_UNROLL_MAX
00246 static int sh_adjust_unroll_max (struct loop *, int, int, int, int);
00247 #endif
00248 static int sh_pr_n_sets (void);
00249 static rtx sh_allocate_initial_value (rtx);
00250 static int shmedia_target_regs_stack_space (HARD_REG_SET *);
00251 static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *);
00252 static int shmedia_target_regs_stack_adjust (HARD_REG_SET *);
00253 static int scavenge_reg (HARD_REG_SET *s);
00254 struct save_schedule_s;
00255 static struct save_entry_s *sh5_schedule_saves (HARD_REG_SET *,
00256 struct save_schedule_s *, int);
00257
00258 static rtx sh_struct_value_rtx (tree, int);
00259 static bool sh_return_in_memory (tree, tree);
00260 static rtx sh_builtin_saveregs (void);
00261 static void sh_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode, tree, int *, int);
00262 static bool sh_strict_argument_naming (CUMULATIVE_ARGS *);
00263 static bool sh_pretend_outgoing_varargs_named (CUMULATIVE_ARGS *);
00264 static tree sh_build_builtin_va_list (void);
00265 static tree sh_gimplify_va_arg_expr (tree, tree, tree *, tree *);
00266 static bool sh_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
00267 tree, bool);
00268 static bool sh_callee_copies (CUMULATIVE_ARGS *, enum machine_mode,
00269 tree, bool);
00270 static int sh_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
00271 tree, bool);
00272 static int sh_dwarf_calling_convention (tree);
00273 static int hard_regs_intersect_p (HARD_REG_SET *, HARD_REG_SET *);
00274
00275
00276
00277 #undef TARGET_ATTRIBUTE_TABLE
00278 #define TARGET_ATTRIBUTE_TABLE sh_attribute_table
00279
00280
00281 #undef TARGET_ASM_UNALIGNED_HI_OP
00282 #define TARGET_ASM_UNALIGNED_HI_OP "\t.uaword\t"
00283 #undef TARGET_ASM_UNALIGNED_SI_OP
00284 #define TARGET_ASM_UNALIGNED_SI_OP "\t.ualong\t"
00285
00286
00287 #undef TARGET_ASM_UNALIGNED_DI_OP
00288 #define TARGET_ASM_UNALIGNED_DI_OP "\t.uaquad\t"
00289 #undef TARGET_ASM_ALIGNED_DI_OP
00290 #define TARGET_ASM_ALIGNED_DI_OP "\t.quad\t"
00291
00292 #undef TARGET_ASM_FUNCTION_EPILOGUE
00293 #define TARGET_ASM_FUNCTION_EPILOGUE sh_output_function_epilogue
00294
00295 #undef TARGET_ASM_OUTPUT_MI_THUNK
00296 #define TARGET_ASM_OUTPUT_MI_THUNK sh_output_mi_thunk
00297
00298 #undef TARGET_ASM_CAN_OUTPUT_MI_THUNK
00299 #define TARGET_ASM_CAN_OUTPUT_MI_THUNK hook_bool_tree_hwi_hwi_tree_true
00300
00301 #undef TARGET_ASM_FILE_START
00302 #define TARGET_ASM_FILE_START sh_file_start
00303 #undef TARGET_ASM_FILE_START_FILE_DIRECTIVE
00304 #define TARGET_ASM_FILE_START_FILE_DIRECTIVE true
00305
00306 #undef TARGET_DEFAULT_TARGET_FLAGS
00307 #define TARGET_DEFAULT_TARGET_FLAGS TARGET_DEFAULT
00308 #undef TARGET_HANDLE_OPTION
00309 #define TARGET_HANDLE_OPTION sh_handle_option
00310
00311 #undef TARGET_INSERT_ATTRIBUTES
00312 #define TARGET_INSERT_ATTRIBUTES sh_insert_attributes
00313
00314 #undef TARGET_SCHED_ADJUST_COST
00315 #define TARGET_SCHED_ADJUST_COST sh_adjust_cost
00316
00317 #undef TARGET_SCHED_ISSUE_RATE
00318 #define TARGET_SCHED_ISSUE_RATE sh_issue_rate
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
00353
00354
00355 #undef TARGET_SCHED_DFA_NEW_CYCLE
00356 #define TARGET_SCHED_DFA_NEW_CYCLE sh_dfa_new_cycle
00357
00358 #undef TARGET_SCHED_INIT_GLOBAL
00359 #define TARGET_SCHED_INIT_GLOBAL sh_md_init_global
00360
00361 #undef TARGET_SCHED_FINISH_GLOBAL
00362 #define TARGET_SCHED_FINISH_GLOBAL sh_md_finish_global
00363
00364 #undef TARGET_SCHED_VARIABLE_ISSUE
00365 #define TARGET_SCHED_VARIABLE_ISSUE sh_variable_issue
00366
00367 #undef TARGET_SCHED_REORDER
00368 #define TARGET_SCHED_REORDER sh_reorder
00369
00370 #undef TARGET_SCHED_REORDER2
00371 #define TARGET_SCHED_REORDER2 sh_reorder2
00372
00373 #undef TARGET_SCHED_INIT
00374 #define TARGET_SCHED_INIT sh_md_init
00375
00376 #undef TARGET_CANNOT_MODIFY_JUMPS_P
00377 #define TARGET_CANNOT_MODIFY_JUMPS_P sh_cannot_modify_jumps_p
00378 #undef TARGET_BRANCH_TARGET_REGISTER_CLASS
00379 #define TARGET_BRANCH_TARGET_REGISTER_CLASS sh_target_reg_class
00380 #undef TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED
00381 #define TARGET_BRANCH_TARGET_REGISTER_CALLEE_SAVED \
00382 sh_optimize_target_register_callee_saved
00383
00384 #undef TARGET_MS_BITFIELD_LAYOUT_P
00385 #define TARGET_MS_BITFIELD_LAYOUT_P sh_ms_bitfield_layout_p
00386
00387 #undef TARGET_INIT_BUILTINS
00388 #define TARGET_INIT_BUILTINS sh_init_builtins
00389 #undef TARGET_EXPAND_BUILTIN
00390 #define TARGET_EXPAND_BUILTIN sh_expand_builtin
00391
00392 #undef TARGET_FUNCTION_OK_FOR_SIBCALL
00393 #define TARGET_FUNCTION_OK_FOR_SIBCALL sh_function_ok_for_sibcall
00394
00395 #undef TARGET_CANNOT_COPY_INSN_P
00396 #define TARGET_CANNOT_COPY_INSN_P sh_cannot_copy_insn_p
00397 #undef TARGET_RTX_COSTS
00398 #define TARGET_RTX_COSTS sh_rtx_costs
00399 #undef TARGET_ADDRESS_COST
00400 #define TARGET_ADDRESS_COST sh_address_cost
00401 #undef TARGET_ALLOCATE_INITIAL_VALUE
00402 #define TARGET_ALLOCATE_INITIAL_VALUE sh_allocate_initial_value
00403
00404 #undef TARGET_MACHINE_DEPENDENT_REORG
00405 #define TARGET_MACHINE_DEPENDENT_REORG sh_reorg
00406
00407 #ifdef HAVE_AS_TLS
00408 #undef TARGET_HAVE_TLS
00409 #define TARGET_HAVE_TLS true
00410 #endif
00411
00412 #undef TARGET_PROMOTE_PROTOTYPES
00413 #define TARGET_PROMOTE_PROTOTYPES sh_promote_prototypes
00414 #undef TARGET_PROMOTE_FUNCTION_ARGS
00415 #define TARGET_PROMOTE_FUNCTION_ARGS sh_promote_prototypes
00416 #undef TARGET_PROMOTE_FUNCTION_RETURN
00417 #define TARGET_PROMOTE_FUNCTION_RETURN sh_promote_prototypes
00418
00419 #undef TARGET_STRUCT_VALUE_RTX
00420 #define TARGET_STRUCT_VALUE_RTX sh_struct_value_rtx
00421 #undef TARGET_RETURN_IN_MEMORY
00422 #define TARGET_RETURN_IN_MEMORY sh_return_in_memory
00423
00424 #undef TARGET_EXPAND_BUILTIN_SAVEREGS
00425 #define TARGET_EXPAND_BUILTIN_SAVEREGS sh_builtin_saveregs
00426 #undef TARGET_SETUP_INCOMING_VARARGS
00427 #define TARGET_SETUP_INCOMING_VARARGS sh_setup_incoming_varargs
00428 #undef TARGET_STRICT_ARGUMENT_NAMING
00429 #define TARGET_STRICT_ARGUMENT_NAMING sh_strict_argument_naming
00430 #undef TARGET_PRETEND_OUTGOING_VARARGS_NAMED
00431 #define TARGET_PRETEND_OUTGOING_VARARGS_NAMED sh_pretend_outgoing_varargs_named
00432 #undef TARGET_MUST_PASS_IN_STACK
00433 #define TARGET_MUST_PASS_IN_STACK must_pass_in_stack_var_size
00434 #undef TARGET_PASS_BY_REFERENCE
00435 #define TARGET_PASS_BY_REFERENCE sh_pass_by_reference
00436 #undef TARGET_CALLEE_COPIES
00437 #define TARGET_CALLEE_COPIES sh_callee_copies
00438 #undef TARGET_ARG_PARTIAL_BYTES
00439 #define TARGET_ARG_PARTIAL_BYTES sh_arg_partial_bytes
00440
00441 #undef TARGET_BUILD_BUILTIN_VA_LIST
00442 #define TARGET_BUILD_BUILTIN_VA_LIST sh_build_builtin_va_list
00443 #undef TARGET_GIMPLIFY_VA_ARG_EXPR
00444 #define TARGET_GIMPLIFY_VA_ARG_EXPR sh_gimplify_va_arg_expr
00445
00446 #undef TARGET_VECTOR_MODE_SUPPORTED_P
00447 #define TARGET_VECTOR_MODE_SUPPORTED_P sh_vector_mode_supported_p
00448
00449 #undef TARGET_CHECK_PCH_TARGET_FLAGS
00450 #define TARGET_CHECK_PCH_TARGET_FLAGS sh_check_pch_target_flags
00451
00452 #undef TARGET_DWARF_CALLING_CONVENTION
00453 #define TARGET_DWARF_CALLING_CONVENTION sh_dwarf_calling_convention
00454
00455
00456 #define INSN_REGMODE_WEIGHT(INSN, MODE) regmode_weight[((MODE) == SImode) ? 0 : 1][INSN_UID (INSN)]
00457
00458
00459 #define CURR_REGMODE_PRESSURE(MODE) curr_regmode_pressure[((MODE) == SImode) ? 0 : 1]
00460
00461 #ifdef SYMBIAN
00462
00463 #undef TARGET_ENCODE_SECTION_INFO
00464 #define TARGET_ENCODE_SECTION_INFO sh_symbian_encode_section_info
00465 #undef TARGET_STRIP_NAME_ENCODING
00466 #define TARGET_STRIP_NAME_ENCODING sh_symbian_strip_name_encoding
00467 #undef TARGET_CXX_IMPORT_EXPORT_CLASS
00468 #define TARGET_CXX_IMPORT_EXPORT_CLASS symbian_import_export_class
00469
00470 #endif
00471
00472 #ifdef TARGET_ADJUST_UNROLL_MAX
00473 #undef TARGET_ADJUST_UNROLL_MAX
00474 #define TARGET_ADJUST_UNROLL_MAX sh_adjust_unroll_max
00475 #endif
00476
00477 #undef TARGET_SECONDARY_RELOAD
00478 #define TARGET_SECONDARY_RELOAD sh_secondary_reload
00479
00480 struct gcc_target targetm = TARGET_INITIALIZER;
00481
00482
00483
00484 static bool
00485 sh_handle_option (size_t code, const char *arg ATTRIBUTE_UNUSED,
00486 int value ATTRIBUTE_UNUSED)
00487 {
00488 switch (code)
00489 {
00490 case OPT_m1:
00491 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH1;
00492 return true;
00493
00494 case OPT_m2:
00495 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2;
00496 return true;
00497
00498 case OPT_m2a:
00499 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2A;
00500 return true;
00501
00502 case OPT_m2a_nofpu:
00503 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2A_NOFPU;
00504 return true;
00505
00506 case OPT_m2a_single:
00507 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2A_SINGLE;
00508 return true;
00509
00510 case OPT_m2a_single_only:
00511 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2A_SINGLE_ONLY;
00512 return true;
00513
00514 case OPT_m2e:
00515 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH2E;
00516 return true;
00517
00518 case OPT_m3:
00519 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH3;
00520 return true;
00521
00522 case OPT_m3e:
00523 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH3E;
00524 return true;
00525
00526 case OPT_m4:
00527 case OPT_m4_100:
00528 case OPT_m4_200:
00529 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4;
00530 return true;
00531
00532 case OPT_m4_nofpu:
00533 case OPT_m4_400:
00534 case OPT_m4_500:
00535 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_NOFPU;
00536 return true;
00537
00538 case OPT_m4_single:
00539 case OPT_m4_100_single:
00540 case OPT_m4_200_single:
00541 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_SINGLE;
00542 return true;
00543
00544 case OPT_m4_single_only:
00545 case OPT_m4_100_single_only:
00546 case OPT_m4_200_single_only:
00547 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4_SINGLE_ONLY;
00548 return true;
00549
00550 case OPT_m4a:
00551 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4A;
00552 return true;
00553
00554 case OPT_m4a_nofpu:
00555 case OPT_m4al:
00556 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4A_NOFPU;
00557 return true;
00558
00559 case OPT_m4a_single:
00560 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4A_SINGLE;
00561 return true;
00562
00563 case OPT_m4a_single_only:
00564 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH4A_SINGLE_ONLY;
00565 return true;
00566
00567 case OPT_m5_32media:
00568 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_32MEDIA;
00569 return true;
00570
00571 case OPT_m5_32media_nofpu:
00572 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_32MEDIA_NOFPU;
00573 return true;
00574
00575 case OPT_m5_64media:
00576 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_64MEDIA;
00577 return true;
00578
00579 case OPT_m5_64media_nofpu:
00580 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_64MEDIA_NOFPU;
00581 return true;
00582
00583 case OPT_m5_compact:
00584 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_COMPACT;
00585 return true;
00586
00587 case OPT_m5_compact_nofpu:
00588 target_flags = (target_flags & ~MASK_ARCH) | SELECT_SH5_COMPACT_NOFPU;
00589 return true;
00590
00591 default:
00592 return true;
00593 }
00594 }
00595
00596
00597
00598 void
00599 print_operand_address (FILE *stream, rtx x)
00600 {
00601 switch (GET_CODE (x))
00602 {
00603 case REG:
00604 case SUBREG:
00605 fprintf (stream, "@%s", reg_names[true_regnum (x)]);
00606 break;
00607
00608 case PLUS:
00609 {
00610 rtx base = XEXP (x, 0);
00611 rtx index = XEXP (x, 1);
00612
00613 switch (GET_CODE (index))
00614 {
00615 case CONST_INT:
00616 fprintf (stream, "@(%d,%s)", (int) INTVAL (index),
00617 reg_names[true_regnum (base)]);
00618 break;
00619
00620 case REG:
00621 case SUBREG:
00622 {
00623 int base_num = true_regnum (base);
00624 int index_num = true_regnum (index);
00625
00626 fprintf (stream, "@(r0,%s)",
00627 reg_names[MAX (base_num, index_num)]);
00628 break;
00629 }
00630
00631 default:
00632 gcc_unreachable ();
00633 }
00634 }
00635 break;
00636
00637 case PRE_DEC:
00638 fprintf (stream, "@-%s", reg_names[true_regnum (XEXP (x, 0))]);
00639 break;
00640
00641 case POST_INC:
00642 fprintf (stream, "@%s+", reg_names[true_regnum (XEXP (x, 0))]);
00643 break;
00644
00645 default:
00646 x = mark_constant_pool_use (x);
00647 output_addr_const (stream, x);
00648 break;
00649 }
00650 }
00651
00652
00653
00654
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674 void
00675 print_operand (FILE *stream, rtx x, int code)
00676 {
00677 int regno;
00678 enum machine_mode mode;
00679
00680 switch (code)
00681 {
00682 tree trapa_attr;
00683
00684 case '.':
00685 if (final_sequence
00686 && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))
00687 && get_attr_length (XVECEXP (final_sequence, 0, 1)))
00688 fprintf (stream, ASSEMBLER_DIALECT ? "/s" : ".s");
00689 break;
00690 case ',':
00691 fprintf (stream, "%s", LOCAL_LABEL_PREFIX);
00692 break;
00693 case '@':
00694 trapa_attr = lookup_attribute ("trap_exit",
00695 DECL_ATTRIBUTES (current_function_decl));
00696 if (trapa_attr)
00697 fprintf (stream, "trapa #%ld",
00698 (long) TREE_INT_CST_LOW (TREE_VALUE (TREE_VALUE (trapa_attr))));
00699 else if (sh_cfun_interrupt_handler_p ())
00700 fprintf (stream, "rte");
00701 else
00702 fprintf (stream, "rts");
00703 break;
00704 case '#':
00705
00706 if (dbr_sequence_length () == 0)
00707 fprintf (stream, "\n\tnop");
00708 break;
00709 case '\'':
00710 {
00711 rtx note = find_reg_note (current_output_insn, REG_BR_PROB, 0);
00712
00713 if (note && INTVAL (XEXP (note, 0)) * 2 < REG_BR_PROB_BASE)
00714 fputs ("/u", stream);
00715 break;
00716 }
00717 case '>':
00718 if (flag_verbose_asm && JUMP_LABEL (current_output_insn))
00719 {
00720 fputs ("\t! target: ", stream);
00721 output_addr_const (stream, JUMP_LABEL (current_output_insn));
00722 }
00723 break;
00724 case 'O':
00725 x = mark_constant_pool_use (x);
00726 output_addr_const (stream, x);
00727 break;
00728
00729
00730
00731
00732
00733
00734
00735 case 'R':
00736 if (REG_P (x) || GET_CODE (x) == SUBREG)
00737 {
00738 regno = true_regnum (x);
00739 regno += FP_REGISTER_P (regno) ? 1 : LSW;
00740 fputs (reg_names[regno], (stream));
00741 }
00742 else if (MEM_P (x))
00743 {
00744 x = adjust_address (x, SImode, 4 * LSW);
00745 print_operand_address (stream, XEXP (x, 0));
00746 }
00747 else
00748 {
00749 rtx sub = NULL_RTX;
00750
00751 mode = GET_MODE (x);
00752 if (mode == VOIDmode)
00753 mode = DImode;
00754 if (GET_MODE_SIZE (mode) >= 8)
00755 sub = simplify_subreg (SImode, x, mode, 4 * LSW);
00756 if (sub)
00757 print_operand (stream, sub, 0);
00758 else
00759 output_operand_lossage ("invalid operand to %%R");
00760 }
00761 break;
00762 case 'S':
00763 if (REG_P (x) || GET_CODE (x) == SUBREG)
00764 {
00765 regno = true_regnum (x);
00766 regno += FP_REGISTER_P (regno) ? 0 : MSW;
00767 fputs (reg_names[regno], (stream));
00768 }
00769 else if (MEM_P (x))
00770 {
00771 x = adjust_address (x, SImode, 4 * MSW);
00772 print_operand_address (stream, XEXP (x, 0));
00773 }
00774 else
00775 {
00776 rtx sub = NULL_RTX;
00777
00778 mode = GET_MODE (x);
00779 if (mode == VOIDmode)
00780 mode = DImode;
00781 if (GET_MODE_SIZE (mode) >= 8)
00782 sub = simplify_subreg (SImode, x, mode, 4 * MSW);
00783 if (sub)
00784 print_operand (stream, sub, 0);
00785 else
00786 output_operand_lossage ("invalid operand to %%S");
00787 }
00788 break;
00789 case 'T':
00790
00791 switch (GET_CODE (x))
00792 {
00793 case REG:
00794 fputs (reg_names[REGNO (x) + 1], (stream));
00795 break;
00796 case MEM:
00797 if (GET_CODE (XEXP (x, 0)) != PRE_DEC
00798 && GET_CODE (XEXP (x, 0)) != POST_INC)
00799 x = adjust_address (x, SImode, 4);
00800 print_operand_address (stream, XEXP (x, 0));
00801 break;
00802 default:
00803 break;
00804 }
00805 break;
00806 case 'o':
00807 switch (GET_CODE (x))
00808 {
00809 case PLUS: fputs ("add", stream); break;
00810 case MINUS: fputs ("sub", stream); break;
00811 case MULT: fputs ("mul", stream); break;
00812 case DIV: fputs ("div", stream); break;
00813 case EQ: fputs ("eq", stream); break;
00814 case NE: fputs ("ne", stream); break;
00815 case GT: case LT: fputs ("gt", stream); break;
00816 case GE: case LE: fputs ("ge", stream); break;
00817 case GTU: case LTU: fputs ("gtu", stream); break;
00818 case GEU: case LEU: fputs ("geu", stream); break;
00819 default:
00820 break;
00821 }
00822 break;
00823 case 'M':
00824 if (TARGET_SHMEDIA)
00825 {
00826 if (GET_CODE (x) == MEM
00827 && GET_CODE (XEXP (x, 0)) == PLUS
00828 && (GET_CODE (XEXP (XEXP (x, 0), 1)) == REG
00829 || GET_CODE (XEXP (XEXP (x, 0), 1)) == SUBREG))
00830 fputc ('x', stream);
00831 }
00832 else
00833 {
00834 if (GET_CODE (x) == MEM)
00835 {
00836 switch (GET_MODE (x))
00837 {
00838 case QImode: fputs (".b", stream); break;
00839 case HImode: fputs (".w", stream); break;
00840 case SImode: fputs (".l", stream); break;
00841 case SFmode: fputs (".s", stream); break;
00842 case DFmode: fputs (".d", stream); break;
00843 default: gcc_unreachable ();
00844 }
00845 }
00846 }
00847 break;
00848
00849 case 'm':
00850 gcc_assert (GET_CODE (x) == MEM);
00851 x = XEXP (x, 0);
00852
00853 case 'U':
00854 switch (GET_CODE (x))
00855 {
00856 case REG:
00857 case SUBREG:
00858 print_operand (stream, x, 0);
00859 fputs (", 0", stream);
00860 break;
00861
00862 case PLUS:
00863 print_operand (stream, XEXP (x, 0), 0);
00864 fputs (", ", stream);
00865 print_operand (stream, XEXP (x, 1), 0);
00866 break;
00867
00868 default:
00869 gcc_unreachable ();
00870 }
00871 break;
00872
00873 case 'd':
00874 gcc_assert (GET_CODE (x) == REG && GET_MODE (x) == V2SFmode);
00875
00876 fprintf ((stream), "d%s", reg_names[REGNO (x)] + 1);
00877 break;
00878
00879 case 'N':
00880 if (x == CONST0_RTX (GET_MODE (x)))
00881 {
00882 fprintf ((stream), "r63");
00883 break;
00884 }
00885 goto default_output;
00886 case 'u':
00887 if (GET_CODE (x) == CONST_INT)
00888 {
00889 fprintf ((stream), "%u", (unsigned) INTVAL (x) & (0x10000 - 1));
00890 break;
00891 }
00892
00893
00894 default_output:
00895 default:
00896 regno = 0;
00897 mode = GET_MODE (x);
00898
00899 switch (GET_CODE (x))
00900 {
00901 case TRUNCATE:
00902 {
00903 rtx inner = XEXP (x, 0);
00904 int offset = 0;
00905 enum machine_mode inner_mode;
00906
00907
00908 if (GET_CODE (inner) == SUBREG
00909 && (GET_MODE_SIZE (GET_MODE (inner))
00910 == GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner))))
00911 && subreg_lowpart_p (inner))
00912 inner = SUBREG_REG (inner);
00913 if (GET_CODE (inner) == CONST_INT)
00914 {
00915 x = GEN_INT (trunc_int_for_mode (INTVAL (inner), GET_MODE (x)));
00916 goto default_output;
00917 }
00918 inner_mode = GET_MODE (inner);
00919 if (GET_CODE (inner) == SUBREG
00920 && (GET_MODE_SIZE (GET_MODE (inner))
00921 < GET_MODE_SIZE (GET_MODE (SUBREG_REG (inner))))
00922 && GET_CODE (SUBREG_REG (inner)) == REG)
00923 {
00924 offset = subreg_regno_offset (REGNO (SUBREG_REG (inner)),
00925 GET_MODE (SUBREG_REG (inner)),
00926 SUBREG_BYTE (inner),
00927 GET_MODE (inner));
00928 inner = SUBREG_REG (inner);
00929 }
00930 if (GET_CODE (inner) != REG || GET_MODE_SIZE (inner_mode) > 8)
00931 abort ();
00932
00933
00934 regno = REGNO (inner);
00935 regno = (HARD_REGNO_NREGS (regno, inner_mode)
00936 - HARD_REGNO_NREGS (regno, mode))
00937 + offset;
00938 x = inner;
00939 goto reg;
00940 }
00941 case SIGN_EXTEND:
00942 x = XEXP (x, 0);
00943 goto reg;
00944
00945
00946
00947
00948
00949 case IF_THEN_ELSE:
00950 gcc_assert (trapping_target_operand (x, VOIDmode));
00951 x = XEXP (XEXP (x, 2), 0);
00952 goto default_output;
00953 case SUBREG:
00954 gcc_assert (SUBREG_BYTE (x) == 0
00955 && GET_CODE (SUBREG_REG (x)) == REG);
00956
00957 x = SUBREG_REG (x);
00958
00959
00960 reg:
00961 case REG:
00962 regno += REGNO (x);
00963 if (FP_REGISTER_P (regno)
00964 && mode == V16SFmode)
00965 fprintf ((stream), "mtrx%s", reg_names[regno] + 2);
00966 else if (FP_REGISTER_P (REGNO (x))
00967 && mode == V4SFmode)
00968 fprintf ((stream), "fv%s", reg_names[regno] + 2);
00969 else if (GET_CODE (x) == REG
00970 && mode == V2SFmode)
00971 fprintf ((stream), "fp%s", reg_names[regno] + 2);
00972 else if (FP_REGISTER_P (REGNO (x))
00973 && GET_MODE_SIZE (mode) > 4)
00974 fprintf ((stream), "d%s", reg_names[regno] + 1);
00975 else
00976 fputs (reg_names[regno], (stream));
00977 break;
00978
00979 case MEM:
00980 output_address (XEXP (x, 0));
00981 break;
00982
00983 case CONST:
00984 if (TARGET_SHMEDIA
00985 && (GET_CODE (XEXP (x, 0)) == SIGN_EXTEND
00986 || GET_CODE (XEXP (x, 0)) == ZERO_EXTEND)
00987 && (GET_MODE (XEXP (x, 0)) == DImode
00988 || GET_MODE (XEXP (x, 0)) == SImode)
00989 && GET_CODE (XEXP (XEXP (x, 0), 0)) == TRUNCATE
00990 && GET_MODE (XEXP (XEXP (x, 0), 0)) == HImode)
00991 {
00992 rtx val = XEXP (XEXP (XEXP (x, 0), 0), 0);
00993 rtx val2 = val;
00994 bool nested_expr = false;
00995
00996 fputc ('(', stream);
00997 if (GET_CODE (val) == ASHIFTRT)
00998 {
00999 fputc ('(', stream);
01000 val2 = XEXP (val, 0);
01001 }
01002 if (GET_CODE (val2) == CONST
01003 || GET_RTX_CLASS (GET_CODE (val2)) != RTX_OBJ)
01004 {
01005 fputc ('(', stream);
01006 nested_expr = true;
01007 }
01008 output_addr_const (stream, val2);
01009 if (nested_expr)
01010 fputc (')', stream);
01011 if (GET_CODE (val) == ASHIFTRT)
01012 {
01013 fputs (" >> ", stream);
01014 output_addr_const (stream, XEXP (val, 1));
01015 fputc (')', stream);
01016 }
01017 fputs (" & 65535)", stream);
01018 break;
01019 }
01020
01021
01022 default:
01023 if (TARGET_SH1)
01024 fputc ('#', stream);
01025 output_addr_const (stream, x);
01026 break;
01027 }
01028 break;
01029 }
01030 }
01031
01032
01033 static void
01034 force_into (rtx value, rtx target)
01035 {
01036 value = force_operand (value, target);
01037 if (! rtx_equal_p (value, target))
01038 emit_insn (gen_move_insn (target, value));
01039 }
01040
01041
01042
01043
01044
01045
01046
01047
01048 int
01049 expand_block_move (rtx *operands)
01050 {
01051 int align = INTVAL (operands[3]);
01052 int constp = (GET_CODE (operands[2]) == CONST_INT);
01053 int bytes = (constp ? INTVAL (operands[2]) : 0);
01054
01055 if (! constp)
01056 return 0;
01057
01058
01059
01060
01061 if (TARGET_SH4A_ARCH && align < 4
01062 && MEM_ALIGN (operands[0]) >= 32
01063 && can_move_by_pieces (bytes, 32))
01064 {
01065 rtx dest = copy_rtx (operands[0]);
01066 rtx src = copy_rtx (operands[1]);
01067
01068
01069
01070 rtx temp = gen_reg_rtx (SImode);
01071 rtx src_addr = copy_addr_to_reg (XEXP (src, 0));
01072 int copied = 0;
01073
01074 while (copied + 4 <= bytes)
01075 {
01076 rtx to = adjust_address (dest, SImode, copied);
01077 rtx from = adjust_automodify_address (src, SImode, src_addr, copied);
01078
01079 emit_insn (gen_movua (temp, from));
01080 emit_move_insn (src_addr, plus_constant (src_addr, 4));
01081 emit_move_insn (to, temp);
01082 copied += 4;
01083 }
01084
01085 if (copied < bytes)
01086 move_by_pieces (adjust_address (dest, BLKmode, copied),
01087 adjust_automodify_address (src, BLKmode,
01088 src_addr, copied),
01089 bytes - copied, align, 0);
01090
01091 return 1;
01092 }
01093
01094
01095
01096 if (align < 4 || (bytes % 4 != 0))
01097 return 0;
01098
01099 if (TARGET_HARD_SH4)
01100 {
01101 if (bytes < 12)
01102 return 0;
01103 else if (bytes == 12)
01104 {
01105 rtx func_addr_rtx = gen_reg_rtx (Pmode);
01106 rtx r4 = gen_rtx_REG (SImode, 4);
01107 rtx r5 = gen_rtx_REG (SImode, 5);
01108
01109 function_symbol (func_addr_rtx, "__movmemSI12_i4", SFUNC_STATIC);
01110 force_into (XEXP (operands[0], 0), r4);
01111 force_into (XEXP (operands[1], 0), r5);
01112 emit_insn (gen_block_move_real_i4 (func_addr_rtx));
01113 return 1;
01114 }
01115 else if (! TARGET_SMALLCODE)
01116 {
01117 const char *entry_name;
01118 rtx func_addr_rtx = gen_reg_rtx (Pmode);
01119 int dwords;
01120 rtx r4 = gen_rtx_REG (SImode, 4);
01121 rtx r5 = gen_rtx_REG (SImode, 5);
01122 rtx r6 = gen_rtx_REG (SImode, 6);
01123
01124 entry_name = (bytes & 4 ? "__movmem_i4_odd" : "__movmem_i4_even");
01125 function_symbol (func_addr_rtx, entry_name, SFUNC_STATIC);
01126 force_into (XEXP (operands[0], 0), r4);
01127 force_into (XEXP (operands[1], 0), r5);
01128
01129 dwords = bytes >> 3;
01130 emit_insn (gen_move_insn (r6, GEN_INT (dwords - 1)));
01131 emit_insn (gen_block_lump_real_i4 (func_addr_rtx));
01132 return 1;
01133 }
01134 else
01135 return 0;
01136 }
01137 if (bytes < 64)
01138 {
01139 char entry[30];
01140 rtx func_addr_rtx = gen_reg_rtx (Pmode);
01141 rtx r4 = gen_rtx_REG (SImode, 4);
01142 rtx r5 = gen_rtx_REG (SImode, 5);
01143
01144 sprintf (entry, "__movmemSI%d", bytes);
01145 function_symbol (func_addr_rtx, entry, SFUNC_STATIC);
01146 force_into (XEXP (operands[0], 0), r4);
01147 force_into (XEXP (operands[1], 0), r5);
01148 emit_insn (gen_block_move_real (func_addr_rtx));
01149 return 1;
01150 }
01151
01152
01153
01154 if (! TARGET_SMALLCODE)
01155 {
01156 rtx func_addr_rtx = gen_reg_rtx (Pmode);
01157 int final_switch, while_loop;
01158 rtx r4 = gen_rtx_REG (SImode, 4);
01159 rtx r5 = gen_rtx_REG (SImode, 5);
01160 rtx r6 = gen_rtx_REG (SImode, 6);
01161
01162 function_symbol (func_addr_rtx, "__movmem", SFUNC_STATIC);
01163 force_into (XEXP (operands[0], 0), r4);
01164 force_into (XEXP (operands[1], 0), r5);
01165
01166
01167
01168
01169
01170
01171
01172 final_switch = 16 - ((bytes / 4) % 16);
01173 while_loop = ((bytes / 4) / 16 - 1) * 16;
01174 emit_insn (gen_move_insn (r6, GEN_INT (while_loop + final_switch)));
01175 emit_insn (gen_block_lump_real (func_addr_rtx));
01176 return 1;
01177 }
01178
01179 return 0;
01180 }
01181
01182
01183
01184
01185 int
01186 prepare_move_operands (rtx operands[], enum machine_mode mode)
01187 {
01188 if ((mode == SImode || mode == DImode)
01189 && flag_pic
01190 && ! ((mode == Pmode || mode == ptr_mode)
01191 && tls_symbolic_operand (operands[1], Pmode) != 0))
01192 {
01193 rtx temp;
01194 if (SYMBOLIC_CONST_P (operands[1]))
01195 {
01196 if (GET_CODE (operands[0]) == MEM)
01197 operands[1] = force_reg (Pmode, operands[1]);
01198 else if (TARGET_SHMEDIA
01199 && GET_CODE (operands[1]) == LABEL_REF
01200 && target_reg_operand (operands[0], mode))
01201 ;
01202 else
01203 {
01204 temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
01205 operands[1] = legitimize_pic_address (operands[1], mode, temp);
01206 }
01207 }
01208 else if (GET_CODE (operands[1]) == CONST
01209 && GET_CODE (XEXP (operands[1], 0)) == PLUS
01210 && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))
01211 {
01212 temp = no_new_pseudos ? operands[0] : gen_reg_rtx (Pmode);
01213 temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
01214 mode, temp);
01215 operands[1] = expand_binop (mode, add_optab, temp,
01216 XEXP (XEXP (operands[1], 0), 1),
01217 no_new_pseudos ? temp
01218 : gen_reg_rtx (Pmode),
01219 0, OPTAB_LIB_WIDEN);
01220 }
01221 }
01222
01223 if (! reload_in_progress && ! reload_completed)
01224 {
01225
01226 if (! register_operand (operands[0], mode)
01227 && ! sh_register_operand (operands[1], mode))
01228 operands[1] = copy_to_mode_reg (mode, operands[1]);
01229
01230 if (GET_CODE (operands[0]) == MEM && ! memory_operand (operands[0], mode))
01231 {
01232
01233
01234 rtx new = change_address (operands[0], mode, 0);
01235 MEM_COPY_ATTRIBUTES (new, operands[0]);
01236 operands[0] = new;
01237 }
01238
01239
01240
01241
01242
01243 else if (TARGET_SH1
01244 && refers_to_regno_p (R0_REG, R0_REG + 1, operands[1], (rtx *)0)
01245 && GET_CODE (operands[0]) == MEM
01246 && GET_CODE (XEXP (operands[0], 0)) == PLUS
01247 && GET_CODE (XEXP (XEXP (operands[0], 0), 1)) == REG)
01248 operands[1] = copy_to_mode_reg (mode, operands[1]);
01249 }
01250
01251 if (mode == Pmode || mode == ptr_mode)
01252 {
01253 rtx op0, op1, opc;
01254 enum tls_model tls_kind;
01255
01256 op0 = operands[0];
01257 op1 = operands[1];
01258 if (GET_CODE (op1) == CONST
01259 && GET_CODE (XEXP (op1, 0)) == PLUS
01260 && tls_symbolic_operand (XEXP (XEXP (op1, 0), 0), Pmode))
01261 {
01262 opc = XEXP (XEXP (op1, 0), 1);
01263 op1 = XEXP (XEXP (op1, 0), 0);
01264 }
01265 else
01266 opc = NULL_RTX;
01267
01268 if ((tls_kind = tls_symbolic_operand (op1, Pmode)))
01269 {
01270 rtx tga_op1, tga_ret, tmp, tmp2;
01271
01272 switch (tls_kind)
01273 {
01274 case TLS_MODEL_GLOBAL_DYNAMIC:
01275 tga_ret = gen_rtx_REG (Pmode, R0_REG);
01276 emit_call_insn (gen_tls_global_dynamic (tga_ret, op1));
01277 op1 = tga_ret;
01278 break;
01279
01280 case TLS_MODEL_LOCAL_DYNAMIC:
01281 tga_ret = gen_rtx_REG (Pmode, R0_REG);
01282 emit_call_insn (gen_tls_local_dynamic (tga_ret, op1));
01283
01284 tmp = gen_reg_rtx (Pmode);
01285 emit_move_insn (tmp, tga_ret);
01286
01287 if (register_operand (op0, Pmode))
01288 tmp2 = op0;
01289 else
01290 tmp2 = gen_reg_rtx (Pmode);
01291
01292 emit_insn (gen_symDTPOFF2reg (tmp2, op1, tmp));
01293 op1 = tmp2;
01294 break;
01295
01296 case TLS_MODEL_INITIAL_EXEC:
01297 if (! flag_pic)
01298 {
01299
01300
01301
01302 if (flag_schedule_insns)
01303 emit_insn (gen_blockage ());
01304 emit_insn (gen_GOTaddr2picreg ());
01305 emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode,
01306 PIC_REG)));
01307 if (flag_schedule_insns)
01308 emit_insn (gen_blockage ());
01309 }
01310 tga_op1 = no_new_pseudos ? op0 : gen_reg_rtx (Pmode);
01311 tmp = gen_sym2GOTTPOFF (op1);
01312 emit_insn (gen_tls_initial_exec (tga_op1, tmp));
01313 op1 = tga_op1;
01314 break;
01315
01316 case TLS_MODEL_LOCAL_EXEC:
01317 tmp2 = gen_reg_rtx (Pmode);
01318 emit_insn (gen_load_gbr (tmp2));
01319 tmp = gen_reg_rtx (Pmode);
01320 emit_insn (gen_symTPOFF2reg (tmp, op1));
01321
01322 if (register_operand (op0, Pmode))
01323 op1 = op0;
01324 else
01325 op1 = gen_reg_rtx (Pmode);
01326
01327 emit_insn (gen_addsi3 (op1, tmp, tmp2));
01328 break;
01329
01330 default:
01331 gcc_unreachable ();
01332 }
01333 if (opc)
01334 emit_insn (gen_addsi3 (op1, op1, force_reg (SImode, opc)));
01335 operands[1] = op1;
01336 }
01337 }
01338
01339 return 0;
01340 }
01341
01342
01343
01344 rtx
01345 prepare_scc_operands (enum rtx_code code)
01346 {
01347 rtx t_reg = gen_rtx_REG (SImode, T_REG);
01348 enum rtx_code oldcode = code;
01349 enum machine_mode mode;
01350
01351
01352 switch (code)
01353 {
01354 case NE:
01355
01356 gcc_unreachable ();
01357 case LT:
01358 code = GT;
01359 break;
01360 case LE:
01361 code = GE;
01362 break;
01363 case LTU:
01364 code = GTU;
01365 break;
01366 case LEU:
01367 code = GEU;
01368 break;
01369 default:
01370 break;
01371 }
01372 if (code != oldcode)
01373 {
01374 rtx tmp = sh_compare_op0;
01375 sh_compare_op0 = sh_compare_op1;
01376 sh_compare_op1 = tmp;
01377 }
01378
01379 mode = GET_MODE (sh_compare_op0);
01380 if (mode == VOIDmode)
01381 mode = GET_MODE (sh_compare_op1);
01382
01383 sh_compare_op0 = force_reg (mode, sh_compare_op0);
01384 if ((code != EQ && code != NE
01385 && (sh_compare_op1 != const0_rtx
01386 || code == GTU || code == GEU || code == LTU || code == LEU))
01387 || (mode == DImode && sh_compare_op1 != const0_rtx)
01388 || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))
01389 sh_compare_op1 = force_reg (mode, sh_compare_op1);
01390
01391 if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
01392 (mode == SFmode ? emit_sf_insn : emit_df_insn)
01393 (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2,
01394 gen_rtx_SET (VOIDmode, t_reg,
01395 gen_rtx_fmt_ee (code, SImode,
01396 sh_compare_op0, sh_compare_op1)),
01397 gen_rtx_USE (VOIDmode, get_fpscr_rtx ()))));
01398 else
01399 emit_insn (gen_rtx_SET (VOIDmode, t_reg,
01400 gen_rtx_fmt_ee (code, SImode,
01401 sh_compare_op0, sh_compare_op1)));
01402
01403 return t_reg;
01404 }
01405
01406
01407
01408 void
01409 from_compare (rtx *operands, int code)
01410 {
01411 enum machine_mode mode = GET_MODE (sh_compare_op0);
01412 rtx insn;
01413 if (mode == VOIDmode)
01414 mode = GET_MODE (sh_compare_op1);
01415 if (code != EQ
01416 || mode == DImode
01417 || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))
01418 {
01419
01420 sh_compare_op0 = force_reg (mode, sh_compare_op0);
01421 if (sh_compare_op1 != const0_rtx
01422 || code == GTU || code == GEU
01423 || (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT))
01424 sh_compare_op1 = force_reg (mode, sh_compare_op1);
01425 }
01426 if (TARGET_SH2E && GET_MODE_CLASS (mode) == MODE_FLOAT && code == GE)
01427 {
01428 from_compare (operands, GT);
01429 insn = gen_ieee_ccmpeqsf_t (sh_compare_op0, sh_compare_op1);
01430 }
01431 else
01432 insn = gen_rtx_SET (VOIDmode,
01433 gen_rtx_REG (SImode, T_REG),
01434 gen_rtx_fmt_ee (code, SImode,
01435 sh_compare_op0, sh_compare_op1));
01436 if ((TARGET_SH4 || TARGET_SH2A) && GET_MODE_CLASS (mode) == MODE_FLOAT)
01437 {
01438 insn = gen_rtx_PARALLEL (VOIDmode,
01439 gen_rtvec (2, insn,
01440 gen_rtx_USE (VOIDmode, get_fpscr_rtx ())));
01441 (mode == SFmode ? emit_sf_insn : emit_df_insn) (insn);
01442 }
01443 else
01444 emit_insn (insn);
01445 }
01446
01447
01448
01449
01450
01451
01452
01453
01454 const char *
01455 output_movedouble (rtx insn ATTRIBUTE_UNUSED, rtx operands[],
01456 enum machine_mode mode)
01457 {
01458 rtx dst = operands[0];
01459 rtx src = operands[1];
01460
01461 if (GET_CODE (dst) == MEM
01462 && GET_CODE (XEXP (dst, 0)) == PRE_DEC)
01463 return "mov.l %T1,%0\n\tmov.l %1,%0";
01464
01465 if (register_operand (dst, mode)
01466 && register_operand (src, mode))
01467 {
01468 if (REGNO (src) == MACH_REG)
01469 return "sts mach,%S0\n\tsts macl,%R0";
01470
01471
01472
01473
01474 if (REGNO (src) + 1 == REGNO (dst))
01475 return "mov %T1,%T0\n\tmov %1,%0";
01476 else
01477 return "mov %1,%0\n\tmov %T1,%T0";
01478 }
01479 else if (GET_CODE (src) == CONST_INT)
01480 {
01481 if (INTVAL (src) < 0)
01482 output_asm_insn ("mov #-1,%S0", operands);
01483 else
01484 output_asm_insn ("mov #0,%S0", operands);
01485
01486 return "mov %1,%R0";
01487 }
01488 else if (GET_CODE (src) == MEM)
01489 {
01490 int ptrreg = -1;
01491 int dreg = REGNO (dst);
01492 rtx inside = XEXP (src, 0);
01493
01494 switch (GET_CODE (inside))
01495 {
01496 case REG:
01497 ptrreg = REGNO (inside);
01498 break;
01499
01500 case SUBREG:
01501 ptrreg = subreg_regno (inside);
01502 break;
01503
01504 case PLUS:
01505 ptrreg = REGNO (XEXP (inside, 0));
01506
01507
01508
01509
01510
01511
01512
01513 gcc_assert (GET_CODE (XEXP (inside, 1)) != REG);
01514 break;
01515
01516 case LABEL_REF:
01517 return "mov.l %1,%0\n\tmov.l %1+4,%T0";
01518 case POST_INC:
01519 return "mov.l %1,%0\n\tmov.l %1,%T0";
01520 default:
01521 gcc_unreachable ();
01522 }
01523
01524
01525 if (dreg == ptrreg)
01526 return "mov.l %T1,%T0\n\tmov.l %1,%0";
01527 }
01528
01529 return "mov.l %1,%0\n\tmov.l %T1,%T0";
01530 }
01531
01532
01533
01534
01535
01536 static void
01537 print_slot (rtx insn)
01538 {
01539 final_scan_insn (XVECEXP (insn, 0, 1), asm_out_file, optimize, 1, NULL);
01540
01541 INSN_DELETED_P (XVECEXP (insn, 0, 1)) = 1;
01542 }
01543
01544 const char *
01545 output_far_jump (rtx insn, rtx op)
01546 {
01547 struct { rtx lab, reg, op; } this;
01548 rtx braf_base_lab = NULL_RTX;
01549 const char *jump;
01550 int far;
01551 int offset = branch_dest (insn) - INSN_ADDRESSES (INSN_UID (insn));
01552 rtx prev;
01553
01554 this.lab = gen_label_rtx ();
01555
01556 if (TARGET_SH2
01557 && offset >= -32764
01558 && offset - get_attr_length (insn) <= 32766)
01559 {
01560 far = 0;
01561 jump = "mov.w %O0,%1; braf %1";
01562 }
01563 else
01564 {
01565 far = 1;
01566 if (flag_pic)
01567 {
01568 if (TARGET_SH2)
01569 jump = "mov.l %O0,%1; braf %1";
01570 else
01571 jump = "mov.l r0,@-r15; mova %O0,r0; mov.l @r0,%1; add r0,%1; mov.l @r15+,r0; jmp @%1";
01572 }
01573 else
01574 jump = "mov.l %O0,%1; jmp @%1";
01575 }
01576
01577 if (GET_CODE ((prev = prev_nonnote_insn (insn))) == INSN
01578 && INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch)
01579 {
01580 this.reg = SET_DEST (XVECEXP (PATTERN (prev), 0, 0));
01581 if (REGNO (this.reg) == R0_REG && flag_pic && ! TARGET_SH2)
01582 jump = "mov.l r1,@-r15; mova %O0,r0; mov.l @r0,r1; add r1,r0; mov.l @r15+,r1; jmp @%1";
01583 output_asm_insn (jump, &this.lab);
01584 if (dbr_sequence_length ())
01585 print_slot (final_sequence);
01586 else
01587 output_asm_insn ("nop", 0);
01588 }
01589 else
01590 {
01591
01592 if (dbr_sequence_length ())
01593 print_slot (final_sequence);
01594
01595 this.reg = gen_rtx_REG (SImode, 13);
01596
01597
01598
01599
01600 if (TARGET_SH5)
01601 output_asm_insn ("lds r13, macl", 0);
01602 else
01603 output_asm_insn ("mov.l r13,@-r15", 0);
01604 output_asm_insn (jump, &this.lab);
01605 if (TARGET_SH5)
01606 output_asm_insn ("sts macl, r13", 0);
01607 else
01608 output_asm_insn ("mov.l @r15+,r13", 0);
01609 }
01610 if (far && flag_pic && TARGET_SH2)
01611 {
01612 braf_base_lab = gen_label_rtx ();
01613 (*targetm.asm_out.internal_label) (asm_out_file, "L",
01614 CODE_LABEL_NUMBER (braf_base_lab));
01615 }
01616 if (far)
01617 output_asm_insn (".align 2", 0);
01618 (*targetm.asm_out.internal_label) (asm_out_file, "L", CODE_LABEL_NUMBER (this.lab));
01619 this.op = op;
01620 if (far && flag_pic)
01621 {
01622 if (TARGET_SH2)
01623 this.lab = braf_base_lab;
01624 output_asm_insn (".long %O2-%O0", &this.lab);
01625 }
01626 else
01627 output_asm_insn (far ? ".long %O2" : ".word %O2-%O0", &this.lab);
01628 return "";
01629 }
01630
01631
01632
01633
01634 static int lf = 100;
01635
01636
01637
01638 const char *
01639 output_branch (int logic, rtx insn, rtx *operands)
01640 {
01641 switch (get_attr_length (insn))
01642 {
01643 case 6:
01644
01645
01646
01647
01648
01649
01650
01651
01652 if (! TARGET_RELAX)
01653 {
01654 int label = lf++;
01655
01656 rtx op0 = operands[0];
01657
01658
01659
01660
01661
01662 if (final_sequence
01663 && ! INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))
01664 && get_attr_length (XVECEXP (final_sequence, 0, 1)))
01665 {
01666 asm_fprintf (asm_out_file, "\tb%s%ss\t%LLF%d\n", logic ? "f" : "t",
01667 ASSEMBLER_DIALECT ? "/" : ".", label);
01668 print_slot (final_sequence);
01669 }
01670 else
01671 asm_fprintf (asm_out_file, "\tb%s\t%LLF%d\n", logic ? "f" : "t", label);
01672
01673 output_asm_insn ("bra\t%l0", &op0);
01674 fprintf (asm_out_file, "\tnop\n");
01675 (*targetm.asm_out.internal_label) (asm_out_file, "LF", label);
01676
01677 return "";
01678 }
01679
01680
01681 case 2:
01682 return logic ? "bt%.\t%l0" : "bf%.\t%l0";
01683
01684
01685
01686 case 8:
01687 if (! TARGET_RELAX)
01688 {
01689 int label = lf++;
01690
01691 gcc_assert (!final_sequence
01692 || !(INSN_ANNULLED_BRANCH_P
01693 (XVECEXP (final_sequence, 0, 0))));
01694 asm_fprintf (asm_out_file, "b%s%ss\t%LLF%d\n",
01695 logic ? "f" : "t",
01696 ASSEMBLER_DIALECT ? "/" : ".", label);
01697 fprintf (asm_out_file, "\tnop\n");
01698 output_asm_insn ("bra\t%l0", operands);
01699 fprintf (asm_out_file, "\tnop\n");
01700 (*targetm.asm_out.internal_label) (asm_out_file, "LF", label);
01701
01702 return "";
01703 }
01704
01705 case 4:
01706 {
01707 char buffer[10];
01708
01709 sprintf (buffer, "b%s%ss\t%%l0",
01710 logic ? "t" : "f",
01711 ASSEMBLER_DIALECT ? "/" : ".");
01712 output_asm_insn (buffer, &operands[0]);
01713 return "nop";
01714 }
01715
01716 default:
01717
01718
01719
01720 gcc_unreachable ();
01721 }
01722 }
01723
01724 const char *
01725 output_branchy_insn (enum rtx_code code, const char *template,
01726 rtx insn, rtx *operands)
01727 {
01728 rtx next_insn = NEXT_INSN (insn);
01729
01730 if (next_insn && GET_CODE (next_insn) == JUMP_INSN && condjump_p (next_insn))
01731 {
01732 rtx src = SET_SRC (PATTERN (next_insn));
01733 if (GET_CODE (src) == IF_THEN_ELSE && GET_CODE (XEXP (src, 0)) != code)
01734 {
01735
01736 operands[9] = gen_label_rtx ();
01737 emit_label_after (operands[9], next_insn);
01738 INSN_ADDRESSES_NEW (operands[9],
01739 INSN_ADDRESSES (INSN_UID (next_insn))
01740 + get_attr_length (next_insn));
01741 return template;
01742 }
01743 else
01744 {
01745 int offset = (branch_dest (next_insn)
01746 - INSN_ADDRESSES (INSN_UID (next_insn)) + 4);
01747 if (offset >= -252 && offset <= 258)
01748 {
01749 if (GET_CODE (src) == IF_THEN_ELSE)
01750
01751 src = XEXP (src, 1);
01752 operands[9] = src;
01753 return template;
01754 }
01755 }
01756 }
01757 operands[9] = gen_label_rtx ();
01758 emit_label_after (operands[9], insn);
01759 INSN_ADDRESSES_NEW (operands[9],
01760 INSN_ADDRESSES (INSN_UID (insn))
01761 + get_attr_length (insn));
01762 return template;
01763 }
01764
01765 const char *
01766 output_ieee_ccmpeq (rtx insn, rtx *operands)
01767 {
01768 return output_branchy_insn (NE, "bt\t%l9\n\tfcmp/eq\t%1,%0",
01769 insn, operands);
01770 }
01771
01772
01773
01774 static void
01775 sh_file_start (void)
01776 {
01777 default_file_start ();
01778
01779 #ifdef SYMBIAN
01780
01781 fputs ("\t.section .directive, \"SM\", @progbits, 1\n", asm_out_file);
01782 fputs ("\t.asciz \"#<SYMEDIT>#\\n\"\n", asm_out_file);
01783 #endif
01784
01785 if (TARGET_ELF)
01786
01787
01788
01789
01790
01791
01792
01793 fprintf (asm_out_file, "%s\n", TEXT_SECTION_ASM_OP);
01794 else
01795
01796
01797 switch_to_section (data_section);
01798
01799 if (TARGET_LITTLE_ENDIAN)
01800 fputs ("\t.little\n", asm_out_file);
01801
01802 if (!TARGET_ELF)
01803 {
01804 if (TARGET_SHCOMPACT)
01805 fputs ("\t.mode\tSHcompact\n", asm_out_file);
01806 else if (TARGET_SHMEDIA)
01807 fprintf (asm_out_file, "\t.mode\tSHmedia\n\t.abi\t%i\n",
01808 TARGET_SHMEDIA64 ? 64 : 32);
01809 }
01810 }
01811
01812
01813
01814 static bool
01815 unspec_caller_rtx_p (rtx pat)
01816 {
01817 switch (GET_CODE (pat))
01818 {
01819 case CONST:
01820 return unspec_caller_rtx_p (XEXP (pat, 0));
01821 case PLUS:
01822 case MINUS:
01823 if (unspec_caller_rtx_p (XEXP (pat, 0)))
01824 return true;
01825 return unspec_caller_rtx_p (XEXP (pat, 1));
01826 case UNSPEC:
01827 if (XINT (pat, 1) == UNSPEC_CALLER)
01828 return true;
01829 default:
01830 break;
01831 }
01832
01833 return false;
01834 }
01835
01836
01837
01838
01839 static bool
01840 sh_cannot_copy_insn_p (rtx insn)
01841 {
01842 rtx pat;
01843
01844 if (!reload_completed || !flag_pic)
01845 return false;
01846
01847 if (GET_CODE (insn) != INSN)
01848 return false;
01849 if (asm_noperands (insn) >= 0)
01850 return false;
01851
01852 pat = PATTERN (insn);
01853 if (GET_CODE (pat) != SET)
01854 return false;
01855 pat = SET_SRC (pat);
01856
01857 if (unspec_caller_rtx_p (pat))
01858 return true;
01859
01860 return false;
01861 }
01862
01863
01864 static const char ashiftrt_insns[] =
01865 { 0,1,2,3,4,5,8,8,8,8,8,8,8,8,8,8,2,3,4,5,8,8,8,8,8,8,8,8,8,8,8,2};
01866
01867
01868 static const char shift_insns[] =
01869 { 0,1,1,2,2,3,3,4,1,2,2,3,3,4,3,3,1,2,2,3,3,4,3,3,2,3,3,4,4,4,3,3};
01870
01871
01872
01873
01874
01875 static const short shift_amounts[32][5] = {
01876 {0}, {1}, {2}, {2, 1},
01877 {2, 2}, {2, 1, 2}, {2, 2, 2}, {2, 2, 1, 2},
01878 {8}, {8, 1}, {8, 2}, {8, 1, 2},
01879 {8, 2, 2}, {8, 2, 1, 2}, {8, -2, 8}, {8, -1, 8},
01880 {16}, {16, 1}, {16, 2}, {16, 1, 2},
01881 {16, 2, 2}, {16, 2, 1, 2}, {16, -2, 8}, {16, -1, 8},
01882 {16, 8}, {16, 1, 8}, {16, 8, 2}, {16, 8, 1, 2},
01883 {16, 8, 2, 2}, {16, -1, -2, 16}, {16, -2, 16}, {16, -1, 16}};
01884
01885
01886
01887
01888
01889 static const char ext_shift_insns[] =
01890 { 0,1,1,2,2,3,2,2,1,2,2,3,3,3,2,2,1,2,2,3,3,4,3,3,2,3,3,4,4,4,3,3};
01891
01892 static const short ext_shift_amounts[32][4] = {
01893 {0}, {1}, {2}, {2, 1},
01894 {2, 2}, {2, 1, 2}, {8, -2}, {8, -1},
01895 {8}, {8, 1}, {8, 2}, {8, 1, 2},
01896 {8, 2, 2}, {16, -2, -1}, {16, -2}, {16, -1},
01897 {16}, {16, 1}, {16, 2}, {16, 1, 2},
01898 {16, 2, 2}, {16, 2, 1, 2}, {16, -2, 8}, {16, -1, 8},
01899 {16, 8}, {16, 1, 8}, {16, 8, 2}, {16, 8, 1, 2},
01900 {16, 8, 2, 2}, {16, -1, -2, 16}, {16, -2, 16}, {16, -1, 16}};
01901
01902
01903
01904
01905 #define EXT_SHIFT_SIGNED(n) (((n) | 8) == 15)
01906
01907
01908
01909
01910 int
01911 shift_insns_rtx (rtx insn)
01912 {
01913 rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
01914 int shift_count = INTVAL (XEXP (set_src, 1));
01915 enum rtx_code shift_code = GET_CODE (set_src);
01916
01917 switch (shift_code)
01918 {
01919 case ASHIFTRT:
01920 return ashiftrt_insns[shift_count];
01921 case LSHIFTRT:
01922 case ASHIFT:
01923 return shift_insns[shift_count];
01924 default:
01925 gcc_unreachable ();
01926 }
01927 }
01928
01929
01930
01931 static inline int
01932 shiftcosts (rtx x)
01933 {
01934 int value;
01935
01936 if (TARGET_SHMEDIA)
01937 return 1;
01938
01939 if (GET_MODE_SIZE (GET_MODE (x)) > UNITS_PER_WORD)
01940 {
01941 if (GET_MODE (x) == DImode
01942 && GET_CODE (XEXP (x, 1)) == CONST_INT
01943 && INTVAL (XEXP (x, 1)) == 1)
01944 return 2;
01945
01946
01947 return MAX_COST;
01948 }
01949
01950 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
01951 return SH_DYNAMIC_SHIFT_COST;
01952
01953 value = INTVAL (XEXP (x, 1));
01954
01955
01956 if (GET_CODE (x) == ASHIFTRT)
01957 {
01958 int cost = ashiftrt_insns[value];
01959
01960 if (cost > 1 + SH_DYNAMIC_SHIFT_COST)
01961 cost = 1 + SH_DYNAMIC_SHIFT_COST;
01962 return cost;
01963 }
01964 else
01965 return shift_insns[value];
01966 }
01967
01968
01969
01970 static inline int
01971 andcosts (rtx x)
01972 {
01973 int i;
01974
01975
01976 if (GET_CODE (XEXP (x, 1)) != CONST_INT)
01977 return 1;
01978
01979 i = INTVAL (XEXP (x, 1));
01980
01981 if (TARGET_SHMEDIA)
01982 {
01983 if (GET_CODE (XEXP (x, 1)) == CONST_INT
01984 && (CONST_OK_FOR_I10 (INTVAL (XEXP (x, 1)))
01985 || CONST_OK_FOR_J16 (INTVAL (XEXP (x, 1)))))
01986 return 1;
01987 else
01988 return 1 + rtx_cost (XEXP (x, 1), AND);
01989 }
01990
01991
01992 if (i == 0xff || i == 0xffff)
01993 return 1;
01994
01995
01996 if (CONST_OK_FOR_K08 (i))
01997 return 2;
01998
01999
02000 if (CONST_OK_FOR_I08 (i))
02001 return 2;
02002
02003
02004 return 3;
02005 }
02006
02007
02008
02009 static inline int
02010 addsubcosts (rtx x)
02011 {
02012
02013 if (GET_CODE (XEXP (x, 1)) == REG
02014 || GET_CODE (XEXP (x, 1)) == SUBREG)
02015 return 1;
02016
02017
02018 if (GET_CODE (XEXP (x, 1)) == CONST_INT
02019 && CONST_OK_FOR_ADD (INTVAL (XEXP (x, 1))))
02020 return 1;
02021
02022 if (TARGET_SHMEDIA)
02023 switch (GET_CODE (XEXP (x, 1)))
02024 {
02025 case CONST:
02026 case LABEL_REF:
02027 case SYMBOL_REF:
02028 return TARGET_SHMEDIA64 ? 5 : 3;
02029
02030 case CONST_INT:
02031 if (CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1))))
02032 return 2;
02033 else if (CONST_OK_FOR_I16 (INTVAL (XEXP (x, 1)) >> 16))
02034 return 3;
02035 else if (CONST_OK_FOR_I16 ((INTVAL (XEXP (x, 1)) >> 16) >> 16))
02036 return 4;
02037
02038
02039 default:
02040 return 5;
02041 }
02042
02043
02044
02045 return 3;
02046 }
02047
02048
02049 static inline int
02050 multcosts (rtx x ATTRIBUTE_UNUSED)
02051 {
02052 if (sh_multcost >= 0)
02053 return sh_multcost;
02054 if (TARGET_SHMEDIA)
02055
02056
02057
02058
02059
02060
02061
02062 return TARGET_SMALLCODE ? 2 : 3;
02063
02064 if (TARGET_SH2)
02065 {
02066
02067
02068
02069 if (TARGET_SMALLCODE)
02070 return 2;
02071 return 3;
02072 }
02073
02074
02075
02076 if (TARGET_SMALLCODE)
02077 return 5;
02078
02079
02080 return 20;
02081 }
02082
02083
02084
02085
02086
02087 static bool
02088 sh_rtx_costs (rtx x, int code, int outer_code, int *total)
02089 {
02090 switch (code)
02091 {
02092 case CONST_INT:
02093 if (TARGET_SHMEDIA)
02094 {
02095 if (INTVAL (x) == 0)
02096 *total = 0;
02097 else if (outer_code == AND && and_operand ((x), DImode))
02098 *total = 0;
02099 else if ((outer_code == IOR || outer_code == XOR
02100 || outer_code == PLUS)
02101 && CONST_OK_FOR_I10 (INTVAL (x)))
02102 *total = 0;
02103 else if (CONST_OK_FOR_I16 (INTVAL (x)))
02104 *total = COSTS_N_INSNS (outer_code != SET);
02105 else if (CONST_OK_FOR_I16 (INTVAL (x) >> 16))
02106 *total = COSTS_N_INSNS ((outer_code != SET) + 1);
02107 else if (CONST_OK_FOR_I16 ((INTVAL (x) >> 16) >> 16))
02108 *total = COSTS_N_INSNS ((outer_code != SET) + 2);
02109 else
02110 *total = COSTS_N_INSNS ((outer_code != SET) + 3);
02111 return true;
02112 }
02113 if (CONST_OK_FOR_I08 (INTVAL (x)))
02114 *total = 0;
02115 else if ((outer_code == AND || outer_code == IOR || outer_code == XOR)
02116 && CONST_OK_FOR_K08 (INTVAL (x)))
02117 *total = 1;
02118 else
02119 *total = 8;
02120 return true;
02121
02122 case CONST:
02123 case LABEL_REF:
02124 case SYMBOL_REF:
02125 if (TARGET_SHMEDIA64)
02126 *total = COSTS_N_INSNS (4);
02127 else if (TARGET_SHMEDIA32)
02128 *total = COSTS_N_INSNS (2);
02129 else
02130 *total = 5;
02131 return true;
02132
02133 case CONST_DOUBLE:
02134 if (TARGET_SHMEDIA)
02135 *total = COSTS_N_INSNS (4);
02136 else
02137 *total = 10;
02138 return true;
02139 case CONST_VECTOR:
02140 if (x == CONST0_RTX (GET_MODE (x)))
02141 *total = 0;
02142 else if (sh_1el_vec (x, VOIDmode))
02143 *total = outer_code != SET;
02144 if (sh_rep_vec (x, VOIDmode))
02145 *total = ((GET_MODE_UNIT_SIZE (GET_MODE (x)) + 3) / 4
02146 + (outer_code != SET));
02147 *total = COSTS_N_INSNS (3) + (outer_code != SET);
02148 return true;
02149
02150 case PLUS:
02151 case MINUS:
02152 *total = COSTS_N_INSNS (addsubcosts (x));
02153 return true;
02154
02155 case AND:
02156 *total = COSTS_N_INSNS (andcosts (x));
02157 return true;
02158
02159 case MULT:
02160 *total = COSTS_N_INSNS (multcosts (x));
02161 return true;
02162
02163 case ASHIFT:
02164 case ASHIFTRT:
02165 case LSHIFTRT:
02166 *total = COSTS_N_INSNS (shiftcosts (x));
02167 return true;
02168
02169 case DIV:
02170 case UDIV:
02171 case MOD:
02172 case UMOD:
02173 *total = COSTS_N_INSNS (20);
02174 return true;
02175
02176 case PARALLEL:
02177 if (sh_1el_vec (x, VOIDmode))
02178 *total = outer_code != SET;
02179 if (sh_rep_vec (x, VOIDmode))
02180 *total = ((GET_MODE_UNIT_SIZE (GET_MODE (x)) + 3) / 4
02181 + (outer_code != SET));
02182 *total = COSTS_N_INSNS (3) + (outer_code != SET);
02183 return true;
02184
02185 case FLOAT:
02186 case FIX:
02187 *total = 100;
02188 return true;
02189
02190 default:
02191 return false;
02192 }
02193 }
02194
02195
02196
02197
02198
02199 static int
02200 sh_address_cost (rtx X)
02201 {
02202 return (GET_CODE (X) == PLUS
02203 && ! CONSTANT_P (XEXP (X, 1))
02204 && ! TARGET_SHMEDIA ? 1 : 0);
02205 }
02206
02207
02208
02209 void
02210 gen_ashift (int type, int n, rtx reg)
02211 {
02212
02213 if (n < 0)
02214 {
02215 if (type == ASHIFT)
02216 type = LSHIFTRT;
02217 else
02218 type = ASHIFT;
02219 n = -n;
02220 }
02221
02222 switch (type)
02223 {
02224 case ASHIFTRT:
02225 emit_insn (gen_ashrsi3_k (reg, reg, GEN_INT (n)));
02226 break;
02227 case LSHIFTRT:
02228 if (n == 1)
02229 emit_insn (gen_lshrsi3_m (reg, reg, GEN_INT (n)));
02230 else
02231 emit_insn (gen_lshrsi3_k (reg, reg, GEN_INT (n)));
02232 break;
02233 case ASHIFT:
02234 emit_insn (gen_ashlsi3_std (reg, reg, GEN_INT (n)));
02235 break;
02236 }
02237 }
02238
02239
02240
02241 void
02242 gen_ashift_hi (int type, int n, rtx reg)
02243 {
02244
02245 if (n < 0)
02246 {
02247 if (type == ASHIFT)
02248 type = LSHIFTRT;
02249 else
02250 type = ASHIFT;
02251 n = -n;
02252 }
02253
02254 switch (type)
02255 {
02256 case ASHIFTRT:
02257 case LSHIFTRT:
02258
02259
02260
02261
02262
02263 {
02264 int offset = 0;
02265 if (GET_CODE (reg) == SUBREG)
02266 {
02267 offset = SUBREG_BYTE (reg);
02268 reg = SUBREG_REG (reg);
02269 }
02270 gen_ashift (type, n, gen_rtx_SUBREG (SImode, reg, offset));
02271 break;
02272 }
02273 case ASHIFT:
02274 emit_insn (gen_ashlhi3_k (reg, reg, GEN_INT (n)));
02275 break;
02276 }
02277 }
02278
02279
02280
02281
02282 void
02283 gen_shifty_op (int code, rtx *operands)
02284 {
02285 int value = INTVAL (operands[2]);
02286 int max, i;
02287
02288
02289 value = value & 0x1f;
02290
02291 if (value == 31)
02292 {
02293 if (code == LSHIFTRT)
02294 {
02295 emit_insn (gen_rotlsi3_1 (operands[0], operands[0]));
02296 emit_insn (gen_movt (operands[0]));
02297 return;
02298 }
02299 else if (code == ASHIFT)
02300 {
02301
02302
02303 if (GET_CODE (operands[0]) == REG && REGNO (operands[0]) == 0)
02304 {
02305 emit_insn (gen_andsi3 (operands[0], operands[0], const1_rtx));
02306 emit_insn (gen_rotlsi3_31 (operands[0], operands[0]));
02307 return;
02308 }
02309 }
02310 }
02311 else if (value == 0)
02312 {
02313
02314
02315
02316 emit_insn (gen_rtx_SET (VOIDmode, operands[0], operands[0]));
02317 return;
02318 }
02319
02320 max = shift_insns[value];
02321 for (i = 0; i < max; i++)
02322 gen_ashift (code, shift_amounts[value][i], operands[0]);
02323 }
02324
02325
02326
02327
02328 void
02329 gen_shifty_hi_op (int code, rtx *operands)
02330 {
02331 int value = INTVAL (operands[2]);
02332 int max, i;
02333 void (*gen_fun) (int, int, rtx);
02334
02335
02336
02337 value &= 31;
02338 if (value == 0)
02339 {
02340 emit_insn (gen_nop ());
02341 return;
02342 }
02343
02344 gen_fun = GET_MODE (operands[0]) == HImode ? gen_ashift_hi : gen_ashift;
02345 if (code == ASHIFT)
02346 {
02347 max = ext_shift_insns[value];
02348 for (i = 0; i < max; i++)
02349 gen_fun (code, ext_shift_amounts[value][i], operands[0]);
02350 }
02351 else
02352
02353
02354 for (i = ext_shift_insns[value] - 1; i >= 0; i--)
02355 gen_fun (code, ext_shift_amounts[value][i], operands[0]);
02356 }
02357
02358
02359
02360
02361
02362 int
02363 expand_ashiftrt (rtx *operands)
02364 {
02365 rtx wrk;
02366 char func[18];
02367 int value;
02368
02369 if (TARGET_SH3)
02370 {
02371 if (GET_CODE (operands[2]) != CONST_INT)
02372 {
02373 rtx count = copy_to_mode_reg (SImode, operands[2]);
02374 emit_insn (gen_negsi2 (count, count));
02375 emit_insn (gen_ashrsi3_d (operands[0], operands[1], count));
02376 return 1;
02377 }
02378 else if (ashiftrt_insns[INTVAL (operands[2]) & 31]
02379 > 1 + SH_DYNAMIC_SHIFT_COST)
02380 {
02381 rtx count
02382 = force_reg (SImode, GEN_INT (- (INTVAL (operands[2]) & 31)));
02383 emit_insn (gen_ashrsi3_d (operands[0], operands[1], count));
02384 return 1;
02385 }
02386 }
02387 if (GET_CODE (operands[2]) != CONST_INT)
02388 return 0;
02389
02390 value = INTVAL (operands[2]) & 31;
02391
02392 if (value == 31)
02393 {
02394
02395
02396
02397 if (currently_expanding_to_rtl)
02398 {
02399 emit_insn (gen_cmpgtsi_t (force_reg (SImode, CONST0_RTX (SImode)),
02400 operands[1]));
02401 emit_insn (gen_mov_neg_si_t (operands[0]));
02402 return 1;
02403 }
02404 emit_insn (gen_ashrsi2_31 (operands[0], operands[1]));
02405 return 1;
02406 }
02407 else if (value >= 16 && value <= 19)
02408 {
02409 wrk = gen_reg_rtx (SImode);
02410 emit_insn (gen_ashrsi2_16 (wrk, operands[1]));
02411 value -= 16;
02412 while (value--)
02413 gen_ashift (ASHIFTRT, 1, wrk);
02414 emit_move_insn (operands[0], wrk);
02415 return 1;
02416 }
02417
02418 else if (value <= 5)
02419 {
02420 wrk = gen_reg_rtx (SImode);
02421 emit_move_insn (wrk, operands[1]);
02422 while (value--)
02423 gen_ashift (ASHIFTRT, 1, wrk);
02424 emit_move_insn (operands[0], wrk);
02425 return 1;
02426 }
02427
02428 wrk = gen_reg_rtx (Pmode);
02429
02430
02431 emit_move_insn (gen_rtx_REG (SImode, 4), operands[1]);
02432 sprintf (func, "__ashiftrt_r4_%d", value);
02433 function_symbol (wrk, func, SFUNC_STATIC);
02434 emit_insn (gen_ashrsi3_n (GEN_INT (value), wrk));
02435 emit_move_insn (operands[0], gen_rtx_REG (SImode, 4));
02436 return 1;
02437 }
02438
02439 int
02440 sh_dynamicalize_shift_p (rtx count)
02441 {
02442 return shift_insns[INTVAL (count)] > 1 + SH_DYNAMIC_SHIFT_COST;
02443 }
02444
02445
02446
02447
02448
02449
02450
02451
02452
02453
02454
02455
02456
02457
02458
02459
02460
02461
02462
02463
02464
02465 int
02466 shl_and_kind (rtx left_rtx, rtx mask_rtx, int *attrp)
02467 {
02468 unsigned HOST_WIDE_INT mask, lsb, mask2, lsb2;
02469 int left = INTVAL (left_rtx), right;
02470 int best = 0;
02471 int cost, best_cost = 10000;
02472 int best_right = 0, best_len = 0;
02473 int i;
02474 int can_ext;
02475
02476 if (left < 0 || left > 31)
02477 return 0;
02478 if (GET_CODE (mask_rtx) == CONST_INT)
02479 mask = (unsigned HOST_WIDE_INT) INTVAL (mask_rtx) >> left;
02480 else
02481 mask = (unsigned HOST_WIDE_INT) GET_MODE_MASK (SImode) >> left;
02482
02483 lsb = ((mask ^ (mask - 1)) >> 1) + 1;
02484 right = exact_log2 (lsb);
02485 mask2 = ~(mask + lsb - 1);
02486 lsb2 = ((mask2 ^ (mask2 - 1)) >> 1) + 1;
02487
02488 if (! mask2)
02489 best_cost = shift_insns[right] + shift_insns[right + left];
02490
02491 else if (! right && mask2 == ~(lsb2 - 1))
02492 {
02493 int late_right = exact_log2 (lsb2);
02494 best_cost = shift_insns[left + late_right] + shift_insns[late_right];
02495 }
02496
02497 if (mask2 == ~(lsb2 - 1))
02498 {
02499 int width, first;
02500
02501 for (width = 8; width <= 16; width += 8)
02502 {
02503
02504 if (lsb2 == (unsigned HOST_WIDE_INT) 1 << width)
02505 {
02506 cost
02507 = 1 + ext_shift_insns[right] + ext_shift_insns[left + right];
02508 if (cost < best_cost)
02509 {
02510 best = 1;
02511 best_cost = cost;
02512 best_right = right;
02513 best_len = cost;
02514 if (attrp)
02515 attrp[2] = -1;
02516 }
02517 continue;
02518 }
02519
02520
02521
02522
02523 first = width - exact_log2 (lsb2) + right;
02524 if (first >= 0 && right + left - first >= 0)
02525 {
02526 cost = ext_shift_insns[right] + ext_shift_insns[first] + 1
02527 + ext_shift_insns[right + left - first];
02528 if (cost < best_cost)
02529 {
02530 best = 1;
02531 best_cost = cost;
02532 best_right = right;
02533 best_len = cost;
02534 if (attrp)
02535 attrp[2] = first;
02536 }
02537 }
02538 }
02539 }
02540
02541 for (i = 0; i <= 2; i++)
02542 {
02543 if (i > right)
02544 break;
02545 if (! CONST_OK_FOR_K08 (mask >> i))
02546 continue;
02547 cost = (i != 0) + 2 + ext_shift_insns[left + i];
02548 if (cost < best_cost)
02549 {
02550 best = 2;
02551 best_cost = cost;
02552 best_right = i;
02553 best_len = cost - 1;
02554 }
02555 }
02556
02557 can_ext = ((mask << left) & ((unsigned HOST_WIDE_INT) 3 << 30)) == 0;
02558 for (i = 0; i <= 2; i++)
02559 {
02560 if (i > right)
02561 break;
02562 cost = (i != 0) + (CONST_OK_FOR_I08 (mask >> i) ? 2 : 3)
02563 + (can_ext ? ext_shift_insns : shift_insns)[left + i];
02564 if (cost < best_cost)
02565 {
02566 best = 4 - can_ext;
02567 best_cost = cost;
02568 best_right = i;
02569 best_len = cost - 1 - ! CONST_OK_FOR_I08 (mask >> i);
02570 }
02571 }
02572
02573 if (attrp)
02574 {
02575 attrp[0] = best_right;
02576 attrp[1] = best_len;
02577 }
02578 return best;
02579 }
02580
02581
02582
02583 int
02584 shl_and_length (rtx insn)
02585 {
02586 rtx set_src, left_rtx, mask_rtx;
02587 int attributes[3];
02588
02589 set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
02590 left_rtx = XEXP (XEXP (set_src, 0), 1);
02591 mask_rtx = XEXP (set_src, 1);
02592 shl_and_kind (left_rtx, mask_rtx, attributes);
02593 return attributes[1];
02594 }
02595
02596
02597
02598 int
02599 shl_and_scr_length (rtx insn)
02600 {
02601 rtx set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
02602 int len = shift_insns[INTVAL (XEXP (set_src, 1))];
02603 rtx op = XEXP (set_src, 0);
02604 len += shift_insns[INTVAL (XEXP (op, 1))] + 1;
02605 op = XEXP (XEXP (op, 0), 0);
02606 return len + shift_insns[INTVAL (XEXP (op, 1))];
02607 }
02608
02609
02610
02611
02612 int
02613 gen_shl_and (rtx dest, rtx left_rtx, rtx mask_rtx, rtx source)
02614 {
02615 int attributes[3];
02616 unsigned HOST_WIDE_INT mask;
02617 int kind = shl_and_kind (left_rtx, mask_rtx, attributes);
02618 int right, total_shift;
02619 void (*shift_gen_fun) (int, rtx *) = gen_shifty_hi_op;
02620
02621 right = attributes[0];
02622 total_shift = INTVAL (left_rtx) + right;
02623 mask = (unsigned HOST_WIDE_INT) INTVAL (mask_rtx) >> total_shift;
02624 switch (kind)
02625 {
02626 default:
02627 return -1;
02628 case 1:
02629 {
02630 int first = attributes[2];
02631 rtx operands[3];
02632
02633 if (first < 0)
02634 {
02635 emit_insn ((mask << right) <= 0xff
02636 ? gen_zero_extendqisi2 (dest,
02637 gen_lowpart (QImode, source))
02638 : gen_zero_extendhisi2 (dest,
02639 gen_lowpart (HImode, source)));
02640 source = dest;
02641 }
02642 if (source != dest)
02643 emit_insn (gen_movsi (dest, source));
02644 operands[0] = dest;
02645 if (right)
02646 {
02647 operands[2] = GEN_INT (right);
02648 gen_shifty_hi_op (LSHIFTRT, operands);
02649 }
02650 if (first > 0)
02651 {
02652 operands[2] = GEN_INT (first);
02653 gen_shifty_hi_op (ASHIFT, operands);
02654 total_shift -= first;
02655 mask <<= first;
02656 }
02657 if (first >= 0)
02658 emit_insn (mask <= 0xff
02659 ? gen_zero_extendqisi2 (dest, gen_lowpart (QImode, dest))
02660 : gen_zero_extendhisi2 (dest, gen_lowpart (HImode, dest)));
02661 if (total_shift > 0)
02662 {
02663 operands[2] = GEN_INT (total_shift);
02664 gen_shifty_hi_op (ASHIFT, operands);
02665 }
02666 break;
02667 }
02668 case 4:
02669 shift_gen_fun = gen_shifty_op;
02670 case 3:
02671
02672
02673
02674 if (mask & ((HOST_WIDE_INT) 1 << (31 - total_shift)))
02675 mask |= (HOST_WIDE_INT) ~0 << (31 - total_shift);
02676 case 2:
02677
02678
02679 if (currently_expanding_to_rtl
02680 || reload_in_progress || reload_completed)
02681 {
02682 rtx operands[3];
02683
02684
02685
02686 gcc_assert (kind <= 2);
02687 if (right)
02688 {
02689 emit_insn (gen_lshrsi3 (dest, source, GEN_INT (right)));
02690 source = dest;
02691 }
02692 emit_insn (gen_andsi3 (dest, source, GEN_INT (mask)));
02693 if (total_shift)
02694 {
02695 operands[0] = dest;
02696 operands[1] = dest;
02697 operands[2] = GEN_INT (total_shift);
02698 shift_gen_fun (ASHIFT, operands);
02699 }
02700 break;
02701 }
02702 else
02703 {
02704 int neg = 0;
02705 if (kind != 4 && total_shift < 16)
02706 {
02707 neg = -ext_shift_amounts[total_shift][1];
02708 if (neg > 0)
02709 neg -= ext_shift_amounts[total_shift][2];
02710 else
02711 neg = 0;
02712 }
02713 emit_insn (gen_and_shl_scratch (dest, source,
02714 GEN_INT (right),
02715 GEN_INT (mask),
02716 GEN_INT (total_shift + neg),
02717 GEN_INT (neg)));
02718 emit_insn (gen_movsi (dest, dest));
02719 break;
02720 }
02721 }
02722 return 0;
02723 }
02724
02725
02726
02727
02728
02729
02730
02731
02732
02733
02734
02735
02736
02737
02738
02739
02740
02741
02742
02743 int
02744 shl_sext_kind (rtx left_rtx, rtx size_rtx, int *costp)
02745 {
02746 int left, size, insize, ext;
02747 int cost = 0, best_cost;
02748 int kind;
02749
02750 left = INTVAL (left_rtx);
02751 size = INTVAL (size_rtx);
02752 insize = size - left;
02753 gcc_assert (insize > 0);
02754
02755 kind = 0;
02756 best_cost = shift_insns[32 - insize] + ashiftrt_insns[32 - size];
02757 if (size <= 16)
02758 {
02759
02760 cost = shift_insns[16 - insize] + 1 + ashiftrt_insns[16 - size];
02761
02762
02763 if (cost < best_cost)
02764 {
02765 kind = 5;
02766 best_cost = cost;
02767 }
02768 }
02769
02770 for (ext = 16; ext >= insize; ext -= 8)
02771 {
02772 if (ext <= size)
02773 {
02774 cost = ext_shift_insns[ext - insize] + 1 + shift_insns[size - ext];
02775 if (cost < best_cost)
02776 {
02777 kind = ext / (unsigned) 8;
02778 best_cost = cost;
02779 }
02780 }
02781
02782
02783 if (EXT_SHIFT_SIGNED (size - ext))
02784 cost = ext_shift_insns[ext - insize] + ext_shift_insns[size - ext] + 1;
02785
02786
02787 else if (size <= 16)
02788 cost = ext_shift_insns[ext - insize] + 1
02789 + ext_shift_insns[size > ext ? size - ext : ext - size] + 1;
02790 else
02791 continue;
02792 if (cost < best_cost)
02793 {
02794 kind = ext / (unsigned) 8 + 2;
02795 best_cost = cost;
02796 }
02797 }
02798
02799 if (insize < 8)
02800 {
02801 cost = 3 + shift_insns[left];
02802 if (cost < best_cost)
02803 {
02804 kind = 6;
02805 best_cost = cost;
02806 }
02807
02808 if (left < 31)
02809 {
02810 cost = 3 + ext_shift_insns[left + 1] + 1;
02811 if (cost < best_cost)
02812 {
02813 kind = 7;
02814 best_cost = cost;
02815 }
02816 }
02817 }
02818 if (TARGET_SH3)
02819 {
02820
02821 cost = shift_insns[32 - insize] + 1 + SH_DYNAMIC_SHIFT_COST;
02822 if (cost < best_cost)
02823 {
02824 kind = 0;
02825 best_cost = cost;
02826 }
02827 }
02828 if (costp)
02829 *costp = cost;
02830 return kind;
02831 }
02832
02833
02834
02835
02836 int
02837 shl_sext_length (rtx insn)
02838 {
02839 rtx set_src, left_rtx, size_rtx;
02840 int cost;
02841
02842 set_src = SET_SRC (XVECEXP (PATTERN (insn), 0, 0));
02843 left_rtx = XEXP (XEXP (set_src, 0), 1);
02844 size_rtx = XEXP (set_src, 1);
02845 shl_sext_kind (left_rtx, size_rtx, &cost);
02846 return cost;
02847 }
02848
02849
02850
02851 int
02852 gen_shl_sext (rtx dest, rtx left_rtx, rtx size_rtx, rtx source)
02853 {
02854 int kind;
02855 int left, size, insize, cost;
02856 rtx operands[3];
02857
02858 kind = shl_sext_kind (left_rtx, size_rtx, &cost);
02859 left = INTVAL (left_rtx);
02860 size = INTVAL (size_rtx);
02861 insize = size - left;
02862 switch (kind)
02863 {
02864 case 1:
02865 case 2:
02866 case 3:
02867 case 4:
02868 {
02869 int ext = kind & 1 ? 8 : 16;
02870 int shift2 = size - ext;
02871
02872
02873
02874 if (! currently_expanding_to_rtl
02875 && ! reload_in_progress && ! reload_completed)
02876 {
02877 emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx));
02878 emit_insn (gen_movsi (dest, source));
02879 break;
02880 }
02881 if (dest != source)
02882 emit_insn (gen_movsi (dest, source));
02883 operands[0] = dest;
02884 if (ext - insize)
02885 {
02886 operands[2] = GEN_INT (ext - insize);
02887 gen_shifty_hi_op (ASHIFT, operands);
02888 }
02889 emit_insn (kind & 1
02890 ? gen_extendqisi2 (dest, gen_lowpart (QImode, dest))
02891 : gen_extendhisi2 (dest, gen_lowpart (HImode, dest)));
02892 if (kind <= 2)
02893 {
02894 if (shift2)
02895 {
02896 operands[2] = GEN_INT (shift2);
02897 gen_shifty_op (ASHIFT, operands);
02898 }
02899 }
02900 else
02901 {
02902 if (shift2 > 0)
02903 {
02904 if (EXT_SHIFT_SIGNED (shift2))
02905 {
02906 operands[2] = GEN_INT (shift2 + 1);
02907 gen_shifty_op (ASHIFT, operands);
02908 operands[2] = const1_rtx;
02909 gen_shifty_op (ASHIFTRT, operands);
02910 break;
02911 }
02912 operands[2] = GEN_INT (shift2);
02913 gen_shifty_hi_op (ASHIFT, operands);
02914 }
02915 else if (shift2)
02916 {
02917 operands[2] = GEN_INT (-shift2);
02918 gen_shifty_hi_op (LSHIFTRT, operands);
02919 }
02920 emit_insn (size <= 8
02921 ? gen_extendqisi2 (dest, gen_lowpart (QImode, dest))
02922 : gen_extendhisi2 (dest, gen_lowpart (HImode, dest)));
02923 }
02924 break;
02925 }
02926 case 5:
02927 {
02928 int i = 16 - size;
02929 if (! currently_expanding_to_rtl
02930 && ! reload_in_progress && ! reload_completed)
02931 emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx));
02932 else
02933 {
02934 operands[0] = dest;
02935 operands[2] = GEN_INT (16 - insize);
02936 gen_shifty_hi_op (ASHIFT, operands);
02937 emit_insn (gen_extendhisi2 (dest, gen_lowpart (HImode, dest)));
02938 }
02939
02940 while (--i >= 0)
02941 gen_ashift (ASHIFTRT, 1, dest);
02942 break;
02943 }
02944 case 6:
02945 case 7:
02946
02947
02948 if (! currently_expanding_to_rtl
02949 && ! reload_in_progress && ! reload_completed)
02950 {
02951 emit_insn (gen_shl_sext_ext (dest, source, left_rtx, size_rtx));
02952 emit_insn (gen_movsi (dest, source));
02953 break;
02954 }
02955 emit_insn (gen_andsi3 (dest, source, GEN_INT ((1 << insize) - 1)));
02956 emit_insn (gen_xorsi3 (dest, dest, GEN_INT (1 << (insize - 1))));
02957 emit_insn (gen_addsi3 (dest, dest, GEN_INT (-1 << (insize - 1))));
02958 operands[0] = dest;
02959 operands[2] = kind == 7 ? GEN_INT (left + 1) : left_rtx;
02960 gen_shifty_op (ASHIFT, operands);
02961 if (kind == 7)
02962 emit_insn (gen_ashrsi3_k (dest, dest, const1_rtx));
02963 break;
02964 default:
02965 return -1;
02966 }
02967 return 0;
02968 }
02969
02970
02971
02972 rtx
02973 gen_datalabel_ref (rtx sym)
02974 {
02975 const char *str;
02976
02977 if (GET_CODE (sym) == LABEL_REF)
02978 return gen_rtx_CONST (GET_MODE (sym),
02979 gen_rtx_UNSPEC (GET_MODE (sym),
02980 gen_rtvec (1, sym),
02981 UNSPEC_DATALABEL));
02982
02983 gcc_assert (GET_CODE (sym) == SYMBOL_REF);
02984
02985 str = XSTR (sym, 0);
02986
02987
02988 str = IDENTIFIER_POINTER (get_identifier (str));
02989 XSTR (sym, 0) = str;
02990
02991 return sym;
02992 }
02993
02994
02995 static alloc_pool label_ref_list_pool;
02996
02997 typedef struct label_ref_list_d
02998 {
02999 rtx label;
03000 struct label_ref_list_d *next;
03001 } *label_ref_list_t;
03002
03003
03004
03005
03006
03007
03008
03009
03010
03011
03012
03013
03014
03015
03016
03017
03018
03019
03020
03021
03022
03023
03024
03025
03026
03027
03028
03029
03030
03031
03032
03033
03034
03035
03036
03037
03038
03039
03040
03041
03042
03043
03044
03045
03046
03047
03048
03049
03050
03051
03052
03053
03054
03055
03056 typedef struct
03057 {
03058 rtx value;
03059 rtx label;
03060 label_ref_list_t wend;
03061 enum machine_mode mode;
03062
03063
03064
03065 bool part_of_sequence_p;
03066 } pool_node;
03067
03068
03069
03070
03071
03072 #define MAX_POOL_SIZE 372
03073 static pool_node pool_vector[MAX_POOL_SIZE];
03074 static int pool_size;
03075 static rtx pool_window_label;
03076 static int pool_window_last;
03077
03078 static int max_labelno_before_reorg;
03079
03080
03081
03082
03083
03084
03085
03086
03087
03088
03089
03090
03091
03092 static rtx
03093 add_constant (rtx x, enum machine_mode mode, rtx last_value)
03094 {
03095 int i;
03096 rtx lab, new;
03097 label_ref_list_t ref, newref;
03098
03099
03100 for (i = 0; i < pool_size; i++)
03101 {
03102 if (x->code == pool_vector[i].value->code
03103 && mode == pool_vector[i].mode)
03104 {
03105 if (x->code == CODE_LABEL)
03106 {
03107 if (XINT (x, 3) != XINT (pool_vector[i].value, 3))
03108 continue;
03109 }
03110 if (rtx_equal_p (x, pool_vector[i].value))
03111 {
03112 lab = new = 0;
03113 if (! last_value
03114 || ! i
03115 || ! rtx_equal_p (last_value, pool_vector[i-1].value))
03116 {
03117 new = gen_label_rtx ();
03118 LABEL_REFS (new) = pool_vector[i].label;
03119 pool_vector[i].label = lab = new;
03120 }
03121 if (lab && pool_window_label)
03122 {
03123 newref = (label_ref_list_t) pool_alloc (label_ref_list_pool);
03124 newref->label = pool_window_label;
03125 ref = pool_vector[pool_window_last].wend;
03126 newref->next = ref;
03127 pool_vector[pool_window_last].wend = newref;
03128 }
03129 if (new)
03130 pool_window_label = new;
03131 pool_window_last = i;
03132 return lab;
03133 }
03134 }
03135 }
03136
03137
03138 pool_vector[pool_size].value = x;
03139 if (last_value && rtx_equal_p (last_value, pool_vector[pool_size - 1].value))
03140 {
03141 lab = 0;
03142 pool_vector[pool_size - 1].part_of_sequence_p = true;
03143 }
03144 else
03145 lab = gen_label_rtx ();
03146 pool_vector[pool_size].mode = mode;
03147 pool_vector[pool_size].label = lab;
03148 pool_vector[pool_size].wend = NULL;
03149 pool_vector[pool_size].part_of_sequence_p = (lab == 0);
03150 if (lab && pool_window_label)
03151 {
03152 newref = (label_ref_list_t) pool_alloc (label_ref_list_pool);
03153 newref->label = pool_window_label;
03154 ref = pool_vector[pool_window_last].wend;
03155 newref->next = ref;
03156 pool_vector[pool_window_last].wend = newref;
03157 }
03158 if (lab)
03159 pool_window_label = lab;
03160 pool_window_last = pool_size;
03161 pool_size++;
03162 return lab;
03163 }
03164
03165
03166
03167
03168
03169
03170
03171 static void
03172 dump_table (rtx start, rtx barrier)
03173 {
03174 rtx scan = barrier;
03175 int i;
03176 int need_align = 1;
03177 rtx lab;
03178 label_ref_list_t ref;
03179 int have_df = 0;
03180
03181
03182
03183 for (i = 0; i < pool_size; i++)
03184 {
03185 pool_node *p = &pool_vector[i];
03186
03187 if (p->mode == HImode)
03188 {
03189 if (need_align)
03190 {
03191 scan = emit_insn_after (gen_align_2 (), scan);
03192 need_align = 0;
03193 }
03194 for (lab = p->label; lab; lab = LABEL_REFS (lab))
03195 scan = emit_label_after (lab, scan);
03196 scan = emit_insn_after (gen_consttable_2 (p->value, const0_rtx),
03197 scan);
03198 for (ref = p->wend; ref; ref = ref->next)
03199 {
03200 lab = ref->label;
03201 scan = emit_insn_after (gen_consttable_window_end (lab), scan);
03202 }
03203 }
03204 else if (p->mode == DFmode)
03205 have_df = 1;
03206 }
03207
03208 need_align = 1;
03209
03210 if (start)
03211 {
03212 scan = emit_insn_after (gen_align_4 (), scan);
03213 need_align = 0;
03214 for (; start != barrier; start = NEXT_INSN (start))
03215 if (GET_CODE (start) == INSN
03216 && recog_memoized (start) == CODE_FOR_casesi_worker_2)
03217 {
03218 rtx src = SET_SRC (XVECEXP (PATTERN (start), 0, 0));
03219 rtx lab = XEXP (XVECEXP (src, 0, 3), 0);
03220
03221 scan = emit_label_after (lab, scan);
03222 }
03223 }
03224 if (TARGET_FMOVD && TARGET_ALIGN_DOUBLE && have_df)
03225 {
03226 rtx align_insn = NULL_RTX;
03227
03228 scan = emit_label_after (gen_label_rtx (), scan);
03229 scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan);
03230 need_align = 0;
03231
03232 for (i = 0; i < pool_size; i++)
03233 {
03234 pool_node *p = &pool_vector[i];
03235
03236 switch (p->mode)
03237 {
03238 case HImode:
03239 break;
03240 case SImode:
03241 case SFmode:
03242 if (align_insn && !p->part_of_sequence_p)
03243 {
03244 for (lab = p->label; lab; lab = LABEL_REFS (lab))
03245 emit_label_before (lab, align_insn);
03246 emit_insn_before (gen_consttable_4 (p->value, const0_rtx),
03247 align_insn);
03248 for (ref = p->wend; ref; ref = ref->next)
03249 {
03250 lab = ref->label;
03251 emit_insn_before (gen_consttable_window_end (lab),
03252 align_insn);
03253 }
03254 delete_insn (align_insn);
03255 align_insn = NULL_RTX;
03256 continue;
03257 }
03258 else
03259 {
03260 for (lab = p->label; lab; lab = LABEL_REFS (lab))
03261 scan = emit_label_after (lab, scan);
03262 scan = emit_insn_after (gen_consttable_4 (p->value,
03263 const0_rtx), scan);
03264 need_align = ! need_align;
03265 }
03266 break;
03267 case DFmode:
03268 if (need_align)
03269 {
03270 scan = emit_insn_after (gen_align_log (GEN_INT (3)), scan);
03271 align_insn = scan;
03272 need_align = 0;
03273 }
03274 case DImode:
03275 for (lab = p->label; lab; lab = LABEL_REFS (lab))
03276 scan = emit_label_after (lab, scan);
03277 scan = emit_insn_after (gen_consttable_8 (p->value, const0_rtx),
03278 scan);
03279 break;
03280 default:
03281 gcc_unreachable ();
03282 }
03283
03284 if (p->mode != HImode)
03285 {
03286 for (ref = p->wend; ref; ref = ref->next)
03287 {
03288 lab = ref->label;
03289 scan = emit_insn_after (gen_consttable_window_end (lab),
03290 scan);
03291 }
03292 }
03293 }
03294
03295 pool_size = 0;
03296 }
03297
03298 for (i = 0; i < pool_size; i++)
03299 {
03300 pool_node *p = &pool_vector[i];
03301
03302 switch (p->mode)
03303 {
03304 case HImode:
03305 break;
03306 case SImode:
03307 case SFmode:
03308 if (need_align)
03309 {
03310 need_align = 0;
03311 scan = emit_label_after (gen_label_rtx (), scan);
03312 scan = emit_insn_after (gen_align_4 (), scan);
03313 }
03314 for (lab = p->label; lab; lab = LABEL_REFS (lab))
03315 scan = emit_label_after (lab, scan);
03316 scan = emit_insn_after (gen_consttable_4 (p->value, const0_rtx),
03317 scan);
03318 break;
03319 case DFmode:
03320 case DImode:
03321 if (need_align)
03322 {
03323 need_align = 0;
03324 scan = emit_label_after (gen_label_rtx (), scan);
03325 scan = emit_insn_after (gen_align_4 (), scan);
03326 }
03327 for (lab = p->label; lab; lab = LABEL_REFS (lab))
03328 scan = emit_label_after (lab, scan);
03329 scan = emit_insn_after (gen_consttable_8 (p->value, const0_rtx),
03330 scan);
03331 break;
03332 default:
03333 gcc_unreachable ();
03334 }
03335
03336 if (p->mode != HImode)
03337 {
03338 for (ref = p->wend; ref; ref = ref->next)
03339 {
03340 lab = ref->label;
03341 scan = emit_insn_after (gen_consttable_window_end (lab), scan);
03342 }
03343 }
03344 }
03345
03346 scan = emit_insn_after (gen_consttable_end (), scan);
03347 scan = emit_barrier_after (scan);
03348 pool_size = 0;
03349 pool_window_label = NULL_RTX;
03350 pool_window_last = 0;
03351 }
03352
03353
03354
03355
03356 static int
03357 hi_const (rtx src)
03358 {
03359 return (GET_CODE (src) == CONST_INT
03360 && INTVAL (src) >= -32768
03361 && INTVAL (src) <= 32767);
03362 }
03363
03364 #define MOVA_LABELREF(mova) XVECEXP (SET_SRC (PATTERN (mova)), 0, 0)
03365
03366
03367
03368
03369
03370
03371
03372 static int
03373 broken_move (rtx insn)
03374 {
03375 if (GET_CODE (insn) == INSN)
03376 {
03377 rtx pat = PATTERN (insn);
03378 if (GET_CODE (pat) == PARALLEL)
03379 pat = XVECEXP (pat, 0, 0);
03380 if (GET_CODE (pat) == SET
03381
03382
03383 && GET_MODE (SET_DEST (pat)) != QImode
03384 && (CONSTANT_P (SET_SRC (pat))
03385
03386 || (GET_CODE (SET_SRC (pat)) == UNSPEC
03387 && XINT (SET_SRC (pat), 1) == UNSPEC_MOVA
03388 && GET_CODE (XVECEXP (SET_SRC (pat), 0, 0)) == CONST))
03389 && ! (TARGET_SH2E
03390 && GET_CODE (SET_SRC (pat)) == CONST_DOUBLE
03391 && (fp_zero_operand (SET_SRC (pat))
03392 || fp_one_operand (SET_SRC (pat)))
03393
03394
03395
03396
03397
03398
03399
03400 && (! TARGET_SH4 || TARGET_FMOVD
03401 || (GET_CODE (XEXP (XVECEXP (PATTERN (insn), 0, 2), 0))
03402 == SCRATCH))
03403 && GET_CODE (SET_DEST (pat)) == REG
03404 && FP_REGISTER_P (REGNO (SET_DEST (pat))))
03405 && ! (TARGET_SH2A
03406 && GET_MODE (SET_DEST (pat)) == SImode
03407 && GET_CODE (SET_SRC (pat)) == CONST_INT
03408 && CONST_OK_FOR_I20 (INTVAL (SET_SRC (pat))))
03409 && (GET_CODE (SET_SRC (pat)) != CONST_INT
03410 || ! CONST_OK_FOR_I08 (INTVAL (SET_SRC (pat)))))
03411 return 1;
03412 }
03413
03414 return 0;
03415 }
03416
03417 static int
03418 mova_p (rtx insn)
03419 {
03420 return (GET_CODE (insn) == INSN
03421 && GET_CODE (PATTERN (insn)) == SET
03422 && GET_CODE (SET_SRC (PATTERN (insn))) == UNSPEC
03423 && XINT (SET_SRC (PATTERN (insn)), 1) == UNSPEC_MOVA
03424
03425 && GET_CODE (MOVA_LABELREF (insn)) == LABEL_REF);
03426 }
03427
03428
03429 static void
03430 fixup_mova (rtx mova)
03431 {
03432 PUT_MODE (XEXP (MOVA_LABELREF (mova), 0), QImode);
03433 if (! flag_pic)
03434 {
03435 SET_SRC (PATTERN (mova)) = MOVA_LABELREF (mova);
03436 INSN_CODE (mova) = -1;
03437 }
03438 else
03439 {
03440 rtx worker = mova;
03441 rtx lab = gen_label_rtx ();
03442 rtx wpat, wpat0, wpat1, wsrc, diff;
03443
03444 do
03445 {
03446 worker = NEXT_INSN (worker);
03447 gcc_assert (worker
03448 && GET_CODE (worker) != CODE_LABEL
03449 && GET_CODE (worker) != JUMP_INSN);
03450 } while (GET_CODE (worker) == NOTE
03451 || recog_memoized (worker) != CODE_FOR_casesi_worker_1);
03452 wpat = PATTERN (worker);
03453 wpat0 = XVECEXP (wpat, 0, 0);
03454 wpat1 = XVECEXP (wpat, 0, 1);
03455 wsrc = SET_SRC (wpat0);
03456 PATTERN (worker) = (gen_casesi_worker_2
03457 (SET_DEST (wpat0), XVECEXP (wsrc, 0, 1),
03458 XEXP (XVECEXP (wsrc, 0, 2), 0), lab,
03459 XEXP (wpat1, 0)));
03460 INSN_CODE (worker) = -1;
03461 diff = gen_rtx_MINUS (Pmode, XVECEXP (SET_SRC (PATTERN (mova)), 0, 0),
03462 gen_rtx_LABEL_REF (Pmode, lab));
03463 diff = gen_rtx_UNSPEC (Pmode, gen_rtvec (1, diff), UNSPEC_PIC);
03464 SET_SRC (PATTERN (mova)) = gen_rtx_CONST (Pmode, diff);
03465 INSN_CODE (mova) = -1;
03466 }
03467 }
03468
03469
03470
03471
03472
03473 static int
03474 untangle_mova (int *num_mova, rtx *first_mova, rtx new_mova)
03475 {
03476 int n_addr = 0;
03477 int f_target, n_target = 0;
03478
03479 if (optimize)
03480 {
03481 n_addr = INSN_ADDRESSES (INSN_UID (new_mova));
03482 n_target = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (new_mova), 0)));
03483 if (n_addr > n_target || n_addr + 1022 < n_target)
03484 {
03485
03486
03487 fixup_mova (new_mova);
03488 return 1;
03489 }
03490 }
03491 if (!(*num_mova)++)
03492 {
03493 *first_mova = new_mova;
03494 return 2;
03495 }
03496 if (!optimize
03497 || ((f_target
03498 = INSN_ADDRESSES (INSN_UID (XEXP (MOVA_LABELREF (*first_mova), 0))))
03499 >= n_target))
03500 return -1;
03501
03502 (*num_mova)--;
03503 if (f_target - INSN_ADDRESSES (INSN_UID (*first_mova))
03504 > n_target - n_addr)
03505 {
03506 fixup_mova (*first_mova);
03507 return 0;
03508 }
03509 else
03510 {
03511 fixup_mova (new_mova);
03512 return 1;
03513 }
03514 }
03515
03516
03517
03518
03519
03520 static rtx
03521 find_barrier (int num_mova, rtx mova, rtx from)
03522 {
03523 int count_si = 0;
03524 int count_hi = 0;
03525 int found_hi = 0;
03526 int found_si = 0;
03527 int found_di = 0;
03528 int hi_align = 2;
03529 int si_align = 2;
03530 int leading_mova = num_mova;
03531 rtx barrier_before_mova = 0, found_barrier = 0, good_barrier = 0;
03532 int si_limit;
03533 int hi_limit;
03534
03535
03536
03537
03538
03539
03540
03541
03542
03543
03544
03545
03546
03547
03548
03549
03550
03551 si_limit = 1018;
03552 hi_limit = 510;
03553
03554 while (from && count_si < si_limit && count_hi < hi_limit)
03555 {
03556 int inc = get_attr_length (from);
03557 int new_align = 1;
03558
03559
03560
03561
03562
03563 if (GET_CODE (from) == CODE_LABEL
03564 && CODE_LABEL_NUMBER (from) <= max_labelno_before_reorg)
03565 {
03566 if (optimize)
03567 new_align = 1 << label_to_alignment (from);
03568 else if (GET_CODE (prev_nonnote_insn (from)) == BARRIER)
03569 new_align = 1 << barrier_align (from);
03570 else
03571 new_align = 1;
03572 inc = 0;
03573 }
03574
03575
03576
03577
03578 else if (GET_CODE (from) == INSN
03579 && GET_CODE (PATTERN (from)) == UNSPEC_VOLATILE
03580 && XINT (PATTERN (from), 1) == UNSPECV_ALIGN)
03581 new_align = INTVAL (XVECEXP (PATTERN (from), 0, 0));
03582
03583
03584
03585
03586 else if (GET_CODE (from) == INSN
03587 && GET_CODE (PATTERN (from)) == UNSPEC_VOLATILE
03588 && XINT (PATTERN (from), 1) == UNSPECV_CONST_END)
03589 return from;
03590
03591 if (GET_CODE (from) == BARRIER)
03592 {
03593
03594 found_barrier = from;
03595
03596
03597
03598
03599 if (barrier_align (from) > 2)
03600 good_barrier = from;
03601 }
03602
03603 if (broken_move (from))
03604 {
03605 rtx pat, src, dst;
03606 enum machine_mode mode;
03607
03608 pat = PATTERN (from);
03609 if (GET_CODE (pat) == PARALLEL)
03610 pat = XVECEXP (pat, 0, 0);
03611 src = SET_SRC (pat);
03612 dst = SET_DEST (pat);
03613 mode = GET_MODE (dst);
03614
03615
03616
03617
03618 if (mode == HImode
03619 || (mode == SImode && hi_const (src) && REGNO (dst) != FPUL_REG))
03620 {
03621 found_hi += 2;
03622
03623
03624
03625
03626 si_limit -= 2;
03627 }
03628 else
03629 {
03630
03631
03632
03633
03634
03635 if (TARGET_SHCOMPACT
03636 && ! found_di
03637 && (mode == DFmode || mode == DImode))
03638 {
03639 found_di = 1;
03640 si_limit -= 8;
03641 }
03642 while (si_align > 2 && found_si + si_align - 2 > count_si)
03643 si_align >>= 1;
03644 if (found_si > count_si)
03645 count_si = found_si;
03646 found_si += GET_MODE_SIZE (mode);
03647 if (num_mova)
03648 si_limit -= GET_MODE_SIZE (mode);
03649 }
03650 }
03651
03652 if (mova_p (from))
03653 {
03654 switch (untangle_mova (&num_mova, &mova, from))
03655 {
03656 case 0: return find_barrier (0, 0, mova);
03657 case 2:
03658 {
03659 leading_mova = 0;
03660 barrier_before_mova
03661 = good_barrier ? good_barrier : found_barrier;
03662 }
03663 default: break;
03664 }
03665 if (found_si > count_si)
03666 count_si = found_si;
03667 }
03668 else if (GET_CODE (from) == JUMP_INSN
03669 && (GET_CODE (PATTERN (from)) == ADDR_VEC
03670 || GET_CODE (PATTERN (from)) == ADDR_DIFF_VEC))
03671 {
03672 if ((num_mova > 1 && GET_MODE (prev_nonnote_insn (from)) == VOIDmode)
03673 || (num_mova
03674 && (prev_nonnote_insn (from)
03675 == XEXP (MOVA_LABELREF (mova), 0))))
03676 num_mova--;
03677 if (barrier_align (next_real_insn (from)) == align_jumps_log)
03678 {
03679
03680
03681
03682
03683
03684
03685
03686
03687 good_barrier = found_barrier;
03688 break;
03689 }
03690 else
03691 {
03692 rtx body = PATTERN (from);
03693 inc = XVECLEN (body, 1) * GET_MODE_SIZE (GET_MODE (body));
03694 }
03695 }
03696
03697 else if (GET_CODE (from) == JUMP_INSN
03698 && ! TARGET_SH2
03699 && ! TARGET_SMALLCODE)
03700 new_align = 4;
03701
03702 if (found_si)
03703 {
03704 count_si += inc;
03705 if (new_align > si_align)
03706 {
03707 si_limit -= (count_si - 1) & (new_align - si_align);
03708 si_align = new_align;
03709 }
03710 count_si = (count_si + new_align - 1) & -new_align;
03711 }
03712 if (found_hi)
03713 {
03714 count_hi += inc;
03715 if (new_align > hi_align)
03716 {
03717 hi_limit -= (count_hi - 1) & (new_align - hi_align);
03718 hi_align = new_align;
03719 }
03720 count_hi = (count_hi + new_align - 1) & -new_align;
03721 }
03722 from = NEXT_INSN (from);
03723 }
03724
03725 if (num_mova)
03726 {
03727 if (leading_mova)
03728 {
03729
03730
03731 fixup_mova (mova);
03732 return find_barrier (0, 0, mova);
03733 }
03734 else
03735 {
03736
03737
03738 from = mova;
03739 good_barrier = found_barrier = barrier_before_mova;
03740 }
03741 }
03742
03743 if (found_barrier)
03744 {
03745 if (good_barrier && next_real_insn (found_barrier))
03746 found_barrier = good_barrier;
03747 }
03748 else
03749 {
03750
03751
03752 rtx label = gen_label_rtx ();
03753
03754
03755
03756
03757 if (count_hi > hi_limit || count_si > si_limit)
03758 from = PREV_INSN (PREV_INSN (from));
03759 else
03760 from = PREV_INSN (from);
03761
03762
03763
03764
03765
03766
03767 while (GET_CODE (from) == JUMP_INSN || GET_CODE (from) == NOTE
03768 || GET_CODE (from) == CODE_LABEL)
03769 from = PREV_INSN (from);
03770
03771 from = emit_jump_insn_after (gen_jump (label), from);
03772 JUMP_LABEL (from) = label;
03773 LABEL_NUSES (label) = 1;
03774 found_barrier = emit_barrier_after (from);
03775 emit_label_after (label, found_barrier);
03776 }
03777
03778 return found_barrier;
03779 }
03780
03781
03782
03783
03784
03785 rtx
03786 sfunc_uses_reg (rtx insn)
03787 {
03788 int i;
03789 rtx pattern, part, reg_part, reg;
03790
03791 if (GET_CODE (insn) != INSN)
03792 return 0;
03793 pattern = PATTERN (insn);
03794 if (GET_CODE (pattern) != PARALLEL || get_attr_type (insn) != TYPE_SFUNC)
03795 return 0;
03796
03797 for (reg_part = 0, i = XVECLEN (pattern, 0) - 1; i >= 1; i--)
03798 {
03799 part = XVECEXP (pattern, 0, i);
03800 if (GET_CODE (part) == USE && GET_MODE (XEXP (part, 0)) == SImode)
03801 reg_part = part;
03802 }
03803 if (! reg_part)
03804 return 0;
03805 reg = XEXP (reg_part, 0);
03806 for (i = XVECLEN (pattern, 0) - 1; i >= 0; i--)
03807 {
03808 part = XVECEXP (pattern, 0, i);
03809 if (part == reg_part || GET_CODE (part) == CLOBBER)
03810 continue;
03811 if (reg_mentioned_p (reg, ((GET_CODE (part) == SET
03812 && GET_CODE (SET_DEST (part)) == REG)
03813 ? SET_SRC (part) : part)))
03814 return 0;
03815 }
03816 return reg;
03817 }
03818
03819
03820
03821
03822
03823 static int
03824 noncall_uses_reg (rtx reg, rtx insn, rtx *set)
03825 {
03826 rtx pattern, reg2;
03827
03828 *set = NULL_RTX;
03829
03830 reg2 = sfunc_uses_reg (insn);
03831 if (reg2 && REGNO (reg2) == REGNO (reg))
03832 {
03833 pattern = single_set (insn);
03834 if (pattern
03835 && GET_CODE (SET_DEST (pattern)) == REG
03836 && REGNO (reg) == REGNO (SET_DEST (pattern)))
03837 *set = pattern;
03838 return 0;
03839 }
03840 if (GET_CODE (insn) != CALL_INSN)
03841 {
03842
03843
03844 pattern = single_set (insn);
03845 if (pattern
03846 && GET_CODE (SET_DEST (pattern)) == REG
03847 && REGNO (reg) == REGNO (SET_DEST (pattern)))
03848 {
03849 rtx par, part;
03850 int i;
03851
03852 *set = pattern;
03853 par = PATTERN (insn);
03854 if (GET_CODE (par) == PARALLEL)
03855 for (i = XVECLEN (par, 0) - 1; i >= 0; i--)
03856 {
03857 part = XVECEXP (par, 0, i);
03858 if (GET_CODE (part) != SET && reg_mentioned_p (reg, part))
03859 return 1;
03860 }
03861 return reg_mentioned_p (reg, SET_SRC (pattern));
03862 }
03863
03864 return 1;
03865 }
03866
03867 pattern = PATTERN (insn);
03868
03869 if (GET_CODE (pattern) == PARALLEL)
03870 {
03871 int i;
03872
03873 for (i = XVECLEN (pattern, 0) - 1; i >= 1; i--)
03874 if (reg_mentioned_p (reg, XVECEXP (pattern, 0, i)))
03875 return 1;
03876 pattern = XVECEXP (pattern, 0, 0);
03877 }
03878
03879 if (GET_CODE (pattern) == SET)
03880 {
03881 if (reg_mentioned_p (reg, SET_DEST (pattern)))
03882 {
03883
03884
03885 if (GET_CODE (SET_DEST (pattern)) != REG
03886 || REGNO (reg) != REGNO (SET_DEST (pattern)))
03887 return 1;
03888
03889 *set = pattern;
03890 }
03891
03892 pattern = SET_SRC (pattern);
03893 }
03894
03895 if (GET_CODE (pattern) != CALL
03896 || GET_CODE (XEXP (pattern, 0)) != MEM
03897 || ! rtx_equal_p (reg, XEXP (XEXP (pattern, 0), 0)))
03898 return 1;
03899
03900 return 0;
03901 }
03902
03903
03904
03905
03906
03907
03908 int
03909 regs_used (rtx x, int is_dest)
03910 {
03911 enum rtx_code code;
03912 const char *fmt;
03913 int i, used = 0;
03914
03915 if (! x)
03916 return used;
03917 code = GET_CODE (x);
03918 switch (code)
03919 {
03920 case REG:
03921 if (REGNO (x) < 16)
03922 return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1)
03923 << (REGNO (x) + is_dest));
03924 return 0;
03925 case SUBREG:
03926 {
03927 rtx y = SUBREG_REG (x);
03928
03929 if (GET_CODE (y) != REG)
03930 break;
03931 if (REGNO (y) < 16)
03932 return (((1 << HARD_REGNO_NREGS (0, GET_MODE (x))) - 1)
03933 << (REGNO (y) +
03934 subreg_regno_offset (REGNO (y),
03935 GET_MODE (y),
03936 SUBREG_BYTE (x),
03937 GET_MODE (x)) + is_dest));
03938 return 0;
03939 }
03940 case SET:
03941 return regs_used (SET_SRC (x), 0) | regs_used (SET_DEST (x), 16);
03942 case RETURN:
03943
03944 return 0x00ffff00;
03945 case CLOBBER:
03946 is_dest = 1;
03947 break;
03948 case MEM:
03949 is_dest = 0;
03950 break;
03951 case CALL:
03952 used |= 0x00ff00f0;
03953 break;
03954 default:
03955 break;
03956 }
03957
03958 fmt = GET_RTX_FORMAT (code);
03959
03960 for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
03961 {
03962 if (fmt[i] == 'E')
03963 {
03964 register int j;
03965 for (j = XVECLEN (x, i) - 1; j >= 0; j--)
03966 used |= regs_used (XVECEXP (x, i, j), is_dest);
03967 }
03968 else if (fmt[i] == 'e')
03969 used |= regs_used (XEXP (x, i), is_dest);
03970 }
03971 return used;
03972 }
03973
03974
03975
03976
03977
03978
03979
03980
03981
03982
03983
03984 static rtx
03985 gen_block_redirect (rtx jump, int addr, int need_block)
03986 {
03987 int dead = 0;
03988 rtx prev = prev_nonnote_insn (jump);
03989 rtx dest;
03990
03991
03992 if (prev && GET_CODE (prev) == INSN && ! INSN_DELETED_P (prev))
03993 {
03994 if (INSN_CODE (prev) == CODE_FOR_indirect_jump_scratch)
03995 return prev;
03996 if (GET_CODE (PATTERN (prev)) == USE
03997 || GET_CODE (PATTERN (prev)) == CLOBBER
03998 || get_attr_in_delay_slot (prev) == IN_DELAY_SLOT_YES)
03999 prev = jump;
04000 else if ((need_block &= ~1) < 0)
04001 return prev;
04002 else if (recog_memoized (prev) == CODE_FOR_block_branch_redirect)
04003 need_block = 0;
04004 }
04005 if (GET_CODE (PATTERN (jump)) == RETURN)
04006 {
04007 if (! need_block)
04008 return prev;
04009
04010
04011 return emit_insn_before (gen_block_branch_redirect (const0_rtx) , jump);
04012 }
04013
04014
04015 dest = XEXP (SET_SRC (PATTERN (jump)), 0);
04016
04017 if (optimize
04018 && (INSN_ADDRESSES (INSN_UID (dest)) - addr + (unsigned) 4092
04019 > 4092 + 4098))
04020 {
04021 rtx scan;
04022
04023
04024 unsigned try = 0x7fff, used;
04025 int jump_left = flag_expensive_optimizations + 1;
04026
04027
04028
04029
04030
04031 for (scan = jump; (scan = PREV_INSN (scan)); )
04032 {
04033 enum rtx_code code;
04034
04035 if (INSN_DELETED_P (scan))
04036 continue;
04037 code = GET_CODE (scan);
04038 if (code == CODE_LABEL || code == JUMP_INSN)
04039 break;
04040 if (code == INSN
04041 && GET_CODE (PATTERN (scan)) != USE
04042 && GET_CODE (PATTERN (scan)) != CLOBBER
04043 && get_attr_in_delay_slot (scan) == IN_DELAY_SLOT_YES)
04044 {
04045 try &= ~regs_used (PATTERN (scan), 0);
04046 break;
04047 }
04048 }
04049 for (used = dead = 0, scan = JUMP_LABEL (jump);
04050 (scan = NEXT_INSN (scan)); )
04051 {
04052 enum rtx_code code;
04053
04054 if (INSN_DELETED_P (scan))
04055 continue;
04056 code = GET_CODE (scan);
04057 if (INSN_P (scan))
04058 {
04059 used |= regs_used (PATTERN (scan), 0);
04060 if (code == CALL_INSN)
04061 used |= regs_used (CALL_INSN_FUNCTION_USAGE (scan), 0);
04062 dead |= (used >> 16) & ~used;
04063 if (dead & try)
04064 {
04065 dead &= try;
04066 break;
04067 }
04068 if (code == JUMP_INSN)
04069 {
04070 if (jump_left-- && simplejump_p (scan))
04071 scan = JUMP_LABEL (scan);
04072 else
04073 break;
04074 }
04075 }
04076 }
04077
04078
04079 dead &= 0x7fff;
04080 }
04081
04082
04083
04084
04085
04086 else if (optimize && need_block >= 0)
04087 {
04088 rtx next = next_active_insn (next_active_insn (dest));
04089 if (next && GET_CODE (next) == JUMP_INSN
04090 && GET_CODE (PATTERN (next)) == SET
04091 && recog_memoized (next) == CODE_FOR_jump_compact)
04092 {
04093 dest = JUMP_LABEL (next);
04094 if (dest
04095 && (INSN_ADDRESSES (INSN_UID (dest)) - addr + (unsigned) 4092
04096 > 4092 + 4098))
04097 gen_block_redirect (next, INSN_ADDRESSES (INSN_UID (next)), -1);
04098 }
04099 }
04100
04101 if (dead)
04102 {
04103 rtx reg = gen_rtx_REG (SImode, exact_log2 (dead & -dead));
04104
04105
04106
04107
04108
04109
04110
04111
04112 rtx insn = emit_insn_before (gen_indirect_jump_scratch
04113 (reg, GEN_INT (INSN_UID (JUMP_LABEL (jump))))
04114 , jump);
04115
04116
04117
04118
04119
04120
04121 INSN_LOCATOR (insn) = INSN_LOCATOR (jump);
04122 INSN_CODE (insn) = CODE_FOR_indirect_jump_scratch;
04123 return insn;
04124 }
04125 else if (need_block)
04126
04127
04128 return emit_insn_before (gen_block_branch_redirect
04129 (GEN_INT (INSN_UID (XEXP (SET_SRC (PATTERN (jump)), 0))))
04130 , jump);
04131 return prev;
04132 }
04133
04134 #define CONDJUMP_MIN -252
04135 #define CONDJUMP_MAX 262
04136 struct far_branch
04137 {
04138
04139
04140 rtx near_label;
04141
04142
04143 rtx insert_place;
04144
04145 rtx far_label;
04146 struct far_branch *prev;
04147
04148
04149 int address;
04150 };
04151
04152 static void gen_far_branch (struct far_branch *);
04153 enum mdep_reorg_phase_e mdep_reorg_phase;
04154 static void
04155 gen_far_branch (struct far_branch *bp)
04156 {
04157 rtx insn = bp->insert_place;
04158 rtx jump;
04159 rtx label = gen_label_rtx ();
04160 int ok;
04161
04162 emit_label_after (label, insn);
04163 if (bp->far_label)
04164 {
04165 jump = emit_jump_insn_after (gen_jump (bp->far_label), insn);
04166 LABEL_NUSES (bp->far_label)++;
04167 }
04168 else
04169 jump = emit_jump_insn_after (gen_return (), insn);
04170
04171
04172
04173
04174
04175 if (optimize)
04176 emit_barrier_after (jump);
04177 emit_label_after (bp->near_label, insn);
04178 JUMP_LABEL (jump) = bp->far_label;
04179 ok = invert_jump (insn, label, 1);
04180 gcc_assert (ok);
04181
04182
04183
04184
04185
04186 if (bp->far_label)
04187 (emit_insn_after
04188 (gen_stuff_delay_slot
04189 (GEN_INT (INSN_UID (XEXP (SET_SRC (PATTERN (jump)), 0))),
04190 GEN_INT (recog_memoized (insn) == CODE_FOR_branch_false)),
04191 insn));
04192
04193 gen_block_redirect (jump, bp->address += 2, 2);
04194 }
04195
04196
04197 void
04198 fixup_addr_diff_vecs (rtx first)
04199 {
04200 rtx insn;
04201
04202 for (insn = first; insn; insn = NEXT_INSN (insn))
04203 {
04204 rtx vec_lab, pat, prev, prevpat, x, braf_label;
04205
04206 if (GET_CODE (insn) != JUMP_INSN
04207 || GET_CODE (PATTERN (insn)) != ADDR_DIFF_VEC)
04208 continue;
04209 pat = PATTERN (insn);
04210 vec_lab = XEXP (XEXP (pat, 0), 0);
04211
04212
04213 for (prev = vec_lab; ; prev = PREV_INSN (prev))
04214 {
04215 if (GET_CODE (prev) != JUMP_INSN)
04216 continue;
04217 prevpat = PATTERN (prev);
04218 if (GET_CODE (prevpat) != PARALLEL || XVECLEN (prevpat, 0) != 2)
04219 continue;
04220 x = XVECEXP (prevpat, 0, 1);
04221 if (GET_CODE (x) != USE)
04222 continue;
04223 x = XEXP (x, 0);
04224 if (GET_CODE (x) == LABEL_REF && XEXP (x, 0) == vec_lab)
04225 break;
04226 }
04227
04228
04229 if (!prev)
04230 continue;
04231
04232
04233
04234 braf_label = XEXP (XEXP (SET_SRC (XVECEXP (prevpat, 0, 0)), 1), 0);
04235 emit_label_after (braf_label, prev);
04236
04237
04238
04239 XEXP (XEXP (pat, 0), 0) = braf_label;
04240 }
04241 }
04242
04243
04244
04245 int
04246 barrier_align (rtx barrier_or_label)
04247 {
04248 rtx next = next_real_insn (barrier_or_label), pat, prev;
04249 int slot, credit, jump_to_next = 0;
04250
04251 if (! next)
04252 return 0;
04253
04254 pat = PATTERN (next);
04255
04256 if (GET_CODE (pat) == ADDR_DIFF_VEC)
04257 return 2;
04258
04259 if (GET_CODE (pat) == UNSPEC_VOLATILE && XINT (pat, 1) == UNSPECV_ALIGN)
04260
04261 return 0;
04262
04263 prev = prev_real_insn (barrier_or_label);
04264 if (GET_CODE (PATTERN (prev)) == ADDR_DIFF_VEC)
04265 {
04266 pat = PATTERN (prev);
04267
04268
04269 return ((TARGET_SMALLCODE
04270 || ((unsigned) XVECLEN (pat, 1) * GET_MODE_SIZE (GET_MODE (pat))
04271 <= (unsigned) 1 << (CACHE_LOG - 2)))
04272 ? 1 << TARGET_SHMEDIA : align_jumps_log);
04273 }
04274
04275 if (TARGET_SMALLCODE)
04276 return 0;
04277
04278 if (! TARGET_SH2 || ! optimize)
04279 return align_jumps_log;
04280
04281
04282
04283
04284 if (mdep_reorg_phase > SH_FIXUP_PCLOAD)
04285 {
04286
04287
04288
04289
04290
04291
04292
04293
04294
04295
04296
04297
04298
04299
04300
04301 prev = prev_real_insn (prev);
04302
04303 for (slot = 2, credit = (1 << (CACHE_LOG - 2)) + 2;
04304 credit >= 0 && prev && GET_CODE (prev) == INSN;
04305 prev = prev_real_insn (prev))
04306 {
04307 jump_to_next = 0;
04308 if (GET_CODE (PATTERN (prev)) == USE
04309 || GET_CODE (PATTERN (prev)) == CLOBBER)
04310 continue;
04311 if (GET_CODE (PATTERN (prev)) == SEQUENCE)
04312 {
04313 prev = XVECEXP (PATTERN (prev), 0, 1);
04314 if (INSN_UID (prev) == INSN_UID (next))
04315 {
04316
04317 jump_to_next = 1;
04318 continue;
04319 }
04320 }
04321
04322 if (slot &&
04323 get_attr_in_delay_slot (prev) == IN_DELAY_SLOT_YES)
04324 slot = 0;
04325 credit -= get_attr_length (prev);
04326 }
04327 if (prev
04328 && GET_CODE (prev) == JUMP_INSN
04329 && JUMP_LABEL (prev))
04330 {
04331 rtx x;
04332 if (jump_to_next
04333 || next_real_insn (JUMP_LABEL (prev)) == next
04334
04335
04336
04337 || JUMP_LABEL (prev) == next_nonnote_insn (next)
04338
04339
04340
04341 || (x = (NEXT_INSN (NEXT_INSN (PREV_INSN (prev)))),
04342 (INSN_P (x)
04343 && (INSN_CODE (x) == CODE_FOR_block_branch_redirect
04344 || INSN_CODE (x) == CODE_FOR_indirect_jump_scratch
04345 || INSN_CODE (x) == CODE_FOR_stuff_delay_slot))))
04346 {
04347 rtx pat = PATTERN (prev);
04348 if (GET_CODE (pat) == PARALLEL)
04349 pat = XVECEXP (pat, 0, 0);
04350 if (credit - slot >= (GET_CODE (SET_SRC (pat)) == PC ? 2 : 0))
04351 return 0;
04352 }
04353 }
04354 }
04355
04356 return align_jumps_log;
04357 }
04358
04359
04360
04361
04362
04363
04364
04365 int
04366 sh_loop_align (rtx label)
04367 {
04368 rtx next = label;
04369
04370 do
04371 next = next_nonnote_insn (next);
04372 while (next && GET_CODE (next) == CODE_LABEL);
04373
04374 if (! next
04375 || ! INSN_P (next)
04376 || GET_CODE (PATTERN (next)) == ADDR_DIFF_VEC
04377 || recog_memoized (next) == CODE_FOR_consttable_2)
04378 return 0;
04379
04380 return align_loops_log;
04381 }
04382
04383
04384
04385
04386 static void
04387 sh_reorg (void)
04388 {
04389 rtx first, insn, mova = NULL_RTX;
04390 int num_mova;
04391 rtx r0_rtx = gen_rtx_REG (Pmode, 0);
04392 rtx r0_inc_rtx = gen_rtx_POST_INC (Pmode, r0_rtx);
04393
04394 first = get_insns ();
04395 max_labelno_before_reorg = max_label_num ();
04396
04397
04398
04399
04400 if (! optimize)
04401 split_all_insns_noflow ();
04402
04403 if (TARGET_SHMEDIA)
04404 return;
04405
04406
04407
04408
04409
04410
04411
04412 mdep_reorg_phase = SH_INSERT_USES_LABELS;
04413 if (TARGET_RELAX)
04414 {
04415
04416
04417
04418
04419
04420
04421 for (insn = first; insn; insn = NEXT_INSN (insn))
04422 {
04423 if (INSN_P (insn))
04424 {
04425 rtx note;
04426
04427 while ((note = find_reg_note (insn, REG_LABEL, NULL_RTX)) != 0)
04428 remove_note (insn, note);
04429 }
04430 }
04431
04432 for (insn = first; insn; insn = NEXT_INSN (insn))
04433 {
04434 rtx pattern, reg, link, set, scan, dies, label;
04435 int rescan = 0, foundinsn = 0;
04436
04437 if (GET_CODE (insn) == CALL_INSN)
04438 {
04439 pattern = PATTERN (insn);
04440
04441 if (GET_CODE (pattern) == PARALLEL)
04442 pattern = XVECEXP (pattern, 0, 0);
04443 if (GET_CODE (pattern) == SET)
04444 pattern = SET_SRC (pattern);
04445
04446 if (GET_CODE (pattern) != CALL
04447 || GET_CODE (XEXP (pattern, 0)) != MEM)
04448 continue;
04449
04450 reg = XEXP (XEXP (pattern, 0), 0);
04451 }
04452 else
04453 {
04454 reg = sfunc_uses_reg (insn);
04455 if (! reg)
04456 continue;
04457 }
04458
04459 if (GET_CODE (reg) != REG)
04460 continue;
04461
04462
04463
04464
04465
04466
04467 for (link = LOG_LINKS (insn); link; link = XEXP (link, 1))
04468 {
04469 rtx linked_insn;
04470
04471 if (REG_NOTE_KIND (link) != 0)
04472 continue;
04473 linked_insn = XEXP (link, 0);
04474 set = single_set (linked_insn);
04475 if (set
04476 && rtx_equal_p (reg, SET_DEST (set))
04477 && ! INSN_DELETED_P (linked_insn))
04478 {
04479 link = linked_insn;
04480 break;
04481 }
04482 }
04483
04484 if (! link)
04485 {
04486
04487
04488
04489 for (scan = PREV_INSN (insn);
04490 scan && GET_CODE (scan) != CODE_LABEL;
04491 scan = PREV_INSN (scan))
04492 {
04493 if (! INSN_P (scan))
04494 continue;
04495
04496 if (! reg_mentioned_p (reg, scan))
04497 continue;
04498
04499 if (noncall_uses_reg (reg, scan, &set))
04500 break;
04501
04502 if (set)
04503 {
04504 link = scan;
04505 break;
04506 }
04507 }
04508 }
04509
04510 if (! link)
04511 continue;
04512
04513
04514
04515
04516
04517
04518
04519 if (GET_CODE (SET_SRC (set)) != SYMBOL_REF
04520 && GET_CODE (SET_SRC (set)) != LABEL_REF)
04521 continue;
04522
04523
04524
04525
04526
04527
04528
04529
04530
04531 dies = NULL_RTX;
04532 for (scan = NEXT_INSN (link); scan; scan = NEXT_INSN (scan))
04533 {
04534 rtx scanset;
04535
04536
04537
04538
04539
04540
04541
04542
04543 if (GET_CODE (scan) == CODE_LABEL && ! foundinsn)
04544 break;
04545
04546 if (! INSN_P (scan))
04547 continue;
04548
04549
04550
04551
04552
04553 if (GET_CODE (scan) == JUMP_INSN)
04554 break;
04555
04556 if (! reg_mentioned_p (reg, scan))
04557 continue;
04558
04559 if (noncall_uses_reg (reg, scan, &scanset))
04560 break;
04561
04562 if (scan == insn)
04563 foundinsn = 1;
04564
04565 if (scan != insn
04566 && (GET_CODE (scan) == CALL_INSN || sfunc_uses_reg (scan)))
04567 {
04568
04569
04570
04571 rescan = 1;
04572 }
04573
04574
04575
04576
04577
04578
04579
04580
04581
04582
04583
04584
04585
04586
04587
04588
04589
04590
04591 if (foundinsn
04592 && (scanset
04593 || find_reg_note (scan, REG_DEAD, reg)))
04594 {
04595 dies = scan;
04596 break;
04597 }
04598 }
04599
04600 if (! dies)
04601 {
04602
04603
04604 continue;
04605 }
04606
04607
04608
04609
04610
04611
04612
04613 label = gen_label_rtx ();
04614 REG_NOTES (link) = gen_rtx_INSN_LIST (REG_LABEL, label,
04615 REG_NOTES (link));
04616 REG_NOTES (insn) = gen_rtx_INSN_LIST (REG_LABEL, label,
04617 REG_NOTES (insn));
04618 if (rescan)
04619 {
04620 scan = link;
04621 do
04622 {
04623 rtx reg2;
04624
04625 scan = NEXT_INSN (scan);
04626 if (scan != insn
04627 && ((GET_CODE (scan) == CALL_INSN
04628 && reg_mentioned_p (reg, scan))
04629 || ((reg2 = sfunc_uses_reg (scan))
04630 && REGNO (reg2) == REGNO (reg))))
04631 REG_NOTES (scan)
04632 = gen_rtx_INSN_LIST (REG_LABEL, label, REG_NOTES (scan));
04633 }
04634 while (scan != dies);
04635 }
04636 }
04637 }
04638
04639 if (TARGET_SH2)
04640 fixup_addr_diff_vecs (first);
04641
04642 if (optimize)
04643 {
04644 mdep_reorg_phase = SH_SHORTEN_BRANCHES0;
04645 shorten_branches (first);
04646 }
04647
04648
04649
04650 label_ref_list_pool = create_alloc_pool ("label references list",
04651 sizeof (struct label_ref_list_d),
04652 30);
04653 mdep_reorg_phase = SH_FIXUP_PCLOAD;
04654 for (insn = first, num_mova = 0; insn; insn = NEXT_INSN (insn))
04655 {
04656 if (mova_p (insn))
04657 {
04658
04659
04660
04661
04662 if (!untangle_mova (&num_mova, &mova, insn))
04663 {
04664 insn = mova;
04665 num_mova = 0;
04666 }
04667 }
04668 else if (GET_CODE (insn) == JUMP_INSN
04669 && GET_CODE (PATTERN (insn)) == ADDR_DIFF_VEC
04670 && num_mova
04671
04672
04673
04674
04675 && ((num_mova > 1
04676 && GET_MODE (prev_nonnote_insn (insn)) == VOIDmode)
04677 || (prev_nonnote_insn (insn)
04678 == XEXP (MOVA_LABELREF (mova), 0))))
04679 {
04680 rtx scan;
04681 int total;
04682
04683 num_mova--;
04684
04685
04686
04687 for (scan = mova, total = 0; scan != insn; scan = NEXT_INSN (scan))
04688 total += get_attr_length (scan);
04689
04690
04691
04692
04693
04694 if (total > 1022)
04695 {
04696
04697
04698 fixup_mova (mova);
04699 insn = mova;
04700 }
04701 }
04702 if (broken_move (insn)
04703 || (GET_CODE (insn) == INSN
04704 && recog_memoized (insn) == CODE_FOR_casesi_worker_2))
04705 {
04706 rtx scan;
04707
04708
04709 rtx barrier = find_barrier (num_mova, mova, insn);
04710 rtx last_float_move = NULL_RTX, last_float = 0, *last_float_addr = NULL;
04711 int need_aligned_label = 0;
04712
04713 if (num_mova && ! mova_p (mova))
04714 {
04715
04716
04717 insn = mova;
04718 num_mova = 0;
04719 }
04720
04721 for (scan = insn; scan != barrier; scan = NEXT_INSN (scan))
04722 {
04723 if (GET_CODE (scan) == CODE_LABEL)
04724 last_float = 0;
04725 if (GET_CODE (scan) == INSN
04726 && recog_memoized (scan) == CODE_FOR_casesi_worker_2)
04727 need_aligned_label = 1;
04728 if (broken_move (scan))
04729 {
04730 rtx *patp = &PATTERN (scan), pat = *patp;
04731 rtx src, dst;
04732 rtx lab;
04733 rtx newsrc;
04734 enum machine_mode mode;
04735
04736 if (GET_CODE (pat) == PARALLEL)
04737 patp = &XVECEXP (pat, 0, 0), pat = *patp;
04738 src = SET_SRC (pat);
04739 dst = SET_DEST (pat);
04740 mode = GET_MODE (dst);
04741
04742 if (mode == SImode && hi_const (src)
04743 && REGNO (dst) != FPUL_REG)
04744 {
04745 int offset = 0;
04746
04747 mode = HImode;
04748 while (GET_CODE (dst) == SUBREG)
04749 {
04750 offset += subreg_regno_offset (REGNO (SUBREG_REG (dst)),
04751 GET_MODE (SUBREG_REG (dst)),
04752 SUBREG_BYTE (dst),
04753 GET_MODE (dst));
04754 dst = SUBREG_REG (dst);
04755 }
04756 dst = gen_rtx_REG (HImode, REGNO (dst) + offset);
04757 }
04758 if (GET_CODE (dst) == REG && FP_ANY_REGISTER_P (REGNO (dst)))
04759 {
04760
04761 rtx *clobberp = &XVECEXP (PATTERN (scan), 0,
04762 XVECLEN (PATTERN (scan), 0)
04763 - 1);
04764 rtx clobber = *clobberp;
04765
04766 gcc_assert (GET_CODE (clobber) == CLOBBER
04767 && rtx_equal_p (XEXP (clobber, 0), r0_rtx));
04768
04769 if (last_float
04770 && reg_set_between_p (r0_rtx, last_float_move, scan))
04771 last_float = 0;
04772 if (last_float
04773 && TARGET_SHCOMPACT
04774 && GET_MODE_SIZE (mode) != 4
04775 && GET_MODE_SIZE (GET_MODE (last_float)) == 4)
04776 last_float = 0;
04777 lab = add_constant (src, mode, last_float);
04778 if (lab)
04779 emit_insn_before (gen_mova (lab), scan);
04780 else
04781 {
04782
04783
04784
04785
04786
04787 rtx note
04788 = find_regno_note (last_float_move, REG_UNUSED, 0);
04789
04790
04791
04792 if (note)
04793 PUT_MODE (note, REG_INC);
04794
04795 *last_float_addr = r0_inc_rtx;
04796 }
04797 last_float_move = scan;
04798 last_float = src;
04799 newsrc = gen_const_mem (mode,
04800 (((TARGET_SH4 && ! TARGET_FMOVD)
04801 || REGNO (dst) == FPUL_REG)
04802 ? r0_inc_rtx
04803 : r0_rtx));
04804 last_float_addr = &XEXP (newsrc, 0);
04805
04806
04807 *clobberp = gen_rtx_CLOBBER (GET_MODE (clobber),
04808 gen_rtx_SCRATCH (Pmode));
04809 }
04810
04811 else if (GET_CODE (src) == UNSPEC
04812 && XINT (src, 1) == UNSPEC_MOVA
04813 && GET_CODE (XVECEXP (src, 0, 0)) == CONST)
04814 {
04815 lab = add_constant (XVECEXP (src, 0, 0), mode, 0);
04816 newsrc = gen_rtx_LABEL_REF (VOIDmode, lab);
04817 newsrc = gen_rtx_UNSPEC (SImode,
04818 gen_rtvec (1, newsrc),
04819 UNSPEC_MOVA);
04820 }
04821 else
04822 {
04823 lab = add_constant (src, mode, 0);
04824 newsrc = gen_rtx_LABEL_REF (VOIDmode, lab);
04825 newsrc = gen_const_mem (mode, newsrc);
04826 }
04827 *patp = gen_rtx_SET (VOIDmode, dst, newsrc);
04828 INSN_CODE (scan) = -1;
04829 }
04830 }
04831 dump_table (need_aligned_label ? insn : 0, barrier);
04832 insn = barrier;
04833 }
04834 }
04835 free_alloc_pool (label_ref_list_pool);
04836 for (insn = first; insn; insn = NEXT_INSN (insn))
04837 PUT_MODE (insn, VOIDmode);
04838
04839 mdep_reorg_phase = SH_SHORTEN_BRANCHES1;
04840 INSN_ADDRESSES_FREE ();
04841 split_branches (first);
04842
04843
04844
04845
04846
04847 if (flag_delayed_branch)
04848 {
04849 for (insn = first; insn; insn = NEXT_INSN (insn))
04850 {
04851 rtx reg = sfunc_uses_reg (insn);
04852
04853 if (! reg)
04854 continue;
04855 emit_insn_before (gen_use_sfunc_addr (reg), insn);
04856 }
04857 }
04858 #if 0
04859
04860
04861
04862
04863 if (TARGET_SH4)
04864 REG_USERVAR_P (get_fpscr_rtx ()) = 0;
04865 #endif
04866 mdep_reorg_phase = SH_AFTER_MDEP_REORG;
04867 }
04868
04869 int
04870 get_dest_uid (rtx label, int max_uid)
04871 {
04872 rtx dest = next_real_insn (label);
04873 int dest_uid;
04874 if (! dest)
04875
04876 return 0;
04877 dest_uid = INSN_UID (dest);
04878
04879
04880
04881
04882 while (dest_uid >= max_uid)
04883 {
04884 dest = NEXT_INSN (dest);
04885 dest_uid = INSN_UID (dest);
04886 }
04887 if (GET_CODE (dest) == JUMP_INSN && GET_CODE (PATTERN (dest)) == RETURN)
04888 return 0;
04889 return dest_uid;
04890 }
04891
04892
04893
04894
04895
04896
04897
04898 static void
04899 split_branches (rtx first)
04900 {
04901 rtx insn;
04902 struct far_branch **uid_branch, *far_branch_list = 0;
04903 int max_uid = get_max_uid ();
04904 int ok;
04905
04906
04907 shorten_branches (first);
04908
04909 uid_branch = (struct far_branch **) alloca (max_uid * sizeof *uid_branch);
04910 memset ((char *) uid_branch, 0, max_uid * sizeof *uid_branch);
04911
04912 for (insn = first; insn; insn = NEXT_INSN (insn))
04913 if (! INSN_P (insn))
04914 continue;
04915 else if (INSN_DELETED_P (insn))
04916 {
04917
04918
04919 PUT_CODE (insn, NOTE);
04920 NOTE_LINE_NUMBER (insn) = NOTE_INSN_DELETED;
04921 NOTE_SOURCE_FILE (insn) = 0;
04922 }
04923 else if (GET_CODE (insn) == JUMP_INSN
04924
04925 && (GET_CODE (PATTERN (insn)) == SET
04926 || GET_CODE (PATTERN (insn)) == RETURN))
04927 {
04928 enum attr_type type = get_attr_type (insn);
04929 if (type == TYPE_CBRANCH)
04930 {
04931 rtx next, beyond;
04932
04933 if (get_attr_length (insn) > 4)
04934 {
04935 rtx src = SET_SRC (PATTERN (insn));
04936 rtx olabel = XEXP (XEXP (src, 1), 0);
04937 int addr = INSN_ADDRESSES (INSN_UID (insn));
04938 rtx label = 0;
04939 int dest_uid = get_dest_uid (olabel, max_uid);
04940 struct far_branch *bp = uid_branch[dest_uid];
04941
04942
04943
04944
04945
04946
04947
04948 if (! optimize)
04949 {
04950 JUMP_LABEL (insn) = olabel;
04951 LABEL_NUSES (olabel)++;
04952 }
04953 if (! bp)
04954 {
04955 bp = (struct far_branch *) alloca (sizeof *bp);
04956 uid_branch[dest_uid] = bp;
04957 bp->prev = far_branch_list;
04958 far_branch_list = bp;
04959 bp->far_label
04960 = XEXP (XEXP (SET_SRC (PATTERN (insn)), 1), 0);
04961 LABEL_NUSES (bp->far_label)++;
04962 }
04963 else
04964 {
04965 label = bp->near_label;
04966 if (! label && bp->address - addr >= CONDJUMP_MIN)
04967 {
04968 rtx block = bp->insert_place;
04969
04970 if (GET_CODE (PATTERN (block)) == RETURN)
04971 block = PREV_INSN (block);
04972 else
04973 block = gen_block_redirect (block,
04974 bp->address, 2);
04975 label = emit_label_after (gen_label_rtx (),
04976 PREV_INSN (block));
04977 bp->near_label = label;
04978 }
04979 else if (label && ! NEXT_INSN (label))
04980 {
04981 if (addr + 2 - bp->address <= CONDJUMP_MAX)
04982 bp->insert_place = insn;
04983 else
04984 gen_far_branch (bp);
04985 }
04986 }
04987 if (! label
04988 || (NEXT_INSN (label) && bp->address - addr < CONDJUMP_MIN))
04989 {
04990 bp->near_label = label = gen_label_rtx ();
04991 bp->insert_place = insn;
04992 bp->address = addr;
04993 }
04994 ok = redirect_jump (insn, label, 1);
04995 gcc_assert (ok);
04996 }
04997 else
04998 {
04999
05000
05001
05002
05003
05004
05005
05006 beyond
05007 = next_active_insn (XEXP (XEXP (SET_SRC (PATTERN (insn)), 1),
05008 0));
05009
05010 if (beyond
05011 && (GET_CODE (beyond) == JUMP_INSN
05012 || ((beyond = next_active_insn (beyond))
05013 && GET_CODE (beyond) == JUMP_INSN))
05014 && GET_CODE (PATTERN (beyond)) == SET
05015 && recog_memoized (beyond) == CODE_FOR_jump_compact
05016 && ((INSN_ADDRESSES
05017 (INSN_UID (XEXP (SET_SRC (PATTERN (beyond)), 0)))
05018 - INSN_ADDRESSES (INSN_UID (insn)) + (unsigned) 252)
05019 > 252 + 258 + 2))
05020 gen_block_redirect (beyond,
05021 INSN_ADDRESSES (INSN_UID (beyond)), 1);
05022 }
05023
05024 next = next_active_insn (insn);
05025
05026 if ((GET_CODE (next) == JUMP_INSN
05027 || ((next = next_active_insn (next))
05028 && GET_CODE (next) == JUMP_INSN))
05029 && GET_CODE (PATTERN (next)) == SET
05030 && recog_memoized (next) == CODE_FOR_jump_compact
05031 && ((INSN_ADDRESSES
05032 (INSN_UID (XEXP (SET_SRC (PATTERN (next)), 0)))
05033 - INSN_ADDRESSES (INSN_UID (insn)) + (unsigned) 252)
05034 > 252 + 258 + 2))
05035 gen_block_redirect (next, INSN_ADDRESSES (INSN_UID (next)), 1);
05036 }
05037 else if (type == TYPE_JUMP || type == TYPE_RETURN)
05038 {
05039 int addr = INSN_ADDRESSES (INSN_UID (insn));
05040 rtx far_label = 0;
05041 int dest_uid = 0;
05042 struct far_branch *bp;
05043
05044 if (type == TYPE_JUMP)
05045 {
05046 far_label = XEXP (SET_SRC (PATTERN (insn)), 0);
05047 dest_uid = get_dest_uid (far_label, max_uid);
05048 if (! dest_uid)
05049 {
05050
05051
05052 if (! NEXT_INSN (far_label))
05053 continue;
05054
05055 if (! optimize)
05056 {
05057 JUMP_LABEL (insn) = far_label;
05058 LABEL_NUSES (far_label)++;
05059 }
05060 redirect_jump (insn, NULL_RTX, 1);
05061 far_label = 0;
05062 }
05063 }
05064 bp = uid_branch[dest_uid];
05065 if (! bp)
05066 {
05067 bp = (struct far_branch *) alloca (sizeof *bp);
05068 uid_branch[dest_uid] = bp;
05069 bp->prev = far_branch_list;
05070 far_branch_list = bp;
05071 bp->near_label = 0;
05072 bp->far_label = far_label;
05073 if (far_label)
05074 LABEL_NUSES (far_label)++;
05075 }
05076 else if (bp->near_label && ! NEXT_INSN (bp->near_label))
05077 if (addr - bp->address <= CONDJUMP_MAX)
05078 emit_label_after (bp->near_label, PREV_INSN (insn));
05079 else
05080 {
05081 gen_far_branch (bp);
05082 bp->near_label = 0;
05083 }
05084 else
05085 bp->near_label = 0;
05086 bp->address = addr;
05087 bp->insert_place = insn;
05088 if (! far_label)
05089 emit_insn_before (gen_block_branch_redirect (const0_rtx), insn);
05090 else
05091 gen_block_redirect (insn, addr, bp->near_label ? 2 : 0);
05092 }
05093 }
05094
05095
05096 while (far_branch_list)
05097 {
05098 if (far_branch_list->near_label
05099 && ! NEXT_INSN (far_branch_list->near_label))
05100 gen_far_branch (far_branch_list);
05101 if (optimize
05102 && far_branch_list->far_label
05103 && ! --LABEL_NUSES (far_branch_list->far_label))
05104 delete_insn (far_branch_list->far_label);
05105 far_branch_list = far_branch_list->prev;
05106 }
05107
05108
05109
05110 init_insn_lengths ();
05111 }
05112
05113
05114
05115
05116
05117
05118
05119
05120
05121
05122
05123
05124 void
05125 final_prescan_insn (rtx insn, rtx *opvec ATTRIBUTE_UNUSED,
05126 int noperands ATTRIBUTE_UNUSED)
05127 {
05128 if (TARGET_DUMPISIZE)
05129 fprintf (asm_out_file, "\n! at %04x\n", INSN_ADDRESSES (INSN_UID (insn)));
05130
05131 if (TARGET_RELAX)
05132 {
05133 rtx note;
05134
05135 note = find_reg_note (insn, REG_LABEL, NULL_RTX);
05136 if (note)
05137 {
05138 rtx pattern;
05139
05140 pattern = PATTERN (insn);
05141 if (GET_CODE (pattern) == PARALLEL)
05142 pattern = XVECEXP (pattern, 0, 0);
05143 switch (GET_CODE (pattern))
05144 {
05145 case SET:
05146 if (GET_CODE (SET_SRC (pattern)) != CALL
05147 && get_attr_type (insn) != TYPE_SFUNC)
05148 {
05149 targetm.asm_out.internal_label
05150 (asm_out_file, "L", CODE_LABEL_NUMBER (XEXP (note, 0)));
05151 break;
05152 }
05153
05154 case CALL:
05155 asm_fprintf (asm_out_file, "\t.uses %LL%d\n",
05156 CODE_LABEL_NUMBER (XEXP (note, 0)));
05157 break;
05158
05159 default:
05160 gcc_unreachable ();
05161 }
05162 }
05163 }
05164 }
05165
05166
05167
05168
05169 const char *
05170 output_jump_label_table (void)
05171 {
05172 int i;
05173
05174 if (pool_size)
05175 {
05176 fprintf (asm_out_file, "\t.align 2\n");
05177 for (i = 0; i < pool_size; i++)
05178 {
05179 pool_node *p = &pool_vector[i];
05180
05181 (*targetm.asm_out.internal_label) (asm_out_file, "L",
05182 CODE_LABEL_NUMBER (p->label));
05183 output_asm_insn (".long %O0", &p->value);
05184 }
05185 pool_size = 0;
05186 }
05187
05188 return "";
05189 }
05190
05191
05192
05193
05194
05195
05196
05197
05198
05199
05200
05201
05202
05203
05204
05205
05206
05207
05208
05209
05210
05211
05212
05213
05214
05215
05216
05217
05218
05219 static void
05220 output_stack_adjust (int size, rtx reg, int epilogue_p,
05221 HARD_REG_SET *live_regs_mask)
05222 {
05223 rtx (*emit_fn) (rtx) = epilogue_p ? &emit_insn : &frame_insn;
05224 if (size)
05225 {
05226 HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT;
05227
05228
05229
05230 #if 0
05231 gcc_assert (!(size % align));
05232 #endif
05233
05234 if (CONST_OK_FOR_ADD (size))
05235 emit_fn (GEN_ADD3 (reg, reg, GEN_INT (size)));
05236
05237
05238
05239 else if (CONST_OK_FOR_ADD (size / 2 & -align)
05240 && CONST_OK_FOR_ADD (size - (size / 2 & -align)))
05241 {
05242 emit_fn (GEN_ADD3 (reg, reg, GEN_INT (size / 2 & -align)));
05243 emit_fn (GEN_ADD3 (reg, reg, GEN_INT (size - (size / 2 & -align))));
05244 }
05245 else
05246 {
05247 rtx const_reg;
05248 rtx insn;
05249 int temp = epilogue_p ? 7 : (TARGET_SH5 ? 0 : 1);
05250 int i;
05251
05252
05253
05254
05255 if (epilogue_p < 0
05256 || current_function_interrupt
05257 || ! call_really_used_regs[temp] || fixed_regs[temp])
05258 temp = -1;
05259 if (temp < 0 && ! current_function_interrupt
05260 && (TARGET_SHMEDIA || epilogue_p >= 0))
05261 {
05262 HARD_REG_SET temps;
05263 COPY_HARD_REG_SET (temps, call_used_reg_set);
05264 AND_COMPL_HARD_REG_SET (temps, call_fixed_reg_set);
05265 if (epilogue_p > 0)
05266 {
05267 int nreg = 0;
05268 if (current_function_return_rtx)
05269 {
05270 enum machine_mode mode;
05271 mode = GET_MODE (current_function_return_rtx);
05272 if (BASE_RETURN_VALUE_REG (mode) == FIRST_RET_REG)
05273 nreg = HARD_REGNO_NREGS (FIRST_RET_REG, mode);
05274 }
05275 for (i = 0; i < nreg; i++)
05276 CLEAR_HARD_REG_BIT (temps, FIRST_RET_REG + i);
05277 if (current_function_calls_eh_return)
05278 {
05279 CLEAR_HARD_REG_BIT (temps, EH_RETURN_STACKADJ_REGNO);
05280 for (i = 0; i <= 3; i++)
05281 CLEAR_HARD_REG_BIT (temps, EH_RETURN_DATA_REGNO (i));
05282 }
05283 }
05284 if (TARGET_SHMEDIA && epilogue_p < 0)
05285 for (i = FIRST_TARGET_REG; i <= LAST_TARGET_REG; i++)
05286 CLEAR_HARD_REG_BIT (temps, i);
05287 if (epilogue_p <= 0)
05288 {
05289 for (i = FIRST_PARM_REG;
05290 i < FIRST_PARM_REG + NPARM_REGS (SImode); i++)
05291 CLEAR_HARD_REG_BIT (temps, i);
05292 if (cfun->static_chain_decl != NULL)
05293 CLEAR_HARD_REG_BIT (temps, STATIC_CHAIN_REGNUM);
05294 }
05295 temp = scavenge_reg (&temps);
05296 }
05297 if (temp < 0 && live_regs_mask)
05298 temp = scavenge_reg (live_regs_mask);
05299 if (temp < 0)
05300 {
05301 rtx adj_reg, tmp_reg, mem;
05302
05303
05304
05305
05306
05307
05308
05309 gcc_assert (!TARGET_SHMEDIA && epilogue_p);
05310
05311
05312
05313
05314
05315
05316
05317
05318
05319
05320
05321
05322
05323
05324
05325
05326
05327
05328
05329 gcc_assert (!fixed_regs[4] && !fixed_regs[5]
05330 && !global_regs[4] && !global_regs[5]);
05331
05332 adj_reg = gen_rtx_REG (GET_MODE (reg), 4);
05333 tmp_reg = gen_rtx_REG (GET_MODE (reg), 5);
05334 emit_move_insn (gen_tmp_stack_mem (Pmode, reg), adj_reg);
05335 emit_insn (GEN_MOV (adj_reg, GEN_INT (size)));
05336 emit_insn (GEN_ADD3 (adj_reg, adj_reg, reg));
05337 mem = gen_tmp_stack_mem (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg));
05338 emit_move_insn (mem, tmp_reg);
05339 emit_move_insn (tmp_reg, gen_tmp_stack_mem (Pmode, reg));
05340 mem = gen_tmp_stack_mem (Pmode, gen_rtx_PRE_DEC (Pmode, adj_reg));
05341 emit_move_insn (mem, tmp_reg);
05342 emit_move_insn (reg, adj_reg);
05343 mem = gen_tmp_stack_mem (Pmode, gen_rtx_POST_INC (Pmode, reg));
05344 emit_move_insn (adj_reg, mem);
05345 mem = gen_tmp_stack_mem (Pmode, gen_rtx_POST_INC (Pmode, reg));
05346 emit_move_insn (tmp_reg, mem);
05347 return;
05348 }
05349 const_reg = gen_rtx_REG (GET_MODE (reg), temp);
05350
05351
05352
05353
05354 if (size < 0)
05355 {
05356 emit_insn (GEN_MOV (const_reg, GEN_INT (-size)));
05357 insn = emit_fn (GEN_SUB3 (reg, reg, const_reg));
05358 }
05359 else
05360 {
05361 emit_insn (GEN_MOV (const_reg, GEN_INT (size)));
05362 insn = emit_fn (GEN_ADD3 (reg, reg, const_reg));
05363 }
05364 if (! epilogue_p)
05365 REG_NOTES (insn)
05366 = (gen_rtx_EXPR_LIST
05367 (REG_FRAME_RELATED_EXPR,
05368 gen_rtx_SET (VOIDmode, reg,
05369 gen_rtx_PLUS (SImode, reg, GEN_INT (size))),
05370 REG_NOTES (insn)));
05371 }
05372 }
05373 }
05374
05375 static rtx
05376 frame_insn (rtx x)
05377 {
05378 x = emit_insn (x);
05379 RTX_FRAME_RELATED_P (x) = 1;
05380 return x;
05381 }
05382
05383
05384
05385 static rtx
05386 push (int rn)
05387 {
05388 rtx x;
05389 if (rn == FPUL_REG)
05390 x = gen_push_fpul ();
05391 else if (rn == FPSCR_REG)
05392 x = gen_push_fpscr ();
05393 else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && ! TARGET_FPU_SINGLE
05394 && FP_OR_XD_REGISTER_P (rn))
05395 {
05396 if (FP_REGISTER_P (rn) && (rn - FIRST_FP_REG) & 1)
05397 return NULL_RTX;
05398 x = gen_push_4 (gen_rtx_REG (DFmode, rn));
05399 }
05400 else if (TARGET_SH2E && FP_REGISTER_P (rn))
05401 x = gen_push_e (gen_rtx_REG (SFmode, rn));
05402 else
05403 x = gen_push (gen_rtx_REG (SImode, rn));
05404
05405 x = frame_insn (x);
05406 REG_NOTES (x)
05407 = gen_rtx_EXPR_LIST (REG_INC,
05408 gen_rtx_REG (SImode, STACK_POINTER_REGNUM), 0);
05409 return x;
05410 }
05411
05412
05413
05414 static void
05415 pop (int rn)
05416 {
05417 rtx x;
05418 if (rn == FPUL_REG)
05419 x = gen_pop_fpul ();
05420 else if (rn == FPSCR_REG)
05421 x = gen_pop_fpscr ();
05422 else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && ! TARGET_FPU_SINGLE
05423 && FP_OR_XD_REGISTER_P (rn))
05424 {
05425 if (FP_REGISTER_P (rn) && (rn - FIRST_FP_REG) & 1)
05426 return;
05427 x = gen_pop_4 (gen_rtx_REG (DFmode, rn));
05428 }
05429 else if (TARGET_SH2E && FP_REGISTER_P (rn))
05430 x = gen_pop_e (gen_rtx_REG (SFmode, rn));
05431 else
05432 x = gen_pop (gen_rtx_REG (SImode, rn));
05433
05434 x = emit_insn (x);
05435 REG_NOTES (x)
05436 = gen_rtx_EXPR_LIST (REG_INC,
05437 gen_rtx_REG (SImode, STACK_POINTER_REGNUM), 0);
05438 }
05439
05440
05441
05442 static void
05443 push_regs (HARD_REG_SET *mask, int interrupt_handler)
05444 {
05445 int i;
05446 int skip_fpscr = 0;
05447
05448
05449
05450
05451 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
05452 {
05453
05454
05455
05456 if (i == FIRST_FP_REG && interrupt_handler && TARGET_FMOVD
05457 && hard_regs_intersect_p (mask, ®_class_contents[DF_REGS]))
05458 {
05459 HARD_REG_SET unsaved;
05460
05461 push (FPSCR_REG);
05462 COMPL_HARD_REG_SET (unsaved, *mask);
05463 fpscr_set_from_mem (NORMAL_MODE (FP_MODE), unsaved);
05464 skip_fpscr = 1;
05465 }
05466 if (i != PR_REG
05467 && (i != FPSCR_REG || ! skip_fpscr)
05468 && TEST_HARD_REG_BIT (*mask, i))
05469 push (i);
05470 }
05471 if (TEST_HARD_REG_BIT (*mask, PR_REG))
05472 push (PR_REG);
05473 }
05474
05475
05476
05477
05478
05479 static int
05480 shmedia_target_regs_stack_space (HARD_REG_SET *live_regs_mask)
05481 {
05482 int reg;
05483 int stack_space = 0;
05484 int interrupt_handler = sh_cfun_interrupt_handler_p ();
05485
05486 for (reg = LAST_TARGET_REG; reg >= FIRST_TARGET_REG; reg--)
05487 if ((! call_really_used_regs[reg] || interrupt_handler)
05488 && ! TEST_HARD_REG_BIT (*live_regs_mask, reg))
05489
05490
05491 stack_space += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
05492 return stack_space;
05493 }
05494
05495
05496
05497
05498
05499
05500 static int
05501 shmedia_reserve_space_for_target_registers_p (int regs_saved,
05502 HARD_REG_SET *live_regs_mask)
05503 {
05504 if (optimize_size)
05505 return 0;
05506 return shmedia_target_regs_stack_space (live_regs_mask) <= regs_saved;
05507 }
05508
05509
05510
05511
05512
05513 static int
05514 shmedia_target_regs_stack_adjust (HARD_REG_SET *live_regs_mask)
05515 {
05516 if (shmedia_space_reserved_for_target_registers)
05517 return shmedia_target_regs_stack_space (live_regs_mask);
05518 else
05519 return 0;
05520 }
05521
05522
05523
05524
05525
05526
05527
05528
05529 static int
05530 calc_live_regs (HARD_REG_SET *live_regs_mask)
05531 {
05532 unsigned int reg;
05533 int count;
05534 tree attrs;
05535 bool interrupt_or_trapa_handler, trapa_handler, interrupt_handler;
05536 bool nosave_low_regs;
05537 int pr_live, has_call;
05538
05539 attrs = DECL_ATTRIBUTES (current_function_decl);
05540 interrupt_or_trapa_handler = sh_cfun_interrupt_handler_p ();
05541 trapa_handler = lookup_attribute ("trapa_handler", attrs) != NULL_TREE;
05542 interrupt_handler = interrupt_or_trapa_handler && ! trapa_handler;
05543 nosave_low_regs = lookup_attribute ("nosave_low_regs", attrs) != NULL_TREE;
05544
05545 CLEAR_HARD_REG_SET (*live_regs_mask);
05546 if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && interrupt_handler
05547 && regs_ever_live[FPSCR_REG])
05548 target_flags &= ~MASK_FPU_SINGLE;
05549
05550 else if ((TARGET_SH4 || TARGET_SH2A_DOUBLE) && TARGET_FMOVD && TARGET_FPU_SINGLE)
05551 for (count = 0, reg = FIRST_FP_REG; reg <= LAST_FP_REG; reg += 2)
05552 if (regs_ever_live[reg] && regs_ever_live[reg+1]
05553 && (! call_really_used_regs[reg]
05554 || interrupt_handler)
05555 && ++count > 2)
05556 {
05557 target_flags &= ~MASK_FPU_SINGLE;
05558 break;
05559 }
05560
05561
05562
05563
05564 if (TARGET_SHMEDIA)
05565
05566
05567 pr_live = sh_pr_n_sets ();
05568 else
05569 {
05570 rtx pr_initial = has_hard_reg_initial_val (Pmode, PR_REG);
05571 pr_live = (pr_initial
05572 ? (GET_CODE (pr_initial) != REG
05573 || REGNO (pr_initial) != (PR_REG))
05574 : regs_ever_live[PR_REG]);
05575
05576
05577
05578 pr_live |= regs_ever_live[RETURN_ADDRESS_POINTER_REGNUM];
05579 }
05580
05581
05582 if (TARGET_SHCOMPACT
05583 && ((current_function_args_info.call_cookie
05584 & ~ CALL_COOKIE_RET_TRAMP (1))
05585 || current_function_has_nonlocal_label))
05586 pr_live = 1;
05587 has_call = TARGET_SHMEDIA ? ! leaf_function_p () : pr_live;
05588 for (count = 0, reg = FIRST_PSEUDO_REGISTER; reg-- != 0; )
05589 {
05590 if (reg == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG)
05591 ? pr_live
05592 : interrupt_handler
05593 ? (
05594 (regs_ever_live[reg]
05595 || (call_really_used_regs[reg]
05596 && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG
05597 || reg == PIC_OFFSET_TABLE_REGNUM)
05598 && has_call)
05599 || (TARGET_SHMEDIA && has_call
05600 && REGISTER_NATURAL_MODE (reg) == SImode
05601 && (GENERAL_REGISTER_P (reg) || TARGET_REGISTER_P (reg))))
05602 && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
05603 && reg != RETURN_ADDRESS_POINTER_REGNUM
05604 && reg != T_REG && reg != GBR_REG
05605
05606 && (reg != FPSCR_REG || TARGET_FPU_ANY))
05607 : (
05608 (TARGET_SHCOMPACT
05609 && flag_pic
05610 && current_function_args_info.call_cookie
05611 && reg == PIC_OFFSET_TABLE_REGNUM)
05612 || (regs_ever_live[reg]
05613 && (!call_really_used_regs[reg]
05614 || (trapa_handler && reg == FPSCR_REG && TARGET_FPU_ANY)))
05615 || (current_function_calls_eh_return
05616 && (reg == EH_RETURN_DATA_REGNO (0)
05617 || reg == EH_RETURN_DATA_REGNO (1)
05618 || reg == EH_RETURN_DATA_REGNO (2)
05619 || reg == EH_RETURN_DATA_REGNO (3)))
05620 || ((reg == MACL_REG || reg == MACH_REG)
05621 && regs_ever_live[reg]
05622 && sh_cfun_attr_renesas_p ())
05623 ))
05624 {
05625 SET_HARD_REG_BIT (*live_regs_mask, reg);
05626 count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
05627
05628 if ((TARGET_SH4 || TARGET_SH2A_DOUBLE || TARGET_SH5) && TARGET_FMOVD
05629 && GET_MODE_CLASS (REGISTER_NATURAL_MODE (reg)) == MODE_FLOAT)
05630 {
05631 if (FP_REGISTER_P (reg))
05632 {
05633 if (! TARGET_FPU_SINGLE && ! regs_ever_live[reg ^ 1])
05634 {
05635 SET_HARD_REG_BIT (*live_regs_mask, (reg ^ 1));
05636 count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg ^ 1));
05637 }
05638 }
05639 else if (XD_REGISTER_P (reg))
05640 {
05641
05642 target_flags &= ~MASK_FPU_SINGLE;
05643 }
05644 }
05645 }
05646 if (nosave_low_regs && reg == R8_REG)
05647 break;
05648 }
05649
05650
05651
05652 if (flag_branch_target_load_optimize2
05653 && TARGET_SAVE_ALL_TARGET_REGS
05654 && shmedia_space_reserved_for_target_registers)
05655 for (reg = LAST_TARGET_REG; reg >= FIRST_TARGET_REG; reg--)
05656 if ((! call_really_used_regs[reg] || interrupt_handler)
05657 && ! TEST_HARD_REG_BIT (*live_regs_mask, reg))
05658 {
05659 SET_HARD_REG_BIT (*live_regs_mask, reg);
05660 count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
05661 }
05662
05663
05664
05665
05666 if (interrupt_handler
05667 && hard_regs_intersect_p (live_regs_mask,
05668 ®_class_contents[TARGET_REGS])
05669 && ! hard_regs_intersect_p (live_regs_mask,
05670 ®_class_contents[GENERAL_REGS]))
05671 {
05672 SET_HARD_REG_BIT (*live_regs_mask, R0_REG);
05673 count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (R0_REG));
05674 }
05675
05676 return count;
05677 }
05678
05679
05680
05681
05682
05683
05684 static HOST_WIDE_INT
05685 rounded_frame_size (int pushed)
05686 {
05687 HOST_WIDE_INT size = get_frame_size ();
05688 HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT;
05689
05690 return ((size + pushed + align - 1) & -align) - pushed;
05691 }
05692
05693
05694
05695
05696 int
05697 sh_media_register_for_return (void)
05698 {
05699 int regno;
05700 int tr0_used;
05701
05702 if (! current_function_is_leaf)
05703 return -1;
05704 if (lookup_attribute ("interrupt_handler",
05705 DECL_ATTRIBUTES (current_function_decl)))
05706 return -1;
05707 if (sh_cfun_interrupt_handler_p ())
05708 return -1;
05709
05710 tr0_used = flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM];
05711
05712 for (regno = FIRST_TARGET_REG + tr0_used; regno <= LAST_TARGET_REG; regno++)
05713 if (call_really_used_regs[regno] && ! regs_ever_live[regno])
05714 return regno;
05715
05716 return -1;
05717 }
05718
05719
05720
05721
05722
05723
05724
05725 #define MAX_SAVED_REGS (62+32+8)
05726
05727 typedef struct save_entry_s
05728 {
05729 unsigned char reg;
05730 unsigned char mode;
05731 short offset;
05732 } save_entry;
05733
05734 #define MAX_TEMPS 4
05735
05736
05737
05738
05739 typedef struct save_schedule_s
05740 {
05741 save_entry entries[MAX_SAVED_REGS + 2];
05742 int temps[MAX_TEMPS+1];
05743 } save_schedule;
05744
05745
05746
05747
05748
05749
05750 static save_entry *
05751 sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule,
05752 int offset_base)
05753 {
05754 int align, i;
05755 save_entry *entry = schedule->entries;
05756 int tmpx = 0;
05757 int offset;
05758
05759 if (! current_function_interrupt)
05760 for (i = FIRST_GENERAL_REG; tmpx < MAX_TEMPS && i <= LAST_GENERAL_REG; i++)
05761 if (call_really_used_regs[i] && ! fixed_regs[i] && i != PR_MEDIA_REG
05762 && ! FUNCTION_ARG_REGNO_P (i)
05763 && i != FIRST_RET_REG
05764 && ! (cfun->static_chain_decl != NULL && i == STATIC_CHAIN_REGNUM)
05765 && ! (current_function_calls_eh_return
05766 && (i == EH_RETURN_STACKADJ_REGNO
05767 || ((unsigned) i >= EH_RETURN_DATA_REGNO (0)
05768 && (unsigned) i <= EH_RETURN_DATA_REGNO (3)))))
05769 schedule->temps[tmpx++] = i;
05770 entry->reg = -1;
05771 entry->mode = VOIDmode;
05772 entry->offset = offset_base;
05773 entry++;
05774
05775
05776
05777
05778
05779
05780
05781
05782 offset = offset_base;
05783 for (align = 1; align >= 0; align--)
05784 {
05785 for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--)
05786 if (TEST_HARD_REG_BIT (*live_regs_mask, i))
05787 {
05788 enum machine_mode mode = REGISTER_NATURAL_MODE (i);
05789 int reg = i;
05790
05791 if (current_function_interrupt)
05792 {
05793 if (TARGET_REGISTER_P (i))
05794 continue;
05795 if (GENERAL_REGISTER_P (i))
05796 mode = DImode;
05797 }
05798 if (mode == SFmode && (i % 2) == 1
05799 && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i)
05800 && (TEST_HARD_REG_BIT (*live_regs_mask, (i ^ 1))))
05801 {
05802 mode = DFmode;
05803 i--;
05804 reg--;
05805 }
05806
05807
05808
05809
05810 if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT) == 0)
05811 != align)
05812 continue;
05813
05814 if (current_function_interrupt
05815 && GENERAL_REGISTER_P (i)
05816 && tmpx < MAX_TEMPS)
05817 schedule->temps[tmpx++] = i;
05818
05819 offset -= GET_MODE_SIZE (mode);
05820 entry->reg = i;
05821 entry->mode = mode;
05822 entry->offset = offset;
05823 entry++;
05824 }
05825 if (align && current_function_interrupt)
05826 for (i = LAST_TARGET_REG; i >= FIRST_TARGET_REG; i--)
05827 if (TEST_HARD_REG_BIT (*live_regs_mask, i))
05828 {
05829 offset -= GET_MODE_SIZE (DImode);
05830 entry->reg = i;
05831 entry->mode = DImode;
05832 entry->offset = offset;
05833 entry++;
05834 }
05835 }
05836 entry->reg = -1;
05837 entry->mode = VOIDmode;
05838 entry->offset = offset;
05839 schedule->temps[tmpx] = -1;
05840 return entry - 1;
05841 }
05842
05843 void
05844 sh_expand_prologue (void)
05845 {
05846 HARD_REG_SET live_regs_mask;
05847 int d, i;
05848 int d_rounding = 0;
05849 int save_flags = target_flags;
05850 int pretend_args;
05851 tree sp_switch_attr
05852 = lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl));
05853
05854 current_function_interrupt = sh_cfun_interrupt_handler_p ();
05855
05856
05857
05858 pretend_args = current_function_pretend_args_size;
05859 if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl)
05860 && (NPARM_REGS(SImode)
05861 > current_function_args_info.arg_count[(int) SH_ARG_INT]))
05862 pretend_args = 0;
05863 output_stack_adjust (-pretend_args
05864 - current_function_args_info.stack_regs * 8,
05865 stack_pointer_rtx, 0, NULL);
05866
05867 if (TARGET_SHCOMPACT && flag_pic && current_function_args_info.call_cookie)
05868
05869
05870
05871
05872 regs_ever_live[PIC_OFFSET_TABLE_REGNUM] = 1;
05873
05874 if (TARGET_SHCOMPACT
05875 && (current_function_args_info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1)))
05876 {
05877 int reg;
05878
05879
05880
05881
05882 for (reg = 0; reg < NPARM_REGS (SImode); reg++)
05883 if (CALL_COOKIE_STACKSEQ_GET (current_function_args_info.call_cookie)
05884 >= NPARM_REGS (SImode) - reg)
05885 for (; reg < NPARM_REGS (SImode); reg++)
05886 emit_insn (gen_shcompact_preserve_incoming_args
05887 (gen_rtx_REG (SImode, FIRST_PARM_REG + reg)));
05888 else if (CALL_COOKIE_INT_REG_GET
05889 (current_function_args_info.call_cookie, reg) == 1)
05890 emit_insn (gen_shcompact_preserve_incoming_args
05891 (gen_rtx_REG (SImode, FIRST_PARM_REG + reg)));
05892
05893 emit_move_insn (gen_rtx_REG (Pmode, MACL_REG),
05894 stack_pointer_rtx);
05895 emit_move_insn (gen_rtx_REG (SImode, R0_REG),
05896 GEN_INT (current_function_args_info.call_cookie));
05897 emit_move_insn (gen_rtx_REG (SImode, MACH_REG),
05898 gen_rtx_REG (SImode, R0_REG));
05899 }
05900 else if (TARGET_SHMEDIA)
05901 {
05902 int tr = sh_media_register_for_return ();
05903
05904 if (tr >= 0)
05905 {
05906 rtx insn = emit_move_insn (gen_rtx_REG (DImode, tr),
05907 gen_rtx_REG (DImode, PR_MEDIA_REG));
05908
05909
05910
05911
05912
05913
05914 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
05915 const0_rtx,
05916 REG_NOTES (insn));
05917 }
05918 }
05919
05920
05921 if (current_function_stdarg)
05922 {
05923 if (TARGET_VARARGS_PRETEND_ARGS (current_function_decl))
05924 {
05925
05926 for (i = 0; i < NPARM_REGS(SImode); i++)
05927 {
05928 int rn = NPARM_REGS(SImode) + FIRST_PARM_REG - i - 1;
05929 rtx insn;
05930
05931 if (i >= (NPARM_REGS(SImode)
05932 - current_function_args_info.arg_count[(int) SH_ARG_INT]
05933 ))
05934 break;
05935 insn = push (rn);
05936 RTX_FRAME_RELATED_P (insn) = 0;
05937 }
05938 }
05939 }
05940
05941
05942 if (sp_switch_attr)
05943 {
05944
05945
05946 const char *s
05947 = ggc_strdup (TREE_STRING_POINTER (TREE_VALUE (sp_switch_attr)));
05948 rtx sp_switch = gen_rtx_SYMBOL_REF (Pmode, s);
05949
05950 emit_insn (gen_sp_switch_1 (sp_switch));
05951 }
05952
05953 d = calc_live_regs (&live_regs_mask);
05954
05955
05956 if (target_flags != save_flags && ! current_function_interrupt)
05957 emit_insn (gen_toggle_sz ());
05958
05959 if (TARGET_SH5)
05960 {
05961 int offset_base, offset;
05962 rtx r0 = NULL_RTX;
05963 int offset_in_r0 = -1;
05964 int sp_in_r0 = 0;
05965 int tregs_space = shmedia_target_regs_stack_adjust (&live_regs_mask);
05966 int total_size, save_size;
05967 save_schedule schedule;
05968 save_entry *entry;
05969 int *tmp_pnt;
05970
05971 if (call_really_used_regs[R0_REG] && ! fixed_regs[R0_REG]
05972 && ! current_function_interrupt)
05973 r0 = gen_rtx_REG (Pmode, R0_REG);
05974
05975
05976
05977
05978
05979
05980
05981
05982 total_size = d + tregs_space;
05983 total_size += rounded_frame_size (total_size);
05984 save_size = total_size - rounded_frame_size (d);
05985 if (save_size % (STACK_BOUNDARY / BITS_PER_UNIT))
05986 d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT)
05987 - save_size % (STACK_BOUNDARY / BITS_PER_UNIT));
05988
05989
05990
05991
05992
05993 if (TARGET_SHMEDIA
05994 && (CONST_OK_FOR_I10 (-total_size)
05995 || (! CONST_OK_FOR_I10 (-(save_size + d_rounding))
05996 && total_size <= 2044)))
05997 d_rounding = total_size - save_size;
05998
05999 offset_base = d + d_rounding;
06000
06001 output_stack_adjust (-(save_size + d_rounding), stack_pointer_rtx,
06002 0, NULL);
06003
06004 sh5_schedule_saves (&live_regs_mask, &schedule, offset_base);
06005 tmp_pnt = schedule.temps;
06006 for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++)
06007 {
06008 enum machine_mode mode = entry->mode;
06009 unsigned int reg = entry->reg;
06010 rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX;
06011 rtx orig_reg_rtx;
06012
06013 offset = entry->offset;
06014
06015 reg_rtx = gen_rtx_REG (mode, reg);
06016
06017 mem_rtx = gen_frame_mem (mode,
06018 gen_rtx_PLUS (Pmode,
06019 stack_pointer_rtx,
06020 GEN_INT (offset)));
06021
06022 GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec);
06023
06024 gcc_assert (r0);
06025 mem_rtx = NULL_RTX;
06026
06027 try_pre_dec:
06028 do
06029 if (HAVE_PRE_DECREMENT
06030 && (offset_in_r0 - offset == GET_MODE_SIZE (mode)
06031 || mem_rtx == NULL_RTX
06032 || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
06033 {
06034 pre_dec = gen_frame_mem (mode, gen_rtx_PRE_DEC (Pmode, r0));
06035
06036 GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0),
06037 pre_dec_ok);
06038
06039 pre_dec = NULL_RTX;
06040
06041 break;
06042
06043 pre_dec_ok:
06044 mem_rtx = NULL_RTX;
06045 offset += GET_MODE_SIZE (mode);
06046 }
06047 while (0);
06048
06049 if (mem_rtx != NULL_RTX)
06050 goto addr_ok;
06051
06052 if (offset_in_r0 == -1)
06053 {
06054 emit_move_insn (r0, GEN_INT (offset));
06055 offset_in_r0 = offset;
06056 }
06057 else if (offset != offset_in_r0)
06058 {
06059 emit_move_insn (r0,
06060 gen_rtx_PLUS
06061 (Pmode, r0,
06062 GEN_INT (offset - offset_in_r0)));
06063 offset_in_r0 += offset - offset_in_r0;
06064 }
06065
06066 if (pre_dec != NULL_RTX)
06067 {
06068 if (! sp_in_r0)
06069 {
06070 emit_move_insn (r0,
06071 gen_rtx_PLUS
06072 (Pmode, r0, stack_pointer_rtx));
06073 sp_in_r0 = 1;
06074 }
06075
06076 offset -= GET_MODE_SIZE (mode);
06077 offset_in_r0 -= GET_MODE_SIZE (mode);
06078
06079 mem_rtx = pre_dec;
06080 }
06081 else if (sp_in_r0)
06082 mem_rtx = gen_frame_mem (mode, r0);
06083 else
06084 mem_rtx = gen_frame_mem (mode,
06085 gen_rtx_PLUS (Pmode,
06086 stack_pointer_rtx,
06087 r0));
06088
06089
06090
06091
06092
06093 gcc_assert (!TARGET_REGISTER_P (reg)
06094 && ((reg != PR_REG && !SPECIAL_REGISTER_P (reg))
06095 || mem_rtx == pre_dec));
06096
06097 addr_ok:
06098 orig_reg_rtx = reg_rtx;
06099 if (TARGET_REGISTER_P (reg)
06100 || ((reg == PR_REG || SPECIAL_REGISTER_P (reg))
06101 && mem_rtx != pre_dec))
06102 {
06103 rtx tmp_reg = gen_rtx_REG (GET_MODE (reg_rtx), *tmp_pnt);
06104
06105 emit_move_insn (tmp_reg, reg_rtx);
06106
06107 if (REGNO (tmp_reg) == R0_REG)
06108 {
06109 offset_in_r0 = -1;
06110 sp_in_r0 = 0;
06111 gcc_assert (!refers_to_regno_p
06112 (R0_REG, R0_REG+1, mem_rtx, (rtx *) 0));
06113 }
06114
06115 if (*++tmp_pnt <= 0)
06116 tmp_pnt = schedule.temps;
06117
06118 reg_rtx = tmp_reg;
06119 }
06120 {
06121 rtx insn;
06122
06123
06124 insn = emit_move_insn (mem_rtx, reg_rtx);
06125 RTX_FRAME_RELATED_P (insn) = 1;
06126
06127
06128
06129
06130
06131
06132
06133 if (REGNO (reg_rtx) != reg)
06134 {
06135 rtx set, note_rtx;
06136
06137 set = gen_rtx_SET (VOIDmode, mem_rtx, orig_reg_rtx);
06138 note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set,
06139 REG_NOTES (insn));
06140 REG_NOTES (insn) = note_rtx;
06141 }
06142
06143 if (TARGET_SHCOMPACT && (offset_in_r0 != -1))
06144 {
06145 rtx reg_rtx = gen_rtx_REG (mode, reg);
06146 rtx set, note_rtx;
06147 rtx mem_rtx = gen_frame_mem (mode,
06148 gen_rtx_PLUS (Pmode,
06149 stack_pointer_rtx,
06150 GEN_INT (offset)));
06151
06152 set = gen_rtx_SET (VOIDmode, mem_rtx, reg_rtx);
06153 note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set,
06154 REG_NOTES (insn));
06155 REG_NOTES (insn) = note_rtx;
06156 }
06157 }
06158 }
06159
06160 gcc_assert (entry->offset == d_rounding);
06161 }
06162 else
06163 push_regs (&live_regs_mask, current_function_interrupt);
06164
06165 if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
06166 {
06167 rtx insn = get_last_insn ();
06168 rtx last = emit_insn (gen_GOTaddr2picreg ());
06169
06170
06171
06172
06173 do
06174 {
06175 insn = NEXT_INSN (insn);
06176
06177 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
06178 const0_rtx,
06179 REG_NOTES (insn));
06180 }
06181 while (insn != last);
06182 }
06183
06184 if (SHMEDIA_REGS_STACK_ADJUST ())
06185 {
06186
06187
06188 function_symbol (gen_rtx_REG (Pmode, R0_REG),
06189 (TARGET_FPU_ANY
06190 ? "__GCC_push_shmedia_regs"
06191 : "__GCC_push_shmedia_regs_nofpu"), SFUNC_GOT);
06192 emit_insn (gen_shmedia_save_restore_regs_compact
06193 (GEN_INT (-SHMEDIA_REGS_STACK_ADJUST ())));
06194 }
06195
06196 if (target_flags != save_flags && ! current_function_interrupt)
06197 {
06198 rtx insn = emit_insn (gen_toggle_sz ());
06199
06200
06201
06202
06203 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
06204 const0_rtx,
06205 REG_NOTES (insn));
06206 }
06207
06208 target_flags = save_flags;
06209
06210 output_stack_adjust (-rounded_frame_size (d) + d_rounding,
06211 stack_pointer_rtx, 0, NULL);
06212
06213 if (frame_pointer_needed)
06214 frame_insn (GEN_MOV (hard_frame_pointer_rtx, stack_pointer_rtx));
06215
06216 if (TARGET_SHCOMPACT
06217 && (current_function_args_info.call_cookie & ~ CALL_COOKIE_RET_TRAMP(1)))
06218 {
06219
06220
06221 function_symbol (gen_rtx_REG (Pmode, R0_REG),
06222 "__GCC_shcompact_incoming_args", SFUNC_GOT);
06223 emit_insn (gen_shcompact_incoming_args ());
06224 }
06225 }
06226
06227 void
06228 sh_expand_epilogue (bool sibcall_p)
06229 {
06230 HARD_REG_SET live_regs_mask;
06231 int d, i;
06232 int d_rounding = 0;
06233
06234 int save_flags = target_flags;
06235 int frame_size, save_size;
06236 int fpscr_deferred = 0;
06237 int e = sibcall_p ? -1 : 1;
06238
06239 d = calc_live_regs (&live_regs_mask);
06240
06241 save_size = d;
06242 frame_size = rounded_frame_size (d);
06243
06244 if (TARGET_SH5)
06245 {
06246 int tregs_space = shmedia_target_regs_stack_adjust (&live_regs_mask);
06247 int total_size;
06248 if (d % (STACK_BOUNDARY / BITS_PER_UNIT))
06249 d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT)
06250 - d % (STACK_BOUNDARY / BITS_PER_UNIT));
06251
06252 total_size = d + tregs_space;
06253 total_size += rounded_frame_size (total_size);
06254 save_size = total_size - frame_size;
06255
06256
06257
06258
06259
06260 if (TARGET_SHMEDIA
06261 && ! frame_pointer_needed
06262 && (CONST_OK_FOR_I10 (total_size)
06263 || (! CONST_OK_FOR_I10 (save_size + d_rounding)
06264 && total_size <= 2044)))
06265 d_rounding = frame_size;
06266
06267 frame_size -= d_rounding;
06268 }
06269
06270 if (frame_pointer_needed)
06271 {
06272
06273
06274 if (flag_exceptions)
06275 emit_insn (gen_blockage ());
06276 output_stack_adjust (frame_size, hard_frame_pointer_rtx, e,
06277 &live_regs_mask);
06278
06279
06280
06281
06282
06283 emit_insn (gen_blockage ());
06284 emit_insn (GEN_MOV (stack_pointer_rtx, hard_frame_pointer_rtx));
06285 }
06286 else if (frame_size)
06287 {
06288
06289
06290
06291
06292 emit_insn (gen_blockage ());
06293 output_stack_adjust (frame_size, stack_pointer_rtx, e, &live_regs_mask);
06294 }
06295
06296 if (SHMEDIA_REGS_STACK_ADJUST ())
06297 {
06298 function_symbol (gen_rtx_REG (Pmode, R0_REG),
06299 (TARGET_FPU_ANY
06300 ? "__GCC_pop_shmedia_regs"
06301 : "__GCC_pop_shmedia_regs_nofpu"), SFUNC_GOT);
06302
06303
06304 emit_insn (gen_shmedia_save_restore_regs_compact
06305 (GEN_INT (SHMEDIA_REGS_STACK_ADJUST ())));
06306 }
06307
06308
06309
06310 if (target_flags != save_flags && ! current_function_interrupt)
06311 emit_insn (gen_toggle_sz ());
06312 if (TARGET_SH5)
06313 {
06314 int offset_base, offset;
06315 int offset_in_r0 = -1;
06316 int sp_in_r0 = 0;
06317 rtx r0 = gen_rtx_REG (Pmode, R0_REG);
06318 save_schedule schedule;
06319 save_entry *entry;
06320 int *tmp_pnt;
06321
06322 entry = sh5_schedule_saves (&live_regs_mask, &schedule, d_rounding);
06323 offset_base = -entry[1].offset + d_rounding;
06324 tmp_pnt = schedule.temps;
06325 for (; entry->mode != VOIDmode; entry--)
06326 {
06327 enum machine_mode mode = entry->mode;
06328 int reg = entry->reg;
06329 rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn;
06330
06331 offset = offset_base + entry->offset;
06332 reg_rtx = gen_rtx_REG (mode, reg);
06333
06334 mem_rtx = gen_frame_mem (mode,
06335 gen_rtx_PLUS (Pmode,
06336 stack_pointer_rtx,
06337 GEN_INT (offset)));
06338
06339 GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc);
06340
06341 mem_rtx = NULL_RTX;
06342
06343 try_post_inc:
06344 do
06345 if (HAVE_POST_INCREMENT
06346 && (offset == offset_in_r0
06347 || (offset + GET_MODE_SIZE (mode) != d + d_rounding
06348 && mem_rtx == NULL_RTX)
06349 || reg == PR_REG || SPECIAL_REGISTER_P (reg)))
06350 {
06351 post_inc = gen_frame_mem (mode, gen_rtx_POST_INC (Pmode, r0));
06352
06353 GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0),
06354 post_inc_ok);
06355
06356 post_inc = NULL_RTX;
06357
06358 break;
06359
06360 post_inc_ok:
06361 mem_rtx = NULL_RTX;
06362 }
06363 while (0);
06364
06365 if (mem_rtx != NULL_RTX)
06366 goto addr_ok;
06367
06368 if (offset_in_r0 == -1)
06369 {
06370 emit_move_insn (r0, GEN_INT (offset));
06371 offset_in_r0 = offset;
06372 }
06373 else if (offset != offset_in_r0)
06374 {
06375 emit_move_insn (r0,
06376 gen_rtx_PLUS
06377 (Pmode, r0,
06378 GEN_INT (offset - offset_in_r0)));
06379 offset_in_r0 += offset - offset_in_r0;
06380 }
06381
06382 if (post_inc != NULL_RTX)
06383 {
06384 if (! sp_in_r0)
06385 {
06386 emit_move_insn (r0,
06387 gen_rtx_PLUS
06388 (Pmode, r0, stack_pointer_rtx));
06389 sp_in_r0 = 1;
06390 }
06391
06392 mem_rtx = post_inc;
06393
06394 offset_in_r0 += GET_MODE_SIZE (mode);
06395 }
06396 else if (sp_in_r0)
06397 mem_rtx = gen_frame_mem (mode, r0);
06398 else
06399 mem_rtx = gen_frame_mem (mode,
06400 gen_rtx_PLUS (Pmode,
06401 stack_pointer_rtx,
06402 r0));
06403
06404 gcc_assert ((reg != PR_REG && !SPECIAL_REGISTER_P (reg))
06405 || mem_rtx == post_inc);
06406
06407 addr_ok:
06408 if ((reg == PR_REG || SPECIAL_REGISTER_P (reg))
06409 && mem_rtx != post_inc)
06410 {
06411 insn = emit_move_insn (r0, mem_rtx);
06412 mem_rtx = r0;
06413 }
06414 else if (TARGET_REGISTER_P (reg))
06415 {
06416 rtx tmp_reg = gen_rtx_REG (mode, *tmp_pnt);
06417
06418
06419
06420 insn = emit_move_insn (tmp_reg, mem_rtx);
06421 mem_rtx = tmp_reg;
06422 if (*++tmp_pnt < 0)
06423 tmp_pnt = schedule.temps;
06424 }
06425
06426 insn = emit_move_insn (reg_rtx, mem_rtx);
06427 if (reg == PR_MEDIA_REG && sh_media_register_for_return () >= 0)
06428
06429 REG_NOTES (insn) = gen_rtx_EXPR_LIST (REG_MAYBE_DEAD,
06430 const0_rtx,
06431 REG_NOTES (insn));
06432 }
06433
06434 gcc_assert (entry->offset + offset_base == d + d_rounding);
06435 }
06436 else
06437 {
06438 save_size = 0;
06439 if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
06440 pop (PR_REG);
06441 for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
06442 {
06443 int j = (FIRST_PSEUDO_REGISTER - 1) - i;
06444
06445 if (j == FPSCR_REG && current_function_interrupt && TARGET_FMOVD
06446 && hard_regs_intersect_p (&live_regs_mask,
06447 ®_class_contents[DF_REGS]))
06448 fpscr_deferred = 1;
06449 else if (j != PR_REG && TEST_HARD_REG_BIT (live_regs_mask, j))
06450 pop (j);
06451 if (j == FIRST_FP_REG && fpscr_deferred)
06452 pop (FPSCR_REG);
06453
06454 }
06455 }
06456 if (target_flags != save_flags && ! current_function_interrupt)
06457 emit_insn (gen_toggle_sz ());
06458 target_flags = save_flags;
06459
06460 output_stack_adjust (current_function_pretend_args_size
06461 + save_size + d_rounding
06462 + current_function_args_info.stack_regs * 8,
06463 stack_pointer_rtx, e, NULL);
06464
06465 if (current_function_calls_eh_return)
06466 emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx,
06467 EH_RETURN_STACKADJ_RTX));
06468
06469
06470 if (lookup_attribute ("sp_switch", DECL_ATTRIBUTES (current_function_decl)))
06471 emit_insn (gen_sp_switch_2 ());
06472
06473
06474
06475
06476
06477 if (TEST_HARD_REG_BIT (live_regs_mask, PR_REG))
06478 emit_insn (gen_rtx_USE (VOIDmode, gen_rtx_REG (SImode, PR_REG)));
06479 }
06480
06481 static int sh_need_epilogue_known = 0;
06482
06483 int
06484 sh_need_epilogue (void)
06485 {
06486 if (! sh_need_epilogue_known)
06487 {
06488 rtx epilogue;
06489
06490 start_sequence ();
06491 sh_expand_epilogue (0);
06492 epilogue = get_insns ();
06493 end_sequence ();
06494 sh_need_epilogue_known = (epilogue == NULL ? -1 : 1);
06495 }
06496 return sh_need_epilogue_known > 0;
06497 }
06498
06499
06500
06501
06502 void
06503 sh_set_return_address (rtx ra, rtx tmp)
06504 {
06505 HARD_REG_SET live_regs_mask;
06506 int d;
06507 int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
06508 int pr_offset;
06509
06510 d = calc_live_regs (&live_regs_mask);
06511
06512
06513
06514 if (! TEST_HARD_REG_BIT (live_regs_mask, pr_reg))
06515 {
06516 rtx rr;
06517
06518 if (TARGET_SHMEDIA)
06519 {
06520 int rr_regno = sh_media_register_for_return ();
06521
06522 if (rr_regno < 0)
06523 rr_regno = pr_reg;
06524
06525 rr = gen_rtx_REG (DImode, rr_regno);
06526 }
06527 else
06528 rr = gen_rtx_REG (SImode, pr_reg);
06529
06530 emit_insn (GEN_MOV (rr, ra));
06531
06532 emit_insn (gen_rtx_USE (VOIDmode, rr));
06533 return;
06534 }
06535
06536 if (TARGET_SH5)
06537 {
06538 int offset;
06539 save_schedule schedule;
06540 save_entry *entry;
06541
06542 entry = sh5_schedule_saves (&live_regs_mask, &schedule, 0);
06543 offset = entry[1].offset;
06544 for (; entry->mode != VOIDmode; entry--)
06545 if (entry->reg == pr_reg)
06546 goto found;
06547
06548
06549 gcc_unreachable ();
06550
06551 found:
06552 offset = entry->offset - offset;
06553 pr_offset = (rounded_frame_size (d) + offset
06554 + SHMEDIA_REGS_STACK_ADJUST ());
06555 }
06556 else
06557 pr_offset = rounded_frame_size (d);
06558
06559 emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset)));
06560 emit_insn (GEN_ADD3 (tmp, tmp, hard_frame_pointer_rtx));
06561
06562 tmp = gen_frame_mem (Pmode, tmp);
06563 emit_insn (GEN_MOV (tmp, ra));
06564 }
06565
06566
06567
06568 static void
06569 sh_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
06570 HOST_WIDE_INT size ATTRIBUTE_UNUSED)
06571 {
06572 sh_need_epilogue_known = 0;
06573 }
06574
06575 static rtx
06576 sh_builtin_saveregs (void)
06577 {
06578
06579 int first_intreg = current_function_args_info.arg_count[(int) SH_ARG_INT];
06580
06581 int n_intregs = MAX (0, NPARM_REGS (SImode) - first_intreg);
06582
06583 int first_floatreg = current_function_args_info.arg_count[(int) SH_ARG_FLOAT];
06584
06585 int n_floatregs = MAX (0, NPARM_REGS (SFmode) - first_floatreg);
06586 rtx regbuf, fpregs;
06587 int bufsize, regno;
06588 HOST_WIDE_INT alias_set;
06589
06590 if (TARGET_SH5)
06591 {
06592 if (n_intregs)
06593 {
06594 int pushregs = n_intregs;
06595
06596 while (pushregs < NPARM_REGS (SImode) - 1
06597 && (CALL_COOKIE_INT_REG_GET
06598 (current_function_args_info.call_cookie,
06599 NPARM_REGS (SImode) - pushregs)
06600 == 1))
06601 {
06602 current_function_args_info.call_cookie
06603 &= ~ CALL_COOKIE_INT_REG (NPARM_REGS (SImode)
06604 - pushregs, 1);
06605 pushregs++;
06606 }
06607
06608 if (pushregs == NPARM_REGS (SImode))
06609 current_function_args_info.call_cookie
06610 |= (CALL_COOKIE_INT_REG (0, 1)
06611 | CALL_COOKIE_STACKSEQ (pushregs - 1));
06612 else
06613 current_function_args_info.call_cookie
06614 |= CALL_COOKIE_STACKSEQ (pushregs);
06615
06616 current_function_pretend_args_size += 8 * n_intregs;
06617 }
06618 if (TARGET_SHCOMPACT)
06619 return const0_rtx;
06620 }
06621
06622 if (! TARGET_SH2E && ! TARGET_SH4 && ! TARGET_SH5)
06623 {
06624 error ("__builtin_saveregs not supported by this subtarget");
06625 return const0_rtx;
06626 }
06627
06628 if (TARGET_SHMEDIA)
06629 n_floatregs = 0;
06630
06631
06632
06633
06634 bufsize = (n_intregs * UNITS_PER_WORD) + (n_floatregs * UNITS_PER_WORD);
06635
06636 if (TARGET_SHMEDIA)
06637 regbuf = gen_frame_mem (BLKmode, gen_rtx_REG (Pmode, ARG_POINTER_REGNUM));
06638 else if (n_floatregs & 1)
06639 {
06640 rtx addr;
06641
06642 regbuf = assign_stack_local (BLKmode, bufsize + UNITS_PER_WORD, 0);
06643 addr = copy_to_mode_reg (Pmode, XEXP (regbuf, 0));
06644 emit_insn (gen_iorsi3 (addr, addr, GEN_INT (UNITS_PER_WORD)));
06645 regbuf = change_address (regbuf, BLKmode, addr);
06646 }
06647 else if (STACK_BOUNDARY < 64 && TARGET_FPU_DOUBLE && n_floatregs)
06648 {
06649 rtx addr, mask;
06650
06651 regbuf = assign_stack_local (BLKmode, bufsize + UNITS_PER_WORD, 0);
06652 addr = copy_to_mode_reg (Pmode, plus_constant (XEXP (regbuf, 0), 4));
06653 mask = copy_to_mode_reg (Pmode, GEN_INT (-8));
06654 emit_insn (gen_andsi3 (addr, addr, mask));
06655 regbuf = change_address (regbuf, BLKmode, addr);
06656 }
06657 else
06658 regbuf = assign_stack_local (BLKmode, bufsize, TARGET_FPU_DOUBLE ? 64 : 0);
06659 alias_set = get_varargs_alias_set ();
06660 set_mem_alias_set (regbuf, alias_set);
06661
06662
06663
06664
06665 if (n_intregs > 0)
06666 move_block_from_reg (BASE_ARG_REG (SImode) + first_intreg,
06667 adjust_address (regbuf, BLKmode,
06668 n_floatregs * UNITS_PER_WORD),
06669 n_intregs);
06670
06671 if (TARGET_SHMEDIA)
06672
06673 return XEXP (regbuf, 0);
06674
06675
06676
06677
06678
06679
06680
06681
06682
06683 fpregs = copy_to_mode_reg (Pmode,
06684 plus_constant (XEXP (regbuf, 0),
06685 n_floatregs * UNITS_PER_WORD));
06686 if (TARGET_SH4 || TARGET_SH2A_DOUBLE)
06687 {
06688 rtx mem;
06689 for (regno = NPARM_REGS (DFmode) - 2; regno >= first_floatreg; regno -= 2)
06690 {
06691 emit_insn (gen_addsi3 (fpregs, fpregs,
06692 GEN_INT (-2 * UNITS_PER_WORD)));
06693 mem = change_address (regbuf, DFmode, fpregs);
06694 emit_move_insn (mem,
06695 gen_rtx_REG (DFmode, BASE_ARG_REG (DFmode) + regno));
06696 }
06697 regno = first_floatreg;
06698 if (regno & 1)
06699 {
06700 emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (-UNITS_PER_WORD)));
06701 mem = change_address (regbuf, SFmode, fpregs);
06702 emit_move_insn (mem,
06703 gen_rtx_REG (SFmode, BASE_ARG_REG (SFmode) + regno
06704 - (TARGET_LITTLE_ENDIAN != 0)));
06705 }
06706 }
06707 else
06708 for (regno = NPARM_REGS (SFmode) - 1; regno >= first_floatreg; regno--)
06709 {
06710 rtx mem;
06711
06712 emit_insn (gen_addsi3 (fpregs, fpregs, GEN_INT (-UNITS_PER_WORD)));
06713 mem = change_address (regbuf, SFmode, fpregs);
06714 emit_move_insn (mem,
06715 gen_rtx_REG (SFmode, BASE_ARG_REG (SFmode) + regno));
06716 }
06717
06718
06719 return XEXP (regbuf, 0);
06720 }
06721
06722
06723
06724 static tree
06725 sh_build_builtin_va_list (void)
06726 {
06727 tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack;
06728 tree record;
06729
06730 if (TARGET_SH5 || (! TARGET_SH2E && ! TARGET_SH4)
06731 || TARGET_HITACHI || sh_cfun_attr_renesas_p ())
06732 return ptr_type_node;
06733
06734 record = (*lang_hooks.types.make_type) (RECORD_TYPE);
06735
06736 f_next_o = build_decl (FIELD_DECL, get_identifier ("__va_next_o"),
06737 ptr_type_node);
06738 f_next_o_limit = build_decl (FIELD_DECL,
06739 get_identifier ("__va_next_o_limit"),
06740 ptr_type_node);
06741 f_next_fp = build_decl (FIELD_DECL, get_identifier ("__va_next_fp"),
06742 ptr_type_node);
06743 f_next_fp_limit = build_decl (FIELD_DECL,
06744 get_identifier ("__va_next_fp_limit"),
06745 ptr_type_node);
06746 f_next_stack = build_decl (FIELD_DECL, get_identifier ("__va_next_stack"),
06747 ptr_type_node);
06748
06749 DECL_FIELD_CONTEXT (f_next_o) = record;
06750 DECL_FIELD_CONTEXT (f_next_o_limit) = record;
06751 DECL_FIELD_CONTEXT (f_next_fp) = record;
06752 DECL_FIELD_CONTEXT (f_next_fp_limit) = record;
06753 DECL_FIELD_CONTEXT (f_next_stack) = record;
06754
06755 TYPE_FIELDS (record) = f_next_o;
06756 TREE_CHAIN (f_next_o) = f_next_o_limit;
06757 TREE_CHAIN (f_next_o_limit) = f_next_fp;
06758 TREE_CHAIN (f_next_fp) = f_next_fp_limit;
06759 TREE_CHAIN (f_next_fp_limit) = f_next_stack;
06760
06761 layout_type (record);
06762
06763 return record;
06764 }
06765
06766
06767
06768 void
06769 sh_va_start (tree valist, rtx nextarg)
06770 {
06771 tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack;
06772 tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack;
06773 tree t, u;
06774 int nfp, nint;
06775
06776 if (TARGET_SH5)
06777 {
06778 expand_builtin_saveregs ();
06779 std_expand_builtin_va_start (valist, nextarg);
06780 return;
06781 }
06782
06783 if ((! TARGET_SH2E && ! TARGET_SH4)
06784 || TARGET_HITACHI || sh_cfun_attr_renesas_p ())
06785 {
06786 std_expand_builtin_va_start (valist, nextarg);
06787 return;
06788 }
06789
06790 f_next_o = TYPE_FIELDS (va_list_type_node);
06791 f_next_o_limit = TREE_CHAIN (f_next_o);
06792 f_next_fp = TREE_CHAIN (f_next_o_limit);
06793 f_next_fp_limit = TREE_CHAIN (f_next_fp);
06794 f_next_stack = TREE_CHAIN (f_next_fp_limit);
06795
06796 next_o = build3 (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
06797 NULL_TREE);
06798 next_o_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
06799 valist, f_next_o_limit, NULL_TREE);
06800 next_fp = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp), valist, f_next_fp,
06801 NULL_TREE);
06802 next_fp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
06803 valist, f_next_fp_limit, NULL_TREE);
06804 next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack),
06805 valist, f_next_stack, NULL_TREE);
06806
06807
06808 u = make_tree (ptr_type_node, expand_builtin_saveregs ());
06809 t = build2 (MODIFY_EXPR, ptr_type_node, next_fp, u);
06810 TREE_SIDE_EFFECTS (t) = 1;
06811 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
06812
06813 nfp = current_function_args_info.arg_count[SH_ARG_FLOAT];
06814 if (nfp < 8)
06815 nfp = 8 - nfp;
06816 else
06817 nfp = 0;
06818 u = fold_build2 (PLUS_EXPR, ptr_type_node, u,
06819 build_int_cst (NULL_TREE, UNITS_PER_WORD * nfp));
06820 t = build2 (MODIFY_EXPR, ptr_type_node, next_fp_limit, u);
06821 TREE_SIDE_EFFECTS (t) = 1;
06822 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
06823
06824 t = build2 (MODIFY_EXPR, ptr_type_node, next_o, u);
06825 TREE_SIDE_EFFECTS (t) = 1;
06826 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
06827
06828 nint = current_function_args_info.arg_count[SH_ARG_INT];
06829 if (nint < 4)
06830 nint = 4 - nint;
06831 else
06832 nint = 0;
06833 u = fold_build2 (PLUS_EXPR, ptr_type_node, u,
06834 build_int_cst (NULL_TREE, UNITS_PER_WORD * nint));
06835 t = build2 (MODIFY_EXPR, ptr_type_node, next_o_limit, u);
06836 TREE_SIDE_EFFECTS (t) = 1;
06837 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
06838
06839 u = make_tree (ptr_type_node, nextarg);
06840 t = build2 (MODIFY_EXPR, ptr_type_node, next_stack, u);
06841 TREE_SIDE_EFFECTS (t) = 1;
06842 expand_expr (t, const0_rtx, VOIDmode, EXPAND_NORMAL);
06843 }
06844
06845
06846
06847 static tree
06848 find_sole_member (tree type)
06849 {
06850 tree field, member = NULL_TREE;
06851
06852 for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
06853 {
06854 if (TREE_CODE (field) != FIELD_DECL)
06855 continue;
06856 if (!DECL_SIZE (field))
06857 return NULL_TREE;
06858 if (integer_zerop (DECL_SIZE (field)))
06859 continue;
06860 if (member)
06861 return NULL_TREE;
06862 member = field;
06863 }
06864 return member;
06865 }
06866
06867
06868 static tree
06869 sh_gimplify_va_arg_expr (tree valist, tree type, tree *pre_p,
06870 tree *post_p ATTRIBUTE_UNUSED)
06871 {
06872 HOST_WIDE_INT size, rsize;
06873 tree tmp, pptr_type_node;
06874 tree addr, lab_over = NULL, result = NULL;
06875 int pass_by_ref = targetm.calls.must_pass_in_stack (TYPE_MODE (type), type);
06876 tree eff_type;
06877
06878 if (pass_by_ref)
06879 type = build_pointer_type (type);
06880
06881 size = int_size_in_bytes (type);
06882 rsize = (size + UNITS_PER_WORD - 1) & -UNITS_PER_WORD;
06883 pptr_type_node = build_pointer_type (ptr_type_node);
06884
06885 if (! TARGET_SH5 && (TARGET_SH2E || TARGET_SH4)
06886 && ! (TARGET_HITACHI || sh_cfun_attr_renesas_p ()))
06887 {
06888 tree f_next_o, f_next_o_limit, f_next_fp, f_next_fp_limit, f_next_stack;
06889 tree next_o, next_o_limit, next_fp, next_fp_limit, next_stack;
06890 int pass_as_float;
06891 tree lab_false;
06892 tree member;
06893
06894 f_next_o = TYPE_FIELDS (va_list_type_node);
06895 f_next_o_limit = TREE_CHAIN (f_next_o);
06896 f_next_fp = TREE_CHAIN (f_next_o_limit);
06897 f_next_fp_limit = TREE_CHAIN (f_next_fp);
06898 f_next_stack = TREE_CHAIN (f_next_fp_limit);
06899
06900 next_o = build3 (COMPONENT_REF, TREE_TYPE (f_next_o), valist, f_next_o,
06901 NULL_TREE);
06902 next_o_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_o_limit),
06903 valist, f_next_o_limit, NULL_TREE);
06904 next_fp = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp),
06905 valist, f_next_fp, NULL_TREE);
06906 next_fp_limit = build3 (COMPONENT_REF, TREE_TYPE (f_next_fp_limit),
06907 valist, f_next_fp_limit, NULL_TREE);
06908 next_stack = build3 (COMPONENT_REF, TREE_TYPE (f_next_stack),
06909 valist, f_next_stack, NULL_TREE);
06910
06911
06912
06913
06914 eff_type = type;
06915 while (TREE_CODE (eff_type) == RECORD_TYPE
06916 && (member = find_sole_member (eff_type))
06917 && (TREE_CODE (TREE_TYPE (member)) == REAL_TYPE
06918 || TREE_CODE (TREE_TYPE (member)) == COMPLEX_TYPE
06919 || TREE_CODE (TREE_TYPE (member)) == RECORD_TYPE))
06920 {
06921 tree field_type = TREE_TYPE (member);
06922
06923 if (TYPE_MODE (eff_type) == TYPE_MODE (field_type))
06924 eff_type = field_type;
06925 else
06926 {
06927 gcc_assert ((TYPE_ALIGN (eff_type)
06928 < GET_MODE_ALIGNMENT (TYPE_MODE (field_type)))
06929 || (TYPE_ALIGN (eff_type)
06930 > GET_MODE_BITSIZE (TYPE_MODE (field_type))));
06931 break;
06932 }
06933 }
06934
06935 if (TARGET_SH4)
06936 {
06937 pass_as_float = ((TREE_CODE (eff_type) == REAL_TYPE && size <= 8)
06938 || (TREE_CODE (eff_type) == COMPLEX_TYPE
06939 && TREE_CODE (TREE_TYPE (eff_type)) == REAL_TYPE
06940 && size <= 16));
06941 }
06942 else
06943 {
06944 pass_as_float = (TREE_CODE (eff_type) == REAL_TYPE && size == 4);
06945 }
06946
06947 addr = create_tmp_var (pptr_type_node, NULL);
06948 lab_false = create_artificial_label ();
06949 lab_over = create_artificial_label ();
06950
06951 valist = build1 (INDIRECT_REF, ptr_type_node, addr);
06952
06953 if (pass_as_float)
06954 {
06955 tree next_fp_tmp = create_tmp_var (TREE_TYPE (f_next_fp), NULL);
06956 tree cmp;
06957 bool is_double = size == 8 && TREE_CODE (eff_type) == REAL_TYPE;
06958
06959 tmp = build1 (ADDR_EXPR, pptr_type_node, next_fp);
06960 tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
06961 gimplify_and_add (tmp, pre_p);
06962
06963 tmp = build2 (MODIFY_EXPR, ptr_type_node, next_fp_tmp, valist);
06964 gimplify_and_add (tmp, pre_p);
06965 tmp = next_fp_limit;
06966 if (size > 4 && !is_double)
06967 tmp = build2 (PLUS_EXPR, TREE_TYPE (tmp), tmp,
06968 fold_convert (TREE_TYPE (tmp), size_int (4 - size)));
06969 tmp = build2 (GE_EXPR, boolean_type_node, next_fp_tmp, tmp);
06970 cmp = build3 (COND_EXPR, void_type_node, tmp,
06971 build1 (GOTO_EXPR, void_type_node, lab_false),
06972 NULL_TREE);
06973 if (!is_double)
06974 gimplify_and_add (cmp, pre_p);
06975
06976 if (TYPE_ALIGN (eff_type) > BITS_PER_WORD
06977 || (is_double || size == 16))
06978 {
06979 tmp = fold_convert (ptr_type_node, size_int (UNITS_PER_WORD));
06980 tmp = build2 (BIT_AND_EXPR, ptr_type_node, next_fp_tmp, tmp);
06981 tmp = build2 (PLUS_EXPR, ptr_type_node, next_fp_tmp, tmp);
06982 tmp = build2 (MODIFY_EXPR, ptr_type_node, next_fp_tmp, tmp);
06983 gimplify_and_add (tmp, pre_p);
06984 }
06985 if (is_double)
06986 gimplify_and_add (cmp, pre_p);
06987
06988 #ifdef FUNCTION_ARG_SCmode_WART
06989 if (TYPE_MODE (eff_type) == SCmode
06990 && TARGET_SH4 && TARGET_LITTLE_ENDIAN)
06991 {
06992 tree subtype = TREE_TYPE (eff_type);
06993 tree real, imag;
06994
06995 imag
06996 = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL);
06997 imag = get_initialized_tmp_var (imag, pre_p, NULL);
06998
06999 real
07000 = std_gimplify_va_arg_expr (next_fp_tmp, subtype, pre_p, NULL);
07001 real = get_initialized_tmp_var (real, pre_p, NULL);
07002
07003 result = build2 (COMPLEX_EXPR, type, real, imag);
07004 result = get_initialized_tmp_var (result, pre_p, NULL);
07005 }
07006 #endif
07007
07008 tmp = build1 (GOTO_EXPR, void_type_node, lab_over);
07009 gimplify_and_add (tmp, pre_p);
07010
07011 tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
07012 gimplify_and_add (tmp, pre_p);
07013
07014 tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack);
07015 tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
07016 gimplify_and_add (tmp, pre_p);
07017 tmp = build2 (MODIFY_EXPR, ptr_type_node, next_fp_tmp, valist);
07018 gimplify_and_add (tmp, pre_p);
07019
07020 tmp = build2 (MODIFY_EXPR, ptr_type_node, valist, next_fp_tmp);
07021 gimplify_and_add (tmp, post_p);
07022 valist = next_fp_tmp;
07023 }
07024 else
07025 {
07026 tmp = fold_convert (ptr_type_node, size_int (rsize));
07027 tmp = build2 (PLUS_EXPR, ptr_type_node, next_o, tmp);
07028 tmp = build2 (GT_EXPR, boolean_type_node, tmp, next_o_limit);
07029 tmp = build3 (COND_EXPR, void_type_node, tmp,
07030 build1 (GOTO_EXPR, void_type_node, lab_false),
07031 NULL_TREE);
07032 gimplify_and_add (tmp, pre_p);
07033
07034 tmp = build1 (ADDR_EXPR, pptr_type_node, next_o);
07035 tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
07036 gimplify_and_add (tmp, pre_p);
07037
07038 tmp = build1 (GOTO_EXPR, void_type_node, lab_over);
07039 gimplify_and_add (tmp, pre_p);
07040
07041 tmp = build1 (LABEL_EXPR, void_type_node, lab_false);
07042 gimplify_and_add (tmp, pre_p);
07043
07044 if (size > 4 && ! TARGET_SH4)
07045 {
07046 tmp = build2 (MODIFY_EXPR, ptr_type_node, next_o, next_o_limit);
07047 gimplify_and_add (tmp, pre_p);
07048 }
07049
07050 tmp = build1 (ADDR_EXPR, pptr_type_node, next_stack);
07051 tmp = build2 (MODIFY_EXPR, void_type_node, addr, tmp);
07052 gimplify_and_add (tmp, pre_p);
07053 }
07054
07055 if (!result)
07056 {
07057 tmp = build1 (LABEL_EXPR, void_type_node, lab_over);
07058 gimplify_and_add (tmp, pre_p);
07059 }
07060 }
07061
07062
07063
07064
07065 tmp = std_gimplify_va_arg_expr (valist, type, pre_p, NULL);
07066 if (result)
07067 {
07068 tmp = build2 (MODIFY_EXPR, void_type_node, result, tmp);
07069 gimplify_and_add (tmp, pre_p);
07070
07071 tmp = build1 (LABEL_EXPR, void_type_node, lab_over);
07072 gimplify_and_add (tmp, pre_p);
07073 }
07074 else
07075 result = tmp;
07076
07077 if (pass_by_ref)
07078 result = build_va_arg_indirect_ref (result);
07079
07080 return result;
07081 }
07082
07083 bool
07084 sh_promote_prototypes (tree type)
07085 {
07086 if (TARGET_HITACHI)
07087 return 0;
07088 if (! type)
07089 return 1;
07090 return ! sh_attr_renesas_p (type);
07091 }
07092
07093
07094
07095
07096
07097
07098 static int
07099 shcompact_byref (CUMULATIVE_ARGS *cum, enum machine_mode mode,
07100 tree type, bool named)
07101 {
07102 unsigned HOST_WIDE_INT size;
07103
07104 if (type)
07105 size = int_size_in_bytes (type);
07106 else
07107 size = GET_MODE_SIZE (mode);
07108
07109 if (cum->arg_count[SH_ARG_INT] < NPARM_REGS (SImode)
07110 && (!named
07111 || GET_SH_ARG_CLASS (mode) == SH_ARG_INT
07112 || (GET_SH_ARG_CLASS (mode) == SH_ARG_FLOAT
07113 && cum->arg_count[SH_ARG_FLOAT] >= NPARM_REGS (SFmode)))
07114 && size > 4
07115 && !SHCOMPACT_FORCE_ON_STACK (mode, type)
07116 && !SH5_WOULD_BE_PARTIAL_NREGS (*cum, mode, type, named))
07117 return size;
07118 else
07119 return 0;
07120 }
07121
07122 static bool
07123 sh_pass_by_reference (CUMULATIVE_ARGS *cum, enum machine_mode mode,
07124 tree type, bool named)
07125 {
07126 if (targetm.calls.must_pass_in_stack (mode, type))
07127 return true;
07128
07129
07130
07131
07132 if (! cum)
07133 return false;
07134
07135 if (TARGET_SHCOMPACT)
07136 {
07137 cum->byref = shcompact_byref (cum, mode, type, named);
07138 return cum->byref != 0;
07139