aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Brook <paul@codesourcery.com>2007-01-04 00:09:48 +0000
committerPaul Brook <pbrook@gcc.gnu.org>2007-01-04 00:09:48 +0000
commita15908a410d8d7d2a20fb78bc95d9a17b10e5d72 (patch)
tree406736e8a2c397ce1dc765f7a7440b8e5af7a24e
parent019df41c9647937186705d54b57b72eaa0a82be7 (diff)
downloadgcc-a15908a410d8d7d2a20fb78bc95d9a17b10e5d72.zip
gcc-a15908a410d8d7d2a20fb78bc95d9a17b10e5d72.tar.gz
gcc-a15908a410d8d7d2a20fb78bc95d9a17b10e5d72.tar.bz2
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
-rw-r--r--gcc/ChangeLog10
-rw-r--r--gcc/config/arm/arm.c47
2 files changed, 41 insertions, 16 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ae2fc67..f9c53fc 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,5 +1,15 @@
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.
* config/arm/thumb2.md: New file.
* config/arm/elf.h (JUMP_TABLES_IN_TEXT_SECTION): Return True for
diff --git a/gcc/config/arm/arm.c b/gcc/config/arm/arm.c
index 9558275..d7fa19c 100644
--- a/gcc/config/arm/arm.c
+++ b/gcc/config/arm/arm.c
@@ -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);