Import VBCC source snapshot (29/04/2022)
diff --git a/alias.c b/alias.c
new file mode 100644
index 0000000..f0a942e
--- /dev/null
+++ b/alias.c
@@ -0,0 +1,822 @@
+/*  $VER: vbcc (alias.c) $Revision: 1.6 $  */
+/*  Listen benutzter/veraenderter Variablen und Behandlung von Decknamen.   */
+
+#include "opt.h"
+
+static char FILE_[]=__FILE__;
+
+static bvtype **gpt;
+
+static unsigned long ptsize;
+
+#define is_restrict(i) ((i)<=vcount-rcount&&(vilist[i]->vtyp->flags&RESTRICT))
+
+/* sets points-to-info for var i to undefined */
+void undef_pt(bvtype **pt,int i)
+{
+  if(i<0||i>=vcount) ierror(0);
+  if(pt[i]) ptsize-=vsize;
+  free(pt[i]);
+  pt[i]=0;
+  if(i<rcount){
+    i+=vcount-rcount;
+    if(pt[i]) ptsize-=vsize;
+    free(pt[i]);
+    pt[i]=0;
+  }
+}
+
+/* walks through a clist and sets the corresponding bit in bv
+   for every variable whose address is contained in the clist */
+void add_clist_refs(bvtype *bv,type *t,const_list *cl)
+{
+  /*FIXME: bei Aufrufen auch auf locale, nicht USEDASDEST|USEDASADDR */
+  int i;zmax sz;
+  if(ISARRAY(t->flags)){
+    for(sz=l2zm(0L);!zmleq(t->size,sz)&&cl;sz=zmadd(sz,l2zm(1L)),cl=cl->next){
+      if(!cl->other){ierror(0);return;}
+      add_clist_refs(bv,t->next,cl->other);
+    }
+    return;
+  }
+  if(ISUNION(t->flags)){
+    add_clist_refs(bv,(*t->exact->sl)[0].styp,cl);
+    return;
+  }
+  if(ISSTRUCT(t->flags)){
+    type *st;
+    for(i=0;i<t->exact->count&&cl;i++){
+      if(!cl->other){ierror(0);return;}
+      st=(*t->exact->sl)[i].styp;
+      if(!(*t->exact->sl)[i].identifier) ierror(0);
+      if((*t->exact->sl)[i].identifier[0]){
+        add_clist_refs(bv,st,cl->other);
+        cl=cl->next;
+      }
+    }
+    return;
+  }
+  if(cl->tree&&(cl->tree->o.flags&VARADR)){
+    /* careful: variable might not have a valid index if it is not
+       used within the function optimized */
+    i=cl->tree->o.v->index;
+    if(i>=0&&i<vcount-rcount&&vilist[i]==cl->tree->o.v){
+      /*printf("add %s\n",vilist[i]->identifier);*/
+      BSET(bv,i);
+    }
+  }
+}
+
+/* copies points-to-info for one var to another */
+void copy_pt(bvtype **pt,int to,int from)
+{
+  if(to<0||to>=vcount) ierror(0);
+  if(from<0||from>=vcount) ierror(0);
+  if(!pt[from]){
+    if(from>=vcount-rcount&&pt[from-(vcount-rcount)]){
+      /* if dref check, whether from only points to initialized const */
+      int i;bvtype *new;
+      for(i=0;i<vcount;i++){
+	if(BTST(pt[from-(vcount-rcount)],i)){
+	  Var *v=vilist[i];
+	  if(!is_const(v->vtyp)||!v->clist||(v->storage_class!=STATIC&&v->storage_class!=EXTERN))
+	    break;
+	}
+      }
+      if(i==vcount){
+	/* yes, take the points-to-info from clist */
+	if(!pt[to]||to+vcount-rcount==from){
+	  new=mymalloc(vsize);
+	  ptsize+=vsize;
+	}else
+	  new=pt[to];
+	memset(new,0,vsize);
+	for(i=0;i<vcount;i++){
+	  if(BTST(pt[from-(vcount-rcount)],i))
+	    add_clist_refs(new,vilist[i]->vtyp,vilist[i]->clist);
+	}
+	if(to+vcount-rcount==from){
+	  ptsize-=vsize;
+	  free(pt[to]);
+	}
+	pt[to]=new;
+	return;
+      }
+    }
+    undef_pt(pt,to);
+  }else{
+    if(!pt[to]){
+      pt[to]=mymalloc(vsize);
+      ptsize+=vsize;
+    }
+    memcpy(pt[to],pt[from],vsize);
+  }
+}
+
+/* set var i points only to j in points-to-info */
+void set_pt(bvtype **pt,int i,int j)
+{
+  if(i<0||i>=vcount) ierror(0);
+  if(j<0||j>=vcount) ierror(0);
+  if(!pt[i]){
+    pt[i]=mymalloc(vsize);
+    ptsize+=vsize;
+  }
+  memset(pt[i],0,vsize);
+  BSET(pt[i],j);
+}
+
+void print_single_pt(bvtype *pt)
+{
+  int j;
+  if(pt){
+    for(j=0;j<vcount;j++){
+      if(BTST(pt,j))
+	printf("  %s<%s>(%p)\n",(j>=vcount-rcount)?"*":"",vilist[j]->identifier,(void*)vilist[j]);
+    }
+  }else{
+    printf("  (undefined)\n");
+  }
+}
+
+void print_pt(bvtype **pt)
+{
+  int i,j;
+  if(!pt) return;
+  printf("points-to:\n");
+  for(i=0;i<vcount;i++){
+    printf("%s<%s>(%p):\n",(i>=vcount-rcount)?"*":"",vilist[i]->identifier,(void*)vilist[i]);
+    print_single_pt(pt[i]);
+  }
+}
+
+/* creates new points-to-info; every var set to undefined */
+bvtype **new_pt(void)
+{
+  bvtype **pt;
+  int i;
+  pt=mymalloc(vcount*sizeof(*pt));
+  ptsize+=vcount*sizeof(*pt);
+  for(i=0;i<vcount;i++){
+    if(i<rcount&&(vilist[i]->vtyp->flags&RESTRICT)){
+      pt[i]=mymalloc(vsize);
+      ptsize+=vsize;
+      memset(pt[i],0,vsize);
+      BSET(pt[i],i+vcount-rcount);
+    }else
+      pt[i]=0;
+  }
+  return pt;
+}
+
+void free_pt(bvtype **pt)
+{
+  int i;
+  if(pt){
+    for(i=0;i<vcount;i++){
+      if(pt[i]) ptsize-=vsize;
+      free(pt[i]);
+    }
+    ptsize-=vcount*sizeof(*pt);
+    free(pt);
+  }
+}
+
+/* set points-to-info of *v to union of points-to of all vars in the
+   points-to-info of v */
+void dref_pt(bvtype **pt,int i)
+{
+  int j,d;
+  if(i<0||i>=rcount) ierror(0);
+  d=i+vcount-rcount;
+  if(!pt[i]){
+    undef_pt(pt,d);
+    return;
+  }
+  if(!pt[d]){
+    pt[d]=mymalloc(vsize);
+    ptsize+=vsize;
+  }
+  memset(pt[d],0,vsize);
+  for(j=0;j<vcount;j++){
+    if(BTST(pt[i],j)){
+      Var *v=vilist[j];
+      if(v->clist&&is_const(v->vtyp)&&(v->storage_class==STATIC||v->storage_class==EXTERN)){
+	add_clist_refs(pt[d],v->vtyp,v->clist);
+      }else if(!pt[j]){
+	undef_pt(pt,d);
+	return;
+      }else
+	bvunite(pt[d],pt[j],vsize);
+    }
+  }
+}
+
+void trans_pt(bvtype **pt,IC *p)
+{
+  int i,j,newset=-1,sv,cp;
+  if((p->code==ADDI2P||p->code==SUBIFP)&&!compare_objs(&p->q1,&p->z,ztyp(p)))
+    return;
+  if((p->z.flags&VAR)&&ISSCALAR(p->z.v->vtyp->flags)){
+    i=p->z.v->index;
+    if(i<0||i>=vcount) ierror(0);
+    if(p->z.flags&DREFOBJ){
+      if(i>=rcount) ierror(0);
+      i+=vcount-rcount;
+    }
+    if(!is_restrict(i)){
+      if(p->code==ASSIGN){
+	newset=i;sv=-1;cp=-1;
+	if(p->q1.flags&VARADR){
+	  sv=p->q1.v->index;
+	  set_pt(pt,i,p->q1.v->index);
+	}else if(p->q1.flags&VAR){
+	  j=p->q1.v->index;
+	  if(j<0||j>=vcount) ierror(0);
+	  if(p->q1.flags&DREFOBJ){
+	    if(j>=rcount) ierror(0);
+	    j+=vcount-rcount;
+	  }
+	  cp=j;
+	  copy_pt(pt,i,j);
+	}else{
+	  if(!pt[i]){
+	    pt[i]=mymalloc(vsize);
+	    ptsize+=vsize;
+	  }
+	  memset(pt[i],0,vsize);
+	}
+      }  
+      if(p->code==ADDRESS){
+	newset=i;sv=p->q1.v->index;cp=-1;
+	set_pt(pt,i,p->q1.v->index);
+      }
+      if((p->code==ADDI2P||p->code==SUBIFP)&&(p->q1.flags&VAR)){
+	newset=i;sv=-1;cp=-1;
+	if(p->q1.flags&VARADR){
+	  sv=p->q1.v->index;
+	  set_pt(pt,i,p->q1.v->index);
+	}else{
+	  j=p->q1.v->index;
+	  if(j<0||j>=vcount) ierror(0);
+	  if(p->q1.flags&DREFOBJ){
+	    if(j>=rcount) ierror(0);
+	    j+=vcount-rcount;
+	  }
+	  cp=j;
+	  copy_pt(pt,i,j);
+	}
+      }
+    }
+  }
+  if(newset>=0&&newset<rcount){
+    if(newset<0) ierror(0);
+    dref_pt(pt,newset);
+  }
+  for(i=0;i<p->change_cnt;i++){
+    j=p->change_list[i].v->index;
+    if(j<0||j>=vcount) ierror(0);
+    if(p->change_list[i].flags&DREFOBJ){
+      if(j>=rcount) ierror(0);
+      j+=vcount-rcount;
+    }
+    if(j!=newset&&!is_restrict(j)){
+      if(newset>=0&&pt[j]){
+	if(sv>=0){
+	  if(sv>=vcount) ierror(0);
+	  BSET(pt[j],sv);
+	}
+	if(cp>=0&&pt[cp]){
+	  if(cp<0||cp>=vcount) ierror(0);
+	  bvunite(pt[j],pt[cp],vsize);
+	}
+      }else
+	undef_pt(pt,j);
+    }
+  }
+}
+
+bvtype **clone_pt(bvtype **pt)
+{
+  int i;
+  bvtype **new;
+  if(!pt)
+    return new_pt();
+  new=mymalloc(vcount*sizeof(*new));
+  ptsize+=vcount*sizeof(*new);
+  for(i=0;i<vcount;i++){
+    if(pt[i]){
+      new[i]=mymalloc(vsize);
+      ptsize+=vsize;
+      memcpy(new[i],pt[i],vsize);
+    }else
+      new[i]=0;
+  }
+  return new;
+}
+
+/* tests if two points-to-infos are identical */
+int equal_pt(bvtype **pt1,bvtype **pt2)
+{
+  int i;
+  if(!pt1&&!pt2) 
+    return 1;
+  if(!pt1||!pt2)
+    return 0;
+  for(i=0;i<vcount;i++){
+    if(!pt1[i]&&!pt2[i])
+      continue;
+    if(!pt1[i]||!pt2[i])
+      return 0;
+    if(memcmp(pt1[i],pt2[i],vsize))
+      return 0;
+  }
+  return 1;
+}
+#if 0
+void calc_pt(flowgraph *fg)
+{
+  flowgraph *g;
+  flowlist *in;
+  IC *p;
+  bvtype **pt,**ppt;
+  int i,all_preds,changed;
+
+  changed=1;
+  while(changed){
+    if(DEBUG&1024) printf("calc_pt pass\n");
+    changed=0;
+    for(g=fg;g;g=g->normalout){
+      /* do all predecessors already have points-to-info? */
+      all_preds=1;
+      for(in=g->in;in;in=in->next){
+	if(!in->graph->pt){
+	  all_preds=0;
+	  break;
+	}
+      }
+      if(all_preds&&g->in){
+	/* calc union of all predecessors */
+	pt=clone_pt(g->in->graph->pt);
+	for(in=g->in->next;in;in=in->next){
+	  ppt=in->graph->pt;
+	  for(i=0;i<vcount;i++){
+	    if(pt[i]){
+	      if(!ppt[i])
+		undef_pt(pt,i);
+	      else
+		bvunite(pt[i],ppt[i],vsize);
+	    }
+	  }
+	}
+      }else
+	pt=new_pt();
+      for(p=g->start;p;p=p->next){
+	trans_pt(pt,p);
+	if(p==g->end)
+	  break;
+      }
+      if(pt==g->pt) ierror(0);
+      if(!changed){
+	if(!equal_pt(pt,g->pt)){
+	  changed=1;
+	  free_pt(g->pt);
+	  g->pt=pt;
+	}else{
+	  free_pt(pt);
+	}
+      }else{
+	free_pt(g->pt);
+	g->pt=pt;
+      }
+    }
+  }
+}
+#endif
+int p_typ(Var *v)
+/*  Liefert den Typ, auf den Variable zeigen kann. Falls nicht eindeutig    */
+/*  wird CHAR zurueckgegeben, da ein char * auf alles zeigen kann.          */
+{
+    type *t=v->vtyp;int f;
+    /*  Kein Zeiger? Dann moeglicherweise Struktur, die verschiedene Zeiger */
+    /*  enthalten koennte. Koennte man evtl. noch genauer pruefen.          */
+    if(!ISPOINTER(t->flags)||!t->next||(v->flags&DNOTTYPESAFE)) return CHAR;
+    f=t->next->flags&NQ;
+    if(f==VOID) f=CHAR;
+    return f;
+}
+
+/* propagates information if a variable whose address may have been taken
+   is modified */
+static void propagate_pointers(bvtype *set,Var *v,int t,int i)
+{
+  int j,t2;
+  if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+    if(noaliasopt){
+      bvunite(set,av_drefs,vsize);
+    }else{
+      for(j=0;j<rcount;j++){
+	t2=p_typ(vilist[j]);
+	if(t==t2||t2==CHAR||!ISSCALAR(t)||!ISSCALAR(t2)){
+	  if(!gpt||!gpt[j]||(i>=0&&BTST(gpt[j],i)))
+	    BSET(set,j+vcount-rcount);
+	}	    
+      }
+    }
+  }
+}
+void alias_propagate(bvtype *set,int i,int t,int wr)
+{
+  int j,t2;
+  Var *v;
+  if(i<0||i>=vcount) ierror(0);
+  t&=NQ;
+  BSET(set,i);
+  if(wr&&i<rcount) BSET(set,i+vcount-rcount);
+  if(i>=vcount-rcount){
+    /* DREFOBJ */
+    if(noaliasopt||t==CHAR||!ISSCALAR(t)){
+      bvunite(set,av_drefs,vsize);
+      bvunite(set,av_address,vsize);
+      bvunite(set,av_globals,vsize);
+    }else{
+      for(j=0;j<vcount-rcount;j++){
+	v=vilist[j];
+	if(!gpt||!gpt[i-(vcount-rcount)]||BTST(gpt[i-(vcount-rcount)],j)){
+	  v=vilist[j];
+	  if(!v) ierror(0);
+	  if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+	    type *tp=v->vtyp;
+	    if(!v->vtyp) ierror(0);
+	    do{
+	      t2=tp->flags&NQ;
+	      tp=tp->next;
+	    }while(ISARRAY(t2));
+	    if(t==t2||!ISSCALAR(t2)){
+	      BSET(set,j);
+	      if(wr&&j<rcount) {BSET(set,j+vcount-rcount);continue;}
+	    }
+	  }
+	}
+	if(j<rcount){
+	  if(i<(vcount-rcount)) ierror(0);
+	  if(!gpt||
+	     (!gpt[i-(vcount-rcount)]&&!is_restrict(j))||
+	     (!gpt[j]&&!is_restrict(i-(vcount-rcount)))||
+	     (gpt[j]&&gpt[i-(vcount-rcount)]&&bvdointersect(gpt[i-(vcount-rcount)],gpt[j],vsize))){
+	    t2=p_typ(v);
+	    if(t==t2||t2==CHAR||!ISSCALAR(t2))
+	      BSET(set,j+vcount-rcount);
+	  }
+	}
+      }
+    }
+  }else{
+    v=vilist[i];
+    propagate_pointers(set,v,t,i);
+  }
+}
+
+void ic_changes(IC *p,bvtype *result)
+/*  Initialisiert den Bitvektor result mit allen Variablen, die durch das   */
+/*  IC p geaendert werden koennten.                                         */
+{
+    int i,j,t,t2;Var *v;
+    memset(result,0,vsize);
+    t=(ztyp(p)&NQ);
+    if(p->z.flags&VAR){
+        v=p->z.v;
+        i=v->index;
+        /*  Hilfsvariable, die waehrend diesem cse-Durchlauf eingefuehrt    */
+        /*  wurde.                                                          */
+        if(i<0) return;
+	if(i>=vcount) ierror(0);
+        if(p->z.flags&DREFOBJ){
+	  if(i>=rcount) ierror(0);
+	  alias_propagate(result,i+vcount-rcount,t,1);
+	}else{
+	  alias_propagate(result,i,t,1);
+	  if(i<rcount) BSET(result,i+vcount-rcount);
+	}
+    }
+    if(p->code==CALL){
+      function_info *fi;
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(fi=p->q1.v->fi)&&(fi->flags&ALL_MODS)&&!(disable&65536)){
+	/*  we can get the set from the function_info */
+	for(i=0;i<fi->change_cnt;i++){
+	  if(v=fi->change_list[i].v){
+	    if(v->inr==inr&&v->index>=0){
+	      if(v->index>=vcount) ierror(0);
+	      alias_propagate(result,v->index,v->vtyp->flags&NQ,1);
+	    }else
+	      propagate_pointers(result,v,v->vtyp->flags&NQ,-1);
+	  }else{
+	    for(j=0;j<vcount-rcount;j++){
+	      v=vilist[j];
+	      if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+		t=v->vtyp->flags&NQ;
+		if(t==(fi->change_list[i].flags&NQ)||!ISSCALAR(t)){
+		  BSET(result,j);
+		  if(j<rcount) BSET(result,j+vcount-rcount);
+		}
+	      }
+	      if(j<rcount){
+		t=p_typ(vilist[j]);
+		if(t==CHAR||!ISSCALAR(t)||t==fi->change_list[i].flags)
+		  BSET(result,j+vcount-rcount);
+	      }
+	    }
+	  }
+	}
+      }else{
+	bvunite(result,av_drefs,vsize);
+	bvunite(result,av_address,vsize);
+	bvunite(result,av_globals,vsize);
+	bvunite(result,av_statics,vsize);
+      }
+    }
+    if((p->z.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      bvunite(result,av_drefs,vsize);
+    }
+}
+void ic_uses(IC *p,bvtype *result)
+/*  Initialisiert den Bitvektor result mit allen Variablen, die durch das   */
+/*  IC p benutzt werden koennten.                                           */
+{
+    int i,j,t,t2,c;Var *v;type *tp;
+    memset(result,0,vsize);
+    c=p->code;
+    if(c!=ADDRESS){
+        if((p->q1.flags&(VAR|VARADR))==VAR&&c!=ADDRESS&&(c!=CALL||(p->q1.flags&DREFOBJ))){
+            v=p->q1.v;
+            i=v->index;
+	    if(i<0||i>=vcount) ierror(0);
+	    t=q1typ(p);
+	    if(p->q1.flags&DREFOBJ){
+	      if(i>=rcount) ierror(0);
+	      alias_propagate(result,i+vcount-rcount,t,0);
+	    }
+	    alias_propagate(result,i,t,0);
+        }
+        if((p->q2.flags&(VAR|VARADR))==VAR){
+            v=p->q2.v;
+            i=v->index;
+	    if(i<0||i>=vcount) ierror(0);
+	    t=q2typ(p);
+	    if(p->q2.flags&DREFOBJ){
+	      if(i>=rcount) ierror(0);
+	      alias_propagate(result,i+vcount-rcount,t,0);
+	    }
+	    alias_propagate(result,i,t,0);
+        }
+    }
+    if((p->z.flags&(VAR|VARADR|DREFOBJ))==(VAR|DREFOBJ)){
+        v=p->z.v;
+        i=v->index;
+        if(i>=vcount) {pric2(stdout,p);ierror(0);}
+	t=(ztyp(p)&NQ);
+	alias_propagate(result,i,t,0);
+    }
+    if(p->code==CALL){
+      function_info *fi;
+      if((p->q1.flags&(VAR|DREFOBJ))==VAR&&(fi=p->q1.v->fi)&&(fi->flags&ALL_USES)&&!(disable&65536)){
+	/*  we can get the set from the function_info */
+	for(i=0;i<fi->use_cnt;i++){
+	  if(v=fi->use_list[i].v){
+	    if(v->inr==inr&&v->index>=0)
+	      alias_propagate(result,v->index,v->vtyp->flags&NQ,0);
+	    else
+	      propagate_pointers(result,v,v->vtyp->flags&NQ,-1);
+	  }else{
+	    for(j=0;j<vcount-rcount;j++){
+	      v=vilist[j];
+	      if(v->nesting==0||v->storage_class==EXTERN||(v->flags&USEDASADR)){
+		t=v->vtyp->flags&NQ;
+		if(t==(fi->use_list[i].flags&NQ)||!ISSCALAR(t))
+		  BSET(result,j);
+	      }
+	      if(j<rcount){
+		t=p_typ(vilist[j]);
+		if(t==CHAR||!ISSCALAR(t)||t==fi->use_list[i].flags)
+		  BSET(result,j+vcount-rcount);
+	      }
+	    }
+	  }
+	}
+      }else{
+	bvunite(result,av_drefs,vsize);
+	bvunite(result,av_address,vsize);
+	bvunite(result,av_globals,vsize);
+	bvunite(result,av_statics,vsize);
+      }
+    }
+    if((p->q1.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      bvunite(result,av_drefs,vsize);
+    }
+    if((p->q2.flags&(KONST|DREFOBJ))==(KONST|DREFOBJ)){
+      bvunite(result,av_drefs,vsize);
+    }
+}
+void free_alias(flowgraph *fg)
+/*  Gibt alle use/change-Listen der ICs im Flussgraphen frei.               */
+{
+    IC *p;flowgraph *g;
+    if(DEBUG&1024) printf("freeing alias info\n");
+    for(g=fg;g;g=g->normalout){
+        for(p=g->start;p;p=p->next){
+            if(p->code==LABEL&&(p->use_cnt>0||p->change_cnt>0)) ierror(0);
+            if(p->use_cnt>0) {free(p->use_list);p->use_cnt=0;}
+            if(p->change_cnt>0) {free(p->change_list);p->change_cnt=0;}
+            if(p==g->end) break;
+        }
+    }
+    have_alias=0;
+}
+void create_alias(flowgraph *fg)
+/*  Initialisiert jedes IC mit einer Liste aller Variablen, die dadurch     */
+/*  benutzt und veraendert werden koennten. Z.Z. wird bis auf Typ-basierte  */
+/*  Optimierungen der worst-case angenommen.                                */
+{
+  bvtype *vars=mymalloc(vsize);
+  IC *p;flowgraph *g;
+  flowlist *in;
+  bvtype **ppt;
+  int i,cnt,all_preds,changed;
+  unsigned long heapsize;
+  if(DEBUG&1024) printf("creating alias info\n");
+
+  ptsize=0;
+  
+  changed=1;
+  while(changed){
+    if(DEBUG&1024) printf("create_alias pass\n");
+    changed=0;
+    if(have_alias)
+      free_alias(fg);
+    heapsize=0;
+    for(g=fg;g;g=g->normalout){
+      if((optflags&1024)&&!noaliasopt){
+	/* do all predecessors already have points-to-info? */
+	all_preds=1;
+	for(in=g->in;in;in=in->next){
+	  if(!in->graph->pt){
+	    all_preds=0;
+	    break;
+	  }
+	}
+	if(/*all_preds&&*/g->in){
+	  /* calc union of all predecessors */
+	  gpt=clone_pt(g->in->graph->pt);
+	  for(in=g->in->next;in;in=in->next){
+	    ppt=in->graph->pt;
+	    if(!ppt)
+	      continue;
+	    for(i=0;i<vcount;i++){
+	      if(gpt[i]){
+		if(!ppt[i])
+		  undef_pt(gpt,i);
+		else
+		  bvunite(gpt[i],ppt[i],vsize);
+	      }
+	    }
+	  }
+	}else
+	  gpt=new_pt();                 
+      }else{
+	gpt=0;
+      }
+      for(p=g->start;p;p=p->next){
+	int da; /* always consider a direct write, even if variable is const-qualified */
+	ic_uses(p,vars);
+	for(i=0,cnt=0;i<vcount;i++)
+	  if(BTST(vars,i)) cnt++;
+	p->use_cnt=cnt;
+	if(cnt==0){
+	  p->use_list=0;
+	}else{
+	  p->use_list=mymalloc(cnt*VLS);
+	  heapsize+=cnt*VLS;
+	  for(cnt=0,i=0;i<vcount;i++){
+	    if(BTST(vars,i)){
+	      p->use_list[cnt].v=vilist[i];
+	      if(i>=vcount-rcount) p->use_list[cnt].flags=DREFOBJ;
+	      else         p->use_list[cnt].flags=0;
+	      cnt++;
+	    }
+	  }
+	}
+	ic_changes(p,vars);
+	if((p->z.flags&(VAR|DREFOBJ))==VAR)
+	  da=p->z.v->index;
+	else
+	  da=0;
+	for(i=0,cnt=0;i<vcount;i++)
+	  if(BTST(vars,i)&&(i>=vcount-rcount||i==da||!is_const(vilist[i]->vtyp))) cnt++;
+	p->change_cnt=cnt;
+	if(cnt==0){
+	  p->change_list=0;
+	}else{
+	  p->change_list=mymalloc(cnt*VLS);
+	  heapsize+=cnt*VLS;
+	  for(cnt=0,i=0;i<vcount;i++){
+	    if(BTST(vars,i)&&(i>=vcount-rcount||i==da||!is_const(vilist[i]->vtyp))){
+	      p->change_list[cnt].v=vilist[i];
+	      if(i>=vcount-rcount) p->change_list[cnt].flags=DREFOBJ;
+	      else         p->change_list[cnt].flags=0;
+	      cnt++;
+	    }
+	  }
+	}
+
+	if(p->code==CALL){
+	  if((p->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
+	    int i=p->q1.v->index;
+	    if(i<0||i>=vcount) ierror(0);
+	    if(gpt&&gpt[i]){
+	      int j,cnt;
+	      for(cnt=0,j=0;j<vcount-rcount;j++){
+		if(BTST(gpt[i],j)&&ISFUNC(vilist[j]->vtyp->flags))
+		  cnt++;
+	      }
+	      if(cnt){
+		if(p->call_cnt) free(p->call_list);
+		p->call_cnt=cnt;
+		p->call_list=mymalloc(sizeof(*p->call_list)*cnt);
+		for(cnt=0,j=0;j<vcount-rcount;j++){
+		  if(BTST(gpt[i],j)&&ISFUNC(vilist[j]->vtyp->flags)){
+		    p->call_list[cnt].v=vilist[j];
+		    p->call_list[cnt].flags=0;
+		    cnt++;
+		  }
+		}
+		if(cnt==1&&all_preds){
+		  if(DEBUG&1024) {printf("replacing indirect call by single target:\n");pric2(stdout,p);}
+		  p->q1.flags=VAR;
+		  p->q1.val.vmax=l2zm(0L);
+		  p->q1.v=p->call_list[0].v;
+		}
+	      }
+	    }
+	  }	  
+	}
+
+	if((optflags&1024)&&!noaliasopt)
+	  trans_pt(gpt,p);
+	if(p==g->end) break;
+      }
+      if((optflags&1024)&&!noaliasopt){
+	if(!changed){
+	  if(!equal_pt(gpt,g->pt)){
+	    changed=1;
+	    free_pt(g->pt);
+	    g->pt=gpt;
+	  }else{
+	    free_pt(gpt);
+	  }
+	}else{
+	  free_pt(g->pt);
+	  g->pt=gpt;
+	}          
+      }           
+    }
+    if(DEBUG&16384) printf("create_alias heapsize=%lu\n",heapsize);
+    have_alias=1;
+  }
+  if(DEBUG&16384) printf("points-to heapsize=%lu\n",ptsize);
+  if((optflags&1024)&&!noaliasopt){
+    for(g=fg;g;g=g->normalout){
+      free_pt(g->pt);
+      g->pt=0;
+    }
+  }
+  free(vars);
+}
+#if 1
+void update_alias(Var *old,Var *new)
+/*  Aendert alle use/changes von (old) auf (new). Wird aufgerufen, wenn     */
+/*  copy-propagation eine Variable neu zu einem DREFOBJ macht.              */
+{
+    IC *p;int i;
+    if(DEBUG&1024) printf("update-alias\n");
+    for(p=first_ic;p;p=p->next){
+        for(i=0;i<p->use_cnt;i++){
+            if(p->use_list[i].v==old&&(p->use_list[i].flags&DREFOBJ)){
+                p->use_cnt++;
+                p->use_list=myrealloc(p->use_list,p->use_cnt*VLS);
+                p->use_list[p->use_cnt-1].v=new;
+                p->use_list[p->use_cnt-1].flags=DREFOBJ;
+                break;
+            }
+        }
+        for(i=0;i<p->change_cnt;i++){
+	  if(p->change_list[i].v==new||(p->change_list[i].v==old&&(p->change_list[i].flags&DREFOBJ))){
+                p->change_cnt++;
+                p->change_list=myrealloc(p->change_list,p->change_cnt*VLS);
+                p->change_list[p->change_cnt-1].v=new;
+                p->change_list[p->change_cnt-1].flags=DREFOBJ;
+                break;
+            }
+        }
+    }
+}
+#endif