|| current_function_calls_alloca
/* 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)))
+ || !(stack_adjust == 0 || (TARGET_APCS_FRAME && frame_pointer_needed
+ && stack_adjust == 4)))
return 0;
saved_int_regs = arm_compute_save_reg_mask ();
}
else
{
- /* In arm mode we handle r11 (FP) as a special case. */
- unsigned last_reg = TARGET_ARM ? 10 : 11;
-
/* In the normal case we only need to save those registers
which are call saved and which are used by this function. */
- for (reg = 0; reg <= last_reg; reg++)
+ for (reg = 0; reg <= 11; reg++)
if (df_regs_ever_live_p (reg) && ! call_used_regs[reg])
save_reg_mask |= (1 << reg);
/* Handle the frame pointer as a special case. */
- if (! TARGET_APCS_FRAME
- && ! frame_pointer_needed
- && df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM)
- && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
- save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
- else if (! TARGET_APCS_FRAME
- && ! frame_pointer_needed
- && df_regs_ever_live_p (HARD_FRAME_POINTER_REGNUM)
- && ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
+ if (frame_pointer_needed)
save_reg_mask |= 1 << HARD_FRAME_POINTER_REGNUM;
/* If we aren't loading the PIC register,
/* If we are creating a stack frame, then we must save the frame pointer,
IP (which will hold the old stack pointer), LR and the PC. */
- if (frame_pointer_needed && TARGET_ARM)
+ if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
save_reg_mask |=
(1 << ARM_HARD_FRAME_POINTER_REGNUM)
| (1 << IP_REGNUM)
if (saved_regs_mask & (1 << reg))
floats_offset += 4;
- if (frame_pointer_needed && TARGET_ARM)
+ if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
{
/* This variable is for the Virtual Frame Pointer, not VFP regs. */
int vfp_offset = offsets->frame;
}
else
{
+ /* This branch is executed for ARM mode (non-apcs frames) and
+ Thumb-2 mode. Frame layout is essentially the same for those
+ cases, except that in ARM mode frame pointer points to the
+ first saved register, while in Thumb-2 mode the frame pointer points
+ to the last saved register.
+
+ It is possible to make frame pointer point to last saved
+ register in both cases, and remove some conditionals below.
+ That means that fp setup in prologue would be just "mov fp, sp"
+ and sp restore in epilogue would be just "mov sp, fp", whereas
+ now we have to use add/sub in those cases. However, the value
+ of that would be marginal, as both mov and add/sub are 32-bit
+ in ARM mode, and it would require extra conditionals
+ in arm_expand_prologue to distingish ARM-apcs-frame case
+ (where frame pointer is required to point at first register)
+ and ARM-non-apcs-frame. Therefore, such change is postponed
+ until real need arise. */
HOST_WIDE_INT amount;
int rfe;
/* Restore stack pointer if necessary. */
- if (frame_pointer_needed)
- {
- /* For Thumb-2 restore sp from the frame pointer.
- Operand restrictions mean we have to increment FP, then copy
- to SP. */
- amount = offsets->locals_base - offsets->saved_regs;
- operands[0] = hard_frame_pointer_rtx;
- }
- else
+ if (TARGET_ARM && frame_pointer_needed)
{
operands[0] = stack_pointer_rtx;
- amount = offsets->outgoing_args - offsets->saved_regs;
+ operands[1] = hard_frame_pointer_rtx;
+
+ operands[2] = GEN_INT (offsets->frame - offsets->saved_regs);
+ output_add_immediate (operands);
}
-
- if (amount)
+ else
{
- operands[1] = operands[0];
- operands[2] = GEN_INT (amount);
- output_add_immediate (operands);
+ if (frame_pointer_needed)
+ {
+ /* For Thumb-2 restore sp from the frame pointer.
+ Operand restrictions mean we have to incrememnt FP, then copy
+ to SP. */
+ amount = offsets->locals_base - offsets->saved_regs;
+ operands[0] = hard_frame_pointer_rtx;
+ }
+ else
+ {
+ operands[0] = stack_pointer_rtx;
+ amount = offsets->outgoing_args - offsets->saved_regs;
+ }
+
+ if (amount)
+ {
+ operands[1] = operands[0];
+ operands[2] = GEN_INT (amount);
+ output_add_immediate (operands);
+ }
+ if (frame_pointer_needed)
+ asm_fprintf (f, "\tmov\t%r, %r\n",
+ SP_REGNUM, HARD_FRAME_POINTER_REGNUM);
}
- if (frame_pointer_needed)
- asm_fprintf (f, "\tmov\t%r, %r\n",
- SP_REGNUM, HARD_FRAME_POINTER_REGNUM);
if (arm_fpu_arch == FPUTYPE_FPA_EMU2)
{
emit_insn (gen_movsi (stack_pointer_rtx, r1));
}
- if (frame_pointer_needed && TARGET_ARM)
+ /* For APCS frames, if IP register is clobbered
+ when creating frame, save that register in a special
+ way. */
+ if (TARGET_APCS_FRAME && frame_pointer_needed && TARGET_ARM)
{
if (IS_INTERRUPT (func_type))
{
}
/* If this is an interrupt service routine, and the link register
- is going to be pushed, and we are not creating a stack frame,
- (which would involve an extra push of IP and a pop in the epilogue)
+ is going to be pushed, and we're not generating extra
+ push of IP (needed when frame is needed and frame layout if apcs),
subtracting four from LR now will mean that the function return
can be done with a single instruction. */
if ((func_type == ARM_FT_ISR || func_type == ARM_FT_FIQ)
&& (live_regs_mask & (1 << LR_REGNUM)) != 0
- && ! frame_pointer_needed
+ && !(frame_pointer_needed && TARGET_APCS_FRAME)
&& TARGET_ARM)
{
rtx lr = gen_rtx_REG (SImode, LR_REGNUM);
if (frame_pointer_needed && TARGET_ARM)
{
/* Create the new frame pointer. */
+ if (TARGET_APCS_FRAME)
{
insn = GEN_INT (-(4 + args_to_push + fp_offset));
insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx, ip_rtx, insn));
emit_insn (gen_prologue_use (ip_rtx));
}
}
+ else
+ {
+ insn = GEN_INT (saved_regs - 4);
+ insn = emit_insn (gen_addsi3 (hard_frame_pointer_rtx,
+ stack_pointer_rtx, insn));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
}
offsets = arm_get_frame_offsets ();