if (func_type & (ARM_FT_VOLATILE | ARM_FT_NAKED | ARM_FT_STACKALIGN))
return 0;
- /* So do interrupt functions that use the frame pointer. */
- if (IS_INTERRUPT (func_type) && frame_pointer_needed)
+ /* So do interrupt functions that use the frame pointer and Thumb
+ interrupt functions. */
+ if (IS_INTERRUPT (func_type) && (frame_pointer_needed || TARGET_THUMB))
return 0;
offsets = arm_get_frame_offsets ();
/* Can't be done if interworking with Thumb, and any registers have been
stacked. */
- if (TARGET_INTERWORK && saved_int_regs != 0)
+ if (TARGET_INTERWORK && saved_int_regs != 0 && !IS_INTERRUPT(func_type))
return 0;
/* On StrongARM, conditional returns are expensive if they aren't
/* Output the operands of a LDM/STM instruction to STREAM.
MASK is the ARM register set mask of which only bits 0-15 are important.
REG is the base register, either the frame pointer or the stack pointer,
- INSTR is the possibly suffixed load or store instruction. */
+ INSTR is the possibly suffixed load or store instruction.
+ RFE is nonzero if the instruction should also copy spsr to cpsr. */
static void
print_multi_reg (FILE *stream, const char *instr, unsigned reg,
- unsigned long mask)
+ unsigned long mask, int rfe)
{
unsigned i;
bool not_first = FALSE;
+ gcc_assert (!rfe || (mask & (1 << PC_REGNUM)));
fputc ('\t', stream);
asm_fprintf (stream, instr, reg);
fputc ('{', stream);
not_first = TRUE;
}
- fprintf (stream, "}\n");
+ if (rfe)
+ fprintf (stream, "}^\n");
+ else
+ fprintf (stream, "}\n");
}
const char * return_reg;
/* If we do not have any special requirements for function exit
- (e.g. interworking, or ISR) then we can load the return address
+ (e.g. interworking) then we can load the return address
directly into the PC. Otherwise we must load it into LR. */
if (really_return
- && ! TARGET_INTERWORK)
+ && (IS_INTERRUPT (func_type) || !TARGET_INTERWORK))
return_reg = reg_names[PC_REGNUM];
else
return_reg = reg_names[LR_REGNUM];
|| current_function_calls_alloca)
asm_fprintf (f, "\tsub\t%r, %r, #%d\n", SP_REGNUM, FP_REGNUM,
4 * bit_count (saved_regs_mask));
- print_multi_reg (f, "ldmfd\t%r, ", SP_REGNUM, saved_regs_mask);
+ print_multi_reg (f, "ldmfd\t%r, ", SP_REGNUM, saved_regs_mask, 0);
if (IS_INTERRUPT (func_type))
/* Interrupt handlers will have pushed the
IP onto the stack, so restore it now. */
- print_multi_reg (f, "ldmfd\t%r!, ", SP_REGNUM, 1 << IP_REGNUM);
+ print_multi_reg (f, "ldmfd\t%r!, ", SP_REGNUM, 1 << IP_REGNUM, 0);
}
else
{
HOST_WIDE_INT amount;
+ int rfe;
/* Restore stack pointer if necessary. */
if (frame_pointer_needed)
{
asm_fprintf (f, "\twldrd\t%r, [%r], #8\n", reg, SP_REGNUM);
/* If we can, restore the LR into the PC. */
- if (ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL
+ if (ARM_FUNC_TYPE (func_type) != ARM_FT_INTERWORKED
+ && (TARGET_ARM || ARM_FUNC_TYPE (func_type) == ARM_FT_NORMAL)
&& !IS_STACKALIGN (func_type)
&& really_return
&& current_function_pretend_args_size == 0
{
saved_regs_mask &= ~ (1 << LR_REGNUM);
saved_regs_mask |= (1 << PC_REGNUM);
+ rfe = IS_INTERRUPT (func_type);
}
+ else
+ rfe = 0;
/* Load the registers off the stack. If we only have one register
to load use the LDR instruction - it is faster. For Thumb-2
always use pop and the assembler will pick the best instruction.*/
- if (TARGET_ARM && saved_regs_mask == (1 << LR_REGNUM))
+ if (TARGET_ARM && saved_regs_mask == (1 << LR_REGNUM)
+ && !IS_INTERRUPT(func_type))
{
asm_fprintf (f, "\tldr\t%r, [%r], #4\n", LR_REGNUM, SP_REGNUM);
}
(i.e. "ldmfd sp!..."). We know that the stack pointer is
in the list of registers and if we add writeback the
instruction becomes UNPREDICTABLE. */
- print_multi_reg (f, "ldmfd\t%r, ", SP_REGNUM, saved_regs_mask);
+ print_multi_reg (f, "ldmfd\t%r, ", SP_REGNUM, saved_regs_mask,
+ rfe);
else if (TARGET_ARM)
- print_multi_reg (f, "ldmfd\t%r!, ", SP_REGNUM, saved_regs_mask);
+ print_multi_reg (f, "ldmfd\t%r!, ", SP_REGNUM, saved_regs_mask,
+ rfe);
else
- print_multi_reg (f, "pop\t", SP_REGNUM, saved_regs_mask);
+ print_multi_reg (f, "pop\t", SP_REGNUM, saved_regs_mask, 0);
}
if (current_function_pretend_args_size)
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_ARM)
{
rtx lr = gen_rtx_REG (SImode, LR_REGNUM);