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