1 /** 2 * Compiler implementation of the 3 * $(LINK2 http://www.dlang.org, D programming language). 4 * 5 * Copyright: Copyright (C) 1986-1998 by Symantec 6 * Copyright (C) 2000-2020 by The D Language Foundation, All Rights Reserved 7 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 8 * License: Distributed under the Boost Software License, Version 1.0. 9 * http://www.boost.org/LICENSE_1_0.txt 10 * Source: https://github.com/dlang/dmd/blob/master/src/dmd/backend/gother.c 11 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/gother.c 12 */ 13 14 module dmd.backend.gother; 15 16 version (SCPP) 17 version = COMPILE; 18 version (MARS) 19 version = COMPILE; 20 21 version (COMPILE) 22 { 23 24 import core.stdc.stdio; 25 import core.stdc.stdlib; 26 import core.stdc.time; 27 28 import dmd.backend.cc; 29 import dmd.backend.cdef; 30 import dmd.backend.code_x86; 31 import dmd.backend.oper; 32 import dmd.backend.global; 33 import dmd.backend.goh; 34 import dmd.backend.el; 35 import dmd.backend.outbuf; 36 import dmd.backend.ty; 37 import dmd.backend.type; 38 39 import dmd.backend.barray; 40 import dmd.backend.dlist; 41 import dmd.backend.dvec; 42 43 nothrow: 44 45 char symbol_isintab(Symbol *s) { return sytab[s.Sclass] & SCSS; } 46 47 extern (C++): 48 49 version (SCPP) 50 import parser; 51 52 version (MARS) 53 import dmd.backend.errors; 54 55 /**********************************************************************/ 56 57 // Lists to help identify ranges of variables 58 struct Elemdata 59 { 60 nothrow: 61 Elemdata *next; // linked list 62 elem *pelem; // the elem in question 63 block *pblock; // which block it's in 64 list_t rdlist; // list of definition elems for *pelem 65 66 static Elemdata *ctor(elem *e,block *b,list_t rd) 67 { 68 Elemdata* ed = cast(Elemdata *) calloc(1, Elemdata.sizeof); 69 assert(ed); 70 ed.pelem = e; 71 ed.pblock = b; 72 ed.rdlist = rd; 73 return ed; 74 } 75 76 /******************************** 77 * Find `e` in Elemdata list. 78 * Params: 79 * e = elem to find 80 * Returns: 81 * Elemdata entry if found, 82 * null if not 83 */ 84 Elemdata* find(elem *e) 85 { 86 Elemdata* edl = &this; 87 for (; edl; edl = edl.next) 88 { 89 if (edl.pelem == e) 90 break; 91 } 92 return edl; 93 } 94 } 95 96 /***************** 97 * Free list of Elemdata's. 98 */ 99 100 private void elemdatafree(Elemdata **plist) 101 { 102 Elemdata *eln; 103 104 for (Elemdata *el = *plist; el; el = eln) 105 { eln = el.next; 106 list_free(&el.rdlist); 107 free(el); 108 } 109 *plist = null; 110 } 111 112 private __gshared 113 { 114 Elemdata *eqeqlist = null; // list of Elemdata's of OPeqeq & OPne elems 115 Elemdata *rellist = null; // list of Elemdata's of relop elems 116 Elemdata *inclist = null; // list of Elemdata's of increment elems 117 } 118 119 /*************************** Constant Propagation ***************************/ 120 121 122 /************************** 123 * Constant propagation. 124 * Also detects use of variable before any possible def. 125 */ 126 127 void constprop() 128 { 129 rd_compute(); 130 intranges(); // compute integer ranges 131 eqeqranges(); // see if we can eliminate some relationals 132 elemdatafree(&eqeqlist); 133 elemdatafree(&rellist); 134 elemdatafree(&inclist); 135 } 136 137 /************************************ 138 * Compute reaching definitions. 139 * Note: RD vectors are destroyed by this. 140 */ 141 142 private __gshared block *thisblock; 143 144 private void rd_compute() 145 { 146 if (debugc) printf("constprop()\n"); 147 assert(dfo); 148 flowrd(); /* compute reaching definitions (rd) */ 149 if (go.defnod.length == 0) /* if no reaching defs */ 150 return; 151 assert(rellist == null && inclist == null && eqeqlist == null); 152 block_clearvisit(); 153 foreach (b; dfo[]) // for each block 154 { 155 switch (b.BC) 156 { 157 case BCjcatch: 158 case BC_finally: 159 case BC_lpad: 160 case BCasm: 161 case BCcatch: 162 block_visit(b); 163 break; 164 165 default: 166 break; 167 } 168 } 169 170 foreach (i, b; dfo[]) // for each block 171 { 172 thisblock = b; 173 174 //printf("block %d Bin ",i); vec_println(b.Binrd); 175 //printf(" Bout "); vec_println(b.Boutrd); 176 177 if (b.Bflags & BFLvisited) 178 continue; // not reliable for this block 179 if (b.Belem) 180 { 181 conpropwalk(b.Belem,b.Binrd); 182 183 debug 184 if (!(vec_equal(b.Binrd,b.Boutrd))) 185 { 186 int j; 187 188 printf("block %d Binrd ", cast(int) i); vec_println(b.Binrd); 189 printf(" Boutrd "); vec_println(b.Boutrd); 190 WReqn(b.Belem); 191 printf("\n"); 192 vec_xorass(b.Binrd,b.Boutrd); 193 j = cast(int)vec_index(0,b.Binrd); 194 WReqn(go.defnod[j].DNelem); 195 printf("\n"); 196 } 197 198 assert(vec_equal(b.Binrd,b.Boutrd)); 199 } 200 } 201 } 202 203 /*************************** 204 * Support routine for constprop(). 205 * Visit each elem in order 206 * If elem is a reference to a variable, and 207 * all the reaching defs of that variable are 208 * defining it to be a specific constant, 209 * Replace reference with that constant. 210 * Generate warning if no reaching defs for a 211 * variable, and the variable is on the stack 212 * or in a register. 213 * If elem is an assignment or function call or OPasm 214 * Modify vector of reaching defs. 215 */ 216 217 private void conpropwalk(elem *n,vec_t IN) 218 { 219 Elemdata *pdata; 220 vec_t L,R; 221 elem *t; 222 223 assert(n && IN); 224 //printf("conpropwalk()\n"),elem_print(n); 225 const op = n.Eoper; 226 if (op == OPcolon || op == OPcolon2) 227 { 228 L = vec_clone(IN); 229 switch (el_returns(n.EV.E1) * 2 | el_returns(n.EV.E2)) 230 { 231 case 3: // E1 and E2 return 232 conpropwalk(n.EV.E1,L); 233 conpropwalk(n.EV.E2,IN); 234 vec_orass(IN,L); // IN = L | R 235 break; 236 237 case 2: // E1 returns 238 conpropwalk(n.EV.E1,IN); 239 conpropwalk(n.EV.E2,L); 240 break; 241 242 case 1: // E2 returns 243 conpropwalk(n.EV.E1,L); 244 conpropwalk(n.EV.E2,IN); 245 break; 246 247 case 0: // neither returns 248 conpropwalk(n.EV.E1,L); 249 vec_copy(L,IN); 250 conpropwalk(n.EV.E2,L); 251 break; 252 253 default: 254 break; 255 } 256 vec_free(L); 257 } 258 else if (op == OPandand || op == OPoror) 259 { 260 conpropwalk(n.EV.E1,IN); 261 R = vec_clone(IN); 262 conpropwalk(n.EV.E2,R); 263 if (el_returns(n.EV.E2)) 264 vec_orass(IN,R); // IN |= R 265 vec_free(R); 266 } 267 else if (OTunary(op)) 268 goto L3; 269 else if (ERTOL(n)) 270 { 271 conpropwalk(n.EV.E2,IN); 272 L3: 273 t = n.EV.E1; 274 if (OTassign(op)) 275 { 276 if (t.Eoper == OPvar) 277 { 278 // Note that the following ignores OPnegass 279 if (OTopeq(op) && sytab[t.EV.Vsym.Sclass] & SCRD) 280 { 281 elem *e; 282 list_t rdl; 283 284 rdl = listrds(IN,t,null); 285 if (!(config.flags & CFGnowarning)) // if warnings are enabled 286 chkrd(t,rdl); 287 e = chkprop(t,rdl); 288 if (e) 289 { // Replace (t op= exp) with (t = e op exp) 290 291 e = el_copytree(e); 292 e.Ety = t.Ety; 293 n.EV.E2 = el_bin(opeqtoop(op),n.Ety,e,n.EV.E2); 294 n.Eoper = OPeq; 295 } 296 list_free(&rdl); 297 } 298 } 299 else 300 conpropwalk(t,IN); 301 } 302 else 303 conpropwalk(t,IN); 304 } 305 else if (OTbinary(op)) 306 { 307 if (OTassign(op)) 308 { t = n.EV.E1; 309 if (t.Eoper != OPvar) 310 conpropwalk(t,IN); 311 } 312 else 313 conpropwalk(n.EV.E1,IN); 314 conpropwalk(n.EV.E2,IN); 315 } 316 317 // Collect data for subsequent optimizations 318 if (OTbinary(op) && n.EV.E1.Eoper == OPvar && n.EV.E2.Eoper == OPconst) 319 { 320 switch (op) 321 { 322 case OPlt: 323 case OPgt: 324 case OPle: 325 case OPge: 326 // Collect compare elems and their rd's in the rellist list 327 if (tyintegral(n.EV.E1.Ety) && 328 tyintegral(n.EV.E2.Ety) 329 ) 330 { 331 //printf("appending to rellist\n"); elem_print(n); 332 //printf("\trellist IN: "); vec_print(IN); printf("\n"); 333 pdata = Elemdata.ctor(n,thisblock,listrds(IN,n.EV.E1,null)); 334 pdata.next = rellist; 335 rellist = pdata; 336 } 337 break; 338 339 case OPaddass: 340 case OPminass: 341 case OPpostinc: 342 case OPpostdec: 343 // Collect increment elems and their rd's in the inclist list 344 if (tyintegral(n.EV.E1.Ety)) 345 { 346 //printf("appending to inclist\n"); elem_print(n); 347 //printf("\tinclist IN: "); vec_print(IN); printf("\n"); 348 pdata = Elemdata.ctor(n,thisblock,listrds(IN,n.EV.E1,null)); 349 pdata.next = inclist; 350 inclist = pdata; 351 } 352 break; 353 354 case OPne: 355 case OPeqeq: 356 // Collect compare elems and their rd's in the rellist list 357 if (tyintegral(n.EV.E1.Ety)) 358 { //printf("appending to eqeqlist\n"); elem_print(n); 359 pdata = Elemdata.ctor(n,thisblock,listrds(IN,n.EV.E1,null)); 360 pdata.next = eqeqlist; 361 eqeqlist = pdata; 362 } 363 break; 364 365 default: 366 break; 367 } 368 } 369 370 371 if (OTdef(op)) /* if definition elem */ 372 updaterd(n,IN,null); /* then update IN vector */ 373 374 /* now we get to the part that checks to see if we can */ 375 /* propagate a constant. */ 376 if (op == OPvar && sytab[n.EV.Vsym.Sclass] & SCRD) 377 { 378 list_t rdl; 379 380 //printf("const prop: %s\n", n.EV.Vsym.Sident); 381 rdl = listrds(IN,n,null); 382 383 if (!(config.flags & CFGnowarning)) // if warnings are enabled 384 chkrd(n,rdl); 385 elem *e = chkprop(n,rdl); 386 if (e) 387 { tym_t nty; 388 389 nty = n.Ety; 390 el_copy(n,e); 391 n.Ety = nty; // retain original type 392 } 393 list_free(&rdl); 394 } 395 } 396 397 /****************************** 398 * Give error if there are no reaching defs for variable v. 399 */ 400 401 private void chkrd(elem *n,list_t rdlist) 402 { 403 Symbol *sv; 404 int unambig; 405 406 sv = n.EV.Vsym; 407 assert(sytab[sv.Sclass] & SCRD); 408 if (sv.Sflags & SFLnord) // if already printed a warning 409 return; 410 if (sv.ty() & (mTYvolatile | mTYshared)) 411 return; 412 unambig = sv.Sflags & SFLunambig; 413 foreach (l; ListRange(rdlist)) 414 { elem *d = cast(elem *) list_ptr(l); 415 416 elem_debug(d); 417 if (d.Eoper == OPasm) /* OPasm elems ruin everything */ 418 return; 419 if (OTassign(d.Eoper)) 420 { 421 if (d.EV.E1.Eoper == OPvar) 422 { 423 if (d.EV.E1.EV.Vsym == sv) 424 return; 425 } 426 else if (!unambig) 427 return; 428 } 429 else 430 { 431 if (!unambig) 432 return; 433 } 434 } 435 436 // If there are any asm blocks, don't print the message 437 foreach (b; dfo[]) 438 if (b.BC == BCasm) 439 return; 440 441 // If variable contains bit fields, don't print message (because if 442 // bit field is the first set, then we get a spurious warning). 443 // STL uses 0 sized structs to transmit type information, so 444 // don't complain about them being used before set. 445 if (type_struct(sv.Stype)) 446 { 447 if (sv.Stype.Ttag.Sstruct.Sflags & (STRbitfields | STR0size)) 448 return; 449 } 450 451 static if (0) 452 { 453 // If variable is zero length static array, don't print message. 454 // BUG: Suppress error even if variable is initialized with void. 455 if (sv.Stype.Tty == TYarray && sv.Stype.Tdim == 0) 456 { 457 printf("sv.Sident = %s\n", sv.Sident); 458 return; 459 } 460 } 461 462 version (SCPP) 463 { 464 { Outbuffer buf; 465 char *p2; 466 467 type_tostring(&buf, sv.Stype); 468 buf.writeByte(' '); 469 buf.write(sv.Sident.ptr); 470 p2 = buf.toString(); 471 warerr(WM.WM_used_b4_set, p2); // variable used before set 472 } 473 } 474 475 version (MARS) 476 { 477 /* Watch out for: 478 void test() 479 { 480 void[0] x; 481 auto y = x; 482 } 483 */ 484 if (type_size(sv.Stype) != 0) 485 { 486 error(n.Esrcpos.Sfilename, n.Esrcpos.Slinnum, n.Esrcpos.Scharnum, 487 "variable %s used before set", sv.Sident.ptr); 488 } 489 } 490 491 sv.Sflags |= SFLnord; // no redundant messages 492 //elem_print(n); 493 } 494 495 /********************************** 496 * Look through the vector of reaching defs (IN) to see 497 * if all defs of n are of the same constant. If so, replace 498 * n with that constant. 499 * Bit fields are gross, so don't propagate anything with assignments 500 * to a bit field. 501 * Note the flaw in the reaching def vector. There is currently no way 502 * to detect RDs from when the function is invoked, i.e. RDs for parameters, 503 * statics and globals. This could be fixed by adding dummy defs for 504 * them before startblock, but we just kludge it and don't propagate 505 * stuff for them. 506 * Returns: 507 * null do not propagate constant 508 * e constant elem that we should replace n with 509 */ 510 511 private elem * chkprop(elem *n,list_t rdlist) 512 { 513 elem *foundelem = null; 514 int unambig; 515 Symbol *sv; 516 tym_t nty; 517 uint nsize; 518 targ_size_t noff; 519 520 //printf("checkprop: "); WReqn(n); printf("\n"); 521 assert(n && n.Eoper == OPvar); 522 elem_debug(n); 523 sv = n.EV.Vsym; 524 assert(sytab[sv.Sclass] & SCRD); 525 nty = n.Ety; 526 if (!tyscalar(nty)) 527 goto noprop; 528 nsize = cast(uint)size(nty); 529 noff = n.EV.Voffset; 530 unambig = sv.Sflags & SFLunambig; 531 foreach (l; ListRange(rdlist)) 532 { 533 elem *d = cast(elem *) list_ptr(l); 534 535 elem_debug(d); 536 537 //printf("\trd: "); WReqn(d); printf("\n"); 538 if (d.Eoper == OPasm) /* OPasm elems ruin everything */ 539 goto noprop; 540 541 // Runs afoul of Buzilla 4506 542 /*if (OTassign(d.Eoper) && EBIN(d))*/ // if assignment elem 543 544 if (OTassign(d.Eoper)) // if assignment elem 545 { 546 elem *t = d.EV.E1; 547 548 if (t.Eoper == OPvar) 549 { 550 assert(t.EV.Vsym == sv); 551 552 if (d.Eoper == OPstreq || 553 !tyscalar(t.Ety)) 554 goto noprop; // not worth bothering with these cases 555 556 if (d.Eoper == OPnegass) 557 goto noprop; // don't bother with this case, either 558 559 /* Everything must match or we must skip this variable */ 560 /* (in case of assigning to overlapping unions, etc.) */ 561 if (t.EV.Voffset != noff || 562 /* If sizes match, we are ok */ 563 size(t.Ety) != nsize && 564 !(d.EV.E2.Eoper == OPconst && size(t.Ety) > nsize && !tyfloating(d.EV.E2.Ety))) 565 goto noprop; 566 } 567 else 568 { 569 if (unambig) /* unambiguous assignments only */ 570 continue; 571 goto noprop; 572 } 573 if (d.Eoper != OPeq) 574 goto noprop; 575 } 576 else /* must be a call elem */ 577 { 578 if (unambig) 579 continue; 580 else 581 goto noprop; /* could be affected */ 582 } 583 584 if (d.EV.E2.Eoper == OPconst || d.EV.E2.Eoper == OPrelconst) 585 { 586 if (foundelem) /* already found one */ 587 { /* then they must be the same */ 588 if (!el_match(foundelem,d.EV.E2)) 589 goto noprop; 590 } 591 else /* else this is it */ 592 foundelem = d.EV.E2; 593 } 594 else 595 goto noprop; 596 } 597 598 if (foundelem) /* if we got one */ 599 { /* replace n with foundelem */ 600 debug if (debugc) 601 { 602 printf("const prop ("); 603 WReqn(n); 604 printf(" replaced by "); 605 WReqn(foundelem); 606 printf("), %p to %p\n",foundelem,n); 607 } 608 go.changes++; 609 return foundelem; 610 } 611 noprop: 612 return null; 613 } 614 615 /*********************************** 616 * Find all the reaching defs of OPvar e. 617 * Put into a linked list, or just set the RD bits in a vector. 618 * 619 */ 620 621 extern (C) list_t listrds(vec_t IN,elem *e,vec_t f) 622 { 623 uint i; 624 uint unambig; 625 Symbol *s; 626 uint nsize; 627 targ_size_t noff; 628 tym_t ty; 629 630 //printf("listrds: "); WReqn(e); printf("\n"); 631 assert(IN); 632 list_t rdlist = null; 633 assert(e.Eoper == OPvar); 634 s = e.EV.Vsym; 635 ty = e.Ety; 636 if (tyscalar(ty)) 637 nsize = cast(uint)size(ty); 638 noff = e.EV.Voffset; 639 unambig = s.Sflags & SFLunambig; 640 if (f) 641 vec_clear(f); 642 for (i = 0; (i = cast(uint) vec_index(i, IN)) < go.defnod.length; ++i) 643 { 644 elem *d = go.defnod[i].DNelem; 645 //printf("\tlooking at "); WReqn(d); printf("\n"); 646 const op = d.Eoper; 647 if (op == OPasm) // assume ASM elems define everything 648 goto listit; 649 if (OTassign(op)) 650 { elem *t = d.EV.E1; 651 652 if (t.Eoper == OPvar && t.EV.Vsym == s) 653 { if (op == OPstreq) 654 goto listit; 655 if (!tyscalar(ty) || !tyscalar(t.Ety)) 656 goto listit; 657 // If t does not overlap e, then it doesn't affect things 658 if (noff + nsize > t.EV.Voffset && 659 t.EV.Voffset + size(t.Ety) > noff) 660 goto listit; // it's an assignment to s 661 } 662 else if (t.Eoper != OPvar && !unambig) 663 goto listit; /* assignment through pointer */ 664 } 665 else if (!unambig) 666 goto listit; /* probably a function call */ 667 continue; 668 669 listit: 670 //printf("\tlisting "); WReqn(d); printf("\n"); 671 if (f) 672 vec_setbit(i,f); 673 else 674 list_prepend(&rdlist,d); // add the definition node 675 } 676 return rdlist; 677 } 678 679 /******************************************** 680 * Look at reaching defs for expressions of the form (v == c) and (v != c). 681 * If all definitions of v are c or are not c, then we can replace the 682 * expression with 1 or 0. 683 */ 684 685 private void eqeqranges() 686 { 687 Symbol *v; 688 int sz; 689 elem *e; 690 targ_llong c; 691 int result; 692 693 for (Elemdata *rel = eqeqlist; rel; rel = rel.next) 694 { 695 e = rel.pelem; 696 v = e.EV.E1.EV.Vsym; 697 if (!(sytab[v.Sclass] & SCRD)) 698 continue; 699 sz = tysize(e.EV.E1.Ety); 700 c = el_tolong(e.EV.E2); 701 702 result = -1; // result not known yet 703 foreach (rdl; ListRange(rel.rdlist)) 704 { 705 elem *erd = cast(elem *) list_ptr(rdl); 706 elem *erd1; 707 int szrd; 708 int tmp; 709 710 elem_debug(erd); 711 if (erd.Eoper != OPeq || 712 (erd1 = erd.EV.E1).Eoper != OPvar || 713 erd.EV.E2.Eoper != OPconst 714 ) 715 goto L1; 716 szrd = tysize(erd1.Ety); 717 if (erd1.EV.Voffset + szrd <= e.EV.E1.EV.Voffset || 718 e.EV.E1.EV.Voffset + sz <= erd1.EV.Voffset) 719 continue; // doesn't affect us, skip it 720 if (szrd != sz || e.EV.E1.EV.Voffset != erd1.EV.Voffset) 721 goto L1; // overlapping - forget it 722 723 tmp = (c == el_tolong(erd.EV.E2)); 724 if (result == -1) 725 result = tmp; 726 else if (result != tmp) 727 goto L1; 728 } 729 if (result >= 0) 730 { 731 //printf("replacing with %d\n",result); 732 el_free(e.EV.E1); 733 el_free(e.EV.E2); 734 e.EV.Vint = (e.Eoper == OPeqeq) ? result : result ^ 1; 735 e.Eoper = OPconst; 736 } 737 L1: 738 } 739 } 740 741 /****************************** 742 * Examine rellist and inclist to determine if any of the signed compare 743 * elems in rellist can be replace by unsigned compares. 744 * rellist is list of relationals in function. 745 * inclist is list of increment elems in function. 746 */ 747 748 private void intranges() 749 { 750 block *rb; 751 block *ib; 752 Symbol *v; 753 elem *rdeq; 754 elem *rdinc; 755 uint incop,relatop; 756 targ_llong initial,increment,final_; 757 758 if (debugc) printf("intranges()\n"); 759 for (Elemdata *rel = rellist; rel; rel = rel.next) 760 { 761 rb = rel.pblock; 762 //printf("rel.pelem: "); WReqn(rel.pelem); printf("\n"); 763 assert(rel.pelem.EV.E1.Eoper == OPvar); 764 v = rel.pelem.EV.E1.EV.Vsym; 765 766 // RD info is only reliable for registers and autos 767 if (!(sytab[v.Sclass] & SCRD)) 768 continue; 769 770 /* Look for two rd's: an = and an increment */ 771 if (list_nitems(rel.rdlist) != 2) 772 continue; 773 rdeq = list_elem(list_next(rel.rdlist)); 774 if (rdeq.Eoper != OPeq) 775 { rdinc = rdeq; 776 rdeq = list_elem(rel.rdlist); 777 if (rdeq.Eoper != OPeq) 778 continue; 779 } 780 else 781 rdinc = list_elem(rel.rdlist); 782 783 static if (0) 784 { 785 printf("\neq: "); WReqn(rdeq); printf("\n"); 786 printf("rel: "); WReqn(rel.pelem); printf("\n"); 787 printf("inc: "); WReqn(rdinc); printf("\n"); 788 } 789 790 incop = rdinc.Eoper; 791 if (!OTpost(incop) && incop != OPaddass && incop != OPminass) 792 continue; 793 794 /* lvalues should be unambiguous defs */ 795 if (rdeq.EV.E1.Eoper != OPvar || rdinc.EV.E1.Eoper != OPvar) 796 continue; 797 /* rvalues should be constants */ 798 if (rdeq.EV.E2.Eoper != OPconst || rdinc.EV.E2.Eoper != OPconst) 799 continue; 800 801 /* Ensure that the only defs reaching the increment elem (rdinc) */ 802 /* are rdeq and rdinc. */ 803 for (Elemdata *iel = inclist; true; iel = iel.next) 804 { 805 elem *rd1; 806 elem *rd2; 807 808 if (!iel) 809 goto nextrel; 810 ib = iel.pblock; 811 if (iel.pelem != rdinc) 812 continue; /* not our increment elem */ 813 if (list_nitems(iel.rdlist) != 2) 814 { 815 //printf("!= 2\n"); 816 goto nextrel; 817 } 818 rd1 = list_elem(iel.rdlist); 819 rd2 = list_elem(list_next(iel.rdlist)); 820 /* The rd's for the relational elem (rdeq,rdinc) must be */ 821 /* the same as the rd's for tne increment elem (rd1,rd2). */ 822 if (rd1 == rdeq && rd2 == rdinc || rd1 == rdinc && rd2 == rdeq) 823 break; 824 } 825 826 // Check that all paths from rdinc to rdinc must pass through rdrel 827 { 828 int i; 829 830 // ib: block of increment 831 // rb: block of relational 832 i = loopcheck(ib,ib,rb); 833 block_clearvisit(); 834 if (i) 835 continue; 836 } 837 838 /* Gather initial, increment, and final values for loop */ 839 initial = el_tolong(rdeq.EV.E2); 840 increment = el_tolong(rdinc.EV.E2); 841 if (incop == OPpostdec || incop == OPminass) 842 increment = -increment; 843 relatop = rel.pelem.Eoper; 844 final_ = el_tolong(rel.pelem.EV.E2); 845 //printf("initial = %d, increment = %d, final_ = %d\n",initial,increment,final_); 846 847 /* Determine if we can make the relational an unsigned */ 848 if (initial >= 0) 849 { 850 if (final_ >= initial) 851 { 852 if (increment > 0 && ((final_ - initial) % increment) == 0) 853 goto makeuns; 854 } 855 else if (final_ >= 0) 856 { /* 0 <= final_ < initial */ 857 if (increment < 0 && ((final_ - initial) % increment) == 0 && 858 !(final_ + increment < 0 && 859 (relatop == OPge || relatop == OPlt) 860 ) 861 ) 862 { 863 makeuns: 864 if (!tyuns(rel.pelem.EV.E2.Ety)) 865 { 866 rel.pelem.EV.E2.Ety = touns(rel.pelem.EV.E2.Ety); 867 rel.pelem.Nflags |= NFLtouns; 868 869 debug 870 if (debugc) 871 { WReqn(rel.pelem); 872 printf(" made unsigned, initial = %lld, increment = %lld," ~ 873 " final_ = %lld\n",cast(long)initial,cast(long)increment,cast(long)final_); 874 } 875 go.changes++; 876 } 877 878 static if (0) 879 { 880 // Eliminate loop if it is empty 881 if (relatop == OPlt && 882 rb.BC == BCiftrue && 883 list_block(rb.Bsucc) == rb && 884 rb.Belem.Eoper == OPcomma && 885 rb.Belem.EV.E1 == rdinc && 886 rb.Belem.EV.E2 == rel.pelem 887 ) 888 { 889 rel.pelem.Eoper = OPeq; 890 rel.pelem.Ety = rel.pelem.EV.E1.Ety; 891 rb.BC = BCgoto; 892 list_subtract(&rb.Bsucc,rb); 893 list_subtract(&rb.Bpred,rb); 894 895 debug 896 if (debugc) 897 { 898 WReqn(rel.pelem); 899 printf(" eliminated loop\n"); 900 } 901 902 go.changes++; 903 } 904 } 905 } 906 } 907 } 908 909 nextrel: 910 } 911 } 912 913 /****************************** 914 * Look for initialization and increment expressions in loop. 915 * Very similar to intranges(). 916 * Params: 917 * rellist = list of relationals in function 918 * inclist = list of increment elems in function. 919 * erel = loop compare expression of the form (v < c) 920 * rdeq = set to loop initialization of v 921 * rdinc = set to loop increment of v 922 * Returns: 923 * false if cannot find rdeq or rdinc 924 */ 925 926 private bool returnResult(bool result) 927 { 928 elemdatafree(&eqeqlist); 929 elemdatafree(&rellist); 930 elemdatafree(&inclist); 931 return result; 932 } 933 934 bool findloopparameters(elem* erel, ref elem* rdeq, ref elem* rdinc) 935 { 936 if (debugc) printf("findloopparameters()\n"); 937 const bool log = false; 938 939 assert(erel.EV.E1.Eoper == OPvar); 940 Symbol* v = erel.EV.E1.EV.Vsym; 941 942 // RD info is only reliable for registers and autos 943 if (!(sytab[v.Sclass] & SCRD)) 944 return false; 945 946 rd_compute(); // compute rellist, inclist, eqeqlist 947 948 /* Find `erel` in `rellist` 949 */ 950 Elemdata* rel = rellist.find(erel); 951 if (!rel) 952 { 953 if (log) printf("\trel not found\n"); 954 return returnResult(false); 955 } 956 957 block* rb = rel.pblock; 958 //printf("rel.pelem: "); WReqn(rel.pelem); printf("\n"); 959 960 961 // Look for one reaching definition: an increment 962 if (list_nitems(rel.rdlist) != 1) 963 { 964 if (log) printf("\tnitems = %d\n", list_nitems(rel.rdlist)); 965 return returnResult(false); 966 } 967 968 rdinc = list_elem(rel.rdlist); 969 970 static if (0) 971 { 972 printf("\neq: "); WReqn(rdeq); printf("\n"); 973 printf("rel: "); WReqn(rel.pelem); printf("\n"); 974 printf("inc: "); WReqn(rdinc); printf("\n"); 975 } 976 977 uint incop = rdinc.Eoper; 978 if (!OTpost(incop) && incop != OPaddass && incop != OPminass) 979 { 980 if (log) printf("\tnot += or -=\n"); 981 return returnResult(false); 982 } 983 984 Elemdata* iel = inclist.find(rdinc); 985 if (!iel) 986 { 987 if (log) printf("\trdinc not found\n"); 988 return returnResult(false); 989 } 990 991 /* The increment should have two reaching definitions: 992 * the initialization 993 * the increment itself 994 * We already have the increment (as rdinc), but need the initialization (rdeq) 995 */ 996 if (list_nitems(iel.rdlist) != 2) 997 { 998 if (log) printf("nitems != 2\n"); 999 return returnResult(false); 1000 } 1001 elem *rd1 = list_elem(iel.rdlist); 1002 elem *rd2 = list_elem(list_next(iel.rdlist)); 1003 if (rd1 == rdinc) 1004 rdeq = rd2; 1005 else if (rd2 == rdinc) 1006 rdeq = rd1; 1007 else 1008 { 1009 if (log) printf("\tnot (rdeq,rdinc)\n"); 1010 return returnResult(false); 1011 } 1012 1013 // lvalues should be unambiguous defs 1014 if (rdeq.Eoper != OPeq || rdeq.EV.E1.Eoper != OPvar || rdinc.EV.E1.Eoper != OPvar) 1015 { 1016 if (log) printf("\tnot OPvar\n"); 1017 return returnResult(false); 1018 } 1019 1020 // rvalues should be constants 1021 if (rdeq.EV.E2.Eoper != OPconst || rdinc.EV.E2.Eoper != OPconst) 1022 { 1023 if (log) printf("\tnot OPconst\n"); 1024 return returnResult(false); 1025 } 1026 1027 /* Check that all paths from rdinc to rdinc must pass through rdrel 1028 * iel.pblock = block of increment 1029 * rel.pblock = block of relational 1030 */ 1031 int i = loopcheck(iel.pblock,iel.pblock,rel.pblock); 1032 block_clearvisit(); 1033 if (i) 1034 { 1035 if (log) printf("\tnot loopcheck()\n"); 1036 return returnResult(false); 1037 } 1038 1039 return returnResult(true); 1040 } 1041 1042 /*********************** 1043 * Return true if there is a path from start to inc without 1044 * passing through rel. 1045 */ 1046 1047 private int loopcheck(block *start,block *inc,block *rel) 1048 { 1049 if (!(start.Bflags & BFLvisited)) 1050 { start.Bflags |= BFLvisited; /* guarantee eventual termination */ 1051 foreach (list; ListRange(start.Bsucc)) 1052 { 1053 block *b = cast(block *) list_ptr(list); 1054 if (b != rel && (b == inc || loopcheck(b,inc,rel))) 1055 return true; 1056 } 1057 } 1058 return false; 1059 } 1060 1061 /**************************** 1062 * Do copy propagation. 1063 * Copy propagation elems are of the form OPvar=OPvar, and they are 1064 * in go.expnod[]. 1065 */ 1066 1067 1068 void copyprop() 1069 { 1070 out_regcand(&globsym); 1071 if (debugc) printf("copyprop()\n"); 1072 assert(dfo); 1073 1074 Louter: 1075 while (1) 1076 { 1077 flowcp(); /* compute available copy statements */ 1078 if (go.exptop <= 1) 1079 return; // none available 1080 static if (0) 1081 { 1082 foreach (i; 1 .. go.exptop) 1083 { 1084 printf("go.expnod[%d] = (",i); 1085 WReqn(go.expnod[i]); 1086 printf(");\n"); 1087 } 1088 } 1089 foreach (i, b; dfo[]) // for each block 1090 { 1091 if (b.Belem) 1092 { 1093 bool recalc; 1094 static if (0) 1095 { 1096 printf("B%d, elem (",i); 1097 WReqn(b.Belem); printf(")\nBin "); 1098 vec_println(b.Bin); 1099 recalc = copyPropWalk(b.Belem,b.Bin); 1100 printf("Bino "); 1101 vec_println(b.Bin); 1102 printf("Bout "); 1103 vec_println(b.Bout); 1104 } 1105 else 1106 { 1107 recalc = copyPropWalk(b.Belem,b.Bin); 1108 } 1109 /*assert(vec_equal(b.Bin,b.Bout)); */ 1110 /* The previous assert() is correct except */ 1111 /* for the following case: */ 1112 /* a=b; d=a; a=b; */ 1113 /* The vectors don't match because the */ 1114 /* equations changed to: */ 1115 /* a=b; d=b; a=b; */ 1116 /* and the d=b copy elem now reaches the end */ 1117 /* of the block (the d=a elem didn't). */ 1118 if (recalc) 1119 continue Louter; 1120 } 1121 } 1122 return; 1123 } 1124 } 1125 1126 /***************************** 1127 * Walk tree n, doing copy propagation as we go. 1128 * Keep IN up to date. 1129 * Params: 1130 * n = tree to walk & do copy propagation in 1131 * IN = vector of live copy expressions, updated as progress is made 1132 * Returns: 1133 * true if need to recalculate data flow equations and try again 1134 */ 1135 1136 private bool copyPropWalk(elem *n,vec_t IN) 1137 { 1138 bool recalc = false; 1139 int nocp = 0; 1140 1141 void cpwalk(elem* n, vec_t IN) 1142 { 1143 assert(n && IN); 1144 /*chkvecdim(go.exptop,0);*/ 1145 if (recalc) 1146 return; 1147 1148 elem *t; 1149 const op = n.Eoper; 1150 if (op == OPcolon || op == OPcolon2) 1151 { 1152 vec_t L = vec_clone(IN); 1153 cpwalk(n.EV.E1,L); 1154 cpwalk(n.EV.E2,IN); 1155 vec_andass(IN,L); // IN = L & R 1156 vec_free(L); 1157 } 1158 else if (op == OPandand || op == OPoror) 1159 { 1160 cpwalk(n.EV.E1,IN); 1161 vec_t L = vec_clone(IN); 1162 cpwalk(n.EV.E2,L); 1163 vec_andass(IN,L); // IN = L & R 1164 vec_free(L); 1165 } 1166 else if (OTunary(op)) 1167 { 1168 t = n.EV.E1; 1169 if (OTassign(op)) 1170 { 1171 if (t.Eoper == OPind) 1172 cpwalk(t.EV.E1,IN); 1173 } 1174 else if (op == OPctor || op == OPdtor) 1175 { 1176 /* This kludge is necessary because in except_pop() 1177 * an el_match is done on the lvalue. If copy propagation 1178 * changes the OPctor but not the corresponding OPdtor, 1179 * then the match won't happen and except_pop() 1180 * will fail. 1181 */ 1182 nocp++; 1183 cpwalk(t,IN); 1184 nocp--; 1185 } 1186 else 1187 cpwalk(t,IN); 1188 } 1189 else if (OTassign(op)) 1190 { 1191 cpwalk(n.EV.E2,IN); 1192 t = n.EV.E1; 1193 if (t.Eoper == OPind) 1194 cpwalk(t,IN); 1195 else 1196 { 1197 debug if (t.Eoper != OPvar) elem_print(n); 1198 assert(t.Eoper == OPvar); 1199 } 1200 } 1201 else if (ERTOL(n)) 1202 { 1203 cpwalk(n.EV.E2,IN); 1204 cpwalk(n.EV.E1,IN); 1205 } 1206 else if (OTbinary(op)) 1207 { 1208 cpwalk(n.EV.E1,IN); 1209 cpwalk(n.EV.E2,IN); 1210 } 1211 1212 if (OTdef(op)) // if definition elem 1213 { 1214 int ambig; /* true if ambiguous def */ 1215 1216 ambig = !OTassign(op) || t.Eoper == OPind; 1217 uint i; 1218 for (i = 0; (i = cast(uint) vec_index(i, IN)) < go.exptop; ++i) // for each active copy elem 1219 { 1220 Symbol *v; 1221 1222 if (op == OPasm) 1223 goto clr; 1224 1225 /* If this elem could kill the lvalue or the rvalue, */ 1226 /* Clear bit in IN. */ 1227 v = go.expnod[i].EV.E1.EV.Vsym; 1228 if (ambig) 1229 { 1230 if (!(v.Sflags & SFLunambig)) 1231 goto clr; 1232 } 1233 else 1234 { 1235 if (v == t.EV.Vsym) 1236 goto clr; 1237 } 1238 v = go.expnod[i].EV.E2.EV.Vsym; 1239 if (ambig) 1240 { 1241 if (!(v.Sflags & SFLunambig)) 1242 goto clr; 1243 } 1244 else 1245 { 1246 if (v == t.EV.Vsym) 1247 goto clr; 1248 } 1249 continue; 1250 1251 clr: /* this copy elem is not available */ 1252 vec_clearbit(i,IN); /* so remove it from the vector */ 1253 } /* foreach */ 1254 1255 /* If this is a copy elem in go.expnod[] */ 1256 /* Set bit in IN. */ 1257 if ((op == OPeq || op == OPstreq) && n.EV.E1.Eoper == OPvar && 1258 n.EV.E2.Eoper == OPvar && n.Eexp) 1259 vec_setbit(n.Eexp,IN); 1260 } 1261 else if (op == OPvar && !nocp) // if reference to variable v 1262 { 1263 Symbol *v = n.EV.Vsym; 1264 1265 //printf("Checking copyprop for '%s', ty=x%x\n",v.Sident,n.Ety); 1266 symbol_debug(v); 1267 const ty = n.Ety; 1268 uint sz = tysize(n.Ety); 1269 if (sz == -1 && !tyfunc(n.Ety)) 1270 sz = cast(uint)type_size(v.Stype); 1271 1272 elem *foundelem = null; 1273 Symbol *f; 1274 for (uint i = 0; (i = cast(uint) vec_index(i, IN)) < go.exptop; ++i) // for all active copy elems 1275 { 1276 elem* c = go.expnod[i]; 1277 assert(c); 1278 1279 uint csz = tysize(c.EV.E1.Ety); 1280 if (c.Eoper == OPstreq) 1281 csz = cast(uint)type_size(c.ET); 1282 assert(cast(int)csz >= 0); 1283 1284 //printf("looking at: ("); WReqn(c); printf("), ty=x%x\n",c.EV.E1.Ety); 1285 /* Not only must symbol numbers match, but */ 1286 /* offsets too (in case of arrays) and sizes */ 1287 /* (in case of unions). */ 1288 if (v == c.EV.E1.EV.Vsym && 1289 n.EV.Voffset >= c.EV.E1.EV.Voffset && 1290 n.EV.Voffset + sz <= c.EV.E1.EV.Voffset + csz) 1291 { 1292 if (foundelem) 1293 { 1294 if (c.EV.E2.EV.Vsym != f) 1295 goto noprop; 1296 } 1297 else 1298 { 1299 foundelem = c; 1300 f = foundelem.EV.E2.EV.Vsym; 1301 } 1302 } 1303 } 1304 if (foundelem) /* if we can do the copy prop */ 1305 { 1306 debug if (debugc) 1307 { 1308 printf("Copyprop, from '%s'(%d) to '%s'(%d)\n", 1309 (v.Sident[0]) ? cast(char *)v.Sident.ptr : "temp".ptr, v.Ssymnum, 1310 (f.Sident[0]) ? cast(char *)f.Sident.ptr : "temp".ptr, f.Ssymnum); 1311 } 1312 1313 type *nt = n.ET; 1314 targ_size_t noffset = n.EV.Voffset; 1315 el_copy(n,foundelem.EV.E2); 1316 n.Ety = ty; // retain original type 1317 n.ET = nt; 1318 n.EV.Voffset += noffset - foundelem.EV.E1.EV.Voffset; 1319 1320 /* original => rewrite 1321 * v = f 1322 * g = v => g = f 1323 * f = x 1324 * d = g => d = f !!error 1325 * Therefore, if n appears as an rvalue in go.expnod[], then recalc 1326 */ 1327 for (size_t j = 1; j < go.exptop; ++j) 1328 { 1329 //printf("go.expnod[%d]: ", j); elem_print(go.expnod[j]); 1330 if (go.expnod[j].EV.E2 == n) 1331 { 1332 recalc = true; 1333 break; 1334 } 1335 } 1336 1337 go.changes++; 1338 } 1339 //else printf("not found\n"); 1340 noprop: 1341 { } 1342 } 1343 } 1344 1345 cpwalk(n, IN); 1346 return recalc; 1347 } 1348 1349 /******************************** 1350 * Remove dead assignments. Those are assignments to a variable v 1351 * for which there are no subsequent uses of v. 1352 */ 1353 1354 private __gshared 1355 { 1356 Barray!(elem*) assnod; /* array of pointers to asg elems */ 1357 vec_t ambigref; /* vector of assignment elems that */ 1358 /* are referenced when an ambiguous */ 1359 /* reference is done (as in *p or call) */ 1360 } 1361 1362 void rmdeadass() 1363 { 1364 if (debugc) printf("rmdeadass()\n"); 1365 flowlv(); /* compute live variables */ 1366 foreach (b; dfo[]) // for each block b 1367 { 1368 if (!b.Belem) /* if no elems at all */ 1369 continue; 1370 if (b.Btry) // if in try-block guarded body 1371 continue; 1372 const assnum = numasg(b.Belem); // # of assignment elems 1373 if (assnum == 0) // if no assignment elems 1374 continue; 1375 1376 assnod.setLength(assnum); // pre-allocate sufficient room 1377 vec_t DEAD = vec_calloc(assnum); 1378 vec_t POSS = vec_calloc(assnum); 1379 1380 ambigref = vec_calloc(assnum); 1381 assnod.setLength(0); 1382 accumda(b.Belem,DEAD,POSS); // fill assnod[], compute DEAD and POSS 1383 assert(assnum == assnod.length); 1384 vec_free(ambigref); 1385 1386 vec_orass(POSS,DEAD); /* POSS |= DEAD */ 1387 for (uint j = 0; (j = cast(uint) vec_index(j, POSS)) < assnum; ++j) // for each possible dead asg. 1388 { 1389 Symbol *v; /* v = target of assignment */ 1390 elem *n; 1391 elem *nv; 1392 1393 n = assnod[j]; 1394 nv = n.EV.E1; 1395 v = nv.EV.Vsym; 1396 if (!symbol_isintab(v)) // not considered 1397 continue; 1398 //printf("assnod[%d]: ",j); WReqn(n); printf("\n"); 1399 //printf("\tPOSS\n"); 1400 /* If not positively dead but v is live on a */ 1401 /* successor to b, then v is live. */ 1402 //printf("\tDEAD=%d, live=%d\n",vec_testbit(j,DEAD),vec_testbit(v.Ssymnum,b.Boutlv)); 1403 if (!vec_testbit(j,DEAD) && vec_testbit(v.Ssymnum,b.Boutlv)) 1404 continue; 1405 /* volatile/shared variables are not dead */ 1406 if ((v.ty() | nv.Ety) & (mTYvolatile | mTYshared)) 1407 continue; 1408 debug if (debugc) 1409 { 1410 printf("dead assignment ("); 1411 WReqn(n); 1412 if (vec_testbit(j,DEAD)) 1413 printf(") DEAD\n"); 1414 else 1415 printf(") Boutlv\n"); 1416 } 1417 elimass(n); 1418 go.changes++; 1419 } /* foreach */ 1420 vec_free(DEAD); 1421 vec_free(POSS); 1422 } /* for */ 1423 } 1424 1425 /*************************** 1426 * Remove side effect of assignment elem. 1427 */ 1428 1429 void elimass(elem *n) 1430 { elem *e1; 1431 1432 switch (n.Eoper) 1433 { 1434 case OPvecsto: 1435 n.EV.E2.Eoper = OPcomma; 1436 goto case OPeq; 1437 1438 case OPeq: 1439 case OPstreq: 1440 /* (V=e) => (random constant,e) */ 1441 /* Watch out for (a=b=c) stuff! */ 1442 /* Don't screw up assnod[]. */ 1443 n.Eoper = OPcomma; 1444 n.Ety |= n.EV.E2.Ety & (mTYconst | mTYvolatile | mTYimmutable | mTYshared 1445 | mTYfar 1446 ); 1447 n.EV.E1.Eoper = OPconst; 1448 break; 1449 1450 /* Convert (V op= e) to (V op e) */ 1451 case OPaddass: 1452 case OPminass: 1453 case OPmulass: 1454 case OPdivass: 1455 case OPorass: 1456 case OPandass: 1457 case OPxorass: 1458 case OPmodass: 1459 case OPshlass: 1460 case OPshrass: 1461 case OPashrass: 1462 n.Eoper = cast(ubyte)opeqtoop(n.Eoper); 1463 break; 1464 1465 case OPpostinc: /* (V i++ c) => V */ 1466 case OPpostdec: /* (V i-- c) => V */ 1467 e1 = n.EV.E1; 1468 el_free(n.EV.E2); 1469 el_copy(n,e1); 1470 el_free(e1); 1471 break; 1472 1473 case OPnegass: 1474 n.Eoper = OPneg; 1475 break; 1476 1477 case OPbtc: 1478 case OPbtr: 1479 case OPbts: 1480 n.Eoper = OPbt; 1481 break; 1482 1483 case OPcmpxchg: 1484 n.Eoper = OPcomma; 1485 n.EV.E2.Eoper = OPcomma; 1486 break; 1487 1488 default: 1489 assert(0); 1490 } 1491 } 1492 1493 /************************ 1494 * Compute number of =,op=,i++,i--,--i,++i elems. 1495 * (Unambiguous assignments only. Ambiguous ones would always be live.) 1496 * Some compilers generate better code for ?: than if-then-else. 1497 */ 1498 1499 private uint numasg(elem *e) 1500 { 1501 assert(e); 1502 if (OTassign(e.Eoper) && e.EV.E1.Eoper == OPvar) 1503 { 1504 e.Nflags |= NFLassign; 1505 return 1 + numasg(e.EV.E1) + (OTbinary(e.Eoper) ? numasg(e.EV.E2) : 0); 1506 } 1507 e.Nflags &= ~NFLassign; 1508 return OTunary(e.Eoper) ? numasg(e.EV.E1) : 1509 OTbinary(e.Eoper) ? numasg(e.EV.E1) + numasg(e.EV.E2) : 0; 1510 } 1511 1512 /****************************** 1513 * Tree walk routine for rmdeadass(). 1514 * DEAD = assignments which are dead 1515 * POSS = assignments which are possibly dead 1516 * The algorithm is basically: 1517 * if we have an assignment to v, 1518 * for all defs of v in POSS 1519 * set corresponding bits in DEAD 1520 * set bit for this def in POSS 1521 * if we have a reference to v, 1522 * clear all bits in POSS that are refs of v 1523 */ 1524 1525 private void accumda(elem *n,vec_t DEAD, vec_t POSS) 1526 { 1527 assert(n && DEAD && POSS); 1528 const op = n.Eoper; 1529 switch (op) 1530 { 1531 case OPcolon: 1532 case OPcolon2: 1533 { 1534 vec_t Pl = vec_clone(POSS); 1535 vec_t Pr = vec_clone(POSS); 1536 vec_t Dl = vec_calloc(vec_numbits(POSS)); 1537 vec_t Dr = vec_calloc(vec_numbits(POSS)); 1538 accumda(n.EV.E1,Dl,Pl); 1539 accumda(n.EV.E2,Dr,Pr); 1540 1541 /* D |= P & (Dl & Dr) | ~P & (Dl | Dr) */ 1542 /* P = P & (Pl & Pr) | ~P & (Pl | Pr) */ 1543 /* = Pl & Pr | ~P & (Pl | Pr) */ 1544 const vecdim = cast(uint)vec_dim(DEAD); 1545 for (uint i = 0; i < vecdim; i++) 1546 { 1547 DEAD[i] |= (POSS[i] & Dl[i] & Dr[i]) | 1548 (~POSS[i] & (Dl[i] | Dr[i])); 1549 POSS[i] = (Pl[i] & Pr[i]) | (~POSS[i] & (Pl[i] | Pr[i])); 1550 } 1551 vec_free(Pl); vec_free(Pr); vec_free(Dl); vec_free(Dr); 1552 break; 1553 } 1554 1555 case OPandand: 1556 case OPoror: 1557 { 1558 accumda(n.EV.E1,DEAD,POSS); 1559 // Substituting into the above equations Pl=P and Dl=0: 1560 // D |= Dr - P 1561 // P = Pr 1562 vec_t Pr = vec_clone(POSS); 1563 vec_t Dr = vec_calloc(vec_numbits(POSS)); 1564 accumda(n.EV.E2,Dr,Pr); 1565 vec_subass(Dr,POSS); 1566 vec_orass(DEAD,Dr); 1567 vec_copy(POSS,Pr); 1568 vec_free(Pr); vec_free(Dr); 1569 break; 1570 } 1571 1572 case OPvar: 1573 { 1574 Symbol *v = n.EV.Vsym; 1575 targ_size_t voff = n.EV.Voffset; 1576 uint vsize = tysize(n.Ety); 1577 1578 // We have a reference. Clear all bits in POSS that 1579 // could be referenced. 1580 1581 foreach (const i; 0 .. cast(uint)assnod.length) 1582 { 1583 elem *ti = assnod[i].EV.E1; 1584 if (v == ti.EV.Vsym && 1585 ((vsize == -1 || tysize(ti.Ety) == -1) || 1586 // If symbol references overlap 1587 (voff + vsize > ti.EV.Voffset && 1588 ti.EV.Voffset + tysize(ti.Ety) > voff) 1589 ) 1590 ) 1591 { 1592 vec_clearbit(i,POSS); 1593 } 1594 } 1595 break; 1596 } 1597 1598 case OPasm: // reference everything 1599 foreach (const i; 0 .. cast(uint)assnod.length) 1600 vec_clearbit(i,POSS); 1601 break; 1602 1603 case OPbt: 1604 accumda(n.EV.E1,DEAD,POSS); 1605 accumda(n.EV.E2,DEAD,POSS); 1606 vec_subass(POSS,ambigref); // remove possibly refed 1607 break; 1608 1609 case OPind: 1610 case OPucall: 1611 case OPucallns: 1612 case OPvp_fp: 1613 accumda(n.EV.E1,DEAD,POSS); 1614 vec_subass(POSS,ambigref); // remove possibly refed 1615 // assignments from list 1616 // of possibly dead ones 1617 break; 1618 1619 case OPconst: 1620 break; 1621 1622 case OPcall: 1623 case OPcallns: 1624 case OPmemcpy: 1625 case OPstrcpy: 1626 case OPmemset: 1627 accumda(n.EV.E2,DEAD,POSS); 1628 goto case OPstrlen; 1629 1630 case OPstrlen: 1631 accumda(n.EV.E1,DEAD,POSS); 1632 vec_subass(POSS,ambigref); // remove possibly refed 1633 // assignments from list 1634 // of possibly dead ones 1635 break; 1636 1637 case OPstrcat: 1638 case OPstrcmp: 1639 case OPmemcmp: 1640 accumda(n.EV.E1,DEAD,POSS); 1641 accumda(n.EV.E2,DEAD,POSS); 1642 vec_subass(POSS,ambigref); // remove possibly refed 1643 // assignments from list 1644 // of possibly dead ones 1645 break; 1646 1647 default: 1648 if (OTassign(op)) 1649 { 1650 elem *t; 1651 1652 if (ERTOL(n)) 1653 accumda(n.EV.E2,DEAD,POSS); 1654 t = n.EV.E1; 1655 // if not (v = expression) then gen refs of left tree 1656 if (op != OPeq && op != OPstreq) 1657 accumda(n.EV.E1,DEAD,POSS); 1658 else if (OTunary(t.Eoper)) // if (*e = expression) 1659 accumda(t.EV.E1,DEAD,POSS); 1660 else if (OTbinary(t.Eoper)) 1661 { 1662 accumda(t.EV.E1,DEAD,POSS); 1663 accumda(t.EV.E2,DEAD,POSS); 1664 } 1665 if (!ERTOL(n) && op != OPnegass) 1666 accumda(n.EV.E2,DEAD,POSS); 1667 1668 // if unambiguous assignment, post all possibilities 1669 // to DEAD 1670 if ((op == OPeq || op == OPstreq) && t.Eoper == OPvar) 1671 { 1672 uint tsz = tysize(t.Ety); 1673 if (n.Eoper == OPstreq) 1674 tsz = cast(uint)type_size(n.ET); 1675 foreach (const i; 0 .. cast(uint)assnod.length) 1676 { 1677 elem *ti = assnod[i].EV.E1; 1678 1679 uint tisz = tysize(ti.Ety); 1680 if (assnod[i].Eoper == OPstreq) 1681 tisz = cast(uint)type_size(assnod[i].ET); 1682 1683 // There may be some problem with this next 1684 // statement with unions. 1685 if (ti.EV.Vsym == t.EV.Vsym && 1686 ti.EV.Voffset == t.EV.Voffset && 1687 tisz == tsz && 1688 !(t.Ety & (mTYvolatile | mTYshared)) && 1689 //t.EV.Vsym.Sflags & SFLunambig && 1690 vec_testbit(i,POSS)) 1691 { 1692 vec_setbit(i,DEAD); 1693 } 1694 } 1695 } 1696 1697 // if assignment operator, post this def to POSS 1698 if (n.Nflags & NFLassign) 1699 { 1700 const i = cast(uint)assnod.length; 1701 vec_setbit(i,POSS); 1702 1703 // if variable could be referenced by a pointer 1704 // or a function call, mark the assignment in 1705 // ambigref 1706 if (!(t.EV.Vsym.Sflags & SFLunambig)) 1707 { 1708 vec_setbit(i,ambigref); 1709 1710 debug if (debugc) 1711 { 1712 printf("ambiguous lvalue: "); 1713 WReqn(n); 1714 printf("\n"); 1715 } 1716 } 1717 1718 assnod.push(n); 1719 } 1720 } 1721 else if (OTrtol(op)) 1722 { 1723 accumda(n.EV.E2,DEAD,POSS); 1724 accumda(n.EV.E1,DEAD,POSS); 1725 } 1726 else if (OTbinary(op)) 1727 { 1728 accumda(n.EV.E1,DEAD,POSS); 1729 accumda(n.EV.E2,DEAD,POSS); 1730 } 1731 else if (OTunary(op)) 1732 accumda(n.EV.E1,DEAD,POSS); 1733 break; 1734 } 1735 } 1736 1737 1738 /*************************** 1739 * Mark all dead variables. Only worry about register candidates. 1740 * Compute live ranges for register candidates. 1741 * Be careful not to compute live ranges for members of structures (CLMOS). 1742 */ 1743 void deadvar() 1744 { 1745 assert(dfo); 1746 1747 /* First, mark each candidate as dead. */ 1748 /* Initialize vectors for live ranges. */ 1749 for (SYMIDX i = 0; i < globsym.top; i++) 1750 { 1751 Symbol *s = globsym.tab[i]; 1752 1753 if (s.Sflags & SFLunambig) 1754 { 1755 s.Sflags |= SFLdead; 1756 if (s.Sflags & GTregcand) 1757 { 1758 s.Srange = vec_realloc(s.Srange, maxblks); 1759 vec_clear(s.Srange); 1760 } 1761 } 1762 } 1763 1764 /* Go through trees and "liven" each one we see. */ 1765 foreach (i, b; dfo[]) 1766 if (b.Belem) 1767 dvwalk(b.Belem,cast(uint)i); 1768 1769 /* Compute live variables. Set bit for block in live range */ 1770 /* if variable is in the IN set for that block. */ 1771 flowlv(); /* compute live variables */ 1772 for (SYMIDX i = 0; i < globsym.top; i++) 1773 { 1774 if (globsym.tab[i].Srange /*&& globsym.tab[i].Sclass != CLMOS*/) 1775 foreach (j, b; dfo[]) 1776 if (vec_testbit(i,b.Binlv)) 1777 vec_setbit(cast(uint)j,globsym.tab[i].Srange); 1778 } 1779 1780 /* Print results */ 1781 for (SYMIDX i = 0; i < globsym.top; i++) 1782 { 1783 char *p; 1784 Symbol *s = globsym.tab[i]; 1785 1786 if (s.Sflags & SFLdead && s.Sclass != SCparameter && s.Sclass != SCregpar) 1787 s.Sflags &= ~GTregcand; // do not put dead variables in registers 1788 debug 1789 { 1790 p = cast(char *) s.Sident.ptr ; 1791 if (s.Sflags & SFLdead) 1792 if (debugc) printf("Symbol %d '%s' is dead\n",i,p); 1793 if (debugc && s.Srange /*&& s.Sclass != CLMOS*/) 1794 { 1795 printf("Live range for %d '%s': ",i,p); 1796 vec_println(s.Srange); 1797 } 1798 } 1799 } 1800 } 1801 1802 1803 /***************************** 1804 * Tree walk support routine for deadvar(). 1805 * Input: 1806 * n = elem to look at 1807 * i = block index 1808 */ 1809 private void dvwalk(elem *n,uint i) 1810 { 1811 for (; true; n = n.EV.E1) 1812 { 1813 assert(n); 1814 if (n.Eoper == OPvar || n.Eoper == OPrelconst) 1815 { 1816 Symbol *s = n.EV.Vsym; 1817 1818 s.Sflags &= ~SFLdead; 1819 if (s.Srange) 1820 vec_setbit(i,s.Srange); 1821 } 1822 else if (!OTleaf(n.Eoper)) 1823 { 1824 if (OTbinary(n.Eoper)) 1825 dvwalk(n.EV.E2,i); 1826 continue; 1827 } 1828 break; 1829 } 1830 } 1831 1832 /********************************* 1833 * Optimize very busy expressions (VBEs). 1834 */ 1835 1836 private __gshared vec_t blockseen; /* which blocks we have visited */ 1837 1838 void verybusyexp() 1839 { 1840 elem **pn; 1841 uint j,l; 1842 1843 if (debugc) printf("verybusyexp()\n"); 1844 flowvbe(); /* compute VBEs */ 1845 if (go.exptop <= 1) return; /* if no VBEs */ 1846 assert(go.expblk.length); 1847 if (blockinit()) 1848 return; // can't handle ASM blocks 1849 compdom(); /* compute dominators */ 1850 /*setvecdim(go.exptop);*/ 1851 genkillae(); /* compute Bgen and Bkill for */ 1852 /* AEs */ 1853 /*chkvecdim(go.exptop,0);*/ 1854 blockseen = vec_calloc(dfo.length); 1855 1856 /* Go backwards through dfo so that VBEs are evaluated as */ 1857 /* close as possible to where they are used. */ 1858 foreach_reverse (i, b; dfo[]) // for each block 1859 { 1860 int done; 1861 1862 /* Do not hoist things to blocks that do not */ 1863 /* divide the flow of control. */ 1864 1865 switch (b.BC) 1866 { 1867 case BCiftrue: 1868 case BCswitch: 1869 break; 1870 1871 default: 1872 continue; 1873 } 1874 1875 /* Find pointer to last statement in current elem */ 1876 pn = &(b.Belem); 1877 if (*pn) 1878 { 1879 while ((*pn).Eoper == OPcomma) 1880 pn = &((*pn).EV.E2); 1881 /* If last statement has side effects, */ 1882 /* don't do these VBEs. Potentially we */ 1883 /* could by assigning the result to */ 1884 /* a temporary, and rewriting the tree */ 1885 /* from (n) to (T=n,T) and installing */ 1886 /* the VBE as (T=n,VBE,T). This */ 1887 /* may not buy us very much, so we will */ 1888 /* just skip it for now. */ 1889 /*if (sideeffect(*pn))*/ 1890 if (!(*pn).Eexp) 1891 continue; 1892 } 1893 1894 /* Eliminate all elems that have already been */ 1895 /* hoisted (indicated by go.expnod[] == 0). */ 1896 /* Constants are not useful as VBEs. */ 1897 /* Eliminate all elems from Bout that are not in blocks */ 1898 /* that are dominated by b. */ 1899 static if (0) 1900 { 1901 printf("block %d Bout = ",i); 1902 vec_println(b.Bout); 1903 } 1904 done = true; 1905 for (j = 0; (j = cast(uint) vec_index(j, b.Bout)) < go.exptop; ++j) 1906 { 1907 if (go.expnod[j] == null || 1908 !!OTleaf(go.expnod[j].Eoper) || 1909 !dom(b,go.expblk[j])) 1910 vec_clearbit(j,b.Bout); 1911 else 1912 done = false; 1913 } 1914 if (done) continue; 1915 1916 /* Eliminate from Bout all elems that are killed by */ 1917 /* a block between b and that elem. */ 1918 static if (0) 1919 { 1920 printf("block %d Bout = ",i); 1921 vec_println(b.Bout); 1922 } 1923 for (j = 0; (j = cast(uint) vec_index(j, b.Bout)) < go.exptop; ++j) 1924 { 1925 vec_clear(blockseen); 1926 foreach (bl; ListRange(go.expblk[j].Bpred)) 1927 { 1928 if (killed(j,list_block(bl),b)) 1929 { 1930 vec_clearbit(j,b.Bout); 1931 break; 1932 } 1933 } 1934 } 1935 1936 /* For each elem still left, make sure that there */ 1937 /* exists a path from b to j along which there is */ 1938 /* no other use of j (else it would be a CSE, and */ 1939 /* it would be a waste of time to hoist it). */ 1940 static if (0) 1941 { 1942 printf("block %d Bout = ",i); 1943 vec_println(b.Bout); 1944 } 1945 1946 for (j = 0; (j = cast(uint) vec_index(j, b.Bout)) < go.exptop; ++j) 1947 { 1948 vec_clear(blockseen); 1949 foreach (bl; ListRange(go.expblk[j].Bpred)) 1950 { 1951 if (ispath(j,list_block(bl),b)) 1952 goto L2; 1953 } 1954 vec_clearbit(j,b.Bout); /* thar ain't no path */ 1955 L2: 1956 } 1957 1958 1959 /* For each elem that appears more than once in Bout */ 1960 /* We have a VBE. */ 1961 static if (0) 1962 { 1963 printf("block %d Bout = ",i); 1964 vec_println(b.Bout); 1965 } 1966 1967 for (j = 0; (j = cast(uint) vec_index(j, b.Bout)) < go.exptop; ++j) 1968 { 1969 uint k; 1970 for (k = j + 1; k < go.exptop; k++) 1971 { if (vec_testbit(k,b.Bout) && 1972 el_match(go.expnod[j],go.expnod[k])) 1973 goto foundvbe; 1974 } 1975 continue; /* no VBE here */ 1976 1977 foundvbe: /* we got one */ 1978 debug 1979 { 1980 if (debugc) 1981 { printf("VBE %d,%d, block %d (",j,k, cast(int) i); 1982 WReqn(go.expnod[j]); 1983 printf(");\n"); 1984 } 1985 } 1986 *pn = el_bin(OPcomma,(*pn).Ety, 1987 el_copytree(go.expnod[j]),*pn); 1988 1989 /* Mark all the vbe elems found but one (the */ 1990 /* go.expnod[j] one) so that the expression will */ 1991 /* only be hoisted again if other occurrences */ 1992 /* of the expression are found later. This */ 1993 /* will substitute for the fact that the */ 1994 /* el_copytree() expression does not appear in go.expnod[]. */ 1995 l = k; 1996 do 1997 { 1998 if (k == l || (vec_testbit(k,b.Bout) && 1999 el_match(go.expnod[j],go.expnod[k]))) 2000 { 2001 /* Fix so nobody else will */ 2002 /* vbe this elem */ 2003 go.expnod[k] = null; 2004 vec_clearbit(k,b.Bout); 2005 } 2006 } while (++k < go.exptop); 2007 go.changes++; 2008 } /* foreach */ 2009 } /* for */ 2010 vec_free(blockseen); 2011 } 2012 2013 /**************************** 2014 * Return true if elem j is killed somewhere 2015 * between b and bp. 2016 */ 2017 2018 private int killed(uint j,block *bp,block *b) 2019 { 2020 if (bp == b || vec_testbit(bp.Bdfoidx,blockseen)) 2021 return false; 2022 if (vec_testbit(j,bp.Bkill)) 2023 return true; 2024 vec_setbit(bp.Bdfoidx,blockseen); /* mark as visited */ 2025 foreach (bl; ListRange(bp.Bpred)) 2026 if (killed(j,list_block(bl),b)) 2027 return true; 2028 return false; 2029 } 2030 2031 /*************************** 2032 * Return true if there is a path from b to bp along which 2033 * elem j is not used. 2034 * Input: 2035 * b . block where we want to put the VBE 2036 * bp . block somewhere between b and block containing j 2037 * j = VBE expression elem candidate (index into go.expnod[]) 2038 */ 2039 2040 private int ispath(uint j,block *bp,block *b) 2041 { 2042 /*chkvecdim(go.exptop,0);*/ 2043 if (bp == b) return true; /* the trivial case */ 2044 if (vec_testbit(bp.Bdfoidx,blockseen)) 2045 return false; /* already seen this block */ 2046 vec_setbit(bp.Bdfoidx,blockseen); /* we've visited this block */ 2047 2048 /* false if elem j is used in block bp (and reaches the end */ 2049 /* of bp, indicated by it being an AE in Bgen) */ 2050 uint i; 2051 for (i = 0; (i = cast(uint) vec_index(i, bp.Bgen)) < go.exptop; ++i) // look thru used expressions 2052 { 2053 if (i != j && go.expnod[i] && el_match(go.expnod[i],go.expnod[j])) 2054 return false; 2055 } 2056 2057 /* Not used in bp, see if there is a path through a predecessor */ 2058 /* of bp */ 2059 foreach (bl; ListRange(bp.Bpred)) 2060 if (ispath(j,list_block(bl),b)) 2061 return true; 2062 2063 return false; /* j is used along all paths */ 2064 } 2065 2066 }