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