ppc question for altivec

mike stump mrs@windriver.com
Fri Jan 25 18:48:00 GMT 2002


In gcc we have:

  total_raw_size	 = (info_ptr->vars_size
			    + info_ptr->parm_size
			    + info_ptr->save_size
			    + info_ptr->varargs_size
			    + info_ptr->fixed_size);

and:

  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
					 8);

and:

#undef STARTING_FRAME_OFFSET
#define STARTING_FRAME_OFFSET						\
  (RS6000_ALIGN (current_function_outgoing_args_size, 16)		\
   + RS6000_VARARGS_AREA						\
   + RS6000_SAVE_AREA)

and:

#define STARTING_FRAME_OFFSET						\
  (RS6000_ALIGN (current_function_outgoing_args_size,			\
		 TARGET_ALTIVEC ? 16 : 8)				\
   + RS6000_VARARGS_AREA						\
   + RS6000_SAVE_AREA)

This seems wrong.  The first thing that is wrong, is that the
calculation for the sizes is wholly separate from the offset
calculations.  This is a bogus design.  If this were fixed, the code
would be more readable and understandable as well as more maintainable
and less likely to be wrong.

The problem is that the starting frame offset is `pushed' over,
farther, and this pushing action needs a corresponding resizing action
to balance the push.  There isn't any such code I can find.  Thus,
this is either confused (lucky), or wrong.  Well, that or I found
myself completely lost in what is going on, which is true.  I think I
have a real bug that I am tracking down and trying to fix, caused by
the testcase at the end.  I tried something near the top of tree, and
with -maltivec -O2, I was able to get:

rtioctl:
        stwu 1,-48(1)
        mflr 0
        lis 9,evtAction@ha
        stw 0,52(1)
        stw 29,36(1)			; store r29 into r1[36]
        mr 29,3
        lwz 0,evtAction@l(9)
        stw 30,40(1)
        addi 30,1,24			; r30=r1+24
        cmpwi 0,0,0
        stw 31,44(1)
        stw 28,32(1)
        mr 31,4
        beq- 0,.L2
        li 0,0
        lis 9,wvNetEventId@ha
        stw 0,wvNetEventId@l(9)
.L2:
        mr 3,30				; clobber 16 bytes starting at r30, or r1+24,
					; r1+24+16==r1+40 is first free byte past the var
        li 4,0
        li 5,16				; size is 16 bytes
        crxor 6,6,6
        bl memset

Now, what is wrong is that the thing bzerod (netMask) is 16 bytes
long, and those 16 bytes start at r1+24, the first free byte not
clobbers is at r1+40, however, r29 is stored into r1[36].  The bzero
wipes the saved value of r29.  The code should be thrown away, as
wrong, and reimplemented with a clean design...  anyway...

The most trivial fix I propose would be to modify:

  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
					 8);

to be

  info_ptr->parm_size    = RS6000_ALIGN (current_function_outgoing_args_size,
					 bla);

where bla is something that subtargets can set as they may.  Some want
16 always, some want TARGET_ALTIVEC ? 16 : 8, and some want 8.  Also,
this same bla should be used in the definition of
STARTING_FRAME_OFFSET, and all other #defines for this brought into
rs6000.h.

The problem is, this code is so convoluted that I cannot even be half
sure this is the right fix.  David, does any of this sound right?

Stan, the failure mode of this should be so spectacular, that I don't
see how darwin could get by with this bug in it.  My code goes back to
the moto altivec release with a gcc from 1998.  Stan, can you see this
in any of your compilers for darwin/altivec?

Thanks.

Mike - the guy that runs gcc in life critical situations.  :-)


typedef	char *	caddr_t;
typedef	unsigned char	u_char;
typedef	unsigned long	u_long;

struct sockaddr {
	u_char	sa_len;
	u_char	sa_family;
	char	sa_data[14];
};

struct ortentry {
	u_long	rt_hash;
	struct	sockaddr rt_dst;
	struct	sockaddr rt_gateway;
	short	rt_flags;
};

struct ifaddr {
	struct	sockaddr *ifa_addr;
	struct	sockaddr *ifa_dstaddr;

	struct	sockaddr *ifa_netmask;
	struct	ifnet *ifa_ifp;
	struct	ifaddr *ifa_next;
	void	(*ifa_rtrequest)();
	short	ifa_refcnt;
	int	ifa_metric;
};

extern int evtAction;

struct in_addr {
	u_long s_addr;
};


struct sockaddr_in {
	struct	in_addr sin_addr;
	char	sin_zero[8];
};


struct in_ifaddr {
	u_long	ia_net;
	u_long	ia_subnetmask;
	struct	in_addr ia_netbroadcast;
	struct	in_ifaddr *ia_next;
};

extern	struct	in_ifaddr *in_ifaddr;
extern  int wvNetModuleId ;
extern  int wvNetLocalFilter ;
static  int wvNetEventId;

int
rtioctl(req, data)
	int req;
	char *data;
{
	struct ortentry * pORE = 0;
	struct sockaddr netMask;
	struct sockaddr * pNetMask = &netMask;
	register u_long i;
	register u_long net;
	register struct in_ifaddr *ia;


    if (evtAction) { wvNetEventId = 0  ;  }
	pORE = (struct ortentry *)data;
	bzero ((caddr_t)&netMask, sizeof (struct sockaddr));
	if (((struct sockaddr_in *)(&pORE->rt_dst))->sin_addr.s_addr)
	    {
	    i = ( ((struct sockaddr_in*)&pORE->rt_dst)->sin_addr.s_addr ) ;

	    for (ia = in_ifaddr; ia; ia = ia->ia_next)
		if (net == ia->ia_net)
		    ((struct sockaddr_in *)pNetMask)->sin_addr.s_addr =
			( ia->ia_subnetmask ) ;
	    in_socktrim ((struct sockaddr_in *)pNetMask);
	    }


       if (req)
	   return (rtrequestAddEqui (&pORE->rt_dst, pNetMask,
                                     &pORE->rt_gateway, pORE->rt_flags,
                                     0 , 0,
                                     0 , 0 , 0));
       else
	   return rtrequestDelEqui (&pORE->rt_dst);
}



More information about the Gcc mailing list