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:
parent
e6a8345b03
commit
121308d427
@ -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
|
||||
|
@ -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))
|
||||
{
|
||||
|
48
gcc/testsuite/gcc.misc-tests/arm-isr.c
Normal file
48
gcc/testsuite/gcc.misc-tests/arm-isr.c
Normal 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);
|
||||
}
|
27
gcc/testsuite/gcc.misc-tests/arm-isr.exp
Normal file
27
gcc/testsuite/gcc.misc-tests/arm-isr.exp
Normal 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
|
||||
|
Loading…
Reference in New Issue
Block a user