Fix prologue/epilogue generation for ARM ISR routines.

Add test case to catch bugs reported in prologue/epilogue generation for ARM ISR routines.

From-SVN: r48210
This commit is contained in:
Nick Clifton 2001-12-20 19:03:37 +00:00
parent e6a8345b03
commit 121308d427
4 changed files with 162 additions and 44 deletions

View File

@ -1,3 +1,25 @@
2001-12-20 Alan Shieh <ashieh@hkn.eecs.berkeley.edu>
* config/arm/arm.c (arm_output_epilogue): Changed IP restore
to use ldmfd instead of ldmea.
* config/arm/arm.c (arm_compute_initial_elimination_offset):
Modified to reflect behavior of arm_expand_prologue when generating
interrupt handlers
2001-12-20 Nick Clifton <nickc@cambridge.redhat.com>
* config/arm/arm.c (arm_compute_save_reg0_reg12_mask): New
function. Compute which of registers r0 through r12 should be
saved onto the stack during a function's prologue.
(arm_compute_save_reg_mask): Use
arm_compute_save_reg0_reg12_mask.
(arm_compute_initial_elimination_offset): Use
arm_compute_save_reg0_reg12_mask.
(arm_expand_prologue): Do not mark as save of the IP register
for an interrupt handler as being part of the frame creation
code.
2001-12-20 Richard Henderson <rth@redhat.com>
* varasm.c (assemble_real): Use REAL_VALUE_TO_x and assemble_integer

View File

