blob: 627fedde943e1aa7ef71d4a75fcf71f6cab866cb [file] [log] [blame]
/* $VER: vbcc (av.c) $Revision: 1.9 $ */
/* aktive Variablen und Elimination unnoetiger Anweisungen */
#include "opt.h"
static char FILE_[]=__FILE__;
/* fuer aktive Variablen */
Var **vilist;
unsigned int vcount; /* 0..vcount-rcount-1: vars, vcount-rcount..vcount: DREFOBJs */
unsigned int rcount;
size_t vsize;
bvtype *av_globals,*av_address,*av_statics,*av_drefs;
int report_dead_statements;
void print_av(bvtype *bitvector)
/* druckt Variablen in einem Bitvektor */
{
int i;
if(!bitvector) {printf("active variables not available\n");return;}
for(i=0;i<vcount-rcount;i++)
if(BTST(bitvector,i)) printf("%3d: %s,%ld\n",i,vilist[i]->identifier,zm2l(vilist[i]->offset));
for(i=vcount-rcount;i<vcount;i++)
if(BTST(bitvector,i)) printf("%3d: (%s),%ld\n",i,vilist[i]->identifier,zm2l(vilist[i]->offset));
}
static int clcnt;
/* walks through a clist and numbers variables whose addresses are
contained; if pass==-1, index is set to -1, if pass==0, index is set,
otherwise vilist
clcnt is used as index-counter in pass 0 */
void num_clist_refs(int pass,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)
return;
num_clist_refs(pass,t->next,cl->other);
}
return;
}
if(ISUNION(t->flags)){
num_clist_refs(pass,(*t->exact->sl)[0].styp,cl);
return;
}
if(ISSTRUCT(t->flags)&&!cl->tree){
type *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)
num_clist_refs(pass,st,cl->other);
cl=cl->next;
}
}
return;
}
if(cl->tree&&(cl->tree->o.flags&VARADR)){
Var *v=cl->tree->o.v;
if(pass==-1){
v->index=-1;
}else if(pass==0){
if(v->index<0) {v->index=clcnt++;v->inr=inr;}
}else{
if(v->index<0||v->index>=vcount-rcount)
ierror(0);
vilist[v->index]=v;
}
}
}
int inr;
void num_vars(void)
/* Numeriert Variablen und erzeugt Indexliste */
{
unsigned int i,j,done;IC *p;Var *v,*a[4],*vp;
unsigned long heapsize=0;
if(DEBUG&1024) printf("numerating variables loop1\n");
inr++;
/* alle Indizes auf -1 */
a[0]=vl0;
a[1]=vl1;
a[2]=vl2;
a[3]=vl3;
#if 1
for(j=0;j<4;j++){
v=a[j];
while(v){
v->index=-1;
/* Variablen von inline-Funktionen */
if(j==0&&v->fi&&v->fi->first_ic){
for(vp=v->fi->vars;vp;vp=vp->next) vp->index=-1;
}
v=v->next;
}
}
/* variables that may be referenced in inter-proc. dflow-info */
for(p=first_ic;p;p=p->next){
if(p->code==CALL&&(p->q1.flags&VAR)&&p->q1.v->fi){
function_info *fi=p->q1.v->fi;
if(fi->flags&ALL_USES){
for(i=0;i<fi->use_cnt;i++){
if(v=fi->use_list[i].v) fi->use_list[i].v->index=-1;
}
}
if(fi->flags&ALL_MODS){
for(i=0;i<fi->change_cnt;i++){
if(v=fi->change_list[i].v) fi->change_list[i].v->index=-1;
}
}
}
/* const-lists */
if((p->q1.flags&VAR))
if(p->q1.v->clist&&is_const(p->q1.v->vtyp)) num_clist_refs(-1,p->q1.v->vtyp,p->q1.v->clist);
if((p->q2.flags&VAR))
if(p->q2.v->clist&&is_const(p->q2.v->vtyp)) num_clist_refs(-1,p->q2.v->vtyp,p->q2.v->clist);
if((p->z.flags&VAR))
if(p->z.v->clist&&is_const(p->z.v->vtyp)) num_clist_refs(-1,p->z.v->vtyp,p->z.v->clist);
}
#endif
/* Do we need this? */
for(p=first_ic;p;p=p->next){
if(p->q1.flags&VAR) {p->q1.v->index=-1;p->q1.v->flags&=~USEDASADR;}
if(p->q2.flags&VAR) {p->q2.v->index=-1;p->q2.v->flags&=~USEDASADR;}
if(p->z.flags&VAR) {p->z.v->index=-1;p->z.v->flags&=~USEDASADR;}
}
/* erst alle Variablen, die als DREFOBJ benutzt werden */
if(DEBUG&1024) printf("numerating variables loop2\n");
i=0;
do{
done=1;
if(DEBUG&1024) printf("pass\n");
for(p=first_ic;p;p=p->next){
if(p->code<LABEL||p->code>BRA){
int c=p->code;
/* mark variables ad USEDASADR */
if(c==ADDRESS) p->q1.v->flags|=USEDASADR;
if(p->q1.flags&VARADR) p->q1.v->flags|=USEDASADR;
if(p->q2.flags&VARADR) p->q2.v->flags|=USEDASADR;
if(p->z.flags&VARADR) p->z.v->flags|=USEDASADR;
j=(q1typ(p)&NQ);
if((p->q1.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
v=p->q1.v;
if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
}
j=(q2typ(p)&NQ);
if((p->q2.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
v=p->q2.v;
if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
}
j=(ztyp(p)&NQ);
if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)){
v=p->z.v;
if(!v->vtyp->next||(v->vtyp->next->flags&NQ)!=j) v->flags|=DNOTTYPESAFE;
if(v->index<0) {v->index=i++;v->inr=inr;done=0;}
}
/* mark copies from DREFs also as DREFs (necessary?) (check z for !DREFOBJ?) */
if((c==ASSIGN||c==ADDI2P||c==SUBIFP)&&(p->q1.flags&VAR)&&p->q1.v->index>=0&&(p->z.flags&VAR)&&p->z.v->index<0){
if(!(p->z.flags&VAR)) ierror(0);
p->z.v->index=i++;p->z.v->inr=inr;done=0;
}
/* mark copies to DREFs as DREFs (because of copy-propagation */
/* and post-op reordering */
if((c==ASSIGN||c==ADDI2P||c==SUBIFP)&&(p->z.flags&VAR)&&p->z.v->index>=0&&(p->q1.flags&VAR)&&p->q1.v->index<0){
p->q1.v->index=i++;p->q1.v->inr=inr;done=0;
}
}
}
}while(!done);
if(DEBUG&1024) printf("numerating variables loop3\n");
rcount=i; /* Anzahl der DREFOBJ-Variablen */
/* jetzt den Rest */
for(p=first_ic;p;p=p->next){
int c=p->code;
if(1/*p->code<LABEL||p->code>BRA*/){
if((p->q1.flags&(VAR|DREFOBJ))==VAR){
j=(q1typ(p)&NQ);
v=p->q1.v;
if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
if(v->index<0) {v->index=i++;v->inr=inr;}
}
if((p->q2.flags&(VAR|DREFOBJ))==VAR){
j=(q2typ(p)&NQ);
v=p->q2.v;
if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
if(v->index<0) {v->index=i++;v->inr=inr;}
}
if((p->z.flags&(VAR|DREFOBJ))==VAR){
j=(ztyp(p)&NQ);
v=p->z.v;
if((v->vtyp->flags&NQ)!=j) v->flags|=NOTTYPESAFE;
if(v->index<0) {v->index=i++;v->inr=inr;}
}
}
/* const-lists */
if((p->q1.flags&VAR))
if(p->q1.v->clist&&is_const(p->q1.v->vtyp)) {clcnt=i;num_clist_refs(0,p->q1.v->vtyp,p->q1.v->clist);i=clcnt;}
if((p->q2.flags&VAR))
if(p->q2.v->clist&&is_const(p->q2.v->vtyp)) {clcnt=i;num_clist_refs(0,p->q2.v->vtyp,p->q2.v->clist);i=clcnt;}
if((p->z.flags&VAR))
if(p->z.v->clist&&is_const(p->z.v->vtyp)) {clcnt=i;num_clist_refs(0,p->z.v->vtyp,p->z.v->clist);i=clcnt;}
}
if(DEBUG&1024) printf("numerating variables loop4\n");
vcount=i+rcount; /* alle benutzten Variablen+Anzahl der DREFOBJs */
vilist=mymalloc(vcount*sizeof(Var *));
heapsize+=vcount*sizeof(Var *);
#if 0
for(j=0;j<4;j++){
int i;
v=a[j];
while(v){
i=v->index;
/* printf("%s has index %d\n",v->identifier,i);*/
if(i>=0){
if(i>=vcount-rcount) ierror(0);
vilist[i]=v;
if(i<rcount) vilist[i+vcount-rcount]=v;
}
/* Variablen von inline-Funktionen */
if(j==0&&v->fi&&v->fi->first_ic){
for(vp=v->fi->vars;vp;vp=vp->next){
i=vp->index;
if(i>=0){
if(i>=vcount-rcount) ierror(0);
vilist[i]=vp;
if(i<rcount) vilist[i+vcount-rcount]=vp;
}
}
}
v=v->next;
}
}
#endif
for(p=first_ic;p;p=p->next){
Var *v;
if(p->q1.flags&VAR){
i=p->q1.v->index;
vilist[i]=v=p->q1.v;
if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
}
if(p->q2.flags&VAR){
i=p->q2.v->index;
vilist[i]=v=p->q2.v;
if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
}
if(p->z.flags&VAR){
i=p->z.v->index;
vilist[i]=v=p->z.v;
if(v->clist&&is_const(v->vtyp)) num_clist_refs(1,v->vtyp,v->clist);
}
}
for(i=0;i<rcount;i++)
vilist[i+vcount-rcount]=vilist[i];
/*vsize=(vcount+CHAR_BIT-1)/CHAR_BIT;*/
vsize=BVSIZE(vcount);
if(DEBUG&(16384|1024)) printf("%lu variables (%lu DREFOBJs), vsize=%lu\n",(unsigned long)vcount,(unsigned long)rcount,(unsigned long)vsize);
av_drefs=mymalloc(vsize);
memset(av_drefs,0,vsize);
/* alle DREFOBJs */
for(i=vcount-rcount;i<vcount;i++) BSET(av_drefs,i);
/* av_globals enthaelt alle globalen Variablen und av_address */
/* zusaetzlich noch alle Variablen, deren Adressen genommen wurden */
av_globals=mymalloc(vsize);
memset(av_globals,0,vsize);
av_statics=mymalloc(vsize);
memset(av_statics,0,vsize);
av_address=mymalloc(vsize);
memcpy(av_address,av_globals,vsize);
heapsize+=4*vsize;
for(i=0;i<vcount-rcount;i++){
if(vilist[i]->nesting==0||vilist[i]->storage_class==EXTERN) BSET(av_globals,i);
if(vilist[i]->flags&USEDASADR) BSET(av_address,i);
if(vilist[i]->storage_class==STATIC) BSET(av_statics,i);
if(i<rcount){
/* if(!ISPOINTER(vilist[i]->vtyp->flags)){ printf("%s(%ld)\n",vilist[i]->identifier,zm2l(vilist[i]->offset));ierror(0);}*/
BSET(av_address,i+vcount-rcount);
BSET(av_globals,i+vcount-rcount);
}
}
if(DEBUG&16384) printf("num_vars heapsize=%lu\n",heapsize);
}
void print_vi(void)
/* Druckt vilist und testet Konsistenz */
{
int i;
printf("\nprint_vi()\n");
for(i=0;i<vcount;i++){
if(!vilist[i]||(i<rcount&&vilist[i]->index!=i)) ierror(0);
printf("%3d: %s\n",i,vilist[i]->identifier);
}
}
void av_change(IC *p,bvtype *use,bvtype *def)
/* Berechnet die Aenderungen, die sich durch IC p an use und def ergeben. */
{
int i,j,n=-1;
int g1,g2;
/* Wenn eine Quelle==Ziel, dann wird dadurch kein neuer use erzeugt, */
/* um z.B. unbenutzte Induktionsvariablen in Schleifen zu eliminieren. */
g1=compare_objs(&p->q1,&p->z,p->typf);
g2=compare_objs(&p->q2,&p->z,p->typf);
if(!g1&&(p->q1.flags&(VAR|DREFOBJ))==VAR) n=p->q1.v->index;
if(!g2&&(p->q2.flags&(VAR|DREFOBJ))==VAR) n=p->q2.v->index;
for(j=0;j<p->use_cnt;j++){
i=p->use_list[j].v->index;
if(p->use_list[j].flags&DREFOBJ) i+=vcount-rcount;
if(i>=vcount) continue;
if(i!=n&&!BTST(def,i)) BSET(use,i);
}
/* Ein Wert wird nicht zerstoert, wenn es kein elementarer Typ ist und */
/* die Groesse kleiner als die Variable (steht in alle solchen ICs in */
/* q2.val.max. */
if((p->z.flags&(VAR|DREFOBJ))==VAR&&(ISSCALAR(p->z.v->vtyp->flags)||p->z.v->vtyp->flags==0||zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp)))){
i=p->z.v->index;
if(i>=vcount) ierror(0);
if(g1&&g2&&!BTST(use,i)) BSET(def,i);
/* Wenn p geaendert wird, wird auch *p geaendert */
if(i<rcount&&!BTST(def,i+vcount-rcount)) BSET(use,i+vcount-rcount);
}
if((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&g1&&g2&&!(p->z.v->flags&DNOTTYPESAFE)){
i=p->z.v->index+vcount-rcount;
if(i>=vcount) ierror(0);
if(!BTST(use,i)) BSET(def,i);
}
}
void active_vars(flowgraph *fg)
/* analysiert aktive Variablen im Flussgraphen, nomain==0, wenn zu */
/* optimierende Funktion main() ist */
{
IC *p;
int changed,pass;flowgraph *g;
unsigned long heapsize=0;
if(DEBUG&1024){printf("analysing active variables\n");/*scanf("%d",&i);*/}
tmp=mymalloc(vsize);
heapsize+=vsize;
/* av_gen und av_kill fuer jeden Basic Block berechnen */
if(DEBUG&1024){printf("active_vars(): loop1\n");/*scanf("%d",&i);*/}
g=fg;
while(g){
g->av_gen=mymalloc(vsize);
memset(g->av_gen,0,vsize);
g->av_kill=mymalloc(vsize);
memset(g->av_kill,0,vsize);
g->av_in=mymalloc(vsize);
memset(g->av_in,0,vsize);
g->av_out=mymalloc(vsize);
memset(g->av_out,0,vsize);
heapsize+=4*vsize;
for(p=g->start;p;p=p->next){
av_change(p,g->av_gen,g->av_kill);
if(p==g->end) break;
}
g=g->normalout;
}
/* av_in und av_out fuer alle Bloecke berechnen */
if(DEBUG&1024){printf("active_vars(): loop2\npass: ");/*scanf("%d",&i);*/}
pass=0;
do{
if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
changed=0;
g=fg;
while(g){
/* out(B)=U in(C) ueber alle Nachfolger C von B */
memset(g->av_out,0,vsize); /* noetig? */
if(g->branchout) bvunite(g->av_out,g->branchout->av_in,vsize);
if((!g->end||g->end->code!=BRA)&&g->normalout) bvunite(g->av_out,g->normalout->av_in,vsize);
/* Am Ende muessen alle globalen Variablen bekannt sein */
if(!g->normalout){
bvunite(g->av_out,av_globals,vsize);
/*if(!nocall)*/ bvunite(g->av_out,av_statics,vsize);
}
/* in(B)=use(B)U(out(B)-def(B)) */
memcpy(tmp,g->av_out,vsize);
bvdiff(tmp,g->av_kill,vsize);
bvunite(tmp,g->av_gen,vsize);
if(!bvcmp(tmp,g->av_in,vsize)){changed=1;memcpy(g->av_in,tmp,vsize);}
g=g->normalout;
}
}while(changed);
if(DEBUG&1024) printf("\n");
free(tmp);
if(DEBUG&16384) printf("av heapsize=%lu\n",heapsize);
}
void av_update(IC *p,bvtype *isused)
{
int i,j;
if((p->z.flags&(VKONST|VAR))==VAR){
i=p->z.v->index;
if(p->z.flags&DREFOBJ) i+=vcount-rcount;
if(i<0||i>=vcount){
printf("i=%d\n",i);pric2(stdout,p); ierror(0);
}
if(p->z.flags&DREFOBJ){
if(!(p->z.v->flags&DNOTTYPESAFE))
BCLR(isused,i);
}else{
if(ISSCALAR(p->z.v->vtyp->flags)||(p->code==ASSIGN&&zmeqto(p->q2.val.vmax,szof(p->z.v->vtyp))))
BCLR(isused,i);
}
/* bei Zuweisung an p wird *p aktiv */
if(i<rcount) BSET(isused,i+vcount-rcount);
}
for(j=0;j<p->use_cnt;j++){
i=p->use_list[j].v->index;
if(p->use_list[j].flags&DREFOBJ) i+=vcount-rcount;
if(i<0||i>=vcount) continue;
BSET(isused,i);
}
}
/* tests, if IC p uses or modifies var v */
static int var_conflicts(Var *v,IC *p)
{
int i;
for(i=0;i<p->use_cnt;i++)
if(p->use_list[i].v==v&&!(p->use_list[i].flags&DREFOBJ))
return 1;
for(i=0;i<p->change_cnt;i++)
if(p->change_list[i].v==v&&!(p->change_list[i].flags&DREFOBJ))
return 1;
return 0;
}
int dead_assignments(flowgraph *fg)
/* Findet Zuweisungen, die unnoetig sind, da die Variable nie mehr */
/* benutzt werden kann. */
{
int changed=0;IC *p;bvtype *isused;
int i,j;
if(DEBUG&1024) printf("searching for dead assignments\n");
isused=mymalloc(vsize);
while(fg){
memcpy(isused,fg->av_out,vsize);
p=fg->end;
while(p){
if(p->z.flags&VAR){
i=p->z.v->index;
if(p->z.flags&DREFOBJ) i+=vcount-rcount;
if(!BTST(isused,i)&&!is_volatile_ic(p)&&!(disable&1)){
if(DEBUG&1024){printf("dead assignment deleted:\n");pric2(stdout,p);}
if(*p->z.v->identifier&&p->code!=ASSIGN){ err_ic=p;error(170,i>=vcount-rcount?"*":"",p->z.v->identifier);err_ic=0;}
/*if(p->code!=GETRETURN)*/ changed=1;
if(p==fg->start){remove_IC_fg(fg,p);break;}
p=p->prev;remove_IC_fg(fg,p->next);
continue;
}
}
if(p->code!=SETRETURN&&p->code!=TEST&&p->code!=COMPARE&&(p->q1.flags&VAR)&&!BTST(isused,p->q1.v->index)&&(!(p->z.flags&VAR)||!p->z.v->reg||p->z.v->identifier)){
IC *m,*a;int f=p->q1.flags,dt=p->q1.dtyp;
p->q1.flags&=~DREFOBJ;
a=p->prev;if(a) m=a->prev; else m=0;
if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->q1,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
if(DEBUG&1024){
printf("reorder post-op(q1):\n");
pric2(stdout,m);pric2(stdout,a);pric(stdout,p);
}
p->q1=a->q1;
m->next=p;p->prev=m;
if(p->next) p->next->prev=a;
a->next=p->next;
a->prev=p;p->next=a;
if(fg->end==p) fg->end=a;
if(p==last_ic) last_ic=a;
remove_IC_fg(fg,m);
av_update(a,isused);
p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
p->use_cnt+=a->use_cnt;
changed=1;
if((f&DREFOBJ)&&p->q1.v->index>=rcount)
ierror(0);
}
p->q1.flags=f;
p->q1.dtyp=dt;
}
if(p->code!=TEST&&p->code!=COMPARE&&(p->q2.flags&VAR)&&!BTST(isused,p->q2.v->index)&&(!(p->z.flags&VAR)||!p->z.v->reg||p->z.v->identifier)){
IC *m,*a;int f=p->q2.flags,dt=p->q2.dtyp;
p->q2.flags&=~DREFOBJ;
a=p->prev;if(a) m=a->prev; else m=0;
if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->q2,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
if(DEBUG&1024){
printf("reorder post-op(q2):\n");
pric2(stdout,m);pric2(stdout,a);pric(stdout,p);
}
p->q2=a->q1;
m->next=p;p->prev=m;
if(p->next) p->next->prev=a;
a->next=p->next;
a->prev=p;p->next=a;
if(fg->end==p) fg->end=a;
if(p==last_ic) last_ic=a;
remove_IC_fg(fg,m);
av_update(a,isused);
p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
p->use_cnt+=a->use_cnt;
changed=1;
if((f&DREFOBJ)&&p->q2.v->index>=rcount)
ierror(0);
}
p->q2.flags=f;
p->q2.dtyp=dt;
}
if(p->code!=TEST&&p->code!=COMPARE&&(p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ)&&!BTST(isused,p->z.v->index)){
IC *m,*a;int f=p->z.flags,dt=p->z.dtyp;
p->z.flags&=~DREFOBJ;
a=p->prev;if(a) m=a->prev; else m=0;
if(m&&a&&m->code==ASSIGN&&(a->q1.flags&(VAR|DREFOBJ))==VAR&&!compare_objs(&p->z,&m->z,0)&&!compare_objs(&a->q1,&a->z,0)&&!compare_objs(&m->q1,&a->z,0)&&(a->q2.flags&KONST)&&!var_conflicts(a->q1.v,p)){
if(DEBUG&1024){
printf("reorder post-op(z):\n");
pric2(stdout,m);pric2(stdout,a);pric2(stdout,p);
printf("--");
}
p->z=a->q1;
m->next=p;p->prev=m;
if(p->next) p->next->prev=a;
a->next=p->next;
a->prev=p;p->next=a;
if(fg->end==p) fg->end=a;
if(p==last_ic) last_ic=a;
remove_IC_fg(fg,m);
av_update(a,isused);
p->use_list=myrealloc(p->use_list,(p->use_cnt+a->use_cnt)*VLS);
memcpy(&p->use_list[p->use_cnt],a->use_list,a->use_cnt*VLS);
p->use_cnt+=a->use_cnt;
changed=1;
if((f&DREFOBJ)&&p->z.v->index>=rcount)
ierror(0);
}
p->z.flags=f;
p->z.dtyp=dt;
}
av_update(p,isused);
if(p==fg->start) break;
p=p->prev;
}
fg=fg->normalout;
}
free(isused);
return(changed);
}