arm.c (use_return_insn): New argument, SIBLING.

* arm.c (use_return_insn): New argument, SIBLING.  Support returning
with a single instruction if the stack has been decremented by 4
and we have a frame pointer.  Update all callers.
(output_return_instruction): Likewise.
(arm_output_epilogue): Change argument to SIBLING.  Calculate
really_return from the new argument.  Update all callers.
* arm.h (USE_RETURN_INSN): Pass NULL for the sibling.
* arm.md (sibcall_epilogue): Call use_return_insn directly, and
pass the sibling call.
* arm-protos.h (use_return_insn, arm_output_epilogue): Update
prototypes.

From-SVN: r73761
This commit is contained in:
Richard Earnshaw 2003-11-20 11:44:19 +00:00 committed by Richard Earnshaw
parent 8d98c44cc3
commit a72d4945d3
5 changed files with 92 additions and 16 deletions

View File

@ -1,3 +1,17 @@
2003-11-20 Richard Earnshaw <rearnsha@arm.com>
* arm.c (use_return_insn): New argument, SIBLING. Support returning
with a single instruction if the stack has been decremented by 4
and we have a frame pointer. Update all callers.
(output_return_instruction): Likewise.
(arm_output_epilogue): Change argument to SIBLING. Calculate
really_return from the new argument. Update all callers.
* arm.h (USE_RETURN_INSN): Pass NULL for the sibling.
* arm.md (sibcall_epilogue): Call use_return_insn directly, and
pass the sibling call.
* arm-protos.h (use_return_insn, arm_output_epilogue): Update
prototypes.
2003-11-20 Joseph S. Myers <jsm@polyomino.org.uk>
* Makefile.in (extraclean): Delete.

View File

@ -24,11 +24,11 @@
#define GCC_ARM_PROTOS_H
extern void arm_override_options (void);
extern int use_return_insn (int);
extern int use_return_insn (int, rtx);
extern int arm_regno_class (int);
extern void arm_finalize_pic (int);
extern int arm_volatile_func (void);
extern const char *arm_output_epilogue (int);
extern const char *arm_output_epilogue (rtx);
extern void arm_expand_prologue (void);
extern HOST_WIDE_INT arm_get_frame_size (void);
extern const char *arm_strip_name_encoding (const char *);

View File

