diff options
author | Ian Bolton <ian.bolton@arm.com> | 2012-06-18 18:02:03 +0000 |
---|---|---|
committer | Greta Yorsh <gretay@gcc.gnu.org> | 2012-06-18 19:02:03 +0100 |
commit | 482baa63f3076b7d954f3b152514a0d69f11a74a (patch) | |
tree | 7d4ce384c1e137bcd335966b253e29ecd86c1521 /gcc | |
parent | f79b86a43ec258a7c603862e39b1e90cb8a18375 (diff) | |
download | gcc-482baa63f3076b7d954f3b152514a0d69f11a74a.zip gcc-482baa63f3076b7d954f3b152514a0d69f11a74a.tar.gz gcc-482baa63f3076b7d954f3b152514a0d69f11a74a.tar.bz2 |
Generate RTL for return in Thumb2 mode. Used by expand of return insn.
2012-06-18 Ian Bolton <ian.bolton@arm.com>
Sameera Deshpande <sameera.deshpande@arm.com>
Greta Yorsh <greta.yorsh@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.
Co-Authored-By: Greta Yorsh <greta.yorsh@arm.com>
Co-Authored-By: Sameera Deshpande <sameera.deshpande@arm.com>
From-SVN: r188744
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/config/arm/arm-protos.h | 1 | ||||
-rw-r--r-- | gcc/config/arm/arm.c | 46 | ||||
-rw-r--r-- | gcc/config/arm/arm.md | 16 |
4 files changed, 69 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 45497a7..cc72e97 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -2,6 +2,14 @@ Sameera Deshpande <sameera.deshpande@arm.com> Greta Yorsh <greta.yorsh@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. + +2012-06-18 Ian Bolton <ian.bolton@arm.com> + Sameera Deshpande <sameera.deshpande@arm.com> + Greta Yorsh <greta.yorsh@arm.com> + * config/arm/arm-protos.h (output_return_instruction): New parameter and int to bool change of parameter types. * config/arm/arm.c (output_return_instruction): Likewise. diff --git a/gcc/config/arm/arm-protos.h b/gcc/config/arm/arm-protos.h index e19c635..5a9940e 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 b9e0f7b..3f5b500 100644 --- a/gcc/config/arm/arm.c +++ b/gcc/config/arm/arm.c @@ -23265,6 +23265,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 5954323..eb99488 100644 --- a/gcc/config/arm/arm.md +++ b/gcc/config/arm/arm.md @@ -8505,8 +8505,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" |