Fix reglap for procedures that use both sizes of reg_float.

After the RA phase of ego, a procedure may put single-word and
double-word values in the same reg_float.  Then ncg will use both
LOCAL and DLOCAL tokens at the same offset.

I add isregvar_size() to ncg.  It receives the size of the LOCAL or
DLOCAL token, and picks the register of the correct size.  This fixes
a problem where ncg got the wrong-size register and corrupted the
stack.  This problem caused one of my test programs to segfault from
stack underflow.

Also adjust how fixregvars() handles both sizes.
This commit is contained in:
George Koehler 2017-10-15 13:15:03 -04:00
parent b342b83d28
commit aa876ff4c2
3 changed files with 51 additions and 20 deletions

View file

@ -102,40 +102,44 @@ tryreg(struct regvar *rvlp, int typ) {
void void
fixregvars(int saveall) { fixregvars(int saveall) {
register struct regvar *rv; struct reginfo *rp, *rp2;
register rvtyp,i; struct regvar *rv;
int i, regno, rvtyp;
swtxt(); swtxt();
i_regsave(); /* machine dependent initialization */ i_regsave(); /* machine dependent initialization */
for (rvtyp=reg_any;rvtyp<=reg_float;rvtyp++) { for (rvtyp=reg_any;rvtyp<=reg_float;rvtyp++) {
for(i=0;i<nregvar[rvtyp];i++) for(i=0;i<nregvar[rvtyp];i++)
if (saveall) { if (saveall) {
struct reginfo *rp;
rp= &machregs[rvnumbers[rvtyp][i]]; rp= &machregs[rvnumbers[rvtyp][i]];
regsave(codestrings[rp->r_repr],
(long)-TEM_WSIZE,rp->r_size);
#ifdef REGLAP #ifdef REGLAP
/* reg_float may have one subregister */ /*
if (rp->r_members[0]!=0) { * A reg_float may have two sizes. If so,
rp= &machregs[rp->r_members[0]]; * only save the larger size.
*/
if ((regno = rp->r_members[0]) != 0 &&
machregs[regno].r_size > rp->r_size)
rp= &machregs[regno];
#endif
regsave(codestrings[rp->r_repr], regsave(codestrings[rp->r_repr],
(long)-TEM_WSIZE,rp->r_size); (long)-TEM_WSIZE,rp->r_size);
}
#endif
} else if(regassigned[rvtyp][i].ra_score>0) { } else if(regassigned[rvtyp][i].ra_score>0) {
rv=regassigned[rvtyp][i].ra_rv; rv=regassigned[rvtyp][i].ra_rv;
rv->rv_reg=rvnumbers[rvtyp][i]; rv->rv_reg = regno = rvnumbers[rvtyp][i];
rv->rv_type = rvtyp; rv->rv_type = rvtyp;
#ifdef REGLAP #ifdef REGLAP
/* reg_float may have alternate size */ /*
if (machregs[rv->rv_reg].r_size != rv->rv_size) { * Change regno to match rv->rv_size, but
rv->rv_reg = machregs[rv->rv_reg].r_members[0]; * leave old regno in rv->rv_reg so that
assert(rv->rv_reg != 0); * isregvar_size() can handle both sizes.
assert(machregs[rv->rv_reg].r_size == */
rv->rv_size); if (machregs[regno].r_size != rv->rv_size) {
regno = machregs[regno].r_members[0];
assert(regno != 0);
assert(machregs[regno].r_size == rv->rv_size);
} }
#endif #endif
regsave(codestrings[machregs[rv->rv_reg].r_repr], regsave(codestrings[machregs[regno].r_repr],
rv->rv_off,rv->rv_size); rv->rv_off,rv->rv_size);
} }
} }
@ -152,6 +156,26 @@ isregvar(long off) {
return(-1); return(-1);
} }
#ifdef REGLAP
int
isregvar_size(long off, int size) {
int regno = isregvar(off);
/*
* A reg_float may have two sizes. If this register has the
* wrong size, then use the overlapping register. A register
* may switch sizes in the middle of a procedure.
*/
if (regno > 0 && machregs[regno].r_size != size) {
if (machregs[regno].r_size != size) {
regno = machregs[regno].r_members[0];
assert(regno != 0);
assert(machregs[regno].r_size == size);
}
}
return regno;
}
#endif /* REGLAP */
int int
isregtyp(long off) { isregtyp(long off) {
register struct regvar *rvlp; register struct regvar *rvlp;

View file

@ -26,5 +26,10 @@ struct regvar *linkreg(long, int, int, int);
void tryreg(struct regvar *, int); void tryreg(struct regvar *, int);
void fixregvars(int); void fixregvars(int);
int isregvar(long); int isregvar(long);
#ifdef REGLAP
int isregvar_size(long, int);
#else
#define isregvar_size(off, size) isregvar(off)
#endif
int isregtyp(long); int isregtyp(long);
void unlinkregs(void); void unlinkregs(void);

View file

@ -121,7 +121,9 @@ instance(instno,token) register token_p token; {
case IN_D_DESCR: case IN_D_DESCR:
compute(&enodes[inp->in_info[1]], &result); compute(&enodes[inp->in_info[1]], &result);
assert(result.e_typ==EV_INT); assert(result.e_typ==EV_INT);
if ((regno=isregvar(result.e_v.e_con)) > 0) { regno = isregvar_size(result.e_v.e_con,
tokens[inp->in_info[0]].t_size);
if (regno > 0) {
token->t_token = -1; token->t_token = -1;
token->t_att[0].ar = regno; token->t_att[0].ar = regno;
for (i=TOKENSIZE-1;i>0;i--) for (i=TOKENSIZE-1;i>0;i--)