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