Rework large stack frame support.

From-SVN: r2884
This commit is contained in:
Michael Meissner 1992-12-16 17:00:05 +00:00
parent f49acdb4d6
commit 7bea35e746
2 changed files with 288 additions and 156 deletions

View File

@ -3731,6 +3731,72 @@ mips_output_float (stream, value)
#endif
}
/* Return TRUE if any register used in the epilogue is used. This to insure
any insn put into the epilogue delay slots is safe. */
int
epilogue_reg_mentioned_p (insn)
rtx insn;
{
register char *fmt;
register int i;
register enum rtx_code code;
register int regno;
if (insn == (rtx)0)
return 0;
if (GET_CODE (insn) == LABEL_REF)
return 0;
code = GET_CODE (insn);
switch (code)
{
case REG:
regno = REGNO (insn);
if (regno == STACK_POINTER_REGNUM)
return 1;
if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
return 1;
if (!call_used_regs[regno])
return 1;
if (regno != MIPS_TEMP1_REGNUM && regno != MIPS_TEMP2_REGNUM)
return 0;
if (!current_frame_info.initialized)
compute_frame_size (get_frame_size ());
return (current_frame_info.total_size >= 32768);
case SCRATCH:
case CC0:
case PC:
case CONST_INT:
case CONST_DOUBLE:
return 0;
}
fmt = GET_RTX_FORMAT (code);
for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
{
if (fmt[i] == 'E')
{
register int j;
for (j = XVECLEN (insn, i) - 1; j >= 0; j--)
if (epilogue_reg_mentioned_p (XVECEXP (insn, i, j)))
return 1;
}
else if (fmt[i] == 'e' && epilogue_reg_mentioned_p (XEXP (insn, i)))
return 1;
}
return 0;
}
/* Return the bytes needed to compute the frame pointer from the current
stack pointer.
@ -3785,22 +3851,22 @@ mips_output_float (stream, value)
*/
unsigned long
long
compute_frame_size (size)
int size; /* # of var. bytes allocated */
{
int regno;
unsigned long total_size; /* # bytes that the entire frame takes up */
unsigned long var_size; /* # bytes that variables take up */
unsigned long args_size; /* # bytes that outgoing arguments take up */
unsigned long extra_size; /* # extra bytes */
unsigned int gp_reg_rounded; /* # bytes needed to store gp after rounding */
unsigned int gp_reg_size; /* # bytes needed to store gp regs */
unsigned int fp_reg_size; /* # bytes needed to store fp regs */
unsigned long mask; /* mask of saved gp registers */
unsigned long fmask; /* mask of saved fp registers */
int fp_inc; /* 1 or 2 depending on the size of fp regs */
int fp_bits; /* bitmask to use for each fp register */
long total_size; /* # bytes that the entire frame takes up */
long var_size; /* # bytes that variables take up */
long args_size; /* # bytes that outgoing arguments take up */
long extra_size; /* # extra bytes */
long gp_reg_rounded; /* # bytes needed to store gp after rounding */
long gp_reg_size; /* # bytes needed to store gp regs */
long fp_reg_size; /* # bytes needed to store fp regs */
long mask; /* mask of saved gp registers */
long fmask; /* mask of saved fp registers */
int fp_inc; /* 1 or 2 depending on the size of fp regs */
long fp_bits; /* bitmask to use for each fp register */
gp_reg_size = 0;
fp_reg_size = 0;
@ -3826,7 +3892,7 @@ compute_frame_size (size)
if (MUST_SAVE_REGISTER (regno))
{
gp_reg_size += UNITS_PER_WORD;
mask |= 1 << (regno - GP_REG_FIRST);
mask |= 1L << (regno - GP_REG_FIRST);
}
}
@ -3900,156 +3966,213 @@ compute_frame_size (size)
}
/* Save/restore registers printing out the instructions to a file. */
/* Common code to emit the insns (or to write the instructions to a file)
to save/restore registers.
void
save_restore (file, gp_op, gp_2word_op, fp_op)
FILE *file; /* stream to write to */
char *gp_op; /* operation to do on gp registers */
char *gp_2word_op; /* 2 word op to do on gp registers */
char *fp_op; /* operation to do on fp registers */
{
int regno;
unsigned long mask = current_frame_info.mask;
unsigned long fmask = current_frame_info.fmask;
unsigned long gp_offset;
unsigned long fp_offset;
unsigned long min_offset;
char *base_reg;
Other parts of the code assume that MIPS_TEMP1_REGNUM (aka large_reg)
is not modified within save_restore_insns. */
if (mask == 0 && fmask == 0)
return;
base_reg = reg_names[STACK_POINTER_REGNUM];
gp_offset = current_frame_info.gp_sp_offset;
fp_offset = current_frame_info.fp_sp_offset;
min_offset = (gp_offset < fp_offset && mask != 0) ? gp_offset : fp_offset;
/* Deal with calling functions with a large structure. */
if (min_offset >= 32768)
{
char *temp = reg_names[MIPS_TEMP2_REGNUM];
fprintf (file, "\tli\t%s,%ld\n", temp, min_offset);
fprintf (file, "\taddu\t%s,%s,%s\n", temp, temp, base_reg);
base_reg = temp;
gp_offset = min_offset - gp_offset;
fp_offset = min_offset - fp_offset;
}
/* Save registers starting from high to low. The debuggers prefer
at least the return register be stored at func+4, and also it
allows us not to need a nop in the epilog if at least one
register is reloaded in addition to return address. */
if (mask || frame_pointer_needed)
{
for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
{
if ((mask & (1L << (regno - GP_REG_FIRST))) != 0
|| (regno == FRAME_POINTER_REGNUM && frame_pointer_needed))
{
fprintf (file, "\t%s\t%s,%d(%s)\n",
gp_op, reg_names[regno],
gp_offset, base_reg);
gp_offset -= UNITS_PER_WORD;
}
}
}
if (fmask)
{
int fp_inc = (TARGET_FLOAT64) ? 1 : 2;
for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
{
if ((fmask & (1L << (regno - FP_REG_FIRST))) != 0)
{
fprintf (file, "\t%s\t%s,%d(%s)\n",
fp_op, reg_names[regno], fp_offset, base_reg);
fp_offset -= 2*UNITS_PER_WORD;
}
}
}
}
/* Common code to emit the insns to save/restore registers. */
#define BITSET_P(value,bit) (((value) & (1L << (bit))) != 0)
static void
save_restore_insns (store_p)
save_restore_insns (store_p, large_reg, large_offset, file)
int store_p; /* true if this is prologue */
rtx large_reg; /* register holding large offset constant or NULL */
long large_offset; /* large constant offset value */
FILE *file; /* file to write instructions to instead of making RTL */
{
long mask = current_frame_info.mask;
long fmask = current_frame_info.fmask;
int regno;
rtx base_reg_rtx = stack_pointer_rtx;
unsigned long mask = current_frame_info.mask;
unsigned long fmask = current_frame_info.fmask;
unsigned long gp_offset;
unsigned long fp_offset;
unsigned long min_offset;
rtx base_reg_rtx;
long base_offset;
long gp_offset;
long fp_offset;
long end_offset;
if (frame_pointer_needed && !BITSET_P (mask, FRAME_POINTER_REGNUM - GP_REG_FIRST))
abort ();
if (mask == 0 && fmask == 0)
return;
gp_offset = current_frame_info.gp_sp_offset;
fp_offset = current_frame_info.fp_sp_offset;
min_offset = (gp_offset < fp_offset && mask != 0) ? gp_offset : fp_offset;
/* Deal with calling functions with a large structure. */
if (min_offset >= 32768)
{
base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
emit_move_insn (base_reg_rtx, GEN_INT (min_offset));
emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx));
gp_offset = min_offset - gp_offset;
fp_offset = min_offset - fp_offset;
}
/* Save registers starting from high to low. The debuggers prefer
at least the return register be stored at func+4, and also it
allows us not to need a nop in the epilog if at least one
register is reloaded in addition to return address. */
if (mask || frame_pointer_needed)
/* Save GP registers if needed. */
if (mask)
{
/* Pick which pointer to use as a base register. For small
frames, just use the stack pointer. Otherwise, use a
temporary register. Save 2 cycles if the save area is near
the end of a large frame, by reusing the constant created in
the prologue/epilogue to adjust the stack frame. */
gp_offset = current_frame_info.gp_sp_offset;
end_offset = gp_offset - (current_frame_info.gp_reg_size - UNITS_PER_WORD);
if (gp_offset < 0 || end_offset < 0)
fatal ("gp_offset (%ld) or end_offset (%ld) is less than zero.",
gp_offset, end_offset);
else if (gp_offset < 32768)
{
base_reg_rtx = stack_pointer_rtx;
base_offset = 0;
}
else if (large_reg != (rtx)0
&& (((unsigned long)(large_offset - gp_offset)) < 32768)
&& (((unsigned long)(large_offset - end_offset)) < 32768))
{
base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
base_offset = large_offset;
if (file == (FILE *)0)
emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx));
else
fprintf (file, "\taddu\t%s,%s,%s\n",
reg_names[MIPS_TEMP2_REGNUM],
reg_names[REGNO (large_reg)],
reg_names[STACK_POINTER_REGNUM]);
}
else
{
base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
base_offset = gp_offset;
if (file == (FILE *)0)
{
emit_move_insn (base_reg_rtx, GEN_INT (gp_offset));
emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx));
}
else
fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n",
reg_names[MIPS_TEMP2_REGNUM],
(long)base_offset,
(long)base_offset,
reg_names[MIPS_TEMP2_REGNUM],
reg_names[MIPS_TEMP2_REGNUM],
reg_names[STACK_POINTER_REGNUM]);
}
for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
{
if ((mask & (1L << (regno - GP_REG_FIRST))) != 0
|| (regno == FRAME_POINTER_REGNUM && frame_pointer_needed))
if (BITSET_P (mask, regno - GP_REG_FIRST))
{
rtx reg_rtx = gen_rtx (REG, Pmode, regno);
rtx mem_rtx = gen_rtx (MEM, Pmode,
gen_rtx (PLUS, Pmode, base_reg_rtx,
GEN_INT (gp_offset)));
if (file == (FILE *)0)
{
rtx reg_rtx = gen_rtx (REG, Pmode, regno);
rtx mem_rtx = gen_rtx (MEM, Pmode,
gen_rtx (PLUS, Pmode, base_reg_rtx,
GEN_INT (gp_offset - base_offset)));
if (store_p)
emit_move_insn (mem_rtx, reg_rtx);
if (store_p)
emit_move_insn (mem_rtx, reg_rtx);
else
emit_move_insn (reg_rtx, mem_rtx);
}
else
emit_move_insn (reg_rtx, mem_rtx);
fprintf (file, "\t%s\t%s,%ld(%s)\n",
(store_p) ? "sw" : "lw",
reg_names[regno],
gp_offset - base_offset,
reg_names[REGNO(base_reg_rtx)]);
gp_offset -= UNITS_PER_WORD;
}
}
}
else
{
base_reg_rtx = (rtx)0; /* Make sure these are initialzed */
base_offset = 0;
}
/* Save floating point registers if needed. */
if (fmask)
{
int fp_inc = (TARGET_FLOAT64) ? 1 : 2;
/* Pick which pointer to use as a base register. */
fp_offset = current_frame_info.fp_sp_offset;
end_offset = fp_offset - (current_frame_info.fp_reg_size - UNITS_PER_WORD);
if (fp_offset < 0 || end_offset < 0)
fatal ("fp_offset (%ld) or end_offset (%ld) is less than zero.",
fp_offset, end_offset);
else if (fp_offset < 32768)
{
base_reg_rtx = stack_pointer_rtx;
base_offset = 0;
}
else if (base_reg_rtx != (rtx)0
&& (((unsigned long)(base_offset - fp_offset)) < 32768)
&& (((unsigned long)(base_offset - end_offset)) < 32768))
{
; /* already set up for gp registers above */
}
else if (large_reg != (rtx)0
&& (((unsigned long)(large_offset - fp_offset)) < 32768)
&& (((unsigned long)(large_offset - end_offset)) < 32768))
{
base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
base_offset = large_offset;
if (file == (FILE *)0)
emit_insn (gen_addsi3 (base_reg_rtx, large_reg, stack_pointer_rtx));
else
fprintf (file, "\taddu\t%s,%s,%s\n",
reg_names[MIPS_TEMP2_REGNUM],
reg_names[REGNO (large_reg)],
reg_names[STACK_POINTER_REGNUM]);
}
else
{
base_reg_rtx = gen_rtx (REG, Pmode, MIPS_TEMP2_REGNUM);
base_offset = fp_offset;
if (file == (FILE *)0)
{
emit_move_insn (base_reg_rtx, GEN_INT (fp_offset));
emit_insn (gen_addsi3 (base_reg_rtx, base_reg_rtx, stack_pointer_rtx));
}
else
fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n\taddu\t%s,%s,%s\n",
reg_names[MIPS_TEMP2_REGNUM],
(long)base_offset,
(long)base_offset,
reg_names[MIPS_TEMP2_REGNUM],
reg_names[MIPS_TEMP2_REGNUM],
reg_names[STACK_POINTER_REGNUM]);
}
for (regno = FP_REG_LAST-1; regno >= FP_REG_FIRST; regno -= fp_inc)
{
if ((fmask & (1L << (regno - FP_REG_FIRST))) != 0)
if (BITSET_P (fmask, regno - FP_REG_FIRST))
{
rtx reg_rtx = gen_rtx (REG, DFmode, regno);
rtx mem_rtx = gen_rtx (MEM, DFmode,
gen_rtx (PLUS, Pmode, base_reg_rtx,
GEN_INT (fp_offset)));
if (file == (FILE *)0)
{
rtx reg_rtx = gen_rtx (REG, DFmode, regno);
rtx mem_rtx = gen_rtx (MEM, DFmode,
gen_rtx (PLUS, Pmode, base_reg_rtx,
GEN_INT (fp_offset - base_offset)));
if (store_p)
emit_move_insn (mem_rtx, reg_rtx);
if (store_p)
emit_move_insn (mem_rtx, reg_rtx);
else
emit_move_insn (reg_rtx, mem_rtx);
}
else
emit_move_insn (reg_rtx, mem_rtx);
fprintf (file, "\t%s\t%s,%ld(%s)\n",
(store_p) ? "s.d" : "l.d",
reg_names[regno],
fp_offset - base_offset,
reg_names[REGNO(base_reg_rtx)]);
fp_offset -= 2*UNITS_PER_WORD;
}
@ -4065,7 +4188,7 @@ function_prologue (file, size)
FILE *file;
int size;
{
int tsize = current_frame_info.total_size;
long tsize = current_frame_info.total_size;
ASM_OUTPUT_SOURCE_FILENAME (file, DECL_SOURCE_FILE (current_function_decl));
@ -4076,6 +4199,7 @@ function_prologue (file, size)
fputs ("\t.ent\t", file);
assemble_name (file, current_function_name);
fputs ("\n", file);
assemble_name (file, current_function_name);
fputs (":\n", file);
@ -4112,7 +4236,7 @@ void
mips_expand_prologue ()
{
int regno;
int tsize;
long tsize;
tree fndecl = current_function_decl; /* current... is tooo long */
tree fntype = TREE_TYPE (fndecl);
tree fnargs = (TREE_CODE (fntype) != METHOD_TYPE)
@ -4120,6 +4244,7 @@ mips_expand_prologue ()
: 0;
tree next_arg;
tree cur_arg;
rtx tmp_rtx = (rtx)0;
char *arg_name = (char *)0;
CUMULATIVE_ARGS args_so_far;
@ -4200,14 +4325,14 @@ mips_expand_prologue ()
if (tsize > 32767)
{
rtx tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
emit_move_insn (tmp_rtx, tsize_rtx);
tsize_rtx = tmp_rtx;
}
emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx));
save_restore_insns (TRUE);
save_restore_insns (TRUE, tmp_rtx, tsize, (FILE *)0);
if (frame_pointer_needed)
emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
@ -4228,7 +4353,7 @@ function_epilogue (file, size)
FILE *file;
int size;
{
int tsize;
long tsize;
char *sp_str = reg_names[STACK_POINTER_REGNUM];
char *t1_str = reg_names[MIPS_TEMP1_REGNUM];
rtx epilogue_delay = current_function_epilogue_delay_list;
@ -4236,6 +4361,9 @@ function_epilogue (file, size)
int noepilogue = FALSE;
int load_nop = FALSE;
int load_only_r31;
rtx tmp_rtx = (rtx)0;
rtx restore_rtx;
int i;
/* The epilogue does not depend on any registers, but the stack
registers, so we assume that if we have 1 pending nop, it can be
@ -4316,13 +4444,16 @@ function_epilogue (file, size)
fprintf (file, "\t.set\tnoreorder\n");
if (tsize > 32767)
fprintf (file, "\tli\t%s,%d\n", t1_str, tsize);
{
fprintf (file, "\tli\t%s,0x%.08lx\t# %ld\n", t1_str, (long)tsize, (long)tsize);
tmp_rtx = gen_rtx (REG, Pmode, MIPS_TEMP1_REGNUM);
}
if (frame_pointer_needed)
fprintf (file, "\tmove\t%s,%s\t\t\t# sp not trusted here\n",
sp_str, reg_names[FRAME_POINTER_REGNUM]);
save_restore (file, "lw", "ld", "l.d");
save_restore_insns (FALSE, tmp_rtx, tsize, file);
load_only_r31 = (current_frame_info.mask == (1 << 31)
&& current_frame_info.fmask == 0);
@ -4469,12 +4600,13 @@ function_epilogue (file, size)
void
mips_expand_epilogue ()
{
int tsize = current_frame_info.total_size;
long tsize = current_frame_info.total_size;
rtx tsize_rtx = GEN_INT (tsize);
rtx tmp_rtx = (rtx)0;
if (tsize > 32767)
{
rtx tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
tmp_rtx = gen_rtx (REG, SImode, MIPS_TEMP1_REGNUM);
emit_move_insn (tmp_rtx, tsize_rtx);
tsize_rtx = tmp_rtx;
}
@ -4484,7 +4616,7 @@ mips_expand_epilogue ()
if (frame_pointer_needed)
emit_insn (gen_movsi (stack_pointer_rtx, frame_pointer_rtx));
save_restore_insns (FALSE);
save_restore_insns (FALSE, tmp_rtx, tsize, (FILE *)0);
emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tsize_rtx));
}

View File

@ -126,7 +126,8 @@ extern int arith32_operand ();
extern int arith_operand ();
extern int cmp_op ();
extern int cmp2_op ();
extern unsigned long compute_frame_size ();
extern long compute_frame_size ();
extern int epilogue_reg_mentioned_p ();
extern void expand_block_move ();
extern int equality_op ();
extern int fcmp_op ();
@ -482,7 +483,7 @@ while (0)
/* Print subsidiary information on the compiler version in use. */
#define MIPS_VERSION "[AL 1.1, MM 31]"
#define MIPS_VERSION "[AL 1.1, MM 32]"
#ifndef MACHINE_TYPE
#define MACHINE_TYPE "BSD Mips"
@ -1229,6 +1230,7 @@ extern char mips_hard_regno_mode_ok[][FIRST_PSEUDO_REGISTER];
scratch register set, and not used for passing and returning
arguments and any other information used in the calling sequence
(such as pic). */
#define MIPS_TEMP1_REGNUM (GP_REG_FIRST + 8)
#define MIPS_TEMP2_REGNUM (GP_REG_FIRST + 9)
@ -1540,21 +1542,21 @@ extern enum reg_class mips_char_to_class[];
struct mips_frame_info
{
unsigned long total_size; /* # bytes that the entire frame takes up */
unsigned long var_size; /* # bytes that variables take up */
unsigned long args_size; /* # bytes that outgoing arguments take up */
unsigned long extra_size; /* # bytes of extra gunk */
unsigned int gp_reg_size; /* # bytes needed to store gp regs */
unsigned int fp_reg_size; /* # bytes needed to store fp regs */
unsigned long mask; /* mask of saved gp registers */
unsigned long fmask; /* mask of saved fp registers */
long gp_save_offset; /* offset from vfp to store gp registers */
long fp_save_offset; /* offset from vfp to store fp registers */
unsigned long gp_sp_offset; /* offset from new sp to store gp registers */
unsigned long fp_sp_offset; /* offset from new sp to store fp registers */
int initialized; /* != 0 if frame size already calculated */
int num_gp; /* number of gp registers saved */
int num_fp; /* number of fp registers saved */
long total_size; /* # bytes that the entire frame takes up */
long var_size; /* # bytes that variables take up */
long args_size; /* # bytes that outgoing arguments take up */
long extra_size; /* # bytes of extra gunk */
int gp_reg_size; /* # bytes needed to store gp regs */
int fp_reg_size; /* # bytes needed to store fp regs */
long mask; /* mask of saved gp registers */
long fmask; /* mask of saved fp registers */
long gp_save_offset; /* offset from vfp to store gp registers */
long fp_save_offset; /* offset from vfp to store fp registers */
long gp_sp_offset; /* offset from new sp to store gp registers */
long fp_sp_offset; /* offset from new sp to store fp registers */
int initialized; /* != 0 if frame size already calculated */
int num_gp; /* number of gp registers saved */
int num_fp; /* number of fp registers saved */
};
extern struct mips_frame_info current_frame_info;
@ -1896,9 +1898,7 @@ typedef struct mips_args {
#define ELIGIBLE_FOR_EPILOGUE_DELAY(INSN,N) \
(get_attr_dslot (INSN) == DSLOT_NO \
&& get_attr_length (INSN) == 1 \
&& ! reg_mentioned_p (stack_pointer_rtx, PATTERN (INSN)) \
&& ! reg_mentioned_p (frame_pointer_rtx, PATTERN (INSN)) \
&& ! reg_mentioned_p (arg_pointer_rtx, PATTERN (INSN)))
&& ! epilogue_reg_mentioned_p (PATTERN (INSN)))
/* Tell prologue and epilogue if register REGNO should be saved / restored. */