PulkoMandy | 17fc759 | 2022-07-28 18:27:54 +0200 | [diff] [blame] | 1 | /* $VER: vbcc (rd.c) $Revision: 1.16 $ */ |
| 2 | /* reaching definitions and constant propagation */ |
| 3 | |
| 4 | #include "opt.h" |
| 5 | |
| 6 | static char FILE_[]=__FILE__; |
| 7 | |
| 8 | unsigned int dcount; |
| 9 | size_t dsize; |
| 10 | IC **dlist; |
| 11 | bvtype *rd_defs; |
| 12 | bvtype **defs_kill; /* definitions killed */ |
| 13 | bvtype **defs_gen; /* definitions undefined */ |
| 14 | bvtype **var_defs; /* definitions of a variable */ |
| 15 | bvtype **var_undefs; /* definitions which are undefined by writing to this var */ |
| 16 | bvtype *rd_matrix; |
| 17 | |
| 18 | int def_overwrites(IC *new,IC *old); |
| 19 | #define NO_OVERWRITE 0 |
| 20 | #define FULL_OVERWRITE 1 |
| 21 | #define PARTIAL_OVERWRITE 2 |
| 22 | #define EXACT_OVERWRITE 3 |
| 23 | |
| 24 | /* compares two constants; -1, if q1<q2; 0, if q1==q1; 1 otherwise */ |
| 25 | int compare_const(union atyps *q1,union atyps *q2,int t) |
| 26 | { |
| 27 | zldouble d1,d2;zmax l1,l2;zumax u1,u2; |
| 28 | t&=NU; |
| 29 | eval_const(q1,t);d1=vldouble;l1=vmax;u1=vumax; |
| 30 | eval_const(q2,t);d2=vldouble;l2=vmax;u2=vumax; |
| 31 | if(ISFLOAT(t)) return(zldleq(d2,d1)?!zldeqto(d1,d2):-1); |
| 32 | if(ISPOINTER(t)||(t&UNSIGNED)) return(zumleq(u2,u1)?!zumeqto(u1,u2):-1); |
| 33 | return(zmleq(l2,l1)?!zmeqto(l1,l2):-1); |
| 34 | } |
| 35 | |
| 36 | /* prints definitions in a bitvector */ |
| 37 | void print_rd(bvtype *bitvector) |
| 38 | { |
| 39 | unsigned int i; |
| 40 | if(!bitvector) {printf("reaching definitions not available\n");return;} |
| 41 | for(i=1;i<=dcount;i++){ |
| 42 | if(BTST(bitvector,i)) {printf("%3u:",i);pric2(stdout,dlist[i]);} |
| 43 | if(BTST(bitvector,UNDEF(i))) {printf("%3u(ud):",i);pric2(stdout,dlist[i]);} |
| 44 | } |
| 45 | } |
| 46 | |
| 47 | /* numbers all definitions and creates some bitvectors */ |
| 48 | void num_defs(void) |
| 49 | { |
| 50 | int i,j;IC *p; |
| 51 | size_t matrix_size; |
| 52 | bvtype *bp; |
| 53 | unsigned long heapsize=0; |
| 54 | if(DEBUG&1024) printf("numerating definitions\n"); |
| 55 | i=0; |
| 56 | for(p=first_ic;p;p=p->next){ |
| 57 | if(!(p->z.flags&(VAR|DREFOBJ))&&p->code!=CALL){p->defindex=0;continue;} |
| 58 | p->defindex=++i; |
| 59 | } |
| 60 | dcount=i; |
| 61 | /*dsize=(2*dcount+1+CHAR_BIT)/CHAR_BIT; /* +1, da bei 1 anfaengt */ |
| 62 | dsize=BVSIZE(2*(dcount+1)); |
| 63 | if(DEBUG&(16384|1024)) printf("%lu definitions, dsize=%lu\n",(unsigned long)dcount,(unsigned long)dsize); |
| 64 | |
| 65 | /* get big memory block to store defs_kill, defs_gen, vars, var_defs and var_undefs */ |
| 66 | matrix_size=(2*(dcount+vcount)*dsize); |
| 67 | rd_matrix=bp=mymalloc(matrix_size); |
| 68 | memset(bp,0,matrix_size); |
| 69 | heapsize+=matrix_size; |
| 70 | |
| 71 | /* calculate bit-vector which contains all definitions killed or */ |
| 72 | /* undefined (=partially overwritten) by this definition */ |
| 73 | defs_kill=mymalloc(sizeof(*defs_kill)*(dcount+1)); |
| 74 | defs_gen=mymalloc(sizeof(*defs_gen)*(dcount+1)); |
| 75 | heapsize+=2*sizeof(*defs_kill)*(dcount+1); |
| 76 | |
| 77 | for(i=1;i<=dcount;i++){ |
| 78 | defs_kill[i]=bp; |
| 79 | bp+=dsize/sizeof(bvtype); |
| 80 | defs_gen[i]=bp; |
| 81 | bp+=dsize/sizeof(bvtype); |
| 82 | } |
| 83 | |
| 84 | /* calculate bit vector with all undefined definitions of each variable */ |
| 85 | var_defs=mymalloc(sizeof(*var_defs)*vcount); |
| 86 | heapsize+=sizeof(*var_defs)*vcount; |
| 87 | var_undefs=mymalloc(sizeof(*var_undefs)*vcount); |
| 88 | heapsize+=sizeof(*var_undefs)*vcount; |
| 89 | for(i=0;i<vcount;i++){ |
| 90 | var_defs[i]=bp; |
| 91 | bp+=dsize/sizeof(bvtype); |
| 92 | var_undefs[i]=bp; |
| 93 | bp+=dsize/sizeof(bvtype); |
| 94 | } |
| 95 | |
| 96 | /* calculate pointers to IC for every definition */ |
| 97 | dlist=mymalloc((dcount+1)*sizeof(*dlist)); |
| 98 | heapsize+=(dcount+1)*sizeof(*dlist); |
| 99 | |
| 100 | for(p=first_ic;p;p=p->next){ |
| 101 | if(p->defindex){ |
| 102 | dlist[p->defindex]=p; |
| 103 | if(p->z.flags&VAR){ |
| 104 | Var *v=p->z.v; |
| 105 | i=v->index; |
| 106 | if(p->z.flags&DREFOBJ) i+=vcount-rcount; |
| 107 | BSET(var_defs[i],p->defindex); |
| 108 | BSET(var_defs[i],UNDEF(p->defindex)); |
| 109 | if(i<rcount){ |
| 110 | BSET(var_defs[i+vcount-rcount],p->defindex); |
| 111 | BSET(var_defs[i+vcount-rcount],UNDEF(p->defindex)); |
| 112 | } |
| 113 | BSET(var_undefs[i],UNDEF(p->defindex)); |
| 114 | } |
| 115 | } |
| 116 | } |
| 117 | |
| 118 | for(i=1;i<=dcount;i++){ |
| 119 | p=dlist[i]; |
| 120 | for(j=0;j<p->change_cnt;j++){ |
| 121 | int idx; |
| 122 | idx=p->change_list[j].v->index; |
| 123 | if(p->change_list[j].flags&DREFOBJ) idx+=vcount-rcount; |
| 124 | if(idx>=vcount) continue; |
| 125 | BSET(var_defs[idx],i); |
| 126 | bvunite(defs_gen[i],var_undefs[idx],dsize); |
| 127 | } |
| 128 | if(p->z.flags&VAR){ |
| 129 | for(j=1;j<=dcount;j++){ |
| 130 | int ow; |
| 131 | IC *p2; |
| 132 | if(i==j) continue; |
| 133 | p2=dlist[j]; |
| 134 | if(!(p2->z.flags&VAR)||p->z.v!=p2->z.v||p->z.flags!=p2->z.flags) |
| 135 | continue; |
| 136 | ow=def_overwrites(p,p2); |
| 137 | if(ow==FULL_OVERWRITE||ow==EXACT_OVERWRITE){ |
| 138 | BSET(defs_kill[i],j); |
| 139 | BSET(defs_kill[i],UNDEF(j)); |
| 140 | } |
| 141 | if(ow==EXACT_OVERWRITE||ow==NO_OVERWRITE){ |
| 142 | BCLR(defs_gen[i],j); |
| 143 | BCLR(defs_gen[i],UNDEF(j)); |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | /* every definition defines itself) */ |
| 148 | BSET(defs_gen[i],i); |
| 149 | BCLR(defs_gen[i],UNDEF(i)); |
| 150 | BSET(defs_kill[i],UNDEF(i)); |
| 151 | } |
| 152 | |
| 153 | if(DEBUG&2048){ |
| 154 | for(i=0;i<vcount;i++){ |
| 155 | printf("var_defs for var %i %s(%p):\n",i,vilist[i]->identifier,vilist[i]); |
| 156 | print_rd(var_defs[i]); |
| 157 | } |
| 158 | |
| 159 | for(i=1;i<=dcount;i++){ |
| 160 | printf("Def%3d: ",i);pric2(stdout,dlist[i]); |
| 161 | printf(" kills:\n"); |
| 162 | for(j=1;j<=dcount;j++){ |
| 163 | if(BTST(defs_kill[i],j)) {printf(" ");pric2(stdout,dlist[j]);} |
| 164 | if(BTST(defs_kill[i],UNDEF(j))) {printf(" (ud)");pric2(stdout,dlist[j]);} |
| 165 | } |
| 166 | printf(" gens:\n"); |
| 167 | for(j=1;j<=dcount;j++){ |
| 168 | if(BTST(defs_gen[i],j)) {printf(" ");pric2(stdout,dlist[j]);} |
| 169 | if(BTST(defs_gen[i],UNDEF(j))) {printf(" (ud)");pric2(stdout,dlist[j]);} |
| 170 | } |
| 171 | } |
| 172 | } |
| 173 | |
| 174 | if(DEBUG&16384) printf("num_defs heapsize=%lu\n",heapsize); |
| 175 | |
| 176 | free(var_undefs); |
| 177 | } |
| 178 | |
| 179 | /* returns whether n overwrites the definition p */ |
| 180 | int def_overwrites(IC *n,IC *o) |
| 181 | { |
| 182 | zmax nstart,nend,ostart,oend,nsize,osize; |
| 183 | if(!(n->z.flags&VAR)) ierror(0); |
| 184 | if(!(o->z.flags&VAR)) ierror(0); |
| 185 | if((n->z.flags&DREFOBJ)!=(o->z.flags&DREFOBJ)) ierror(0); |
| 186 | if(n->code==ASSIGN){ |
| 187 | nsize=n->q2.val.vmax; |
| 188 | }else{ |
| 189 | nsize=sizetab[ztyp(n)&NQ]; |
| 190 | } |
| 191 | if(o->code==ASSIGN){ |
| 192 | osize=o->q2.val.vmax; |
| 193 | }else{ |
| 194 | osize=sizetab[ztyp(o)&NQ]; |
| 195 | } |
| 196 | if(n->z.flags&DREFOBJ) |
| 197 | return zmleq(osize,nsize); |
| 198 | |
| 199 | nstart=n->z.val.vmax; |
| 200 | nend=zmsub(zmadd(nstart,nsize),l2zm(1L)); |
| 201 | ostart=o->z.val.vmax; |
| 202 | oend=zmsub(zmadd(ostart,osize),l2zm(1L)); |
| 203 | |
| 204 | if(zmeqto(nstart,ostart)&&zmeqto(nend,oend)) |
| 205 | return EXACT_OVERWRITE; |
| 206 | |
| 207 | if(zmleq(nstart,ostart)&&zmleq(oend,nend)) |
| 208 | return FULL_OVERWRITE; |
| 209 | |
| 210 | if(zmleq(ostart,nstart)&&zmleq(nstart,oend)) |
| 211 | return PARTIAL_OVERWRITE; |
| 212 | if(zmleq(ostart,nend)&&zmleq(nend,oend)) |
| 213 | return PARTIAL_OVERWRITE; |
| 214 | |
| 215 | return NO_OVERWRITE; |
| 216 | } |
| 217 | |
| 218 | /* performs data flow analysis for reaching definitions */ |
| 219 | void reaching_definitions(flowgraph *fg) |
| 220 | { |
| 221 | flowgraph *g;IC *p;bvtype *tmp,*init; |
| 222 | int changed,pass,i,j; |
| 223 | unsigned long heapsize=0; |
| 224 | /* rd_gen und rd_kill fuer jeden Block berechnen */ |
| 225 | if(DEBUG&1024) printf("analysing reaching definitions\n"); |
| 226 | tmp=mymalloc(dsize); |
| 227 | init=mymalloc(dsize); |
| 228 | heapsize+=2*dsize; |
| 229 | memset(init,0,dsize); |
| 230 | for(i=1;i<=dcount;i++){ |
| 231 | p=dlist[i]; |
| 232 | if(p->z.flags&VAR){ |
| 233 | Var *v=p->z.v; |
| 234 | if(v->storage_class==EXTERN||v->storage_class==STATIC||v->reg!=0||!zmleq(l2zm(0L),v->offset)){ |
| 235 | BSET(init,UNDEF(i)); |
| 236 | } |
| 237 | } |
| 238 | } |
| 239 | g=fg; |
| 240 | while(g){ |
| 241 | g->rd_in=mymalloc(dsize); |
| 242 | memset(g->rd_in,0,dsize); |
| 243 | g->rd_out=mymalloc(dsize); |
| 244 | memset(g->rd_out,0,dsize); |
| 245 | g->rd_gen=mymalloc(dsize); |
| 246 | memset(g->rd_gen,0,dsize); |
| 247 | g->rd_kill=mymalloc(dsize); |
| 248 | memset(g->rd_kill,0,dsize); |
| 249 | heapsize+=4*dsize; |
| 250 | p=g->end; |
| 251 | while(p){ |
| 252 | if(p->defindex){ |
| 253 | bvunite(g->rd_gen,defs_gen[p->defindex],dsize); |
| 254 | bvdiff(g->rd_gen,g->rd_kill,dsize); |
| 255 | bvunite(g->rd_kill,defs_kill[p->defindex],dsize); |
| 256 | bvdiff(g->rd_kill,g->rd_gen,dsize); |
| 257 | } |
| 258 | if(p==g->start) break; |
| 259 | p=p->prev; |
| 260 | } |
| 261 | memcpy(g->rd_out,g->rd_gen,dsize); |
| 262 | g=g->normalout; |
| 263 | } |
| 264 | |
| 265 | /* rd_in und rd_out fuer jeden Block berechnen */ |
| 266 | /* out(b)=gen(B) vorinitialisiert */ |
| 267 | if(DEBUG&1024) {printf("pass:");pass=0;} |
| 268 | do{ |
| 269 | if(DEBUG&1024) {printf(" %d",++pass);fflush(stdout);} |
| 270 | changed=0; |
| 271 | g=fg; |
| 272 | while(g){ |
| 273 | flowlist *lp; |
| 274 | /* in(B)=U out(C) : C Vorgaenger von B */ |
| 275 | if(g==fg) |
| 276 | memcpy(g->rd_in,init,dsize); |
| 277 | else |
| 278 | memset(g->rd_in,0,dsize); |
| 279 | lp=g->in; |
| 280 | while(lp){ |
| 281 | if(!lp->graph) ierror(0); |
| 282 | if(lp->graph->branchout==g||!lp->graph->end||lp->graph->end->code!=BRA) |
| 283 | bvunite(g->rd_in,lp->graph->rd_out,dsize); |
| 284 | lp=lp->next; |
| 285 | } |
| 286 | /* out(b)=gen(B) U (in(B)-kill(B) */ |
| 287 | memcpy(tmp,g->rd_in,dsize); |
| 288 | bvdiff(tmp,g->rd_kill,dsize); |
| 289 | bvunite(tmp,g->rd_gen,dsize); |
| 290 | if(!bvcmp(tmp,g->rd_out,dsize)){changed=1;memcpy(g->rd_out,tmp,dsize);} |
| 291 | g=g->normalout; |
| 292 | } |
| 293 | }while(changed); |
| 294 | if(DEBUG&1024) printf("\n"); |
| 295 | if(DEBUG&16384) printf("reaching_defs heapsize=%lu\n",heapsize); |
| 296 | free(tmp); |
| 297 | free(init); |
| 298 | } |
| 299 | |
| 300 | /* calculates z:=q1 op q2 with constants */ |
| 301 | /* if p is non-zero q1typ,q2typ from p will be used */ |
| 302 | void calc(int c,int t,union atyps *q1,union atyps *q2,union atyps *z,IC *p) |
| 303 | { |
| 304 | zldouble d1,d2;zmax l1,l2;zumax u1,u2; |
| 305 | if(p) t=q1typ(p); |
| 306 | eval_const(q1,t); |
| 307 | d1=vldouble;l1=vmax;u1=vumax; |
| 308 | if(c!=MINUS&&c!=KOMPLEMENT){ |
| 309 | if(p) |
| 310 | eval_const(q2,q2typ(p)); |
| 311 | else |
| 312 | eval_const(q2,t); |
| 313 | d2=vldouble;l2=vmax;u2=vumax; |
| 314 | } |
| 315 | if(c==ADD){ vldouble=zldadd(d1,d2);vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);} |
| 316 | if(c==SUB){ vldouble=zldsub(d1,d2);vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);} |
| 317 | if(c==ADDI2P){ vmax=zmadd(l1,l2);vumax=zumadd(u1,u2);} |
| 318 | if(c==SUBIFP){ vmax=zmsub(l1,l2);vumax=zumsub(u1,u2);} |
| 319 | if(c==MULT){ vldouble=zldmult(d1,d2);vmax=zmmult(l1,l2);vumax=zummult(u1,u2);} |
| 320 | if(c==DIV||c==MOD){ |
| 321 | if(zldeqto(d2,d2zld(0.0))&&zmeqto(l2,l2zm(0L))&&zumeqto(u2,ul2zum(0UL))){ |
| 322 | err_ic=p;error(210);err_ic=0; |
| 323 | vmax=l2zm(0L);vumax=ul2zum(0L);vldouble=d2zld(0.0); |
| 324 | }else{ |
| 325 | if(c==DIV){ |
| 326 | vldouble=zlddiv(d1,d2); |
| 327 | if(!zmeqto(l2,l2zm(0L))) vmax=zmdiv(l1,l2); |
| 328 | if(!zumeqto(u2,ul2zum(0UL))) vumax=zumdiv(u1,u2); |
| 329 | }else{ |
| 330 | if(!zmeqto(l2,l2zm(0L))) vmax=zmmod(l1,l2); |
| 331 | if(!zumeqto(u2,ul2zum(0UL))) vumax=zummod(u1,u2); |
| 332 | } |
| 333 | } |
| 334 | } |
| 335 | if(c==AND){ vmax=zmand(l1,l2);vumax=zumand(u1,u2);} |
| 336 | if(c==OR){ vmax=zmor(l1,l2);vumax=zumor(u1,u2);} |
| 337 | if(c==XOR){ vmax=zmxor(l1,l2);vumax=zumxor(u1,u2);} |
| 338 | if(c==LSHIFT){ vmax=zmlshift(l1,l2);vumax=zumlshift(u1,l2);} |
| 339 | if(c==RSHIFT){ vmax=zmrshift(l1,l2);vumax=zumrshift(u1,l2);} |
| 340 | if(c==MINUS){ vldouble=zldsub(d2zld(0.0),d1);vmax=zmsub(l2zm(0L),l1);vumax=zumsub(ul2zum(0UL),u1);} |
| 341 | if(c==KOMPLEMENT){ vmax=zmkompl(l1);vumax=zumkompl(u1);} |
| 342 | |
| 343 | if(ISFLOAT(t)){ |
| 344 | gval.vldouble=vldouble; |
| 345 | eval_const(&gval,LDOUBLE); |
| 346 | }else if(t&UNSIGNED){ |
| 347 | gval.vumax=vumax; |
| 348 | eval_const(&gval,(UNSIGNED|MAXINT)); |
| 349 | }else{ |
| 350 | gval.vmax=vmax; |
| 351 | eval_const(&gval,MAXINT); |
| 352 | } |
| 353 | if(p) t=ztyp(p); |
| 354 | insert_const(z,t); |
| 355 | } |
| 356 | |
| 357 | /* folds constant ICs */ |
| 358 | int fold(IC *p) |
| 359 | { |
| 360 | int c; |
| 361 | if(!p) ierror(0); |
| 362 | c=p->code; |
| 363 | if(c==SUBPFP||c==ASSIGN||c==PUSH||c==SETRETURN) return 0; |
| 364 | if(DEBUG&1024) {printf("folding IC:\n");pric2(stdout,p);} |
| 365 | if(c==TEST||c==COMPARE){ |
| 366 | union atyps val;int cc; /* condition codes */ |
| 367 | IC *bp; |
| 368 | if(c==TEST){ |
| 369 | eval_const(&p->q1.val,p->typf); |
| 370 | if(zmeqto(vmax,l2zm(0L))&&zumeqto(vumax,ul2zum(0UL))&&zldeqto(vldouble,d2zld(0.0))) |
| 371 | cc=0; |
| 372 | else |
| 373 | cc=1; |
| 374 | }else{ |
| 375 | if(p->q1.flags&VARADR) |
| 376 | cc=compare_const(&p->q1.val,&p->q2.val,UNSIGNED|MAXINT); |
| 377 | else |
| 378 | cc=compare_const(&p->q1.val,&p->q2.val,p->typf); |
| 379 | } |
| 380 | bp=p->next; |
| 381 | if(bp->code>=BEQ&&bp->code<=BGT&&(!p->z.flags||p->z.v==bp->q1.v)){ |
| 382 | if(DEBUG&1024) printf("(cc=%d; comparison eliminated)\n",cc); |
| 383 | if(have_alias){ free(p->use_list);free(p->change_list);} |
| 384 | remove_IC(p); |
| 385 | while(1){ /* zugehoerigen Branch suchen */ |
| 386 | if(!bp||bp->code==LABEL||bp->code==BRA) ierror(0); |
| 387 | c=bp->code; |
| 388 | if(c>=BEQ&&c<=BGT) break; |
| 389 | bp=bp->next; |
| 390 | } |
| 391 | 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)){ |
| 392 | if(DEBUG&1024){ printf("changed following branch to BRA:\n");pric2(stdout,bp);} |
| 393 | bp->code=BRA;bp->q1.flags=0; |
| 394 | }else{ |
| 395 | if(DEBUG&1024){ printf("removed following branch:\n");pric2(stdout,bp);} |
| 396 | if(have_alias){ free(bp->use_list);free(bp->change_list);} |
| 397 | remove_IC(bp); |
| 398 | } |
| 399 | return 1; |
| 400 | } |
| 401 | if(p->z.flags==0){ |
| 402 | p->code=NOP; |
| 403 | p->q1.flags=p->q2.flags=p->z.flags=0; |
| 404 | return 1; |
| 405 | }else |
| 406 | return 0; |
| 407 | } |
| 408 | if(c==CONVERT){ |
| 409 | eval_const(&p->q1.val,p->typf2); |
| 410 | insert_const(&p->q1.val,p->typf); |
| 411 | }else |
| 412 | calc(c,p->typf,&p->q1.val,&p->q2.val,&p->q1.val,p); |
| 413 | p->q2.flags=0; |
| 414 | if(p->code==ADDI2P||p->code==SUBIFP) |
| 415 | p->typf=p->typf2; |
| 416 | p->q2.val.vmax=sizetab[p->typf&NQ]; |
| 417 | p->code=ASSIGN; |
| 418 | if(DEBUG&1024){printf("becomes\n");pric2(stdout,p);} |
| 419 | return 1; |
| 420 | } |
| 421 | |
| 422 | /* tries to replace objects by constants and detects some uninitialized */ |
| 423 | /* variables; if cponly==0, address-constants will be replaced, */ |
| 424 | /* otherwise only real constants are replaced, sic points to the IC */ |
| 425 | /* containing the object pointed to by o */ |
| 426 | int propagate(IC *sic,obj *o,int cponly,int global) |
| 427 | { |
| 428 | unsigned int i,j,t,found;union atyps *val=0; |
| 429 | Var *v,*vaddr=0;IC *p; |
| 430 | zmax voff; |
| 431 | if(!o||!o->v) ierror(0); |
| 432 | if(cponly){ |
| 433 | if(is_volatile_obj(o)) |
| 434 | return 0; |
| 435 | }else{ |
| 436 | if((o->flags&VAR)&&(o->v->vtyp->flags&VOLATILE)) |
| 437 | return 0; |
| 438 | } |
| 439 | if(disable&8) return 0; |
| 440 | v=o->v; |
| 441 | i=v->index; |
| 442 | /* do not replace in ICs of the form move char with size!=1, |
| 443 | because these are builtin memcpy */ |
| 444 | if(cponly&&sic->code==ASSIGN&&(sic->typf&NQ)==CHAR&&!zmeqto(sic->q2.val.vmax,l2zm(1L))) |
| 445 | return 0; |
| 446 | if(cponly&&(o->flags&DREFOBJ)) i+=vcount-rcount; |
| 447 | if(DEBUG&2048){ |
| 448 | printf("propagate(cponly=%d) <%s>(%p)\n",cponly,o->v->identifier,(void *)v); |
| 449 | if(o->flags&DREFOBJ) printf("(DREFOBJ)"); |
| 450 | printf("\nall reaching definitions:\n");print_rd(rd_defs); |
| 451 | printf("defs for var:\n"); |
| 452 | print_rd(var_defs[i]); |
| 453 | } |
| 454 | if(v->nesting==0||v->storage_class==STATIC||v->storage_class==EXTERN){ |
| 455 | /* Wenn moeglich bei statischen Variablen den Wert bei der */ |
| 456 | /* Initialisierung ermitteln. */ |
| 457 | /*if(cponly&&ISARITH(v->vtyp->flags)&&((v->vtyp->flags&CONST)||(v->nesting>0&&!(v->flags&(USEDASADR|USEDASDEST))))){*/ |
| 458 | printf("var1(%s) %d\n",v->identifier,cponly); |
| 459 | if(cponly&&is_const(v->vtyp)){ |
| 460 | /* Variable hat noch den Wert der Initialisierung. */ |
| 461 | if(v->clist){ |
| 462 | int t; |
| 463 | if(o==&sic->q1) t=q1typ(sic); |
| 464 | else if(o==&sic->q2) t=q2typ(sic); |
| 465 | else if(o==&sic->z) t=ztyp(sic); |
| 466 | else ierror(0); |
| 467 | printf("var2(%s)\n",v->identifier); |
| 468 | if(ISARITH(v->vtyp->flags)||ISPOINTER(v->vtyp->flags)){ |
| 469 | /* Der Wert der Initialisierung ist noch gespeichert. */ |
| 470 | if(DEBUG&1024) printf("using static initializer\n"); |
| 471 | o->val=v->clist->val; |
| 472 | o->flags=KONST; |
| 473 | return 1; |
| 474 | }else if(ISINT(t&NQ)){ |
| 475 | int state; |
| 476 | if(DEBUG&1024) printf("using static initializer (new version)\n"); |
| 477 | gval.vumax=get_clist_int(v->vtyp,v->clist,o->val.vmax,sizetab[t&NQ],&state); |
| 478 | if(state){ |
| 479 | if(DEBUG&1024) printf("using static initializer (new version)\n"); |
| 480 | eval_const(&gval,UNSIGNED|MAXINT); |
| 481 | insert_const(&o->val,t); |
| 482 | o->flags=KONST; |
| 483 | return 1; |
| 484 | } |
| 485 | } |
| 486 | }else{ |
| 487 | /* Hier evtl. eine implizite 0 erkennen. */ |
| 488 | } |
| 489 | } |
| 490 | } |
| 491 | found=0; |
| 492 | for(j=1;j<=dcount;j++){ |
| 493 | if((!BTST(rd_defs,UNDEF(j))||!BTST(var_defs[i],UNDEF(j)))&& |
| 494 | (!BTST(rd_defs,j)||!BTST(var_defs[i],j))) continue; |
| 495 | found=1; |
| 496 | p=dlist[j]; |
| 497 | if(!(p->z.flags&VAR)) return 0; |
| 498 | if(p->z.v!=o->v) continue; |
| 499 | t=ztyp(p)&NU; |
| 500 | if(cponly&&!ISSCALAR(t)) continue; |
| 501 | if(!zmeqto(p->z.val.vmax,o->val.vmax)) continue; |
| 502 | if(cponly){ |
| 503 | if(p->z.flags!=o->flags) continue; |
| 504 | }else{ |
| 505 | if((p->z.flags|DREFOBJ)!=o->flags) continue; |
| 506 | if(p->z.flags&DREFOBJ) continue; |
| 507 | } |
| 508 | if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],UNDEF(j))) return 0; |
| 509 | if(BTST(rd_defs,UNDEF(j))&&BTST(var_defs[i],j)) return 0; |
| 510 | |
| 511 | if((p->code!=ASSIGN||((p->q1.flags&(KONST|DREFOBJ))!=KONST&&(p->q1.flags&(VARADR|DREFOBJ))!=VARADR)) |
| 512 | &&(p->code!=ADDRESS||!(o->flags&DREFOBJ))) return 0; |
| 513 | if(p->q1.flags&KONST){ |
| 514 | if(vaddr) return 0; |
| 515 | if(val){ |
| 516 | if((p->typf&NQ)!=(t&NQ)) return 0; |
| 517 | if(compare_const(&p->q1.val,val,t)) return 0; |
| 518 | }else{ |
| 519 | val=&p->q1.val;t=p->typf&NU; |
| 520 | } |
| 521 | } |
| 522 | if(p->code==ADDRESS||(p->q1.flags&VARADR)){ |
| 523 | if(val) return 0; |
| 524 | if(vaddr){ |
| 525 | if(p->q1.v!=vaddr||!zmeqto(p->q1.val.vmax,voff)) return 0; |
| 526 | } |
| 527 | vaddr=p->q1.v; |
| 528 | voff=p->q1.val.vmax; |
| 529 | } |
| 530 | } |
| 531 | |
| 532 | /* found constant */ |
| 533 | if(val){ |
| 534 | if(cponly){ |
| 535 | if(o==&sic->q1&&(q1typ(sic)&NQ)!=(t&NQ)) return 0; |
| 536 | if(o==&sic->q2&&(q2typ(sic)&NQ)!=(t&NQ)) return 0; |
| 537 | if(o==&sic->z&&(ztyp(sic)&NQ)!=(t&NQ)) return 0; |
| 538 | |
| 539 | if(DEBUG&1024) printf("can replace %ld+<%s>(%p) by constant\n",zm2l(o->val.vmax),o->v->identifier,o->v); |
| 540 | /* TODO: do we need eval_const/insert_const (if representation of unsigned is different? */ |
| 541 | o->val=*val; |
| 542 | o->flags=KONST; |
| 543 | }else{ |
| 544 | if(DEBUG&1024) printf("can replace <%s> by constant address\n",o->v->identifier); |
| 545 | o->val=*val; |
| 546 | o->flags|=KONST; |
| 547 | o->flags&=~VAR; |
| 548 | o->v=0; |
| 549 | } |
| 550 | return 1; |
| 551 | } |
| 552 | if(vaddr&&(vaddr->storage_class==EXTERN||vaddr->storage_class==STATIC)){ |
| 553 | if(DEBUG&1024) printf("can replace <%s> by varadr\n",o->v->identifier); |
| 554 | o->v=vaddr; |
| 555 | o->val.vmax=voff; |
| 556 | if((o->flags&DREFOBJ)&&!cponly) |
| 557 | o->flags=VAR; |
| 558 | else |
| 559 | o->flags=VAR|VARADR; |
| 560 | return 2; |
| 561 | } |
| 562 | if(vaddr&&(o->flags&DREFOBJ)){ |
| 563 | t=vaddr->vtyp->flags&NU; |
| 564 | if(o==&sic->q1&&(q1typ(sic)&NU)!=t) return 0; |
| 565 | if(o==&sic->q2&&(q2typ(sic)&NU)!=t) return 0; |
| 566 | if(o==&sic->z&&(ztyp(sic)&NU)!=t) return 0; |
| 567 | if(DEBUG&1024) printf("can replace *<%s> by address\n",o->v->identifier); |
| 568 | o->v=vaddr; |
| 569 | o->val.vmax=voff; |
| 570 | o->flags&=~DREFOBJ; |
| 571 | return 2; |
| 572 | } |
| 573 | /* no definition found */ |
| 574 | if(!found&&global&&v->storage_class!=EXTERN&&v->storage_class!=STATIC&&!(v->flags&USEDBEFORE)&&v->reg==0&&zmleq(l2zm(0L),v->offset)){ |
| 575 | if(*v->identifier||!(optflags&4096)){ |
| 576 | #ifdef HAVE_MISRA |
| 577 | misra_neu(30,9,1,0,v->identifier); |
| 578 | #endif |
| 579 | error(171,v->identifier);v->flags|=USEDBEFORE; |
| 580 | if(!*v->identifier) {printf("<%p>\n",(void *)v);ierror(0);} |
| 581 | } |
| 582 | } |
| 583 | return 0; |
| 584 | } |
| 585 | |
| 586 | /* searches for constant objects and uninitialized variables; if */ |
| 587 | /* global!=0, reaching definitions are used, otherwise only local */ |
| 588 | /* constant propagation will be done */ |
| 589 | int constant_propagation(flowgraph *fg,int global) |
| 590 | { |
| 591 | IC *p;int changed=0,i,t;flowgraph *g; |
| 592 | rd_defs=mymalloc(dsize); |
| 593 | g=fg; |
| 594 | while(g){ |
| 595 | if(global) |
| 596 | memcpy(rd_defs,g->rd_in,dsize); |
| 597 | else |
| 598 | memset(rd_defs,0,dsize); |
| 599 | p=g->start; |
| 600 | while(p){ |
| 601 | int c=p->code; |
| 602 | /* if(DEBUG&1024){print_rd(rd_defs);pric2(stdout,p);}*/ |
| 603 | if(c!=ADDRESS&&c!=NOP&&ISSCALAR(p->typf)&&(c<LABEL||c>BRA)){ |
| 604 | if((p->q1.flags&(VAR|VARADR))==VAR){ |
| 605 | if(!(q1typ(p)&VOLATILE)&&!is_volatile_obj(&p->q1)) |
| 606 | changed|=propagate(p,&p->q1,1,global); |
| 607 | if((p->q1.flags&DREFOBJ)&&!(p->q1.v->vtyp->flags&VOLATILE)) |
| 608 | changed|=propagate(p,&p->q1,0,global); |
| 609 | } |
| 610 | if((p->q2.flags&(VAR|VARADR))==VAR){ |
| 611 | if(!(q2typ(p)&VOLATILE)&&!is_volatile_obj(&p->q2)) |
| 612 | changed|=propagate(p,&p->q2,1,global); |
| 613 | if((p->q2.flags&DREFOBJ)&&!(p->q2.v->vtyp->flags&VOLATILE)) |
| 614 | changed|=propagate(p,&p->q2,0,global); |
| 615 | } |
| 616 | } |
| 617 | /* only there to detect uninitialized variables */ |
| 618 | if(((p->z.flags&(VAR|DREFOBJ))==(VAR|DREFOBJ))){ |
| 619 | if(!(p->z.v->vtyp->flags&VOLATILE)) |
| 620 | changed|=propagate(p,&p->z,0,global); |
| 621 | } |
| 622 | rd_change(p); |
| 623 | |
| 624 | if(p==g->end) break; |
| 625 | p=p->next; |
| 626 | } |
| 627 | break; |
| 628 | g=g->normalout; |
| 629 | } |
| 630 | |
| 631 | gchanged|=changed; |
| 632 | |
| 633 | free(rd_defs); |
| 634 | return changed; |
| 635 | } |
| 636 | |
| 637 | /* performs changes to rd_defs which are caused by IC p */ |
| 638 | void rd_change(IC *p) |
| 639 | { |
| 640 | if(DEBUG&4096) print_rd(rd_defs); |
| 641 | if(p->defindex){ |
| 642 | bvdiff(rd_defs,defs_kill[p->defindex],dsize); |
| 643 | bvunite(rd_defs,defs_gen[p->defindex],dsize); |
| 644 | } |
| 645 | if(DEBUG&4096) pric2(stdout,p); |
| 646 | } |
| 647 | |