flow patch for building ia64

amacleod@cygnus.com amacleod@cygnus.com
Thu Jul 26 14:30:00 GMT 2001


I was looking at why the trunk cannot build libgcc for ia64 today.
It bombs out in propagate_one_insn when trying to compile __fixdfti
in libgcc2.c. The function isn't very big, and simply reduces down to:

typedef int TItype __attribute__ ((mode (TI)));
typedef float DFtype __attribute__ ((mode (DF)));

TItype
__fixdfti (DFtype a)
{
  if (a < 0)
    return - __fixunsdfti (-a);
  return __fixunsdfti (a);
}

It turns out the only thing the prologue saves is the value of b0 
into register r33.   This value is then restored in the epilogue.
The processing in propagate_one_insn goes through the entire list of 
registers which are invalidated by a call, and removes them from 
the live list.  What it doesn't take into acocunt is that there
are a few registers which are 'symbolic' in nature, but may map back to
hardware registers. the important ones are
mapped right in gen_rtx_REG (), and MAY consist of:

      frame_pointer_rtx
      hard_frame_pointer_rtx
      arg_pointer_rtx
      return_address_pointer_rtx
      stack_pointer_rtx

In the ia64 case, after the copy of b0 into r33, we updated
return_address_pointer_rtx to be r33. Then during propagate_one_insn,
the symbolic register RETURN_ADDRESS_POINTER_REGNUM (reg #329)
is marked as killed by a call, so propagate_one_insn clears
register #329 from the reg_live list, but the call to gen_rtx_REG
maps register 329 back to r33, and so r33 is removed from the list 
instead.

So... there are 2 solutions. Since this doesn't seem to be 
affecting anything except ia64, the simple thing is to 
not mark the return_address_register as call-killed. b0 is
marked, so I dont think this will have any undesired side effects.

The other option would be to look at the register generated by the 
call to gen_rtx_REG and test whether it is call clobbered or not. 
This seem like a more general solution, but I dont know if that
might have other unexpected side effects....  Either one
solves the problem for ia64.

Which is the preferable solution?  (Or maybe both? :-)  I'm 
working on bootstrapping the general one right now.


simple ia64 one:

	* config/ia64/ia64.h (CALL_USED_REGISTERS): Unset RA register, b0 
	already handles this.

Index: config/ia64/ia64.h
===================================================================
RCS file: /cvs/gcc/egcs/gcc/config/ia64/ia64.h,v
retrieving revision 1.78
diff -c -p -r1.78 ia64.h
*** ia64.h	2001/07/25 13:21:49	1.78
--- ia64.h	2001/07/26 21:24:24
*************** while (0)
*** 630,636 ****
    /* Branch registers.  */				\
    1, 0, 0, 0, 0, 0, 1, 1,				\
    /*FP RA CCV UNAT PFS LC EC */				\
!      1, 1,  1,   1,  1, 0, 1				\
  }
  
  /* Define this macro if the target machine has register windows.  This C
--- 630,636 ----
    /* Branch registers.  */				\
    1, 0, 0, 0, 0, 0, 1, 1,				\
    /*FP RA CCV UNAT PFS LC EC */				\
!      1, 0,  1,   1,  1, 0, 1				\
  }
  
  /* Define this macro if the target machine has register windows.  This C


or the more general one:

	* flow.c (propagate_one_insn): Ensure that the register we are 
	invalidating doesn't point to a different register which is valid.

Index: flow.c
===================================================================
RCS file: /cvs/gcc/egcs/gcc/flow.c,v
retrieving revision 1.442
diff -c -p -r1.442 flow.c
*** flow.c	2001/07/25 20:51:24	1.442
--- flow.c	2001/07/26 21:08:19
*************** propagate_one_insn (pbi, insn)
*** 5090,5097 ****
  	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  	    if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
  	      {
  		/* We do not want REG_UNUSED notes for these registers.  */
! 		mark_set_1 (pbi, CLOBBER, gen_rtx_REG (reg_raw_mode[i], i),
  			    cond, insn,
  			    pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
  	      }
--- 5090,5104 ----
  	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
  	    if (TEST_HARD_REG_BIT (regs_invalidated_by_call, i))
  	      {
+ 	        rtx reg = gen_rtx_REG (reg_raw_mode[i], i);
+ 		/* If this register maps to a different one, make
+ 		   sure this one is invalidated by the call.  */
+ 		if (REGNO (reg) != i 
+ 		    && !TEST_HARD_REG_BIT (regs_invalidated_by_call, 
+ 					   REGNO (reg)))
+ 		  continue;
  		/* We do not want REG_UNUSED notes for these registers.  */
! 		mark_set_1 (pbi, CLOBBER, reg,
  			    cond, insn,
  			    pbi->flags & ~(PROP_DEATH_NOTES | PROP_REG_INFO));
  	      }



More information about the Gcc-bugs mailing list