Helper function for epilogue expansion.
Helper function for epilogue expansion. Emit RTL for APCS frame epilogue (when -mapcs-frame command line option is specified). This function is used by a later patch. gcc/ 2012-06-18 Ian Bolton <ian.bolton@arm.com> Sameera Deshpande <sameera.deshpande@arm.com> Greta Yorsh <greta.yorsh@arm.com> * config/arm/arm.c (arm_expand_epilogue_apcs_frame): New function. * config/arm/arm.md (arm_addsi3) Add an alternative. Co-Authored-By: Greta Yorsh <greta.yorsh@arm.com> Co-Authored-By: Sameera Deshpande <sameera.deshpande@arm.com> From-SVN: r188741
This commit is contained in:
parent
4b2678f886
commit
0f9926f367
|
@ -1,3 +1,10 @@
|
|||
2012-06-18 Ian Bolton <ian.bolton@arm.com>
|
||||
Sameera Deshpande <sameera.deshpande@arm.com>
|
||||
Greta Yorsh <greta.yorsh@arm.com>
|
||||
|
||||
* config/arm/arm.c (arm_expand_epilogue_apcs_frame): New function.
|
||||
* config/arm/arm.md (arm_addsi3) Add an alternative.
|
||||
|
||||
2012-06-18 Ian Bolton <ian.bolton@arm.com>
|
||||
Sameera Deshpande <sameera.deshpande@arm.com>
|
||||
Greta Yorsh <greta.yorsh@arm.com>
|
||||
|
|
|
@ -23320,6 +23320,159 @@ thumb1_expand_epilogue (void)
|
|||
emit_use (gen_rtx_REG (SImode, LR_REGNUM));
|
||||
}
|
||||
|
||||
/* Epilogue code for APCS frame. */
|
||||
static void
|
||||
arm_expand_epilogue_apcs_frame (bool really_return)
|
||||
{
|
||||
unsigned long func_type;
|
||||
unsigned long saved_regs_mask;
|
||||
int num_regs = 0;
|
||||
int i;
|
||||
int floats_from_frame = 0;
|
||||
arm_stack_offsets *offsets;
|
||||
|
||||
gcc_assert (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM);
|
||||
func_type = arm_current_func_type ();
|
||||
|
||||
/* Get frame offsets for ARM. */
|
||||
offsets = arm_get_frame_offsets ();
|
||||
saved_regs_mask = offsets->saved_regs_mask;
|
||||
|
||||
/* Find the offset of the floating-point save area in the frame. */
|
||||
floats_from_frame = offsets->saved_args - offsets->frame;
|
||||
|
||||
/* Compute how many core registers saved and how far away the floats are. */
|
||||
for (i = 0; i <= LAST_ARM_REGNUM; i++)
|
||||
if (saved_regs_mask & (1 << i))
|
||||
{
|
||||
num_regs++;
|
||||
floats_from_frame += 4;
|
||||
}
|
||||
|
||||
if (TARGET_HARD_FLOAT && TARGET_VFP)
|
||||
{
|
||||
int start_reg;
|
||||
|
||||
/* The offset is from IP_REGNUM. */
|
||||
int saved_size = arm_get_vfp_saved_size ();
|
||||
if (saved_size > 0)
|
||||
{
|
||||
floats_from_frame += saved_size;
|
||||
emit_insn (gen_addsi3 (gen_rtx_REG (SImode, IP_REGNUM),
|
||||
hard_frame_pointer_rtx,
|
||||
GEN_INT (-floats_from_frame)));
|
||||
}
|
||||
|
||||
/* Generate VFP register multi-pop. */
|
||||
start_reg = FIRST_VFP_REGNUM;
|
||||
|
||||
for (i = FIRST_VFP_REGNUM; i < LAST_VFP_REGNUM; i += 2)
|
||||
/* Look for a case where a reg does not need restoring. */
|
||||
if ((!df_regs_ever_live_p (i) || call_used_regs[i])
|
||||
&& (!df_regs_ever_live_p (i + 1)
|
||||
|| call_used_regs[i + 1]))
|
||||
{
|
||||
if (start_reg != i)
|
||||
arm_emit_vfp_multi_reg_pop (start_reg,
|
||||
(i - start_reg) / 2,
|
||||
gen_rtx_REG (SImode,
|
||||
IP_REGNUM));
|
||||
start_reg = i + 2;
|
||||
}
|
||||
|
||||
/* Restore the remaining regs that we have discovered (or possibly
|
||||
even all of them, if the conditional in the for loop never
|
||||
fired). */
|
||||
if (start_reg != i)
|
||||
arm_emit_vfp_multi_reg_pop (start_reg,
|
||||
(i - start_reg) / 2,
|
||||
gen_rtx_REG (SImode, IP_REGNUM));
|
||||
}
|
||||
|
||||
if (TARGET_IWMMXT)
|
||||
{
|
||||
/* The frame pointer is guaranteed to be non-double-word aligned, as
|
||||
it is set to double-word-aligned old_stack_pointer - 4. */
|
||||
rtx insn;
|
||||
int lrm_count = (num_regs % 2) ? (num_regs + 2) : (num_regs + 1);
|
||||
|
||||
for (i = LAST_IWMMXT_REGNUM; i >= FIRST_IWMMXT_REGNUM; i--)
|
||||
if (df_regs_ever_live_p (i) && !call_used_regs[i])
|
||||
{
|
||||
rtx addr = gen_frame_mem (V2SImode,
|
||||
plus_constant (Pmode, hard_frame_pointer_rtx,
|
||||
- lrm_count * 4));
|
||||
insn = emit_insn (gen_movsi (gen_rtx_REG (V2SImode, i), addr));
|
||||
REG_NOTES (insn) = alloc_reg_note (REG_CFA_RESTORE,
|
||||
gen_rtx_REG (V2SImode, i),
|
||||
NULL_RTX);
|
||||
lrm_count += 2;
|
||||
}
|
||||
}
|
||||
|
||||
/* saved_regs_mask should contain IP which contains old stack pointer
|
||||
at the time of activation creation. Since SP and IP are adjacent registers,
|
||||
we can restore the value directly into SP. */
|
||||
gcc_assert (saved_regs_mask & (1 << IP_REGNUM));
|
||||
saved_regs_mask &= ~(1 << IP_REGNUM);
|
||||
saved_regs_mask |= (1 << SP_REGNUM);
|
||||
|
||||
/* There are two registers left in saved_regs_mask - LR and PC. We
|
||||
only need to restore LR (the return address), but to
|
||||
save time we can load it directly into PC, unless we need a
|
||||
special function exit sequence, or we are not really returning. */
|
||||
if (really_return
|
||||
&& ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
|
||||
&& !crtl->calls_eh_return)
|
||||
/* Delete LR from the register mask, so that LR on
|
||||
the stack is loaded into the PC in the register mask. */
|
||||
saved_regs_mask &= ~(1 << LR_REGNUM);
|
||||
else
|
||||
saved_regs_mask &= ~(1 << PC_REGNUM);
|
||||
|
||||
num_regs = bit_count (saved_regs_mask);
|
||||
if ((offsets->outgoing_args != (1 + num_regs)) || cfun->calls_alloca)
|
||||
{
|
||||
/* Unwind the stack to just below the saved registers. */
|
||||
emit_insn (gen_addsi3 (stack_pointer_rtx,
|
||||
hard_frame_pointer_rtx,
|
||||
GEN_INT (- 4 * num_regs)));
|
||||
}
|
||||
|
||||
arm_emit_multi_reg_pop (saved_regs_mask);
|
||||
|
||||
if (IS_INTERRUPT (func_type))
|
||||
{
|
||||
/* Interrupt handlers will have pushed the
|
||||
IP onto the stack, so restore it now. */
|
||||
rtx insn;
|
||||
rtx addr = gen_rtx_MEM (SImode,
|
||||
gen_rtx_POST_INC (SImode,
|
||||
stack_pointer_rtx));
|
||||
set_mem_alias_set (addr, get_frame_alias_set ());
|
||||
insn = emit_insn (gen_movsi (gen_rtx_REG (SImode, IP_REGNUM), addr));
|
||||
REG_NOTES (insn) = alloc_reg_note (REG_CFA_RESTORE,
|
||||
gen_rtx_REG (SImode, IP_REGNUM),
|
||||
NULL_RTX);
|
||||
}
|
||||
|
||||
if (!really_return || (saved_regs_mask & (1 << PC_REGNUM)))
|
||||
return;
|
||||
|
||||
if (crtl->calls_eh_return)
|
||||
emit_insn (gen_addsi3 (stack_pointer_rtx,
|
||||
stack_pointer_rtx,
|
||||
GEN_INT (ARM_EH_STACKADJ_REGNUM)));
|
||||
|
||||
if (IS_STACKALIGN (func_type))
|
||||
/* Restore the original stack pointer. Before prologue, the stack was
|
||||
realigned and the original stack pointer saved in r0. For details,
|
||||
see comment in arm_expand_prologue. */
|
||||
emit_insn (gen_movsi (stack_pointer_rtx, gen_rtx_REG (SImode, 0)));
|
||||
|
||||
emit_jump_insn (simple_return_rtx);
|
||||
}
|
||||
|
||||
/* Implementation of insn prologue_thumb1_interwork. This is the first
|
||||
"instruction" of a function called in ARM mode. Swap to thumb mode. */
|
||||
|
||||
|
|
|
@ -724,9 +724,9 @@
|
|||
;; (plus (reg rN) (reg sp)) into (reg rN). In this case reload will
|
||||
;; put the duplicated register first, and not try the commutative version.
|
||||
(define_insn_and_split "*arm_addsi3"
|
||||
[(set (match_operand:SI 0 "s_register_operand" "=r, k,r,r, k, r, k,r, k, r")
|
||||
(plus:SI (match_operand:SI 1 "s_register_operand" "%rk,k,r,rk,k, rk,k,rk,k, rk")
|
||||
(match_operand:SI 2 "reg_or_int_operand" "rI,rI,k,Pj,Pj,L, L,PJ,PJ,?n")))]
|
||||
[(set (match_operand:SI 0 "s_register_operand" "=r, k,r,r, k, r, k,k,r, k, r")
|
||||
(plus:SI (match_operand:SI 1 "s_register_operand" "%rk,k,r,rk,k, rk,k,r,rk,k, rk")
|
||||
(match_operand:SI 2 "reg_or_int_operand" "rI,rI,k,Pj,Pj,L, L,L,PJ,PJ,?n")))]
|
||||
"TARGET_32BIT"
|
||||
"@
|
||||
add%?\\t%0, %1, %2
|
||||
|
@ -736,6 +736,7 @@
|
|||
addw%?\\t%0, %1, %2
|
||||
sub%?\\t%0, %1, #%n2
|
||||
sub%?\\t%0, %1, #%n2
|
||||
sub%?\\t%0, %1, #%n2
|
||||
subw%?\\t%0, %1, #%n2
|
||||
subw%?\\t%0, %1, #%n2
|
||||
#"
|
||||
|
@ -750,9 +751,9 @@
|
|||
operands[1], 0);
|
||||
DONE;
|
||||
"
|
||||
[(set_attr "length" "4,4,4,4,4,4,4,4,4,16")
|
||||
[(set_attr "length" "4,4,4,4,4,4,4,4,4,4,16")
|
||||
(set_attr "predicable" "yes")
|
||||
(set_attr "arch" "*,*,*,t2,t2,*,*,t2,t2,*")]
|
||||
(set_attr "arch" "*,*,*,t2,t2,*,*,a,t2,t2,*")]
|
||||
)
|
||||
|
||||
(define_insn_and_split "*thumb1_addsi3"
|
||||
|
|
Loading…
Reference in New Issue