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 }