@ -1002,14 +1002,17 @@ arm_current_func_type (void)
return cfun->machine->func_type;
}
/* Return 1 if it is possible to return using a single instruction. */
/* Return 1 if it is possible to return using a single instruction.
If SIBLING is non-null, this is a test for a return before a sibling
call. SIBLING is the call insn, so we can examine its register usage. */
int
use_return_insn (int iscond)
use_return_insn (int iscond, rtx sibling)
{
int regno;
unsigned int func_type;
unsigned long saved_int_regs;
unsigned HOST_WIDE_INT stack_adjust;
/* Never use a return instruction before reload has run. */
if (!reload_completed)
@ -1026,6 +1029,8 @@ use_return_insn (int iscond)
if (IS_INTERRUPT (func_type) && frame_pointer_needed)
return 0;
stack_adjust = arm_get_frame_size () + current_function_outgoing_args_size;
/* As do variadic functions. */
if (current_function_pretend_args_size
|| cfun->machine->uses_anonymous_args
@ -1033,12 +1038,51 @@ use_return_insn (int iscond)
|| ARM_FUNC_TYPE (func_type) == ARM_FT_EXCEPTION_HANDLER
/* Or if the function calls alloca */
|| current_function_calls_alloca
/* Or if there is a stack adjustment. */
|| (arm_get_frame_size () + current_function_outgoing_args_size != 0))
/* Or if there is a stack adjustment. However, if the stack pointer
is saved on the stack, we can use a pre-incrementing stack load. */
|| !(stack_adjust == 0 || (frame_pointer_needed && stack_adjust == 4)))
return 0;
saved_int_regs = arm_compute_save_reg_mask ();
/* Unfortunately, the insn
ldmib sp, {..., sp, ...}
triggers a bug on most SA-110 based devices, such that the stack
pointer won't be correctly restored if the instruction takes a
page fault. We work around this problem by poping r3 along with
the other registers, since that is never slower than executing
another instruction.
We test for !arm_arch5 here, because code for any architecture
less than this could potentially be run on one of the buggy
chips. */
if (stack_adjust == 4 && !arm_arch5)
{
/* Validate that r3 is a call-clobbered register (always true in
the default abi) ... */
if (!call_used_regs[3])
return 0;
/* ... that it isn't being used for a return value (always true
until we implement return-in-regs), or for a tail-call
argument ... */
if (sibling)
{
if (GET_CODE (sibling) != CALL_INSN)
abort ();
if (find_regno_fusage (sibling, USE, 3))
return 0;
}
/* ... and that there are no call-saved registers in r0-r2
(always true in the default ABI). */
if (saved_int_regs & 0x7)
return 0;
}
/* Can't be done if interworking with Thumb, and any registers have been
stacked. */
if (TARGET_INTERWORK && saved_int_regs != 0)
@ -8194,7 +8238,24 @@ output_return_instruction (rtx operand, int really_return, int reverse)
frame_pointer_needed is true, but only if sp already
points to the base of the saved core registers. */
if (live_regs_mask & (1 << SP_REGNUM))
{
unsigned HOST_WIDE_INT stack_adjust =
arm_get_frame_size () + current_function_outgoing_args_size;
if (stack_adjust != 0 && stack_adjust != 4)
abort ();
if (stack_adjust && arm_arch5)
sprintf (instr, "ldm%sib\t%%|sp, {", conditional);
else
{
/* If we can't use ldmib (SA110 bug), then try to pop r3
instead. */
if (stack_adjust)
live_regs_mask |= 1 << 3;
sprintf (instr, "ldm%sfd\t%%|sp, {", conditional);
}
}
else
sprintf (instr, "ldm%sfd\t%%|sp!, {", conditional);
@ -8401,7 +8462,7 @@ arm_output_function_prologue (FILE *f, HOST_WIDE_INT frame_size)
}
const char *
arm_output_epilogue (int really_return)
arm_output_epilogue (rtx sibling)
{
int reg;
unsigned long saved_regs_mask;
@ -8414,10 +8475,11 @@ arm_output_epilogue (int really_return)
FILE * f = asm_out_file;
rtx eh_ofs = cfun->machine->eh_epilogue_sp_ofs;
unsigned int lrm_count = 0;
int really_return = (sibling == NULL);
/* If we have already generated the return instruction
then it is futile to generate anything else. */
if (use_return_insn (FALSE) && return_used_this_function)
if (use_return_insn (FALSE, sibling) && return_used_this_function)
return "";
func_type = arm_current_func_type ();
@ -8730,7 +8792,7 @@ arm_output_function_epilogue (FILE *file ATTRIBUTE_UNUSED,
/* We need to take into account any stack-frame rounding. */
frame_size = arm_get_frame_size ();
if (use_return_insn (FALSE)
if (use_return_insn (FALSE, NULL)
&& return_used_this_function
&& (frame_size + current_function_outgoing_args_size) != 0
&& !frame_pointer_needed)
@ -10187,7 +10249,7 @@ arm_final_prescan_insn (rtx insn)
/* Fail if a conditional return is undesirable (eg on a
StrongARM), but still allow this if optimizing for size. */
else if (GET_CODE (scanbody) == RETURN
&& !use_return_insn (TRUE)
&& !use_return_insn (TRUE, NULL)
&& !optimize_size)
fail = TRUE;
else if (GET_CODE (scanbody) == RETURN

View File

@ -1870,7 +1870,7 @@ typedef struct
/* Determine if the epilogue should be output as RTL.
You should override this if you define FUNCTION_EXTRA_EPILOGUE. */
#define USE_RETURN_INSN(ISCOND) \
(TARGET_ARM ? use_return_insn (ISCOND) : 0)
(TARGET_ARM ? use_return_insn (ISCOND, NULL) : 0)
/* Definitions for register eliminations.

View File

@ -9338,9 +9338,9 @@
(unspec_volatile [(return)] VUNSPEC_EPILOGUE)])]
"TARGET_ARM"
"*
if (USE_RETURN_INSN (FALSE))
if (use_return_insn (FALSE, next_nonnote_insn (insn)))
return output_return_instruction (const_true_rtx, FALSE, FALSE);
return arm_output_epilogue (FALSE);
return arm_output_epilogue (next_nonnote_insn (insn));
"
;; Length is absolute worst case
[(set_attr "length" "44")
@ -9356,7 +9356,7 @@
"TARGET_EITHER"
"*
if (TARGET_ARM)
return arm_output_epilogue (TRUE);
return arm_output_epilogue (NULL);
else /* TARGET_THUMB */
return thumb_unexpanded_epilogue ();
"