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