diff --git a/mach/powerpc/ncg/mach.c b/mach/powerpc/ncg/mach.c index 31ca2d371..32e05daa3 100644 --- a/mach/powerpc/ncg/mach.c +++ b/mach/powerpc/ncg/mach.c @@ -106,6 +106,7 @@ char *segname[] = { static long savedf[32]; static long savedi[32]; static int savedtop; +static unsigned long lfs_set; /* Calculate the register score of a local variable. */ int @@ -118,7 +119,7 @@ regscore(long offset, int size, int type, int frequency, int totype) /* Don't put reg_float in reg_any. */ if (totype != reg_float) return -1; - assert(size == 8); + assert(size == 4 || size == 8); break; default: assert(size == 4); @@ -155,6 +156,8 @@ i_regsave(void) /* Set top of register save area, relative to fp. */ savedtop = -framesize; + + lfs_set = 0; /* empty set */ } /* Mark a register as being saved. */ @@ -168,6 +171,8 @@ regsave(const char* regname, long offset, int size) case 'f': savedf[regnum] = offset; framesize += 8; + if (size == 4) + lfs_set |= (1U << regnum); break; case 'r': savedi[regnum] = offset; @@ -224,9 +229,14 @@ f_regsave(void) emit_prolog(); saveloadregs("stw", "stmw", "stfd"); + /* + * Register variables with offset >= 0 must load an argument + * from that offset. + */ for (reg = 31; reg >= 0; reg--) if (savedf[reg] >= 0) - fprintf(codefile, "lfd f%d, %ld(fp)\n", + fprintf(codefile, "%s f%d, %ld(fp)\n", + (lfs_set & (1U << reg)) ? "lfs" : "lfd", reg, savedf[reg]); for (reg = 31; reg >= 0; reg--) diff --git a/mach/powerpc/ncg/table b/mach/powerpc/ncg/table index 7c6ffbd49..23b904264 100644 --- a/mach/powerpc/ncg/table +++ b/mach/powerpc/ncg/table @@ -77,6 +77,14 @@ REGISTERS fs13("f13")=f13 : FSREG. + /* reglap: reg_float may have subregister of different size */ + fs14("f14")=f14, fs15("f15")=f15, fs16("f16")=f16, fs17("f17")=f17, + fs18("f18")=f18, fs19("f19")=f19, fs20("f20")=f20, fs21("f21")=f21, + fs22("f22")=f22, fs23("f23")=f23, fs24("f24")=f24, fs25("f25")=f25, + fs26("f26")=f26, fs27("f27")=f27, fs28("f28")=f28, fs29("f29")=f29, + fs30("f30")=f30, fs31("f31")=f31 + : FSREG regvar(reg_float). + lr, ctr : SPR. cr0 : CR. @@ -257,7 +265,7 @@ INSTRUCTIONS fdiv FREG+DLOCAL:wo, FREG:ro, FREG:ro cost(4, 35). fdivs FSREG:wo, FSREG:ro, FSREG:ro cost(4, 21). fmr FPR+DLOCAL:wo, FPR:ro cost(4, 5). - fmr FSREG:wo, FSREG:ro cost(4, 5). + fmr FSREG+LOCAL:wo, FSREG:ro cost(4, 5). fmul FREG+DLOCAL:wo, FREG:ro, FREG:ro cost(4, 5). fmuls FSREG:wo, FSREG:ro, FSREG:ro cost(4, 5). fneg FREG+DLOCAL:wo, FREG:ro cost(4, 5). @@ -270,9 +278,9 @@ INSTRUCTIONS lfd FPR+DLOCAL:wo, IND_RC_D+IND_RL_D:ro cost(4, 5). lfdu FPR:wo, IND_RC_D:ro cost(4, 5). lfdx FPR+DLOCAL:wo, GPR:ro, GPR:ro cost(4, 5). - lfs FSREG:wo, IND_RC_W+IND_RL_W:ro cost(4, 4). + lfs FSREG+LOCAL:wo, IND_RC_W+IND_RL_W:ro cost(4, 4). lfsu FSREG:wo, IND_RC_W:rw cost(4, 4). - lfsx FSREG:wo, GPR:ro, GPR:ro cost(4, 4). + lfsx FSREG+LOCAL:wo, GPR:ro, GPR:ro cost(4, 4). lha GPR:wo, IND_RC_H_S+IND_RL_H_S:ro cost(4, 3). lhax GPR:wo, GPR:ro, GPR:ro cost(4, 3). lhz GPR:wo, IND_RC_H+IND_RL_H:ro cost(4, 3). @@ -309,7 +317,7 @@ INSTRUCTIONS stfdu FPR+DLOCAL:ro, IND_RC_D:rw cost(4, 4). stfdx FPR:ro, GPR:ro, GPR:ro cost(4, 4). stfs FSREG:ro, IND_RC_W+IND_RL_W:rw cost(4, 3). - stfsu FSREG:ro, IND_RC_W:rw cost(4, 3). + stfsu FSREG+LOCAL:ro, IND_RC_W:rw cost(4, 3). stfsx FSREG:ro, GPR:ro, GPR:ro cost(4, 3). sth GPR:ro, IND_RC_H+IND_RL_H:rw cost(4, 3). sthx GPR:ro, GPR:ro, GPR:ro cost(4, 3). @@ -328,6 +336,9 @@ MOVES from GPR to GPR gen mr %2, %1 + from FSREG to FSREG + gen fmr %2, %1 + from FPR to FPR+DLOCAL gen fmr %2, %1 @@ -577,6 +588,11 @@ TESTS STACKINGRULES + from LOCAL inreg(%off)==reg_float to STACK + gen + COMMENT("stack LOCAL") + stfsu %1, {IND_RC_W, sp, 0-4} + from LOCAL to STACK gen COMMENT("stack LOCAL") @@ -775,7 +791,7 @@ PATTERNS yields {SUM_RC, %a, los($1)} /* Load word from local */ - pat lol inreg($1)==reg_any + pat lol inreg($1)==reg_any || inreg($1)==reg_float yields {LOCAL, $1} pat lol leaving @@ -795,6 +811,13 @@ PATTERNS with ANY_BHW kills regvar($1), LOCAL %off==$1 gen move %1, {GPRE, regvar($1)} + pat stl inreg($1)==reg_float + with exact FSREG + gen fmr {LOCAL, $1}, %1 + with STACK + gen + lfs {LOCAL, $1}, {IND_RC_W, sp, 0} + addi sp, sp, {CONST, 4} pat stl leaving lal $1 diff --git a/mach/proto/ncg/regvar.c b/mach/proto/ncg/regvar.c index 4c11da2b1..934b775f8 100644 --- a/mach/proto/ncg/regvar.c +++ b/mach/proto/ncg/regvar.c @@ -50,7 +50,19 @@ tryreg(rvlp,typ) register struct regvar *rvlp; { struct regvar *save; if (typ != reg_any && nregvar[typ]!=0) { - if (machregs[rvnumbers[typ][0]].r_size!=rvlp->rv_size) + struct reginfo *ri = &machregs[rvnumbers[typ][0]]; + int size, wrong; + + size = ri->r_size; + wrong = (size!=rvlp->rv_size); +#ifdef REGLAP + /* reg_float may have one subregister */ + if (wrong && ri->r_members[0]!=0) { + size = machregs[ri->r_members[0]].r_size; + wrong = (size!=rvlp->rv_size); + } +#endif /* REGLAP */ + if (wrong) score = -1; else score = regscore(rvlp->rv_off, @@ -99,11 +111,29 @@ fixregvars(saveall) { if (saveall) { struct reginfo *rp; rp= &machregs[rvnumbers[rvtyp][i]]; - regsave(codestrings[rp->r_repr],(long)-TEM_WSIZE,rp->r_size); + 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); + } +#endif } else if(regassigned[rvtyp][i].ra_score>0) { rv=regassigned[rvtyp][i].ra_rv; rv->rv_reg=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); + } +#endif regsave(codestrings[machregs[rv->rv_reg].r_repr], rv->rv_off,rv->rv_size); } diff --git a/util/ncgg/expr.c b/util/ncgg/expr.c index 77afe5774..0a6351590 100644 --- a/util/ncgg/expr.c +++ b/util/ncgg/expr.c @@ -18,6 +18,7 @@ static char rcsid[]= "$Id$"; #include "expr.h" #include "regvar.h" #include +#include #include "extern.h" extern set_t l_sets[]; @@ -276,12 +277,21 @@ expr_t iextoaddr(e) expr_t e; { expr_t regvar_expr(e,regtyp) expr_t e; { expr_t result; register i; - + result = make_expr(TYPREG,EX_REGVAR,i_expr(e),0); for(i=0;i=0); + /* + * Write .r_refcount = 1 for register variables or 0 + * for other registers. + * + * reglap: Write .r_refcount = 0 if the register + * variable has a subregister. + */ + fprintf(ctable,",%d", + l_regs[i].ri_rregvar>=0 && l_regs[i].ri_memb[0]==0); fprintf(ctable,"},\n"); } fprintf(ctable,"};\n\n short clashlist[] = {\n\t"); @@ -332,6 +340,8 @@ outregvars() { register i,j; fprintf(htable,"#define REGVARS\n"); + if (reglap!=0) + fprintf(htable,"#define REGLAP\n"); fprintf(ctable,"#include \"regvar.h\"\n"); fprintf(ctable,"int nregvar[4] = { "); for (i=0;i<4;i++) { diff --git a/util/ncgg/regvar.h b/util/ncgg/regvar.h index 7961d1eb9..9a772c0f6 100644 --- a/util/ncgg/regvar.h +++ b/util/ncgg/regvar.h @@ -9,6 +9,7 @@ #define DL_REGVAR 0x4 extern int rvused; +extern int reglap; extern int nregvar[4]; extern int rvsize[4]; extern int rvnumbers[4][MAXREGVAR]; diff --git a/util/ncgg/subr.c b/util/ncgg/subr.c index 08c7c650f..89b2b0917 100644 --- a/util/ncgg/subr.c +++ b/util/ncgg/subr.c @@ -19,6 +19,7 @@ static char rcsid[]= "$Id$"; #include "token.h" #include "regvar.h" #include +#include #include "extern.h" n_proc(name) char *name; { @@ -228,6 +229,70 @@ n_sconst(ident,val) char *ident,*val; { sy_p->sy_value.syv_stringno = strlookup(val); } +static void +add_regvar(int rvnum, reginfo *regp, int rv) +{ + int overlap, wrong; + + overlap = wrong = 0; + if (regp->ri_memb[0]!=0) { + /* reglap: float may overlap with one subregister */ + if (rv==reg_float && regp->ri_memb[1]==0) + overlap = 1; + else + wrong = 1; + } + if (wrong) + error("Register variables may not have subregisters"); + + rvused |= ANY_REGVAR; + if (regp->ri_size == wordsize) + rvused |= SL_REGVAR; + else if (regp->ri_size == 2*wordsize) + rvused |= DL_REGVAR; + + wrong = 0; + if (overlap) { + /* reglap = size of overlap float */ + if (reglap==0) + reglap = regp->ri_size; + else if (reglap!=regp->ri_size) + wrong = 1; + } else { + if (nregvar[rv]==0) + rvsize[rv] = regp->ri_size; + else if (rvsize[rv]!=regp->ri_size) + wrong = 1; + } + if (wrong) + error("All register variables of one type must have the same size"); + + if (overlap) { + reginfo *member_p = &l_regs[regp->ri_memb[0]]; + int i; + + /* + * reglap: Remove member_p from rvnumbers. + * Add reg_p in its place. + */ + wrong = 1; + for (i = 0; i < nregvar[rv]; i++) { + if (rvnumbers[rv][i] == regp->ri_memb[0]) { + rvnumbers[rv][i] = rvnum; + wrong = 0; + break; + } + } + if (wrong) + error("Register variable %s can't overlap %s", + regp->ri_name, member_p->ri_name); + } else { + NEXT(nregvar[rv],MAXREGVAR,"Register variable"); + rvnumbers[rv][nregvar[rv]-1] = rvnum; + } +} + +void regline(rl,pl,rv) varinfo *rl,*pl; { register varinfo *rrl,*rpl; register short *sp; @@ -251,21 +316,8 @@ regline(rl,pl,rv) varinfo *rl,*pl; { regp->ri_size = thissize; regp->ri_class = regclass; regp->ri_rregvar = rv; - if (rv>=0) { - if (regp->ri_memb[0]!=0) - error("Register variables may not have subregisters"); - rvused |= ANY_REGVAR; - if (regp->ri_size == wordsize) - rvused |= SL_REGVAR; - else if (regp->ri_size == 2*wordsize) - rvused |= DL_REGVAR; - if (nregvar[rv]==0) - rvsize[rv] = regp->ri_size; - else if (rvsize[rv]!=regp->ri_size) - error("All register variables of one type must have the same size"); - NEXT(nregvar[rv],MAXREGVAR,"Register variable"); - rvnumbers[rv][nregvar[rv]-1] = rrl->vi_int[0]; - } + if (rv>=0) + add_regvar(rrl->vi_int[0], regp, rv); } regclass++; } diff --git a/util/ncgg/var.c b/util/ncgg/var.c index 72a3f825d..19a4da4f3 100644 --- a/util/ncgg/var.c +++ b/util/ncgg/var.c @@ -39,6 +39,7 @@ int maxmembers=0; int regclass=1; int maxtokensize=0; int rvused=0; +int reglap=0; int nregvar[4]; int rvsize[4]; int rvnumbers[4][MAXREGVAR];