1 /** 2 * Manipulating basic blocks and their edges. 3 * 4 * Copyright: Copyright (C) 1986-1997 by Symantec 5 * Copyright (C) 2000-2021 by The D Language Foundation, All Rights Reserved 6 * Authors: $(LINK2 http://www.digitalmars.com, Walter Bright) 7 * License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 8 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/blockopt.d, backend/blockopt.d) 9 * Documentation: https://dlang.org/phobos/dmd_backend_blockopt.html 10 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/blockopt.d 11 */ 12 13 module dmd.backend.blockopt; 14 15 /**************************************************************** 16 * Handle basic blocks. 17 */ 18 19 version (SPP) {} else 20 { 21 22 version (SCPP) 23 version = COMPILE; 24 else version (HTOD) 25 version = COMPILE; 26 27 import core.stdc.stdio; 28 import core.stdc.string; 29 import core.stdc.time; 30 import core.stdc.stdlib; 31 32 import dmd.backend.cc; 33 import dmd.backend.cdef; 34 import dmd.backend.oper; 35 import dmd.backend.dlist; 36 import dmd.backend.dvec; 37 import dmd.backend.el; 38 import dmd.backend.mem; 39 import dmd.backend.type; 40 import dmd.backend.global; 41 import dmd.backend.goh; 42 import dmd.backend.code; 43 import dmd.backend.ty; 44 45 import dmd.backend.barray; 46 47 version (COMPILE) 48 { 49 import parser; 50 import iasm; 51 import precomp; 52 } 53 54 55 version (SCPP) 56 enum SCPP_OR_NTEXCEPTIONS = true; 57 else static if (NTEXCEPTIONS) 58 enum SCPP_OR_NTEXCEPTIONS = true; 59 else 60 enum SCPP_OR_NTEXCEPTIONS = false; 61 62 extern(C++): 63 64 nothrow: 65 66 67 extern (C) void *mem_fcalloc(size_t numbytes); // tk/mem.c 68 extern (C) void mem_free(void*); // tk/mem.c 69 70 alias MEM_PH_FREE = mem_free; 71 72 version (HTOD) 73 void *util_realloc(void* p, size_t n, size_t size); 74 else 75 import dmd.backend.gflow : util_realloc; 76 77 __gshared 78 { 79 block *startblock; // beginning block of function 80 // (can have no predecessors) 81 82 Barray!(block*) dfo; // array of depth first order 83 84 block *curblock; // current block being read in 85 block *block_last; // last block read in 86 87 block *block_freelist; 88 89 block blkzero; // storage allocator 90 } 91 92 pragma(inline, true) block *block_calloc_i() 93 { 94 block *b; 95 96 if (block_freelist) 97 { 98 b = block_freelist; 99 block_freelist = b.Bnext; 100 *b = blkzero; 101 } 102 else 103 b = cast(block *) mem_calloc(block.sizeof); 104 return b; 105 } 106 107 block *block_calloc() 108 { 109 return block_calloc_i(); 110 } 111 112 /********************************* 113 */ 114 115 __gshared goal_t[BCMAX] bc_goal; 116 117 void block_init() 118 { 119 for (size_t i = 0; i < BCMAX; i++) 120 bc_goal[i] = GOALvalue; 121 122 bc_goal[BCgoto] = GOALnone; 123 bc_goal[BCret ] = GOALnone; 124 bc_goal[BCexit] = GOALnone; 125 126 bc_goal[BCiftrue] = GOALflags; 127 } 128 129 /********************************* 130 */ 131 132 void block_term() 133 { 134 while (block_freelist) 135 { 136 block *b = block_freelist.Bnext; 137 mem_free(block_freelist); 138 block_freelist = b; 139 } 140 } 141 142 /************************** 143 * Finish up this block and start the next one. 144 */ 145 146 version (MARS) 147 { 148 void block_next(Blockx *bctx,int bc,block *bn) 149 { 150 bctx.curblock.BC = cast(ubyte) bc; 151 block_last = bctx.curblock; 152 if (!bn) 153 bn = block_calloc_i(); 154 bctx.curblock.Bnext = bn; // next block 155 bctx.curblock = bctx.curblock.Bnext; // new current block 156 bctx.curblock.Btry = bctx.tryblock; 157 bctx.curblock.Bflags |= bctx.flags; 158 } 159 } 160 else 161 { 162 void block_next(int bc,block *bn) 163 { 164 curblock.BC = cast(ubyte) bc; 165 curblock.Bsymend = globsym.length; 166 block_last = curblock; 167 if (!bn) 168 bn = block_calloc_i(); 169 curblock.Bnext = bn; // next block 170 curblock = curblock.Bnext; // new current block 171 curblock.Bsymstart = globsym.length; 172 curblock.Btry = pstate.STbtry; 173 } 174 175 void block_next() 176 { 177 block_next(cast(BC)curblock.BC,null); 178 } 179 } 180 181 /************************** 182 * Finish up this block and start the next one. 183 */ 184 185 version (MARS) 186 { 187 block *block_goto(Blockx *bx,int bc,block *bn) 188 { 189 block *b; 190 191 b = bx.curblock; 192 block_next(bx,bc,bn); 193 b.appendSucc(bx.curblock); 194 return bx.curblock; 195 } 196 } 197 198 /**************************** 199 * Goto a block named gotolbl. 200 * Start a new block that is labelled by newlbl. 201 */ 202 203 version (COMPILE) 204 { 205 206 void block_goto() 207 { 208 block_goto(block_calloc()); 209 } 210 211 void block_goto(block *bn) 212 { 213 block_goto(bn,bn); 214 } 215 216 void block_goto(block *bgoto,block *bnew) 217 { 218 BC bc; 219 220 assert(bgoto); 221 curblock.appendSucc(bgoto); 222 if (curblock.Bcode) // If there is already code in the block 223 // then this is an ASM block 224 bc = BCasm; 225 else 226 bc = BCgoto; // fall thru to next block 227 block_next(bc,bnew); 228 } 229 230 } 231 232 /********************************** 233 * Replace block numbers with block pointers. 234 */ 235 236 void block_ptr() 237 { 238 //printf("block_ptr()\n"); 239 240 uint numblks = 0; 241 for (block *b = startblock; b; b = b.Bnext) /* for each block */ 242 { 243 b.Bblknum = numblks; 244 numblks++; 245 } 246 } 247 248 /******************************* 249 * Build predecessor list (Bpred) for each block. 250 */ 251 252 void block_pred() 253 { 254 //printf("block_pred()\n"); 255 for (block *b = startblock; b; b = b.Bnext) // for each block 256 list_free(&b.Bpred,FPNULL); 257 258 for (block *b = startblock; b; b = b.Bnext) // for each block 259 { 260 //printf("b = %p, BC = ",b); WRBC(b.BC); printf("\n"); 261 foreach (bp; ListRange(b.Bsucc)) 262 { /* for each successor to b */ 263 //printf("\tbs = %p\n",list_block(bp)); 264 assert(list_block(bp)); 265 list_prepend(&(list_block(bp).Bpred),b); 266 } 267 } 268 assert(startblock.Bpred == null); /* startblock has no preds */ 269 } 270 271 /******************************************** 272 * Clear visit. 273 */ 274 275 void block_clearvisit() 276 { 277 for (block *b = startblock; b; b = b.Bnext) // for each block 278 b.Bflags &= ~BFLvisited; // mark as unvisited 279 } 280 281 /******************************************** 282 * Visit block and each of its predecessors. 283 */ 284 285 void block_visit(block *b) 286 { 287 b.Bflags |= BFLvisited; 288 foreach (l; ListRange(b.Bsucc)) 289 { 290 block *bs = list_block(l); 291 assert(bs); 292 if ((bs.Bflags & BFLvisited) == 0) // if not visited 293 block_visit(bs); 294 } 295 } 296 297 /***************************** 298 * Compute number of parents (Bcount) of each basic block. 299 */ 300 301 void block_compbcount() 302 { 303 block_clearvisit(); 304 block_visit(startblock); // visit all reachable blocks 305 elimblks(); // eliminate unvisited blocks 306 } 307 308 /******************************* 309 * Free list of blocks. 310 */ 311 312 void blocklist_free(block **pb) 313 { 314 block *bn; 315 for (block *b = *pb; b; b = bn) 316 { 317 bn = b.Bnext; 318 block_free(b); 319 } 320 *pb = null; 321 } 322 323 /******************************** 324 * Free optimizer gathered data. 325 */ 326 327 void block_optimizer_free(block *b) 328 { 329 static void vfree(ref vec_t v) { vec_free(v); v = null; } 330 vfree(b.Bdom); 331 vfree(b.Binrd); 332 vfree(b.Boutrd); 333 vfree(b.Binlv); 334 vfree(b.Boutlv); 335 vfree(b.Bin); 336 vfree(b.Bout); 337 vfree(b.Bgen); 338 vfree(b.Bkill); 339 vfree(b.Bout2); 340 vfree(b.Bgen2); 341 vfree(b.Bkill2); 342 343 // memset(&b->_BLU,0,sizeof(b->_BLU)); 344 } 345 346 /**************************** 347 * Free a block. 348 */ 349 350 void block_free(block *b) 351 { 352 assert(b); 353 if (b.Belem) 354 el_free(b.Belem); 355 list_free(&b.Bsucc,FPNULL); 356 list_free(&b.Bpred,FPNULL); 357 if (OPTIMIZER) 358 block_optimizer_free(b); 359 switch (b.BC) 360 { 361 case BCswitch: 362 case BCifthen: 363 case BCjmptab: 364 version (MARS) 365 { 366 free(b.Bswitch); 367 } 368 else 369 { 370 MEM_PH_FREE(b.Bswitch); 371 } 372 break; 373 374 version (SCPP) 375 { 376 case BCcatch: 377 type_free(b.Bcatchtype); 378 break; 379 } 380 381 version (MARS) 382 { 383 case BCjcatch: 384 free(b.actionTable); 385 break; 386 } 387 388 case BCasm: 389 version (HTOD) {} else 390 { 391 code_free(b.Bcode); 392 } 393 break; 394 395 default: 396 break; 397 } 398 b.Bnext = block_freelist; 399 block_freelist = b; 400 } 401 402 /**************************** 403 * Hydrate/dehydrate a list of blocks. 404 */ 405 406 version (COMPILE) 407 { 408 static if (HYDRATE) 409 { 410 void blocklist_hydrate(block **pb) 411 { 412 while (isdehydrated(*pb)) 413 { 414 /*printf("blocklist_hydrate(*pb = %p) =",*pb);*/ 415 block *b = cast(block *)ph_hydrate(cast(void**)pb); 416 /*printf(" %p\n",b);*/ 417 el_hydrate(&b.Belem); 418 list_hydrate(&b.Bsucc,FPNULL); 419 list_hydrate(&b.Bpred,FPNULL); 420 cast(void) ph_hydrate(cast(void**)&b.Btry); 421 cast(void) ph_hydrate(cast(void**)&b.Bendscope); 422 symbol_hydrate(&b.Binitvar); 423 switch (b.BC) 424 { 425 case BCtry: 426 symbol_hydrate(&b.catchvar); 427 break; 428 429 case BCcatch: 430 type_hydrate(&b.Bcatchtype); 431 break; 432 433 case BCswitch: 434 ph_hydrate(cast(void**)&b.Bswitch); 435 break; 436 437 case BC_finally: 438 //(void) ph_hydrate(&b.B_ret); 439 break; 440 441 case BC_lpad: 442 symbol_hydrate(&b.flag); 443 break; 444 445 case BCasm: 446 version (HTOD) {} else 447 { 448 code_hydrate(&b.Bcode); 449 } 450 break; 451 452 default: 453 break; 454 } 455 filename_translate(&b.Bsrcpos); 456 srcpos_hydrate(&b.Bsrcpos); 457 pb = &b.Bnext; 458 } 459 } 460 } 461 462 static if (DEHYDRATE) 463 { 464 void blocklist_dehydrate(block **pb) 465 { 466 block *b; 467 468 while ((b = *pb) != null && !isdehydrated(b)) 469 { 470 version (DEBUG_XSYMGEN) 471 { 472 if (xsym_gen && ph_in_head(b)) 473 return; 474 } 475 476 /*printf("blocklist_dehydrate(*pb = %p) =",b);*/ 477 ph_dehydrate(pb); 478 /*printf(" %p\n",*pb);*/ 479 el_dehydrate(&b.Belem); 480 list_dehydrate(&b.Bsucc,FPNULL); 481 list_dehydrate(&b.Bpred,FPNULL); 482 ph_dehydrate(&b.Btry); 483 ph_dehydrate(&b.Bendscope); 484 symbol_dehydrate(&b.Binitvar); 485 switch (b.BC) 486 { 487 case BCtry: 488 symbol_dehydrate(&b.catchvar); 489 break; 490 491 case BCcatch: 492 type_dehydrate(&b.Bcatchtype); 493 break; 494 495 case BCswitch: 496 ph_dehydrate(&b.Bswitch); 497 break; 498 499 case BC_finally: 500 //ph_dehydrate(&b.B_ret); 501 break; 502 503 case BC_lpad: 504 symbol_dehydrate(&b.flag); 505 break; 506 507 case BCasm: 508 code_dehydrate(&b.Bcode); 509 break; 510 511 default: 512 break; 513 } 514 srcpos_dehydrate(&b.Bsrcpos); 515 pb = &b.Bnext; 516 } 517 } 518 } 519 } 520 521 /**************************** 522 * Append elem to the elems comprising the current block. 523 * Read in an expression and put it in curblock.Belem. 524 * If there is one already there, create a tree like: 525 * , 526 * / \ 527 * old e 528 */ 529 530 void block_appendexp(block *b,elem *e) 531 { 532 version (MARS) {} 533 else assert(PARSER); 534 535 if (e) 536 { 537 assert(b); 538 elem_debug(e); 539 elem **pe = &b.Belem; 540 elem *ec = *pe; 541 if (ec != null) 542 { 543 type *t = e.ET; 544 545 if (t) 546 type_debug(t); 547 elem_debug(e); 548 version (MARS) 549 { 550 tym_t ty = e.Ety; 551 552 elem_debug(e); 553 /* Build tree such that (a,b) => (a,(b,e)) */ 554 while (ec.Eoper == OPcomma) 555 { 556 ec.Ety = ty; 557 ec.ET = t; 558 pe = &(ec.EV.E2); 559 ec = *pe; 560 } 561 e = el_bin(OPcomma,ty,ec,e); 562 e.ET = t; 563 } 564 else 565 { 566 /* Build tree such that (a,b) => (a,(b,e)) */ 567 while (ec.Eoper == OPcomma) 568 { 569 el_settype(ec,t); 570 pe = &(ec.EV.E2); 571 ec = *pe; 572 } 573 e = el_bint(OPcomma,t,ec,e); 574 } 575 } 576 *pe = e; 577 } 578 } 579 580 /************************ 581 * Mark curblock as initializing Symbol s. 582 */ 583 584 version (COMPILE) 585 { 586 587 //#undef block_initvar 588 589 void block_initvar(Symbol *s) 590 { 591 symbol_debug(s); 592 curblock.Binitvar = s; 593 } 594 595 } 596 597 /******************* 598 * Mark end of function. 599 * flag: 600 * 0 do a "return" 601 * 1 do a "return 0" 602 */ 603 604 void block_endfunc(int flag) 605 { 606 curblock.Bsymend = globsym.length; 607 curblock.Bendscope = curblock; 608 if (flag) 609 { 610 elem *e = el_longt(tstypes[TYint], 0); 611 block_appendexp(curblock, e); 612 curblock.BC = BCretexp; // put a return at the end 613 } 614 else 615 curblock.BC = BCret; // put a return at the end 616 curblock = null; // undefined from now on 617 block_last = null; 618 } 619 620 /****************************** 621 * Perform branch optimization on basic blocks. 622 */ 623 624 void blockopt(int iter) 625 { 626 if (OPTIMIZER) 627 { 628 blassertsplit(); // only need this once 629 630 int iterationLimit = 200; 631 if (iterationLimit < dfo.length) 632 iterationLimit = cast(int)dfo.length; 633 int count = 0; 634 do 635 { 636 //printf("changes = %d, count = %d, dfo.length = %d\n",go.changes,count,dfo.length); 637 go.changes = 0; 638 bropt(); // branch optimization 639 brrear(); // branch rearrangement 640 blident(); // combine identical blocks 641 blreturn(); // split out return blocks 642 bltailmerge(); // do tail merging 643 brtailrecursion(); // do tail recursion 644 brcombine(); // convert graph to expressions 645 blexit(); 646 if (iter >= 2) 647 brmin(); // minimize branching 648 do 649 { 650 compdfo(); /* compute depth first order (DFO) */ 651 elimblks(); /* remove blocks not in DFO */ 652 assert(count < iterationLimit); 653 count++; 654 } while (mergeblks()); /* merge together blocks */ 655 } while (go.changes); 656 657 debug if (debugw) 658 { 659 numberBlocks(startblock); 660 for (block *b = startblock; b; b = b.Bnext) 661 WRblock(b); 662 } 663 } 664 else 665 { 666 debug 667 { 668 numberBlocks(startblock); 669 } 670 671 /* canonicalize the trees */ 672 for (block *b = startblock; b; b = b.Bnext) 673 { 674 debug if (debugb) 675 WRblock(b); 676 677 if (b.Belem) 678 { 679 b.Belem = doptelem(b.Belem,bc_goal[b.BC] | GOALstruct); 680 if (b.Belem) 681 b.Belem = el_convert(b.Belem); 682 } 683 684 debug if (debugb) 685 { printf("after optelem():\n"); 686 WRblock(b); 687 } 688 } 689 if (localgot) 690 { // Initialize with: 691 // localgot = OPgot; 692 elem *e = el_long(TYnptr, 0); 693 e.Eoper = OPgot; 694 e = el_bin(OPeq, TYnptr, el_var(localgot), e); 695 startblock.Belem = el_combine(e, startblock.Belem); 696 } 697 698 bropt(); /* branch optimization */ 699 brrear(); /* branch rearrangement */ 700 comsubs(); /* eliminate common subexpressions */ 701 702 debug if (debugb) 703 { 704 printf("...................After blockopt().............\n"); 705 numberBlocks(startblock); 706 for (block *b = startblock; b; b = b.Bnext) 707 WRblock(b); 708 } 709 } 710 } 711 712 /*********************************** 713 * Try to remove control structure. 714 * That is, try to resolve if-else, goto and return statements 715 * into &&, || and ?: combinations. 716 */ 717 718 void brcombine() 719 { 720 debug if (debugc) printf("brcombine()\n"); 721 //numberBlocks(startblock); 722 //for (block *b = startblock; b; b = b.Bnext) 723 //WRblock(b); 724 725 if (funcsym_p.Sfunc.Fflags3 & (Fcppeh | Fnteh)) 726 { // Don't mess up extra EH info by eliminating blocks 727 return; 728 } 729 730 do 731 { 732 int anychanges = 0; 733 for (block *b = startblock; b; b = b.Bnext) // for each block 734 { 735 /* Look for [e1 IFFALSE L3,L2] L2: [e2 GOTO L3] L3: [e3] */ 736 /* Replace with [(e1 && e2),e3] */ 737 ubyte bc = b.BC; 738 if (bc == BCiftrue) 739 { 740 block *b2 = b.nthSucc(0); 741 block *b3 = b.nthSucc(1); 742 743 if (list_next(b2.Bpred)) // if more than one predecessor 744 continue; 745 if (b2 == b3) 746 continue; 747 if (b2 == startblock) 748 continue; 749 if (!PARSER && b2.Belem && !OTleaf(b2.Belem.Eoper)) 750 continue; 751 752 ubyte bc2 = b2.BC; 753 if (bc2 == BCgoto && 754 b3 == b2.nthSucc(0)) 755 { 756 b.BC = BCgoto; 757 if (b2.Belem) 758 { 759 int op = OPandand; 760 b.Belem = PARSER ? el_bint(op,tstypes[TYint],b.Belem,b2.Belem) 761 : el_bin(op,TYint,b.Belem,b2.Belem); 762 b2.Belem = null; 763 } 764 list_subtract(&(b.Bsucc),b2); 765 list_subtract(&(b2.Bpred),b); 766 debug if (debugc) printf("brcombine(): if !e1 then e2 => e1 || e2\n"); 767 anychanges++; 768 } 769 else if (list_next(b3.Bpred) || b3 == startblock) 770 continue; 771 else if ((bc2 == BCretexp && b3.BC == BCretexp) 772 //|| (bc2 == BCret && b3.BC == BCret) 773 ) 774 { 775 if (PARSER) 776 { 777 type *t = (bc2 == BCretexp) ? b2.Belem.ET : tstypes[TYvoid]; 778 elem *e = el_bint(OPcolon2,t,b2.Belem,b3.Belem); 779 b.Belem = el_bint(OPcond,t,b.Belem,e); 780 } 781 else 782 { 783 if (!OTleaf(b3.Belem.Eoper)) 784 continue; 785 tym_t ty = (bc2 == BCretexp) ? b2.Belem.Ety : cast(tym_t) TYvoid; 786 elem *e = el_bin(OPcolon2,ty,b2.Belem,b3.Belem); 787 b.Belem = el_bin(OPcond,ty,b.Belem,e); 788 } 789 b.BC = bc2; 790 b.Belem.ET = b2.Belem.ET; 791 b2.Belem = null; 792 b3.Belem = null; 793 list_free(&b.Bsucc,FPNULL); 794 list_subtract(&(b2.Bpred),b); 795 list_subtract(&(b3.Bpred),b); 796 debug if (debugc) printf("brcombine(): if e1 return e2 else return e3 => ret e1?e2:e3\n"); 797 anychanges++; 798 } 799 else if (bc2 == BCgoto && 800 b3.BC == BCgoto && 801 b2.nthSucc(0) == b3.nthSucc(0)) 802 { 803 block *bsucc = b2.nthSucc(0); 804 if (b2.Belem) 805 { 806 elem *e; 807 if (PARSER) 808 { 809 if (b3.Belem) 810 { 811 e = el_bint(OPcolon2,b2.Belem.ET, 812 b2.Belem,b3.Belem); 813 e = el_bint(OPcond,e.ET,b.Belem,e); 814 } 815 else 816 { 817 int op = OPandand; 818 e = el_bint(op,tstypes[TYint],b.Belem,b2.Belem); 819 } 820 } 821 else 822 { 823 if (b3.Belem) 824 { 825 if (!OTleaf(b3.Belem.Eoper)) 826 continue; 827 e = el_bin(OPcolon2,b2.Belem.Ety, 828 b2.Belem,b3.Belem); 829 e = el_bin(OPcond,e.Ety,b.Belem,e); 830 e.ET = b2.Belem.ET; 831 } 832 else 833 { 834 int op = OPandand; 835 e = el_bin(op,TYint,b.Belem,b2.Belem); 836 } 837 } 838 b2.Belem = null; 839 b.Belem = e; 840 } 841 else if (b3.Belem) 842 { 843 int op = OPoror; 844 b.Belem = PARSER ? el_bint(op,tstypes[TYint],b.Belem,b3.Belem) 845 : el_bin(op,TYint,b.Belem,b3.Belem); 846 } 847 b.BC = BCgoto; 848 b3.Belem = null; 849 list_free(&b.Bsucc,FPNULL); 850 851 b.appendSucc(bsucc); 852 list_append(&bsucc.Bpred,b); 853 854 list_free(&(b2.Bpred),FPNULL); 855 list_free(&(b2.Bsucc),FPNULL); 856 list_free(&(b3.Bpred),FPNULL); 857 list_free(&(b3.Bsucc),FPNULL); 858 b2.BC = BCret; 859 b3.BC = BCret; 860 list_subtract(&(bsucc.Bpred),b2); 861 list_subtract(&(bsucc.Bpred),b3); 862 debug if (debugc) printf("brcombine(): if e1 goto e2 else goto e3 => ret e1?e2:e3\n"); 863 anychanges++; 864 } 865 } 866 else if (bc == BCgoto && PARSER) 867 { 868 block *b2 = b.nthSucc(0); 869 if (!list_next(b2.Bpred) && b2.BC != BCasm // if b is only parent 870 && b2 != startblock 871 && b2.BC != BCtry 872 && b2.BC != BC_try 873 && b.Btry == b2.Btry 874 ) 875 { 876 if (b2.Belem) 877 { 878 if (PARSER) 879 { 880 block_appendexp(b,b2.Belem); 881 } 882 else if (b.Belem) 883 b.Belem = el_bin(OPcomma,b2.Belem.Ety,b.Belem,b2.Belem); 884 else 885 b.Belem = b2.Belem; 886 b2.Belem = null; 887 } 888 list_subtract(&b.Bsucc,b2); 889 list_subtract(&b2.Bpred,b); 890 891 /* change predecessor of successors of b2 from b2 to b */ 892 foreach (bl; ListRange(b2.Bsucc)) 893 { 894 list_t bp; 895 for (bp = list_block(bl).Bpred; bp; bp = list_next(bp)) 896 { 897 if (list_block(bp) == b2) 898 bp.ptr = cast(void *)b; 899 } 900 } 901 902 b.BC = b2.BC; 903 b.BS = b2.BS; 904 b.Bsucc = b2.Bsucc; 905 b2.Bsucc = null; 906 b2.BC = BCret; /* a harmless one */ 907 debug if (debugc) printf("brcombine(): %p goto %p eliminated\n",b,b2); 908 anychanges++; 909 } 910 } 911 } 912 if (anychanges) 913 { go.changes++; 914 continue; 915 } 916 } while (0); 917 } 918 919 /*********************** 920 * Branch optimization. 921 */ 922 923 private void bropt() 924 { 925 debug if (debugc) printf("bropt()\n"); 926 assert(!PARSER); 927 for (block *b = startblock; b; b = b.Bnext) // for each block 928 { 929 elem **pn = &(b.Belem); 930 if (OPTIMIZER && *pn) 931 while ((*pn).Eoper == OPcomma) 932 pn = &((*pn).EV.E2); 933 934 elem *n = *pn; 935 if (b.BC == BCiftrue) 936 { 937 assert(n); 938 /* Replace IF (!e) GOTO ... with */ 939 /* IF OPnot (e) GOTO ... */ 940 if (n.Eoper == OPnot) 941 { 942 tym_t tym; 943 944 tym = n.EV.E1.Ety; 945 *pn = el_selecte1(n); 946 (*pn).Ety = tym; 947 for (n = b.Belem; n.Eoper == OPcomma; n = n.EV.E2) 948 n.Ety = tym; 949 b.Bsucc = list_reverse(b.Bsucc); 950 debug if (debugc) printf("CHANGE: if (!e)\n"); 951 go.changes++; 952 } 953 954 /* Take care of IF (constant) */ 955 block *db; 956 if (iftrue(n)) /* if elem is true */ 957 { 958 // select first succ 959 db = b.nthSucc(1); 960 goto L1; 961 } 962 else if (iffalse(n)) 963 { 964 // select second succ 965 db = b.nthSucc(0); 966 967 L1: 968 list_subtract(&(b.Bsucc),db); 969 list_subtract(&(db.Bpred),b); 970 b.BC = BCgoto; 971 /* delete elem if it has no side effects */ 972 b.Belem = doptelem(b.Belem,GOALnone | GOALagain); 973 debug if (debugc) printf("CHANGE: if (const)\n"); 974 go.changes++; 975 } 976 977 /* Look for both destinations being the same */ 978 else if (b.nthSucc(0) == 979 b.nthSucc(1)) 980 { 981 b.BC = BCgoto; 982 db = b.nthSucc(0); 983 list_subtract(&(b.Bsucc),db); 984 list_subtract(&(db.Bpred),b); 985 debug if (debugc) printf("CHANGE: if (e) goto L1; else goto L1;\n"); 986 go.changes++; 987 } 988 } 989 else if (b.BC == BCswitch) 990 { /* see we can evaluate this switch now */ 991 while (n.Eoper == OPcomma) 992 n = n.EV.E2; 993 if (n.Eoper != OPconst) 994 continue; 995 assert(tyintegral(n.Ety)); 996 targ_llong value = el_tolong(n); 997 targ_llong* pv = b.Bswitch; // ptr to switch data 998 assert(pv); 999 uint ncases = cast(uint) *pv++; // # of cases 1000 uint i = 1; // first case 1001 while (1) 1002 { 1003 if (i > ncases) 1004 { 1005 i = 0; // select default 1006 break; 1007 } 1008 if (*pv++ == value) 1009 break; // found it 1010 i++; // next case 1011 } 1012 /* the ith entry in Bsucc is the one we want */ 1013 block *db = b.nthSucc(i); 1014 /* delete predecessors of successors (!) */ 1015 foreach (bl; ListRange(b.Bsucc)) 1016 if (i--) // if not ith successor 1017 { 1018 void *p = list_subtract(&(list_block(bl).Bpred),b); 1019 assert(p == b); 1020 } 1021 1022 /* dump old successor list and create a new one */ 1023 list_free(&b.Bsucc,FPNULL); 1024 b.appendSucc(db); 1025 b.BC = BCgoto; 1026 b.Belem = doptelem(b.Belem,GOALnone | GOALagain); 1027 debug if (debugc) printf("CHANGE: switch (const)\n"); 1028 go.changes++; 1029 } 1030 } 1031 } 1032 1033 /********************************* 1034 * Do branch rearrangement. 1035 */ 1036 1037 private void brrear() 1038 { 1039 debug if (debugc) printf("brrear()\n"); 1040 for (block *b = startblock; b; b = b.Bnext) // for each block 1041 { 1042 foreach (bl; ListRange(b.Bsucc)) 1043 { /* For each transfer of control block pointer */ 1044 int iter = 0; 1045 1046 block *bt = list_block(bl); 1047 1048 /* If it is a transfer to a block that consists */ 1049 /* of nothing but an unconditional transfer, */ 1050 /* Replace transfer address with that */ 1051 /* transfer address. */ 1052 /* Note: There are certain kinds of infinite */ 1053 /* loops which we avoid by putting a lid on */ 1054 /* the number of iterations. */ 1055 1056 version (SCPP) 1057 { 1058 static if (NTEXCEPTIONS) 1059 enum additionalAnd = "b.Btry == bt.Btry && 1060 bt.Btry == bt.nthSucc(0).Btry"; 1061 else 1062 enum additionalAnd = "b.Btry == bt.Btry"; 1063 } 1064 else static if (NTEXCEPTIONS) 1065 enum additionalAnd = "b.Btry == bt.Btry && 1066 bt.Btry == bt.nthSucc(0).Btry"; 1067 else 1068 enum additionalAnd = "true"; 1069 1070 while (bt.BC == BCgoto && !bt.Belem && 1071 mixin(additionalAnd) && 1072 (OPTIMIZER || !(bt.Bsrcpos.Slinnum && configv.addlinenumbers)) && 1073 ++iter < 10) 1074 { 1075 bl.ptr = list_ptr(bt.Bsucc); 1076 if (bt.Bsrcpos.Slinnum && !b.Bsrcpos.Slinnum) 1077 b.Bsrcpos = bt.Bsrcpos; 1078 b.Bflags |= bt.Bflags; 1079 list_append(&(list_block(bl).Bpred),b); 1080 list_subtract(&(bt.Bpred),b); 1081 debug if (debugc) printf("goto.goto\n"); 1082 bt = list_block(bl); 1083 } 1084 1085 // Bsucc after the first are the targets of 1086 // jumps, calls and loops, and as such to do this right 1087 // we need to traverse the Bcode list and fix up 1088 // the IEV2.Vblock pointers. 1089 if (b.BC == BCasm) 1090 break; 1091 } 1092 1093 static if(0) 1094 { 1095 /* Replace cases of */ 1096 /* IF (e) GOTO L1 ELSE L2 */ 1097 /* L1: */ 1098 /* with */ 1099 /* IF OPnot (e) GOTO L2 ELSE L1 */ 1100 /* L1: */ 1101 1102 if (b.BC == BCiftrue || b.BC == BCiffalse) 1103 { 1104 block *bif = b.nthSucc(0); 1105 block *belse = b.nthSucc(1); 1106 1107 if (bif == b.Bnext) 1108 { 1109 b.BC ^= BCiffalse ^ BCiftrue; /* toggle */ 1110 b.setNthSucc(0, belse); 1111 b.setNthSucc(1, bif); 1112 b.Bflags |= bif.Bflags & BFLvisited; 1113 debug if (debugc) printf("if (e) L1 else L2\n"); 1114 } 1115 } 1116 } 1117 } /* for */ 1118 } 1119 1120 /************************* 1121 * Compute depth first order (DFO). 1122 * Equivalent to Aho & Ullman Fig. 13.8. 1123 * Blocks not in dfo[] are unreachable. 1124 * Params: 1125 * dfo = array to fill in in DFO 1126 * startblock = list of blocks 1127 */ 1128 1129 void compdfo() 1130 { 1131 compdfo(dfo, startblock); 1132 } 1133 1134 void compdfo(ref Barray!(block*) dfo, block* startblock) 1135 { 1136 debug if (debugc) printf("compdfo()\n"); 1137 assert(OPTIMIZER); 1138 block_clearvisit(); 1139 debug assert(!PARSER); 1140 dfo.setLength(0); 1141 1142 /****************************** 1143 * Add b's successors to dfo[], then b 1144 */ 1145 void walkDFO(block *b) 1146 { 1147 assert(b); 1148 b.Bflags |= BFLvisited; // executed at least once 1149 1150 foreach (bl; ListRange(b.Bsucc)) // for each successor 1151 { 1152 block *bs = list_block(bl); 1153 assert(bs); 1154 if ((bs.Bflags & BFLvisited) == 0) // if not visited 1155 walkDFO(bs); 1156 } 1157 1158 dfo.push(b); 1159 } 1160 1161 1162 dfo.setLength(0); 1163 walkDFO(startblock); 1164 1165 // Reverse the array 1166 if (dfo.length) 1167 { 1168 size_t i = 0; 1169 size_t k = dfo.length - 1; 1170 while (i < k) 1171 { 1172 auto b = dfo[k]; 1173 dfo[k] = dfo[i]; 1174 dfo[i] = b; 1175 ++i; 1176 --k; 1177 } 1178 1179 foreach (j, b; dfo[]) 1180 b.Bdfoidx = cast(uint)j; 1181 } 1182 1183 static if(0) 1184 { 1185 foreach (i, b; dfo[]) 1186 printf("dfo[%d] = %p\n", cast(int)i, b); 1187 } 1188 } 1189 1190 1191 /************************* 1192 * Remove blocks not marked as visited (they aren't in dfo[]). 1193 * A block is not in dfo[] if not visited. 1194 */ 1195 1196 private void elimblks() 1197 { 1198 debug if (debugc) printf("elimblks()\n"); 1199 block *bf = null; 1200 block *b; 1201 for (block **pb = &startblock; (b = *pb) != null;) 1202 { 1203 if (((b.Bflags & BFLvisited) == 0) // if block is not visited 1204 && ((b.Bflags & BFLlabel) == 0) // need label offset 1205 ) 1206 { 1207 /* for each marked successor S to b */ 1208 /* remove b from S.Bpred. */ 1209 /* Presumably all predecessors to b are unmarked also. */ 1210 foreach (s; ListRange(b.Bsucc)) 1211 { 1212 assert(list_block(s)); 1213 if (list_block(s).Bflags & BFLvisited) /* if it is marked */ 1214 list_subtract(&(list_block(s).Bpred),b); 1215 } 1216 if (b.Balign && b.Bnext && b.Balign > b.Bnext.Balign) 1217 b.Bnext.Balign = b.Balign; 1218 *pb = b.Bnext; // remove from linked list 1219 1220 b.Bnext = bf; 1221 bf = b; // prepend to deferred list to free 1222 debug if (debugc) printf("CHANGE: block %p deleted\n",b); 1223 go.changes++; 1224 } 1225 else 1226 pb = &((*pb).Bnext); 1227 } 1228 1229 // Do deferred free's of the blocks 1230 for ( ; bf; bf = b) 1231 { 1232 b = bf.Bnext; 1233 block_free(bf); 1234 } 1235 1236 debug if (debugc) printf("elimblks done\n"); 1237 } 1238 1239 /********************************** 1240 * Merge together blocks where the first block is a goto to the next 1241 * block and the next block has only the first block as a predecessor. 1242 * Example: 1243 * e1; GOTO L2; 1244 * L2: return e2; 1245 * becomes: 1246 * L2: return (e1 , e2); 1247 * Returns: 1248 * # of merged blocks 1249 */ 1250 1251 private int mergeblks() 1252 { 1253 int merge = 0; 1254 1255 assert(OPTIMIZER); 1256 debug if (debugc) printf("mergeblks()\n"); 1257 foreach (b; dfo[]) 1258 { 1259 if (b.BC == BCgoto) 1260 { block *bL2 = list_block(b.Bsucc); 1261 1262 if (b == bL2) 1263 { 1264 Lcontinue: 1265 continue; 1266 } 1267 assert(bL2.Bpred); 1268 if (!list_next(bL2.Bpred) && bL2 != startblock) 1269 { 1270 if (b == bL2 || bL2.BC == BCasm) 1271 continue; 1272 1273 if (bL2.BC == BCtry || 1274 bL2.BC == BC_try || 1275 b.Btry != bL2.Btry) 1276 continue; 1277 version (SCPP) 1278 { 1279 // If any predecessors of b are BCasm, don't merge. 1280 foreach (bl; ListRange(b.Bpred)) 1281 { 1282 if (list_block(bl).BC == BCasm) 1283 goto Lcontinue; 1284 } 1285 } 1286 1287 /* JOIN the elems */ 1288 elem *e = el_combine(b.Belem,bL2.Belem); 1289 if (b.Belem && bL2.Belem) 1290 e = doptelem(e,bc_goal[bL2.BC] | GOALagain); 1291 bL2.Belem = e; 1292 b.Belem = null; 1293 1294 /* Remove b from predecessors of bL2 */ 1295 list_free(&(bL2.Bpred),FPNULL); 1296 bL2.Bpred = b.Bpred; 1297 b.Bpred = null; 1298 /* Remove bL2 from successors of b */ 1299 list_free(&b.Bsucc,FPNULL); 1300 1301 /* fix up successor list of predecessors */ 1302 foreach (bl; ListRange(bL2.Bpred)) 1303 { 1304 foreach (bs; ListRange(list_block(bl).Bsucc)) 1305 if (list_block(bs) == b) 1306 bs.ptr = cast(void *)bL2; 1307 } 1308 1309 merge++; 1310 debug if (debugc) printf("block %p merged with %p\n",b,bL2); 1311 1312 if (b == startblock) 1313 { /* bL2 is the new startblock */ 1314 debug if (debugc) printf("bL2 is new startblock\n"); 1315 /* Remove bL2 from list of blocks */ 1316 for (block **pb = &startblock; 1; pb = &(*pb).Bnext) 1317 { 1318 assert(*pb); 1319 if (*pb == bL2) 1320 { 1321 *pb = bL2.Bnext; 1322 break; 1323 } 1324 } 1325 1326 /* And relink bL2 at the start */ 1327 bL2.Bnext = startblock.Bnext; 1328 startblock = bL2; // new start 1329 1330 block_free(b); 1331 break; // dfo[] is now invalid 1332 } 1333 } 1334 } 1335 } 1336 return merge; 1337 } 1338 1339 /******************************* 1340 * Combine together blocks that are identical. 1341 */ 1342 1343 private void blident() 1344 { 1345 debug if (debugc) printf("blident()\n"); 1346 assert(startblock); 1347 1348 version (SCPP) 1349 { 1350 // Determine if any asm blocks 1351 int anyasm = 0; 1352 for (block *bn = startblock; bn; bn = bn.Bnext) 1353 { 1354 if (bn.BC == BCasm) 1355 { anyasm = 1; 1356 break; 1357 } 1358 } 1359 } 1360 1361 block *bnext; 1362 for (block *bn = startblock; bn; bn = bnext) 1363 { 1364 bnext = bn.Bnext; 1365 if (bn.Bflags & BFLnomerg) 1366 continue; 1367 1368 for (block *b = bnext; b; b = b.Bnext) 1369 { 1370 /* Blocks are identical if: */ 1371 /* BC match */ 1372 /* not optimized for time or it's a return */ 1373 /* (otherwise looprotate() is undone) */ 1374 /* successors match */ 1375 /* elems match */ 1376 static if (SCPP_OR_NTEXCEPTIONS) 1377 bool additionalAnd = b.Btry == bn.Btry; 1378 else 1379 enum additionalAnd = true; 1380 if (b.BC == bn.BC && 1381 //(!OPTIMIZER || !(go.mfoptim & MFtime) || !b.Bsucc) && 1382 (!OPTIMIZER || !(b.Bflags & BFLnomerg) || !b.Bsucc) && 1383 list_equal(b.Bsucc,bn.Bsucc) && 1384 additionalAnd && 1385 el_match(b.Belem,bn.Belem) 1386 ) 1387 { /* Eliminate block bn */ 1388 switch (b.BC) 1389 { 1390 case BCswitch: 1391 if (memcmp(b.Bswitch,bn.Bswitch,list_nitems(bn.Bsucc) * (*bn.Bswitch).sizeof)) 1392 continue; 1393 break; 1394 1395 case BCtry: 1396 case BCcatch: 1397 case BCjcatch: 1398 case BC_try: 1399 case BC_finally: 1400 case BC_lpad: 1401 case BCasm: 1402 Lcontinue: 1403 continue; 1404 1405 default: 1406 break; 1407 } 1408 assert(!b.Bcode); 1409 1410 foreach (bl; ListRange(bn.Bpred)) 1411 { 1412 block *bp = list_block(bl); 1413 if (bp.BC == BCasm) 1414 // Can't do this because of jmp's and loop's 1415 goto Lcontinue; 1416 } 1417 1418 static if(0) // && SCPP 1419 { 1420 // Predecessors must all be at the same btry level. 1421 if (bn.Bpred) 1422 { 1423 block *bp = list_block(bn.Bpred); 1424 btry = bp.Btry; 1425 if (bp.BC == BCtry) 1426 btry = bp; 1427 } 1428 else 1429 btry = null; 1430 1431 foreach (bl; ListRange(b.Bpred)) 1432 { 1433 block *bp = list_block(bl); 1434 if (bp.BC != BCtry) 1435 bp = bp.Btry; 1436 if (btry != bp) 1437 goto Lcontinue; 1438 } 1439 } 1440 1441 // if bn is startblock, eliminate b instead of bn 1442 if (bn == startblock) 1443 { 1444 goto Lcontinue; // can't handle predecessors to startblock 1445 // unreachable code 1446 //bn = b; 1447 //b = startblock; /* swap b and bn */ 1448 } 1449 1450 version (SCPP) 1451 { 1452 // Don't do it if any predecessors are ASM blocks, since 1453 // we'd have to walk the code list to fix up any jmps. 1454 if (anyasm) 1455 { 1456 foreach (bl; ListRange(bn.Bpred)) 1457 { 1458 block *bp = list_block(bl); 1459 if (bp.BC == BCasm) 1460 goto Lcontinue; 1461 foreach (bls; ListRange(bp.Bsucc)) 1462 if (list_block(bls) == bn && 1463 list_block(bls).BC == BCasm) 1464 goto Lcontinue; 1465 } 1466 } 1467 } 1468 1469 /* Change successors to predecessors of bn to point to */ 1470 /* b instead of bn */ 1471 foreach (bl; ListRange(bn.Bpred)) 1472 { 1473 block *bp = list_block(bl); 1474 foreach (bls; ListRange(bp.Bsucc)) 1475 if (list_block(bls) == bn) 1476 { bls.ptr = cast(void *)b; 1477 list_prepend(&b.Bpred,bp); 1478 } 1479 } 1480 1481 /* Entirely remove predecessor list from bn. */ 1482 /* elimblks() will delete bn entirely. */ 1483 list_free(&(bn.Bpred),FPNULL); 1484 1485 debug 1486 { 1487 assert(bn.BC != BCcatch); 1488 if (debugc) 1489 printf("block B%d (%p) removed, it was same as B%d (%p)\n", 1490 bn.Bdfoidx,bn,b.Bdfoidx,b); 1491 } 1492 1493 go.changes++; 1494 break; 1495 } 1496 } 1497 } 1498 } 1499 1500 /********************************** 1501 * Split out return blocks so the returns can be combined into a 1502 * single block by blident(). 1503 */ 1504 1505 private void blreturn() 1506 { 1507 if (!(go.mfoptim & MFtime)) /* if optimized for space */ 1508 { 1509 int retcount = 0; // number of return counts 1510 1511 /* Find last return block */ 1512 for (block *b = startblock; b; b = b.Bnext) 1513 { 1514 if (b.BC == BCret) 1515 retcount++; 1516 if (b.BC == BCasm) 1517 return; // mucks up blident() 1518 } 1519 1520 if (retcount < 2) /* quit if nothing to combine */ 1521 return; 1522 1523 /* Split return blocks */ 1524 for (block *b = startblock; b; b = b.Bnext) 1525 { 1526 if (b.BC != BCret) 1527 continue; 1528 static if (SCPP_OR_NTEXCEPTIONS) 1529 { 1530 // If no other blocks with the same Btry, don't split 1531 version (SCPP) 1532 { 1533 auto ifCondition = config.flags3 & CFG3eh; 1534 } 1535 else 1536 { 1537 enum ifCondition = true; 1538 } 1539 if (ifCondition) 1540 { 1541 for (block *b2 = startblock; b2; b2 = b2.Bnext) 1542 { 1543 if (b2.BC == BCret && b != b2 && b.Btry == b2.Btry) 1544 goto L1; 1545 } 1546 continue; 1547 } 1548 L1: 1549 } 1550 if (b.Belem) 1551 { /* Split b into a goto and a b */ 1552 debug if (debugc) 1553 printf("blreturn: splitting block B%d\n",b.Bdfoidx); 1554 1555 block *bn = block_calloc(); 1556 bn.BC = BCret; 1557 bn.Bnext = b.Bnext; 1558 static if(SCPP_OR_NTEXCEPTIONS) 1559 { 1560 bn.Btry = b.Btry; 1561 } 1562 b.BC = BCgoto; 1563 b.Bnext = bn; 1564 list_append(&b.Bsucc,bn); 1565 list_append(&bn.Bpred,b); 1566 1567 b = bn; 1568 } 1569 } 1570 1571 blident(); /* combine return blocks */ 1572 } 1573 } 1574 1575 /***************************************** 1576 * Convert comma-expressions into an array of expressions. 1577 */ 1578 1579 extern (D) 1580 private void bl_enlist2(ref Barray!(elem*) elems, elem* e) 1581 { 1582 if (e) 1583 { 1584 elem_debug(e); 1585 if (e.Eoper == OPcomma) 1586 { 1587 bl_enlist2(elems, e.EV.E1); 1588 bl_enlist2(elems, e.EV.E2); 1589 e.EV.E1 = e.EV.E2 = null; 1590 el_free(e); 1591 } 1592 else 1593 elems.push(e); 1594 } 1595 } 1596 1597 private list_t bl_enlist(elem *e) 1598 { 1599 list_t el = null; 1600 1601 if (e) 1602 { 1603 elem_debug(e); 1604 if (e.Eoper == OPcomma) 1605 { 1606 list_t el2 = bl_enlist(e.EV.E1); 1607 el = bl_enlist(e.EV.E2); 1608 e.EV.E1 = e.EV.E2 = null; 1609 el_free(e); 1610 1611 /* Append el2 list to el */ 1612 assert(el); 1613 list_t pl; 1614 for (pl = el; list_next(pl); pl = list_next(pl)) 1615 {} 1616 pl.next = el2; 1617 } 1618 else 1619 list_prepend(&el,e); 1620 } 1621 return el; 1622 } 1623 1624 /***************************************** 1625 * Take a list of expressions and convert it back into an expression tree. 1626 */ 1627 1628 extern (D) 1629 private elem* bl_delist2(elem*[] elems) 1630 { 1631 elem* result = null; 1632 foreach (e; elems) 1633 { 1634 result = el_combine(result, e); 1635 } 1636 return result; 1637 } 1638 1639 private elem * bl_delist(list_t el) 1640 { 1641 elem *e = null; 1642 foreach (els; ListRange(el)) 1643 e = el_combine(list_elem(els),e); 1644 list_free(&el,FPNULL); 1645 return e; 1646 } 1647 1648 /***************************************** 1649 * Do tail merging. 1650 */ 1651 1652 private void bltailmerge() 1653 { 1654 debug if (debugc) printf("bltailmerge()\n"); 1655 assert(!PARSER && OPTIMIZER); 1656 if (!(go.mfoptim & MFtime)) /* if optimized for space */ 1657 { 1658 /* Split each block into a reversed linked list of elems */ 1659 for (block *b = startblock; b; b = b.Bnext) 1660 b.Blist = bl_enlist(b.Belem); 1661 1662 /* Search for two blocks that have the same successor list. 1663 If the first expressions both lists are the same, split 1664 off a new block with that expression in it. 1665 */ 1666 static if (SCPP_OR_NTEXCEPTIONS) 1667 enum additionalAnd = "b.Btry == bn.Btry"; 1668 else 1669 enum additionalAnd = "true"; 1670 for (block *b = startblock; b; b = b.Bnext) 1671 { 1672 if (!b.Blist) 1673 continue; 1674 elem *e = list_elem(b.Blist); 1675 elem_debug(e); 1676 for (block *bn = b.Bnext; bn; bn = bn.Bnext) 1677 { 1678 elem *en; 1679 if (b.BC == bn.BC && 1680 list_equal(b.Bsucc,bn.Bsucc) && 1681 bn.Blist && 1682 el_match(e,(en = list_elem(bn.Blist))) && 1683 mixin(additionalAnd) 1684 ) 1685 { 1686 switch (b.BC) 1687 { 1688 case BCswitch: 1689 if (memcmp(b.Bswitch,bn.Bswitch,list_nitems(bn.Bsucc) * (*bn.Bswitch).sizeof)) 1690 continue; 1691 break; 1692 1693 case BCtry: 1694 case BCcatch: 1695 case BCjcatch: 1696 case BC_try: 1697 case BC_finally: 1698 case BC_lpad: 1699 case BCasm: 1700 continue; 1701 1702 default: 1703 break; 1704 } 1705 1706 /* We've got a match */ 1707 1708 /* Create a new block, bnew, which will be the 1709 merged block. Physically locate it just after bn. 1710 */ 1711 debug if (debugc) 1712 printf("tail merging: %p and %p\n", b, bn); 1713 1714 block *bnew = block_calloc(); 1715 bnew.Bnext = bn.Bnext; 1716 bnew.BC = b.BC; 1717 static if (SCPP_OR_NTEXCEPTIONS) 1718 { 1719 bnew.Btry = b.Btry; 1720 } 1721 if (bnew.BC == BCswitch) 1722 { 1723 bnew.Bswitch = b.Bswitch; 1724 b.Bswitch = null; 1725 bn.Bswitch = null; 1726 } 1727 bn.Bnext = bnew; 1728 1729 /* The successor list to bnew is the same as b's was */ 1730 bnew.Bsucc = b.Bsucc; 1731 b.Bsucc = null; 1732 list_free(&bn.Bsucc,FPNULL); 1733 1734 /* Update the predecessor list of the successor list 1735 of bnew, from b to bnew, and removing bn 1736 */ 1737 foreach (bl; ListRange(bnew.Bsucc)) 1738 { 1739 list_subtract(&list_block(bl).Bpred,b); 1740 list_subtract(&list_block(bl).Bpred,bn); 1741 list_append(&list_block(bl).Bpred,bnew); 1742 } 1743 1744 /* The predecessors to bnew are b and bn */ 1745 list_append(&bnew.Bpred,b); 1746 list_append(&bnew.Bpred,bn); 1747 1748 /* The successors to b and bn are bnew */ 1749 b.BC = BCgoto; 1750 bn.BC = BCgoto; 1751 list_append(&b.Bsucc,bnew); 1752 list_append(&bn.Bsucc,bnew); 1753 1754 go.changes++; 1755 1756 /* Find all the expressions we can merge */ 1757 do 1758 { 1759 list_append(&bnew.Blist,e); 1760 el_free(en); 1761 list_pop(&b.Blist); 1762 list_pop(&bn.Blist); 1763 if (!b.Blist) 1764 goto nextb; 1765 e = list_elem(b.Blist); 1766 if (!bn.Blist) 1767 break; 1768 en = list_elem(bn.Blist); 1769 } while (el_match(e,en)); 1770 } 1771 } 1772 nextb: 1773 } 1774 1775 /* Recombine elem lists into expression trees */ 1776 for (block *b = startblock; b; b = b.Bnext) 1777 b.Belem = bl_delist(b.Blist); 1778 } 1779 } 1780 1781 /********************************** 1782 * Rearrange blocks to minimize jmp's. 1783 */ 1784 1785 private void brmin() 1786 { 1787 version (SCPP) 1788 { 1789 // Dunno how this may mess up generating EH tables. 1790 if (config.flags3 & CFG3eh) // if EH turned on 1791 return; 1792 } 1793 1794 debug if (debugc) printf("brmin()\n"); 1795 debug assert(startblock); 1796 for (block *b = startblock.Bnext; b; b = b.Bnext) 1797 { 1798 block *bnext = b.Bnext; 1799 if (!bnext) 1800 break; 1801 foreach (bl; ListRange(b.Bsucc)) 1802 { 1803 block *bs = list_block(bl); 1804 if (bs == bnext) 1805 goto L1; 1806 } 1807 1808 // b is a block which does not have bnext as a successor. 1809 // Look for a successor of b for which everyone must jmp to. 1810 1811 foreach (bl; ListRange(b.Bsucc)) 1812 { 1813 block *bs = list_block(bl); 1814 block *bn; 1815 foreach (blp; ListRange(bs.Bpred)) 1816 { 1817 block *bsp = list_block(blp); 1818 if (bsp.Bnext == bs) 1819 goto L2; 1820 } 1821 1822 // Move bs so it is the Bnext of b 1823 for (bn = bnext; 1; bn = bn.Bnext) 1824 { 1825 if (!bn) 1826 goto L2; 1827 if (bn.Bnext == bs) 1828 break; 1829 } 1830 bn.Bnext = null; 1831 b.Bnext = bs; 1832 for (bn = bs; bn.Bnext; bn = bn.Bnext) 1833 {} 1834 bn.Bnext = bnext; 1835 debug if (debugc) printf("Moving block %p to appear after %p\n",bs,b); 1836 go.changes++; 1837 break; 1838 1839 L2: 1840 } 1841 1842 1843 L1: 1844 } 1845 } 1846 1847 /******************************** 1848 * Check integrity of blocks. 1849 */ 1850 1851 static if(0) 1852 { 1853 1854 private void block_check() 1855 { 1856 for (block *b = startblock; b; b = b.Bnext) 1857 { 1858 int nsucc = list_nitems(b.Bsucc); 1859 int npred = list_nitems(b.Bpred); 1860 switch (b.BC) 1861 { 1862 case BCgoto: 1863 assert(nsucc == 1); 1864 break; 1865 1866 case BCiftrue: 1867 assert(nsucc == 2); 1868 break; 1869 } 1870 1871 foreach (bl; ListRange(b.Bsucc)) 1872 { 1873 block *bs = list_block(bl); 1874 1875 foreach (bls; ListRange(bs.Bpred)) 1876 { 1877 assert(bls); 1878 if (list_block(bls) == b) 1879 break; 1880 } 1881 } 1882 } 1883 } 1884 1885 } 1886 1887 /*************************************** 1888 * Do tail recursion. 1889 */ 1890 1891 private void brtailrecursion() 1892 { 1893 version (SCPP) 1894 { 1895 // if (tyvariadic(funcsym_p.Stype)) 1896 return; 1897 return; // haven't dealt with struct params, and ctors/dtors 1898 } 1899 if (funcsym_p.Sfunc.Fflags3 & Fnotailrecursion) 1900 return; 1901 if (localgot) 1902 { /* On OSX, tail recursion will result in two OPgot's: 1903 int status5; 1904 struct MyStruct5 { } 1905 void rec5(int i, MyStruct5 s) 1906 { 1907 if( i > 0 ) 1908 { status5++; 1909 rec5(i-1, s); 1910 } 1911 } 1912 */ 1913 1914 return; 1915 } 1916 1917 for (block *b = startblock; b; b = b.Bnext) 1918 { 1919 if (b.BC == BC_try) 1920 return; 1921 elem **pe = &b.Belem; 1922 block *bn = null; 1923 if (*pe && 1924 (b.BC == BCret || 1925 b.BC == BCretexp || 1926 (b.BC == BCgoto && (bn = list_block(b.Bsucc)).Belem == null && 1927 bn.BC == BCret) 1928 ) 1929 ) 1930 { 1931 if (el_anyframeptr(*pe)) // if any OPframeptr's 1932 return; 1933 1934 static elem** skipCommas(elem** pe) 1935 { 1936 while ((*pe).Eoper == OPcomma) 1937 pe = &(*pe).EV.E2; 1938 return pe; 1939 } 1940 1941 pe = skipCommas(pe); 1942 1943 elem *e = *pe; 1944 1945 static bool isCandidate(elem* e) 1946 { 1947 e = *skipCommas(&e); 1948 if (e.Eoper == OPcond) 1949 return isCandidate(e.EV.E2.EV.E1) || isCandidate(e.EV.E2.EV.E2); 1950 1951 return OTcall(e.Eoper) && 1952 e.EV.E1.Eoper == OPvar && 1953 e.EV.E1.EV.Vsym == funcsym_p; 1954 } 1955 1956 if (e.Eoper == OPcond && 1957 (isCandidate(e.EV.E2.EV.E1) || isCandidate(e.EV.E2.EV.E2))) 1958 { 1959 /* Split OPcond into a BCiftrue block and two return blocks 1960 */ 1961 block* b1 = block_calloc(); 1962 block* b2 = block_calloc(); 1963 1964 b1.Belem = e.EV.E2.EV.E1; 1965 e.EV.E2.EV.E1 = null; 1966 1967 b2.Belem = e.EV.E2.EV.E2; 1968 e.EV.E2.EV.E2 = null; 1969 1970 *pe = e.EV.E1; 1971 e.EV.E1 = null; 1972 el_free(e); 1973 1974 if (b.BC == BCgoto) 1975 { 1976 list_subtract(&b.Bsucc, bn); 1977 list_subtract(&bn.Bpred, b); 1978 list_append(&b1.Bsucc, bn); 1979 list_append(&bn.Bpred, b1); 1980 list_append(&b2.Bsucc, bn); 1981 list_append(&bn.Bpred, b2); 1982 } 1983 1984 list_append(&b.Bsucc, b1); 1985 list_append(&b1.Bpred, b); 1986 list_append(&b.Bsucc, b2); 1987 list_append(&b2.Bpred, b); 1988 1989 b1.BC = b.BC; 1990 b2.BC = b.BC; 1991 b.BC = BCiftrue; 1992 1993 b2.Bnext = b.Bnext; 1994 b1.Bnext = b2; 1995 b.Bnext = b1; 1996 continue; 1997 } 1998 1999 if (OTcall(e.Eoper) && 2000 e.EV.E1.Eoper == OPvar && 2001 e.EV.E1.EV.Vsym == funcsym_p) 2002 { 2003 //printf("before:\n"); 2004 //elem_print(*pe); 2005 if (OTunary(e.Eoper)) 2006 { 2007 *pe = el_long(TYint,0); 2008 } 2009 else 2010 { 2011 int si = 0; 2012 elem *e2 = null; 2013 *pe = assignparams(&e.EV.E2,&si,&e2); 2014 *pe = el_combine(*pe,e2); 2015 } 2016 el_free(e); 2017 //printf("after:\n"); 2018 //elem_print(*pe); 2019 2020 if (b.BC == BCgoto) 2021 { 2022 list_subtract(&b.Bsucc,bn); 2023 list_subtract(&bn.Bpred,b); 2024 } 2025 b.BC = BCgoto; 2026 list_append(&b.Bsucc,startblock); 2027 list_append(&startblock.Bpred,b); 2028 2029 // Create a new startblock, bs, because startblock cannot 2030 // have predecessors. 2031 block *bs = block_calloc(); 2032 bs.BC = BCgoto; 2033 bs.Bnext = startblock; 2034 list_append(&bs.Bsucc,startblock); 2035 list_append(&startblock.Bpred,bs); 2036 startblock = bs; 2037 2038 debug if (debugc) printf("tail recursion\n"); 2039 go.changes++; 2040 } 2041 } 2042 } 2043 } 2044 2045 /***************************************** 2046 * Convert parameter expression to assignment statements. 2047 */ 2048 2049 private elem * assignparams(elem **pe,int *psi,elem **pe2) 2050 { 2051 elem *e = *pe; 2052 2053 if (e.Eoper == OPparam) 2054 { 2055 elem *ea = null; 2056 elem *eb = null; 2057 elem *e2 = assignparams(&e.EV.E2,psi,&eb); 2058 elem *e1 = assignparams(&e.EV.E1,psi,&ea); 2059 e.EV.E1 = null; 2060 e.EV.E2 = null; 2061 e = el_combine(e1,e2); 2062 *pe2 = el_combine(eb,ea); 2063 } 2064 else 2065 { 2066 int si = *psi; 2067 type *t; 2068 2069 assert(si < globsym.length); 2070 Symbol *sp = globsym[si]; 2071 Symbol *s = symbol_genauto(sp.Stype); 2072 s.Sfl = FLauto; 2073 int op = OPeq; 2074 if (e.Eoper == OPstrpar) 2075 { 2076 op = OPstreq; 2077 t = e.ET; 2078 elem *ex = e; 2079 e = e.EV.E1; 2080 ex.EV.E1 = null; 2081 el_free(ex); 2082 } 2083 elem *es = el_var(s); 2084 es.Ety = e.Ety; 2085 e = el_bin(op,TYvoid,es,e); 2086 if (op == OPstreq) 2087 e.ET = t; 2088 *pe2 = el_bin(op,TYvoid,el_var(sp),el_copytree(es)); 2089 (*pe2).EV.E1.Ety = es.Ety; 2090 if (op == OPstreq) 2091 (*pe2).ET = t; 2092 *psi = ++si; 2093 *pe = null; 2094 } 2095 return e; 2096 } 2097 2098 /**************************************************** 2099 * Eliminate empty loops. 2100 */ 2101 2102 private void emptyloops() 2103 { 2104 debug if (debugc) printf("emptyloops()\n"); 2105 for (block *b = startblock; b; b = b.Bnext) 2106 { 2107 if (b.BC == BCiftrue && 2108 list_block(b.Bsucc) == b && 2109 list_nitems(b.Bpred) == 2) 2110 { 2111 // Find predecessor to b 2112 block *bpred = list_block(b.Bpred); 2113 if (bpred == b) 2114 bpred = list_block(list_next(b.Bpred)); 2115 if (!bpred.Belem) 2116 continue; 2117 2118 // Find einit 2119 elem *einit; 2120 for (einit = bpred.Belem; einit.Eoper == OPcomma; einit = einit.EV.E2) 2121 { } 2122 if (einit.Eoper != OPeq || 2123 einit.EV.E2.Eoper != OPconst || 2124 einit.EV.E1.Eoper != OPvar) 2125 continue; 2126 2127 // Look for ((i += 1) < limit) 2128 elem *erel = b.Belem; 2129 if (erel.Eoper != OPlt || 2130 erel.EV.E2.Eoper != OPconst || 2131 erel.EV.E1.Eoper != OPaddass) 2132 continue; 2133 2134 elem *einc = erel.EV.E1; 2135 if (einc.EV.E2.Eoper != OPconst || 2136 einc.EV.E1.Eoper != OPvar || 2137 !el_match(einc.EV.E1,einit.EV.E1)) 2138 continue; 2139 2140 if (!tyintegral(einit.EV.E1.Ety) || 2141 el_tolong(einc.EV.E2) != 1 || 2142 el_tolong(einit.EV.E2) >= el_tolong(erel.EV.E2) 2143 ) 2144 continue; 2145 2146 { 2147 erel.Eoper = OPeq; 2148 erel.Ety = erel.EV.E1.Ety; 2149 erel.EV.E1 = el_selecte1(erel.EV.E1); 2150 b.BC = BCgoto; 2151 list_subtract(&b.Bsucc,b); 2152 list_subtract(&b.Bpred,b); 2153 2154 debug if (debugc) 2155 { 2156 WReqn(erel); 2157 printf(" eliminated loop\n"); 2158 } 2159 2160 go.changes++; 2161 } 2162 } 2163 } 2164 } 2165 2166 /****************************************** 2167 * Determine if function has any side effects. 2168 * This means, determine if all the function does is return a value; 2169 * no extraneous definitions or effects or exceptions. 2170 * A function with no side effects can be CSE'd. It does not reference 2171 * statics or indirect references. 2172 */ 2173 2174 void funcsideeffects() 2175 { 2176 version (MARS) 2177 { 2178 //printf("funcsideeffects('%s')\n",funcsym_p.Sident); 2179 for (block *b = startblock; b; b = b.Bnext) 2180 { 2181 if (b.Belem && funcsideeffect_walk(b.Belem)) 2182 { 2183 //printf(" function '%s' has side effects\n",funcsym_p.Sident); 2184 return; 2185 } 2186 } 2187 funcsym_p.Sfunc.Fflags3 |= Fnosideeff; 2188 //printf(" function '%s' has no side effects\n",funcsym_p.Sident); 2189 } 2190 } 2191 2192 version (MARS) 2193 { 2194 2195 private int funcsideeffect_walk(elem *e) 2196 { 2197 assert(e); 2198 elem_debug(e); 2199 if (typemask(e) & (mTYvolatile | mTYshared)) 2200 return 1; 2201 int op = e.Eoper; 2202 switch (op) 2203 { 2204 case OPcall: 2205 case OPucall: 2206 Symbol *s; 2207 if (e.EV.E1.Eoper == OPvar && 2208 tyfunc((s = e.EV.E1.EV.Vsym).Stype.Tty) && 2209 ((s.Sfunc && s.Sfunc.Fflags3 & Fnosideeff) || s == funcsym_p) 2210 ) 2211 break; 2212 goto Lside; 2213 2214 // Note: we should allow assignments to local variables as 2215 // not being a 'side effect'. 2216 2217 default: 2218 assert(op < OPMAX); 2219 return OTsideff(op) || 2220 (OTunary(op) && funcsideeffect_walk(e.EV.E1)) || 2221 (OTbinary(op) && (funcsideeffect_walk(e.EV.E1) || 2222 funcsideeffect_walk(e.EV.E2))); 2223 } 2224 return 0; 2225 2226 Lside: 2227 return 1; 2228 } 2229 2230 } 2231 2232 /******************************* 2233 * Determine if there are any OPframeptr's in the tree. 2234 */ 2235 2236 private int el_anyframeptr(elem *e) 2237 { 2238 while (1) 2239 { 2240 if (OTunary(e.Eoper)) 2241 e = e.EV.E1; 2242 else if (OTbinary(e.Eoper)) 2243 { 2244 if (el_anyframeptr(e.EV.E2)) 2245 return 1; 2246 e = e.EV.E1; 2247 } 2248 else if (e.Eoper == OPframeptr) 2249 return 1; 2250 else 2251 break; 2252 } 2253 return 0; 2254 } 2255 2256 2257 /************************************** 2258 * Split off asserts into their very own BCexit 2259 * blocks after the end of the function. 2260 * This is because assert calls are never in a hot branch. 2261 */ 2262 2263 private void blassertsplit() 2264 { 2265 debug if (debugc) printf("blassertsplit()\n"); 2266 Barray!(elem*) elems; 2267 for (block *b = startblock; b; b = b.Bnext) 2268 { 2269 /* Not sure of effect of jumping out of a try block 2270 */ 2271 if (b.Btry) 2272 continue; 2273 2274 if (b.BC == BCexit) 2275 continue; 2276 2277 elems.reset(); 2278 bl_enlist2(elems, b.Belem); 2279 auto earray = elems[]; 2280 L1: 2281 int dctor = 0; 2282 2283 int accumDctor(elem *e) 2284 { 2285 while (1) 2286 { 2287 if (OTunary(e.Eoper)) 2288 { 2289 e = e.EV.E1; 2290 continue; 2291 } 2292 else if (OTbinary(e.Eoper)) 2293 { 2294 accumDctor(e.EV.E1); 2295 e = e.EV.E2; 2296 continue; 2297 } 2298 else if (e.Eoper == OPdctor) 2299 ++dctor; 2300 else if (e.Eoper == OPddtor) 2301 --dctor; 2302 break; 2303 } 2304 return dctor; 2305 } 2306 2307 foreach (i, e; earray) 2308 { 2309 if (!(dctor == 0 && // don't split block between a dctor..ddtor pair 2310 e.Eoper == OPoror && e.EV.E2.Eoper == OPcall && e.EV.E2.EV.E1.Eoper == OPvar)) 2311 { 2312 accumDctor(e); 2313 continue; 2314 } 2315 Symbol *f = e.EV.E2.EV.E1.EV.Vsym; 2316 if (!(f.Sflags & SFLexit)) 2317 { 2318 accumDctor(e); 2319 continue; 2320 } 2321 2322 if (accumDctor(e.EV.E1)) 2323 { 2324 accumDctor(e.EV.E2); 2325 continue; 2326 } 2327 2328 // Create exit block 2329 block *bexit = block_calloc(); 2330 bexit.BC = BCexit; 2331 bexit.Belem = e.EV.E2; 2332 2333 /* Append bexit to block list 2334 */ 2335 for (block *bx = b; 1; ) 2336 { 2337 block* bxn = bx.Bnext; 2338 if (!bxn) 2339 { 2340 bx.Bnext = bexit; 2341 break; 2342 } 2343 bx = bxn; 2344 } 2345 2346 earray[i] = e.EV.E1; 2347 e.EV.E1 = null; 2348 e.EV.E2 = null; 2349 el_free(e); 2350 2351 /* Split b into two blocks, [b,b2] 2352 */ 2353 block *b2 = block_calloc(); 2354 b2.Bnext = b.Bnext; 2355 b.Bnext = b2; 2356 b2.BC = b.BC; 2357 b2.BS = b.BS; 2358 2359 b.Belem = bl_delist2(earray[0 .. i + 1]); 2360 2361 /* Transfer successors of b to b2. 2362 * Fix up predecessors of successors to b2 to point to b2 instead of b 2363 */ 2364 b2.Bsucc = b.Bsucc; 2365 b.Bsucc = null; 2366 foreach (b2sl; ListRange(b2.Bsucc)) 2367 { 2368 block *b2s = list_block(b2sl); 2369 foreach (b2spl; ListRange(b2s.Bpred)) 2370 { 2371 if (list_block(b2spl) == b) 2372 b2spl.ptr = cast(void *)b2; 2373 } 2374 } 2375 2376 b.BC = BCiftrue; 2377 assert(b.Belem); 2378 list_append(&b.Bsucc, b2); 2379 list_append(&b2.Bpred, b); 2380 list_append(&b.Bsucc, bexit); 2381 list_append(&bexit.Bpred, b); 2382 2383 b = b2; 2384 earray = earray[i + 1 .. earray.length]; // rest of expressions go into b2 2385 debug if (debugc) 2386 { 2387 printf(" split off assert\n"); 2388 } 2389 go.changes++; 2390 goto L1; 2391 } 2392 b.Belem = bl_delist2(earray); 2393 } 2394 elems.dtor(); 2395 } 2396 2397 /************************************************* 2398 * Detect exit blocks and move them to the end. 2399 */ 2400 private void blexit() 2401 { 2402 debug if (debugc) printf("blexit()\n"); 2403 2404 Barray!(block*) bexits; 2405 for (block *b = startblock; b; b = b.Bnext) 2406 { 2407 /* Not sure of effect of jumping out of a try block 2408 */ 2409 if (b.Btry) 2410 continue; 2411 2412 if (b.BC == BCexit) 2413 continue; 2414 2415 if (!b.Belem || el_returns(b.Belem)) 2416 continue; 2417 2418 b.BC = BCexit; 2419 2420 foreach (bsl; ListRange(b.Bsucc)) 2421 { 2422 block *bs = list_block(bsl); 2423 list_subtract(&bs.Bpred, b); 2424 } 2425 list_free(&b.Bsucc, FPNULL); 2426 2427 if (b != startblock && b.Bnext) 2428 bexits.push(b); 2429 2430 debug if (debugc) 2431 printf(" to exit block\n"); 2432 go.changes++; 2433 } 2434 2435 /* Move all the newly detected Bexit blocks in bexits[] to the end 2436 */ 2437 2438 /* First remove them from the list of blocks 2439 */ 2440 size_t i = 0; 2441 block** pb = &startblock.Bnext; 2442 while (1) 2443 { 2444 if (i == bexits.length) 2445 break; 2446 2447 if (*pb == bexits[i]) 2448 { 2449 *pb = (*pb).Bnext; 2450 ++i; 2451 } 2452 else 2453 pb = &(*pb).Bnext; 2454 } 2455 2456 /* Advance pb to point to the last Bnext 2457 */ 2458 while (*pb) 2459 pb = &(*pb).Bnext; 2460 2461 /* Append the bexits[] to the end 2462 */ 2463 foreach (b; bexits[]) 2464 { 2465 *pb = b; 2466 pb = &b.Bnext; 2467 } 2468 *pb = null; 2469 2470 bexits.dtor(); 2471 } 2472 2473 } //!SPP