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