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