1 /**
2  * Code to do the Data Flow Analysis (doesn't act on the data).
3  *
4  * Copyright:   Copyright (C) 1985-1998 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/gflow.d, backend/gflow.d)
9  * Documentation:  https://dlang.org/phobos/dmd_backend_gflow.html
10  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/gflow.d
11  */
12 
13 module dmd.backend.gflow;
14 
15 version (SCPP)
16     version = COMPILE;
17 version (MARS)
18     version = COMPILE;
19 
20 version (COMPILE)
21 {
22 
23 import core.stdc.stdio;
24 import core.stdc.stdlib;
25 import core.stdc.string;
26 
27 import dmd.backend.cc;
28 import dmd.backend.cdef;
29 import dmd.backend.code_x86;
30 import dmd.backend.oper;
31 import dmd.backend.global;
32 import dmd.backend.goh;
33 import dmd.backend.el;
34 import dmd.backend.outbuf;
35 import dmd.backend.ty;
36 import dmd.backend.type;
37 
38 import dmd.backend.barray;
39 import dmd.backend.dlist;
40 import dmd.backend.dvec;
41 
42 nothrow:
43 
44 void vec_setclear(size_t b, vec_t vs, vec_t vc) { vec_setbit(b, vs); vec_clearbit(b, vc); }
45 
46 bool Eunambig(elem* e) { return OTassign(e.Eoper) && e.EV.E1.Eoper == OPvar; }
47 
48 char symbol_isintab(Symbol *s) { return sytab[s.Sclass] & SCSS; }
49 
50 void util_free(void* p) { if (p) free(p); }
51 void *util_calloc(uint n, uint size) { void* p = calloc(n, size); assert(!(n * size) || p); return p; }
52 void *util_realloc(void* p, size_t n, size_t size) { void* q = realloc(p, n * size); assert(!(n * size) || q); return q; }
53 
54 extern (C++):
55 
56 
57 /* Since many routines are nearly identical, we can combine them with   */
58 /* this flag:                                                           */
59 
60 enum
61 {
62     AE = 1,
63     CP,
64     VBE
65 }
66 
67 
68 private __gshared
69 {
70     int flowxx;              // one of the above values
71 
72     vec_t ambigsym = null;
73 }
74 
75 
76 /***************** REACHING DEFINITIONS *********************/
77 
78 /************************************
79  * Compute reaching definitions (RDs).
80  * That is, for each block B and each program variable X
81  * find all elems that could be the last elem that defines
82  * X along some path to B.
83  * Binrd = the set of defs reaching the beginning of B.
84  * Boutrd = the set of defs reaching the end of B.
85  * Bkillrd = set of defs that are killed by some def in B.
86  * Bgenrd = set of defs in B that reach the end of B.
87  */
88 
89 void flowrd()
90 {
91     rdgenkill();            /* Compute Bgen and Bkill for RDs       */
92     if (go.defnod.length == 0)     /* if no definition elems               */
93         return;             /* no analysis to be done               */
94 
95     /* The transfer equation is:                                    */
96     /*      Bin = union of Bouts of all predecessors of B.          */
97     /*      Bout = (Bin - Bkill) | Bgen                             */
98     /* Using Ullman's algorithm:                                    */
99 
100     foreach (b; dfo[])
101         vec_copy(b.Boutrd, b.Bgen);
102 
103     bool anychng;
104     vec_t tmp = vec_calloc(go.defnod.length);
105     do
106     {
107         anychng = false;
108         foreach (b; dfo[])    // for each block
109         {
110             /* Binrd = union of Boutrds of all predecessors of b */
111             vec_clear(b.Binrd);
112             if (b.BC != BCcatch /*&& b.BC != BCjcatch*/)
113             {
114                 /* Set Binrd to 0 to account for:
115                  * i = 0;
116                  * try { i = 1; throw; } catch () { x = i; }
117                  */
118                 foreach (bp; ListRange(b.Bpred))
119                     vec_orass(b.Binrd,list_block(bp).Boutrd);
120             }
121             /* Bout = (Bin - Bkill) | Bgen */
122             vec_sub(tmp,b.Binrd,b.Bkill);
123             vec_orass(tmp,b.Bgen);
124             if (!anychng)
125                 anychng = !vec_equal(tmp,b.Boutrd);
126             vec_copy(b.Boutrd,tmp);
127         }
128     } while (anychng);              /* while any changes to Boutrd  */
129     vec_free(tmp);
130 
131     static if (0)
132     {
133         dbg_printf("Reaching definitions\n");
134         foreach (i, b; dfo[])    // for each block
135         {
136             assert(vec_numbits(b.Binrd) == go.defnod.length);
137             dbg_printf("B%d Bin ", cast(int)i); vec_println(b.Binrd);
138             dbg_printf("  Bgen "); vec_println(b.Bgen);
139             dbg_printf(" Bkill "); vec_println(b.Bkill);
140             dbg_printf("  Bout "); vec_println(b.Boutrd);
141         }
142     }
143 }
144 
145 /***************************
146  * Compute Bgen and Bkill for RDs.
147  */
148 
149 private void rdgenkill()
150 {
151     /* Compute number of definition elems. */
152     uint num_unambig_def = 0;
153     uint deftop = 0;
154     foreach (b; dfo[])    // for each block
155         if (b.Belem)
156         {
157             deftop += numdefelems(b.Belem, &num_unambig_def);
158         }
159 
160     /* Allocate array of pointers to all definition elems   */
161     /*      The elems are in dfo order.                     */
162     /*      go.defnod[]s consist of a elem pointer and a pointer */
163     /*      to the enclosing block.                         */
164     go.defnod.setLength(deftop);
165     if (deftop == 0)
166         return;
167 
168     /* Allocate buffer for the DNunambig vectors
169      */
170     const size_t dim = (deftop + (VECBITS - 1)) >> VECSHIFT;
171     const sz = (dim + 2) * num_unambig_def;
172     go.dnunambig.setLength(sz);
173     go.dnunambig[] = 0;
174 
175     go.defnod.setLength(0);
176     foreach (b; dfo[])    // for each block
177         if (b.Belem)
178             asgdefelems(b, b.Belem);    // fill in go.defnod[]
179     assert(go.defnod.length == deftop);
180 
181     initDNunambigVectors();
182 
183     foreach (b; dfo[])    // for each block
184     {
185         /* dump any existing vectors */
186         vec_free(b.Bgen);
187         vec_free(b.Bkill);
188         vec_free(b.Binrd);
189         vec_free(b.Boutrd);
190 
191         /* calculate and create new vectors */
192         rdelem(&(b.Bgen),&(b.Bkill),b.Belem);
193         if (b.BC == BCasm)
194         {
195             vec_clear(b.Bkill);        // KILL nothing
196             vec_set(b.Bgen);           // GEN everything
197         }
198         b.Binrd = vec_calloc(deftop);
199         b.Boutrd = vec_calloc(deftop);
200     }
201 }
202 
203 /**********************
204  * Compute and return # of definition elems in e.
205  */
206 
207 private uint numdefelems(elem *e, uint *pnum_unambig_def)
208 {
209     uint n = 0;
210     while (1)
211     {
212         assert(e);
213         if (OTdef(e.Eoper))
214         {
215             ++n;
216             if (OTassign(e.Eoper) && e.EV.E1.Eoper == OPvar)
217                 ++*pnum_unambig_def;
218         }
219         if (OTbinary(e.Eoper))
220         {
221             n += numdefelems(e.EV.E1, pnum_unambig_def);
222             e = e.EV.E2;
223         }
224         else if (OTunary(e.Eoper))
225         {
226             e = e.EV.E1;
227         }
228         else
229             break;
230     }
231     return n;
232 }
233 
234 /**************************
235  * Load go.defnod[] array.
236  * Loaded in order of execution of the elems. Not sure if this is
237  * necessary.
238  */
239 
240 private void asgdefelems(block *b,elem *n)
241 {
242     assert(b && n);
243     const op = n.Eoper;
244     if (ERTOL(n))
245     {
246         asgdefelems(b,n.EV.E2);
247         asgdefelems(b,n.EV.E1);
248     }
249     else if (OTbinary(op))
250     {
251         asgdefelems(b,n.EV.E1);
252         asgdefelems(b,n.EV.E2);
253     }
254     else if (OTunary(op))
255         asgdefelems(b,n.EV.E1);
256     if (OTdef(op))
257     {
258         n.Edef = cast(uint)go.defnod.length;
259         go.defnod.push(DefNode(n, b, null));
260     }
261     else
262         n.Edef = ~0;       // just to ensure it is not in the array
263 }
264 
265 /*************************************
266  * Allocate and initialize DNumambig vectors in go.defnod[]
267  */
268 
269 private void initDNunambigVectors()
270 {
271     //printf("initDNunambigVectors()\n");
272     const size_t numbits = go.defnod.length;
273     const size_t dim = (numbits + (VECBITS - 1)) >> VECSHIFT;
274 
275     uint j = 0;
276     foreach (const i; 0 .. go.defnod.length)
277     {
278         elem *e = go.defnod[i].DNelem;
279         if (OTassign(e.Eoper) && e.EV.E1.Eoper == OPvar)
280         {
281             vec_t v = &go.dnunambig[j] + 2;
282             assert(vec_dim(v) == 0);
283             vec_dim(v) = dim;
284             vec_numbits(v) = numbits;
285             j += dim + 2;
286             fillInDNunambig(v, e);
287             go.defnod[i].DNunambig = v;
288         }
289     }
290     assert(j <= go.dnunambig.length);
291 }
292 
293 /*************************************
294  * Allocate and compute rd GEN and KILL.
295  */
296 
297 private void rdelem(vec_t *pgen,vec_t *pkill,   /* where to put result          */
298         elem *n)                                /* tree to evaluate for GEN and KILL */
299 {
300     *pgen = vec_calloc(go.defnod.length);
301     *pkill = vec_calloc(go.defnod.length);
302     if (n)
303         accumrd(*pgen,*pkill,n);
304 }
305 
306 /**************************************
307  * Accumulate GEN and KILL vectors for this elem.
308  */
309 
310 private void accumrd(vec_t GEN,vec_t KILL,elem *n)
311 {
312     assert(GEN && KILL && n);
313     const op = n.Eoper;
314     if (OTunary(op))
315         accumrd(GEN,KILL,n.EV.E1);
316     else if (OTbinary(op))
317     {
318         if (op == OPcolon || op == OPcolon2)
319         {
320             vec_t Gl,Kl,Gr,Kr;
321             rdelem(&Gl,&Kl,n.EV.E1);
322             rdelem(&Gr,&Kr,n.EV.E2);
323 
324             switch (el_returns(n.EV.E1) * 2 | int(el_returns(n.EV.E2)))
325             {
326                 case 3: // E1 and E2 return
327                     /* GEN = (GEN - Kl) | Gl |
328                      *       (GEN - Kr) | Gr
329                      * KILL |= Kl & Kr
330                      * This simplifies to:
331                      * GEN = GEN | (Gl | Gr) | (GEN - (Kl & Kr)
332                      * KILL |= Kl & Kr
333                      */
334                     vec_andass(Kl,Kr);
335                     vec_orass(KILL,Kl);
336 
337                     vec_orass(Gl,Gr);
338                     vec_sub(Gr,GEN,Kl);  // (GEN - (Kl & Kr)
339                     vec_or(GEN,Gl,Gr);
340                     break;
341 
342                 case 2: // E1 returns
343                     /* GEN = (GEN - Kl) | Gl
344                      * KILL |= Kl
345                      */
346                     vec_subass(GEN,Kl);
347                     vec_orass(GEN,Gl);
348                     vec_orass(KILL,Kl);
349                     break;
350 
351                 case 1: // E2 returns
352                     /* GEN = (GEN - Kr) | Gr
353                      * KILL |= Kr
354                      */
355                     vec_subass(GEN,Kr);
356                     vec_orass(GEN,Gr);
357                     vec_orass(KILL,Kr);
358                     break;
359 
360                 case 0: // neither returns
361                     break;
362 
363                 default:
364                     assert(0);
365             }
366 
367             vec_free(Gl);
368             vec_free(Kl);
369             vec_free(Gr);
370             vec_free(Kr);
371         }
372         else if (op == OPandand || op == OPoror)
373         {
374             vec_t Gr,Kr;
375             accumrd(GEN,KILL,n.EV.E1);
376             rdelem(&Gr,&Kr,n.EV.E2);
377             if (el_returns(n.EV.E2))
378                 vec_orass(GEN,Gr);      // GEN |= Gr
379 
380             vec_free(Gr);
381             vec_free(Kr);
382         }
383         else if (OTrtol(op) && ERTOL(n))
384         {
385             accumrd(GEN,KILL,n.EV.E2);
386             accumrd(GEN,KILL,n.EV.E1);
387         }
388         else
389         {
390             accumrd(GEN,KILL,n.EV.E1);
391             accumrd(GEN,KILL,n.EV.E2);
392         }
393     }
394 
395     if (OTdef(op))                  /* if definition elem           */
396         updaterd(n,GEN,KILL);
397 }
398 
399 /******************** AVAILABLE EXPRESSIONS ***********************/
400 
401 /************************************
402  * Compute available expressions (AEs).
403  * That is, expressions whose result is still current.
404  * Bin = the set of AEs reaching the beginning of B.
405  * Bout = the set of AEs reaching the end of B.
406  */
407 
408 void flowae()
409 {
410     flowxx = AE;
411     flowaecp(AE);
412 }
413 
414 /**************************** COPY PROPAGATION ************************/
415 
416 /***************************************
417  * Compute copy propagation info (CPs).
418  * Very similar to AEs (the same code is used).
419  * Using RDs for copy propagation is WRONG!
420  * That is, set of copy statements still valid.
421  * Bin = the set of CPs reaching the beginning of B.
422  * Bout = the set of CPs reaching the end of B.
423  */
424 
425 void flowcp()
426 {
427     flowxx = CP;
428     flowaecp(CP);
429 }
430 
431 /*****************************************
432  * Common flow analysis routines for Available Expressions and
433  * Copy Propagation.
434  * Input:
435  *      flowxx
436  */
437 
438 private void flowaecp(int flowxx)
439 {
440     aecpgenkill(go, flowxx);   // Compute Bgen and Bkill for AEs or CPs
441     if (go.exptop <= 1)        /* if no expressions                    */
442         return;
443 
444     /* The transfer equation is:                    */
445     /*      Bin = & Bout(all predecessors P of B)   */
446     /*      Bout = (Bin - Bkill) | Bgen             */
447     /* Using Ullman's algorithm:                    */
448 
449     vec_clear(startblock.Bin);
450     vec_copy(startblock.Bout,startblock.Bgen); /* these never change */
451     if (startblock.BC == BCiftrue)
452         vec_copy(startblock.Bout2,startblock.Bgen2); // these never change
453 
454     /* For all blocks except startblock     */
455     foreach (b; dfo[1 .. $])
456     {
457         vec_set(b.Bin);        /* Bin = all expressions        */
458 
459         /* Bout = (Bin - Bkill) | Bgen  */
460         vec_sub(b.Bout,b.Bin,b.Bkill);
461         vec_orass(b.Bout,b.Bgen);
462         if (b.BC == BCiftrue)
463         {
464             vec_sub(b.Bout2,b.Bin,b.Bkill2);
465             vec_orass(b.Bout2,b.Bgen2);
466         }
467     }
468 
469     vec_t tmp = vec_calloc(go.exptop);
470     bool anychng;
471     do
472     {
473         anychng = false;
474 
475         // For all blocks except startblock
476         foreach (b; dfo[1 .. $])
477         {
478             // Bin = & of Bout of all predecessors
479             // Bout = (Bin - Bkill) | Bgen
480 
481             bool first = true;
482             foreach (bl; ListRange(b.Bpred))
483             {
484                 block* bp = list_block(bl);
485                 if (bp.BC == BCiftrue && bp.nthSucc(0) != b)
486                 {
487                     if (first)
488                         vec_copy(b.Bin,bp.Bout2);
489                     else
490                         vec_andass(b.Bin,bp.Bout2);
491                 }
492                 else
493                 {
494                     if (first)
495                         vec_copy(b.Bin,bp.Bout);
496                     else
497                         vec_andass(b.Bin,bp.Bout);
498                 }
499                 first = false;
500             }
501             assert(!first);     // it must have had predecessors
502 
503             if (b.BC == BCjcatch)
504             {
505                 /* Set Bin to 0 to account for:
506                     void* pstart = p;
507                     try
508                     {
509                         p = null; // account for this
510                         throw;
511                     }
512                     catch (Throwable o) { assert(p != pstart); }
513                 */
514                 vec_clear(b.Bin);
515             }
516 
517             if (anychng)
518             {
519                 vec_sub(b.Bout,b.Bin,b.Bkill);
520                 vec_orass(b.Bout,b.Bgen);
521             }
522             else
523             {
524                 vec_sub(tmp,b.Bin,b.Bkill);
525                 vec_orass(tmp,b.Bgen);
526                 if (!vec_equal(tmp,b.Bout))
527                 {   // Swap Bout and tmp instead of
528                     // copying tmp over Bout
529                     vec_t v = tmp;
530                     tmp = b.Bout;
531                     b.Bout = v;
532                     anychng = true;
533                 }
534             }
535 
536             if (b.BC == BCiftrue)
537             {   // Bout2 = (Bin - Bkill2) | Bgen2
538                 if (anychng)
539                 {
540                     vec_sub(b.Bout2,b.Bin,b.Bkill2);
541                     vec_orass(b.Bout2,b.Bgen2);
542                 }
543                 else
544                 {
545                     vec_sub(tmp,b.Bin,b.Bkill2);
546                     vec_orass(tmp,b.Bgen2);
547                     if (!vec_equal(tmp,b.Bout2))
548                     {   // Swap Bout and tmp instead of
549                         // copying tmp over Bout2
550                         vec_t v = tmp;
551                         tmp = b.Bout2;
552                         b.Bout2 = v;
553                         anychng = true;
554                     }
555                 }
556             }
557         }
558     } while (anychng);
559     vec_free(tmp);
560 }
561 
562 
563 /***********************************
564  * Compute Bgen and Bkill for AEs, CPs, and VBEs.
565  */
566 
567 private void aecpgenkill(ref GlobalOptimizer go, int flowxx)
568 {
569     block* this_block;
570 
571     /********************************
572      * Assign cp elems to go.expnod[] (in order of evaluation).
573      */
574     void asgcpelems(elem *n)
575     {
576         while (1)
577         {
578             const op = n.Eoper;
579             if (OTunary(op))
580             {
581                 n.Eexp = 0;
582                 n = n.EV.E1;
583                 continue;
584             }
585             else if (OTbinary(op))
586             {
587                 if (ERTOL(n))
588                 {
589                     asgcpelems(n.EV.E2);
590                     asgcpelems(n.EV.E1);
591                 }
592                 else
593                 {
594                     asgcpelems(n.EV.E1);
595                     asgcpelems(n.EV.E2);
596                 }
597 
598                 /* look for elem of the form OPvar=OPvar, where they aren't the
599                  * same variable.
600                  * Don't mix XMM and integer registers.
601                  */
602                 elem* e1;
603                 elem* e2;
604                 if ((op == OPeq || op == OPstreq) &&
605                     (e1 = n.EV.E1).Eoper == OPvar &&
606                     (e2 = n.EV.E2).Eoper == OPvar &&
607                     !((e1.Ety | e2.Ety) & (mTYvolatile | mTYshared)) &&
608                     (!config.fpxmmregs ||
609                      (!tyfloating(e1.EV.Vsym.Stype.Tty) == !tyfloating(e2.EV.Vsym.Stype.Tty))) &&
610                     e1.EV.Vsym != e2.EV.Vsym)
611                 {
612                     n.Eexp = cast(uint)go.expnod.length;
613                     go.expnod.push(n);
614                 }
615                 else
616                     n.Eexp = 0;
617             }
618             else
619                 n.Eexp = 0;
620             return;
621         }
622     }
623 
624     /********************************
625      * Assign ae and vbe elems to go.expnod[] (in order of evaluation).
626      */
627     bool asgaeelems(elem *n)
628     {
629         bool ae;
630 
631         assert(n);
632         const op = n.Eoper;
633         if (OTunary(op))
634         {
635             ae = asgaeelems(n.EV.E1);
636             // Disallow starred references to avoid problems with VBE's
637             // being hoisted before tests of an invalid pointer.
638             if (flowxx == VBE && op == OPind)
639             {
640                 n.Eexp = 0;
641                 return false;
642             }
643         }
644         else if (OTbinary(op))
645         {
646             if (ERTOL(n))
647                 ae = asgaeelems(n.EV.E2) & asgaeelems(n.EV.E1);
648             else
649                 ae = asgaeelems(n.EV.E1) & asgaeelems(n.EV.E2);
650         }
651         else
652             ae = true;
653 
654         if (ae && OTae(op) && !(n.Ety & (mTYvolatile | mTYshared)) &&
655             // Disallow struct AEs, because we can't handle CSEs that are structs
656             tybasic(n.Ety) != TYstruct &&
657             tybasic(n.Ety) != TYarray)
658         {
659             n.Eexp = cast(uint)go.expnod.length;       // remember index into go.expnod[]
660             go.expnod.push(n);
661             if (flowxx == VBE)
662                 go.expblk.push(this_block);
663             return true;
664         }
665         else
666         {
667             n.Eexp = 0;
668             return false;
669         }
670     }
671 
672     go.expnod.setLength(0);             // dump any existing one
673     go.expnod.push(null);
674 
675     go.expblk.setLength(0);             // dump any existing one
676     go.expblk.push(null);
677 
678     foreach (b; dfo[])
679     {
680         if (b.Belem)
681         {
682             if (flowxx == CP)
683                 asgcpelems(b.Belem);
684             else
685             {
686                 this_block = b;    // so asgaeelems knows about this
687                 asgaeelems(b.Belem);
688             }
689         }
690     }
691     go.exptop = cast(uint)go.expnod.length;
692     if (go.exptop <= 1)
693         return;
694 
695     defstarkill();                  /* compute go.defkill and go.starkill */
696 
697     static if (0)
698     {
699         assert(vec_numbits(go.defkill) == go.expnod.length);
700         assert(vec_numbits(go.starkill) == go.expnod.length);
701         assert(vec_numbits(go.vptrkill) == go.expnod.length);
702         dbg_printf("defkill  "); vec_println(go.defkill);
703         if (go.starkill)
704         {   dbg_printf("starkill "); vec_println(go.starkill);}
705         if (go.vptrkill)
706         {   dbg_printf("vptrkill "); vec_println(go.vptrkill); }
707     }
708 
709     foreach (i, b; dfo[])
710     {
711         /* dump any existing vectors    */
712         vec_free(b.Bin);
713         vec_free(b.Bout);
714         vec_free(b.Bgen);
715         vec_free(b.Bkill);
716         b.Bgen = vec_calloc(go.expnod.length);
717         b.Bkill = vec_calloc(go.expnod.length);
718         switch (b.BC)
719         {
720             case BCiftrue:
721                 vec_free(b.Bout2);
722                 vec_free(b.Bgen2);
723                 vec_free(b.Bkill2);
724                 elem* e;
725                 for (e = b.Belem; e.Eoper == OPcomma; e = e.EV.E2)
726                     accumaecp(b.Bgen,b.Bkill,e.EV.E1);
727                 if (e.Eoper == OPandand || e.Eoper == OPoror)
728                 {
729                     accumaecp(b.Bgen,b.Bkill,e.EV.E1);
730                     vec_t Kr = vec_calloc(go.expnod.length);
731                     vec_t Gr = vec_calloc(go.expnod.length);
732                     accumaecp(Gr,Kr,e.EV.E2);
733 
734                     // We might or might not have executed E2
735                     // KILL1 = KILL | Kr
736                     // GEN1 = GEN & ((GEN - Kr) | Gr)
737 
738                     // We definitely executed E2
739                     // KILL2 = (KILL - Gr) | Kr
740                     // GEN2 = (GEN - Kr) | Gr
741 
742                     const uint dim = cast(uint)vec_dim(Kr);
743                     vec_t KILL = b.Bkill;
744                     vec_t GEN = b.Bgen;
745 
746                     foreach (j; 0 .. dim)
747                     {
748                         vec_base_t KILL1 = KILL[j] | Kr[j];
749                         vec_base_t GEN1  = GEN[j] & ((GEN[j] & ~Kr[j]) | Gr[j]);
750 
751                         vec_base_t KILL2 = (KILL[j] & ~Gr[j]) | Kr[j];
752                         vec_base_t GEN2  = (GEN[j] & ~Kr[j]) | Gr[j];
753 
754                         KILL[j] = KILL1;
755                         GEN[j] = GEN1;
756                         Kr[j] = KILL2;
757                         Gr[j] = GEN2;
758                     }
759 
760                     if (e.Eoper == OPandand)
761                     {   b.Bkill  = Kr;
762                         b.Bgen   = Gr;
763                         b.Bkill2 = KILL;
764                         b.Bgen2  = GEN;
765                     }
766                     else
767                     {   b.Bkill  = KILL;
768                         b.Bgen   = GEN;
769                         b.Bkill2 = Kr;
770                         b.Bgen2  = Gr;
771                     }
772                 }
773                 else
774                 {
775                     accumaecp(b.Bgen,b.Bkill,e);
776                     b.Bgen2 = vec_clone(b.Bgen);
777                     b.Bkill2 = vec_clone(b.Bkill);
778                 }
779                 b.Bout2 = vec_calloc(go.expnod.length);
780                 break;
781 
782             case BCasm:
783                 vec_set(b.Bkill);              // KILL everything
784                 vec_clear(b.Bgen);             // GEN nothing
785                 break;
786 
787             default:
788                 // calculate GEN & KILL vectors
789                 if (b.Belem)
790                     accumaecp(b.Bgen,b.Bkill,b.Belem);
791                 break;
792         }
793         static if (0)
794         {
795             printf("block %d Bgen ",i); vec_println(b.Bgen);
796             printf("       Bkill "); vec_println(b.Bkill);
797         }
798         b.Bin = vec_calloc(go.expnod.length);
799         b.Bout = vec_calloc(go.expnod.length);
800     }
801 }
802 
803 /********************************
804  * Compute defkill, starkill and vptrkill vectors.
805  *      starkill:       set of expressions killed when a variable is
806  *                      changed that somebody could be pointing to.
807  *                      (not needed for cp)
808  *                      starkill is a subset of defkill.
809  *      defkill:        set of expressions killed by an ambiguous
810  *                      definition.
811  *      vptrkill:       set of expressions killed by an access to a vptr.
812  */
813 
814 private void defstarkill()
815 {
816     const exptop = go.exptop;
817     vec_recycle(go.defkill, exptop);
818     if (flowxx == CP)
819     {
820         vec_recycle(go.starkill, 0);
821         vec_recycle(go.vptrkill, 0);
822     }
823     else
824     {
825         vec_recycle(go.starkill, exptop);      // and create new ones
826         vec_recycle(go.vptrkill, exptop);      // and create new ones
827     }
828 
829     if (!exptop)
830         return;
831 
832     auto defkill = go.defkill;
833 
834     if (flowxx == CP)
835     {
836         foreach (i, n; go.expnod[1 .. exptop])
837         {
838             const op = n.Eoper;
839             assert(op == OPeq || op == OPstreq);
840             assert(n.EV.E1.Eoper==OPvar && n.EV.E2.Eoper==OPvar);
841 
842             // Set bit in defkill if either the left or the
843             // right variable is killed by an ambiguous def.
844 
845             if (Symbol_isAffected(*n.EV.E1.EV.Vsym) ||
846                 Symbol_isAffected(*n.EV.E2.EV.Vsym))
847             {
848                 vec_setbit(i + 1,defkill);
849             }
850         }
851     }
852     else
853     {
854         auto starkill = go.starkill;
855         auto vptrkill = go.vptrkill;
856 
857         foreach (j, n; go.expnod[1 .. exptop])
858         {
859             const i = j + 1;
860             const op = n.Eoper;
861             switch (op)
862             {
863                 case OPvar:
864                     if (Symbol_isAffected(*n.EV.Vsym))
865                         vec_setbit(i,defkill);
866                     break;
867 
868                 case OPind:         // if a 'starred' ref
869                     if (tybasic(n.EV.E1.Ety) == TYimmutPtr)
870                         break;
871                     goto case OPstrlen;
872 
873                 case OPstrlen:
874                 case OPstrcmp:
875                 case OPmemcmp:
876                 case OPbt:          // OPbt is like OPind
877                     vec_setbit(i,defkill);
878                     vec_setbit(i,starkill);
879                     break;
880 
881                 case OPvp_fp:
882                 case OPcvp_fp:
883                     vec_setbit(i,vptrkill);
884                     goto Lunary;
885 
886                 default:
887                     if (OTunary(op))
888                     {
889                     Lunary:
890                         if (vec_testbit(n.EV.E1.Eexp,defkill))
891                             vec_setbit(i,defkill);
892                         if (vec_testbit(n.EV.E1.Eexp,starkill))
893                             vec_setbit(i,starkill);
894                     }
895                     else if (OTbinary(op))
896                     {
897                         if (vec_testbit(n.EV.E1.Eexp,defkill) ||
898                             vec_testbit(n.EV.E2.Eexp,defkill))
899                                 vec_setbit(i,defkill);
900                         if (vec_testbit(n.EV.E1.Eexp,starkill) ||
901                             vec_testbit(n.EV.E2.Eexp,starkill))
902                                 vec_setbit(i,starkill);
903                     }
904                     break;
905             }
906         }
907     }
908 }
909 
910 /********************************
911  * Compute GEN and KILL vectors only for AEs.
912  * defkill and starkill are assumed to be already set up correctly.
913  * go.expnod[] is assumed to be set up correctly.
914  */
915 
916 void genkillae()
917 {
918     flowxx = AE;
919     assert(go.exptop > 1);
920     foreach (b; dfo[])
921     {
922         assert(b);
923         vec_clear(b.Bgen);
924         vec_clear(b.Bkill);
925         if (b.Belem)
926             accumaecp(b.Bgen,b.Bkill,b.Belem);
927         else if (b.BC == BCasm)
928         {
929             vec_set(b.Bkill);          // KILL everything
930             vec_clear(b.Bgen);         // GEN nothing
931         }
932     }
933 }
934 
935 /************************************
936  * Allocate and compute KILL and GEN vectors for a elem.
937  */
938 
939 private void aecpelem(vec_t *pgen,vec_t *pkill, elem *n)
940 {
941     *pgen = vec_calloc(go.exptop);
942     *pkill = vec_calloc(go.exptop);
943     if (n)
944     {
945         if (flowxx == VBE)
946             accumvbe(*pgen,*pkill,n);
947         else
948             accumaecp(*pgen,*pkill,n);
949     }
950 }
951 
952 /*************************************
953  * Accumulate GEN and KILL sets for AEs and CPs for this elem.
954  */
955 
956 private __gshared
957 {
958     vec_t GEN;       // use static copies to save on parameter passing
959     vec_t KILL;
960 }
961 
962 private void accumaecp(vec_t g,vec_t k,elem *n)
963 {   vec_t GENsave,KILLsave;
964 
965     assert(g && k);
966     GENsave = GEN;
967     KILLsave = KILL;
968     GEN = g;
969     KILL = k;
970     accumaecpx(n);
971     GEN = GENsave;
972     KILL = KILLsave;
973 }
974 
975 private void accumaecpx(elem *n)
976 {
977     elem *t;
978 
979     assert(n);
980     elem_debug(n);
981     const op = n.Eoper;
982 
983     switch (op)
984     {
985         case OPvar:
986         case OPconst:
987         case OPrelconst:
988             if ((flowxx == AE) && n.Eexp)
989             {   uint b;
990                 debug assert(go.expnod[n.Eexp] == n);
991                 b = n.Eexp;
992                 vec_setclear(b,GEN,KILL);
993             }
994             return;
995 
996         case OPcolon:
997         case OPcolon2:
998         {   vec_t Gl,Kl,Gr,Kr;
999 
1000             aecpelem(&Gl,&Kl,n.EV.E1);
1001             aecpelem(&Gr,&Kr,n.EV.E2);
1002 
1003             /* KILL |= Kl | Kr           */
1004             /* GEN =((GEN - Kl) | Gl) &  */
1005             /*     ((GEN - Kr) | Gr)     */
1006 
1007             vec_orass(KILL,Kl);
1008             vec_orass(KILL,Kr);
1009 
1010             vec_sub(Kl,GEN,Kl);
1011             vec_sub(Kr,GEN,Kr);
1012             vec_orass(Kl,Gl);
1013             vec_orass(Kr,Gr);
1014             vec_and(GEN,Kl,Kr);
1015 
1016             vec_free(Gl);
1017             vec_free(Gr);
1018             vec_free(Kl);
1019             vec_free(Kr);
1020             break;
1021         }
1022 
1023         case OPandand:
1024         case OPoror:
1025         {   vec_t Gr,Kr;
1026 
1027             accumaecpx(n.EV.E1);
1028             aecpelem(&Gr,&Kr,n.EV.E2);
1029 
1030             if (el_returns(n.EV.E2))
1031             {
1032                 // KILL |= Kr
1033                 // GEN &= (GEN - Kr) | Gr
1034 
1035                 vec_orass(KILL,Kr);
1036                 vec_sub(Kr,GEN,Kr);
1037                 vec_orass(Kr,Gr);
1038                 vec_andass(GEN,Kr);
1039             }
1040 
1041             vec_free(Gr);
1042             vec_free(Kr);
1043             break;
1044         }
1045 
1046         case OPddtor:
1047         case OPasm:
1048             assert(!n.Eexp);                   // no ASM available expressions
1049             vec_set(KILL);                      // KILL everything
1050             vec_clear(GEN);                     // GEN nothing
1051             return;
1052 
1053         case OPeq:
1054         case OPstreq:
1055             accumaecpx(n.EV.E2);
1056             goto case OPnegass;
1057 
1058         case OPnegass:
1059             accumaecpx(n.EV.E1);
1060             t = n.EV.E1;
1061             break;
1062 
1063         case OPvp_fp:
1064         case OPcvp_fp:                          // if vptr access
1065             if ((flowxx == AE) && n.Eexp)
1066                 vec_orass(KILL,go.vptrkill);       // kill all other vptr accesses
1067             break;
1068 
1069         case OPprefetch:
1070             accumaecpx(n.EV.E1);                  // don't check E2
1071             break;
1072 
1073         default:
1074             if (OTunary(op))
1075             {
1076         case OPind:                             // most common unary operator
1077                 accumaecpx(n.EV.E1);
1078                 debug assert(!OTassign(op));
1079             }
1080             else if (OTbinary(op))
1081             {
1082                 if (OTrtol(op) && ERTOL(n))
1083                 {
1084                     accumaecpx(n.EV.E2);
1085                     accumaecpx(n.EV.E1);
1086                 }
1087                 else
1088                 {
1089                     accumaecpx(n.EV.E1);
1090                     accumaecpx(n.EV.E2);
1091                 }
1092                 if (OTassign(op))               // if assignment operator
1093                     t = n.EV.E1;
1094             }
1095             break;
1096     }
1097 
1098 
1099     /* Do copy propagation stuff first  */
1100 
1101     if (flowxx == CP)
1102     {
1103         if (!OTdef(op))                         /* if not def elem      */
1104             return;
1105         if (!Eunambig(n))                       /* if ambiguous def elem */
1106         {
1107             vec_orass(KILL,go.defkill);
1108             vec_subass(GEN,go.defkill);
1109         }
1110         else                                    /* unambiguous def elem */
1111         {
1112             assert(t.Eoper == OPvar);
1113             Symbol* s = t.EV.Vsym;                  // ptr to var being def'd
1114             foreach (uint i; 1 .. go.exptop)        // for each ae elem
1115             {
1116                 elem *e = go.expnod[i];
1117 
1118                 /* If it could be changed by the definition,     */
1119                 /* set bit in KILL.                              */
1120 
1121                 if (e.EV.E1.EV.Vsym == s || e.EV.E2.EV.Vsym == s)
1122                     vec_setclear(i,KILL,GEN);
1123             }
1124         }
1125 
1126         /* GEN CP elems */
1127         if (n.Eexp)
1128         {
1129             const uint b = n.Eexp;
1130             vec_setclear(b,GEN,KILL);
1131         }
1132 
1133         return;
1134     }
1135 
1136     /* Else Available Expression stuff  */
1137 
1138     if (n.Eexp)
1139     {
1140         const uint b = n.Eexp;             // add elem to GEN
1141         assert(go.expnod[b] == n);
1142         vec_setclear(b,GEN,KILL);
1143     }
1144     else if (OTdef(op))                         /* else if definition elem */
1145     {
1146         if (!Eunambig(n))                       /* if ambiguous def elem */
1147         {
1148             vec_orass(KILL,go.defkill);
1149             vec_subass(GEN,go.defkill);
1150             if (OTcalldef(op))
1151             {
1152                 vec_orass(KILL,go.vptrkill);
1153                 vec_subass(GEN,go.vptrkill);
1154             }
1155         }
1156         else                                    /* unambiguous def elem */
1157         {
1158             assert(t.Eoper == OPvar);
1159             Symbol* s = t.EV.Vsym;             // idx of var being def'd
1160             if (!(s.Sflags & SFLunambig))
1161             {
1162                 vec_orass(KILL,go.starkill);       /* kill all 'starred' refs */
1163                 vec_subass(GEN,go.starkill);
1164             }
1165             foreach (uint i; 1 .. go.exptop)        // for each ae elem
1166             {
1167                 elem *e = go.expnod[i];
1168                 const int eop = e.Eoper;
1169 
1170                 /* If it could be changed by the definition,     */
1171                 /* set bit in KILL.                              */
1172                 if (eop == OPvar)
1173                 {
1174                     if (e.EV.Vsym != s)
1175                         continue;
1176                 }
1177                 else if (OTunary(eop))
1178                 {
1179                     if (!vec_testbit(e.EV.E1.Eexp,KILL))
1180                         continue;
1181                 }
1182                 else if (OTbinary(eop))
1183                 {
1184                     if (!vec_testbit(e.EV.E1.Eexp,KILL) &&
1185                         !vec_testbit(e.EV.E2.Eexp,KILL))
1186                         continue;
1187                 }
1188                 else
1189                         continue;
1190 
1191                 vec_setclear(i,KILL,GEN);
1192             }
1193         }
1194 
1195         /* GEN the lvalue of an assignment operator      */
1196         if (OTassign(op) && !OTpost(op) && t.Eexp)
1197         {
1198             uint b = t.Eexp;
1199 
1200             vec_setclear(b,GEN,KILL);
1201         }
1202     }
1203 }
1204 
1205 /************************* LIVE VARIABLES **********************/
1206 
1207 /*********************************
1208  * Do live variable analysis (LVs).
1209  * A variable is 'live' at some point if there is a
1210  * subsequent use of it before a redefinition.
1211  * Binlv = the set of variables live at the beginning of B.
1212  * Boutlv = the set of variables live at the end of B.
1213  * Bgen = set of variables used before any definition in B.
1214  * Bkill = set of variables unambiguously defined before
1215  *       any use in B.
1216  * Note that Bgen & Bkill = 0.
1217  */
1218 
1219 void flowlv()
1220 {
1221     lvgenkill();            /* compute Bgen and Bkill for LVs.      */
1222     //assert(globsym.length);  /* should be at least some symbols      */
1223 
1224     /* Create a vector of all the variables that are live on exit   */
1225     /* from the function.                                           */
1226 
1227     vec_t livexit = vec_calloc(globsym.length);
1228     foreach (i; 0 .. globsym.length)
1229     {
1230         if (globsym[i].Sflags & SFLlivexit)
1231             vec_setbit(i,livexit);
1232     }
1233 
1234     /* The transfer equation is:                            */
1235     /*      Bin = (Bout - Bkill) | Bgen                     */
1236     /*      Bout = union of Bin of all successors to B.     */
1237     /* Using Ullman's algorithm:                            */
1238 
1239     foreach (b; dfo[])
1240     {
1241         vec_copy(b.Binlv, b.Bgen);   // Binlv = Bgen
1242     }
1243 
1244     vec_t tmp = vec_calloc(globsym.length);
1245     uint cnt = 0;
1246     bool anychng;
1247     do
1248     {
1249         anychng = false;
1250 
1251         /* For each block B in reverse DFO order        */
1252         foreach_reverse (b; dfo[])
1253         {
1254             /* Bout = union of Bins of all successors to B. */
1255             bool first = true;
1256             foreach (bl; ListRange(b.Bsucc))
1257             {
1258                 const inlv = list_block(bl).Binlv;
1259                 if (first)
1260                     vec_copy(b.Boutlv, inlv);
1261                 else
1262                     vec_orass(b.Boutlv, inlv);
1263                 first = false;
1264             }
1265 
1266             if (first) /* no successors, Boutlv = livexit */
1267             {   //assert(b.BC==BCret||b.BC==BCretexp||b.BC==BCexit);
1268                 vec_copy(b.Boutlv,livexit);
1269             }
1270 
1271             /* Bin = (Bout - Bkill) | Bgen                  */
1272             vec_sub(tmp,b.Boutlv,b.Bkill);
1273             vec_orass(tmp,b.Bgen);
1274             if (!anychng)
1275                 anychng = !vec_equal(tmp,b.Binlv);
1276             vec_copy(b.Binlv,tmp);
1277         }
1278         cnt++;
1279         assert(cnt < 50);
1280     } while (anychng);
1281 
1282     vec_free(tmp);
1283     vec_free(livexit);
1284 
1285     static if (0)
1286     {
1287         printf("Live variables\n");
1288         foreach (i, b; dfo[])
1289         {
1290             printf("B%d IN\t", cast(int)i);
1291             vec_println(b.Binlv);
1292             printf("B%d GEN\t", cast(int)i);
1293             vec_println(b.Bgen);
1294             printf("  KILL\t");
1295             vec_println(b.Bkill);
1296             printf("  OUT\t");
1297             vec_println(b.Boutlv);
1298         }
1299     }
1300 }
1301 
1302 /***********************************
1303  * Compute Bgen and Bkill for LVs.
1304  * Allocate Binlv and Boutlv vectors.
1305  */
1306 
1307 private void lvgenkill()
1308 {
1309     /* Compute ambigsym, a vector of all variables that could be    */
1310     /* referenced by a *e or a call.                                */
1311 
1312     assert(ambigsym == null);
1313     ambigsym = vec_calloc(globsym.length);
1314     foreach (i; 0 .. globsym.length)
1315         if (!(globsym[i].Sflags & SFLunambig))
1316             vec_setbit(i,ambigsym);
1317 
1318     foreach (b; dfo[])
1319     {
1320         vec_free(b.Bgen);
1321         vec_free(b.Bkill);
1322         lvelem(&(b.Bgen),&(b.Bkill),b.Belem);
1323         if (b.BC == BCasm)
1324         {
1325             vec_set(b.Bgen);
1326             vec_clear(b.Bkill);
1327         }
1328 
1329         vec_free(b.Binlv);
1330         vec_free(b.Boutlv);
1331         b.Binlv = vec_calloc(globsym.length);
1332         b.Boutlv = vec_calloc(globsym.length);
1333     }
1334 
1335     vec_free(ambigsym);             /* dump any existing one        */
1336     ambigsym = null;
1337 }
1338 
1339 /*****************************
1340  * Allocate and compute KILL and GEN for live variables.
1341  */
1342 
1343 private void lvelem(vec_t *pgen,vec_t *pkill,elem *n)
1344 {
1345     *pgen = vec_calloc(globsym.length);
1346     *pkill = vec_calloc(globsym.length);
1347     if (n && globsym.length)
1348         accumlv(*pgen,*pkill,n);
1349 }
1350 
1351 /**********************************************
1352  * Accumulate GEN and KILL sets for LVs for this elem.
1353  */
1354 
1355 private void accumlv(vec_t GEN,vec_t KILL,elem *n)
1356 {
1357     assert(GEN && KILL && n);
1358 
1359     while (1)
1360     {
1361         elem_debug(n);
1362         const op = n.Eoper;
1363         switch (op)
1364         {
1365             case OPvar:
1366                 if (symbol_isintab(n.EV.Vsym))
1367                 {
1368                     const si = n.EV.Vsym.Ssymnum;
1369 
1370                     assert(cast(uint)si < globsym.length);
1371                     if (!vec_testbit(si,KILL))  // if not in KILL
1372                         vec_setbit(si,GEN);     // put in GEN
1373                 }
1374                 break;
1375 
1376             case OPcolon:
1377             case OPcolon2:
1378             {
1379                 vec_t Gl,Kl,Gr,Kr;
1380                 lvelem(&Gl,&Kl,n.EV.E1);
1381                 lvelem(&Gr,&Kr,n.EV.E2);
1382 
1383                 /* GEN |= (Gl | Gr) - KILL      */
1384                 /* KILL |= (Kl & Kr) - GEN      */
1385 
1386                 vec_orass(Gl,Gr);
1387                 vec_subass(Gl,KILL);
1388                 vec_orass(GEN,Gl);
1389                 vec_andass(Kl,Kr);
1390                 vec_subass(Kl,GEN);
1391                 vec_orass(KILL,Kl);
1392 
1393                 vec_free(Gl);
1394                 vec_free(Gr);
1395                 vec_free(Kl);
1396                 vec_free(Kr);
1397                 break;
1398             }
1399 
1400             case OPandand:
1401             case OPoror:
1402             {
1403                 vec_t Gr,Kr;
1404                 accumlv(GEN,KILL,n.EV.E1);
1405                 lvelem(&Gr,&Kr,n.EV.E2);
1406 
1407                 /* GEN |= Gr - KILL     */
1408                 /* KILL |= 0            */
1409 
1410                 vec_subass(Gr,KILL);
1411                 vec_orass(GEN,Gr);
1412 
1413                 vec_free(Gr);
1414                 vec_free(Kr);
1415                 break;
1416             }
1417 
1418             case OPasm:
1419                 vec_set(GEN);           /* GEN everything not already KILLed */
1420                 vec_subass(GEN,KILL);
1421                 break;
1422 
1423             case OPcall:
1424             case OPcallns:
1425             case OPstrcpy:
1426             case OPmemcpy:
1427             case OPmemset:
1428                 debug assert(OTrtol(op));
1429                 accumlv(GEN,KILL,n.EV.E2);
1430                 accumlv(GEN,KILL,n.EV.E1);
1431                 goto L1;
1432 
1433             case OPstrcat:
1434                 debug assert(!OTrtol(op));
1435                 accumlv(GEN,KILL,n.EV.E1);
1436                 accumlv(GEN,KILL,n.EV.E2);
1437             L1:
1438                 vec_orass(GEN,ambigsym);
1439                 vec_subass(GEN,KILL);
1440                 break;
1441 
1442             case OPeq:
1443             case OPstreq:
1444             {
1445                 /* Avoid GENing the lvalue of an =      */
1446                 accumlv(GEN,KILL,n.EV.E2);
1447                 elem *t = n.EV.E1;
1448                 if (t.Eoper != OPvar)
1449                     accumlv(GEN,KILL,t.EV.E1);
1450                 else /* unambiguous assignment */
1451                 {
1452                     Symbol* s = t.EV.Vsym;
1453                     symbol_debug(s);
1454 
1455                     uint tsz = tysize(t.Ety);
1456                     if (op == OPstreq)
1457                         tsz = cast(uint)type_size(n.ET);
1458 
1459                     /* if not GENed already, KILL it */
1460                     if (symbol_isintab(s) &&
1461                         !vec_testbit(s.Ssymnum,GEN) &&
1462                         t.EV.Voffset == 0 &&
1463                         tsz == type_size(s.Stype)
1464                        )
1465                     {
1466                         // printf("%s\n", s.Sident);
1467                         assert(cast(uint)s.Ssymnum < globsym.length);
1468                         vec_setbit(s.Ssymnum,KILL);
1469                     }
1470                 }
1471                 break;
1472             }
1473 
1474             case OPbt:                          // much like OPind
1475                 accumlv(GEN,KILL,n.EV.E1);
1476                 accumlv(GEN,KILL,n.EV.E2);
1477                 vec_orass(GEN,ambigsym);
1478                 vec_subass(GEN,KILL);
1479                 break;
1480 
1481             case OPind:
1482             case OPucall:
1483             case OPucallns:
1484             case OPstrlen:
1485                 accumlv(GEN,KILL,n.EV.E1);
1486 
1487                 /* If it was a *p elem, set bits in GEN for all symbols */
1488                 /* it could have referenced, but only if bits in KILL   */
1489                 /* are not already set.                                 */
1490 
1491                 vec_orass(GEN,ambigsym);
1492                 vec_subass(GEN,KILL);
1493                 break;
1494 
1495             default:
1496                 if (OTunary(op))
1497                 {
1498                     n = n.EV.E1;
1499                     continue;
1500                 }
1501                 else if (OTrtol(op) && ERTOL(n))
1502                 {
1503                     accumlv(GEN,KILL,n.EV.E2);
1504 
1505                     /* Note that lvalues of op=,i++,i-- elems */
1506                     /* are GENed.                               */
1507                     n = n.EV.E1;
1508                     continue;
1509                 }
1510                 else if (OTbinary(op))
1511                 {
1512                     accumlv(GEN,KILL,n.EV.E1);
1513                     n = n.EV.E2;
1514                     continue;
1515                 }
1516                 break;
1517         }
1518         break;
1519     }
1520 }
1521 
1522 /********************* VERY BUSY EXPRESSIONS ********************/
1523 
1524 /**********************************************
1525  * Compute very busy expressions(VBEs).
1526  * That is,expressions that are evaluated along
1527  * separate paths.
1528  * Bin = the set of VBEs at the beginning of B.
1529  * Bout = the set of VBEs at the end of B.
1530  * Bgen = set of expressions X+Y such that X+Y is
1531  *      evaluated before any def of X or Y.
1532  * Bkill = set of expressions X+Y such that X or Y could
1533  *      be defined before X+Y is computed.
1534  * Note that gen and kill are mutually exclusive.
1535  */
1536 
1537 void flowvbe()
1538 {
1539     flowxx = VBE;
1540     aecpgenkill(go, VBE);   // compute Bgen and Bkill for VBEs
1541     if (go.exptop <= 1)     /* if no candidates for VBEs            */
1542         return;
1543 
1544     /*foreach (uint i; 0 .. go.exptop)
1545             printf("go.expnod[%d] = 0x%x\n",i,go.expnod[i]);*/
1546 
1547     /* The transfer equation is:                    */
1548     /*      Bout = & Bin(all successors S of B)     */
1549     /*      Bin =(Bout - Bkill) | Bgen              */
1550     /* Using Ullman's algorithm:                    */
1551 
1552     /*printf("defkill = "); vec_println(go.defkill);
1553     printf("starkill = "); vec_println(go.starkill);*/
1554 
1555     foreach (b; dfo[])
1556     {
1557         /*printf("block %p\n",b);
1558         printf("Bgen = "); vec_println(b.Bgen);
1559         printf("Bkill = "); vec_println(b.Bkill);*/
1560 
1561         if (b.BC == BCret || b.BC == BCretexp || b.BC == BCexit)
1562             vec_clear(b.Bout);
1563         else
1564             vec_set(b.Bout);
1565 
1566         /* Bin = (Bout - Bkill) | Bgen  */
1567         vec_sub(b.Bin,b.Bout,b.Bkill);
1568         vec_orass(b.Bin,b.Bgen);
1569     }
1570 
1571     vec_t tmp = vec_calloc(go.exptop);
1572     bool anychng;
1573     do
1574     {
1575         anychng = false;
1576 
1577         /* for all blocks except return blocks in reverse dfo order */
1578         foreach_reverse (b; dfo[])
1579         {
1580             if (b.BC == BCret || b.BC == BCretexp || b.BC == BCexit)
1581                 continue;
1582 
1583             /* Bout = & of Bin of all successors */
1584             bool first = true;
1585             foreach (bl; ListRange(b.Bsucc))
1586             {
1587                 const vin = list_block(bl).Bin;
1588                 if (first)
1589                     vec_copy(b.Bout, vin);
1590                 else
1591                     vec_andass(b.Bout, vin);
1592 
1593                 first = false;
1594             }
1595 
1596             assert(!first);     // must have successors
1597 
1598             /* Bin = (Bout - Bkill) | Bgen  */
1599             vec_sub(tmp,b.Bout,b.Bkill);
1600             vec_orass(tmp,b.Bgen);
1601             if (!anychng)
1602                 anychng = !vec_equal(tmp,b.Bin);
1603             vec_copy(b.Bin,tmp);
1604         }
1605     } while (anychng);      /* while any changes occurred to any Bin */
1606     vec_free(tmp);
1607 }
1608 
1609 /*************************************
1610  * Accumulate GEN and KILL sets for VBEs for this elem.
1611  */
1612 
1613 private void accumvbe(vec_t GEN,vec_t KILL,elem *n)
1614 {
1615     elem *t;
1616 
1617     assert(GEN && KILL && n);
1618     const op = n.Eoper;
1619 
1620     switch (op)
1621     {
1622         case OPcolon:
1623         case OPcolon2:
1624         {
1625             vec_t Gl,Gr,Kl,Kr;
1626 
1627             aecpelem(&Gl,&Kl,n.EV.E1);
1628             aecpelem(&Gr,&Kr,n.EV.E2);
1629 
1630             /* GEN |=((Gr - Kl) | (Gl - Kr)) - KILL */
1631             vec_subass(Gr,Kl);
1632             vec_subass(Gl,Kr);
1633             vec_orass(Gr,Gl);
1634             vec_subass(Gr,KILL);
1635             vec_orass(GEN,Gr);
1636 
1637             /* KILL |=(Kl | Kr) - GEN       */
1638             vec_orass(Kl,Kr);
1639             vec_subass(Kl,GEN);
1640             vec_orass(KILL,Kl);
1641 
1642             vec_free(Gl);
1643             vec_free(Kl);
1644             vec_free(Gr);
1645             vec_free(Kr);
1646             break;
1647         }
1648 
1649         case OPandand:
1650         case OPoror:
1651             accumvbe(GEN,KILL,n.EV.E1);
1652             /* WARNING: just so happens that it works this way.     */
1653             /* Be careful about (b+c)||(b+c) being VBEs, only the   */
1654             /* first should be GENed. Doing things this way instead */
1655             /* of (GEN |= Gr - KILL) and (KILL |= Kr - GEN) will    */
1656             /* ensure this.                                         */
1657             accumvbe(GEN,KILL,n.EV.E2);
1658             break;
1659 
1660         case OPnegass:
1661             t = n.EV.E1;
1662             if (t.Eoper != OPvar)
1663             {
1664                 accumvbe(GEN,KILL,t.EV.E1);
1665                 if (OTbinary(t.Eoper))
1666                     accumvbe(GEN,KILL,t.EV.E2);
1667             }
1668             break;
1669 
1670         case OPcall:
1671         case OPcallns:
1672             accumvbe(GEN,KILL,n.EV.E2);
1673             goto case OPucall;
1674 
1675         case OPucall:
1676         case OPucallns:
1677             t = n.EV.E1;
1678             // Do not VBE indirect function calls
1679             if (t.Eoper == OPind)
1680                 t = t.EV.E1;
1681             accumvbe(GEN,KILL,t);
1682             break;
1683 
1684         case OPasm:                 // if the dreaded OPasm elem
1685             vec_set(KILL);          // KILL everything
1686             vec_subass(KILL,GEN);   // except for GENed stuff
1687             return;
1688 
1689         default:
1690             if (OTunary(op))
1691             {
1692                 t = n.EV.E1;
1693                 accumvbe(GEN,KILL,t);
1694             }
1695             else if (ERTOL(n))
1696             {
1697                 accumvbe(GEN,KILL,n.EV.E2);
1698                 t = n.EV.E1;
1699                 // do not GEN the lvalue of an assignment op
1700                 if (OTassign(op))
1701                 {
1702                     t = n.EV.E1;
1703                     if (t.Eoper != OPvar)
1704                     {
1705                         accumvbe(GEN,KILL,t.EV.E1);
1706                         if (OTbinary(t.Eoper))
1707                             accumvbe(GEN,KILL,t.EV.E2);
1708                     }
1709                 }
1710                 else
1711                     accumvbe(GEN,KILL,t);
1712             }
1713             else if (OTbinary(op))
1714             {
1715                 /* do not GEN the lvalue of an assignment op    */
1716                 if (OTassign(op))
1717                 {
1718                     t = n.EV.E1;
1719                     if (t.Eoper != OPvar)
1720                     {
1721                         accumvbe(GEN,KILL,t.EV.E1);
1722                         if (OTbinary(t.Eoper))
1723                             accumvbe(GEN,KILL,t.EV.E2);
1724                     }
1725                 }
1726                 else
1727                     accumvbe(GEN,KILL,n.EV.E1);
1728                 accumvbe(GEN,KILL,n.EV.E2);
1729             }
1730             break;
1731     }
1732 
1733     if (n.Eexp)                    /* if a vbe elem                */
1734     {
1735         const int ne = n.Eexp;
1736 
1737         assert(go.expnod[ne] == n);
1738         if (!vec_testbit(ne,KILL))      /* if not already KILLed */
1739         {
1740             /* GEN this expression only if it hasn't        */
1741             /* already been GENed in this block.            */
1742             /* (Don't GEN common subexpressions.)           */
1743             if (vec_testbit(ne,GEN))
1744                 vec_clearbit(ne,GEN);
1745             else
1746             {
1747                 vec_setbit(ne,GEN); /* GEN this expression  */
1748                 /* GEN all identical expressions            */
1749                 /* (operators only, as there is no point    */
1750                 /* to hoisting out variables and constants) */
1751                 if (!OTleaf(op))
1752                 {
1753                     foreach (uint i; 1 .. go.exptop)
1754                     {
1755                         if (op == go.expnod[i].Eoper &&
1756                             i != ne &&
1757                             el_match(n,go.expnod[i]))
1758                         {
1759                             vec_setbit(i,GEN);
1760                             assert(!vec_testbit(i,KILL));
1761                         }
1762                     }
1763                 }
1764             }
1765         }
1766         if (op == OPvp_fp || op == OPcvp_fp)
1767         {
1768             vec_orass(KILL,go.vptrkill);   /* KILL all vptr accesses */
1769             vec_subass(KILL,GEN);          /* except for GENed stuff */
1770         }
1771     }
1772     else if (OTdef(op))             /* if definition elem           */
1773     {
1774         if (!Eunambig(n))           /* if ambiguous definition      */
1775         {
1776             vec_orass(KILL,go.defkill);
1777             if (OTcalldef(op))
1778                 vec_orass(KILL,go.vptrkill);
1779         }
1780         else                    /* unambiguous definition       */
1781         {
1782             assert(t.Eoper == OPvar);
1783             Symbol* s = t.EV.Vsym;  // ptr to var being def'd
1784             if (!(s.Sflags & SFLunambig))
1785                 vec_orass(KILL,go.starkill);/* kill all 'starred' refs */
1786             foreach (uint i; 1 .. go.exptop)        // for each vbe elem
1787             {
1788                 elem *e = go.expnod[i];
1789                 uint eop = e.Eoper;
1790 
1791                 /* If it could be changed by the definition,     */
1792                 /* set bit in KILL.                              */
1793                 if (eop == OPvar)
1794                 {
1795                     if (e.EV.Vsym != s)
1796                         continue;
1797                 }
1798                 else if (OTbinary(eop))
1799                 {
1800                     if (!vec_testbit(e.EV.E1.Eexp,KILL) &&
1801                         !vec_testbit(e.EV.E2.Eexp,KILL))
1802                         continue;
1803                 }
1804                 else if (OTunary(eop))
1805                 {
1806                     if (!vec_testbit(e.EV.E1.Eexp,KILL))
1807                         continue;
1808                 }
1809                 else /* OPconst or OPrelconst or OPstring */
1810                     continue;
1811 
1812                 vec_setbit(i,KILL);     // KILL it
1813             } /* for */
1814         } /* if */
1815         vec_subass(KILL,GEN);
1816     } /* if */
1817 }
1818 
1819 }