Fix bootstrapping on the PA

Jeffrey A Law
Tue Jun 1 07:35:00 GMT 2004

The PA is a segmented architecture with implicit segment selection.
However, segment selection is performed on the base register rather
than the effective address.  Thus

ldw %r1(%r2),%r3  /*    *(%r1+%r2) -> %r3 */

Is not the same as

ldw %r2(%r1),%r3  /*    *(%r2+%r1) -> %r3 */

The first load will reference the segment based on the upper bits of
%r2 while the second load will reference the segment based on the
upper bits in %r1.

The PA port uses REG_POINTER to distinguish between base and index
registers in unscaled indexed addressing modes.  Unfortunately, GCC
tends to mark lots of non-pointer objects with REG_POINTER.

The problem is our representation for pointer arithmetic is
fundamentally broken -- specifically the front-ends and later
various optimizers force both operands in a pointer arithmetic
expression to have pointer types.  Thus if given something like
this at the source level:

char *p;
int i;

for (i = 0; i < 10; i++)
  foo (p + i);

Will effectively be turned into

char *p;
int i;
for (i = 0; i < 10; i++)
  foo (p + (char *)i);

NOP_EXPRs are not valid gimple operands, so gimplification will
turn that into something like this:

char *p,*temp;
int i;
for (i = 0; i < 10; i++)
    temp = (char *)i;
    foo (p + temp);

Note that "temp" has a pointer type and thus will be marked with
REG_POINTER by stmt.c::expand_decl.

In this particular example, both p and temp will be marked as pointers
and the PA backend will DTRT (not use unscaled indexed address modes).
However, in more complex cases, we can have a base register which is
_not_ marked with REG_POINTER and at the same time we can have a
temporary which is marked with REG_POINTER even though the temporary
is just a loop index.  This can and does cause the PA to generate
incorrect code.

Note very very carefully this means that failure to mark a pointer
with REG_POINTER can result in incorrect code on the PA (and possibly
ia64 and the mn10300).  That is very very bad as it means that
it is not safe to have a pointer which is not marked with REG_POINTER.

I am still working on fixing GCC's type system to deal with this
properly, but in the mean time some changes are necessary to make
GCC more sanely set REG_POINTER and avoid some of this losing

It turns out that we can avoid these problems by being more selective
about our marking of pointers in stmt.c::expand_decl.

Specifically, the problems occur due to the creation of _temporaries_
with pointer types but which actually hold index values (instead of
base pointers).  So rather than marking every pointer object with
REG_POINTER, we just mark those objects which correspond to user
variables with REG_POINTER.

With this patch the 32bit PA compiler bootstraps when previously
it failed during the stage2 build.  The target libs do not build
yet, but that's a totally unrelated problem.   I need to do a 
major update on my PA64 tools before I can try a bootstrap on PA64
(trying to bootstrap with my circa 2000 tools fails miserably as
does trying to bootstrap with the native PA64 tools supplied by HP).

Anyway, this patch is still a good step forward.

-------------- next part --------------
	* stmt.c (expand_decl): Be more selective about calling 

Index: stmt.c
RCS file: /cvs/gcc/gcc/gcc/stmt.c,v
retrieving revision 1.356
diff -c -p -r1.356 stmt.c
*** stmt.c	26 May 2004 22:36:49 -0000	1.356
--- stmt.c	1 Jun 2004 05:46:15 -0000
*************** expand_decl (tree decl)
*** 3422,3433 ****
        SET_DECL_RTL (decl, gen_reg_rtx (reg_mode));
        if (!DECL_ARTIFICIAL (decl))
! 	mark_user_reg (DECL_RTL (decl));
!       if (POINTER_TYPE_P (type))
! 	mark_reg_pointer (DECL_RTL (decl),
! 			  TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
        maybe_set_unchanging (DECL_RTL (decl), decl);
--- 3422,3442 ----
        SET_DECL_RTL (decl, gen_reg_rtx (reg_mode));
+       /* Note if the object is a user variable.  */
        if (!DECL_ARTIFICIAL (decl))
! 	{
! 	  mark_user_reg (DECL_RTL (decl));
! 	  /* Trust user variables which have a pointer type to really
! 	     be pointers.  Do not trust compiler generated temporaries
! 	     as our type system is totally busted as it relates to
! 	     pointer arithmetic which translates into lots of compiler
! 	     generated objects with pointer types, but which are not really
! 	     pointers.  */
! 	  if (POINTER_TYPE_P (type))
! 	    mark_reg_pointer (DECL_RTL (decl),
! 			      TYPE_ALIGN (TREE_TYPE (TREE_TYPE (decl))));
! 	}
        maybe_set_unchanging (DECL_RTL (decl), decl);

More information about the Gcc-patches mailing list