diff options
Diffstat (limited to 'contrib/gcc/config/arm/arm.c')
-rw-r--r-- | contrib/gcc/config/arm/arm.c | 29 |
1 files changed, 19 insertions, 10 deletions
diff --git a/contrib/gcc/config/arm/arm.c b/contrib/gcc/config/arm/arm.c index f07a281..8c696c6 100644 --- a/contrib/gcc/config/arm/arm.c +++ b/contrib/gcc/config/arm/arm.c @@ -890,6 +890,7 @@ use_return_insn (iscond) { int regno; unsigned int func_type; + unsigned long saved_int_regs; /* Never use a return instruction before reload has run. */ if (!reload_completed) @@ -912,23 +913,31 @@ use_return_insn (iscond) && !frame_pointer_needed)) return 0; + saved_int_regs = arm_compute_save_reg_mask (); + /* Can't be done if interworking with Thumb, and any registers have been - stacked. Similarly, on StrongARM, conditional returns are expensive - if they aren't taken and registers have been stacked. */ - if (iscond && arm_is_strong && frame_pointer_needed) + stacked. */ + if (TARGET_INTERWORK && saved_int_regs != 0) return 0; - - if ((iscond && arm_is_strong) - || TARGET_INTERWORK) + + /* On StrongARM, conditional returns are expensive if they aren't + taken and multiple registers have been stacked. */ + if (iscond && arm_is_strong) { - for (regno = 0; regno <= LAST_ARM_REGNUM; regno++) - if (regs_ever_live[regno] && !call_used_regs[regno]) - return 0; + /* Conditional return when just the LR is stored is a simple + conditional-load instruction, that's not expensive. */ + if (saved_int_regs != 0 && saved_int_regs != (1 << LR_REGNUM)) + return 0; if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM]) return 0; } - + + /* If there are saved registers but the LR isn't saved, then we need + two instructions for the return. */ + if (saved_int_regs && !(saved_int_regs & (1 << LR_REGNUM))) + return 0; + /* Can't be done if any of the FPU regs are pushed, since this also requires an insn. */ if (TARGET_HARD_FLOAT) |