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
fixregvars(int saveall) {
register struct regvar *rv;
register rvtyp,i;
struct reginfo *rp, *rp2;
struct regvar *rv;
int i, regno, rvtyp;
swtxt();
i_regsave(); /* machine dependent initialization */
for (rvtyp=reg_any;rvtyp<=reg_float;rvtyp++) {
for(i=0;i<nregvar[rvtyp];i++)
if (saveall) {
struct reginfo *rp;
rp= &machregs[rvnumbers[rvtyp][i]];
regsave(codestrings[rp->r_repr],
(long)-TEM_WSIZE,rp->r_size);
#ifdef REGLAP
/* reg_float may have one subregister */
if (rp->r_members[0]!=0) {
rp= &machregs[rp->r_members[0]];
/*
* A reg_float may have two sizes. If so,
* 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],
(long)-TEM_WSIZE,rp->r_size);
}
#endif
} else if(regassigned[rvtyp][i].ra_score>0) {
rv=regassigned[rvtyp][i].ra_rv;
rv->rv_reg=rvnumbers[rvtyp][i];
rv->rv_reg = regno = rvnumbers[rvtyp][i];
rv->rv_type = rvtyp;
#ifdef REGLAP
/* reg_float may have alternate size */
if (machregs[rv->rv_reg].r_size != rv->rv_size) {
rv->rv_reg = machregs[rv->rv_reg].r_members[0];
assert(rv->rv_reg != 0);
assert(machregs[rv->rv_reg].r_size ==
rv->rv_size);
/*
* Change regno to match rv->rv_size, but
* leave old regno in rv->rv_reg so that
* isregvar_size() can handle both sizes.
*/
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
regsave(codestrings[machregs[rv->rv_reg].r_repr],
regsave(codestrings[machregs[regno].r_repr],
rv->rv_off,rv->rv_size);
}
}
@ -152,6 +156,26 @@ isregvar(long off) {
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
isregtyp(long off) {
register struct regvar *rvlp;

View file

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

View file

@ -121,7 +121,9 @@ instance(instno,token) register token_p token; {
case IN_D_DESCR:
compute(&enodes[inp->in_info[1]], &result);
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_att[0].ar = regno;
for (i=TOKENSIZE-1;i>0;i--)