@ -104,6 +104,7 @@ static void push_minipool_barrier PARAMS ((rtx, Hint));
static void push_minipool_fix PARAMS ((rtx, Hint, rtx *, Mmode, rtx));
static void note_invalid_constants PARAMS ((rtx, Hint));
static int current_file_function_operand PARAMS ((rtx));
static Ulong arm_compute_save_reg0_reg12_mask PARAMS ((void));
static Ulong arm_compute_save_reg_mask PARAMS ((void));
static Ulong arm_isr_value PARAMS ((tree));
static Ulong arm_compute_func_type PARAMS ((void));
@ -7001,38 +7002,20 @@ output_ascii_pseudo_op (stream, p, len)
fputs ("\"\n", stream);
}
/* Compute a bit mask of which registers need to be
saved on the stack for the current function. */
/* Compute the register sabe mask for registers 0 through 12
inclusive. This code is used by both arm_compute_save_reg_mask
and arm_compute_initial_elimination_offset. */
static unsigned long
arm_compute_save_reg_mask ()
arm_compute_save_reg0_reg12_mask ()
{
unsigned long func_type = arm_current_func_type ();
unsigned int save_reg_mask = 0;
unsigned int reg;
unsigned long func_type = arm_current_func_type ();
if (IS_NAKED (func_type))
/* This should never really happen. */
return 0;
/* 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)
save_reg_mask |=
(1 << ARM_HARD_FRAME_POINTER_REGNUM)
| (1 << IP_REGNUM)
| (1 << LR_REGNUM)
| (1 << PC_REGNUM);
/* Volatile functions do not return, so there
is no need to save any other registers. */
if (IS_VOLATILE (func_type))
return save_reg_mask;
if (IS_INTERRUPT (func_type))
{
unsigned int max_reg;
/* Interrupt functions must not corrupt any registers,
even call clobbered ones. If this is a leaf function
we can just examine the registers used by the RTL, but
@ -7042,7 +7025,7 @@ arm_compute_save_reg_mask ()
if (ARM_FUNC_TYPE (func_type) == ARM_FT_FIQ)
/* FIQ handlers have registers r8 - r12 banked, so
we only need to check r0 - r7, Normal ISRs only
bank r14 and r15, so ew must check up to r12.
bank r14 and r15, so we must check up to r12.
r13 is the stack pointer which is always preserved,
so we do not need to consider it here. */
max_reg = 7;
@ -7077,6 +7060,38 @@ arm_compute_save_reg_mask ()
save_reg_mask |= 1 << PIC_OFFSET_TABLE_REGNUM;
}
return save_reg_mask;
}
/* Compute a bit mask of which registers need to be
saved on the stack for the current function. */
static unsigned long
arm_compute_save_reg_mask ()
{
unsigned int save_reg_mask = 0;
unsigned long func_type = arm_current_func_type ();
if (IS_NAKED (func_type))
/* This should never really happen. */
return 0;
/* 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)
save_reg_mask |=
(1 << ARM_HARD_FRAME_POINTER_REGNUM)
| (1 << IP_REGNUM)
| (1 << LR_REGNUM)
| (1 << PC_REGNUM);
/* Volatile functions do not return, so there
is no need to save any other registers. */
if (IS_VOLATILE (func_type))
return save_reg_mask;
save_reg_mask |= arm_compute_save_reg0_reg12_mask ();
/* Decide if we need to save the link register.
Interrupt routines have their own banked link register,
so they never need to save it.
@ -7535,7 +7550,7 @@ arm_output_epilogue (really_return)
if (IS_INTERRUPT (func_type))
/* Interrupt handlers will have pushed the
IP onto the stack, so restore it now. */
print_multi_reg (f, "ldmea\t%r", SP_REGNUM, 1 << IP_REGNUM);
print_multi_reg (f, "ldmfd\t%r", SP_REGNUM, 1 << IP_REGNUM);
}
else
{
@ -7946,27 +7961,22 @@ arm_compute_initial_elimination_offset (from, to)
call_saved_registers = 0;
if (! IS_VOLATILE (func_type))
{
unsigned int reg_mask;
unsigned int reg;
/* In theory we should check all of the hard registers to
see if they will be saved onto the stack. In practice
registers 11 upwards have special meanings and need to
be check individually. */
for (reg = 0; reg <= 10; reg ++)
if (regs_ever_live[reg] && ! call_used_regs[reg])
/* Makre sure that we compute which registers will be saved
on the stack using the same algorithm that is used by
arm_compute_save_reg_mask(). */
reg_mask = arm_compute_save_reg0_reg12_mask ();
/* Now count the number of bits set in save_reg_mask.
For each set bit we need 4 bytes of stack space. */
while (reg_mask)
{
call_saved_registers += 4;
/* Determine if register 11 will be clobbered. */
if (! TARGET_APCS_FRAME
&& ! frame_pointer_needed
&& regs_ever_live[HARD_FRAME_POINTER_REGNUM]
&& ! call_used_regs[HARD_FRAME_POINTER_REGNUM])
call_saved_registers += 4;
/* The PIC register is fixed, so if the function will
corrupt it, it has to be saved onto the stack. */
if (flag_pic && regs_ever_live[PIC_OFFSET_TABLE_REGNUM])
call_saved_registers += 4;
reg_mask = reg_mask & ~ (reg_mask & - reg_mask);
}
if (regs_ever_live[LR_REGNUM]
/* If a stack frame is going to be created, the LR will
@ -8097,7 +8107,18 @@ arm_expand_prologue ()
Creating a frame pointer however, corrupts the IP
register, so we must push it first. */
insn = emit_multi_reg_push (1 << IP_REGNUM);
RTX_FRAME_RELATED_P (insn) = 1;
/* Do not set RTX_FRAME_RELATED_P on this insn.
The dwarf stack unwinding code only wants to see one
stack decrement per function, and this is not it. If
this instruction is labeled as being part of the frame
creation sequence then dwarf2out_frame_debug_expr will
abort when it encounters the assignment of IP to FP
later on, since the use of SP here establishes SP as
the CFA register and not IP.
Anyway this instruction is not really part of the stack
frame creation although it is part of the prologue. */
}
else if (IS_NESTED (func_type))
{

View File

@ -0,0 +1,48 @@
#ifndef __thumb__
/* There used to be a couple of bugs in the ARM's prologue and epilogue
generation for ISR routines. The wrong epilogue instruction would be
generated to restore the IP register if it had to be pushed onto the
stack, and the wrong offset was being computed for local variables if
r0 - r3 had to be saved. This tests for both of these cases. */
int z = 9;
int
bar (void)
{
return z;
}
int
foo (int a, int b, int c, int d, int e, int f, int g, int h)
{
volatile int i = (a + b) - (g + h) + bar ();
volatile int j = (e + f) - (c + d);
return a + b + c + d + e + f + g + h + i + j;
}
int foo1 (int a, int b, int c, int d, int e, int f, int g, int h) __attribute__ ((interrupt ("IRQ")));
int
foo1 (int a, int b, int c, int d, int e, int f, int g, int h)
{
volatile int i = (a + b) - (g + h) + bar ();
volatile int j = (e + f) - (c + d);
return a + b + c + d + e + f + g + h + i + j;
}
#endif
int
main (void)
{
#ifndef __thumb__
if (foo (1, 2, 3, 4, 5, 6, 7, 8) != 32)
abort ();
if (foo1 (1, 2, 3, 4, 5, 6, 7, 8) != 32)
abort ();
#endif
exit (0);
}

View File

@ -0,0 +1,27 @@
# Copyright (C) 2001 Free Software Foundation, Inc.
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
# This file is based on a bug report submitted to gcc-bugs:
# Load support procs.
load_lib gcc-dg.exp
dg-init
if {[istarget "*arm-*-*"] || [istarget "xscale-*-*"]} {
dg-runtest "$srcdir/$subdir/arm-isr.c" "" ""
}
dg-finish