1865 lines · 59.7 KB · C
RawDownload
/*  $VER: vbcc (regs.c) V0.8    *//*  Registerzuteilung           */ #include "opt.h" static char FILE_[]=__FILE__; #ifndef NO_OPTIMIZER int (*savings)[MAXR+1],regu[MAXR+1];int *rvlist; static int const_vars; struct regp {int treg;struct Var *tvar,*tmp;};void do_load_parms(struct regp [],struct flowgraph *);void load_one_parm(int,int,struct Var *,struct Var *,struct flowgraph *); static void insert_cobj(struct obj *o,struct obj *co); #ifndef HAVE_TARGET_RALLOCint 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(struct IC *p,int r,struct 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(struct 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.      */{    struct flowlist *lp;    lp=fg->in;    while(lp){        if(lp->graph&&lp->graph->regv[i]!=fg->regv[i]&&(fg->regv[i]->index>=vcount-rcount||BTST(lp->graph->av_out,fg->regv[i]->index))) 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,struct flowgraph *start,struct flowgraph *end){  int j,k;  struct IC *p;struct Var *v;  struct 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(struct 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.                                        */{    struct 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(struct flowgraph *fg)/*  Laedt Registerparameter, falls noetig.                              */{    int i,j; struct Var *v;    struct 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&REGPARM)&&(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) regp[abs(v->reg)].treg=j;	}    }    do_load_parms(regp,fg);} void insert_regs(struct flowgraph *fg1)/*  Fuegt Registervariablen in die ICs ein.                             */{    int i;struct IC *p,*lic=0,*new;struct 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);        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]){		    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]){		    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]){		  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) 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)){                        struct IC *tp;                        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;                            while(tp!=fg->start&&(tp->code==FREEREG||tp->code==SETRETURN))                                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(fg->regv[i]->index>=vcount-rcount||BTST(fg->av_in,fg->regv[i]->index)){                    if((fg==fg1||entry_load(fg,i))&&(fg!=fg1||!(fg->regv[i]->flags&REGPARM))){                        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(struct flowgraph *start,struct 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.                    */{  struct flowgraph *g,*lend;  int i,r,iterations;  struct 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){    struct 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		savings[i][r]+=(cost_save_reg(r,vilist[i])-cost_move_reg(pr,r));	    }	  }	}      }    }    /*  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){    struct IC *p;struct 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&&regok(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;		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&&regok(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;	      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&&regok(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;	      else		savings[i][r]+=iterations*s;

Lines 1–500 of 1865.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t