Commit aadcdb45 by Jeff Law

pa.c (print_stw, print_ldw): Delete.

	* pa.c (print_stw, print_ldw): Delete.
	(eligible_for_epilogue_delay): Delete.
	(hppa_epilogue_delay_slots): Delete.
	(store_reg, load_reg, set_reg_plus_d): New helper functions.
	(output_function_prologue): Only emit assembler pseudo-ops
	to denote the start of a function.  Place the correct
	value into hp_profile_label_name if profiling.
	(output_function_epilogue): Only emit assembler pseudo-ops
	to deonte the end of a function.
	(hppa_expand_prologue): New function to emit all prologue
	code as RTL.
	(hppa_expand_epilogue): Likewise for the epilogue.
	(compute_frame_size): Update to account for using %r4 as an
	allocatable register if the frame pointer was eliminated.

From-SVN: r4025
parent 527986c9
...@@ -1597,29 +1597,94 @@ output_ascii (file, p, size) ...@@ -1597,29 +1597,94 @@ output_ascii (file, p, size)
*/ */
/* Helper functions */ /* Emit RTL to store REG at the memory location specified by BASE+DISP.
void Handle case where DISP > 8k by using the add_high_const pattern.
print_stw (file, r, disp, base)
FILE *file; Note in DISP > 8k case, we will leave the high part of the address
int r, disp, base; in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/
static void
store_reg (reg, disp, base)
int reg, disp, base;
{ {
if (VAL_14_BITS_P (disp)) if (VAL_14_BITS_P (disp))
fprintf (file, "\tstw %%r%d,%d(0,%%r%d)\n", r, disp, base); {
emit_move_insn (gen_rtx (MEM, SImode,
gen_rtx (PLUS, SImode,
gen_rtx (REG, SImode, base),
GEN_INT (disp))),
gen_rtx (REG, SImode, reg));
}
else else
fprintf (file, "\taddil L'%d,%%r%d\n\tstw %%r%d,R'%d(0,%%r1)\n", disp, base, {
r, disp); emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1),
gen_rtx (REG, SImode, base),
GEN_INT (disp)));
emit_move_insn (gen_rtx (MEM, SImode,
gen_rtx (LO_SUM, SImode,
gen_rtx (REG, SImode, 1),
GEN_INT (disp))),
gen_rtx (REG, SImode, reg));
}
} }
void /* Emit RTL to load REG from the memory location specified by BASE+DISP.
print_ldw (file, r, disp, base) Handle case where DISP > 8k by using the add_high_const pattern.
FILE *file;
int r, disp, base; Note in DISP > 8k case, we will leave the high part of the address
in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/
static void
load_reg (reg, disp, base)
int reg, disp, base;
{ {
if (VAL_14_BITS_P (disp)) if (VAL_14_BITS_P (disp))
fprintf (file, "\tldw %d(0,%d),%d\n", disp, base, r); {
emit_move_insn (gen_rtx (REG, SImode, reg),
gen_rtx (MEM, SImode,
gen_rtx (PLUS, SImode,
gen_rtx (REG, SImode, base),
GEN_INT (disp))));
}
else else
fprintf (file, "\taddil L'%d,%d\n\tldw R'%d(0,%%r1),%d\n", disp, base, {
disp, r); emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1),
gen_rtx (REG, SImode, base),
GEN_INT (disp)));
emit_move_insn (gen_rtx (REG, SImode, reg),
gen_rtx (MEM, SImode,
gen_rtx (LO_SUM, SImode,
gen_rtx (REG, SImode, 1),
GEN_INT (disp))));
}
}
/* Emit RTL to set REG to the value specified by BASE+DISP.
Handle case where DISP > 8k by using the add_high_const pattern.
Note in DISP > 8k case, we will leave the high part of the address
in %r1. There is code in expand_hppa_{prologue,epilogue} that knows this.*/
static void
set_reg_plus_d(reg, base, disp)
int reg, base, disp;
{
if (VAL_14_BITS_P (disp))
{
emit_move_insn (gen_rtx (REG, SImode, reg),
gen_rtx (PLUS, SImode,
gen_rtx (REG, SImode, base),
GEN_INT (disp)));
}
else
{
emit_insn (gen_add_high_const (gen_rtx (REG, SImode, 1),
gen_rtx (REG, SImode, base),
GEN_INT (disp)));
emit_move_insn (gen_rtx (REG, SImode, reg),
gen_rtx (LO_SUM, SImode,
gen_rtx (REG, SImode, 1),
GEN_INT (disp)));
}
} }
/* Global variables set by FUNCTION_PROLOGUE. */ /* Global variables set by FUNCTION_PROLOGUE. */
...@@ -1641,12 +1706,21 @@ compute_frame_size (size, fregs_live) ...@@ -1641,12 +1706,21 @@ compute_frame_size (size, fregs_live)
fsize = size + (size || frame_pointer_needed ? 8 : 0); fsize = size + (size || frame_pointer_needed ? 8 : 0);
/* fp is stored in a special place. */ /* fp is stored in a special place. */
if (frame_pointer_needed)
{
for (i = 18; i >= 5; i--) for (i = 18; i >= 5; i--)
if (regs_ever_live[i]) if (regs_ever_live[i])
fsize += 4; fsize += 4;
if (regs_ever_live[3]) if (regs_ever_live[3])
fsize += 4; fsize += 4;
}
else
{
for (i = 18; i >= 3; i--)
if (regs_ever_live[i])
fsize += 4;
}
fsize = (fsize + 7) & ~7; fsize = (fsize + 7) & ~7;
if (!TARGET_SNAKE) if (!TARGET_SNAKE)
...@@ -1675,23 +1749,17 @@ compute_frame_size (size, fregs_live) ...@@ -1675,23 +1749,17 @@ compute_frame_size (size, fregs_live)
return TARGET_SNAKE ? (fsize + 63 & ~63) : fsize; return TARGET_SNAKE ? (fsize + 63 & ~63) : fsize;
} }
rtx hp_profile_label_rtx;
static char hp_profile_label_name[8];
void void
output_function_prologue (file, size) output_function_prologue (file, size)
FILE *file; FILE *file;
int size; int size;
{ {
extern char call_used_regs[];
extern int frame_pointer_needed;
extern int current_function_returns_struct;
int i, offset;
int merge_sp_adjust_with_store = 0;
save_fregs = 0;
local_fsize = size + (size || frame_pointer_needed ? 8 : 0);
actual_fsize = compute_frame_size (size, &save_fregs);
/* Let's not try to bullshit more than we need to here. */ /* hppa_expand_prologue does the dirty work now. We just need
/* This might be right a lot of the time */ to output the assembler directives which denote the start
of a function. */
fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=%d", actual_fsize); fprintf (file, "\t.PROC\n\t.CALLINFO FRAME=%d", actual_fsize);
if (regs_ever_live[2] || profile_flag) if (regs_ever_live[2] || profile_flag)
fprintf (file, ",CALLS,SAVE_RP\n"); fprintf (file, ",CALLS,SAVE_RP\n");
...@@ -1699,104 +1767,159 @@ output_function_prologue (file, size) ...@@ -1699,104 +1767,159 @@ output_function_prologue (file, size)
fprintf (file, ",NO_CALLS\n"); fprintf (file, ",NO_CALLS\n");
fprintf (file, "\t.ENTRY\n"); fprintf (file, "\t.ENTRY\n");
/* Some registers have places to go in the current stack /* Horrid hack. emit_function_prologue will modify this RTL in
structure. */ place to get the expected results. */
if (profile_flag)
sprintf(hp_profile_label_name, "LP$%04d", hp_profile_labelno);
}
hppa_expand_prologue()
{
extern char call_used_regs[];
int size = get_frame_size ();
int merge_sp_adjust_with_store = 0;
int i, offset;
rtx tmpreg, size_rtx;
save_fregs = 0;
local_fsize = size + (size || frame_pointer_needed ? 8 : 0);
actual_fsize = compute_frame_size (size, &save_fregs);
/* Compute a few things we will use often. */
tmpreg = gen_rtx (REG, SImode, 1);
size_rtx = GEN_INT (actual_fsize);
/* Save RP first. The calling conventions manual states RP will
always be stored into the caller's frame at sp-20. */
if (regs_ever_live[2] || profile_flag) if (regs_ever_live[2] || profile_flag)
fprintf (file, "\tstw %%r2,-20(0,%%r30)\n"); store_reg (2, -20, STACK_POINTER_REGNUM);
/* Reserve space for local variables. */ /* Allocate the local frame and set up the frame pointer if needed. */
if (actual_fsize) if (actual_fsize)
if (frame_pointer_needed) if (frame_pointer_needed)
{ {
/* Copy the old frame pointer temporarily into %r1. Set up the
new stack pointer, then store away the saved old frame pointer
into the stack at sp+actual_fsize and at the same time update
the stack pointer by actual_fsize bytes. Two versions, first
handles small (<8k) frames. The second handles large (>8k)
frames. */
emit_move_insn (tmpreg, frame_pointer_rtx);
emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
if (VAL_14_BITS_P (actual_fsize)) if (VAL_14_BITS_P (actual_fsize))
fprintf (file, "\tcopy %%r4,%%r1\n\tcopy %%r30,%%r4\n\tstwm %%r1,%d(0,%%r30)\n", emit_insn (gen_post_stwm (stack_pointer_rtx,
actual_fsize); stack_pointer_rtx,
size_rtx, tmpreg));
else else
{ {
fprintf (file, "\tcopy %%r4,%%r1\n\tcopy %%r30,%%r4\n\tstw %%r1,0(0,%%r4)\n"); store_reg (1, 0, FRAME_POINTER_REGNUM);
fprintf (file, "\taddil L'%d,%%r30\n\tldo R'%d(%%r1),%%r30\n", set_reg_plus_d (STACK_POINTER_REGNUM,
actual_fsize, actual_fsize); STACK_POINTER_REGNUM,
actual_fsize);
} }
} }
/* no frame pointer needed. */
else else
{ {
/* In some cases we can perform the first callee register save
and allocating the stack frame at the same time. If so, just
make a note of it and defer allocating the frame until saving
the callee registers. */
if (VAL_14_BITS_P (-actual_fsize) if (VAL_14_BITS_P (-actual_fsize)
&& local_fsize == 0 && ! flag_pic && ! profile_flag) && local_fsize == 0
&& ! profile_flag
&& ! flag_pic)
merge_sp_adjust_with_store = 1; merge_sp_adjust_with_store = 1;
else if (VAL_14_BITS_P (actual_fsize)) /* Can not optimize. Adjust the stack frame by actual_fsize bytes. */
fprintf (file, "\tldo %d(%%r30),%%r30\n", actual_fsize); else if (actual_fsize != 0)
else set_reg_plus_d (STACK_POINTER_REGNUM,
fprintf (file, "\taddil L'%d,%%r30\n\tldo R'%d(%%r1),%%r30\n", STACK_POINTER_REGNUM,
actual_fsize, actual_fsize); actual_fsize);
} }
/* The hppa calling conventions say that that %r19, the pic offset /* The hppa calling conventions say that that %r19, the pic offset
register, is saved at sp - 32 (in this function's frame) */ register, is saved at sp - 32 (in this function's frame) when
generating PIC code. */
if (flag_pic) if (flag_pic)
{ store_reg (19, -32, STACK_POINTER_REGNUM);
fprintf (file, "\tstw %%r19,-32(0,%%r30)\n");
}
/* Instead of taking one argument, the counter label, as most normal
mcounts do, _mcount appears to behave differently on the HPPA. It
takes the return address of the caller, the address of this
routine, and the address of the label. Also, it isn't magic, so
argument registers have to be preserved. */
/* Profiling code.
Instead of taking one argument, the counter label, as most normal
mcounts do, _mcount appears to behave differently on the HPPA. It
takes the return address of the caller, the address of this routine,
and the address of the label. Also, it isn't magic, so
argument registre hsave to be preserved. */
if (profile_flag) if (profile_flag)
{ {
unsigned int pc_offset = int pc_offset, i, arg_offset, basereg, offsetadj;
(4 + (frame_pointer_needed
pc_offset = 4 + (frame_pointer_needed
? (VAL_14_BITS_P (actual_fsize) ? 12 : 20) ? (VAL_14_BITS_P (actual_fsize) ? 12 : 20)
: (VAL_14_BITS_P (actual_fsize) ? 4 : 8))); : (VAL_14_BITS_P (actual_fsize) ? 4 : 8));
int i, arg_offset;
int basereg, offsetadj;
/* When the function has a frame pointer, use that as the base /* When the function has a frame pointer, use it as the base
register for saving/restoring registers. Else use the stack register for saving/restore registers. Else use the stack
pointer. Adjust the offset according to the frame size if this pointer. Adjust the offset according to the frame size if
function does not have a frame pointer. */ this function does not have a frame pointer. */
basereg = frame_pointer_needed ? FRAME_POINTER_REGNUM basereg = frame_pointer_needed ? FRAME_POINTER_REGNUM
: STACK_POINTER_REGNUM; : STACK_POINTER_REGNUM;
offsetadj = frame_pointer_needed ? 0 : actual_fsize; offsetadj = frame_pointer_needed ? 0 : actual_fsize;
/* Horrid hack. emit_function_prologue will modify this RTL in
place to get the expected results. sprintf here is just to
put something in the name. */
sprintf(hp_profile_label_name, "LP$%04d", -1);
hp_profile_label_rtx = gen_rtx (SYMBOL_REF, SImode,
hp_profile_label_name);
if (current_function_returns_struct) if (current_function_returns_struct)
print_stw (file, STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg); store_reg (STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg);
for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4) for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4)
if (regs_ever_live[i]) if (regs_ever_live [i])
{ {
print_stw (file, i, arg_offset, basereg); store_reg (i, arg_offset, basereg);
/* It is possible for the arg_offset not to fit in 14 bits /* Deal with arg_offset not fitting in 14 bits. */
when profiling a function without a frame pointer. Deal
with such cases. */
pc_offset += VAL_14_BITS_P (arg_offset) ? 4 : 8; pc_offset += VAL_14_BITS_P (arg_offset) ? 4 : 8;
} }
fprintf (file,
"\tcopy %%r2,%%r26\n\taddil L'LP$%04d-$global$,%%r27\n\tldo R'LP$%04d-$global$(%%r1),%%r24\n\tbl _mcount,%%r2\n\tldo %d(%%r2),%%r25\n", emit_move_insn (gen_rtx (REG, SImode, 26), gen_rtx (REG, SImode, 2));
hp_profile_labelno, hp_profile_labelno, -pc_offset - 12 - 8); emit_move_insn (tmpreg, gen_rtx (HIGH, SImode, hp_profile_label_rtx));
emit_move_insn (gen_rtx (REG, SImode, 24),
gen_rtx (LO_SUM, SImode, tmpreg, hp_profile_label_rtx));
/* %r25 is set from within the output pattern. */
emit_insn (gen_call_profiler (GEN_INT (- pc_offset - 20)));
/* Restore argument registers. */
for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4) for (i = 26, arg_offset = -36 - offsetadj; i >= 23; i--, arg_offset -= 4)
if (regs_ever_live[i]) if (regs_ever_live [i])
print_ldw (file, i, arg_offset, basereg); load_reg (i, arg_offset, basereg);
if (current_function_returns_struct) if (current_function_returns_struct)
print_ldw (file, STRUCT_VALUE_REGNUM, - 12 - offsetadj, basereg); load_reg (STRUCT_VALUE_REGNUM, -12 - offsetadj, basereg);
} }
/* Normal register save. */ /* Normal register save.
Do not save the frame pointer in the frame_pointer_needed case. It
was done earlier. */
if (frame_pointer_needed) if (frame_pointer_needed)
{ {
for (i = 18, offset = local_fsize; i >= 5; i--) for (i = 18, offset = local_fsize; i >= 3; i--)
if (regs_ever_live[i] && ! call_used_regs[i]) if (regs_ever_live[i] && ! call_used_regs[i]
{ && i != FRAME_POINTER_REGNUM)
print_stw (file, i, offset, 4); offset += 4;
}
if (regs_ever_live[3] && ! call_used_regs[3])
{ {
print_stw (file, 3, offset, 4); offset += 4; store_reg (i, offset, FRAME_POINTER_REGNUM);
offset += 4;
} }
} }
/* No frame pointer needed. */
else else
{ {
for (i = 18, offset = local_fsize - actual_fsize; i >= 5; i--) for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
if (regs_ever_live[i] && ! call_used_regs[i]) if (regs_ever_live[i] && ! call_used_regs[i])
{ {
/* If merge_sp_adjust_with_store is nonzero, then we can /* If merge_sp_adjust_with_store is nonzero, then we can
...@@ -1804,27 +1927,22 @@ output_function_prologue (file, size) ...@@ -1804,27 +1927,22 @@ output_function_prologue (file, size)
if (merge_sp_adjust_with_store) if (merge_sp_adjust_with_store)
{ {
merge_sp_adjust_with_store = 0; merge_sp_adjust_with_store = 0;
fprintf (file, "\tstwm %d,%d(0,%d)\n", i, -offset, 30); emit_insn (gen_post_stwm (stack_pointer_rtx,
} stack_pointer_rtx,
else GEN_INT (-offset),
print_stw (file, i, offset, 30); offset += 4; gen_rtx (REG, SImode, i)));
}
if (regs_ever_live[3] && ! call_used_regs[3])
{
/* If merge_sp_adjust_with_store is nonzero, then we can
optimize the first GR save. */
if (merge_sp_adjust_with_store)
{
merge_sp_adjust_with_store = 0;
fprintf (file, "\tstwm %%r3,%d(0,%%r30)\n", -offset);
} }
else else
print_stw (file, 3, offset, 30); offset += 4; store_reg (i, offset, STACK_POINTER_REGNUM);
offset += 4;
} }
/* If we wanted to merge the SP adjustment with a GR save, but we never /* If we wanted to merge the SP adjustment with a GR save, but we never
did any GR saves, then just output the adjustment here. */ did any GR saves, then just emit the adjustment here. */
if (merge_sp_adjust_with_store) if (merge_sp_adjust_with_store)
fprintf (file, "\tldo %d(%%r30),%%r30\n", actual_fsize); set_reg_plus_d (STACK_POINTER_REGNUM,
STACK_POINTER_REGNUM,
actual_fsize);
} }
/* Align pointer properly (doubleword boundary). */ /* Align pointer properly (doubleword boundary). */
...@@ -1833,28 +1951,23 @@ output_function_prologue (file, size) ...@@ -1833,28 +1951,23 @@ output_function_prologue (file, size)
/* Floating point register store. */ /* Floating point register store. */
if (save_fregs) if (save_fregs)
{ {
/* First get the frame or stack pointer to the start of the FP register
save area. */
if (frame_pointer_needed) if (frame_pointer_needed)
{ set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
if (VAL_14_BITS_P (offset))
fprintf (file, "\tldo %d(%%r4),%%r1\n", offset);
else else
fprintf (file, "\taddil L'%d,%%r4\n\tldo R'%d(%%r1),%%r1\n", set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
offset, offset);
} /* Now actually save the FP registers. */
else if (! TARGET_SNAKE)
{
if (VAL_14_BITS_P (offset))
fprintf (file, "\tldo %d(%%r30),%%r1\n", offset);
else
fprintf (file, "\taddil L'%d,%%r30\n\tldo R'%d(%%r1),%%r1\n",
offset, offset);
}
if (!TARGET_SNAKE)
{ {
for (i = 43; i >= 40; i--) for (i = 43; i >= 40; i--)
{ {
if (regs_ever_live[i]) if (regs_ever_live[i])
fprintf (file, "\tfstds,ma %s,8(0,%%r1)\n", reg_names[i]); emit_move_insn (gen_rtx (MEM, DFmode,
gen_rtx (POST_INC, DFmode, tmpreg)),
gen_rtx (REG, DFmode, i));
} }
} }
else else
...@@ -1862,199 +1975,144 @@ output_function_prologue (file, size) ...@@ -1862,199 +1975,144 @@ output_function_prologue (file, size)
for (i = 78; i >= 60; i -= 2) for (i = 78; i >= 60; i -= 2)
if (regs_ever_live[i] || regs_ever_live[i + 1]) if (regs_ever_live[i] || regs_ever_live[i + 1])
{ {
fprintf (file, "\tfstds,ma %s,8(0,%%r1)\n", reg_names[i]); emit_move_insn (gen_rtx (MEM, DFmode,
gen_rtx (POST_INC, DFmode, tmpreg)),
gen_rtx (REG, DFmode, i));
} }
} }
} }
} }
void void
output_function_epilogue (file, size) output_function_epilogue (file, size)
FILE *file; FILE *file;
int size; int size;
{ {
extern char call_used_regs[]; /* hppa_expand_epilogue does the dirty work now. We just need
extern int frame_pointer_needed; to output the assembler directives which denote the end
int i, offset; of a function. */
fprintf (file, "\t.EXIT\n\t.PROCEND\n");
}
void
hppa_expand_epilogue()
{
rtx tmpreg;
int offset,i;
int merge_sp_adjust_with_load = 0; int merge_sp_adjust_with_load = 0;
/* In the common cases restore RP early to avoid load/use interlock when /* We will use this often. */
RP gets used in the bv instruction. */ tmpreg = gen_rtx (REG, SImode, 1);
/* Try to restore RP early to avoid load/use interlocks when
RP gets used in the return (bv) instruction. This appears to still
be necessary even when we schedule the prologue and epilogue. */
if (frame_pointer_needed if (frame_pointer_needed
&& (regs_ever_live [2] || profile_flag)) && (regs_ever_live [2] || profile_flag))
fprintf (file, "\tldw -20(%%r4),%%r2\n"); load_reg (2, -20, FRAME_POINTER_REGNUM);
else if (VAL_14_BITS_P (actual_fsize + 20)
&& (regs_ever_live [2] || profile_flag)) /* No frame pointer, and stack is smaller than 8k. */
fprintf(file,"\tldw %d(0,%%r30),%%r2\n", - (actual_fsize + 20)); else if (! frame_pointer_needed
&& VAL_14_BITS_P (actual_fsize + 20)
&& (regs_ever_live[2] || profile_flag))
load_reg (2, - (actual_fsize + 20), STACK_POINTER_REGNUM);
/* General register restores. */
if (frame_pointer_needed) if (frame_pointer_needed)
{ {
for (i = 18, offset = local_fsize; i >= 5; i--) for (i = 18, offset = local_fsize; i >= 3; i--)
if (regs_ever_live[i] && ! call_used_regs[i]) if (regs_ever_live[i] && ! call_used_regs[i]
{ && i != FRAME_POINTER_REGNUM)
print_ldw (file, i, offset, 4); offset += 4;
}
if (regs_ever_live[3] && ! call_used_regs[3])
{ {
print_ldw (file, 3, offset, 4); offset += 4; load_reg (i, offset, FRAME_POINTER_REGNUM);
offset += 4;
} }
} }
else else
{ {
for (i = 18, offset = local_fsize - actual_fsize; i >= 5; i--) for (i = 18, offset = local_fsize - actual_fsize; i >= 3; i--)
if (regs_ever_live[i] && ! call_used_regs[i]) if (regs_ever_live[i] && ! call_used_regs[i])
{ {
/* Only for first load. And not if profiling. /* Only for the first load.
merge_sp_adjust_with_load holds the register load with merge_sp_adjust_with_load holds the register load
which we will merge the sp adjustment with.*/ with which we will merge the sp adjustment. */
if (VAL_14_BITS_P (actual_fsize + 20) if (VAL_14_BITS_P (actual_fsize + 20)
&& local_fsize == 0 && local_fsize == 0
&& ! profile_flag
&& ! merge_sp_adjust_with_load) && ! merge_sp_adjust_with_load)
merge_sp_adjust_with_load = i; merge_sp_adjust_with_load = i;
else else
print_ldw (file, i, offset, 30); offset += 4; load_reg (i, offset, STACK_POINTER_REGNUM);
} offset += 4;
if (regs_ever_live[3] && ! call_used_regs[3])
{
/* Only for first load. And not if profiling.
merge_sp_adjust_with_load holds the register load with
which we will merge the sp adjustment with.*/
if (VAL_14_BITS_P (actual_fsize + 20)
&& local_fsize == 0
&& ! profile_flag
&& ! merge_sp_adjust_with_load)
merge_sp_adjust_with_load = 3;
else
print_ldw (file, 3, offset, 30); offset += 4;
} }
} }
/* Align pointer properly (doubleword boundary). */ /* Align pointer properly (doubleword boundary). */
offset = (offset + 7) & ~7; offset = (offset + 7) & ~7;
/* Floating point register restore. */ /* FP register restores. */
if (save_fregs) if (save_fregs)
{ {
/* Adjust the register to index off of. */
if (frame_pointer_needed) if (frame_pointer_needed)
{ set_reg_plus_d (1, FRAME_POINTER_REGNUM, offset);
if (VAL_14_BITS_P (offset))
fprintf (file, "\tldo %d(%%r4),%%r1\n", offset);
else
fprintf (file, "\taddil L'%d,%%r4\n\tldo R'%d(%%r1),%%r1\n",
offset, offset);
}
else else
{ set_reg_plus_d (1, STACK_POINTER_REGNUM, offset);
if (VAL_14_BITS_P (offset))
fprintf (file, "\tldo %d(%%r30),%%r1\n", offset); /* Actually do the restores now. */
else if (! TARGET_SNAKE)
fprintf (file, "\taddil L'%d,%%r30\n\tldo R'%d(%%r1),%%r1\n",
offset, offset);
}
if (!TARGET_SNAKE)
{ {
for (i = 43; i >= 40; i--) for (i = 43; i >= 40; i--)
{
if (regs_ever_live[i]) if (regs_ever_live[i])
fprintf (file, "\tfldds,ma 8(0,%%r1),%s\n", reg_names[i]); emit_move_insn (gen_rtx (REG, DFmode, i),
} gen_rtx (MEM, DFmode,
gen_rtx (POST_INC, DFmode, tmpreg)));
} }
else else
{ {
for (i = 78; i >= 60; i -= 2) for (i = 78; i >= 60; i -= 2)
if (regs_ever_live[i] || regs_ever_live[i + 1]) if (regs_ever_live[i] || regs_ever_live[i + 1])
{ emit_move_insn (gen_rtx (REG, DFmode, i),
fprintf (file, "\tfldds,ma 8(0,%%r1),%s\n", reg_names[i]); gen_rtx (MEM, DFmode,
} gen_rtx (POST_INC, DFmode, tmpreg)));
}
} }
/* Reset stack pointer (and possibly frame pointer). The stack */
/* pointer is initially set to fp + 64 to avoid a race condition.
??? What race condition?!? */
if (frame_pointer_needed)
{
/* RP has already been restored in this case. */
fprintf (file, "\tldo 64(%%r4),%%r30\n");
fprintf (file, "\tbv 0(%%r2)\n\tldwm -64(0,%%r30),%%r4\n");
} }
else if (actual_fsize)
{
if (regs_ever_live[2] || profile_flag)
/* No frame pointer, but we have a stack greater than 8k. We restore
%r2 very late in this case. (all other cases are restored as early
as possible. */
if (! frame_pointer_needed
&& ! VAL_14_BITS_P (actual_fsize + 20)
&& (regs_ever_live[2] || profile_flag))
{ {
/* In this case RP has already been restored! */ set_reg_plus_d (STACK_POINTER_REGNUM,
if (VAL_14_BITS_P (actual_fsize + 20)) STACK_POINTER_REGNUM,
{
/* Optimize load and sp adjustment. */
if (merge_sp_adjust_with_load)
fprintf (file, "\tbv 0(%%r2)\n\tldwm %d(0,%%r30),%d\n",
-actual_fsize, merge_sp_adjust_with_load);
else
fprintf (file, "\tbv 0(%%r2)\n\tldo %d(%%r30),%%r30\n", -actual_fsize);
}
/* Large frame. Uncommon and not worth extra hair to avoid
load/use delay for RP. */
else
fprintf (file,
"\taddil L'%d,%%r30\n\tldw %d(0,%%r1),%%r2\n\tbv 0(%%r2)\n\tldo R'%d(%%r1),%%r30\n",
- actual_fsize,
- (actual_fsize + 20 + ((-actual_fsize) & ~0x7ff)),
- actual_fsize); - actual_fsize);
/* Uses value left over in %r1 by set_reg_plus_d. */
load_reg (2, - (actual_fsize + 20 + ((- actual_fsize) & ~0x7ff)), 1);
} }
/* Merge load with SP adjustment. */
else if (merge_sp_adjust_with_load)
fprintf (file, "\tbv 0(%%r2)\n\tldwm %d(0,%%r30),%d\n",
- actual_fsize, merge_sp_adjust_with_load);
else if (VAL_14_BITS_P (actual_fsize))
fprintf (file, "\tbv 0(%%r2)\n\tldo %d(%%r30),%%r30\n", - actual_fsize);
else
fprintf (file, "\taddil L'%d,%%r30\n\tbv 0(%%r2)\n\tldo R'%d(%%r1),%%r30\n",
- actual_fsize, - actual_fsize);
}
else if (current_function_epilogue_delay_list)
{
fprintf (file, "\tbv 0(%%r2)\n");
final_scan_insn (XEXP (current_function_epilogue_delay_list, 0), file,
1, 0, 1);
}
else
fprintf (file, "\tbv,n 0(%%r2)\n");
fprintf (file, "\t.EXIT\n\t.PROCEND\n");
}
/* If there's a frame, it will be deallocated in the delay slot of the /* Reset stack pointer (and possibly frame pointer). The stack */
bv 0(2) return instruction. */ /* pointer is initially set to fp + 64 to avoid a race condition.
??? What race condition?!? */
int else if (frame_pointer_needed)
hppa_epilogue_delay_slots () {
{ set_reg_plus_d (STACK_POINTER_REGNUM, FRAME_POINTER_REGNUM, 64);
return (compute_frame_size (get_frame_size (), 0) ? 0 : 1); emit_insn (gen_pre_ldwm (stack_pointer_rtx, stack_pointer_rtx,
} GEN_INT (-64), frame_pointer_rtx));
}
/* Return nonzero if TRIAL can go into the function epilogue's /* If we were deferring a callee register restore, do it now. */
delay slot. SLOT is the slot we are trying to fill. */ else if (! frame_pointer_needed && merge_sp_adjust_with_load)
emit_insn (gen_pre_ldwm (stack_pointer_rtx,
int stack_pointer_rtx,
eligible_for_epilogue_delay (trial, slot) GEN_INT (- actual_fsize),
rtx trial; gen_rtx (REG, SImode,
int slot; merge_sp_adjust_with_load)));
{ else if (actual_fsize != 0)
if (slot >= 1) set_reg_plus_d (STACK_POINTER_REGNUM,
return 0; STACK_POINTER_REGNUM,
if (GET_CODE (trial) != INSN - actual_fsize);
|| GET_CODE (PATTERN (trial)) != SET)
return 0;
if (get_attr_length (trial) != 1)
return 0;
/* The epilogue clobbers whatever value is in %r2 before the
delay slot executes, so insns which use %r2 can not be
used to fill the epilogue's delay slot. */
if (refers_to_regno_p (2, 3, PATTERN (trial), NULL_PTR))
return 0;
return (get_attr_in_branch_delay (trial) == IN_BRANCH_DELAY_TRUE);
} }
/* This is only valid once reload has completed because it depends on /* This is only valid once reload has completed because it depends on
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment