#ifndef NORCSID static char rcsid[] = "$Header$"; #endif #include "assert.h" #include "param.h" #include "tables.h" #include "types.h" #include <cgg_cg.h> #include "data.h" #include "result.h" #include "state.h" #include "equiv.h" #include "extern.h" /* * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands. * See the copyright notice in the ACK home directory, in the file "Copyright". * * Author: Hans van Staveren */ #define ALLOW_NEXTEM /* code generator is allowed new try of NEXTEM in exceptional cases */ #define MAXPATTERN 5 #define MAXREPLLEN 5 /* Max length of EM-replacement, should come from boot */ byte startupcode[] = { DO_NEXTEM }; byte *nextem(); unsigned costcalc(); unsigned docoerc(); unsigned stackupto(); string tostring(); string ad2str(); #ifdef NDEBUG #define DEBUG(string) #else #include <stdio.h> #define DEBUG(string) {if(Debug) fprintf(stderr,"%-*d%s\n",4*level,level,string);} #endif #define BROKE() {assert(origcp!=startupcode);DEBUG("BROKE");totalcost=INFINITY;goto doreturn;} #define CHKCOST() {if (totalcost>=costlimit) BROKE();} #ifdef TABLEDEBUG int tablelines[MAXTDBUG]; int ntableline; int set_fd,set_size; short *set_val; char *set_flag; #endif unsigned codegen(codep,ply,toplevel,costlimit,forced) byte *codep; unsigned costlimit; { #ifndef NDEBUG byte *origcp=codep; static int level=0; #endif unsigned totalcost = 0; int inscoerc=0; int procarg[2]; #ifdef ALLOW_NEXTEM int paniced; char *savebp; #endif state_t state; #define SAVEST savestatus(&state) #define RESTST restorestatus(&state) #define FREEST /* nothing */ #ifdef TABLEDEBUG extern char *tablename; #endif #ifndef NDEBUG level++; DEBUG("Entering codegen"); #endif for (;;) { switch( (*codep++)&037 ) { default: assert(FALSE); /* NOTREACHED */ #ifdef TABLEDEBUG case DO_DLINE: { int n; getint(n,codep); tablelines[ntableline++] = n; if (ntableline>=MAXTDBUG) ntableline -= MAXTDBUG; if (set_fd) set_val[n>>4] &= ~(1<<(n&017)); #ifndef NDEBUG if (Debug) fprintf(stderr,"code from \"%s\", line %d\n",tablename,n); #endif break; } #endif case DO_NEXTEM: { byte *bp; int n; unsigned mindistance,dist; register i; int cindex; int npos,pos[MAXRULE]; unsigned mincost,t; DEBUG("NEXTEM"); tokpatlen = 0; nallreg=0; if (toplevel) { garbage_collect(); totalcost=0; } else { if (--ply <= 0) goto doreturn; } if (stackheight>MAXFSTACK-7) { #ifndef NDEBUG if (Debug) fprintf(stderr,"Fakestack overflow threatens(%d), action ...\n",stackheight); #endif totalcost += stackupto(&fakestack[6],ply,toplevel); } #ifndef ALLOW_NEXTEM bp = nextem(toplevel); #else paniced=0; savebp = nextem(toplevel); panic: bp = savebp; #endif if (bp == 0) { /* * No pattern found, can be pseudo or error * in table. */ if (toplevel) { codep--; DEBUG("pseudo"); dopseudo(); } else goto doreturn; } else { #ifndef NDEBUG chkregs(); #endif n = *bp++; if (n==0) { /* "procedure" */ getint(i,bp); getint(procarg[0],bp); getint(procarg[1],bp); bp= &pattern[i]; n = *bp++; DEBUG("PROC_CALL"); } assert(n>0 && n<=MAXRULE); if (n>1) { mindistance = MAXINT; npos=0; for(i=0;i<n;i++) { getint(cindex,bp); dist=distance(cindex); #ifndef NDEBUG if (Debug) fprintf(stderr,"distance of pos %d is %u\n",i,dist); #endif if (dist<=mindistance) { if (dist<mindistance) { if(dist==0) goto gotit; npos=0; mindistance = dist; } pos[npos++] = cindex; } } assert(mindistance<MAXINT); if (npos>1) { /* * More than 1 tokenpattern is a candidate. * Decision has to be made by lookahead. */ SAVEST; mincost = costlimit-totalcost+1; for(i=0;i<npos;i++) { t=codegen(&coderules[pos[i]],ply,FALSE,mincost,0); #ifndef NDEBUG if (Debug) fprintf(stderr,"mincost %u,cost %u,pos %d\n",mincost,t,i); #endif if (t<mincost) { mincost = t; cindex = pos[i]; } RESTST; } FREEST; if (totalcost+mincost>costlimit) BROKE(); } else { cindex = pos[0]; } } else { getint(cindex,bp); } gotit: /* * Now cindex contains the code-index of the best candidate * so proceed to use it. */ codep = &coderules[cindex]; } break; } case DO_COERC: { DEBUG("COERC"); tokpatlen=1; inscoerc=1; break; } case DO_XXMATCH: DEBUG("XXMATCH"); case DO_XMATCH: { register i; int temp; DEBUG("XMATCH"); tokpatlen=(codep[-1]>>5)&07; for (i=0;i<tokpatlen;i++) getint(temp,codep); break; /* match already checked by distance() */ } case DO_MATCH: { register i; int j; unsigned mincost,t; token_p tp; int size,lsize; int tokexp[MAXPATTERN]; int nregneeded; token_p regtp[MAXCREG]; c3_p regcp[MAXCREG]; rl_p regls[MAXCREG]; c3_p cp,findcoerc(); int sret; int stackpad; struct perm *tup,*ntup,*besttup,*tuples(); DEBUG("MATCH"); tokpatlen=(codep[-1]>>5)&07; for(i=0;i<tokpatlen;i++) getint(tokexp[i],codep); tokexp[i] = 0; tp = &fakestack[stackheight-1]; i=0; while (i<tokpatlen && tp>=fakestack) { size=tsize(tp); while (i<tokpatlen && (lsize=ssize(tokexp[i]))<=size) { size -= lsize; i++; } if (i<tokpatlen && size!=0) { totalcost += stackupto(tp,ply,toplevel); CHKCOST(); break; } tp--; } tp = &fakestack[stackheight-1]; i=0; while (i<tokpatlen && tp >= fakestack) { size = tsize(tp); lsize= ssize(tokexp[i]); if (size != lsize) { /* find coercion */ #ifdef MAXSPLIT sret = split(tp,&tokexp[i],ply,toplevel); if (sret==0) { #endif MAXSPLIT totalcost += stackupto(tp,ply,toplevel); CHKCOST(); break; #ifdef MAXSPLIT } i += sret; #endif MAXSPLIT } else i += 1; tp--; } nextmatch: tp = &fakestack[stackheight-1]; i=0; nregneeded = 0; while (i<tokpatlen && tp>=fakestack) { if (!match(tp,&machsets[tokexp[i]],0)) { cp = findcoerc(tp, &machsets[tokexp[i]]); #ifndef NDEBUG if (Debug>1) fprintf(stderr,"findcoerc returns %d at position %d\n",cp,i); #endif if (cp==0) { for (j=0;j<nregneeded;j++) regtp[j] -= (tp-fakestack+1); totalcost += stackupto(tp,ply,toplevel); CHKCOST(); break; } else { if (cp->c3_prop<0) { totalcost+=docoerc(tp,cp,ply,toplevel,0); CHKCOST(); } else { #ifndef NDEBUG if(Debug>1) fprintf(stderr,"Register of type %d needed, remembering...\n",cp->c3_prop); #endif assert(nregneeded<MAXCREG); regtp[nregneeded] = tp; regcp[nregneeded] = cp; regls[nregneeded] = curreglist; nregneeded++; } } } i++; tp--; } if (tokpatlen>stackheight) { #ifndef NDEBUG if(Debug>1) fprintf(stderr,"Pattern too long, %d with only %d items on stack\n", tokpatlen,stackheight); #endif stackpad = tokpatlen-stackheight; for (j=stackheight-1;j>=0;j--) fakestack[j+stackpad] = fakestack[j]; for (j=0;j<stackpad;j++) fakestack[j].t_token=0; stackheight += stackpad; for (j=0;j<nregneeded;j++) regtp[j] += stackpad; for (tp = &fakestack[stackpad-1];i<tokpatlen && tp>=fakestack;i++,tp--) { cp = findcoerc((token_p) 0, &machsets[tokexp[i]]); if (cp==0) { for (j=0;j<nregneeded;j++) myfree(regls[j]); #ifndef ALLOW_NEXTEM assert(!toplevel); BROKE(); #else assert(!(toplevel&&paniced)); goto normalfailed; #endif } if (cp->c3_prop<0) { totalcost+=docoerc(tp,cp,ply,toplevel,0); CHKCOST(); } else { assert(nregneeded<MAXCREG); regtp[nregneeded] = tp; regcp[nregneeded] = cp; regls[nregneeded] = curreglist; nregneeded++; } } } else stackpad=0; assert(i==tokpatlen); if (nregneeded==0) break; SAVEST; mincost=costlimit-totalcost+1; tup = tuples(regls,nregneeded); besttup=0; for (; tup != 0; tup = ntup) { #ifndef NDEBUG if(Debug>1) fprintf(stderr,"Next tuple %d,%d,%d,%d\n", tup->p_rar[0], tup->p_rar[1], tup->p_rar[2], tup->p_rar[3]); #endif ntup = tup->p_next; for (i=0,t=0;i<nregneeded && t<mincost; i++) t += docoerc(regtp[i],regcp[i],ply,FALSE,tup->p_rar[i]); if ( t<mincost && tokpatlen<=stackheight ) { #ifndef NDEBUG if (Debug>2) fprintf(stderr,"Continuing match after coercions\n"); #endif t += codegen(codep,ply,FALSE,mincost-t,0); } if ( t<mincost && tokpatlen<=stackheight ) { mincost = t; besttup = tup; } else myfree(tup); RESTST; } FREEST; for (i=0;i<nregneeded;i++) myfree(regls[i]); if (totalcost+mincost>costlimit) { if (besttup) myfree(besttup); normalfailed: if (stackpad!=tokpatlen) { if (stackpad) { if (costlimit<MAXINT) BROKE(); for (i=0;i<stackheight-stackpad;i++) fakestack[i] = fakestack[i+stackpad]; stackheight -= stackpad; totalcost += stackupto(&fakestack[stackheight-1],ply,toplevel); } else totalcost += stackupto(fakestack,ply,toplevel); CHKCOST(); goto nextmatch; } totalcost += mincost; #ifndef ALLOW_NEXTEM BROKE(); #else if (toplevel && !paniced) { stackheight=0; paniced++; DEBUG("PANIC!"); goto panic; } else BROKE(); #endif } for (i=0;i<nregneeded;i++) totalcost += docoerc(regtp[i],regcp[i],ply,toplevel,besttup->p_rar[i]); myfree(besttup); break; } case DO_TOSTACK: case DO_REMOVE: { int texpno,nodeno; token_p tp; struct reginfo *rp; int doremove = (codep[-1] & 037) == DO_REMOVE; extern int allsetno; DEBUG("REMOVE"); if (codep[-1]&32) { getint(texpno,codep); getint(nodeno,codep); } else { getint(texpno,codep); nodeno=0; } if (texpno == allsetno) { totalcost += stackupto(&fakestack[stackheight-tokpatlen-1],ply,toplevel); CHKCOST(); if (doremove) for (rp=machregs;rp<machregs+NREGS;rp++) rp->r_contents.t_token=0; break; } for (tp= &fakestack[stackheight-tokpatlen-1];tp>=&fakestack[0];tp--) if (match(tp,&machsets[texpno],nodeno)) { /* investigate possible coercion to register */ totalcost += stackupto(tp,ply,toplevel); CHKCOST(); break; } if (doremove) for (rp=machregs;rp<machregs+NREGS;rp++) if (rp->r_contents.t_token != 0 && match(&rp->r_contents,&machsets[texpno],nodeno)) rp->r_contents.t_token=0; break; } case DO_RREMOVE: { /* register remove */ register i; int nodeno; token_p tp; tkdef_p tdp; result_t result; DEBUG("RREMOVE"); getint(nodeno,codep); result=compute(&enodes[nodeno]); if (result.e_typ!=EV_REG) break; if ( in_stack(result.e_v.e_reg) ) BROKE() ; /* Check aside-stack */ for (tp= &fakestack[stackheight-tokpatlen-1];tp>=&fakestack[0];tp--) if (tp->t_token==-1) { if(tp->t_att[0].ar==result.e_v.e_reg) goto gotone; } else { tdp = &tokens[tp->t_token]; for(i=0;i<TOKENSIZE;i++) if (tdp->t_type[i]==EV_REG && tp->t_att[i].ar==result.e_v.e_reg) goto gotone; } break; gotone: /* investigate possible coercion to register */ totalcost += stackupto(tp,ply,toplevel); CHKCOST(); break; } case DO_DEALLOCATE: { register i; tkdef_p tdp; int tinstno; token_t token; DEBUG("DEALLOCATE"); getint(tinstno,codep); instance(tinstno,&token); if (token.t_token==-1) chrefcount(token.t_att[0].ar,-1,TRUE); else { tdp= &tokens[token.t_token]; for (i=0;i<TOKENSIZE;i++) if (tdp->t_type[i]==EV_REG) chrefcount(token.t_att[i].ar,-1,TRUE); } break; } case DO_REALLOCATE: { struct reginfo *rp; DEBUG("REALLOCATE"); for(rp=machregs+1;rp<machregs+NREGS;rp++) if(rp->r_tcount) { rp->r_refcount -= rp->r_tcount; rp->r_tcount = 0; } break; } case DO_ALLOCATE: { register i; int j; int tinstno; int npos,npos2,pos[NREGS],pos2[NREGS]; unsigned mincost,t; struct reginfo *rp,**rpp; token_t token,mtoken,token2; int propno; int exactmatch; int decision; if (codep[-1]&32) { getint(propno,codep); getint(tinstno,codep); DEBUG("ALLOCATE,INIT"); } else { getint(propno,codep); tinstno=0; DEBUG("ALLOCATE,EMPTY"); } instance(tinstno,&token); if (!forced) { do { npos=exactmatch=0; for(rpp=reglist[propno];rp= *rpp; rpp++) if (getrefcount(rp-machregs)==0) { pos[npos++] = rp-machregs; if (eqtoken(&rp->r_contents,&token)) exactmatch++; } /* * Now pos[] contains all free registers with desired * property. If none then some stacking has to take place. */ if (npos==0) { if (stackheight<=tokpatlen) { if (!toplevel) { BROKE(); } else { if (paniced) fatal("No regs available"); totalcost += stackupto( &fakestack[0],ply,toplevel); goto panic; } } totalcost += stackupto( &fakestack[0],ply,toplevel); CHKCOST(); } } while (npos==0); if (!exactmatch) { npos2=npos; for(i=0;i<npos;i++) pos2[i]=pos[i]; } else { /* * Now we are reducing the number of possible registers. * We take only one equally likely register out of every * equivalence class as given by set of properties. */ mtoken = token; npos2=0; for(i=0;i<npos;i++) if (eqtoken(&machregs[pos[i]].r_contents,&mtoken)) { pos2[npos2++] = pos[i]; for(j=0;j<npos2-1;j++) if (eqregclass(pos2[j],pos[i])) { npos2--; break; } } } /* * Now pos2[] contains all possibilities to try, if more than * one, lookahead is necessary. */ token2.t_token= -1; for (i=1;i<TOKENSIZE;i++) token2.t_att[i].aw=0; if (npos2==1) decision=pos2[0]; else { SAVEST; mincost=costlimit-totalcost+1; for(j=0;j<npos2;j++) { chrefcount(pos2[j],1,FALSE); token2.t_att[0].ar=pos2[j]; allreg[nallreg++] = pos2[j]; if (token.t_token != 0) t=move(&token,&token2,ply,FALSE,mincost); else { t = 0; erasereg(pos2[j]); } if (t<mincost) t += codegen(codep,ply,FALSE,mincost-t,0); if (t<mincost) { mincost=t; decision=pos2[j]; } RESTST; } FREEST; if (totalcost+mincost>costlimit) BROKE(); } } else { decision = forced; if (getrefcount(decision)!=0) BROKE(); token2.t_token = -1; } chrefcount(decision,1,FALSE); token2.t_att[0].ar=decision; if (token.t_token != 0) { totalcost+=move(&token,&token2,ply,toplevel,MAXINT); CHKCOST(); } else erasereg(decision); allreg[nallreg++]=decision; break; } case DO_INSTR: { register i; int n; int tinstno; token_t token; int stringno; DEBUG("INSTR"); n=((codep[-1]>>5)&07); getint(stringno,codep); if (toplevel) { swtxt(); if (stringno>10000) { assert(stringno== 10001 || stringno== 10002); genstr(procarg[stringno-10001]); } else genstr(stringno); } for(i=0;i<n;i++) { getint(tinstno,codep); instance(tinstno,&token); if (toplevel) prtoken(&token,i==0 ? ' ' : ','); if (token.t_token>0) totalcost += tokens[token.t_token].t_cost.ct_space; } if (toplevel) gennl(); break; } case DO_MOVE: { int tinstno; token_t token,token2; DEBUG("MOVE"); getint(tinstno,codep); instance(tinstno,&token); getint(tinstno,codep); instance(tinstno,&token2); totalcost += move(&token,&token2,ply,toplevel,costlimit-totalcost+1); CHKCOST(); break; } case DO_TEST: { int tinstno; token_t token; DEBUG("TEST"); getint(tinstno,codep); instance(tinstno,&token); totalcost += test(&token,ply,toplevel,costlimit-totalcost+1); CHKCOST(); break; } case DO_SETCC: { int tinstno; token_t token; DEBUG("SETCC"); getint(tinstno,codep); instance(tinstno,&token); setcc(&token); break; } case DO_ERASE: { int nodeno; result_t result; DEBUG("ERASE"); getint(nodeno,codep); result=compute(&enodes[nodeno]); assert(result.e_typ!=EV_INT && result.e_typ!=EV_ADDR); if (result.e_typ==EV_REG) erasereg(result.e_v.e_reg); break; } case DO_TOKREPLACE: { register i; int tinstno; int repllen; token_t reptoken[MAXREPLLEN]; DEBUG("TOKREPLACE"); assert(stackheight>=tokpatlen); repllen=(codep[-1]>>5)&07; #ifndef NDEBUG if (Debug>2) fprintf(stderr,"Stackheight=%d, tokpatlen=%d, repllen=%d %s\n", stackheight,tokpatlen,repllen,inscoerc ? "(inscoerc)":""); #endif for(i=0;i<repllen;i++) { getint(tinstno,codep); instance(tinstno,&reptoken[i]); tref(&reptoken[i],1); } for(i=0;i<tokpatlen;i++) { if (!inscoerc) tref(&fakestack[stackheight-1],-1); stackheight--; } for (i=0;i<repllen;i++) { assert(stackheight<MAXFSTACK); fakestack[stackheight++] = reptoken[i]; } for(i=0;i<nallreg;i++) chrefcount(allreg[i],-1,FALSE); break; } case DO_EMREPLACE: { register i; int j; int nodeno; result_t result; int emrepllen,eminstr; DEBUG("EMREPLACE"); emrepllen=(codep[-1]>>5)&07; j=emp-emlines; if (emrepllen>j) { assert(nemlines+emrepllen-j<MAXEMLINES); for (i=nemlines;i>=0;i--) emlines[i+emrepllen-j] = emlines[i]; nemlines += emrepllen-j; emp += emrepllen-j; } emp -= emrepllen; for (i=0;i<emrepllen;i++) { getint(eminstr,codep); getint(nodeno,codep); emp[i].em_instr = eminstr; result = compute(&enodes[nodeno]); switch(result.e_typ) { default: assert(FALSE); case 0: emp[i].em_optyp = OPNO; emp[i].em_soper = 0; break; case EV_INT: emp[i].em_optyp = OPINT; emp[i].em_soper = tostring(result.e_v.e_con); emp[i].em_u.em_ioper = result.e_v.e_con; break; case EV_ADDR: emp[i].em_optyp = OPSYMBOL; emp[i].em_soper = ad2str(result.e_v.e_addr); break; } } if (!toplevel) ply += emrepllen; break; } case DO_COST: { cost_t cost; DEBUG("COST"); getint(cost.ct_space,codep); getint(cost.ct_time,codep); totalcost += costcalc(cost); CHKCOST(); break; } #ifdef REGVARS case DO_PRETURN: { if (toplevel) { swtxt(); regreturn(); /* in mach.c */ } break; } #endif case DO_RETURN: DEBUG("RETURN"); assert(origcp!=startupcode); doreturn: #ifndef NDEBUG level--; #endif return(totalcost); } } } readcodebytes() { #ifndef CODEINC register fd; extern int ncodebytes; if ((fd=open("code",0))<0) { error("Can't open code"); } if (read(fd,coderules,ncodebytes)!=ncodebytes) { error("Short read from code"); } close(fd); #endif } #ifdef TABLEDEBUG initlset(f) char *f; { extern char *myalloc(); set_flag = f; if ((set_fd=open(f+1,2))<0) error("Can't open %s rw",f+1); read(set_fd,&set_size,sizeof(int)); set_val=( short *) myalloc(set_size); read(set_fd,set_val,set_size); } termlset() { if (set_fd) { lseek(set_fd,(long) sizeof(int),0); write(set_fd,set_val,set_size); close(set_fd); if (set_flag[0]=='u') { register i; fprintf(stderr,"Unused code rules:\n\n"); for(i=0;i<8*set_size;i++) if(set_val[i>>4]&(1<<(i&017))) fprintf(stderr,"\"%s\", line %d\n",tablename,i); } } } #endif