From fada196198e4c9350a78fe08c7a132bb4055ba05 Mon Sep 17 00:00:00 2001 From: "J\"orn Rennecke" Date: Wed, 16 Jul 2003 21:41:20 +0000 Subject: [PATCH] prologue / epilogue / warning patches: 2003-07-16 J"orn Rennecke Con Bradley * sh-protos.h (sh_get_pr_initial_val): Declare. * sh.c (regno_reg_class): Make its elements type enum reg_class. (output_stack_adjust): Remove emit_fn argument. Add epilogue_p and live_regs_mask arguments. Changed all callers. (save_schedule_s): New structure. (save_schedule): New typedef. (scavenge_reg, sh5_schedule_saves, sh5_schedule_saves): New functions. (calc_live_regs): For TARGET_SHMEDIA, use leaf_function_p. In interrupts handlers, also save registers that are usually partially saved, and make sure there is at least one general purpose register saved if a target register needs saving. Add casts in comparisons to avoid warnings. (sh_media_register_for_return): return -1 for interrupt handlers. (MAX_SAVED_REGS, MAX_TEMPS): New defines. (sh_expand_prologue): Use sh5_schedule_saves. Check that any temp registers used are available. Set RTX_FRAME_RELATED_P where appropriate. Add an REG_FRAME_RELATED_EXPR for r0 + offset addressing. (sh_expand_epilogue, sh_set_return_address): Use sh5_schedule_saves. (initial_elimination_offset): Likewise. * sh.h (DWARF_CIE_DATA_ALIGNMENT): Set to -4. (LOCAL_ALIGNMENT, GENERAL_REGISTER_P): Add casts to avoid warnings. (FP_REGISTER_P): Add casts to fix broken handling of unsigned REGNO. (XD_REGISTER_P, TARGET_REGISTER_P): Likewise. (HARD_REGNO_CALL_PART_CLOBBERED): Also yield nonzero for r15, and for target registers. (RETURN_IN_MEMORY): Add parentheses to avoid warnings. (regno_reg_class): Make its elements type enum reg_class. (CONSTRAINT_LEN): Don't use isdigit. (FUNCTION_ARG_REGNO_P): Add casts to avoid warnings. (FUNCTION_ARG): Add parentheses to avoid warnings. (RETURN_ADDR_RTX): Use sh_get_pr_initial_val. (RETURN_ADDR_OFFSET): Define to -1 for TARGET_SH5. (SH_DBX_REGISTER_NUMBER): Add casts to avoid warnings. (EH_RETURN_DATA_REGNO): Use unsigned constants to avoid warnings. * sh.md (xordi3+1): Remove unused variable regno. (return_media): Check that tr0 is available before using it. Co-Authored-By: Con Bradley From-SVN: r69480 --- gcc/ChangeLog | 41 ++ gcc/config/sh/sh-protos.h | 1 + gcc/config/sh/sh.c | 842 ++++++++++++++++++++++---------------- gcc/config/sh/sh.h | 75 ++-- gcc/config/sh/sh.md | 4 +- 5 files changed, 580 insertions(+), 383 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 973cb776277..40f776f66d9 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,44 @@ +2003-07-16 J"orn Rennecke + Con Bradley + + * sh-protos.h (sh_get_pr_initial_val): Declare. + * sh.c (regno_reg_class): Make its elements type enum reg_class. + (output_stack_adjust): Remove emit_fn argument. Add epilogue_p + and live_regs_mask arguments. Changed all callers. + (save_schedule_s): New structure. + (save_schedule): New typedef. + (scavenge_reg, sh5_schedule_saves, sh5_schedule_saves): New functions. + (calc_live_regs): For TARGET_SHMEDIA, use leaf_function_p. + In interrupts handlers, also save registers that are usually + partially saved, and make sure there is at least one general purpose + register saved if a target register needs saving. + Add casts in comparisons to avoid warnings. + (sh_media_register_for_return): return -1 for interrupt handlers. + (MAX_SAVED_REGS, MAX_TEMPS): New defines. + (sh_expand_prologue): Use sh5_schedule_saves. Check that any temp + registers used are available. + Set RTX_FRAME_RELATED_P where appropriate. + Add an REG_FRAME_RELATED_EXPR for r0 + offset addressing. + (sh_expand_epilogue, sh_set_return_address): Use sh5_schedule_saves. + (initial_elimination_offset): Likewise. + * sh.h (DWARF_CIE_DATA_ALIGNMENT): Set to -4. + (LOCAL_ALIGNMENT, GENERAL_REGISTER_P): Add casts to avoid warnings. + (FP_REGISTER_P): Add casts to fix broken handling of unsigned REGNO. + (XD_REGISTER_P, TARGET_REGISTER_P): Likewise. + (HARD_REGNO_CALL_PART_CLOBBERED): Also yield nonzero for r15, + and for target registers. + (RETURN_IN_MEMORY): Add parentheses to avoid warnings. + (regno_reg_class): Make its elements type enum reg_class. + (CONSTRAINT_LEN): Don't use isdigit. + (FUNCTION_ARG_REGNO_P): Add casts to avoid warnings. + (FUNCTION_ARG): Add parentheses to avoid warnings. + (RETURN_ADDR_RTX): Use sh_get_pr_initial_val. + (RETURN_ADDR_OFFSET): Define to -1 for TARGET_SH5. + (SH_DBX_REGISTER_NUMBER): Add casts to avoid warnings. + (EH_RETURN_DATA_REGNO): Use unsigned constants to avoid warnings. + * sh.md (xordi3+1): Remove unused variable regno. + (return_media): Check that tr0 is available before using it. + 2003-07-16 Neil Booth * c.opt: Document more options. diff --git a/gcc/config/sh/sh-protos.h b/gcc/config/sh/sh-protos.h index 10ef2e4a591..e046206dc39 100644 --- a/gcc/config/sh/sh-protos.h +++ b/gcc/config/sh/sh-protos.h @@ -136,5 +136,6 @@ extern void sh_pr_interrupt PARAMS ((struct cpp_reader *)); extern void sh_pr_trapa PARAMS ((struct cpp_reader *)); extern void sh_pr_nosave_low_regs PARAMS ((struct cpp_reader *)); extern rtx function_symbol (const char *); +extern rtx sh_get_pr_initial_val (void); #endif /* ! GCC_SH_PROTOS_H */ diff --git a/gcc/config/sh/sh.c b/gcc/config/sh/sh.c index ee8193c61b3..cc75c2f5899 100644 --- a/gcc/config/sh/sh.c +++ b/gcc/config/sh/sh.c @@ -108,7 +108,7 @@ rtx sh_compare_op1; /* Provides the class number of the smallest class containing reg number. */ -int regno_reg_class[FIRST_PSEUDO_REGISTER] = +enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER] = { R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, @@ -190,7 +190,7 @@ static rtx find_barrier PARAMS ((int, rtx, rtx)); static int noncall_uses_reg PARAMS ((rtx, rtx, rtx *)); static rtx gen_block_redirect PARAMS ((rtx, int, int)); static void sh_reorg PARAMS ((void)); -static void output_stack_adjust PARAMS ((int, rtx, int, rtx (*) (rtx))); +static void output_stack_adjust (int, rtx, int, HARD_REG_SET *); static rtx frame_insn PARAMS ((rtx)); static rtx push PARAMS ((int)); static void pop PARAMS ((int)); @@ -234,6 +234,10 @@ static int sh_address_cost PARAMS ((rtx)); static int shmedia_target_regs_stack_space (HARD_REG_SET *); static int shmedia_reserve_space_for_target_registers_p (int, HARD_REG_SET *); static int shmedia_target_regs_stack_adjust (HARD_REG_SET *); +static int scavenge_reg (HARD_REG_SET *s); +struct save_schedule_s; +static struct save_entry_s *sh5_schedule_saves (HARD_REG_SET *, + struct save_schedule_s *, int); /* Initialize the GCC target structure. */ #undef TARGET_ATTRIBUTE_TABLE @@ -4558,17 +4562,16 @@ output_jump_label_table () static int extra_push; -/* Adjust the stack by SIZE bytes. REG holds the rtl of the register - to be adjusted, and TEMP, if nonnegative, holds the register number - of a general register that we may clobber. */ +/* Adjust the stack by SIZE bytes. REG holds the rtl of the register to be + adjusted. If epilogue_p is zero, this is for a prologue; otherwise, it's + for an epilogue. If LIVE_REGS_MASK is nonzero, it points to a HARD_REG_SET + of all the registers that are about to be restored, and hence dead. */ static void -output_stack_adjust (size, reg, temp, emit_fn) - int size; - rtx reg; - int temp; - rtx (*emit_fn) PARAMS ((rtx)); +output_stack_adjust (int size, rtx reg, int epilogue_p, + HARD_REG_SET *live_regs_mask) { + rtx (*emit_fn) (rtx) = epilogue_p ? &emit_insn : &frame_insn; if (size) { HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT; @@ -4591,10 +4594,43 @@ output_stack_adjust (size, reg, temp, emit_fn) { rtx const_reg; rtx insn; + int temp = epilogue_p ? 7 : (TARGET_SH5 ? 0 : 1); + int i; /* If TEMP is invalid, we could temporarily save a general register to MACL. However, there is currently no need to handle this case, so just abort when we see it. */ + if (current_function_interrupt + || ! call_used_regs[temp] || fixed_regs[temp]) + temp = -1; + if (temp < 0 && ! current_function_interrupt) + { + HARD_REG_SET temps; + COPY_HARD_REG_SET (temps, call_used_reg_set); + AND_COMPL_HARD_REG_SET (temps, call_fixed_reg_set); + if (epilogue_p) + { + for (i = 0; i < HARD_REGNO_NREGS (FIRST_RET_REG, DImode); i++) + CLEAR_HARD_REG_BIT (temps, FIRST_RET_REG + i); + if (current_function_calls_eh_return) + { + CLEAR_HARD_REG_BIT (temps, EH_RETURN_STACKADJ_REGNO); + for (i = 0; i <= 3; i++) + CLEAR_HARD_REG_BIT (temps, EH_RETURN_DATA_REGNO (i)); + } + } + else + { + for (i = FIRST_PARM_REG; + i < FIRST_PARM_REG + NPARM_REGS (SImode); i++) + CLEAR_HARD_REG_BIT (temps, i); + if (current_function_needs_context) + CLEAR_HARD_REG_BIT (temps, STATIC_CHAIN_REGNUM); + } + temp = scavenge_reg (&temps); + } + if (temp < 0 && live_regs_mask) + temp = scavenge_reg (live_regs_mask); if (temp < 0) abort (); const_reg = gen_rtx_REG (GET_MODE (reg), temp); @@ -4612,7 +4648,7 @@ output_stack_adjust (size, reg, temp, emit_fn) emit_insn (GEN_MOV (const_reg, GEN_INT (size))); insn = emit_fn (GEN_ADD3 (reg, reg, const_reg)); } - if (emit_fn == frame_insn) + if (! epilogue_p) REG_NOTES (insn) = (gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, @@ -4789,12 +4825,11 @@ calc_live_regs (live_regs_mask) int reg; int count; int interrupt_handler; - int pr_live; + int pr_live, has_call; interrupt_handler = sh_cfun_interrupt_handler_p (); - for (count = 0; 32 * count < FIRST_PSEUDO_REGISTER; count++) - CLEAR_HARD_REG_SET (*live_regs_mask); + CLEAR_HARD_REG_SET (*live_regs_mask); if (TARGET_SH4 && TARGET_FMOVD && interrupt_handler && regs_ever_live[FPSCR_REG]) target_flags &= ~FPU_SINGLE_BIT; @@ -4829,16 +4864,19 @@ calc_live_regs (live_regs_mask) & ~ CALL_COOKIE_RET_TRAMP (1)) || current_function_has_nonlocal_label)) pr_live = 1; + has_call = TARGET_SHMEDIA ? ! leaf_function_p () : pr_live; for (count = 0, reg = FIRST_PSEUDO_REGISTER - 1; reg >= 0; reg--) { - if (reg == (TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG) + if ((! TARGET_SHMEDIA && reg == PR_REG) ? pr_live : (interrupt_handler && ! pragma_trapa) ? (/* Need to save all the regs ever live. */ (regs_ever_live[reg] || (call_used_regs[reg] && (! fixed_regs[reg] || reg == MACH_REG || reg == MACL_REG) - && pr_live)) + && has_call) + || (has_call && REGISTER_NATURAL_MODE (reg) == SImode + && (GENERAL_REGISTER_P (reg) || TARGET_REGISTER_P (reg)))) && reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM && reg != RETURN_ADDRESS_POINTER_REGNUM && reg != T_REG && reg != GBR_REG @@ -4848,13 +4886,13 @@ calc_live_regs (live_regs_mask) (TARGET_SHCOMPACT && flag_pic && current_function_args_info.call_cookie - && reg == PIC_OFFSET_TABLE_REGNUM) + && reg == (int) PIC_OFFSET_TABLE_REGNUM) || (regs_ever_live[reg] && ! call_used_regs[reg]) || (current_function_calls_eh_return - && (reg == EH_RETURN_DATA_REGNO (0) - || reg == EH_RETURN_DATA_REGNO (1) - || reg == EH_RETURN_DATA_REGNO (2) - || reg == EH_RETURN_DATA_REGNO (3))))) + && (reg == (int) EH_RETURN_DATA_REGNO (0) + || reg == (int) EH_RETURN_DATA_REGNO (1) + || reg == (int) EH_RETURN_DATA_REGNO (2) + || reg == (int) EH_RETURN_DATA_REGNO (3))))) { SET_HARD_REG_BIT (*live_regs_mask, reg); count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg)); @@ -4891,6 +4929,19 @@ calc_live_regs (live_regs_mask) SET_HARD_REG_BIT (*live_regs_mask, reg); count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg)); } + /* If this is an interrupt handler, we don't have any call-clobbered + registers we can conveniently use for target register save/restore. + Make sure we save at least one general purpose register when we need + to save target registers. */ + if (interrupt_handler + && hard_regs_intersect_p (live_regs_mask, + ®_class_contents[TARGET_REGS]) + && ! hard_regs_intersect_p (live_regs_mask, + ®_class_contents[GENERAL_REGS])) + { + SET_HARD_REG_BIT (*live_regs_mask, R0_REG); + count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (R0_REG)); + } return count; } @@ -4921,6 +4972,9 @@ sh_media_register_for_return () if (! current_function_is_leaf) return -1; + if (lookup_attribute ("interrupt_handler", + DECL_ATTRIBUTES (current_function_decl))) + return -1; tr0_used = flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]; @@ -4931,6 +4985,130 @@ sh_media_register_for_return () return -1; } +/* The maximum registers we need to save are: + - 62 general purpose registers (r15 is stack pointer, r63 is zero) + - 32 floating point registers (for each pair, we save none, + one single precision value, or a double precision value). + - 8 target registers + - add 1 entry for a delimiter. */ +#define MAX_SAVED_REGS (62+32+8) + +typedef struct save_entry_s +{ + unsigned char reg; + unsigned char mode; + short offset; +} save_entry; + +#define MAX_TEMPS 4 + +/* There will be a delimiter entry with VOIDmode both at the start and the + end of a filled in schedule. The end delimiter has the offset of the + save with the smallest (i.e. most negative) offset. */ +typedef struct save_schedule_s +{ + save_entry entries[MAX_SAVED_REGS + 2]; + int temps[MAX_TEMPS+1]; +} save_schedule; + +/* Fill in SCHEDULE according to LIVE_REGS_MASK. If RESTORE is nonzero, + use reverse order. Returns the last entry written to (not counting + the delimiter). OFFSET_BASE is a number to be added to all offset + entries. */ + +static save_entry * +sh5_schedule_saves (HARD_REG_SET *live_regs_mask, save_schedule *schedule, + int offset_base) +{ + int align, i; + save_entry *entry = schedule->entries; + int tmpx = 0; + int offset; + + if (! current_function_interrupt) + for (i = FIRST_GENERAL_REG; tmpx < MAX_TEMPS && i <= LAST_GENERAL_REG; i++) + if (call_used_regs[i] && ! fixed_regs[i] + && ! FUNCTION_ARG_REGNO_P (i) + && i != FIRST_RET_REG + && ! (current_function_needs_context && i == STATIC_CHAIN_REGNUM) + && ! (current_function_calls_eh_return + && (i == EH_RETURN_STACKADJ_REGNO + || ((unsigned)i <= EH_RETURN_DATA_REGNO (0) + && (unsigned)i >= EH_RETURN_DATA_REGNO (3))))) + schedule->temps[tmpx++] = i; + entry->reg = -1; + entry->mode = VOIDmode; + entry->offset = offset_base; + entry++; + /* We loop twice: first, we save 8-byte aligned registers in the + higher addresses, that are known to be aligned. Then, we + proceed to saving 32-bit registers that don't need 8-byte + alignment. + If this is an interrupt function, all registers that need saving + need to be saved in full. moreover, we need to postpone saving + target registers till we have saved some general purpose registers + we can then use as scratch registers. */ + offset = offset_base; + for (align = 1; align >= 0; align--) + { + for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) + if (TEST_HARD_REG_BIT (*live_regs_mask, i)) + { + enum machine_mode mode = REGISTER_NATURAL_MODE (i); + int reg = i; + + if (current_function_interrupt) + { + if (TARGET_REGISTER_P (i)) + continue; + if (GENERAL_REGISTER_P (i)) + mode = DImode; + } + if (mode == SFmode && (i % 2) == 1 + && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i) + && (TEST_HARD_REG_BIT (*live_regs_mask, (i ^ 1)))) + { + mode = DFmode; + i--; + reg--; + } + + /* If we're doing the aligned pass and this is not aligned, + or we're doing the unaligned pass and this is aligned, + skip it. */ + if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT) == 0) + != align) + continue; + + if (current_function_interrupt + && GENERAL_REGISTER_P (i) + && tmpx < MAX_TEMPS) + schedule->temps[tmpx++] = i; + + offset -= GET_MODE_SIZE (mode); + entry->reg = i; + entry->mode = mode; + entry->offset = offset; + entry++; + } + if (align && current_function_interrupt) + for (i = LAST_TARGET_REG; i >= FIRST_TARGET_REG; i--) + if (TEST_HARD_REG_BIT (*live_regs_mask, i)) + { + offset -= GET_MODE_SIZE (DImode); + entry->reg = i; + entry->mode = DImode; + entry->offset = offset; + entry++; + } + } + entry->reg = -1; + entry->mode = VOIDmode; + entry->offset = offset; + schedule->temps[tmpx] = -1; + return entry - 1; +} + void sh_expand_prologue () { @@ -4945,7 +5123,7 @@ sh_expand_prologue () and partially on the stack, e.g. a large structure. */ output_stack_adjust (-current_function_pretend_args_size - current_function_args_info.stack_regs * 8, - stack_pointer_rtx, TARGET_SH5 ? 0 : 1, frame_insn); + stack_pointer_rtx, 0, NULL); extra_push = 0; @@ -5034,14 +5212,19 @@ sh_expand_prologue () if (TARGET_SH5) { - int i; - int offset; - int align; - rtx r0 = gen_rtx_REG (Pmode, R0_REG); + int offset_base, offset; + rtx r0 = NULL_RTX; int offset_in_r0 = -1; int sp_in_r0 = 0; int tregs_space = shmedia_target_regs_stack_adjust (&live_regs_mask); int total_size, save_size; + save_schedule schedule; + save_entry *entry; + int *tmp_pnt; + + if (call_used_regs[R0_REG] && ! fixed_regs[R0_REG] + && ! current_function_interrupt) + r0 = gen_rtx_REG (Pmode, R0_REG); /* D is the actual number of bytes that we need for saving registers, however, in initial_elimination_offset we have committed to using @@ -5067,146 +5250,153 @@ sh_expand_prologue () && total_size <= 2044))) d_rounding = total_size - save_size; - offset = d + d_rounding; + offset_base = d + d_rounding; output_stack_adjust (-(save_size + d_rounding), stack_pointer_rtx, - 1, frame_insn); + 0, NULL); - /* We loop twice: first, we save 8-byte aligned registers in the - higher addresses, that are known to be aligned. Then, we - proceed to saving 32-bit registers that don't need 8-byte - alignment. */ - /* Note that if you change this code in a way that affects where - the return register is saved, you have to update not only - sh_expand_epilogue, but also sh_set_return_address. */ - for (align = 1; align >= 0; align--) - for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) - if (TEST_HARD_REG_BIT (live_regs_mask, i)) + sh5_schedule_saves (&live_regs_mask, &schedule, offset_base); + tmp_pnt = schedule.temps; + for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++) + { + enum machine_mode mode = entry->mode; + int reg = entry->reg; + rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX; + + offset = entry->offset; + + reg_rtx = gen_rtx_REG (mode, reg); + + mem_rtx = gen_rtx_MEM (mode, + gen_rtx_PLUS (Pmode, + stack_pointer_rtx, + GEN_INT (offset))); + + GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec); + + if (! r0) + abort (); + mem_rtx = NULL_RTX; + + try_pre_dec: + do + if (HAVE_PRE_DECREMENT + && (offset_in_r0 - offset == GET_MODE_SIZE (mode) + || mem_rtx == NULL_RTX + || reg == PR_REG || SPECIAL_REGISTER_P (reg))) + { + pre_dec = gen_rtx_MEM (mode, + gen_rtx_PRE_DEC (Pmode, r0)); + + GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0), + pre_dec_ok); + + pre_dec = NULL_RTX; + + break; + + pre_dec_ok: + mem_rtx = NULL_RTX; + offset += GET_MODE_SIZE (mode); + } + while (0); + + if (mem_rtx != NULL_RTX) + goto addr_ok; + + if (offset_in_r0 == -1) { - enum machine_mode mode = REGISTER_NATURAL_MODE (i); - int reg = i; - rtx reg_rtx, mem_rtx, pre_dec = NULL_RTX; - - if (mode == SFmode && (i % 2) == 1 - && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i) - && (TEST_HARD_REG_BIT (live_regs_mask, (i ^ 1)))) - { - mode = DFmode; - i--; - reg--; - } - - /* If we're doing the aligned pass and this is not aligned, - or we're doing the unaligned pass and this is aligned, - skip it. */ - if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT) - == 0) != align) - continue; - - offset -= GET_MODE_SIZE (mode); - - reg_rtx = gen_rtx_REG (mode, reg); - - mem_rtx = gen_rtx_MEM (mode, - gen_rtx_PLUS (Pmode, - stack_pointer_rtx, - GEN_INT (offset))); - - GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec); - - mem_rtx = NULL_RTX; - - try_pre_dec: - do - if (HAVE_PRE_DECREMENT - && (offset_in_r0 - offset == GET_MODE_SIZE (mode) - || mem_rtx == NULL_RTX - || i == PR_REG || SPECIAL_REGISTER_P (i))) - { - pre_dec = gen_rtx_MEM (mode, - gen_rtx_PRE_DEC (Pmode, r0)); - - GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0), - pre_dec_ok); - - pre_dec = NULL_RTX; - - break; - - pre_dec_ok: - mem_rtx = NULL_RTX; - offset += GET_MODE_SIZE (mode); - } - while (0); - - if (mem_rtx != NULL_RTX) - goto addr_ok; - - if (offset_in_r0 == -1) - { - emit_move_insn (r0, GEN_INT (offset)); - offset_in_r0 = offset; - } - else if (offset != offset_in_r0) + emit_move_insn (r0, GEN_INT (offset)); + offset_in_r0 = offset; + } + else if (offset != offset_in_r0) + { + emit_move_insn (r0, + gen_rtx_PLUS + (Pmode, r0, + GEN_INT (offset - offset_in_r0))); + offset_in_r0 += offset - offset_in_r0; + } + + if (pre_dec != NULL_RTX) + { + if (! sp_in_r0) { emit_move_insn (r0, gen_rtx_PLUS - (Pmode, r0, - GEN_INT (offset - offset_in_r0))); - offset_in_r0 += offset - offset_in_r0; + (Pmode, r0, stack_pointer_rtx)); + sp_in_r0 = 1; } - - if (pre_dec != NULL_RTX) + + offset -= GET_MODE_SIZE (mode); + offset_in_r0 -= GET_MODE_SIZE (mode); + + mem_rtx = pre_dec; + } + else if (sp_in_r0) + mem_rtx = gen_rtx_MEM (mode, r0); + else + mem_rtx = gen_rtx_MEM (mode, + gen_rtx_PLUS (Pmode, + stack_pointer_rtx, + r0)); + + /* We must not use an r0-based address for target-branch + registers or for special registers without pre-dec + memory addresses, since we store their values in r0 + first. */ + if (TARGET_REGISTER_P (reg) + || ((reg == PR_REG || SPECIAL_REGISTER_P (reg)) + && mem_rtx != pre_dec)) + abort (); + + addr_ok: + if (TARGET_REGISTER_P (reg) + || ((reg == PR_REG || SPECIAL_REGISTER_P (reg)) + && mem_rtx != pre_dec)) + { + rtx tmp_reg = gen_rtx_REG (GET_MODE (reg_rtx), *tmp_pnt); + + emit_move_insn (tmp_reg, reg_rtx); + + if (REGNO (tmp_reg) == R0_REG) { - if (! sp_in_r0) - { - emit_move_insn (r0, - gen_rtx_PLUS - (Pmode, r0, stack_pointer_rtx)); - sp_in_r0 = 1; - } - - offset -= GET_MODE_SIZE (mode); - offset_in_r0 -= GET_MODE_SIZE (mode); - - mem_rtx = pre_dec; - } - else if (sp_in_r0) - mem_rtx = gen_rtx_MEM (mode, r0); - else - mem_rtx = gen_rtx_MEM (mode, - gen_rtx_PLUS (Pmode, - stack_pointer_rtx, - r0)); - - /* We must not use an r0-based address for target-branch - registers or for special registers without pre-dec - memory addresses, since we store their values in r0 - first. */ - if (TARGET_REGISTER_P (i) - || ((i == PR_REG || SPECIAL_REGISTER_P (i)) - && mem_rtx != pre_dec)) - abort (); - - addr_ok: - if (TARGET_REGISTER_P (i) - || ((i == PR_REG || SPECIAL_REGISTER_P (i)) - && mem_rtx != pre_dec)) - { - rtx r0mode = gen_rtx_REG (GET_MODE (reg_rtx), R0_REG); - - emit_move_insn (r0mode, reg_rtx); - offset_in_r0 = -1; sp_in_r0 = 0; - - reg_rtx = r0mode; + if (refers_to_regno_p (R0_REG, R0_REG+1, mem_rtx, (rtx *) 0)) + abort (); } - emit_move_insn (mem_rtx, reg_rtx); - } + if (*++tmp_pnt <= 0) + tmp_pnt = schedule.temps; - if (offset != d_rounding) + reg_rtx = tmp_reg; + } + { + rtx insn; + + /* Mark as interesting for dwarf cfi generator */ + insn = emit_move_insn (mem_rtx, reg_rtx); + RTX_FRAME_RELATED_P (insn) = 1; + + if (TARGET_SHCOMPACT && (offset_in_r0 != -1)) + { + rtx reg_rtx = gen_rtx_REG (mode, reg); + rtx set, note_rtx; + rtx mem_rtx = gen_rtx_MEM (mode, + gen_rtx_PLUS (Pmode, + stack_pointer_rtx, + GEN_INT (offset))); + + set = gen_rtx_SET (VOIDmode, mem_rtx, reg_rtx); + note_rtx = gen_rtx_EXPR_LIST (REG_FRAME_RELATED_EXPR, set, + REG_NOTES (insn)); + REG_NOTES (insn) = note_rtx; + } + } + } + + if (entry->offset != d_rounding) abort (); } else @@ -5258,7 +5448,7 @@ sh_expand_prologue () target_flags = save_flags; output_stack_adjust (-rounded_frame_size (d) + d_rounding, - stack_pointer_rtx, TARGET_SH5 ? 0 : 1, frame_insn); + stack_pointer_rtx, 0, NULL); if (frame_pointer_needed) frame_insn (GEN_MOV (frame_pointer_rtx, stack_pointer_rtx)); @@ -5318,7 +5508,7 @@ sh_expand_epilogue () if (frame_pointer_needed) { - output_stack_adjust (frame_size, frame_pointer_rtx, 7, emit_insn); + output_stack_adjust (frame_size, frame_pointer_rtx, 1, &live_regs_mask); /* We must avoid moving the stack pointer adjustment past code which reads from the local frame, else an interrupt could @@ -5334,7 +5524,7 @@ sh_expand_epilogue () occur after the SP adjustment and clobber data in the local frame. */ emit_insn (gen_blockage ()); - output_stack_adjust (frame_size, stack_pointer_rtx, 7, emit_insn); + output_stack_adjust (frame_size, stack_pointer_rtx, 1, &live_regs_mask); } if (SHMEDIA_REGS_STACK_ADJUST ()) @@ -5355,143 +5545,126 @@ sh_expand_epilogue () emit_insn (gen_toggle_sz ()); if (TARGET_SH5) { - int offset = d_rounding; + int offset_base, offset; int offset_in_r0 = -1; int sp_in_r0 = 0; - int align; rtx r0 = gen_rtx_REG (Pmode, R0_REG); - int tmp_regno = R20_REG; + save_schedule schedule; + save_entry *entry; + int *tmp_pnt; - /* We loop twice: first, we save 8-byte aligned registers in the - higher addresses, that are known to be aligned. Then, we - proceed to saving 32-bit registers that don't need 8-byte - alignment. */ - for (align = 0; align <= 1; align++) - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (TEST_HARD_REG_BIT (live_regs_mask, i)) + entry = sh5_schedule_saves (&live_regs_mask, &schedule, d_rounding); + offset_base = -entry[1].offset + d_rounding; + tmp_pnt = schedule.temps; + for (; entry->mode != VOIDmode; entry--) + { + enum machine_mode mode = entry->mode; + int reg = entry->reg; + rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn; + + offset = offset_base + entry->offset; + reg_rtx = gen_rtx_REG (mode, reg); + + mem_rtx = gen_rtx_MEM (mode, + gen_rtx_PLUS (Pmode, + stack_pointer_rtx, + GEN_INT (offset))); + + GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc); + + mem_rtx = NULL_RTX; + + try_post_inc: + do + if (HAVE_POST_INCREMENT + && (offset == offset_in_r0 + || (offset + GET_MODE_SIZE (mode) != d + d_rounding + && mem_rtx == NULL_RTX) + || reg == PR_REG || SPECIAL_REGISTER_P (reg))) + { + post_inc = gen_rtx_MEM (mode, + gen_rtx_POST_INC (Pmode, r0)); + + GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0), + post_inc_ok); + + post_inc = NULL_RTX; + + break; + + post_inc_ok: + mem_rtx = NULL_RTX; + } + while (0); + + if (mem_rtx != NULL_RTX) + goto addr_ok; + + if (offset_in_r0 == -1) { - enum machine_mode mode = REGISTER_NATURAL_MODE (i); - int reg = i; - rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn; - - if (mode == SFmode && (i % 2) == 0 - && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i) - && (TEST_HARD_REG_BIT (live_regs_mask, (i ^ 1)))) - { - mode = DFmode; - i++; - } - - /* If we're doing the aligned pass and this is not aligned, - or we're doing the unaligned pass and this is aligned, - skip it. */ - if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT) - == 0) != align) - continue; - - reg_rtx = gen_rtx_REG (mode, reg); - - mem_rtx = gen_rtx_MEM (mode, - gen_rtx_PLUS (Pmode, - stack_pointer_rtx, - GEN_INT (offset))); - - GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc); - - mem_rtx = NULL_RTX; - - try_post_inc: - do - if (HAVE_POST_INCREMENT - && (offset == offset_in_r0 - || (offset + GET_MODE_SIZE (mode) != d + d_rounding - && mem_rtx == NULL_RTX) - || i == PR_REG || SPECIAL_REGISTER_P (i))) - { - post_inc = gen_rtx_MEM (mode, - gen_rtx_POST_INC (Pmode, r0)); - - GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0), - post_inc_ok); - - post_inc = NULL_RTX; - - break; - - post_inc_ok: - mem_rtx = NULL_RTX; - } - while (0); + emit_move_insn (r0, GEN_INT (offset)); + offset_in_r0 = offset; + } + else if (offset != offset_in_r0) + { + emit_move_insn (r0, + gen_rtx_PLUS + (Pmode, r0, + GEN_INT (offset - offset_in_r0))); + offset_in_r0 += offset - offset_in_r0; + } - if (mem_rtx != NULL_RTX) - goto addr_ok; - - if (offset_in_r0 == -1) - { - emit_move_insn (r0, GEN_INT (offset)); - offset_in_r0 = offset; - } - else if (offset != offset_in_r0) + if (post_inc != NULL_RTX) + { + if (! sp_in_r0) { emit_move_insn (r0, gen_rtx_PLUS - (Pmode, r0, - GEN_INT (offset - offset_in_r0))); - offset_in_r0 += offset - offset_in_r0; + (Pmode, r0, stack_pointer_rtx)); + sp_in_r0 = 1; } - - if (post_inc != NULL_RTX) - { - if (! sp_in_r0) - { - emit_move_insn (r0, - gen_rtx_PLUS - (Pmode, r0, stack_pointer_rtx)); - sp_in_r0 = 1; - } - - mem_rtx = post_inc; + + mem_rtx = post_inc; - offset_in_r0 += GET_MODE_SIZE (mode); - } - else if (sp_in_r0) - mem_rtx = gen_rtx_MEM (mode, r0); - else - mem_rtx = gen_rtx_MEM (mode, - gen_rtx_PLUS (Pmode, - stack_pointer_rtx, - r0)); + offset_in_r0 += GET_MODE_SIZE (mode); + } + else if (sp_in_r0) + mem_rtx = gen_rtx_MEM (mode, r0); + else + mem_rtx = gen_rtx_MEM (mode, + gen_rtx_PLUS (Pmode, + stack_pointer_rtx, + r0)); - if ((i == PR_REG || SPECIAL_REGISTER_P (i)) - && mem_rtx != post_inc) - abort (); + if ((reg == PR_REG || SPECIAL_REGISTER_P (reg)) + && mem_rtx != post_inc) + abort (); - addr_ok: - if ((i == PR_REG || SPECIAL_REGISTER_P (i)) - && mem_rtx != post_inc) - { - insn = emit_move_insn (r0, mem_rtx); - mem_rtx = r0; - } - else if (TARGET_REGISTER_P (i)) - { - rtx tmp_reg = gen_rtx_REG (mode, tmp_regno); + addr_ok: + if ((reg == PR_REG || SPECIAL_REGISTER_P (reg)) + && mem_rtx != post_inc) + { + insn = emit_move_insn (r0, mem_rtx); + mem_rtx = r0; + } + else if (TARGET_REGISTER_P (reg)) + { + rtx tmp_reg = gen_rtx_REG (mode, *tmp_pnt); - /* Give the scheduler a bit of freedom by using R20..R23 - in a round-robin fashion. Don't use R1 here because - we want to use it for EH_RETURN_STACKADJ_RTX. */ - insn = emit_move_insn (tmp_reg, mem_rtx); - mem_rtx = tmp_reg; - if (++tmp_regno > R23_REG) - tmp_regno = R20_REG; - } - - insn = emit_move_insn (reg_rtx, mem_rtx); - - offset += GET_MODE_SIZE (mode); + /* Give the scheduler a bit of freedom by using up to + MAX_TEMPS registers in a round-robin fashion. */ + insn = emit_move_insn (tmp_reg, mem_rtx); + mem_rtx = tmp_reg; + if (*++tmp_pnt < 0) + tmp_pnt = schedule.temps; } - if (offset != d + d_rounding) + insn = emit_move_insn (reg_rtx, mem_rtx); + + offset += GET_MODE_SIZE (mode); + } + + if (entry->offset + offset_base != d + d_rounding) abort (); } else /* ! TARGET_SH5 */ @@ -5521,7 +5694,7 @@ sh_expand_epilogue () output_stack_adjust (extra_push + current_function_pretend_args_size + save_size + d_rounding + current_function_args_info.stack_regs * 8, - stack_pointer_rtx, 7, emit_insn); + stack_pointer_rtx, 1, NULL); if (current_function_calls_eh_return) emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx, @@ -5566,7 +5739,6 @@ sh_set_return_address (ra, tmp) { HARD_REG_SET live_regs_mask; int d; - int d_rounding = 0; int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG; int pr_offset; @@ -5598,56 +5770,26 @@ sh_set_return_address (ra, tmp) if (TARGET_SH5) { - int i; int offset; - int align; + save_schedule schedule; + save_entry *entry; - if (d % (STACK_BOUNDARY / BITS_PER_UNIT)) - d_rounding = ((STACK_BOUNDARY / BITS_PER_UNIT) - - d % (STACK_BOUNDARY / BITS_PER_UNIT)); - - offset = 0; - - /* We loop twice: first, we save 8-byte aligned registers in the - higher addresses, that are known to be aligned. Then, we - proceed to saving 32-bit registers that don't need 8-byte - alignment. */ - for (align = 0; align <= 1; align++) - for (i = 0; i < FIRST_PSEUDO_REGISTER; i++) - if (TEST_HARD_REG_BIT (live_regs_mask, i)) - { - enum machine_mode mode = REGISTER_NATURAL_MODE (i); - - if (mode == SFmode && (i % 2) == 0 - && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i) - && (TEST_HARD_REG_BIT (live_regs_mask, (i ^ 1)))) - { - mode = DFmode; - i++; - } - - /* If we're doing the aligned pass and this is not aligned, - or we're doing the unaligned pass and this is aligned, - skip it. */ - if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT) - == 0) != align) - continue; - - if (i == pr_reg) - goto found; - - offset += GET_MODE_SIZE (mode); - } + entry = sh5_schedule_saves (&live_regs_mask, &schedule, 0); + offset = entry[1].offset; + for (; entry->mode != VOIDmode; entry--) + if (entry->reg == pr_reg) + goto found; /* We can't find pr register. */ abort (); found: - pr_offset = (rounded_frame_size (d) - d_rounding + offset + offset = entry->offset - offset; + pr_offset = (rounded_frame_size (d) + offset + SHMEDIA_REGS_STACK_ADJUST ()); } else - pr_offset = rounded_frame_size (d) - d_rounding; + pr_offset = rounded_frame_size (d); emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset))); emit_insn (GEN_ADD3 (tmp, tmp, frame_pointer_rtx)); @@ -6188,9 +6330,10 @@ initial_elimination_offset (from, to) { if (TARGET_SH5) { - int i, n = total_saved_regs_space; - int align; + int n = total_saved_regs_space; int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG; + save_schedule schedule; + save_entry *entry; n += total_auto_space; @@ -6200,40 +6343,13 @@ initial_elimination_offset (from, to) target_flags = copy_flags; - /* We loop twice: first, check 8-byte aligned registers, - that are stored in the higher addresses, that are known - to be aligned. Then, check 32-bit registers that don't - need 8-byte alignment. */ - for (align = 1; align >= 0; align--) - for (i = FIRST_PSEUDO_REGISTER - 1; i >= 0; i--) - if (TEST_HARD_REG_BIT (live_regs_mask, i)) - { - enum machine_mode mode = REGISTER_NATURAL_MODE (i); - - if (mode == SFmode && (i % 2) == 1 - && ! TARGET_FPU_SINGLE && FP_REGISTER_P (i) - && TEST_HARD_REG_BIT (live_regs_mask, (i ^ 1))) - { - mode = DFmode; - i--; - } - - /* If we're doing the aligned pass and this is not aligned, - or we're doing the unaligned pass and this is aligned, - skip it. */ - if ((GET_MODE_SIZE (mode) % (STACK_BOUNDARY / BITS_PER_UNIT) - == 0) != align) - continue; - - n -= GET_MODE_SIZE (mode); - - if (i == pr_reg) - { - target_flags = save_flags; - return n; - } - } - + sh5_schedule_saves (&live_regs_mask, &schedule, n); + for (entry = &schedule.entries[1]; entry->mode != VOIDmode; entry++) + if (entry->reg == pr_reg) + { + target_flags = save_flags; + return entry->offset; + } abort (); } else @@ -8705,4 +8821,22 @@ function_symbol (const char *name) return sym; } +/* Find the number of a general purpose register in S. */ +static int +scavenge_reg (HARD_REG_SET *s) +{ + int r; + for (r = FIRST_GENERAL_REG; r <= LAST_GENERAL_REG; r++) + if (TEST_HARD_REG_BIT (*s, r)) + return r; + return -1; +} + +rtx +sh_get_pr_initial_val (void) +{ + return + get_hard_reg_initial_val (Pmode, TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG); +} + #include "gt-sh.h" diff --git a/gcc/config/sh/sh.h b/gcc/config/sh/sh.h index 9ab647aff5d..cf97d9129bc 100644 --- a/gcc/config/sh/sh.h +++ b/gcc/config/sh/sh.h @@ -591,6 +591,13 @@ do { \ #define UNITS_PER_WORD (TARGET_SHMEDIA ? 8 : 4) #define MIN_UNITS_PER_WORD 4 +/* Scaling factor for Dwarf data offsets for CFI information. + The dwarf2out.c default would use -UNITS_PER_WORD, which is -8 for + SHmedia; however, since we do partial register saves for the registers + visible to SHcompact, and for target registers for SHMEDIA32, we have + to allow saves that are only 4-byte aligned. */ +#define DWARF_CIE_DATA_ALIGNMENT -4 + /* Width in bits of a pointer. See also the macro `Pmode' defined below. */ #define POINTER_SIZE (TARGET_SHMEDIA64 ? 64 : 32) @@ -639,8 +646,8 @@ do { \ #define LOCAL_ALIGNMENT(TYPE, ALIGN) \ ((GET_MODE_CLASS (TYPE_MODE (TYPE)) == MODE_COMPLEX_INT \ || GET_MODE_CLASS (TYPE_MODE (TYPE)) == MODE_COMPLEX_FLOAT) \ - ? MIN (BIGGEST_ALIGNMENT, GET_MODE_BITSIZE (TYPE_MODE (TYPE))) \ - : ALIGN) + ? (unsigned) MIN (BIGGEST_ALIGNMENT, GET_MODE_BITSIZE (TYPE_MODE (TYPE))) \ + : (unsigned) ALIGN) /* Make arrays of chars word-aligned for the same reasons. */ #define DATA_ALIGNMENT(TYPE, ALIGN) \ @@ -816,16 +823,18 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ #define LAST_TARGET_REG (FIRST_TARGET_REG + (TARGET_SHMEDIA ? 7 : -1)) #define GENERAL_REGISTER_P(REGNO) \ - IN_RANGE ((REGNO), FIRST_GENERAL_REG, LAST_GENERAL_REG) + IN_RANGE ((REGNO), \ + (unsigned HOST_WIDE_INT) FIRST_GENERAL_REG, \ + (unsigned HOST_WIDE_INT) LAST_GENERAL_REG) #define GENERAL_OR_AP_REGISTER_P(REGNO) \ (GENERAL_REGISTER_P (REGNO) || ((REGNO) == AP_REG)) #define FP_REGISTER_P(REGNO) \ - ((REGNO) >= FIRST_FP_REG && (REGNO) <= LAST_FP_REG) + ((int) (REGNO) >= FIRST_FP_REG && (int) (REGNO) <= LAST_FP_REG) #define XD_REGISTER_P(REGNO) \ - ((REGNO) >= FIRST_XD_REG && (REGNO) <= LAST_XD_REG) + ((int) (REGNO) >= FIRST_XD_REG && (int) (REGNO) <= LAST_XD_REG) #define FP_OR_XD_REGISTER_P(REGNO) \ (FP_REGISTER_P (REGNO) || XD_REGISTER_P (REGNO)) @@ -838,7 +847,7 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ || (REGNO) == MACH_REG || (REGNO) == MACL_REG) #define TARGET_REGISTER_P(REGNO) \ - ((REGNO) >= FIRST_TARGET_REG && (REGNO) <= LAST_TARGET_REG) + ((int) (REGNO) >= FIRST_TARGET_REG && (int) (REGNO) <= LAST_TARGET_REG) #define SHMEDIA_REGISTER_P(REGNO) \ (GENERAL_REGISTER_P (REGNO) || FP_REGISTER_P (REGNO) \ @@ -951,7 +960,8 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ (TARGET_SHMEDIA32 \ && GET_MODE_SIZE (MODE) > 4 \ && (((REGNO) >= FIRST_GENERAL_REG + 10 \ - && (REGNO) <= FIRST_GENERAL_REG + 14) \ + && (REGNO) <= FIRST_GENERAL_REG + 15) \ + || TARGET_REGISTER_P (REGNO) \ || (REGNO) == PR_MEDIA_REG)) /* Return number of consecutive hard regs needed starting at reg REGNO @@ -1137,7 +1147,7 @@ extern char sh_additional_register_names[ADDREGNAMES_SIZE] \ ? (unsigned HOST_WIDE_INT) int_size_in_bytes (TYPE) \ : GET_MODE_SIZE (TYPE_MODE (TYPE))) > 8) \ : (TYPE_MODE (TYPE) == BLKmode \ - || TARGET_HITACHI && TREE_CODE (TYPE) == RECORD_TYPE)) + || (TARGET_HITACHI && TREE_CODE (TYPE) == RECORD_TYPE))) /* Don't default to pcc-struct-return, because we have already specified exactly how to return structures in the RETURN_IN_MEMORY macro. */ @@ -1273,7 +1283,7 @@ enum reg_class reg number REGNO. This could be a conditional expression or could index an array. */ -extern int regno_reg_class[FIRST_PSEUDO_REGISTER]; +extern enum reg_class regno_reg_class[FIRST_PSEUDO_REGISTER]; #define REGNO_REG_CLASS(REGNO) regno_reg_class[(REGNO)] /* When defined, the compiler allows registers explicitly used in the @@ -1363,7 +1373,9 @@ extern enum reg_class reg_class_from_letter[]; #define CONSTRAINT_LEN(C,STR) \ (((C) == 'L' || (C) == 'O' || (C) == 'D' || (C) == 'T' || (C) == 'U' \ || (C) == 'Y' \ - || ((C) == 'I' && (((STR)[1] != '0' && (STR)[1] != '1') || ! isdigit ((STR)[2]))) \ + || ((C) == 'I' \ + && (((STR)[1] != '0' && (STR)[1] != '1') \ + || (STR)[2] < '0' || (STR)[2] > '9')) \ || ((C) == 'B' && ((STR)[1] != 's' || (STR)[2] != 'c')) \ || ((C) == 'J' && ((STR)[1] != '1' || (STR)[2] != '6')) \ || ((C) == 'K' && ((STR)[1] != '0' || (STR)[2] != '8')) \ @@ -1667,12 +1679,15 @@ extern enum reg_class reg_class_from_letter[]; || (TARGET_SHMEDIA_FPU && (REGNO) == FIRST_FP_RET_REG)) /* 1 if N is a possible register number for function argument passing. */ +/* ??? There are some callers that pass REGNO as int, and others that pass + it as unsigned. We get warnings unless we do casts everywhere. */ #define FUNCTION_ARG_REGNO_P(REGNO) \ - (((REGNO) >= FIRST_PARM_REG && (REGNO) < (FIRST_PARM_REG \ - + NPARM_REGS (SImode))) \ + (((unsigned) (REGNO) >= (unsigned) FIRST_PARM_REG \ + && (unsigned) (REGNO) < (unsigned) (FIRST_PARM_REG + NPARM_REGS (SImode)))\ || (TARGET_FPU_ANY \ - && (REGNO) >= FIRST_FP_PARM_REG && (REGNO) < (FIRST_FP_PARM_REG \ - + NPARM_REGS (SFmode)))) + && (unsigned) (REGNO) >= (unsigned) FIRST_FP_PARM_REG \ + && (unsigned) (REGNO) < (unsigned) (FIRST_FP_PARM_REG \ + + NPARM_REGS (SFmode)))) /* Define a data type for recording info about an argument list during the scan of that argument list. This data type should @@ -2057,13 +2072,13 @@ struct sh_args { (VOIDmode, \ gen_rtx_REG (SFmode, \ BASE_ARG_REG (MODE) \ - + ROUND_REG ((CUM), (MODE)) ^ 1), \ + + (ROUND_REG ((CUM), (MODE)) ^ 1)), \ const0_rtx)), \ (gen_rtx_EXPR_LIST \ (VOIDmode, \ gen_rtx_REG (SFmode, \ BASE_ARG_REG (MODE) \ - + (ROUND_REG ((CUM), (MODE)) + 1) ^ 1), \ + + ((ROUND_REG ((CUM), (MODE)) + 1) ^ 1)), \ GEN_INT (4))))))) \ : gen_rtx_REG ((MODE), \ ((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \ @@ -2311,9 +2326,7 @@ while (0) can ignore COUNT. */ #define RETURN_ADDR_RTX(COUNT, FRAME) \ - (((COUNT) == 0) \ - ? get_hard_reg_initial_val (Pmode, TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG) \ - : (rtx) 0) + (((COUNT) == 0) ? sh_get_pr_initial_val () : (rtx) 0) /* A C expression whose value is RTL representing the location of the incoming return address at the beginning of any function, before the @@ -2322,6 +2335,11 @@ while (0) the stack. */ #define INCOMING_RETURN_ADDR_RTX \ gen_rtx_REG (Pmode, TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG) + +/* libstdc++-v3/libsupc++/eh_personality.cc:__gxx_personality_v0 + can get confused by SHmedia return addresses when it does: + ip = _Unwind_GetIP (context) - 1; */ +#define RETURN_ADDR_OFFSET (TARGET_SH5 ? -1 : 0) /* Generate necessary RTL for __builtin_saveregs(). */ #define EXPAND_BUILTIN_SAVEREGS() sh_builtin_saveregs () @@ -3085,18 +3103,18 @@ while (0) #define SH_DBX_REGISTER_NUMBER(REGNO) \ (GENERAL_REGISTER_P (REGNO) \ - ? ((REGNO) - FIRST_GENERAL_REG) \ + ? ((unsigned) (REGNO) - FIRST_GENERAL_REG) \ : FP_REGISTER_P (REGNO) \ - ? ((REGNO) - FIRST_FP_REG + (TARGET_SH5 ? (TARGET_SHCOMPACT ? 245 \ - : 77) : 25)) \ + ? ((unsigned) (REGNO) - FIRST_FP_REG \ + + (TARGET_SH5 ? (TARGET_SHCOMPACT ? 245 : 77) : 25)) \ : XD_REGISTER_P (REGNO) \ - ? ((REGNO) - FIRST_XD_REG + (TARGET_SH5 ? 289 : 87)) \ + ? ((unsigned) (REGNO) - FIRST_XD_REG + (TARGET_SH5 ? 289 : 87)) \ : TARGET_REGISTER_P (REGNO) \ - ? ((REGNO) - FIRST_TARGET_REG + 68) \ + ? ((unsigned) (REGNO) - FIRST_TARGET_REG + 68) \ : (REGNO) == PR_REG \ ? (TARGET_SH5 ? 241 : 17) \ : (REGNO) == PR_MEDIA_REG \ - ? (TARGET_SH5 ? 18 : -1) \ + ? (TARGET_SH5 ? 18 : (unsigned) -1) \ : (REGNO) == T_REG \ ? (TARGET_SH5 ? 242 : 18) \ : (REGNO) == GBR_REG \ @@ -3107,7 +3125,7 @@ while (0) ? (TARGET_SH5 ? 240 : 21) \ : (REGNO) == FPUL_REG \ ? (TARGET_SH5 ? 244 : 23) \ - : -1) + : (unsigned) -1) /* This is how to output a reference to a symbol_ref. On SH5, references to non-code symbols must be preceded by `datalabel'. */ @@ -3449,9 +3467,10 @@ extern int rtx_equal_function_value_matters; (TARGET_SH5 ? DWARF_FRAME_REGNUM (PR_MEDIA_REG) : DWARF_FRAME_REGNUM (PR_REG)) #define EH_RETURN_DATA_REGNO(N) \ - ((N) < 4 ? (N) + (TARGET_SH5 ? 2 : 4) : INVALID_REGNUM) + ((N) < 4 ? (N) + (TARGET_SH5 ? 2U : 4U) : INVALID_REGNUM) -#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM) +#define EH_RETURN_STACKADJ_REGNO STATIC_CHAIN_REGNUM +#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, EH_RETURN_STACKADJ_REGNO) #if (defined CRT_BEGIN || defined CRT_END) && ! __SHMEDIA__ /* SH constant pool breaks the devices in crtstuff.c to control section diff --git a/gcc/config/sh/sh.md b/gcc/config/sh/sh.md index 2af568b772c..8e012d75f7b 100644 --- a/gcc/config/sh/sh.md +++ b/gcc/config/sh/sh.md @@ -2052,7 +2052,7 @@ " { enum machine_mode inmode = GET_MODE (operands[1]); - int regno, offset = 0; + int offset = 0; if (GET_CODE (operands[0]) == SUBREG) { @@ -7247,6 +7247,8 @@ mov.l\\t1f,r0\\n\\ { rtx r18 = gen_rtx_REG (DImode, PR_MEDIA_REG); + if (! call_used_regs[TR0_REG] || fixed_regs[TR0_REG]) + abort (); tr_regno = TR0_REG; tr = gen_rtx_REG (DImode, tr_regno); emit_move_insn (tr, r18);