Generate RTL for return in Thumb2 mode. Used by expand of return insn.
ChangeLog:
gcc
2012-05-31 Ian Bolton <ian.bol...@arm.com>
Sameera Deshpande <sameera.deshpa...@arm.com>
Greta Yorsh <greta.yo...@arm.com>
* config/arm/arm-protos.h (thumb2_expand_return): New declaration.
* config/arm/arm.c (thumb2_expand_return): New function.
* config/arm/arm.md (return): Update condition and code.
diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h
index 01cd794..2fef0f2 100644
--- a/gcc/config/arm/arm-protos.h
+++ b/gcc/config/arm/arm-protos.h
@@ -31,6 +31,7 @@ extern int arm_volatile_func (void);
extern const char *arm_output_epilogue (rtx);
extern void arm_expand_prologue (void);
extern void arm_expand_epilogue (bool);
+extern void thumb2_expand_return (void);
extern const char *arm_strip_name_encoding (const char *);
extern void arm_asm_output_labelref (FILE *, const char *);
extern void thumb2_asm_output_opcode (FILE *);
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index e7a74e0..8bc6dcc 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -22841,6 +22841,52 @@ thumb1_expand_prologue (void)
cfun->machine->lr_save_eliminated = 0;
}
+/* Generate pattern *pop_multiple_with_stack_update_and_return if single
+ POP instruction can be generated. LR should be replaced by PC. All
+ the checks required are already done by USE_RETURN_INSN (). Hence,
+ all we really need to check here is if single register is to be
+ returned, or multiple register return. */
+void
+thumb2_expand_return (void)
+{
+ int i, num_regs;
+ unsigned long saved_regs_mask;
+ arm_stack_offsets *offsets;
+
+ offsets = arm_get_frame_offsets ();
+ saved_regs_mask = offsets->saved_regs_mask;
+
+ for (i = 0, num_regs = 0; i <= LAST_ARM_REGNUM; i++)
+ if (saved_regs_mask & (1 << i))
+ num_regs++;
+
+ if (saved_regs_mask)
+ {
+ if (num_regs == 1)
+ {
+ rtx par = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (2));
+ rtx reg = gen_rtx_REG (SImode, PC_REGNUM);
+ rtx addr = gen_rtx_MEM (SImode,
+ gen_rtx_POST_INC (SImode,
+ stack_pointer_rtx));
+ set_mem_alias_set (addr, get_frame_alias_set ());
+ XVECEXP (par, 0, 0) = ret_rtx;
+ XVECEXP (par, 0, 1) = gen_rtx_SET (SImode, reg, addr);
+ RTX_FRAME_RELATED_P (XVECEXP (par, 0, 1)) = 1;
+ emit_jump_insn (par);
+ }
+ else
+ {
+ saved_regs_mask &= ~ (1 << LR_REGNUM);
+ saved_regs_mask |= (1 << PC_REGNUM);
+ arm_emit_multi_reg_pop (saved_regs_mask);
+ }
+ }
+ else
+ {
+ emit_jump_insn (simple_return_rtx);
+ }
+}
void
thumb1_expand_epilogue (void)
diff --git a/gcc/config/arm/arm.md b/gcc/config/arm/arm.md
index 867dcbe..387ca15 100644
--- a/gcc/config/arm/arm.md
+++ b/gcc/config/arm/arm.md
@@ -8583,8 +8583,20 @@
(define_expand "return"
[(return)]
- "TARGET_32BIT && USE_RETURN_INSN (FALSE)"
- "")
+ "(TARGET_ARM || (TARGET_THUMB2
+ && ARM_FUNC_TYPE (arm_current_func_type ()) == ARM_FT_NORMAL
+ && !IS_STACKALIGN (arm_current_func_type ())))
+ && USE_RETURN_INSN (FALSE)"
+ "
+ {
+ if (TARGET_THUMB2)
+ {
+ thumb2_expand_return ();
+ DONE;
+ }
+ }
+ "
+)
;; Often the return insn will be the same as loading from memory, so set attr
(define_insn "*arm_return"