This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
applied to SH port: prologue / epiloge & warning patches
- From: Joern Rennecke <joern dot rennecke at superh dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Wed, 16 Jul 2003 22:42:54 +0100 (BST)
- Subject: applied to SH port: prologue / epiloge & warning patches
2003-07-16 J"orn Rennecke <joern.rennecke@superh.com>
Con Bradley <con.bradley@superh.com>
* 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.
Index: config/sh/sh-protos.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh-protos.h,v
retrieving revision 1.44
diff -p -r1.44 sh-protos.h
*** config/sh/sh-protos.h 19 Jun 2003 21:47:23 -0000 1.44
--- config/sh/sh-protos.h 16 Jul 2003 21:38:34 -0000
*************** extern void sh_pr_interrupt PARAMS ((str
*** 136,140 ****
--- 136,141 ----
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 */
Index: config/sh/sh.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.c,v
retrieving revision 1.229
diff -p -r1.229 sh.c
*** config/sh/sh.c 10 Jul 2003 18:04:25 -0000 1.229
--- config/sh/sh.c 16 Jul 2003 21:38:35 -0000
*************** rtx sh_compare_op1;
*** 108,114 ****
/* Provides the class number of the smallest class containing
reg number. */
! int regno_reg_class[FIRST_PSEUDO_REGISTER] =
{
R0_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
GENERAL_REGS, GENERAL_REGS, GENERAL_REGS, GENERAL_REGS,
--- 108,114 ----
/* Provides the class number of the smallest class containing
reg number. */
! 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,
*************** static rtx find_barrier PARAMS ((int, rt
*** 190,196 ****
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 rtx frame_insn PARAMS ((rtx));
static rtx push PARAMS ((int));
static void pop PARAMS ((int));
--- 190,196 ----
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 (int, rtx, int, HARD_REG_SET *);
static rtx frame_insn PARAMS ((rtx));
static rtx push PARAMS ((int));
static void pop PARAMS ((int));
*************** static int sh_address_cost PARAMS ((rtx)
*** 234,239 ****
--- 234,243 ----
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
*************** output_jump_label_table ()
*** 4558,4574 ****
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. */
static void
! output_stack_adjust (size, reg, temp, emit_fn)
! int size;
! rtx reg;
! int temp;
! rtx (*emit_fn) PARAMS ((rtx));
{
if (size)
{
HOST_WIDE_INT align = STACK_BOUNDARY / BITS_PER_UNIT;
--- 4562,4577 ----
static int extra_push;
! /* 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 (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;
*************** output_stack_adjust (size, reg, temp, em
*** 4591,4600 ****
--- 4594,4636 ----
{
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);
*************** output_stack_adjust (size, reg, temp, em
*** 4612,4618 ****
emit_insn (GEN_MOV (const_reg, GEN_INT (size)));
insn = emit_fn (GEN_ADD3 (reg, reg, const_reg));
}
! if (emit_fn == frame_insn)
REG_NOTES (insn)
= (gen_rtx_EXPR_LIST
(REG_FRAME_RELATED_EXPR,
--- 4648,4654 ----
emit_insn (GEN_MOV (const_reg, GEN_INT (size)));
insn = emit_fn (GEN_ADD3 (reg, reg, const_reg));
}
! if (! epilogue_p)
REG_NOTES (insn)
= (gen_rtx_EXPR_LIST
(REG_FRAME_RELATED_EXPR,
*************** calc_live_regs (live_regs_mask)
*** 4789,4800 ****
int reg;
int count;
int interrupt_handler;
! int pr_live;
interrupt_handler = sh_cfun_interrupt_handler_p ();
! for (count = 0; 32 * count < FIRST_PSEUDO_REGISTER; count++)
! CLEAR_HARD_REG_SET (*live_regs_mask);
if (TARGET_SH4 && TARGET_FMOVD && interrupt_handler
&& regs_ever_live[FPSCR_REG])
target_flags &= ~FPU_SINGLE_BIT;
--- 4825,4835 ----
int reg;
int count;
int interrupt_handler;
! int pr_live, has_call;
interrupt_handler = sh_cfun_interrupt_handler_p ();
! CLEAR_HARD_REG_SET (*live_regs_mask);
if (TARGET_SH4 && TARGET_FMOVD && interrupt_handler
&& regs_ever_live[FPSCR_REG])
target_flags &= ~FPU_SINGLE_BIT;
*************** calc_live_regs (live_regs_mask)
*** 4829,4844 ****
& ~ CALL_COOKIE_RET_TRAMP (1))
|| current_function_has_nonlocal_label))
pr_live = 1;
for (count = 0, reg = FIRST_PSEUDO_REGISTER - 1; reg >= 0; reg--)
{
! if (reg == (TARGET_SHMEDIA ? PR_MEDIA_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))
&& reg != STACK_POINTER_REGNUM && reg != ARG_POINTER_REGNUM
&& reg != RETURN_ADDRESS_POINTER_REGNUM
&& reg != T_REG && reg != GBR_REG
--- 4864,4882 ----
& ~ 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 ((! 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)
! && 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
*************** calc_live_regs (live_regs_mask)
*** 4848,4860 ****
(TARGET_SHCOMPACT
&& flag_pic
&& current_function_args_info.call_cookie
! && reg == 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)))))
{
SET_HARD_REG_BIT (*live_regs_mask, reg);
count += GET_MODE_SIZE (REGISTER_NATURAL_MODE (reg));
--- 4886,4898 ----
(TARGET_SHCOMPACT
&& flag_pic
&& current_function_args_info.call_cookie
! && reg == (int) PIC_OFFSET_TABLE_REGNUM)
|| (regs_ever_live[reg] && ! call_used_regs[reg])
|| (current_function_calls_eh_return
! && (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));
*************** calc_live_regs (live_regs_mask)
*** 4891,4896 ****
--- 4929,4947 ----
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;
}
*************** sh_media_register_for_return ()
*** 4921,4926 ****
--- 4972,4980 ----
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];
*************** sh_media_register_for_return ()
*** 4931,4936 ****
--- 4985,5114 ----
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 ()
{
*************** sh_expand_prologue ()
*** 4945,4951 ****
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);
extra_push = 0;
--- 5123,5129 ----
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, 0, NULL);
extra_push = 0;
*************** sh_expand_prologue ()
*** 5034,5047 ****
if (TARGET_SH5)
{
! int i;
! int offset;
! int align;
! rtx r0 = gen_rtx_REG (Pmode, R0_REG);
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;
/* D is the actual number of bytes that we need for saving registers,
however, in initial_elimination_offset we have committed to using
--- 5212,5230 ----
if (TARGET_SH5)
{
! 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
*************** sh_expand_prologue ()
*** 5067,5212 ****
&& total_size <= 2044)))
d_rounding = total_size - save_size;
! offset = d + d_rounding;
output_stack_adjust (-(save_size + d_rounding), stack_pointer_rtx,
! 1, frame_insn);
! /* 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))
! {
! 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_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, 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;
}
! emit_move_insn (mem_rtx, reg_rtx);
}
! if (offset != d_rounding)
abort ();
}
else
--- 5250,5402 ----
&& total_size <= 2044)))
d_rounding = total_size - save_size;
! offset_base = d + d_rounding;
output_stack_adjust (-(save_size + d_rounding), stack_pointer_rtx,
! 0, NULL);
! 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)
! {
! 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, 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 (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)
+ {
offset_in_r0 = -1;
sp_in_r0 = 0;
! if (refers_to_regno_p (R0_REG, R0_REG+1, mem_rtx, (rtx *) 0))
! abort ();
}
! if (*++tmp_pnt <= 0)
! tmp_pnt = schedule.temps;
!
! 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
*************** sh_expand_prologue ()
*** 5258,5264 ****
target_flags = save_flags;
output_stack_adjust (-rounded_frame_size (d) + d_rounding,
! stack_pointer_rtx, TARGET_SH5 ? 0 : 1, frame_insn);
if (frame_pointer_needed)
frame_insn (GEN_MOV (frame_pointer_rtx, stack_pointer_rtx));
--- 5448,5454 ----
target_flags = save_flags;
output_stack_adjust (-rounded_frame_size (d) + d_rounding,
! stack_pointer_rtx, 0, NULL);
if (frame_pointer_needed)
frame_insn (GEN_MOV (frame_pointer_rtx, stack_pointer_rtx));
*************** sh_expand_epilogue ()
*** 5318,5324 ****
if (frame_pointer_needed)
{
! output_stack_adjust (frame_size, frame_pointer_rtx, 7, emit_insn);
/* We must avoid moving the stack pointer adjustment past code
which reads from the local frame, else an interrupt could
--- 5508,5514 ----
if (frame_pointer_needed)
{
! 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
*************** sh_expand_epilogue ()
*** 5334,5340 ****
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);
}
if (SHMEDIA_REGS_STACK_ADJUST ())
--- 5524,5530 ----
occur after the SP adjustment and clobber data in the local
frame. */
emit_insn (gen_blockage ());
! output_stack_adjust (frame_size, stack_pointer_rtx, 1, &live_regs_mask);
}
if (SHMEDIA_REGS_STACK_ADJUST ())
*************** sh_expand_epilogue ()
*** 5355,5497 ****
emit_insn (gen_toggle_sz ());
if (TARGET_SH5)
{
! int offset = d_rounding;
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;
! /* 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);
! 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);
! 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_rtx_PLUS
! (Pmode, r0,
! GEN_INT (offset - offset_in_r0)));
! offset_in_r0 += offset - offset_in_r0;
}
!
! 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;
! 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 ();
!
! 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);
! /* 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);
}
! if (offset != d + d_rounding)
abort ();
}
else /* ! TARGET_SH5 */
--- 5545,5670 ----
emit_insn (gen_toggle_sz ());
if (TARGET_SH5)
{
! int offset_base, offset;
int offset_in_r0 = -1;
int sp_in_r0 = 0;
rtx r0 = gen_rtx_REG (Pmode, R0_REG);
! save_schedule schedule;
! save_entry *entry;
! int *tmp_pnt;
! 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)
! {
! 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 (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;
! 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 ((reg == PR_REG || SPECIAL_REGISTER_P (reg))
! && mem_rtx != post_inc)
! abort ();
! 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 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;
}
! 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 */
*************** sh_expand_epilogue ()
*** 5521,5527 ****
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);
if (current_function_calls_eh_return)
emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx,
--- 5694,5700 ----
output_stack_adjust (extra_push + current_function_pretend_args_size
+ save_size + d_rounding
+ current_function_args_info.stack_regs * 8,
! stack_pointer_rtx, 1, NULL);
if (current_function_calls_eh_return)
emit_insn (GEN_ADD3 (stack_pointer_rtx, stack_pointer_rtx,
*************** sh_set_return_address (ra, tmp)
*** 5566,5572 ****
{
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;
--- 5739,5744 ----
*************** sh_set_return_address (ra, tmp)
*** 5598,5653 ****
if (TARGET_SH5)
{
- int i;
int offset;
! int align;
! 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);
! }
/* We can't find pr register. */
abort ();
found:
! pr_offset = (rounded_frame_size (d) - d_rounding + offset
+ SHMEDIA_REGS_STACK_ADJUST ());
}
else
! pr_offset = rounded_frame_size (d) - d_rounding;
emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset)));
emit_insn (GEN_ADD3 (tmp, tmp, frame_pointer_rtx));
--- 5770,5795 ----
if (TARGET_SH5)
{
int offset;
! save_schedule schedule;
! save_entry *entry;
! 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:
! offset = entry->offset - offset;
! pr_offset = (rounded_frame_size (d) + offset
+ SHMEDIA_REGS_STACK_ADJUST ());
}
else
! pr_offset = rounded_frame_size (d);
emit_insn (GEN_MOV (tmp, GEN_INT (pr_offset)));
emit_insn (GEN_ADD3 (tmp, tmp, frame_pointer_rtx));
*************** initial_elimination_offset (from, to)
*** 6188,6196 ****
{
if (TARGET_SH5)
{
! int i, n = total_saved_regs_space;
! int align;
int pr_reg = TARGET_SHMEDIA ? PR_MEDIA_REG : PR_REG;
n += total_auto_space;
--- 6330,6339 ----
{
if (TARGET_SH5)
{
! 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;
*************** initial_elimination_offset (from, to)
*** 6200,6239 ****
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;
! }
! }
!
abort ();
}
else
--- 6343,6355 ----
target_flags = copy_flags;
! 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
*************** function_symbol (const char *name)
*** 8703,8708 ****
--- 8819,8842 ----
rtx sym = gen_rtx_SYMBOL_REF (Pmode, name);
SYMBOL_REF_FLAGS (sym) = SYMBOL_FLAG_FUNCTION;
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"
Index: config/sh/sh.h
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.h,v
retrieving revision 1.216
diff -p -r1.216 sh.h
*** config/sh/sh.h 3 Jul 2003 16:25:51 -0000 1.216
--- config/sh/sh.h 16 Jul 2003 21:38:35 -0000
*************** do { \
*** 591,596 ****
--- 591,603 ----
#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)
*************** do { \
*** 639,646 ****
#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)
/* Make arrays of chars word-aligned for the same reasons. */
#define DATA_ALIGNMENT(TYPE, ALIGN) \
--- 646,653 ----
#define LOCAL_ALIGNMENT(TYPE, ALIGN) \
((GET_MODE_CLASS (TYPE_MODE (TYPE)) == MODE_COMPLEX_INT \
|| GET_MODE_CLASS (TYPE_MODE (TYPE)) == MODE_COMPLEX_FLOAT) \
! ? (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) \
*************** extern char sh_additional_register_names
*** 816,831 ****
#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)
#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)
#define XD_REGISTER_P(REGNO) \
! ((REGNO) >= FIRST_XD_REG && (REGNO) <= LAST_XD_REG)
#define FP_OR_XD_REGISTER_P(REGNO) \
(FP_REGISTER_P (REGNO) || XD_REGISTER_P (REGNO))
--- 823,840 ----
#define LAST_TARGET_REG (FIRST_TARGET_REG + (TARGET_SHMEDIA ? 7 : -1))
#define GENERAL_REGISTER_P(REGNO) \
! 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) \
! ((int) (REGNO) >= FIRST_FP_REG && (int) (REGNO) <= LAST_FP_REG)
#define XD_REGISTER_P(REGNO) \
! ((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))
*************** extern char sh_additional_register_names
*** 838,844 ****
|| (REGNO) == MACH_REG || (REGNO) == MACL_REG)
#define TARGET_REGISTER_P(REGNO) \
! ((REGNO) >= FIRST_TARGET_REG && (REGNO) <= LAST_TARGET_REG)
#define SHMEDIA_REGISTER_P(REGNO) \
(GENERAL_REGISTER_P (REGNO) || FP_REGISTER_P (REGNO) \
--- 847,853 ----
|| (REGNO) == MACH_REG || (REGNO) == MACL_REG)
#define TARGET_REGISTER_P(REGNO) \
! ((int) (REGNO) >= FIRST_TARGET_REG && (int) (REGNO) <= LAST_TARGET_REG)
#define SHMEDIA_REGISTER_P(REGNO) \
(GENERAL_REGISTER_P (REGNO) || FP_REGISTER_P (REGNO) \
*************** extern char sh_additional_register_names
*** 951,957 ****
(TARGET_SHMEDIA32 \
&& GET_MODE_SIZE (MODE) > 4 \
&& (((REGNO) >= FIRST_GENERAL_REG + 10 \
! && (REGNO) <= FIRST_GENERAL_REG + 14) \
|| (REGNO) == PR_MEDIA_REG))
/* Return number of consecutive hard regs needed starting at reg REGNO
--- 960,967 ----
(TARGET_SHMEDIA32 \
&& GET_MODE_SIZE (MODE) > 4 \
&& (((REGNO) >= FIRST_GENERAL_REG + 10 \
! && (REGNO) <= FIRST_GENERAL_REG + 15) \
! || TARGET_REGISTER_P (REGNO) \
|| (REGNO) == PR_MEDIA_REG))
/* Return number of consecutive hard regs needed starting at reg REGNO
*************** extern char sh_additional_register_names
*** 1137,1143 ****
? (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))
/* Don't default to pcc-struct-return, because we have already specified
exactly how to return structures in the RETURN_IN_MEMORY macro. */
--- 1147,1153 ----
? (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)))
/* Don't default to pcc-struct-return, because we have already specified
exactly how to return structures in the RETURN_IN_MEMORY macro. */
*************** enum reg_class
*** 1273,1279 ****
reg number REGNO. This could be a conditional expression
or could index an array. */
! extern int 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
--- 1283,1289 ----
reg number REGNO. This could be a conditional expression
or could index an array. */
! 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
*************** extern enum reg_class reg_class_from_let
*** 1363,1369 ****
#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) == 'B' && ((STR)[1] != 's' || (STR)[2] != 'c')) \
|| ((C) == 'J' && ((STR)[1] != '1' || (STR)[2] != '6')) \
|| ((C) == 'K' && ((STR)[1] != '0' || (STR)[2] != '8')) \
--- 1373,1381 ----
#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') \
! || (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')) \
*************** extern enum reg_class reg_class_from_let
*** 1667,1678 ****
|| (TARGET_SHMEDIA_FPU && (REGNO) == FIRST_FP_RET_REG))
/* 1 if N is a possible register number for function argument passing. */
#define FUNCTION_ARG_REGNO_P(REGNO) \
! (((REGNO) >= FIRST_PARM_REG && (REGNO) < (FIRST_PARM_REG \
! + NPARM_REGS (SImode))) \
|| (TARGET_FPU_ANY \
! && (REGNO) >= FIRST_FP_PARM_REG && (REGNO) < (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
--- 1679,1693 ----
|| (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) \
! (((unsigned) (REGNO) >= (unsigned) FIRST_PARM_REG \
! && (unsigned) (REGNO) < (unsigned) (FIRST_PARM_REG + NPARM_REGS (SImode)))\
|| (TARGET_FPU_ANY \
! && (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
*************** struct sh_args {
*** 2057,2069 ****
(VOIDmode, \
gen_rtx_REG (SFmode, \
BASE_ARG_REG (MODE) \
! + 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), \
GEN_INT (4))))))) \
: gen_rtx_REG ((MODE), \
((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \
--- 2072,2084 ----
(VOIDmode, \
gen_rtx_REG (SFmode, \
BASE_ARG_REG (MODE) \
! + (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)), \
GEN_INT (4))))))) \
: gen_rtx_REG ((MODE), \
((BASE_ARG_REG (MODE) + ROUND_REG ((CUM), (MODE))) \
*************** while (0)
*** 2311,2319 ****
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)
/* A C expression whose value is RTL representing the location of the
incoming return address at the beginning of any function, before the
--- 2326,2332 ----
can ignore COUNT. */
#define RETURN_ADDR_RTX(COUNT, FRAME) \
! (((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
*************** while (0)
*** 2322,2327 ****
--- 2335,2345 ----
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 ()
*************** while (0)
*** 3085,3102 ****
#define SH_DBX_REGISTER_NUMBER(REGNO) \
(GENERAL_REGISTER_P (REGNO) \
! ? ((REGNO) - FIRST_GENERAL_REG) \
: FP_REGISTER_P (REGNO) \
! ? ((REGNO) - FIRST_FP_REG + (TARGET_SH5 ? (TARGET_SHCOMPACT ? 245 \
! : 77) : 25)) \
: XD_REGISTER_P (REGNO) \
! ? ((REGNO) - FIRST_XD_REG + (TARGET_SH5 ? 289 : 87)) \
: TARGET_REGISTER_P (REGNO) \
! ? ((REGNO) - FIRST_TARGET_REG + 68) \
: (REGNO) == PR_REG \
? (TARGET_SH5 ? 241 : 17) \
: (REGNO) == PR_MEDIA_REG \
! ? (TARGET_SH5 ? 18 : -1) \
: (REGNO) == T_REG \
? (TARGET_SH5 ? 242 : 18) \
: (REGNO) == GBR_REG \
--- 3103,3120 ----
#define SH_DBX_REGISTER_NUMBER(REGNO) \
(GENERAL_REGISTER_P (REGNO) \
! ? ((unsigned) (REGNO) - FIRST_GENERAL_REG) \
: FP_REGISTER_P (REGNO) \
! ? ((unsigned) (REGNO) - FIRST_FP_REG \
! + (TARGET_SH5 ? (TARGET_SHCOMPACT ? 245 : 77) : 25)) \
: XD_REGISTER_P (REGNO) \
! ? ((unsigned) (REGNO) - FIRST_XD_REG + (TARGET_SH5 ? 289 : 87)) \
: TARGET_REGISTER_P (REGNO) \
! ? ((unsigned) (REGNO) - FIRST_TARGET_REG + 68) \
: (REGNO) == PR_REG \
? (TARGET_SH5 ? 241 : 17) \
: (REGNO) == PR_MEDIA_REG \
! ? (TARGET_SH5 ? 18 : (unsigned) -1) \
: (REGNO) == T_REG \
? (TARGET_SH5 ? 242 : 18) \
: (REGNO) == GBR_REG \
*************** while (0)
*** 3107,3113 ****
? (TARGET_SH5 ? 240 : 21) \
: (REGNO) == FPUL_REG \
? (TARGET_SH5 ? 244 : 23) \
! : -1)
/* This is how to output a reference to a symbol_ref. On SH5,
references to non-code symbols must be preceded by `datalabel'. */
--- 3125,3131 ----
? (TARGET_SH5 ? 240 : 21) \
: (REGNO) == FPUL_REG \
? (TARGET_SH5 ? 244 : 23) \
! : (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'. */
*************** extern int rtx_equal_function_value_matt
*** 3449,3457 ****
(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)
! #define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, STATIC_CHAIN_REGNUM)
#if (defined CRT_BEGIN || defined CRT_END) && ! __SHMEDIA__
/* SH constant pool breaks the devices in crtstuff.c to control section
--- 3467,3476 ----
(TARGET_SH5 ? DWARF_FRAME_REGNUM (PR_MEDIA_REG) : DWARF_FRAME_REGNUM (PR_REG))
#define EH_RETURN_DATA_REGNO(N) \
! ((N) < 4 ? (N) + (TARGET_SH5 ? 2U : 4U) : INVALID_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
Index: config/sh/sh.md
===================================================================
RCS file: /cvs/gcc/gcc/gcc/config/sh/sh.md,v
retrieving revision 1.153
diff -p -r1.153 sh.md
*** config/sh/sh.md 3 Jul 2003 16:25:51 -0000 1.153
--- config/sh/sh.md 16 Jul 2003 21:38:35 -0000
***************
*** 2052,2058 ****
"
{
enum machine_mode inmode = GET_MODE (operands[1]);
! int regno, offset = 0;
if (GET_CODE (operands[0]) == SUBREG)
{
--- 2052,2058 ----
"
{
enum machine_mode inmode = GET_MODE (operands[1]);
! int offset = 0;
if (GET_CODE (operands[0]) == SUBREG)
{
*************** mov.l\\t1f,r0\\n\\
*** 7247,7252 ****
--- 7247,7254 ----
{
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);