Fix reglap for procedures that use both sizes of reg_float.
authorGeorge Koehler <xkernigh@netscape.net>
Sun, 15 Oct 2017 17:15:03 +0000 (13:15 -0400)
committerGeorge Koehler <xkernigh@netscape.net>
Sun, 15 Oct 2017 17:15:03 +0000 (13:15 -0400)
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
mach/proto/ncg/regvar.h
mach/proto/ncg/subr.c

index f391348..51909b0 100644 (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]];
-                               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;
index 2a66ddc..cd7da21 100644 (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);
index 0c14fa4..0ce937e 100644 (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--)