This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Bug in mark_reg_pointer
- To: gcc-patches at gcc dot gnu dot org
- Subject: Bug in mark_reg_pointer
- From: Richard Earnshaw <rearnsha at arm dot com>
- Date: Tue, 10 Aug 1999 15:15:03 +0100
- Cc: richard dot earnshaw at arm dot com
- Organization: ARM Ltd.
- Reply-To: richard dot earnshaw at arm dot com
This is a problem we have come across while trying to get the latest
snapshot of Aladin ghostscript to compile on the ARM and the Alpha.
There is a bug in the current implementation of mark_reg_pointer in the
way it notes alignment information. The bug is revealed by the test case
below on machines which make use of this information to optimize sub-word
accesses (currently the Alpha and the ARM I believe). The problem stems
from the fact that mark_reg_pointer unconditionally updates the known
alignment of a pointer when certain casting operations are performed, but
this means that in other cases a pointer may be assumed to be more aligned
than is in fact the case.
In the test case the cast to "struct s" causes the compiler to note that
the pointer is sufficiently aligned that it can dereference elements of
this struct, but it then later incorrectly uses this information when
dereferencing the short or char.
The patch simply forces mark_reg_pointer not to allow the known alignment
to be increased after an initial marking of a register (it does allow the
known alignment to be reduced -- I'm not sure how useful this is in
practice, it probably only has an effect on non-conforming programs).
I believe the test case is conforming ANSI code (pointers are only
dereferenced in the type they were originally written to). Is the test ok
for adding to the test suite?
Richard
struct s {long a; int b;};
int foo(int x, void *y)
{
switch(x) {
case 0: return ((struct s*)y)->a;
case 1: return *(signed char*)y;
case 2: return *(short*)y;
}
abort();
}
int main ()
{
struct s s;
short sh[10];
signed char c[10];
int i;
s.a = 1;
s.b = 2;
for (i = 0; i < 10; i++) {
sh[i] = i;
c[i] = i;
}
if (foo(0, &s) != 1) abort();
if (foo(1, c+3) != 3) abort();
if (foo(2, sh+3) != 3) abort();
exit(0);
}
Index: emit-rtl.c
===================================================================
RCS file: /egcs/carton/cvsfiles/egcs/gcc/emit-rtl.c,v
retrieving revision 1.66
diff -p -r1.66 emit-rtl.c
*** emit-rtl.c 1999/08/01 12:07:34 1.66
--- emit-rtl.c 1999/08/07 12:13:25
*************** mark_reg_pointer (reg, align)
*** 629,637 ****
rtx reg;
int align;
{
! REGNO_POINTER_FLAG (REGNO (reg)) = 1;
! if (align)
REGNO_POINTER_ALIGN (REGNO (reg)) = align;
}
--- 629,643 ----
rtx reg;
int align;
{
! if (! REGNO_POINTER_FLAG (REGNO (reg)))
! {
! REGNO_POINTER_FLAG (REGNO (reg)) = 1;
! if (align)
! REGNO_POINTER_ALIGN (REGNO (reg)) = align;
! }
! else if (align && align < REGNO_POINTER_ALIGN (REGNO (reg)))
! /* We can no-longer be sure just how aligned this pointer is */
REGNO_POINTER_ALIGN (REGNO (reg)) = align;
}