1570 lines · 44.2 KB · C
RawDownload
/*  $VER: vbcc (opt.c) V0.8     *//*  allgemeine Routinen fuer den Optimizer und Steuerung der einzelnen  *//*  Laeufe                                                              */ #include "opt.h" static char FILE_[]=__FILE__; /*  die naechsten Funktionen sollten evtl. in ic.c                  */ /*  Sind use/change-Listen initialisiert?   */int have_alias; int static_cse=1,dref_cse=1; #ifdef ALEX_REGextern struct flowgraph *pFg;#endif void insert_IC(struct IC *p,struct IC *new)/*  fuegt new hinter p ein; p darf 0 sein                           */{  if((new->code==ADDI2P||new->code==SUBIFP||new->code==SUBPFP)&&!ISPOINTER(new->typf2))    ierror(0);  new->prev=p;  if(p){    new->next=p->next; p->next=new;  }else{    new->next=first_ic; first_ic=new;   }  if(new->next)     new->next->prev=new;   else     last_ic=new;  new->q1.am=new->q2.am=new->z.am=0;} #ifndef NO_OPTIMIZER int gchanged;   /*  Merker, ob Optimierungslauf etwas geaendert hat */int norek;      /*  diese Funktion wird nicht rekursiv auf          */int nocall;     /*  diese Funktion kehrt nicht zum Caller zurueck   */ #if HAVE_LIBCALLSextern np gen_libcall(char *fname,np arg1,struct Typ *t1,np arg2,struct Typ *t2);  /* insert libcalls just before register allocation */static int insert_libcalls(struct flowgraph *fg){  struct IC *p,*next,*add;  int replaced=0;  static struct node n,nl,nr;  static struct Typ t,tl,tr;  if(DEBUG&1024) printf("insert_libcalls\n");  while(fg){    for(p=fg->start;p;p=next){      int c=p->code,end=0;      char *libname;      next=p->next;      if((c>=OR&&c<=XOR)||(c>=LSHIFT&&c<=KOMPLEMENT)||c==COMPARE||c==CONVERT||c==MINUS||c==TEST){	if(libname=use_libcall(c,p->typf,p->typf2)){	  struct IC *merk_first,*merk_last;	  static struct node n1,n2;	  static struct Typ t1,t2;	  if(DEBUG&1024){	    printf("converting IC to libcall:\n");	    pric2(stdout,p);	  }	  replaced=1;	  merk_last=last_ic;	  merk_first=first_ic;	  first_ic=last_ic=0;	  n1.flags=REINTERPRET;	  n1.o=p->q1;	  n1.ntyp=&t1;	  t1.flags=q1typ(p);	  if(p->q2.flags){	    n2.flags=REINTERPRET;	    n2.o=p->q2;	    n2.ntyp=&t2;	    t2.flags=q2typ(p);	    gen_libcall(libname,&n1,&t1,&n2,&t2);	  }else	    gen_libcall(libname,&n1,&t1,0,0);	  if(!last_ic||last_ic->code!=GETRETURN) ierror(0);	  last_ic->z=p->z;	  add=first_ic;	  last_ic=merk_last;	  first_ic=merk_first;	  for(;add;add=next){	    next=add->next;	    insert_IC_fg(fg,p->prev,add);	  }	  next=p->next;	  if(fg->end==p) end=1;	  if(p->z.flags){	    remove_IC_fg(fg,p);	  }else{	    struct Typ *t=new_typ();	    t->flags=INT;	    p->code=TEST;	    p->typf=INT;	    p->q1.flags=VAR;	    p->q1.v=add_tmp_var(t);	    p->q1.val.vmax=l2zm(0L);	    p->prev->z=p->q1;	    p->q2.flags=p->z.flags=0;	  }	}      }      if(end||p==fg->end) break;    }    fg=fg->normalout;  }  return replaced;}#endif /*  temporary fuer verschiedene Bitvektoren */bvtype *tmp; int in_varlist(struct varlist *vl,int cnt,struct Var *v,int flags){  int i;  /*FIXME: slow */  for(i=0;i<cnt;i++){    if(vl[i].v==v&&vl[i].flags==flags) return 1;  }  return 0;} static void add_call_list(void){  struct IC *p;  for(p=first_ic;p;p=p->next){    if(p->code==CALL&&p->call_cnt==0){      if((p->q1.flags&(VAR|DREFOBJ))==VAR){	p->call_cnt=1;	p->call_list=mymalloc(sizeof(*p->call_list));	p->call_list[0].v=p->q1.v;	p->call_list[0].flags=0;      }    }  }} void calc_finfo(struct Var *v,int flags){  struct IC *p;int i,known,maxtyp,t,c;  /* 128 types should be enough for everyone :-) */  #define TSIZE BVSIZE(128)  static bvtype tf[TSIZE];  if(!v->fi) ierror(0);  if(flags&CALC_USES){    if(v->fi->flags&ALL_USES) return;    free(v->fi->use_list);    v->fi->use_cnt=0;    v->fi->use_list=0;    memset(tf,0,TSIZE);    known=1;maxtyp=-1;    for(p=first_ic;p;p=p->next){      c=p->code;      if(p->q1.flags&DREFOBJ){	t=(q1typ(p)&NQ);	if(t>maxtyp) maxtyp=t;	BSET(tf,t);      }      if(p->q2.flags&DREFOBJ){	t=(q2typ(p)&NQ);	if(t>maxtyp) maxtyp=t;	BSET(tf,t);      }      if(c==CALL){	if((p->q1.flags&(VAR|DREFOBJ))!=VAR||!p->q1.v->fi||!(p->q1.v->fi->flags&ALL_USES)){	  free(v->fi->use_list);	  v->fi->use_cnt=0;	  v->fi->use_list=0;	  known=0;	  break;	}else{	  for(i=0;i<p->q1.v->fi->use_cnt;i++){	    if(p->q1.v->fi->use_list[i].v){	      if(!in_varlist(v->fi->use_list,v->fi->use_cnt,p->q1.v->fi->use_list[i].v,p->q1.v->fi->use_list[i].flags)){		v->fi->use_cnt++;		v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(struct varlist));		v->fi->use_list[v->fi->use_cnt-1]=p->q1.v->fi->use_list[i];	      }	    }else{	      BSET(tf,p->q1.v->fi->use_list[i].flags&NQ);	    }	  }	}      }else{	for(i=0;i<p->use_cnt;i++){	  if(p->use_list[i].v->nesting!=0) continue;	  if(!in_varlist(v->fi->use_list,v->fi->use_cnt,p->use_list[i].v,p->use_list[i].flags)){	    v->fi->use_cnt++;	    v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(struct varlist));	    v->fi->use_list[v->fi->use_cnt-1]=p->use_list[i];	  }	}      }    }    for(c=0;c<=maxtyp;c++){      if(BTST(tf,c)){	v->fi->use_cnt++;	v->fi->use_list=myrealloc(v->fi->use_list,v->fi->use_cnt*sizeof(struct varlist));	v->fi->use_list[v->fi->use_cnt-1].v=0;	v->fi->use_list[v->fi->use_cnt-1].flags=c;      }    }    if(known) v->fi->flags|=ALL_USES;  }  if(flags&CALC_CHANGES){    if(v->fi->flags&ALL_MODS) return;    free(v->fi->change_list);    v->fi->change_cnt=0;    v->fi->change_list=0;    memset(tf,0,TSIZE);    known=1;maxtyp=-1;    for(p=first_ic;p;p=p->next){      c=p->code;      if(p->z.flags&DREFOBJ){	t=(ztyp(p)&NQ);	if(t>maxtyp) maxtyp=t;	BSET(tf,t);      }      if(c==CALL){	if((p->q1.flags&(VAR|DREFOBJ))!=VAR||!p->q1.v->fi||!(p->q1.v->fi->flags&ALL_MODS)){	  free(v->fi->change_list);	  v->fi->change_cnt=0;	  	  v->fi->change_list=0;	  known=0;	  break;	}else{	  for(i=0;i<p->q1.v->fi->change_cnt;i++){	    if(p->q1.v->fi->change_list[i].v){	      if(!in_varlist(v->fi->change_list,v->fi->change_cnt,p->q1.v->fi->change_list[i].v,p->q1.v->fi->change_list[i].flags)){		v->fi->change_cnt++;		v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(struct varlist));		v->fi->change_list[v->fi->change_cnt-1]=p->q1.v->fi->change_list[i];	      }	    }else{	      BSET(tf,p->q1.v->fi->change_list[i].flags&NQ);	    }	  }	}      }else{	for(i=0;i<p->change_cnt;i++){	  if(p->change_list[i].v->nesting!=0) continue;	  if(!in_varlist(v->fi->change_list,v->fi->change_cnt,p->change_list[i].v,p->change_list[i].flags)){	    v->fi->change_cnt++;	    v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(struct varlist));	    v->fi->change_list[v->fi->change_cnt-1]=p->change_list[i];	  }	}      }    }    for(c=0;c<=maxtyp;c++){      if(BTST(tf,c)){	v->fi->change_cnt++;	v->fi->change_list=myrealloc(v->fi->change_list,v->fi->change_cnt*sizeof(struct varlist));	v->fi->change_list[v->fi->change_cnt-1].v=0;	v->fi->change_list[v->fi->change_cnt-1].flags=c;      }    }    if(known) v->fi->flags|=ALL_MODS;  }  if(flags&CALC_CALLS){    if(v->fi->flags&ALL_CALLS) return;    free(v->fi->call_list);    v->fi->call_list=0;    v->fi->call_cnt=0;    p=v->fi->opt_ic;    if(!p)      p=v->fi->first_ic;    for(;p;p=p->next){      if(p->code==CALL){	if(p->q1.flags&DREFOBJ) return;	if(!in_varlist(v->fi->call_list,v->fi->call_cnt,p->q1.v,0)){	  v->fi->call_cnt++;	  v->fi->call_list=myrealloc(v->fi->call_list,v->fi->call_cnt*sizeof(struct varlist));	  v->fi->call_list[v->fi->call_cnt-1].v=p->q1.v;	  v->fi->call_list[v->fi->call_cnt-1].flags=0;	}      }    }    v->fi->flags|=ALL_CALLS;  }} void used_clist(struct Typ *t,struct const_list *cl){  int i;zmax l;  if(ISARRAY(t->flags)){    for(l=l2zm(0L);!zmleq(t->size,l)&&cl;l=zmadd(l,l2zm(1L)),cl=cl->next){      if(!cl->other){ierror(0);return;}      used_clist(t->next,cl->other);    }    return;  }  if(ISUNION(t->flags)){    used_clist((*t->exact->sl)[0].styp,cl);    return;  }  if(ISSTRUCT(t->flags)){    struct Typ *st;    for(i=0;i<t->exact->count&&cl;i++){      st=(*t->exact->sl)[i].styp;      if(!(*t->exact->sl)[i].identifier) ierror(0);      if((*t->exact->sl)[i].identifier[0]){        if(cl->other) used_clist(st,cl->other);        cl=cl->next;      }    }    return;  }  if(cl->tree&&(cl->tree->o.flags&VAR))    used_objects(cl->tree->o.v);  return;} void used_objects(struct Var *v){  int i;  if(v->flags&REFERENCED) return;  v->flags|=REFERENCED;  if(ISFUNC(v->vtyp->flags)){    struct IC *p;    if(!(v->flags&DEFINED)) return;    if(!v->fi) ierror(0);    for(i=0;i<v->fi->call_cnt;i++){      if(v->fi->call_list[i].v->flags&DEFINED)	used_objects(v->fi->call_list[i].v);    }    /*FIXME: use/change aus fi */    for(p=v->fi->opt_ic;p;p=p->next){      if(p->q1.flags&VAR) used_objects(p->q1.v);      if(p->q2.flags&VAR) used_objects(p->q2.v);      if(p->z.flags&VAR) used_objects(p->z.v);    }  }else{    if(v->clist) used_clist(v->vtyp,v->clist);  }} zmax recalc_start_offset; void recalc_offsets(struct flowgraph *fg)/*  berechnet Offsets fuer auto-Variablen neu und versucht, fuer Variablen, *//*  die nicht gleichzeitig aktiv sind, den gleichen Platz zu belegen        */{  int i,b,*eqto;size_t bsize;zmax *al,*sz;  bvtype **used,*tmp,*empty;  struct IC *p;   if(DEBUG&1024) printf("recalculating offsets\n");  if(DEBUG&1024) printf("setting up arrays\n");  /*bsize=(basic_blocks+CHAR_BIT-1)/CHAR_BIT; /* we don's use fg->index but count from 0 */  bsize=BVSIZE(basic_blocks);  if(DEBUG&1024) printf("bsize=%lu\n",(unsigned long)bsize);  tmp=mymalloc(bsize);  al=mymalloc(sizeof(*al)*(vcount-rcount));  eqto=mymalloc(sizeof(int)*(vcount-rcount));  sz=mymalloc(sizeof(*sz)*(vcount-rcount));  empty=mymalloc(bsize);  memset(empty,0,bsize);  used=mymalloc(sizeof(bvtype *)*(vcount-rcount));  /*  Tabelle, welche Variable in welchem Block belegt ist, aufbauen  */  for(i=0;i<vcount-rcount;i++){    if(zmleq(l2zm(0L),vilist[i]->offset)&&(vilist[i]->storage_class==AUTO||vilist[i]->storage_class==REGISTER)){      if(DEBUG&2048) printf("setting up for %s,%ld\n",vilist[i]->identifier,zm2l(vilist[i]->offset));      used[i]=mymalloc(bsize);      memset(used[i],0,bsize);    }else{      used[i]=0;    }    sz[i]=szof(vilist[i]->vtyp);    al[i]=falign(vilist[i]->vtyp);    eqto[i]=-1;  }  b=0;  while(fg){    if(b>=basic_blocks) ierror(0);    for(i=0;i<vcount-rcount;i++){      if(used[i]&&(BTST(fg->av_in,i)||BTST(fg->av_out,i))){	int r;	BSET(used[i],b);	for(r=1;r<=MAXR;r++)	  if(fg->regv[r]&&fg->regv[r]->index==i) BCLR(used[i],b);      }    }    for(p=fg->start;p;p=p->next){      if((p->q1.flags&(VAR|REG))==VAR){	i=p->q1.v->index;	if(i!=-1){	  if(i<0||i>=vcount) ierror(0);	  if(i>=0&&used[i]){	    BSET(used[i],b);	  }	}      }      if((p->q2.flags&(VAR|REG))==VAR){	i=p->q2.v->index;	if(i!=-1){	  if(i<0||i>=vcount) ierror(0);	  if(i>=0&&used[i]){	    BSET(used[i],b);	  }	}      }      if((p->z.flags&(VAR|REG))==VAR){	i=p->z.v->index;	if(i!=-1){	  if(i<0||i>=vcount) ierror(0);	  if(i>=0&&used[i]){	    BSET(used[i],b);	  }	}      }      if(p==fg->end) break;    }    fg=fg->normalout;    b++;  }  /*  schauen, ob Variablen in gleichen Speicher koennen  */  if(DEBUG&1024) printf("looking for distinct variables\n");  for(i=0;i<vcount-rcount;i++){    if(!used[i]||eqto[i]>=0) continue;    if(!memcmp(used[i],empty,bsize)){ free(used[i]);used[i]=0;continue;}    for(b=i+1;b<vcount-rcount;b++){      if(!used[b]||eqto[b]>=0) continue;      if(!memcmp(used[b],empty,bsize)){ free(used[b]);used[b]=0;continue;}      if(DEBUG&2048) printf("comparing %s(%p) and %s(%p)\n",vilist[i]->identifier,(void *)vilist[i],vilist[b]->identifier,(void *)vilist[b]);            memcpy(tmp,used[i],bsize);      bvintersect(tmp,used[b],bsize);      if(!memcmp(tmp,empty,bsize)){	if(DEBUG&1024) printf("memory for %s(%p) and %s(%p) equal\n",vilist[i]->identifier,(void *)vilist[i],vilist[b]->identifier,(void *)vilist[b]);	eqto[b]=i;	if(!zmleq(al[b],al[i])) al[i]=al[b];	if(!zmleq(sz[b],sz[i])) sz[i]=sz[b];	bvunite(used[i],used[b],bsize);      }    }  }  if(DEBUG&1024) printf("final recalculating\n");  max_offset=recalc_start_offset;  for(i=0;i<vcount-rcount;i++){    if(!used[i]) continue;    free(used[i]);    if(DEBUG&2048) printf("adjusting offset for %s,%ld\n",vilist[i]->identifier,zm2l(vilist[i]->offset));    if(eqto[i]>=0){      vilist[i]->offset=vilist[eqto[i]]->offset;      continue;    }    vilist[i]->offset=zmmult(zmdiv(zmadd(max_offset,zmsub(al[i],l2zm(1L))),al[i]),al[i]);    max_offset=zmadd(vilist[i]->offset,sz[i]);  }  recalc_start_offset=l2zm(0L);  free(used);  free(sz);  free(al);  free(tmp);  free(empty);  free(eqto);}void remove_IC_fg(struct flowgraph *g,struct IC *p)/*  Entfernt IC p und beachtet Flussgraph. Ausserdem werden             *//*  use/change-Listen freigegeben.                                      */{  if(p->q1.am||p->q2.am||p->z.am) ierror(0);  if(have_alias){    free(p->use_list);    free(p->change_list);  }  if(g->start==g->end){    g->start=g->end=0;  }else{    if(p==g->end) g->end=p->prev;    if(p==g->start) g->start=p->next;  }  remove_IC(p);} /* allowed to create new variables */int early_peephole(void){  struct IC *p;  int changed,gchanged=0,c,t;  do{    changed=0;    p=first_ic;    while(p){      c=p->code;      t=p->typf;      if(c==COMPARE&&(p->q2.flags&KONST)&&ISINT(p->typf)){	struct case_table *ct;	if((ct=calc_case_table(p,JUMP_TABLE_DENSITY))&&ct->num>1&&ct->density==1){

Lines 1–500 of 1570.