re PR target/16634 (arm-elf-gcc problems when generating code for __attribute__ ((interrupt ("IRQ"))))

2007-01-03  Paul Brook  <paul@codesourcery.com>

	PR target/16634
	gcc/
	* config/arm/arm.c (output_return_instruction): Pop PC in interrupt
	functions.
	(use_return_insn): Return 0 for Thumb interrupt functions.
	(print_multi_reg): Add rfe argument for IRQ returns.
	(arm_output_epilogue): Pop interrupt return address directly into PC.
	(arm_expand_prologue): Only adjust IRQ return address in Arm mode.

From-SVN: r120413
This commit is contained in:
Paul Brook 2007-01-04 00:09:48 +00:00 committed by Paul Brook
parent 019df41c96
commit a15908a410
2 changed files with 41 additions and 16 deletions

View File

@ -1,3 +1,13 @@
2007-01-03 Paul Brook <paul@codesourcery.com>
PR target/16634
* config/arm/arm.c (output_return_instruction): Pop PC in interrupt
functions.
(use_return_insn): Return 0 for Thumb interrupt functions.
(print_multi_reg): Add rfe argument for IRQ returns.
(arm_output_epilogue): Pop interrupt return address directly into PC.
(arm_expand_prologue): Only adjust IRQ return address in Arm mode.
2007-01-03 Paul Brook <paul@codesourcery.com>
Merge from sourcerygxx-4_1.

View File

@ -1543,8 +1543,9 @@ use_return_insn (int iscond, rtx sibling)
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 ();
@ -1605,7 +1606,7 @@ use_return_insn (int iscond, rtx sibling)
/* 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
@ -8739,15 +8740,17 @@ fp_const_from_val (REAL_VALUE_TYPE *r)
/* 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);
@ -8762,7 +8765,10 @@ print_multi_reg (FILE *stream, const char *instr, unsigned reg,
not_first = TRUE;
}
fprintf (stream, "}\n");
if (rfe)
fprintf (stream, "}^\n");
else
fprintf (stream, "}\n");
}
@ -9971,10 +9977,10 @@ output_return_instruction (rtx operand, int really_return, int reverse)
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];
@ -10427,16 +10433,17 @@ arm_output_epilogue (rtx sibling)
|| 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)
{
@ -10527,7 +10534,8 @@ arm_output_epilogue (rtx sibling)
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
@ -10536,12 +10544,16 @@ arm_output_epilogue (rtx sibling)
{
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);
}
@ -10552,11 +10564,13 @@ arm_output_epilogue (rtx sibling)
(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)
@ -11389,7 +11403,8 @@ arm_expand_prologue (void)
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);