From aa876ff4c20c8c30173057cd05ab8dc210dc1894 Mon Sep 17 00:00:00 2001 From: George Koehler Date: Sun, 15 Oct 2017 13:15:03 -0400 Subject: [PATCH] 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. --- mach/proto/ncg/regvar.c | 62 ++++++++++++++++++++++++++++------------- mach/proto/ncg/regvar.h | 5 ++++ mach/proto/ncg/subr.c | 4 ++- 3 files changed, 51 insertions(+), 20 deletions(-) diff --git a/mach/proto/ncg/regvar.c b/mach/proto/ncg/regvar.c index f39134892..51909b082 100644 --- a/mach/proto/ncg/regvar.c +++ b/mach/proto/ncg/regvar.c @@ -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;ir_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]]; - regsave(codestrings[rp->r_repr], - (long)-TEM_WSIZE,rp->r_size); - } + /* + * 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); } 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; diff --git a/mach/proto/ncg/regvar.h b/mach/proto/ncg/regvar.h index 2a66ddc4d..cd7da216f 100644 --- a/mach/proto/ncg/regvar.h +++ b/mach/proto/ncg/regvar.h @@ -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); diff --git a/mach/proto/ncg/subr.c b/mach/proto/ncg/subr.c index 0c14fa410..0ce937ecb 100644 --- a/mach/proto/ncg/subr.c +++ b/mach/proto/ncg/subr.c @@ -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--) -- 2.34.1