| /* $VER: vbcc (regs.c) $Revision: 1.31 $ */ |
| /* Registerzuteilung */ |
| |
| #include "opt.h" |
| |
| static char FILE_[]=__FILE__; |
| |
| typedef struct regp {int treg;Var *tvar,*tmp;} regp; |
| int sregsa[MAXR+1]; |
| |
| void do_load_parms(regp [],flowgraph *); |
| void load_one_parm(int,int,Var *,Var *,flowgraph *); |
| |
| #ifndef NO_OPTIMIZER |
| |
| int (*savings)[MAXR+1],regu[MAXR+1]; |
| int *rvlist; |
| |
| static int const_vars; |
| |
| static bvtype bregs[BVSIZE(MAXR+1)/sizeof(bvtype)]; |
| static bvtype bregsm[BVSIZE(MAXR+1)/sizeof(bvtype)]; |
| |
| Var *lparms[MAXR+1]; |
| |
| static void insert_cobj(obj *o,obj *co); |
| |
| #ifndef HAVE_TARGET_RALLOC |
| int reg_prio[MAXR+1]; |
| #define cost_move_reg(x,y) 1 |
| #define cost_load_reg(x,y) 2 |
| #define cost_save_reg(x,y) 2 |
| #define cost_pushpop_reg(x) 4 |
| |
| int cost_savings(IC *p,int r,obj *o) |
| { |
| int c=p->code; |
| if(o->flags&VKONST) return 0; |
| if(o->flags&DREFOBJ){ |
| int t; |
| if(o==&p->q1){ |
| t=q1typ(p); |
| }else if(o==&p->q2){ |
| t=q2typ(p); |
| }else{ |
| t=ztyp(p); |
| } |
| if(regok(r,o->v->vtyp->flags,t)) return 4; |
| } |
| if(c==SETRETURN&&r==p->z.reg&&!(o->flags&DREFOBJ)) return 3; |
| if(c==GETRETURN&&r==p->q1.reg&&!(o->flags&DREFOBJ)) return 3; |
| return 2; |
| } |
| #endif |
| |
| int cmp_savings(const void *v1,const void *v2) |
| /* Vergleichsfkt, um rvlist nach savings zu sortieren */ |
| { |
| return savings[*(int *)v2][0]-savings[*(int *)v1][0]; |
| } |
| int entry_load(flowgraph *fg,int i) |
| /* Testet, ob die Variable in Register i am Anfang von Block fg geladen */ |
| /* werden muss, d.h. ein Vorgaenger sie nicht im selben Register hat. */ |
| { |
| flowlist *lp; |
| Var *v=fg->regv[i]; |
| int vi=v->index; |
| lp=fg->in; |
| |
| while(lp){ |
| if(lp->graph&&lp->graph->regv[i]!=v&&(vi>=vcount-rcount||BTST(lp->graph->av_out,vi))) return 1; |
| lp=lp->next; |
| } |
| return 0; |
| } |
| |
| /* checks if variable i can be held in a register in loop start-end */ |
| /* currently we check whether an IC uses/modifies the variable and */ |
| /* has a corresponding drefobj which might alias the variable */ |
| int check_cacheable(int i,flowgraph *start,flowgraph *end) |
| { |
| int j,k; |
| IC *p;Var *v; |
| flowgraph *g; |
| /* constants are always cacheable */ |
| if(vilist[i]->identifier[0]==' ') |
| return 1; |
| if(i<vcount-rcount){ |
| /* simple local variables are also easy */ |
| v=vilist[i]; |
| if(v->storage_class!=STATIC&&v->storage_class!=EXTERN&&!(v->flags&USEDASADR)) |
| return 1; |
| } |
| if(disable&16384) return 0; |
| for(g=start;g;g=g->normalout){ |
| for(p=g->start;p;p=p->next){ |
| for(j=0;j<p->use_cnt;j++){ |
| k=p->use_list[j].v->index; |
| if(p->use_list[j].flags&DREFOBJ) |
| k+=vcount-rcount; |
| if(k==i&&(p->code==CALL||(p->q1.flags&DREFOBJ)||(p->q2.flags&DREFOBJ))) |
| return 0; |
| } |
| for(j=0;j<p->change_cnt;j++){ |
| k=p->change_list[j].v->index; |
| if(p->change_list[j].flags&DREFOBJ) |
| k+=vcount-rcount; |
| if(k==i&&(p->code==CALL||(p->z.flags&DREFOBJ))) |
| return 0; |
| } |
| if(p==g->end) break; |
| } |
| if(g==end) break; |
| } |
| /*printf("assigned static %s to reg\n",vilist[i]->identifier);*/ |
| return 1; |
| } |
| int exit_save(flowgraph *fg,int i) |
| /* Testet, ob die Variable in Register i am Ende von Block fg gespeichert */ |
| /* werden muss, d.h. der Vorgaenger eines Nachfolgers nicht dieselbe */ |
| /* Variable im selben Register hat. */ |
| { |
| flowlist *lp; |
| /* Konstanten muessen nie gespeichert werden */ |
| if(fg->regv[i]->index>=vcount-rcount) return 0; |
| if(!fg->normalout){ |
| /* letzter Block, statische Variablen und drefobjs aktiv */ |
| int sc=fg->regv[i]->storage_class; |
| return sc==STATIC||sc==EXTERN; |
| } |
| if((fg->normalout&&(!fg->end||fg->end->code!=BRA))&&BTST(fg->normalout->av_in,fg->regv[i]->index)){ |
| if(fg->normalout->regv[i]!=fg->regv[i]) return 1; |
| lp=fg->normalout->in; |
| while(lp){ |
| if(lp->graph&&lp->graph->regv[i]!=fg->regv[i]) return 1; |
| lp=lp->next; |
| } |
| } |
| if(fg->branchout&&BTST(fg->branchout->av_in,fg->regv[i]->index)){ |
| if(fg->branchout->regv[i]!=fg->regv[i]) return 1; |
| lp=fg->branchout->in; |
| while(lp){ |
| if(lp->graph&&lp->graph->regv[i]!=fg->regv[i]) return 1; |
| lp=lp->next; |
| } |
| } |
| return 0; |
| } |
| void load_reg_parms(flowgraph *fg) |
| /* Laedt Registerparameter, falls noetig. */ |
| { |
| int i,j; Var *v; |
| regp regp[MAXR+1]={0}; |
| /* for(i=1;i<=MAXR;i++){ regp[i].treg=0;regp[i].tvar=0;} */ |
| for(i=0;i<vcount-rcount;i++){ |
| v=vilist[i]; |
| if((v->flags®PARM)&&(fg->regv[abs(v->reg)]!=v||(v->flags&CONVPARAMETER))&&(BTST(fg->av_in,i)||(v->flags&USEDASADR))){ |
| regp[abs(v->reg)].tvar=v; |
| for(j=1;j<=MAXR;j++) |
| if(fg->regv[j]==v||lparms[j]==v) regp[abs(v->reg)].treg=j; |
| } |
| } |
| do_load_parms(regp,fg); |
| } |
| |
| static int check_retreg(flowgraph *fg) |
| { |
| IC *p;int retreg=0; |
| for(p=fg->start;p;p=p->next){ |
| if(p->code==SETRETURN&&p->z.reg>=0){ |
| retreg=p->z.reg; |
| break; |
| } |
| } |
| for(p=last_ic;retreg&&p;p=p->prev){ |
| if(p->code==FREEREG){ |
| if(p->q1.reg==retreg) |
| retreg=0; |
| }else |
| break; |
| } |
| if(DEBUG&1024) printf("check_retreg: %s\n",regnames[retreg]); |
| return retreg; |
| } |
| void insert_regs(flowgraph *fg1) |
| /* Fuegt Registervariablen in die ICs ein. */ |
| { |
| int i,exit_block;IC *p,*lic=0,*new;flowgraph *lfg=0,*fg; |
| if(DEBUG&9216) printf("inserting register variables\n"); |
| fg=fg1; |
| while(fg){ |
| if(DEBUG&8192) printf("block %d:\n",fg->index); |
| if(fg!=fg1&&!fg->branchout&&!fg->normalout&&fg->start==fg->end) |
| exit_block=1; |
| else |
| exit_block=0; |
| p=fg->start; |
| while(p){ |
| for(i=1;i<=MAXR;i++){ |
| if(!fg->regv[i]) continue; |
| if(p->code==ALLOCREG&&p->q1.reg==i) ierror(0); |
| if((p->q1.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->q1.v==fg->regv[i]&&(p->q1.v->index<vcount-rcount||cost_savings(p,i,&p->q1)>0)){ |
| if(p->q1.v->index>=vcount-rcount) |
| p->q1.flags&=~(KONST|VAR|VARADR); |
| p->q1.flags|=REG; |
| p->q1.reg=i; |
| } |
| if((p->q2.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->q2.v==fg->regv[i]&&(p->q2.v->index<vcount-rcount||cost_savings(p,i,&p->q2)>0)){ |
| if(p->q2.v->index>=vcount-rcount) |
| p->q2.flags&=~(KONST|VAR|VARADR); |
| p->q2.flags|=REG; |
| p->q2.reg=i; |
| } |
| if((p->z.flags&(VAR|REG|DONTREGISTERIZE))==VAR&&p->z.v==fg->regv[i]&&(p->z.v->index<vcount-rcount||cost_savings(p,i,&p->z)>0)){ |
| if(p->z.v->index>=vcount-rcount) |
| p->z.flags&=~(KONST|VAR|VARADR); |
| p->z.flags|=REG; |
| p->z.reg=i; |
| } |
| } |
| /* evtl. const-Variablen ruecksubstituieren */ |
| if((p->q1.flags&VAR)&&p->q1.v->index>=vcount-rcount){ |
| insert_cobj(&p->q1,&p->q1.v->cobj); |
| } |
| if((p->q2.flags&VAR)&&p->q2.v->index>=vcount-rcount){ |
| insert_cobj(&p->q2,&p->q2.v->cobj); |
| } |
| if((p->z.flags&VAR)&&p->z.v->index>=vcount-rcount){ |
| insert_cobj(&p->z,&p->z.v->cobj); |
| } |
| if(DEBUG&8192) pric2(stdout,p); |
| if(p==fg->end) break; |
| p=p->next; |
| } |
| if(fg->start&&fg->start->code==LABEL&&fg!=fg1) lic=fg->start; |
| for(i=1;i<=MAXR;i++){ |
| if(fg->regv[i]){ |
| if(DEBUG&8192){ |
| printf("(%s),%ld(%p) assigned to %s\n",fg->regv[i]->identifier,zm2l(fg->regv[i]->offset),(void *)fg->regv[i],regnames[i]); |
| if(fg->regv[i]->index>=vcount-rcount||BTST(fg->av_in,fg->regv[i]->index)) printf("active at the start of block\n"); |
| if(fg->regv[i]->index<vcount-rcount&&BTST(fg->av_out,fg->regv[i]->index)) printf("active at the end of block\n"); |
| } |
| |
| if(fg->regv[i]->index<vcount-rcount&&BTST(fg->av_out,fg->regv[i]->index)){ |
| /* Variable beim Austritt aktiv? */ |
| if(exit_save(fg,i)){ |
| IC *tp;int mark_retreg=0; |
| if(DEBUG&8192) printf("\thave to save it at end of block\n"); |
| new=new_IC(); |
| new->line=0; |
| new->file=0; |
| new->code=ASSIGN; |
| new->typf=fg->regv[i]->vtyp->flags; |
| /* vla */ |
| if(ISARRAY(new->typf)) |
| new->typf=POINTER_TYPE(fg->regv[i]->vtyp->next); |
| /* cc */ |
| if(new->typf==0) ierror(0); |
| new->q1.flags=VAR|REG; |
| new->q1.val.vmax=l2zm(0L); |
| new->q1.v=fg->regv[i]; |
| new->q1.reg=i; |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(fg->regv[i]->vtyp); |
| new->z.flags=VAR|DONTREGISTERIZE; |
| new->z.val.vmax=l2zm(0L); |
| new->z.v=fg->regv[i]; |
| new->q1.am=new->q2.am=new->z.am=0; |
| new->use_cnt=new->change_cnt=0; |
| new->use_list=new->change_list=0; |
| /* Vor FREEREGs und evtl. Branch+COMPARE/TEST setzen */ |
| if(fg->end){ |
| tp=fg->end; |
| if(!tp->next){ |
| mark_retreg=check_retreg(fg1); |
| if(DEBUG&1024) printf("save at end, markretreg=%s\n",regnames[mark_retreg]); |
| } |
| while(tp!=fg->start&&(tp->code==FREEREG||tp->code==SETRETURN||tp->code==NOP)){ |
| if(tp->code==SETRETURN) mark_retreg=0; |
| tp=tp->prev; |
| } |
| if(tp&&tp->code>=BEQ&&tp->code<=BRA){ |
| if(tp->code<BRA){ |
| int c; |
| do{ |
| tp=tp->prev; |
| c=tp->code; |
| if(c!=FREEREG&&c!=COMPARE&&c!=TEST) ierror(0); |
| }while(c!=COMPARE&&c!=TEST); |
| } |
| tp=tp->prev; |
| } |
| }else tp=lic; |
| insert_IC_fg(fg,tp,new); |
| if(mark_retreg){ |
| IC *nop; |
| insert_allocreg(fg,tp,ALLOCREG,mark_retreg); |
| insert_allocreg(fg,new,FREEREG,mark_retreg); |
| nop=new_IC(); |
| nop->code=NOP; |
| nop->q1.flags=REG; |
| nop->q1.reg=mark_retreg; |
| insert_IC_fg(fg,new,nop); |
| } |
| } |
| } |
| if(fg->regv[i]->index>=vcount-rcount||BTST(fg->av_in,fg->regv[i]->index)){ |
| if(!exit_block&&(fg==fg1||entry_load(fg,i))&&(fg!=fg1||!(fg->regv[i]->flags®PARM))){ |
| if(DEBUG&8192) printf("\thave to load it at start of block\n"); |
| new=new_IC(); |
| new->line=0; |
| new->file=0; |
| new->code=ASSIGN; |
| new->typf=fg->regv[i]->vtyp->flags; |
| /* vla */ |
| if(ISARRAY(new->typf)) |
| new->typf=POINTER_TYPE(fg->regv[i]->vtyp->next); |
| /* cc */ |
| if(new->typf==0) ierror(0); |
| if(fg->regv[i]->index>=vcount-rcount){ |
| insert_cobj(&new->q1,&fg->regv[i]->cobj); |
| }else{ |
| new->q1.flags=VAR|DONTREGISTERIZE; |
| new->q1.val.vmax=l2zm(0L); |
| new->q1.v=fg->regv[i]; |
| } |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(fg->regv[i]->vtyp); |
| if(fg->regv[i]->index>=vcount-rcount) |
| new->z.flags=REG; |
| else |
| new->z.flags=VAR|REG; |
| new->z.val.vmax=l2zm(0L); |
| new->z.v=fg->regv[i]; |
| new->z.reg=i; |
| new->q1.am=new->q2.am=new->z.am=0; |
| new->use_cnt=new->change_cnt=0; |
| new->use_list=new->change_list=0; |
| insert_IC_fg(fg,lic,new); |
| } |
| } |
| if(!lfg||!lfg->regv[i]) insert_allocreg(fg,lic,ALLOCREG,i); |
| if(!fg->normalout||!fg->normalout->regv[i]) |
| insert_allocreg(fg,fg->end?fg->end:lic,FREEREG,i); |
| } |
| } |
| if(fg->end) lic=fg->end; |
| lfg=fg; |
| fg=fg->normalout; |
| } |
| load_reg_parms(fg1); |
| } |
| |
| void do_loop_regs(flowgraph *start,flowgraph *end,int intask) |
| /* Macht die Variablenzuweisung in Schleife start-end. */ |
| /* Wenn end==0 Registerzuweisung fuer die ganze Funktion, ansonsten */ |
| /* fuer die Schleife, die zum Header start gehoert. */ |
| { |
| flowgraph *g,*lend; |
| int i,r,iterations; |
| Var *lregs[MAXR+1]={0}; |
| unsigned char regu[MAXR+1]={0}; |
| bvtype *isused=mymalloc(vsize); |
| /* Berechnen, wieviel ungefaehr eingespart wird, wenn eine Variable */ |
| /* fuer diese Schleife in einem best. Register gehalten wird. */ |
| /* Die savings in einer Schleife werden multipliziert, um das */ |
| /* Laden/Speichern ausserhalb der Schleife geringer zu wichten. */ |
| /* if(end&&(!g->normalout||!g->normalout->loopend||g->normalout->loopend->normalout->index!=-2)) ierror(0);*/ |
| /* alle auf 0 */ |
| |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| if(i<vcount-rcount&&(vilist[i]->vtyp->flags&VOLATILE)){ |
| for(r=1;r<=MAXR;r++){ |
| savings[i][r]=INT_MIN; |
| } |
| }else{ |
| for(r=1;r<=MAXR;r++){ |
| savings[i][r]=0; |
| } |
| } |
| } |
| if(end){ |
| Var *v; |
| /* estimated number of iterations, avoid too big values */ |
| if(optsize) |
| iterations=1; |
| else |
| iterations=4; |
| /* Evtl. Kosten fuers Laden/Speichern beim Ein-/Austritt in die */ |
| /* Schleife. */ |
| end=start->normalout->loopend; |
| g=end->normalout; |
| if(DEBUG&9216) printf("assigning regs to blocks %d to %d\n",start->normalout->index,end->index); |
| /* Werte modifizieren, falls Variable am Anfang/Ende der Schleife */ |
| /* geladen/gespeichert werden muss. */ |
| /* FIXME: Evtl. noetige stores/loads in anderen Bloecken! */ |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| v=vilist[i]; |
| if(i>=vcount-rcount||BTST(start->av_in,i)){ |
| for(r=1;r<=MAXR;r++) |
| if(start->regv[r]!=v&&savings[i][r]!=INT_MIN) |
| savings[i][r]-=cost_load_reg(r,v); |
| } |
| if(i<vcount-rcount&&BTST(g->av_out,i)){ |
| for(r=1;r<=MAXR;r++) |
| if(g->regv[r]!=v&&savings[i][r]!=INT_MIN) |
| savings[i][r]-=cost_save_reg(r,v); |
| } |
| } |
| /* Werte modifizieren, falls eine andere Variable gespeichert oder */ |
| /* geladen werden muss. Hmm..stimmt das so? */ |
| for(r=1;r<=MAXR;r++){ |
| v=start->regv[r]; |
| if(v&&v->index<vcount-rcount&&BTST(start->av_in,v->index)){ |
| for(i=0;i<vcount-rcount;i++) |
| if(v->index!=i&&savings[i][r]!=INT_MIN) |
| savings[i][r]-=cost_load_reg(r,vilist[i]); |
| } |
| if(v&&v->index<vcount-rcount&&BTST(g->av_out,v->index)){ |
| for(i=0;i<vcount-rcount;i++) |
| if(v->index!=i&&savings[i][r]!=INT_MIN) |
| savings[i][r]-=cost_save_reg(r,vilist[i]); |
| } |
| } |
| g=start->normalout; |
| }else{ |
| iterations=1; |
| /* Bei Registervergabe fuer die ganze Funktion muessen alle beim */ |
| /* Eintritt der Funktion aktiven Variablen geladen werden. */ |
| /* statics have to be saved at the end */ |
| if(DEBUG&9216) printf("assigning regs to whole function\n"); |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| if(i<vcount-rcount&&(vilist[i]->storage_class==STATIC||vilist[i]->storage_class==EXTERN)){ |
| for(r=1;r<=MAXR;r++) |
| if(savings[i][r]!=INT_MIN) |
| savings[i][r]-=cost_save_reg(r,vilist[i]); |
| } |
| if(i>=vcount-rcount||BTST(start->av_in,i)){ |
| int pr=abs(vilist[i]->reg); |
| for(r=1;r<=MAXR;r++){ |
| if(savings[i][r]!=INT_MIN){ |
| if(pr==0){ |
| savings[i][r]-=cost_load_reg(r,vilist[i]); |
| }else if(!regsa[r]){ |
| if(r==pr) |
| savings[i][r]+=cost_save_reg(r,vilist[i]); |
| else |
| /* factor of 2, because load_parms is not always optimal */ |
| savings[i][r]+=(cost_save_reg(r,vilist[i])-cost_move_reg(pr,r))/2; |
| } |
| } |
| } |
| } |
| } |
| /* Nonscratchregister muessen geladen/gesichert werden. */ |
| /*FIXME: einige unschoene Effekte(?) */ |
| if(!intask){ |
| for(r=1;r<=MAXR;r++){ |
| if(!regscratch[r]&&!regsa[r]){ |
| for(i=0;i<vcount-rcount+const_vars;i++) |
| if(savings[i][r]!=INT_MIN) |
| savings[i][r]-=cost_pushpop_reg(r); |
| } |
| } |
| } |
| g=start; |
| } |
| if(DEBUG&9216) printf("calculating approximate savings\n"); |
| |
| lend=0; |
| for(;g;g=g->normalout){ |
| IC *p;Var *v; |
| int t,vt; |
| if(!end&&!lend){ |
| lend=g->loopend; |
| if(lend&&iterations==1&&!optsize) iterations=4; |
| } |
| |
| /* Wenn das Register in dem Block benutzt wird, muss man es retten */ |
| for(r=1;r<=MAXR;r++){ |
| if(BTST(g->regused,r)||(reg_pair(r,&rp)&&(BTST(g->regused,rp.r1)||BTST(g->regused,rp.r2)))){ |
| int vi; |
| if(g->regv[r]) vi=g->regv[r]->index; else vi=-1; |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| if(i>=vcount-rcount||BTST(g->av_out,i)||BTST(g->av_gen,i)) |
| if(vi!=i&&savings[i][r]!=INT_MIN) |
| savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i])); |
| } |
| } |
| } |
| memcpy(isused,g->av_out,vsize); |
| p=g->end; |
| while(p){ |
| if((p->q1.flags&(VAR|VARADR|REG))==VAR){ |
| v=p->q1.v;vt=v->vtyp->flags; |
| /* vla */ |
| if(ISARRAY(vt)&&is_vlength(v->vtyp)) |
| vt=POINTER_TYPE(v->vtyp->next); |
| if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){ |
| i=v->index; |
| if(p->code==ADDRESS||((p->code==ASSIGN||p->code==PUSH)&&(q1typ(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L)))){ |
| for(r=1;r<=MAXR;r++) |
| savings[i][r]=INT_MIN; |
| }else{ |
| for(r=1;r<=MAXR;r++){ |
| if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&®ok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){ |
| int s=cost_savings(p,r,&p->q1); |
| if(s==INT_MIN||savings[i][r]==INT_MIN) |
| savings[i][r]=INT_MIN; |
| else |
| savings[i][r]+=iterations*s; |
| } |
| } |
| } |
| } |
| } |
| if((p->q2.flags&(VAR|VARADR|REG))==VAR){ |
| v=p->q2.v;vt=v->vtyp->flags; |
| /* vla */ |
| if(ISARRAY(vt)&&is_vlength(v->vtyp)) |
| vt=POINTER_TYPE(v->vtyp->next); |
| if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){ |
| i=v->index; |
| for(r=1;r<=MAXR;r++){ |
| if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&®ok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){ |
| int s=cost_savings(p,r,&p->q2); |
| if(s==INT_MIN||savings[i][r]==INT_MIN) |
| savings[i][r]=INT_MIN; |
| else |
| savings[i][r]+=iterations*s; |
| } |
| } |
| } |
| } |
| if((p->z.flags&(VAR|VARADR|REG))==VAR){ |
| v=p->z.v;vt=v->vtyp->flags; |
| if(ISARRAY(vt)&&is_vlength(v->vtyp)) |
| vt=POINTER_TYPE(v->vtyp->next); |
| if((optflags&1024)||((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR))){ |
| i=v->index; |
| if(p->code==ASSIGN&&(ztyp(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L))){ |
| for(r=1;r<=MAXR;r++) |
| savings[i][r]=INT_MIN; |
| } |
| for(r=1;r<=MAXR;r++){ |
| if(!regsa[r]&&!BTST(g->regused,r)&&savings[i][r]!=INT_MIN&®ok(r,vt,-1)&&(!reg_pair(r,&rp)||(!regsa[rp.r1]&&!regsa[rp.r2]&&!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){ |
| int s=cost_savings(p,r,&p->z); |
| if(s==INT_MIN||savings[i][r]==INT_MIN) |
| savings[i][r]=INT_MIN; |
| else |
| savings[i][r]+=iterations*s; |
| } |
| } |
| } |
| } |
| /* bei Funktionsaufruf zerstoert... */ |
| if(p->code==CALL){ |
| if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){ |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| if(i>=vcount-rcount||BTST(isused,i)){ |
| for(r=1;r<=MAXR;r++){ |
| if(regscratch[r]&&savings[i][r]!=INT_MIN&&BTST(p->q1.v->fi->regs_modified,r)) |
| savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i])); |
| } |
| } |
| } |
| }else{ |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| if(i>=vcount-rcount||BTST(isused,i)){ |
| for(r=1;r<=MAXR;r++){ |
| if(regscratch[r]&&savings[i][r]!=INT_MIN) |
| savings[i][r]-=iterations*(cost_load_reg(r,vilist[i])+cost_save_reg(r,vilist[i])); |
| } |
| } |
| } |
| } |
| } |
| if(p==g->start) break; |
| if(p->change_cnt!=0||p->use_cnt!=0) |
| av_update(p,isused); |
| p=p->prev; |
| } |
| if(g==end) break; |
| if(!end){ |
| if(g==lend) {lend=0;iterations=1;} |
| } |
| } |
| /* Maximum ermitteln */ |
| memset(bregs,0,sizeof(bregs)); |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| int m=0,t;Var *v; |
| v=vilist[i];t=v->vtyp->flags; |
| if(ISARRAY(t)&&is_vlength(v->vtyp)) |
| t=POINTER_TYPE(v->vtyp->next); |
| if(!(optflags&1024)&&((v->storage_class!=AUTO&&v->storage_class!=REGISTER)||(v->flags&USEDASADR))){ |
| for(r=0;r<=MAXR;r++) |
| savings[i][r]=INT_MIN; |
| }else{ |
| int one=0; |
| for(r=1;r<=MAXR;r++){ |
| /* Variables should have been put to argument registers by local_regs() */ |
| /*if(r==abs(v->reg)&&!(v->flags®PARM)) savings[i][r]=INT_MAX;*/ |
| if(regsa[r]||!regok(r,t,-1)) savings[i][r]=INT_MIN; |
| if(savings[i][r]>m){ |
| m=savings[i][r]; |
| one=r; |
| }else if(savings[i][r]==m){ |
| one=0; |
| } |
| } |
| savings[i][0]=m; |
| if(one) BSET(bregs,one); /* mark one register has unique value */ |
| } |
| } |
| if(DEBUG&8192){ |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| printf("(%s),%ld(best=%d):\n",vilist[i]->identifier,zm2l(vilist[i]->offset),savings[i][0]); |
| for(r=1;r<=MAXR;r++) |
| printf("%s=%d ",regnames[r],savings[i][r]); |
| printf("\n"); |
| } |
| for(r=0;r<=MAXR;r++) |
| if(BTST(bregs,r)) |
| printf("reg %s unique\n",regnames[r]); |
| } |
| /* Suchen, welche Variablen/Registerkombination das beste Ergebnis */ |
| /* liefert. Nur angenaehert, da sonst wohl zu aufwendig. Simplex? */ |
| for(i=0;i<vcount-rcount+const_vars;i++) rvlist[i]=i; |
| vqsort(rvlist,vcount-rcount+const_vars,sizeof(*rvlist),cmp_savings); |
| for(i=0;i<vcount-rcount+const_vars;i++){ |
| int use=0,m=0,prio=0,vi; |
| vi=rvlist[i]; |
| /*if(vilist[vi]->flags&USEDASADR) continue;*/ |
| if(DEBUG&8192) printf("%d: (%s),%ld(best=%d)\n",i,vilist[vi]->identifier,zm2l(vilist[vi]->offset),savings[vi][0]); |
| for(r=1;r<=MAXR;r++){ |
| if(!lregs[r]&&!regu[r]&&savings[vi][r]>=m&&(!reg_pair(r,&rp)||(!regu[rp.r1]&&!regu[rp.r2]))){ |
| int better=0; |
| if(savings[vi][r]>m){ |
| better=1; |
| }else if(savings[vi][r]==m){ |
| if(reg_prio[r]>prio){ |
| better=1; |
| }else if(BTST(bregs,use)&&!BTST(bregs,r)){ |
| better=1; |
| } |
| } |
| if(better){ |
| m=savings[vi][r];prio=reg_prio[r]; |
| use=r; |
| } |
| } |
| } |
| if(m>0&&check_cacheable(vi,start,end)){ |
| if(DEBUG&9216) printf("assigned (%s),%ld(%p) to %s, saving=%d\n",vilist[vi]->identifier,zm2l(vilist[vi]->offset),(void *)vilist[vi],regnames[use],m); |
| lregs[use]=vilist[vi]; |
| regu[use]=1; |
| if(reg_pair(use,&rp)) |
| regu[rp.r1]=regu[rp.r2]=1; |
| } |
| } |
| /* Registervariablen in alle Bloecke der Schleife eintragen */ |
| /* dabei beruecksichtigen, dass sie in manchen Bloecken nicht */ |
| /* in Register kommen koennen, wenn das Register da schon von */ |
| /* local_regs benutzt wird */ |
| /* Gegebenenfalls auch in Header/Footer einer Schleife */ |
| /* eintragen. */ |
| if(DEBUG&9216) printf("propagate register vars\n"); |
| for(g=start;g;g=g->normalout){ |
| for(r=1;r<=MAXR;r++){ |
| if(lregs[r]&&!BTST(g->regused,r)&&(!reg_pair(r,&rp)||(!BTST(g->regused,rp.r1)&&!BTST(g->regused,rp.r2)))){ |
| /* Falls Variable schon in anderem Register, loeschen */ |
| for(i=1;i<=MAXR;i++){ |
| if(g->regv[i]==lregs[r]) g->regv[i]=0; |
| if(reg_pair(i,&rp)){ |
| if(rp.r1==r||rp.r2==r) g->regv[i]=0; |
| } |
| } |
| g->regv[r]=lregs[r]; |
| if(reg_pair(r,&rp)) g->regv[rp.r1]=g->regv[rp.r2]=0; |
| } |
| } |
| if(end&&g==end->normalout) break; |
| } |
| } |
| void block_regs(flowgraph *fg) |
| /* macht die Variablenzuweisung fuer einzelne Bloecke */ |
| { |
| flowgraph *g,**fgp; |
| int i,r,changed,fgz; |
| if(DEBUG&9216) printf("block_regs\n"); |
| |
| savings=mymalloc((vcount-rcount)*sizeof(*savings)); |
| rvlist=mymalloc((vcount-rcount)*sizeof(*rvlist)); |
| |
| /* Array auf Bloecke im Flussgraphen mangels doppelter Verkettung */ |
| fgp=mymalloc(basic_blocks*sizeof(*fgp)); |
| g=fg;fgz=0; |
| while(g){ |
| fgp[fgz]=g;fgz++; |
| g=g->normalout; |
| } |
| if(fgz>basic_blocks) ierror(0); else basic_blocks=fgz; |
| /* alle auf 0 */ |
| do{ |
| changed=0; |
| if(DEBUG&9216) printf("block_regs pass\n"); |
| for(fgz=basic_blocks-1;fgz>=0;fgz--){ |
| IC *p;Var *v;flowlist *lp; |
| int t,vt; |
| g=fgp[fgz]; |
| if(DEBUG&8192) printf("assigning regs to block %d\n",g->index); |
| /* berechnen, wieviel ungefaehr eingespart wird, wenn eine Variable */ |
| /* fuer diesen Block in einem best. Register gehalten wird */ |
| if(DEBUG&8192) printf("calculating approximate savings\n"); |
| |
| for(i=0;i<vcount-rcount;i++){ |
| for(r=1;r<=MAXR;r++){ |
| if(!g->regv[r]||g->regv[r]->index!=i){ |
| int w=0; |
| /* Variable muss evtl. geladen/gespeichert werden */ |
| if(BTST(g->av_in,i)) w--; |
| if(BTST(g->av_out,i)) w--; |
| savings[i][r]=w; |
| } |
| } |
| } |
| if(g->calls>0){ |
| /* bei Funktionsaufrufen muessen Scratchregister gespeichert werden */ |
| for(r=1;r<=MAXR;r++) |
| if(regscratch[r]) |
| for(i=0;i<vcount-rcount;i++) savings[i][r]-=g->calls*2; |
| } |
| /* Wenn Vorgaenger/Nachfolger selbe Variable im selben */ |
| /* Register hat, entfaellt Laden/Speichern in diesem */ |
| /* Block und vermutlich auch im Vorgaenger/Nachfolger */ |
| /* nicht immer, aber naeherungsweise... */ |
| lp=g->in; |
| while(lp){ |
| if(lp->graph){ |
| for(r=1;r<=MAXR;r++){ |
| if(lp->graph->regv[r]&&BTST(g->av_in,lp->graph->regv[r]->index)) savings[lp->graph->regv[r]->index][r]+=2; |
| } |
| } |
| lp=lp->next; |
| } |
| if(g->branchout){ |
| for(r=1;r<=MAXR;r++){ |
| if(g->branchout->regv[r]&&BTST(g->av_out,g->branchout->regv[r]->index)) savings[g->branchout->regv[r]->index][r]+=2; |
| } |
| } |
| if(g->normalout&&(!g->normalout->end||g->normalout->end->code!=BRA)){ |
| for(r=1;r<=MAXR;r++){ |
| if(g->normalout->regv[r]&&BTST(g->av_out,g->normalout->regv[r]->index)) savings[g->normalout->regv[r]->index][r]+=2; |
| } |
| } |
| |
| p=g->start; |
| while(p){ |
| if((p->q1.flags&(VAR|VARADR|REG))==VAR){ |
| v=p->q1.v; |
| if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){ |
| vt=v->vtyp->flags&NU; |
| i=v->index; |
| if(p->q1.flags&DREFOBJ) t=p->typf&NU; else t=0; |
| for(r=1;r<=MAXR;r++){ |
| if(!regsa[r]&&!BTST(g->regused,r)){ |
| /* extra saving, falls passendes Reg fuer DREF */ |
| if(t&®ok(r,vt,t)) savings[i][r]++; |
| if(regok(r,vt,0)) savings[i][r]++; |
| } |
| } |
| } |
| } |
| if((p->q2.flags&(VAR|VARADR|REG))==VAR){ |
| v=p->q2.v; |
| if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){ |
| vt=v->vtyp->flags&NU; |
| i=v->index; |
| if(p->q2.flags&DREFOBJ) t=p->typf&NU; else t=0; |
| for(r=1;r<=MAXR;r++){ |
| if(!regsa[r]&&!BTST(g->regused,r)){ |
| /* extra saving, falls passendes Reg fuer DREF */ |
| if(t&®ok(r,vt,t)) savings[i][r]++; |
| if(regok(r,vt,0)) savings[i][r]++; |
| } |
| } |
| } |
| } |
| if((p->z.flags&(VAR|VARADR|REG))==VAR){ |
| v=p->z.v; |
| if((v->storage_class==AUTO||v->storage_class==REGISTER)&&!(v->flags&USEDASADR)){ |
| vt=v->vtyp->flags&NU; |
| i=v->index; |
| if(p->z.flags&DREFOBJ) t=p->typf&NU; else t=0; |
| for(r=1;r<=MAXR;r++){ |
| if(!regsa[r]&&!BTST(g->regused,r)){ |
| /* extra saving, falls passendes Reg fuer DREF */ |
| if(t&®ok(r,vt,t)) savings[i][r]++; |
| if(regok(r,vt,0)) savings[i][r]++; |
| } |
| } |
| } |
| } |
| if(p==g->end) break; |
| p=p->next; |
| } |
| /* moegliche Kandidaten suchen; muss nicht immer die beste */ |
| /* Kombination finden, sollte aber bei lokaler Vergabe */ |
| /* selten einen Unterschied machen */ |
| for(r=1;r<=MAXR;r++){ |
| if(g->regv[r]||BTST(g->regused,r)) continue; |
| for(i=0;i<vcount-rcount;i++){ |
| if(savings[i][r]>0){ |
| int flag;Var *v=vilist[i]; |
| /* Variable schon in anderem Register? */ |
| for(flag=1;flag<=MAXR;flag++) |
| if(g->regv[flag]==v){flag=-1;break;} |
| if(flag>0){ |
| if(DEBUG&9216) printf("assigned (%s),%ld(%p) to %s; saving=%d\n",vilist[i]->identifier,zm2l(vilist[i]->offset),(void *)vilist[i],regnames[r],savings[i][r]); |
| if(vilist[i]&&!vilist[i]->vtyp->flags) ierror(0); |
| g->regv[r]=vilist[i]; |
| changed=1; |
| break; |
| } |
| } |
| } |
| } |
| } |
| }while(changed); |
| /* jetzt nochmal globale Register vergeben */ |
| /* do_loop_regs(fgp[0],fgp[basic_blocks-1]);*/ |
| |
| free(fgp); |
| free(rvlist); |
| free(savings); |
| } |
| |
| void loop_regs(flowgraph *fg,int intask) |
| /* weist Variablen in Schleifen Register zu */ |
| { |
| flowgraph *g; |
| if(disable&4096) return; |
| if(DEBUG&9216) printf("assigning regs to function\n"); |
| savings=mymalloc((vcount-rcount+const_vars)*sizeof(*savings)); |
| rvlist=mymalloc((vcount-rcount+const_vars)*sizeof(*rvlist)); |
| do_loop_regs(fg,0,intask); |
| if(DEBUG&9216) printf("assigning regs in loops\n"); |
| for(g=fg;g;g=g->normalout){ |
| if(g->index==-1&&!(disable&32768)) do_loop_regs(g,g,0); |
| } |
| free(rvlist); |
| free(savings); |
| } |
| void insert_allocreg(flowgraph *fg,IC *p,int code,int reg) |
| /* Fuegt ein ALLOCREG/FREEREG (in code) hinter p ein - bei p==0 in */ |
| /* first_ic. */ |
| { |
| IC *new=new_IC(); |
| /* printf("%s %s",code==FREEREG?"freereg":"allocreg",regnames[reg]);pric2(stdout,p);*/ |
| new->line=0; |
| new->file=0; |
| BSET(fg->regused,reg); |
| if(reg_pair(reg,&rp)){ |
| BSET(fg->regused,rp.r1); |
| BSET(fg->regused,rp.r2); |
| regused[rp.r1]=regused[rp.r2]=1; |
| } |
| regused[reg]=1; |
| new->code=code; |
| new->typf=0; |
| new->q1.am=new->q2.am=new->z.am=0; |
| new->q1.flags=REG; |
| new->q1.reg=reg; |
| new->q2.flags=new->z.flags=0; |
| new->use_cnt=new->change_cnt=0; |
| new->use_list=new->change_list=0; |
| insert_IC_fg(fg,p,new); |
| } |
| |
| Var *lregv[MAXR+1],*first_const,*last_const; |
| flowgraph *lfg; |
| static int is_header; |
| |
| /* re-inserts a cobj into an obj */ |
| static void insert_cobj(obj *o,obj *co) |
| { |
| int dt=o->dtyp,df=o->flags&DREFOBJ; |
| *o=*co; |
| o->flags|=df; |
| o->dtyp=dt; |
| } |
| |
| static Var *find_const_var(obj *o,int t) |
| { |
| Var *v; |
| for(v=first_const;v;v=v->next){ |
| if((v->ctyp&NQ)==(t&NQ)&&!compare_objs(o,&v->cobj,t)) |
| return v; |
| } |
| return 0; |
| } |
| |
| static long cidx; |
| |
| static Var *add_const_var(obj *o,int t) |
| { |
| Var *v; |
| static type vt={VOID},tt; |
| int m=o->flags; |
| if(o->flags&DREFOBJ){ |
| t=o->dtyp; |
| o->flags&=~DREFOBJ; |
| } |
| if(v=find_const_var(o,t)){ |
| o->flags=m; |
| return v; |
| } |
| v=mymalloc(sizeof(*v)); |
| v->storage_class=AUTO; |
| v->cobj=*o; |
| v->ctyp=t; |
| tt.flags=t; |
| if(ISPOINTER(t)) tt.next=&vt; |
| v->vtyp=clone_typ(&tt); |
| v->next=0; |
| v->identifier=" constant"; |
| v->flags=0; |
| v->reg=0; |
| #ifdef HAVE_TARGET_ATTRIBUTES |
| v->tattr=0; |
| #endif |
| cidx++; |
| v->offset=l2zm(cidx); |
| if(last_const){ |
| last_const->next=v; |
| }else{ |
| first_const=v; |
| const_vars=0; |
| } |
| last_const=v; |
| v->index=vcount-rcount+const_vars; |
| const_vars++; |
| /* Wir ueberschreiben die Eintraege von vcount-rcount bis vcount. */ |
| /* Da sie nicht mehr benutzt werden, sollte das ok sein. */ |
| vilist=myrealloc(vilist,sizeof(*vilist)*(vcount-rcount+const_vars)); |
| vilist[vcount-rcount+const_vars-1]=v; |
| o->flags=m; |
| return v; |
| } |
| |
| void create_const_vars(flowgraph *fg) |
| { |
| IC *p;int t; |
| Var *v; |
| if(DEBUG&1024) printf("creating const-vars\n"); |
| cidx=0; |
| const_vars=0; |
| first_const=last_const=0; |
| for(;fg;fg=fg->normalout){ |
| for(p=fg->start;p;p=p->next){ |
| if(p->q1.flags&(KONST|VARADR)){ |
| t=q1typ(p); |
| v=add_const_var(&p->q1,t); |
| p->q1.flags&=~(KONST|VARADR); |
| p->q1.flags|=(VAR|VKONST); |
| p->q1.v=v; |
| p->q1.val.vmax=l2zm(0L); |
| } |
| if(p->q2.flags&(KONST|VARADR)){ |
| t=q2typ(p); |
| v=add_const_var(&p->q2,t); |
| p->q2.flags&=~(KONST|VARADR); |
| p->q2.flags|=(VAR|VKONST); |
| p->q2.v=v; |
| p->q2.val.vmax=l2zm(0L); |
| } |
| if(p->z.flags&(KONST|VARADR)){ |
| t=ztyp(p); |
| v=add_const_var(&p->z,t); |
| p->z.flags&=~(KONST|VARADR); |
| p->z.flags|=(VAR|VKONST); |
| p->z.v=v; |
| p->z.val.vmax=l2zm(0L); |
| } |
| if(p==fg->end) break; |
| } |
| } |
| if(DEBUG&1024){ |
| Var *v; |
| printf("const-vars:\n"); |
| for(v=first_const;v;v=v->next){ |
| printf("%d: ",v->index); |
| probj(stdout,&v->cobj,v->ctyp); |
| printf(" (t=%d)\n",v->ctyp); |
| } |
| } |
| } |
| |
| void free_const_vars(void) |
| { |
| Var *v,*m; |
| if(DEBUG&1024) printf("free_const_vars()\n"); |
| for(v=first_const;v;){ |
| m=v->next; |
| free(v); |
| v=m; |
| } |
| } |
| |
| #if 0 |
| int free_hreg(flowgraph *fg,IC *p,int reg,int mustr) |
| /* Macht das Register reg frei, damit es als lokale Variable im IC p */ |
| /* zur Verfuegung steht. Wenn mustr!=0, muss das Register unbedingt */ |
| /* freigemacht werden, ansonsten kann davon abgesehen werden. */ |
| { |
| IC *m,*first;Var *v; |
| int preg[MAXR+1]={0},calls[MAXR+1]={0},rreg,i; |
| first=0; |
| v=lregv[reg]; |
| if(!v) |
| ierror(0); |
| if(DEBUG&8192) printf("free_hreg %s,%s,%d\n",regnames[reg],v->identifier,mustr); |
| if(v->reg&&!*v->identifier) ierror(0); |
| for(m=p;m;m=m->next){ |
| if(m->code==CALL){ |
| if((m->q1.flags&(VAR|DREFOBJ))==VAR&&m->q1.v->fi&&(m->q1.v->fi->flags&ALL_REGS)){ |
| for(i=1;i<=MAXR;i++) |
| if(BTST(m->q1.v->fi->regs_modified,i)) calls[i]++; |
| }else{ |
| for(i=1;i<=MAXR;i++) |
| if(regscratch[i]) calls[i]++; |
| } |
| } |
| if(m->code==ALLOCREG){ |
| preg[m->q1.reg]=1; |
| if(m->q1.reg==reg) ierror(0); |
| } |
| if(m->code==FREEREG){ |
| preg[m->q1.reg]=1; |
| if(m->q1.reg==reg) break; |
| } |
| if(!USEQ2ASZ){ |
| if((m->q2.flags&VAR)&&m->q2.v==v&&(m->z.flags&(REG|DREFOBJ))==REG&& |
| (!(m->z.flags&VAR)||m->z.v!=v)) |
| preg[m->z.reg]=1; |
| } |
| if(((m->q1.flags&VAR)&&m->q1.v==v)|| |
| ((m->q2.flags&VAR)&&m->q2.v==v)|| |
| ((m->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&m->z.v==v)) |
| first=m; |
| /* if((m->z.flags&(REG|DREFOBJ))==REG&&m->z.reg==reg) break;*/ |
| } |
| if(!first) {pric(stdout,p);ierror(0);} |
| rp.r1=rp.r2=0; |
| for(rreg=0,i=1;i<=MAXR;i++){ |
| if(preg[i]||regu[i]||regsa[i]||!regok(i,v->vtyp->flags,0)) continue; |
| if(reg_pair(i,&rp)&&(preg[rp.r1]||preg[rp.r2]||regu[rp.r1]||regu[rp.r2]||regsa[rp.r1]||regsa[rp.r2])) continue; |
| if(calls[i]==0&®scratch[i]){rreg=i;break;} |
| if(calls[i]==0) rreg=i; |
| } |
| if(!rreg&&!mustr) return 0; |
| for(m=p;m!=first->next;m=m->next){ |
| if((m->q1.flags&VAR)&&m->q1.v==v) |
| {if(!rreg) m->q1.flags&=~REG; else m->q1.reg=rreg;} |
| if((m->q2.flags&VAR)&&m->q2.v==v) |
| {if(!rreg) m->q2.flags&=~REG; else m->q2.reg=rreg;} |
| if((m->z.flags&VAR)&&m->z.v==v) |
| {if(!rreg) m->z.flags&=~REG; else m->z.reg=rreg;} |
| #if 0 |
| if((m->z.flags&(VAR|DREFOBJ))==VAR&&m->z.v==v) |
| break; |
| #endif |
| } |
| if(rreg){ |
| lregv[rreg]=lregv[reg]; |
| regused[rreg]=1;regu[rreg]=1;BSET(fg->regused,rreg); |
| if(reg_pair(rreg,&rp)){ |
| regused[rp.r1]=1;regu[rp.r1]=1;BSET(fg->regused,rp.r1); |
| regused[rp.r2]=1;regu[rp.r2]=1;BSET(fg->regused,rp.r2); |
| } |
| } |
| lregv[reg]=0;regu[reg]=0; |
| if(reg_pair(reg,&rp)) |
| regu[rp.r1]=regu[rp.r2]=0; |
| |
| for(m=first->next;m&&m->code==FREEREG;m=m->next){ |
| if(m->q1.reg==reg){ |
| if(!rreg) remove_IC_fg(fg,m); else m->q1.reg=rreg; |
| /* if(rreg) insert_allocreg(fg,first,FREEREG,rreg);*/ |
| return rreg; |
| } |
| } |
| insert_allocreg(fg,first->prev,ALLOCREG,reg); |
| if(rreg) |
| insert_allocreg(fg,first,FREEREG,rreg); |
| return rreg; |
| } |
| #endif |
| int replace_local_reg(obj *o) |
| /* tested, ob o eine Scratch-Variable ist und ersetzt sie gegebenenfalls */ |
| { |
| int i;Var *v; |
| if((o->flags&(VAR|REG|VARADR))==VAR){ |
| v=o->v;i=v->index; |
| if((BTST(lfg->av_kill,i)||is_header)&&!BTST(lfg->av_out,i)){ |
| for(i=1;i<=MAXR;i++){ |
| if(lregv[i]==v){ |
| o->flags|=(REG|SCRATCH); |
| /* o->flags&=~VAR;*/ |
| o->reg=i; |
| return i; |
| } |
| } |
| } |
| } |
| return 0; |
| } |
| void local_combine(flowgraph *fg) |
| /* Versucht, Zuweisungen der Form (x)->tmp in ein direkt folgendes IC */ |
| /* einzugliedern. Nur einfache Tests, da nur loads eliminiert werden */ |
| /* sollen, die zum leichten Erkennen per cse explizit wurden. */ |
| { |
| IC *p,*pprev;int i,cl; |
| bvtype *used=mymalloc(vsize); |
| if(DEBUG&1024) printf("local combining\n"); |
| for(;fg;fg=fg->normalout){ |
| memcpy(used,fg->av_out,vsize); |
| for(p=fg->end;p;){ |
| if(p->code==NOP||(!p->q1.flags&&!p->q2.flags)){ |
| if(p==fg->start) break; |
| if(p->z.flags&VAR) BSET(used,p->z.v->index); |
| p=p->prev; |
| continue; |
| } |
| pprev=p->prev; |
| while(pprev&&pprev->code==NOP) pprev=pprev->prev; |
| if(pprev&&p->code==ASSIGN&&zmeqto(p->q2.val.vmax,sizetab[p->typf&NQ])&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&pprev->z.flags==p->q1.flags&&p->q1.v==pprev->z.v&&(!(p->z.flags&VAR)||p->z.v!=p->q1.v)&&ztyp(pprev)==q1typ(p)&&!BTST(used,p->q1.v->index)&&(pprev->code!=ASSIGN||zmeqto(pprev->q2.val.vmax,sizetab[pprev->typf&NQ]))){ |
| /* x op y ->tmp; move tmp->*p => x op y ->*p */ |
| if(DEBUG&1024){ |
| printf("local combine(3):\n"); |
| pric2(stdout,pprev);pric2(stdout,p); |
| } |
| pprev->z=p->z; |
| pprev->change_cnt=p->change_cnt; |
| pprev->change_list=p->change_list; |
| p->change_cnt=0; |
| p->change_list=0; |
| pprev->use_list=myrealloc(pprev->use_list,(pprev->use_cnt+p->use_cnt)*VLS); |
| memcpy(&pprev->use_list[pprev->use_cnt],p->use_list,p->use_cnt*VLS); |
| pprev->use_cnt+=p->use_cnt; |
| p->q1.flags=p->z.flags=0; |
| p->code=NOP; |
| /* restart */ |
| memcpy(used,fg->av_out,vsize); |
| p=fg->end; |
| continue; |
| } |
| if((pprev)&&pprev->code==ASSIGN&&zmeqto(pprev->q2.val.vmax,sizetab[pprev->typf&NQ]) |
| &&zmeqto(pprev->q2.val.vmax,sizetab[p->typf&NQ]) |
| &&((pprev->q1.flags&DREFOBJ)||(static_cse&&(pprev->q1.flags&(VAR|VARADR))==VAR&&(pprev->q1.v->storage_class==EXTERN||pprev->q1.v->storage_class==STATIC)))&&(pprev->z.flags&(VAR|DREFOBJ))==VAR |
| &&!BTST(used,pprev->z.v->index)&&pprev->z.v->storage_class==AUTO |
| &&!(pprev->z.v->flags&USEDASADR) |
| &&((p->code!=ASSIGN&&p->code!=PUSH)||zmeqto(p->q2.val.vmax,sizetab[p->typf&NQ]))){ |
| cl=0; |
| i=pprev->z.v->index; |
| if((p->z.flags&VAR)&&p->z.v->index==i) cl=4; |
| if((p->q1.flags&(VAR|DREFOBJ))==VAR){ |
| if(p->q1.v->index==i&&zmeqto(p->q1.val.vmax,pprev->z.val.vmax)) |
| cl|=1; |
| } |
| if((p->q2.flags&(VAR|DREFOBJ))==VAR){ |
| if(p->q2.v->index==i&&zmeqto(p->q2.val.vmax,pprev->z.val.vmax)) |
| cl|=2; |
| } |
| if(cl==1||cl==2){ |
| if(cl!=2||USEQ2ASZ||compare_objs(&pprev->q1,&p->z,p->typf)){ |
| if(DEBUG&1024){printf("local combine:\n");pric2(stdout,pprev);pric2(stdout,p);} |
| if(cl==1) |
| p->q1=pprev->q1; |
| else |
| p->q2=pprev->q1; |
| p->use_list=myrealloc(p->use_list,(p->use_cnt+pprev->use_cnt)*VLS); |
| memcpy(&p->use_list[p->use_cnt],pprev->use_list,pprev->use_cnt*VLS); |
| p->use_cnt+=pprev->use_cnt; |
| pprev->code=NOP; |
| pprev->q1.flags=pprev->z.flags=0; |
| pprev->typf=0; |
| /* restart */ |
| memcpy(used,fg->av_out,vsize); |
| p=fg->end; |
| continue; |
| } |
| } |
| } |
| if(p==fg->start) break; |
| if(p->q1.flags&VAR) BSET(used,p->q1.v->index); |
| if(p->q2.flags&VAR) BSET(used,p->q2.v->index); |
| if(p->z.flags&VAR) BSET(used,p->z.v->index); |
| p=p->prev; |
| } |
| } |
| free(used); |
| } |
| |
| /* Fuegt evtl. noetige allocreg/freereg nach local_regs in Block ein. */ |
| /* Kann durch free_hreg noetig werden. */ |
| void fix_local_allocreg(flowgraph *fg) |
| { |
| char regs[MAXR+1]={0}; |
| IC *p=fg->end; |
| while(p){ |
| if(p->code==ALLOCREG){ |
| if(!regs[p->q1.reg]) ierror(0); |
| regs[p->q1.reg]=0; |
| }else if(p->code==FREEREG){ |
| if(regs[p->q1.reg]){ |
| ierror(0); |
| } |
| regs[p->q1.reg]=1; |
| }else{ |
| if((p->q1.flags®)&&!regs[p->q1.reg]){ |
| insert_allocreg(fg,p,FREEREG,p->q1.reg); |
| regs[p->q1.reg]=1; |
| } |
| if((p->q2.flags®)&&!regs[p->q2.reg]){ |
| insert_allocreg(fg,p,FREEREG,p->q2.reg); |
| regs[p->q2.reg]=1; |
| } |
| if((p->z.flags&(REG|DREFOBJ))==(REG|DREFOBJ)&&!regs[p->z.reg]){ |
| insert_allocreg(fg,p,FREEREG,p->z.reg); |
| regs[p->z.reg]=1; |
| } |
| if((p->z.flags&(REG|DREFOBJ))==REG){ |
| if(!(p->q1.flags®)||p->q1.reg!=p->z.reg){ |
| if(!(p->q2.flags®)||p->q2.reg!=p->z.reg){ |
| IC *p2; |
| for(p2=p->prev;p2;p2=p2->prev){ |
| if(p2->code==ALLOCREG&&p2->q1.reg==p->z.reg) break; |
| if(p2->code!=ALLOCREG&&p2->code!=FREEREG) break; |
| } |
| if(p2->code!=ALLOCREG||p2->q1.reg!=p->z.reg){ |
| insert_allocreg(fg,p->prev,ALLOCREG,p->z.reg); |
| } |
| } |
| } |
| } |
| } |
| if(p==fg->start) return; |
| p=p->prev; |
| } |
| } |
| |
| /* searches back to determine the best local register for v |
| register-pairs must not be alive in the same instruction as |
| one of the halves */ |
| int find_best_local_reg(IC *fp,Var *v,int preferred) |
| { |
| int r,used,tmp,savings[MAXR+1]={0}; |
| IC *p=fp; |
| |
| if(v->reg&&!*v->identifier) |
| return abs(v->reg); |
| if(v->vtyp->flags&VOLATILE) |
| return 0; |
| if(!USEQ2ASZ&&(p->q2.flags&VAR)&&p->q2.v==v) |
| savings[preferred]=INT_MIN; |
| else |
| savings[preferred]=1; |
| if(reg_pair(preferred,&rp)){ |
| savings[rp.r1]=INT_MIN; |
| savings[rp.r2]=INT_MIN; |
| } |
| for(r=1;r<=MAXR;r++){ |
| if(regu[r]||regsa[r]==REGSA_NEVER){ |
| savings[r]=INT_MIN; |
| if(reg_pair(r,&rp)){ |
| savings[rp.r1]=INT_MIN; |
| savings[rp.r2]=INT_MIN; |
| } |
| }else if(reg_pair(r,&rp)){ |
| if(rp.r1==preferred||rp.r2==preferred||regu[rp.r1]||regsa[rp.r1]==REGSA_NEVER||regu[rp.r2]||regsa[rp.r2]==REGSA_NEVER) |
| savings[r]=INT_MIN; |
| } |
| if(savings[r]!=INT_MIN&&!regok(r,v->vtyp->flags,-1)) |
| savings[r]=INT_MIN; |
| } |
| for(r=1;r<=MAXR;r++){ |
| if(savings[r]!=INT_MIN&®_pair(r,&rp)){ |
| if(regu[rp.r1]||regu[rp.r2]||regsa[rp.r1]==REGSA_NEVER||regsa[rp.r2]==REGSA_NEVER) |
| savings[r]=INT_MIN; |
| } |
| } |
| while(1){ |
| if(!p){ |
| if(!is_header) |
| ierror(0); |
| break; |
| } |
| if(!p||(p!=fp&&p->code>=LABEL&&p->code<=BRA)) return 0; |
| if(p!=fp){ |
| if((p->z.flags&VAR)&&p->z.v->reg&&!*p->z.v->identifier){ |
| if(p->z.v==v) |
| return abs(p->z.v->reg); |
| else |
| savings[abs(p->z.v->reg)]=INT_MIN; |
| } |
| } |
| used=0; |
| if((p->q1.flags&VAR)&&p->q1.v==v){ |
| if(p->code==ADDRESS) return 0; |
| if((p->code==ASSIGN||p->code==PUSH)&&(q1typ(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L))) |
| return 0; |
| used=1; |
| for(r=1;r<=MAXR;r++){ |
| if(savings[r]!=INT_MIN){ |
| tmp=cost_savings(p,r,&p->q1); |
| if(tmp==INT_MIN) |
| savings[r]=INT_MIN; |
| else |
| savings[r]+=tmp; |
| } |
| } |
| } |
| if((p->q2.flags&VAR)&&p->q2.v==v){ |
| used=1; |
| for(r=1;r<=MAXR;r++){ |
| if(savings[r]!=INT_MIN){ |
| tmp=cost_savings(p,r,&p->q2); |
| if(tmp==INT_MIN) |
| savings[r]=INT_MIN; |
| else |
| savings[r]+=tmp; |
| } |
| } |
| } |
| if((p->z.flags&VAR)&&p->z.v==v){ |
| if(p->code==ASSIGN&&(ztyp(p)&NQ)==(CHAR)&&!zmeqto(p->q2.val.vmax,l2zm(1L))) |
| return 0; |
| for(r=1;r<=MAXR;r++){ |
| if(savings[r]!=INT_MIN){ |
| tmp=cost_savings(p,r,&p->z); |
| if(tmp==INT_MIN) |
| savings[r]=INT_MIN; |
| else |
| savings[r]+=tmp; |
| } |
| } |
| if(used==0&&!(p->z.flags&DREFOBJ)) |
| break; |
| } |
| if(p->code==CALL){ |
| if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){ |
| for(r=1;r<=MAXR;r++){ |
| if(regscratch[r]&&BTST(p->q1.v->fi->regs_modified,r)) |
| savings[r]=INT_MIN; |
| } |
| }else{ |
| for(r=1;r<=MAXR;r++){ |
| if(regscratch[r]) |
| savings[r]=INT_MIN; |
| } |
| } |
| } |
| |
| /* check for register arguments */ |
| if((p->z.flags&(VAR|DREFOBJ))==VAR&&!*p->z.v->identifier&&p->z.v->reg){ |
| if(p->code==ASSIGN&&(p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v==v){ |
| savings[abs(p->z.v->reg)]++; |
| }else{ |
| savings[abs(p->z.v->reg)]=INT_MIN; |
| if(reg_pair(abs(p->z.v->reg),&rp)){ |
| savings[rp.r1]=INT_MIN; |
| savings[rp.r2]=INT_MIN; |
| } |
| } |
| } |
| |
| p=p->prev; |
| } |
| r=0; |
| savings[0]=0; |
| for(tmp=1;tmp<=MAXR;tmp++){ |
| if(savings[tmp]>savings[r]){ |
| r=tmp; |
| }else if(savings[tmp]==savings[r]){ |
| if(reg_prio[tmp]>reg_prio[r]) |
| r=tmp; |
| else if(reg_prio[tmp]==reg_prio[r]){ |
| if(regscratch[tmp]&&!regscratch[r]) |
| r=tmp; |
| else if(regscratch[tmp]==regscratch[r]&&BTST(bregs,r)&&!BTST(bregs,tmp)) |
| /* if equal, prefer to leave registers used by parameters */ |
| r=tmp; |
| } |
| } |
| } |
| return r; |
| } |
| |
| static bvtype *late_changes; |
| |
| void search_late_opt(flowgraph *fg,IC *n,obj *o) |
| { |
| Var *v=o->v; |
| IC *p=n->prev,*cp; |
| if(!zmeqto(o->val.vmax,Z0)) return; |
| if(o->v->reg!=0) return; |
| while(1){ |
| if(!p) ierror(0); |
| if(p->code==LABEL) ierror(0); |
| if((p->q1.flags&VAR)&&p->q1.v==v) return; |
| if((p->q2.flags&VAR)&&p->q2.v==v) return; |
| if((p->z.flags&VAR)&&p->z.v==v){ |
| if(p->z.flags&DREFOBJ) return; |
| if(p->code==CONVERT&&!must_convert(p->typf,p->typf2,0)){ |
| int ucnt=0; |
| if((p->q1.flags&DREFOBJ)&&(o->flags&DREFOBJ)) return; |
| if(p->q1.flags&VARADR) return; |
| if((n->q1.flags&VAR)&&n->q1.v==o->v) ucnt++; |
| if((n->q2.flags&VAR)&&n->q2.v==o->v) ucnt++; |
| if((n->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&n->q1.v==o->v) ucnt++; |
| if(ucnt!=1) return; |
| memset(late_changes,vsize,0); |
| if((p->q1.flags&(VAR|VARADR))==VAR){ |
| int i=p->q1.v->index; |
| if(p->q1.flags&DREFOBJ) i+=vcount-rcount; |
| for(cp=p;cp&&cp!=n;cp=cp->next){ |
| ic_changes(cp,late_changes); |
| if(BTST(late_changes,i)) return; |
| } |
| } |
| if(DEBUG&1024){printf("removing CONVERT (!must_convert)\n");pric2(stdout,p);pric2(stdout,n);} |
| if(p->q1.flags&VAR){ |
| o->v=p->q1.v; |
| o->val.vmax=p->q1.val.vmax; |
| if(p->q1.flags&DREFOBJ){ |
| o->flags|=DREFOBJ; |
| o->dtyp=p->q1.dtyp; |
| } |
| n->use_list=myrealloc(n->use_list,VLS*(n->use_cnt+p->use_cnt)); |
| memcpy(&n->use_list[n->use_cnt],&p->use_list[0],p->use_cnt*VLS); |
| n->use_cnt+=p->use_cnt; |
| }else |
| *o=p->q1; |
| |
| remove_IC_fg(fg,p); |
| } |
| #if 0/* BIGENDIAN||LITTLEENDIAN*/ |
| if(p->code==CONVERT&&ISINT(p->typf)&&ISINT(p->typf2)&&(p->typf&NQ)<=(p->typf2&NQ)){ |
| if((p->q1.flags&DREFOBJ)&&(o->flags&DREFOBJ)) return; |
| if(DEBUG&1024){printf("removing CONVERT (int=>smallint)\n");pric2(stdout,p);pric2(stdout,n);} |
| o->v=p->q1.v; |
| o->val.vmax=p->q1.val.vmax; |
| if(p->q1.flags&DREFOBJ){ |
| o->flags|=DREFOBJ; |
| o->dtyp=p->q1.dtyp; |
| } |
| #if BIGENDIAN |
| o->val.vmax=zmadd(o->val.vmax,zmsub(sizetab[p->typf2&NQ],sizetab[p->typf&NQ])); |
| #endif |
| remove_IC_fg(fg,p); |
| } |
| #endif |
| return; |
| } |
| if(p==fg->start) {pric2(stdout,n);ierror(0);} |
| p=p->prev; |
| } |
| } |
| |
| |
| void late_opt(flowgraph *fg) |
| { |
| IC *p;int j;bvtype *isused; |
| isused=mymalloc(vsize); |
| late_changes=mymalloc(vsize); |
| while(fg){ |
| if(DEBUG&1024) printf("late opt pass block %d\n",fg->index); |
| memcpy(isused,fg->av_out,vsize); |
| for(p=fg->end;p;p=p->prev){ |
| if(p->code!=NOP&&p->code!=ADDRESS&&(p->q1.flags&(VAR|VARADR))==VAR){ |
| j=p->q1.v->index; |
| if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j)) |
| search_late_opt(fg,p,&p->q1); |
| } |
| if(p->code!=NOP&&(p->q2.flags&(VAR|VARADR))==VAR){ |
| j=p->q2.v->index; |
| if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j)) |
| search_late_opt(fg,p,&p->q2); |
| } |
| if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){ |
| j=p->z.v->index; |
| if(BTST(fg->av_kill,j)&&!BTST(fg->av_out,j)&&!BTST(isused,j)) |
| search_late_opt(fg,p,&p->z); |
| } |
| if(p==fg->start) break; |
| if(p->change_cnt||p->use_cnt) |
| av_update(p,isused); |
| } |
| fg=fg->normalout; |
| } |
| free(isused); |
| free(late_changes); |
| } |
| |
| void local_regs(flowgraph *fg) |
| /* versucht Variablen, die nur innerhalb eines Basic Blocks benutzt */ |
| /* werden (kill==true und out==false), Register zuzuweisen. */ |
| { |
| IC *p; |
| int i,j,t,r,nr,mustalloc,savings,prio,nr1,nr2; |
| late_opt(fg); |
| if(DEBUG&1024) print_flowgraph(fg); |
| bvtype *inmem=mymalloc(vsize); |
| if(DEBUG&9216) printf("assigning temporary variables to registers\n"); |
| memset(inmem,0,vsize); |
| memset(bregs,0,sizeof(bregs)); |
| for(i=0;i<=MAXR;i++) lparms[i]=0; |
| /* mark registers used by parameters */ |
| for(p=first_ic;p;p=p->next){ |
| if((p->q1.flags&VAR)&&p->q1.v->reg) BSET(bregs,abs(p->q1.v->reg)); |
| if((p->q2.flags&VAR)&&p->q2.v->reg) BSET(bregs,abs(p->q2.v->reg)); |
| if((p->z.flags&VAR)&&p->z.v->reg) BSET(bregs,abs(p->z.v->reg)); |
| } |
| memcpy(bregsm,bregs,sizeof(bregs)); |
| lfg=fg; |
| while(lfg){ |
| if(DEBUG&1024) printf("block %d\n",lfg->index); |
| for(i=1;i<=MAXR;i++){lregv[i]=0; regu[i]=(regsa[i]==REGSA_NEVER); lfg->regv[i]=0;} |
| memset(&lfg->regused,0,RSIZE); |
| lfg->calls=0; |
| // if(lfg==fg&&!lfg->in) is_header=1; else is_header=0; |
| /* unmark registers used as register arguments */ |
| memcpy(bregs,bregsm,sizeof(bregs)); |
| for(p=lfg->start;p;p=p->next){ |
| if((p->z.flags&VAR)&&!*p->z.v->identifier&&p->z.v->reg!=0) BCLR(bregs,abs(p->z.v->reg)); |
| if(p==lfg->end) break; |
| } |
| p=lfg->end; |
| while(p){ |
| nr=nr1=nr2=0; |
| i=replace_local_reg(&p->z); |
| if((p->z.flags&(VAR|DREFOBJ))==VAR){ |
| if(i){ |
| lregv[i]=0;regu[i]=0; |
| if(reg_pair(i,&rp)){ |
| nr1=rp.r1; |
| nr2=rp.r2; |
| regu[nr1]=regu[nr2]=0; |
| } |
| nr=i;mustalloc=1; |
| if(DEBUG&8192) printf("regu[%s] decremented to %d\n",regnames[i],regu[i]); |
| }else{ |
| BCLR(inmem,p->z.v->index); |
| } |
| } |
| if(p->code!=ADDRESS){ |
| if(replace_local_reg(&p->q1)==nr) mustalloc=0; |
| if(replace_local_reg(&p->q2)==nr) mustalloc=0; |
| } |
| if((p->q1.flags&(VAR|REG|VARADR))==VAR&&!(p->q1.v->flags&USEDASADR)&&(!(p->q1.v->vtyp->flags&VOLATILE)||p->q1.v->reg)&&(p->q1.v->storage_class==AUTO||p->q1.v->storage_class==REGISTER)){ |
| j=p->q1.v->index; |
| if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){ |
| r=find_best_local_reg(p,p->q1.v,nr); |
| if(r){ |
| if(r!=nr) |
| insert_allocreg(lfg,p,FREEREG,r); |
| else |
| mustalloc=0; |
| lregv[r]=p->q1.v;regused[r]=regu[r]=1; |
| if(reg_pair(r,&rp)){ |
| regu[rp.r1]=regu[rp.r2]=1; |
| regused[rp.r1]=regused[rp.r2]=1; |
| } |
| if(replace_local_reg(&p->q1)!=r) ierror(0); |
| replace_local_reg(&p->q2); |
| replace_local_reg(&p->z); |
| if((DEBUG&9216)&&*p->q1.v->identifier) printf("temporary <%s> assigned to %s (v3)\n",p->q1.v->identifier,regnames[r]); |
| if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v3)\n",p->q1.v->identifier,(void *)p->q1.v,regnames[r]); |
| }else BSET(inmem,j); |
| } |
| } |
| /* hier wegen USEQ2ASZ aufpassen; kommutative ICs sollten so */ |
| /* angeordnet werden, dass ein evtl. Register rechts steht */ |
| if((p->q2.flags&(VAR|REG|VARADR))==VAR&&!(p->q2.v->flags&USEDASADR)&&!(p->q2.v->vtyp->flags&VOLATILE)&&(p->q2.v->storage_class==AUTO||p->q2.v->storage_class==REGISTER)){ |
| j=p->q2.v->index; |
| if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){ |
| r=find_best_local_reg(p,p->q2.v,nr); |
| if(r){ |
| if(r!=nr) insert_allocreg(lfg,p,FREEREG,r); |
| else mustalloc=0; |
| lregv[r]=p->q2.v;regused[r]=regu[r]=1; |
| if(reg_pair(r,&rp)){ |
| regu[rp.r1]=regu[rp.r2]=1; |
| regused[rp.r1]=regused[rp.r2]=1; |
| } |
| if(replace_local_reg(&p->q2)!=r) ierror(0); |
| replace_local_reg(&p->z); |
| if((DEBUG&9216)&&*p->q2.v->identifier) printf("temporary <%s> assigned to %s (v1)\n",p->q2.v->identifier,regnames[r]); |
| if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v1)\n",p->q2.v->identifier,(void *)p->q2.v,regnames[r]); |
| }else BSET(inmem,j); |
| } |
| } |
| if((p->z.flags&(VAR|REG|DREFOBJ))==(VAR|DREFOBJ)&&!(p->z.v->flags&USEDASADR)&&!(p->z.v->vtyp->flags&VOLATILE)&&(p->z.v->storage_class==AUTO||p->z.v->storage_class==REGISTER)){ |
| j=p->z.v->index; |
| if((BTST(lfg->av_kill,j)||is_header)&&!BTST(lfg->av_out,j)&&!BTST(inmem,j)){ |
| r=find_best_local_reg(p,p->z.v,nr); |
| if(r){ |
| insert_allocreg(lfg,p,FREEREG,r); |
| lregv[r]=p->z.v;regused[r]=regu[r]=1; |
| if(reg_pair(r,&rp)){ |
| regu[rp.r1]=regu[rp.r2]=1; |
| regused[rp.r1]=regused[rp.r2]=1; |
| } |
| if(replace_local_reg(&p->z)!=r){ |
| for(i=1;i<=MAXR;i++) if(lregv[i]) printf("%d:%s=%s(%p)\n",i,regnames[i],lregv[i]->identifier,(void*)lregv[i]); |
| ierror(r);} |
| if((DEBUG&9216)&&*p->z.v->identifier) printf("temporary <%s> assigned to %s (v2)\n",p->z.v->identifier,regnames[r]); |
| if(DEBUG&8192) printf("temporary <%s>(%p) assigned to %s (v2)\n",p->z.v->identifier,(void *)p->z.v,regnames[r]); |
| }else BSET(inmem,j); |
| } |
| } |
| if(p->code==CALL){ |
| lfg->calls++; |
| #if 0 |
| /* falls Scratchregister bei Funktionsaufruf benutzt */ |
| /* wird, moeglichst auf ein anderes ausweichen */ |
| for(i=1;i<=MAXR;i++){ |
| if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)){ |
| if(lregv[i]&®scratch[i]&&BTST(p->q1.v->fi->regs_modified,i)){ |
| int j=lregv[i]->index; |
| if(lregv[i]->reg&&!*lregv[i]->identifier) ierror(0); |
| if(free_hreg(lfg,p,i,1/*0*/)==0) BSET(inmem,j); |
| } |
| }else{ |
| if(lregv[i]&®scratch[i]){ |
| int j=lregv[i]->index; |
| if(lregv[i]->reg&&!*lregv[i]->identifier) ierror(0); |
| if(free_hreg(lfg,p,i,1/*0*/)==0) BSET(inmem,j); |
| } |
| } |
| } |
| #endif |
| } |
| /* die Faelle beachten, wenn schon im IC ein Register */ |
| /* angesprochen wird (sollte nur bei CALL und return auftreten */ |
| if(p->code==FREEREG){ |
| ierror(0); |
| } |
| if(p->code==ALLOCREG){ |
| ierror(0); |
| } |
| if(p==lfg->start) i=1; else i=0; |
| p=p->prev; |
| if(nr&&mustalloc) insert_allocreg(lfg,p,ALLOCREG,nr); |
| if(i) break; |
| } |
| fix_local_allocreg(lfg); |
| lfg=lfg->normalout; |
| if(is_header){ |
| for(i=1;i<=MAXR;i++) |
| lparms[i]=lregv[i]; |
| } |
| } |
| free(inmem); |
| } |
| void insert_saves(flowgraph *fg) |
| /* fuegt speichern von Registern bei Funktionsaufrufen ein */ |
| { |
| int r,c,i;IC *p,*new,*n,*before,*after;Var *v; |
| bvtype *isused=mymalloc(vsize); |
| if(DEBUG&9216) printf("insert_saves\n"); |
| for(;fg;fg=fg->normalout){ |
| memcpy(isused,fg->av_out,vsize); |
| p=fg->end; |
| while(p){ |
| c=p->code; |
| if(c==CALL){ |
| if(p==fg->start) n=0; else n=p->prev; |
| for(r=1;r<=MAXR;r++){ |
| i=0; |
| if((v=fg->regv[r])&&(v->index>=vcount-rcount||BTST(isused,v->index))){ |
| if((p->q1.flags&(VAR|DREFOBJ))==VAR&&p->q1.v->fi&&(p->q1.v->fi->flags&ALL_REGS)&&!(disable&2048)){ |
| if(regscratch[r]&&BTST(p->q1.v->fi->regs_modified,r)) i=1; |
| }else{ |
| if(regscratch[r]) i=1; |
| } |
| } |
| if(i){ |
| if(!n) before=fg->start->prev; else before=n; |
| after=p->next; |
| while(after&&(after->code==FREEREG||after->code==ALLOCREG||after->code==NOP)) |
| after=after->next; |
| if(!after||after->code!=GETRETURN){ |
| after=p; |
| }else{ |
| if((after->z.flags®)&&after->z.reg==r) after->z.flags&=~REG; |
| } |
| if(v->index>=vcount-rcount){ |
| /* it is a const_var; reload instead of store */ |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=v->vtyp->flags; |
| insert_cobj(&new->q1,&v->cobj); |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(v->vtyp); |
| new->z.flags=REG; |
| new->z.reg=r; |
| new->z.val.vmax=l2zm(0L); |
| new->z.v=v; |
| new->file=p->file; |
| new->line=p->line; |
| /* fake, we do nothing with this afterwards */ |
| new->use_cnt=new->change_cnt=0; |
| new->change_list=new->use_list=0; |
| insert_IC_fg(fg,after,new); |
| }else{ |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=v->vtyp->flags; |
| /* vla */ |
| if(ISARRAY(new->typf)) |
| new->typf=POINTER_TYPE(v->vtyp->next); |
| new->q1.flags=VAR|REG; |
| new->q1.v=v; |
| new->q1.val.vmax=l2zm(0L); |
| new->q1.reg=r; |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(v->vtyp); |
| new->z.flags=VAR; |
| new->z.val.vmax=l2zm(0L); |
| new->z.v=v; |
| new->file=p->file; |
| new->line=p->line; |
| /* fake, we do nothing with this afterwards */ |
| new->use_cnt=new->change_cnt=0; |
| new->change_list=new->use_list=0; |
| insert_IC_fg(fg,before,new); |
| new=new_IC(); |
| new->code=ASSIGN; |
| new->typf=v->vtyp->flags; |
| /* vla */ |
| if(ISARRAY(new->typf)) |
| new->typf=POINTER_TYPE(v->vtyp->next); |
| new->q1.flags=VAR; |
| new->q1.v=v; |
| new->q1.val.vmax=l2zm(0L); |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(v->vtyp); |
| new->z.flags=VAR|REG; |
| new->z.v=v; |
| new->z.val.vmax=l2zm(0L); |
| new->z.reg=r; |
| new->file=p->file; |
| new->line=p->line; |
| /* fake, we do nothing with this afterwards */ |
| new->use_cnt=new->change_cnt=0; |
| new->change_list=new->use_list=0; |
| insert_IC_fg(fg,after,new); |
| } |
| } |
| } |
| if(p->change_cnt!=0||p->use_cnt!=0) |
| av_update(p,isused); |
| p=n; |
| continue; |
| } |
| if(p==fg->start) break; |
| if(p->change_cnt!=0||p->use_cnt!=0) |
| av_update(p,isused); |
| p=p->prev; |
| } |
| } |
| free(isused); |
| } |
| |
| |
| #endif |
| |
| void insert_simple_allocreg(IC *p,int code,int reg) |
| /* Fuegt ein ALLOCREG/FREEREG (in code) hinter p ein - bei p==0 in */ |
| /* first_ic. */ |
| { |
| IC *new=new_IC(); |
| new->line=0; |
| new->file=0; |
| regused[reg]=1; |
| if(reg_pair(reg,&rp)) |
| regused[rp.r1]=regused[rp.r2]=1; |
| new->code=code; |
| new->typf=0; |
| new->q1.am=new->q2.am=new->z.am=0; |
| new->q1.flags=REG; |
| new->q1.reg=reg; |
| new->q2.flags=new->z.flags=0; |
| new->use_cnt=new->change_cnt=0; |
| new->use_list=new->change_list=0; |
| insert_IC(p,new); |
| } |
| |
| void load_simple_reg_parms(void) |
| /* Laedt Registerparameter, falls noetig. Nicht-optimierende Version. */ |
| { |
| int i,j; Var *v; |
| regp regp[MAXR+1]={0}; |
| /* for(i=1;i<=MAXR;i++) {regp[i].treg=0;regp[i].tvar=0;} */ |
| for(i=0;i<=1;i++){ |
| if(i==0) v=vl3; else v=vl2; |
| for(;v;v=v->next){ |
| if((v->flags®PARM)&&(regsv[abs(v->reg)]!=v||(v->flags&CONVPARAMETER))){ |
| regp[abs(v->reg)].tvar=v; |
| for(j=1;j<=MAXR;j++) |
| if(regsv[j]==v) regp[abs(v->reg)].treg=j; |
| } |
| } |
| } |
| do_load_parms(regp,0); |
| } |
| |
| extern zmax recalc_start_offset; |
| |
| void do_load_parms(regp regp[],flowgraph *fg) |
| { |
| int i,i1,i2,j,j1,j2,c,k,notdone; |
| struct {int freg,treg;Var *tvar,*tmp;} order[MAXR]={0}; |
| if(DEBUG&1){ |
| printf("do_load_parms:\n"); |
| for(i=1;i<=MAXR;i++) |
| if(regp[i].tvar) |
| printf("%s->%s(%s)\n",regnames[i],regnames[regp[i].treg],regp[i].tvar->identifier); |
| } |
| do{ |
| c=0; |
| do{ |
| notdone=0; |
| for(i=1;i<=MAXR;i++){ |
| int notfree; |
| if(reg_pair(i,&rp)){ |
| i1=rp.r1; |
| i2=rp.r2; |
| }else |
| i1=i2=0; |
| if(!regp[i].tvar) continue; |
| j=regp[i].treg; |
| if(j&®_pair(j,&rp)){ |
| j1=rp.r1; |
| j2=rp.r2; |
| }else |
| j1=j2=0; |
| notfree=0; |
| for(k=1;k<=MAXR;k++){ |
| if(regp[k].tvar&®_pair(k,&rp)&&(rp.r1==j||rp.r1==j1||rp.r1==j2||rp.r2==j||rp.r2==j1||rp.r2==j2)){ |
| notfree=1; |
| break; |
| } |
| } |
| if(j==0||(!notfree&&!regp[j].tvar&&(!j1||!regp[j1].tvar)&&(!j2||!regp[j2].tvar))||i==j||regp[i].tmp){ |
| order[c].freg=i; |
| order[c].treg=j; |
| order[c].tvar=regp[i].tvar; |
| if(regp[i].tmp){order[c].treg=0;order[c].tvar=regp[i].tmp;} |
| c++; notdone=1; |
| regp[i].treg=0; |
| regp[i].tvar=0; |
| } |
| } |
| }while(notdone); |
| for(i=c-1;i>=0;i--) |
| load_one_parm(order[i].freg,order[i].treg,0,order[i].tvar,fg); |
| notdone=0; |
| /* first try to spill register-pair (probably suboptimal, but should |
| avoid a deadlock) */ |
| for(i=1;i<=MAXR;i++){ |
| if(regp[i].tvar&®_pair(i,&rp)) |
| break; |
| } |
| if(i>MAXR){ |
| for(i=1;i<=MAXR;i++){ |
| if(regp[i].tvar) |
| break; |
| } |
| } |
| if(i<=MAXR){ |
| static type dtyp={DOUBLE}; |
| if(!regp[i].tvar) ierror(0); |
| if(regp[i].tvar->flags&CONVPARAMETER) |
| regp[i].tmp=add_tmp_var(clone_typ(&dtyp)); |
| else |
| regp[i].tmp=add_tmp_var(clone_typ(regp[i].tvar->vtyp)); |
| /* num_vars is already done, so mark it by -1 */ |
| regp[i].tmp->index=-1; |
| /* allocate memory for recalc_offsets */ |
| #ifndef NO_OPTIMIZER |
| if(fg){ |
| regp[i].tmp->offset=l2zm(0L); |
| if(zmleq(recalc_start_offset,regsize[i])) |
| recalc_start_offset=regsize[i]; |
| } |
| #endif |
| load_one_parm(0,regp[i].treg,regp[i].tmp,regp[i].tvar,fg); |
| notdone=1; |
| } |
| }while(notdone); |
| } |
| void load_one_parm(int freg,int treg,Var *fvar,Var *tvar,flowgraph *fg) |
| { |
| IC *new; |
| if(DEBUG&1) printf("lop: %s(%s)->%s(%s)\n",regnames[freg],fvar?fvar->identifier:empty,regnames[treg],tvar?tvar->identifier:empty); |
| if(freg&&freg!=treg){ |
| if(fg){ |
| #ifndef NO_OPTIMIZER |
| insert_allocreg(fg,0,FREEREG,freg); |
| #endif |
| }else |
| insert_simple_allocreg(0,FREEREG,freg); |
| } |
| new=new_IC(); |
| new->line=0; |
| new->file=0; |
| if(tvar->flags&CONVPARAMETER){ |
| new->code=CONVERT; |
| new->typf=tvar->vtyp->flags; |
| new->typf2=DOUBLE; |
| }else{ |
| new->code=ASSIGN; |
| new->typf=tvar->vtyp->flags; |
| } |
| if(ISFLOAT(new->typf)) float_used=1; |
| if(fvar){ |
| new->q1.flags=VAR; |
| new->q1.v=fvar; |
| new->q1.val.vmax=l2zm(0L); |
| }else{ |
| new->q1.flags=REG; |
| new->q1.reg=freg; |
| } |
| new->q2.flags=0; |
| new->q2.val.vmax=szof(tvar->vtyp); |
| if(treg) |
| new->z.flags=REG|VAR; |
| else |
| new->z.flags=VAR; |
| new->z.val.vmax=l2zm(0L); |
| new->z.v=tvar; |
| new->z.reg=treg; |
| new->q1.am=new->q2.am=new->z.am=0; |
| new->use_cnt=new->change_cnt=0; |
| new->use_list=new->change_list=0; |
| if((new->typf&NQ)==CHAR&&!regok(new->q1.reg,new->typf,0)){ |
| new->code=CONVERT; |
| new->typf2=INT; |
| } |
| if(fg){ |
| #ifndef NO_OPTIMIZER |
| insert_IC_fg(fg,0,new); |
| if(freg&&freg!=treg) insert_allocreg(fg,0,ALLOCREG,freg); |
| #endif |
| }else{ |
| insert_IC(0,new); |
| if(freg&&freg!=treg) insert_simple_allocreg(0,ALLOCREG,freg); |
| } |
| if(new->z.flags®){ |
| /* ALLOCREG verschieben */ |
| IC *p; |
| if(fg){ |
| #ifndef NO_OPTIMIZER |
| insert_allocreg(fg,0,ALLOCREG,treg); |
| #endif |
| }else |
| insert_simple_allocreg(0,ALLOCREG,treg); |
| for(p=new->next;p;p=p->next){ |
| if(p->code==ALLOCREG&&p->q1.reg==treg){ |
| if(fg){ |
| #ifndef NO_OPTIMIZER |
| remove_IC_fg(fg,p); |
| #endif |
| }else |
| remove_IC(p); |
| break; |
| } |
| } |
| if(!p) ierror(0); |
| } |
| } |
| |
| void simple_regs(void) |
| /* haelt Variablen in Registern, simple Version */ |
| { |
| int i2,i,j;int pri;Var *v; |
| IC *icp,*start=first_ic; |
| if(!first_ic) return; |
| for(i=1;i<=MAXR;i++) regsv[i]=0; |
| for(i2=0;i2<=MAXR*4;i2++){ |
| int only_best,pointertype=0; |
| if(i2<=MAXR*2){i=i2;only_best=1;} else {i=i2/2;pointertype=only_best=0;} |
| if(i<=MAXR&®sv[i]) continue; |
| if(i>MAXR&®sv[i-MAXR]) continue; |
| if(i>MAXR||!regsv[i]){ |
| if(i>MAXR){ |
| i-=MAXR; |
| if(regsv[i]) continue; |
| }else{ |
| /* Ziehe Scratchregister vor, wenn kein Funktionsaufruf */ |
| /* erfolgt, sonst erst andere */ |
| if(!regscratch[i]) continue; |
| } |
| if(regused[i]) continue; |
| if(sregsa[i]==REGSA_TEMPS) continue; |
| if(reg_pair(i,&rp)){ |
| if(regused[rp.r1]||regused[rp.r2]) continue; |
| } |
| if(simple_scratch[i]) continue; |
| /*pri=2;*/ pri=0; |
| for(j=0;j<=1;j++){ |
| if(j==0) v=vl3; else v=vl2; |
| while(v){ |
| if(v->storage_class==AUTO||v->storage_class==REGISTER){ |
| if(!(v->flags&USEDASADR)&&!(v->vtyp->flags&VOLATILE)){ |
| int vt=v->vtyp->flags&NU; |
| /* vla */ |
| if(ISARRAY(vt)&&is_vlength(v->vtyp)) |
| vt=POINTER_TYPE(v->vtyp->next); |
| if(only_best&&v->vtyp->next) pointertype=v->vtyp->next->flags; |
| if(v->priority>pri&®ok(i,vt,pointertype)){ |
| regsv[i]=v;pri=v->priority; |
| } |
| } |
| } |
| v=v->next; |
| } |
| } |
| } |
| if(regsv[i]){ |
| if(DEBUG&1) printf("Assigned <%s>(%p) to %s,%d\n",regsv[i]->identifier,(void *)regsv[i],regnames[i],i); |
| regsv[i]->priority=0;regused[i]=1; |
| if(reg_pair(i,&rp)) {regused[rp.r1]=regused[rp.r2]=1;} |
| if(!zmleq(l2zm(0L),regsv[i]->offset)&&!(regsv[i]->flags&(CONVPARAMETER|REGPARM))){ |
| icp=new_IC(); |
| icp->line=0; |
| icp->file=0; |
| icp->q1.am=icp->q2.am=icp->z.am=0; |
| icp->code=ASSIGN; |
| icp->typf=regsv[i]->vtyp->flags&NU; |
| icp->q1.flags=VAR; |
| icp->q1.v=regsv[i]; |
| icp->q1.val.vmax=l2zm(0L); |
| icp->q2.flags=0; |
| icp->q2.val.vmax=szof(regsv[i]->vtyp); |
| icp->z.flags=REG; |
| icp->z.reg=i; |
| icp->next=first_ic; |
| icp->prev=0; |
| first_ic->prev=icp; |
| first_ic=icp; |
| } |
| icp=new_IC(); |
| icp->line=0; |
| icp->file=0; |
| icp->q1.am=icp->q2.am=icp->z.am=0; |
| icp->code=ALLOCREG; |
| icp->q1.flags=REG; |
| icp->q1.reg=i; |
| icp->q2.flags=icp->z.flags=icp->typf=0; |
| icp->next=first_ic; |
| icp->prev=0; |
| first_ic->prev=icp; |
| first_ic=icp; |
| icp=new_IC(); |
| icp->q1.am=icp->q2.am=icp->z.am=0; |
| icp->code=FREEREG; |
| icp->q1.flags=REG; |
| icp->q1.reg=i; |
| icp->q2.flags=icp->z.flags=icp->typf=0; |
| icp->next=0; |
| add_IC(icp); |
| } |
| } |
| icp=start; |
| while(icp){ |
| if((icp->code==ALLOCREG||icp->code==FREEREG)&®sv[icp->q1.reg]){ |
| /* irgendwelche allocreg/freereg im Code entfernen */ |
| /* sollte nur beim Returnregister vorkommen */ |
| IC *m=icp->next; |
| remove_IC(icp); |
| icp=m;continue; |
| } |
| for(i=1;i<=MAXR;i++){ |
| if(!regsv[i]) continue; |
| if((icp->q1.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->q1.v==regsv[i]){ |
| icp->q1.flags|=REG; |
| icp->q1.reg=i; |
| } |
| if((icp->q2.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->q2.v==regsv[i]){ |
| icp->q2.flags|=REG; |
| icp->q2.reg=i; |
| } |
| if((icp->z.flags&(VAR|DONTREGISTERIZE))==VAR&&icp->z.v==regsv[i]){ |
| icp->z.flags|=REG; |
| icp->z.reg=i; |
| } |
| } |
| icp=icp->next; |
| } |
| } |
| |
| |