blob: 79ad51348c7840959da857dc343ab47c1d590415 [file] [log] [blame]
/* $VER: vbcc (rd.c) $Revision: 1.16 $ */
/* reaching definitions and constant propagation */
#include "opt.h"
static char FILE_[]=__FILE__;
unsigned int dcount;
size_t dsize;
IC **dlist;
bvtype *rd_defs;
bvtype **defs_kill; /* definitions killed */
bvtype **defs_gen; /* definitions undefined */
bvtype **var_defs; /* definitions of a variable */
bvtype **var_undefs; /* definitions which are undefined by writing to this var */
bvtype *rd_matrix;
int def_overwrites(IC *new,IC *old);
#define NO_OVERWRITE 0
#define FULL_OVERWRITE 1
#define PARTIAL_OVERWRITE 2
#define EXACT_OVERWRITE 3
/* compares two constants; -1, if q1<q2; 0, if q1==q1; 1 otherwise */
int compare_const(union atyps *q1,union atyps *q2,int t)
{
zldouble d1,d2;zmax l1,l2;zumax u1,u2;
t&=NU;
eval_const(q1,t);d1=vldouble;l1=vmax;u1=vumax;
eval_const(q2,t);d2=vldouble;l2=vmax;u2=vumax;
if(ISFLOAT(t)) return(zldleq(d2,d1)?!zldeqto(d1,d2):-1);
if(ISPOINTER(t)||(t&UNSIGNED)) return(zumleq(u2,u1)?!zumeqto(u1,u2):-1);
return(zmleq(l2,l1)?!zmeqto(l1,l2):-1);
}
/* prints definitions in a bitvector */
void print_rd(bvtype *bitvector)
{
unsigned int i;
if(!bitvector) {printf("reaching definitions not available\n");return;}
for(i=1;i<=dcount;i++){
if(BTST(bitvector,i)) {printf("%3u:",i);pric2(stdout,dlist[i]);}
if(BTST(bitvector,UNDEF(i))) {printf("%3u(ud):",i);pric2(stdout,dlist[i]);}
}
}
/* numbers all definitions and creates some bitvectors */
void num_defs(void)
{
int i,j;IC *p;
size_t matrix_size;
bvtype *bp;
unsigned long heapsize=0;
if(DEBUG&1024) printf("numerating definitions\n");
i=0;
for(p=first_ic;p;p=p->next){
if(!(p->z.flags&(VAR|DREFOBJ))&&p->code!=CALL){p->defindex=0;continue;}
p->defindex=++i;
}
dcount=i;
/*dsize=(2*dcount+1+CHAR_BIT)/CHAR_BIT; /* +1, da bei 1 anfaengt */
dsize=BVSIZE(2*(dcount+1));
if(DEBUG&(16384|1024)) printf("%lu definitions, dsize=%lu\n",(unsigned long)dcount,(unsigned long)dsize);
/* get big memory block to store defs_kill, defs_gen, vars, var_defs and var_undefs */
matrix_size=(2*(dcount+vcount)*dsize);
rd_matrix=bp=mymalloc(matrix_size);
memset(bp,0,matrix_size);
heapsize+=matrix_size;
/* calculate bit-vector which contains all definitions killed or */
/* undefined (=partially overwritten) by this definition */
defs_kill=mymalloc(sizeof(*defs_kill)*(dcount+1));
defs_gen=mymalloc(sizeof(*defs_gen)*(dcount+1));
heapsize+=2*sizeof(*defs_kill)*(dcount+1);
for(i=1;i<=dcount;i++){
defs_kill[i]=bp;
bp+=dsize/sizeof(bvtype);
defs_gen[i]=bp;
bp+=dsize/sizeof(bvtype);
}
/* calculate bit vector with all undefined definitions of each variable */
var_defs=mymalloc(sizeof(*var_defs)*vcount);
heapsize+=sizeof(*var_defs)*vcount;
var_undefs=mymalloc(sizeof(*var_undefs)*vcount);
heapsize+=sizeof(*var_undefs)*vcount;
for(i=0;i<vcount;i++){
var_defs[i]=bp;
bp+=dsize/sizeof(bvtype);
var_undefs[i]=bp;
bp+=dsize/sizeof(bvtype);
}
/* calculate pointers to IC for every definition */
dlist=mymalloc((dcount+1)*sizeof(*dlist));
heapsize+=(dcount+1)*sizeof(*dlist);
for(p=first_ic;p;p=p->next){
if(p->defindex){
dlist[p->defindex]=p;
if(p->z.flags&VAR){
Var *v=p->z.v;
i=v->index;
if(p->z.flags&DREFOBJ) i+=vcount-rcount;
BSET(var_defs[i],p->defindex);
BSET(var_defs[i],UNDEF(p->defindex));
if(i<rcount){
BSET(var_defs[i+vcount-rcount],p->defindex);
BSET(var_defs[i+vcount-rcount],UNDEF(p->defindex));
}
BSET(var_undefs[i],UNDEF(p->defindex));
}
}
}
for(i=1;i<=dcount;i++){
p=dlist[i];
for(j=0;j<p->change_cnt;j++){
int idx;
idx=p->change_list[j].v->index;
if(p->change_list[j].flags&DREFOBJ) idx+=vcount-rcount;
if(idx>=vcount) continue;
BSET(var_defs[idx],i);
bvunite(defs_gen[i],var_undefs[idx],dsize);
}
if(p->z.flags&VAR){
for(j=1;j<=dcount;j++){
int ow;
IC *p2;
if(i==j) continue;
p2=dlist[j];
if(!(p2->z.flags&VAR)||p->z.v!=p2->z.v||p->z.flags!=p2->z.flags)
continue;
ow=def_overwrites(p,p2);
if(ow==FULL_OVERWRITE||ow==EXACT_OVERWRITE){
BSET(defs_kill[i],j);
BSET(defs_kill[i],UNDEF(j));
}
if(ow==EXACT_OVERWRITE||ow==NO_OVERWRITE){
BCLR(defs_gen[i],j);
BCLR(defs_gen[i],UNDEF(j));
}
}
}
/* every definition defines itself) */
BSET(defs_gen[i],i);
BCLR(defs_gen[i],UNDEF(i));
BSET(defs_kill[i],UNDEF(i));
}
if(DEBUG&2048){
for(i=0;i<vcount;i++){
printf("var_defs for var %i %s(%p):\n",i,vilist[i]->identifier,vilist[i]);
print_rd(var_defs[i]);
}
for(i=1;i<=dcount;i++){
printf("Def%3d: ",i);pric2(stdout,dlist[i]);
printf(" kills:\n");
for(j=1;j<=dcount;j++){
if(BTST(defs_kill[i],j)) {printf(" ");pric2(stdout,dlist[j]);}
if(BTST(defs_kill[i],UNDEF(j))) {printf(" (ud)");pric2(stdout,dlist[j]);}
}
printf(" gens:\n");
for(j=1;j<=dcount;j++){
if(BTST(defs_gen[i],j)) {printf(" ");pric2(stdout,dlist[j]);}
if(BTST(defs_gen[i],UNDEF(j))) {printf(" (ud)");pric2(stdout,dlist[j]);}
}
}
}
if(DEBUG&16384) printf("num_defs heapsize=%lu\n",heapsize);
free(var_undefs);
}
/* returns whether n overwrites the definition p */
int def_overwrites(IC *n,IC *o)
{
zmax nstart,nend,ostart,oend,nsize,osize;
if(!(n->z.flags&VAR)) ierror(0);
if(!(o->z.flags&VAR)) ierror(0);
if((n->z.flags&DREFOBJ)!=(o->z.flags&DREFOBJ)) ierror(0);
if(n->code==ASSIGN){
nsize=n->q2.val.vmax;
}else{
nsize=sizetab[ztyp(n)&NQ];
}
if(o->code==ASSIGN){
osize=o->q2.val.vmax;
}else{
osize=sizetab[ztyp(o)&NQ];
}
if(n->z.flags&DREFOBJ)
return zmleq(osize,nsize);
nstart=n->z.val.vmax;
nend=zmsub(zmadd(nstart,nsize),l2zm(1L));
ostart=o->z.val.vmax;
oend=zmsub(zmadd(ostart,osize),l2zm(1L));
if(zmeqto(nstart,ostart)&&zmeqto(nend,oend))
return EXACT_OVERWRITE;
if(zmleq(nstart,ostart)&&zmleq(oend,nend))
return FULL_OVERWRITE;
if(zmleq(ostart,nstart)&&zmleq(nstart,oend))
return PARTIAL_OVERWRITE;
if(zmleq(ostart,nend)&&zmleq(nend,oend))
return PARTIAL_OVERWRITE;
return NO_OVERWRITE;
}
/* performs data flow analysis for reaching definitions */
void reaching_definitions(flowgraph *fg)
{
flowgraph *g;IC *p;bvtype *tmp,*init;
int changed,pass,i,j;
unsigned long heapsize=0;
/* rd_gen und rd_kill fuer jeden Block berechnen */
if(DEBUG&1024) printf("analysing reaching definitions\n");
tmp=mymalloc(dsize);
init=mymalloc(dsize);
heapsize+=2*dsize;
memset(init,0,dsize);
for(i=1;i<=dcount;i++){
p=dlist[i];
if(p->z.flags&VAR){
Var *v=p->z.v;
if(v->storage_class==EXTERN||v->storage_class==STATIC||v->reg!=0||!zmleq(l2zm(0L),v->offset)){
BSET(init,UNDEF(i));
}
}
}
g=fg;
while(g){
g->rd_in=mymalloc(dsize);
memset(g->rd_in,0,dsize);
g->rd_out=mymalloc(dsize);
memset(g->rd_out,0,dsize);
g->rd_gen=mymalloc(dsize);
memset(g->rd_gen,0,dsize);
g->rd_kill=mymalloc(dsize);
memset(g->rd_kill,0,dsize);
heapsize+=4*dsize;
p=g->end;
while(p){
if(p->defindex){
bvunite(g->rd_gen,defs_gen[p->defindex],dsize);
bvdiff(g->rd_gen,g->rd_kill,dsize);
bvunite(g->rd_kill,defs_kill[p->defindex],dsize);
bvdiff(g->rd_kill,g->rd_gen,dsize);
}
if(p==g->start) break;
p=p->prev;
}
memcpy(g->rd_out,g->rd_gen,dsize);
g=g->normalout;
}
/* rd_in und rd_out fuer jeden Block berechnen */
/* out(b)=gen(B) vorinitialisiert */
if(DEBUG&1024) {printf("pass:");pass=0;}
do{
if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);}
changed=0;
g=fg;
while(g){
flowlist *lp;
/* in(B)=U out(C) : C Vorgaenger von B */
if(g==fg)
memcpy(g->rd_in,init,dsize);
else
memset(g->rd_in,0,dsize);
lp=g->in;
while(lp){
if(!lp->graph) ierror(0);
if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA)
bvunite(g->rd_in,lp->graph->rd_out,dsize);
lp=lp->next;
}
/* out(b)=gen(B) U (in(B)-kill(B) */
memcpy(tmp,g->rd_in,dsize);
bvdiff(tmp,g->rd_kill,dsize);
bvunite(tmp,g->rd_gen,dsize);
if(!bvcmp(tmp,g->rd_out,dsize)){changed=1;memcpy(g->rd_out,tmp,dsize);}
g=g->normalout;
}
}while(changed);
if(DEBUG&1024) printf("\n");
if(DEBUG&16384) printf("reaching_defs heapsize=%lu\n",heapsize);
free(tmp);
free(init);
}
/* calculates z:=q1 op q2 with constants */
/* if p is non-zero q1typ,q2typ from p will be used */
void calc(int c,int t,union atyps *q1,union atyps *q2,union atyps *z,IC *p)
{
zldouble d1,d2;zmax l1,l2;zumax u1,u2;
if(p) t=q1typ(p);
eval_const(q1,t);
d1=vldouble;l1=vmax;u1=vumax;
if(c!=MINUS&&c!=KOMPLEMENT){
if(p)
eval_const(q2,q2typ(p));
else
eval_const(q2,t);
d2=vldouble;l2=vmax;u2=vumax;
}
if(c==ADD){ vldouble=zldadd(d1,d2);vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
if(c==SUB){ vldouble=zldsub(d1,d2);vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
if(c==ADDI2P){ vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);}
if(c==SUBIFP){ vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);}
if(c==MULT){ vldouble=zldmult(d1,d2);vmax=zmmult(l1,l2);vumax=zummult(u1,u2);}
if(c==DIV||c==MOD){
if(zldeqto(d2,d2zld(0.0))&&zmeqto(l2,l2zm(0L))&&zumeqto(u2,ul2zum(0UL))){
err_ic=p;error(210);err_ic=0;
vmax=l2zm(0L);vumax=ul2zum(0L);vldouble=d2zld(0.0);
}else{
if(c==DIV){
vldouble=zlddiv(d1,d2);
if(!zmeqto(l2,l2zm(0L))) vmax=zmdiv(l1,l2);
if(!zumeqto(u2,ul2zum(0UL))) vumax=zumdiv(u1,u2);
}else{
if(!zmeqto(l2,l2zm(0L))) vmax=zmmod(l1,l2);
if(!zumeqto(u2,ul2zum(0UL))) vumax=zummod(u1,u2);
}
}
}
if(c==AND){ vmax=zmand(l1,l2);vumax=zumand(u1,u2);}
if(c==OR){ vmax=zmor(l1,l2);vumax=zumor(u1,u2);}
if(c==XOR){ vmax=zmxor(l1,l2);vumax=zumxor(u1,u2);}
if(c==LSHIFT){ vmax=zmlshift(l1,l2);vumax=zumlshift(u1,l2);}
if(c==RSHIFT){ vmax=zmrshift(l1,l2);vumax=zumrshift(u1,l2);}
if(c==MINUS){ vldouble=zldsub(d2zld(0.0),d1);vmax=zmsub(l2zm(0L),l1);vumax=zumsub(ul2zum(0UL),u1);}
if(c==KOMPLEMENT){ vmax=zmkompl(l1);vumax=zumkompl(u1);}
if(ISFLOAT(t)){
gval.vldouble=vldouble;
eval_const(&gval,LDOUBLE);
}else if(t&UNSIGNED){
gval.vumax=vumax;
eval_const(&gval,(UNSIGNED|MAXINT));
}else{
gval.vmax=vmax;
eval_const(&gval,MAXINT);
}
if(p) t=ztyp(p);
insert_const(z,t);
}
/* folds constant ICs */
int fold(IC *p)
{
int c;
if(!p) ierror(0);
c=p->code;
if(c==SUBPFP||c==ASSIGN||c==PUSH||c==SETRETURN) return 0;
if(DEBUG&1024) {printf("folding IC:\n");pric2(stdout,p);}
if(c==TEST||c==COMPARE){
union atyps val;int cc; /* condition codes */
IC *bp;
if(c==TEST){
eval_const(&p->q1.val,p->typf);
if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0)))
cc=0;
else
cc=1;
}else{
if(p->q1.flags&VARADR)
cc=compare_const(&p->q1.val,&p->q2.val,UNSIGNED|MAXINT);
else
cc=compare_const(&p->q1.val,&p->q2.val,p->typf);
}
bp=p->next;
if(bp->code>=BEQ&&bp->code<=BGT&&(!p->z.flags||p->z.v==bp->q1.v)){
if(DEBUG&1024) printf("(cc=%d; comparison eliminated)\n",cc);
if(have_alias){ free(p->use_list);free(p->change_list);}
remove_IC(p);
while(1){ /* zugehoerigen Branch suchen */
if(!bp||bp->code==LABEL||bp->code==BRA) ierror(0);
c=bp->code;
if(c>=BEQ&&c<=BGT) break;
bp=bp->next;
}
if((c==BEQ&&cc==0)||(c==BNE&&cc!=0)||(c==BLT&&cc<0)||(c==BGT&&cc>0)||(c==BLE&&cc<=0)||(c==BGE&&cc>=0)){
if(DEBUG&1024){ printf("changed following branch to BRA:\n");pric2(stdout,bp);}
bp->code=BRA;bp->q1.flags=0;
}else{
if(DEBUG&1024){ printf("removed following branch:\n");pric2(stdout,bp);}
if(have_alias){ free(bp->use_list);free(bp->change_list);}
remove_IC(bp);
}
return 1;
}
if(p->z.flags==0){
p->code=NOP;
p->q1.flags=p->q2.flags=p->z.flags=0;
return 1;
}else
return 0;
}
if(c==CONVERT){
eval_const(&p->q1.val,p->typf2);
insert_const(&p->q1.val,p->typf);
}else
calc(c,p->typf,&p->q1.val,&p->q2.val,&p->q1.val,p);
p->q2.flags=0;
if(p->code==ADDI2P||p->code==SUBIFP)
p->typf=p->typf2;
p->q2.val.vmax=sizetab[p->typf&NQ];
p->code=ASSIGN;
if(DEBUG&1024){printf("becomes\n");pric2(stdout,p);}
return 1;
}
/* tries to replace objects by constants and detects some uninitialized */
/* variables; if cponly==0, address-constants will be replaced, */
/* otherwise only real constants are replaced, sic points to the IC */
/* containing the object pointed to by o */
int propagate(IC *sic,obj *o,int cponly,int global)
{
unsigned int i,j,t,found;union atyps *val=0;
Var *v,*vaddr=0;IC *p;
zmax voff;
if(!o||!o->v) ierror(0);
if(cponly){
if(is_volatile_obj(o))
return 0;
}else{
if((o->flags&VAR)&&(o->v->vtyp->flags&VOLATILE))
return 0;
}
if(disable&8) return 0;
v=o->v;
i=v->index;
/* do not replace in ICs of the form move char with size!=1,
because these are builtin memcpy */
if(cponly&&sic->code==ASSIGN&&(sic->typf&NQ)==CHAR&&!zmeqto(sic->q2.val.vmax,l2zm(1L)))
return 0;
if(cponly&&(o->flags&DREFOBJ)) i+=vcount-rcount;
if(DEBUG&2048){
printf("propagate(cponly=%d) <%s>(%p)\n",cponly,o->v->identifier,(void *)v);
if(o->flags&DREFOBJ) printf("(DREFOBJ)");
printf("\nall reaching definitions:\n");print_rd(rd_defs);
printf("defs for var:\n");
print_rd(var_defs[i]);
}
if(v->nesting==0||v->storage_class==STATIC||v->storage_class==EXTERN){
/* Wenn moeglich bei statischen Variablen den Wert bei der */
/* Initialisierung ermitteln. */
/*if(cponly&&ISARITH(v->vtyp->flags)&&((v->vtyp->flags&CONST)||(v->nesting>0&&!(v->flags&(USEDASADR|USEDASDEST))))){*/
if(cponly&&is_const(v->vtyp)){
/* Variable hat noch den Wert der Initialisierung. */
if(v->clist){
int t;
if(o==&sic->q1) t=q1typ(sic);
else if(o==&sic->q2) t=q2typ(sic);
else if(o==&sic->z) t=ztyp(sic);
else ierror(0);
if(ISARITH(v->vtyp->flags)){
/* Der Wert der Initialisierung ist noch gespeichert. */
if(DEBUG&1024) printf("using static initializer\n");
o->val=v->clist->val;
o->flags=KONST;
return 1;
}else if(ISINT(t&NQ)){
int state;
if(DEBUG&1024) printf("using static initializer (new version)\n");
gval.vumax=get_clist_int(v->vtyp,v->clist,o->val.vmax,sizetab[t&NQ],&state);
if(state){
if(DEBUG&1024) printf("using static initializer (new version)\n");
eval_const(&gval,UNSIGNED|MAXINT);
insert_const(&o->val,t);
o->flags=KONST;
return 1;
}
}
}else{
/* Hier evtl. eine implizite 0 erkennen. */
}
}
}
found=0;
for(j=1;j<=dcount;j++){
if((!BTST(rd_defs,UNDEF(j))||!BTST(var_defs[i],UNDEF(j)))&&
(!BTST(rd_defs,j)||!BTST(var_defs[i],j))) continue;
found=1;
p=dlist[j];
if(!(p->z.flags&VAR)) return 0;
if(p->z.v!=o->v) continue;
t=ztyp(p)&NU;
if(cponly&&!ISSCALAR(t)) continue;
if(!zmeqto(p->z.val.vmax,o->val.vmax)) continue;
if(cponly){
if(p->z.flags!=o->flags) continue;
}else{
if((p->z.flags|DREFOBJ)!=o->flags) continue;
if(p->z.flags&DREFOBJ) continue;
}
if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))) return 0;
if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],j)) return 0;
if((p->code!=ASSIGN||((p->q1.flags&(KONST|DREFOBJ))!=KONST&&(p->q1.flags&(VARADR|DREFOBJ))!=VARADR))
&&(p->code!=ADDRESS||!(o->flags&DREFOBJ))) return 0;
if(p->q1.flags&KONST){
if(vaddr) return 0;
if(val){
if((p->typf&NQ)!=(t&NQ)) return 0;
if(compare_const(&p->q1.val,val,t)) return 0;
}else{
val=&p->q1.val;t=p->typf&NU;
}
}
if(p->code==ADDRESS||(p->q1.flags&VARADR)){
if(val) return 0;
if(vaddr){
if(p->q1.v!=vaddr||!zmeqto(p->q1.val.vmax,voff)) return 0;
}
vaddr=p->q1.v;
voff=p->q1.val.vmax;
}
}
/* found constant */
if(val){
if(cponly){
if(o==&sic->q1&&(q1typ(sic)&NQ)!=(t&NQ)) return 0;
if(o==&sic->q2&&(q2typ(sic)&NQ)!=(t&NQ)) return 0;
if(o==&sic->z&&(ztyp(sic)&NQ)!=(t&NQ)) return 0;
if(DEBUG&1024) printf("can replace %ld+<%s>(%p) by constant\n",zm2l(o->val.vmax),o->v->identifier,o->v);
/* TODO: do we need eval_const/insert_const (if representation of unsigned is different? */
o->val=*val;
o->flags=KONST;
}else{
if(DEBUG&1024) printf("can replace <%s> by constant address\n",o->v->identifier);
o->val=*val;
o->flags|=KONST;
o->flags&=~VAR;
o->v=0;
}
return 1;
}
if(vaddr&&(vaddr->storage_class==EXTERN||vaddr->storage_class==STATIC)){
if(DEBUG&1024) printf("can replace <%s> by varadr\n",o->v->identifier);
o->v=vaddr;
o->val.vmax=voff;
if((o->flags&DREFOBJ)&&!cponly)
o->flags=VAR;
else
o->flags=VAR|VARADR;
return 2;
}
if(vaddr&&(o->flags&DREFOBJ)){
t=vaddr->vtyp->flags&NU;
if(o==&sic->q1&&(q1typ(sic)&NU)!=t) return 0;
if(o==&sic->q2&&(q2typ(sic)&NU)!=t) return 0;
if(o==&sic->z&&(ztyp(sic)&NU)!=t) return 0;
if(DEBUG&1024) printf("can replace *<%s> by address\n",o->v->identifier);
o->v=vaddr;
o->val.vmax=voff;
o->flags&=~DREFOBJ;
return 2;
}
/* no definition found */
if(!found&&global&&v->storage_class!=EXTERN&&v->storage_class!=STATIC&&!(v->flags&USEDBEFORE)&&v->reg==0&&zmleq(l2zm(0L),v->offset)){
if(*v->identifier||!(optflags&4096)){
#ifdef HAVE_MISRA
/* removed */
#endif
error(171,v->identifier);v->flags|=USEDBEFORE;
if(!*v->identifier) {printf("<%p>\n",(void *)v);ierror(0);}
}
}
return 0;
}
/* searches for constant objects and uninitialized variables; if */
/* global!=0, reaching definitions are used, otherwise only local */
/* constant propagation will be done */
int constant_propagation(flowgraph *fg,int global)
{
IC *p;int changed=0,i,t;flowgraph *g;
rd_defs=mymalloc(dsize);
g=fg;
while(g){
if(global)
memcpy(rd_defs,g->rd_in,dsize);
else
memset(rd_defs,0,dsize);
p=g->start;
while(p){
int c=p->code;
/* if(DEBUG&1024){print_rd(rd_defs);pric2(stdout,p);}*/
if(c!=ADDRESS&&c!=NOP&&ISSCALAR(p->typf)&&(c<LABEL||c>BRA)){
if((p->q1.flags&(VAR|VARADR))==VAR){
if(!(q1typ(p)&VOLATILE)&&!is_volatile_obj(&p->q1))
changed|=propagate(p,&p->q1,1,global);
if((p->q1.flags&DREFOBJ)&&!(p->q1.v->vtyp->flags&VOLATILE))
changed|=propagate(p,&p->q1,0,global);
}
if((p->q2.flags&(VAR|VARADR))==VAR){
if(!(q2typ(p)&VOLATILE)&&!is_volatile_obj(&p->q2))
changed|=propagate(p,&p->q2,1,global);
if((p->q2.flags&DREFOBJ)&&!(p->q2.v->vtyp->flags&VOLATILE))
changed|=propagate(p,&p->q2,0,global);
}
}
/* only there to detect uninitialized variables */
if(((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ))){
if(!(p->z.v->vtyp->flags&VOLATILE))
changed|=propagate(p,&p->z,0,global);
}
rd_change(p);
if(p==g->end) break;
p=p->next;
}
break;
g=g->normalout;
}
gchanged|=changed;
free(rd_defs);
return changed;
}
/* performs changes to rd_defs which are caused by IC p */
void rd_change(IC *p)
{
if(DEBUG&4096) print_rd(rd_defs);
if(p->defindex){
bvdiff(rd_defs,defs_kill[p->defindex],dsize);
bvunite(rd_defs,defs_gen[p->defindex],dsize);
}
if(DEBUG&4096) pric2(stdout,p);
}