summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authoramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-16 21:41:20 +0000
committeramylaar <amylaar@138bc75d-0d04-0410-961f-82ee72b054a4>2003-07-16 21:41:20 +0000
commit41fafa66e3a981c1b87149ebd136f1a6531024ee (patch)
tree6bdbd9cf60de950e5058b8fdfbdd21aeb5837078 /gcc/config
parent7e7c8e9d3ff0101b0255805298da946111f45e22 (diff)
downloadgcc-41fafa66e3a981c1b87149ebd136f1a6531024ee.tar.gz
prologue / epilogue / 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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@69480 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/sh/sh-protos.h1
-rw-r--r--gcc/config/sh/sh.c798
-rw-r--r--gcc/config/sh/sh.h75
-rw-r--r--gcc/config/sh/sh.md4
4 files changed, 517 insertions, 361 deletions
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,
+ &reg_class_contents[TARGET_REGS])
+ && ! hard_regs_intersect_p (live_regs_mask,
+ &reg_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);
-
- /* 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;
+ 0, NULL);
- 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;
+ 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 -= GET_MODE_SIZE (mode);
+ offset = entry->offset;
- reg_rtx = gen_rtx_REG (mode, reg);
+ reg_rtx = gen_rtx_REG (mode, reg);
- mem_rtx = gen_rtx_MEM (mode,
- gen_rtx_PLUS (Pmode,
- stack_pointer_rtx,
- GEN_INT (offset)));
+ 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);
+ GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_pre_dec);
- mem_rtx = NULL_RTX;
+ 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
- || i == PR_REG || SPECIAL_REGISTER_P (i)))
- {
- pre_dec = gen_rtx_MEM (mode,
- gen_rtx_PRE_DEC (Pmode, r0));
+ 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);
+ GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (pre_dec, 0),
+ pre_dec_ok);
- pre_dec = NULL_RTX;
+ pre_dec = NULL_RTX;
- break;
+ break;
- pre_dec_ok:
- mem_rtx = NULL_RTX;
- offset += GET_MODE_SIZE (mode);
- }
- while (0);
+ pre_dec_ok:
+ mem_rtx = NULL_RTX;
+ offset += GET_MODE_SIZE (mode);
+ }
+ while (0);
- if (mem_rtx != NULL_RTX)
- goto addr_ok;
+ 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 (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,
- 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)
- {
- 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);
+ 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);
+ 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 (r0mode, reg_rtx);
+ emit_move_insn (tmp_reg, reg_rtx);
+ if (REGNO (tmp_reg) == R0_REG)
+ {
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;
+
+ 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 (offset != d_rounding)
+ 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))
- {
- enum machine_mode mode = REGISTER_NATURAL_MODE (i);
- int reg = i;
- rtx reg_rtx, mem_rtx, post_inc = NULL_RTX, insn;
+ 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;
- 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++;
- }
+ offset = offset_base + entry->offset;
+ reg_rtx = gen_rtx_REG (mode, 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;
+ mem_rtx = gen_rtx_MEM (mode,
+ gen_rtx_PLUS (Pmode,
+ stack_pointer_rtx,
+ GEN_INT (offset)));
- reg_rtx = gen_rtx_REG (mode, reg);
+ GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc);
- mem_rtx = gen_rtx_MEM (mode,
- gen_rtx_PLUS (Pmode,
- stack_pointer_rtx,
- GEN_INT (offset)));
+ mem_rtx = NULL_RTX;
- GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (mem_rtx, 0), try_post_inc);
+ 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));
- mem_rtx = NULL_RTX;
+ GO_IF_LEGITIMATE_ADDRESS (mode, XEXP (post_inc, 0),
+ post_inc_ok);
- 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;
- post_inc = NULL_RTX;
+ break;
+
+ post_inc_ok:
+ mem_rtx = NULL_RTX;
+ }
+ while (0);
+
+ if (mem_rtx != NULL_RTX)
+ goto addr_ok;
- break;
-
- post_inc_ok:
- mem_rtx = NULL_RTX;
- }
- while (0);
+ 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 (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));
-
- 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;
- }
+ 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));
- insn = emit_move_insn (reg_rtx, mem_rtx);
+ if ((reg == PR_REG || SPECIAL_REGISTER_P (reg))
+ && mem_rtx != post_inc)
+ abort ();
- offset += GET_MODE_SIZE (mode);
+ 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;
}
- 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);