This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]

Bug in mark_reg_pointer



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;
  }
  

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]