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