1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (C) 1986-1998 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:     Distributed under the Boost Software License, Version 1.0.
9  *              http://www.boost.org/LICENSE_1_0.txt
10  * Source:      https://github.com/dlang/dmd/blob/master/src/dmd/backend/gother.c
11  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/gother.c
12  */
13 
14 module dmd.backend.gother;
15 
16 version (SCPP)
17     version = COMPILE;
18 version (MARS)
19     version = COMPILE;
20 
21 version (COMPILE)
22 {
23 
24 import core.stdc.stdio;
25 import core.stdc.stdlib;
26 import core.stdc.time;
27 
28 import dmd.backend.cc;
29 import dmd.backend.cdef;
30 import dmd.backend.code_x86;
31 import dmd.backend.oper;
32 import dmd.backend.global;
33 import dmd.backend.goh;
34 import dmd.backend.el;
35 import dmd.backend.outbuf;
36 import dmd.backend.ty;
37 import dmd.backend.type;
38 
39 import dmd.backend.barray;
40 import dmd.backend.dlist;
41 import dmd.backend.dvec;
42 
43 nothrow:
44 
45 char symbol_isintab(Symbol *s) { return sytab[s.Sclass] & SCSS; }
46 
47 extern (C++):
48 
49 version (SCPP)
50     import parser;
51 
52 version (MARS)
53     import dmd.backend.errors;
54 
55 /**********************************************************************/
56 
57 // Lists to help identify ranges of variables
58 struct Elemdata
59 {
60 nothrow:
61     Elemdata *next;         // linked list
62     elem *pelem;            // the elem in question
63     block *pblock;          // which block it's in
64     list_t  rdlist;         // list of definition elems for *pelem
65 
66     static Elemdata *ctor(elem *e,block *b,list_t rd)
67     {
68         Elemdata* ed = cast(Elemdata *) calloc(1, Elemdata.sizeof);
69         assert(ed);
70         ed.pelem = e;
71         ed.pblock = b;
72         ed.rdlist = rd;
73         return ed;
74     }
75 
76     /********************************
77      * Find `e` in Elemdata list.
78      * Params:
79      *      e = elem to find
80      * Returns:
81      *      Elemdata entry if found,
82      *      null if not
83      */
84     Elemdata* find(elem *e)
85     {
86         Elemdata* edl = &this;
87         for (; edl; edl = edl.next)
88         {
89             if (edl.pelem == e)
90                 break;
91         }
92         return edl;
93     }
94 }
95 
96 /*****************
97  * Free list of Elemdata's.
98  */
99 
100 private void elemdatafree(Elemdata **plist)
101 {
102     Elemdata *eln;
103 
104     for (Elemdata *el = *plist; el; el = eln)
105     {   eln = el.next;
106         list_free(&el.rdlist);
107         free(el);
108     }
109     *plist = null;
110 }
111 
112 private __gshared
113 {
114     Elemdata *eqeqlist = null;       // list of Elemdata's of OPeqeq & OPne elems
115     Elemdata *rellist = null;        // list of Elemdata's of relop elems
116     Elemdata *inclist = null;        // list of Elemdata's of increment elems
117 }
118 
119 /*************************** Constant Propagation ***************************/
120 
121 
122 /**************************
123  * Constant propagation.
124  * Also detects use of variable before any possible def.
125  */
126 
127 void constprop()
128 {
129     rd_compute();
130     intranges();                // compute integer ranges
131     eqeqranges();               // see if we can eliminate some relationals
132     elemdatafree(&eqeqlist);
133     elemdatafree(&rellist);
134     elemdatafree(&inclist);
135 }
136 
137 /************************************
138  * Compute reaching definitions.
139  * Note: RD vectors are destroyed by this.
140  */
141 
142 private __gshared block *thisblock;
143 
144 private void rd_compute()
145 {
146     if (debugc) printf("constprop()\n");
147     assert(dfo);
148     flowrd();               /* compute reaching definitions (rd)    */
149     if (go.defnod.length == 0)     /* if no reaching defs                  */
150         return;
151     assert(rellist == null && inclist == null && eqeqlist == null);
152     block_clearvisit();
153     foreach (b; dfo[])    // for each block
154     {
155         switch (b.BC)
156         {
157             case BCjcatch:
158             case BC_finally:
159             case BC_lpad:
160             case BCasm:
161             case BCcatch:
162                 block_visit(b);
163                 break;
164 
165             default:
166                 break;
167         }
168     }
169 
170     foreach (i, b; dfo[])    // for each block
171     {
172         thisblock = b;
173 
174         //printf("block %d Bin ",i); vec_println(b.Binrd);
175         //printf("       Bout "); vec_println(b.Boutrd);
176 
177         if (b.Bflags & BFLvisited)
178             continue;                   // not reliable for this block
179         if (b.Belem)
180         {
181             conpropwalk(b.Belem,b.Binrd);
182 
183             debug
184             if (!(vec_equal(b.Binrd,b.Boutrd)))
185             {
186                 int j;
187 
188                 printf("block %d Binrd ", cast(int) i); vec_println(b.Binrd);
189                 printf("       Boutrd "); vec_println(b.Boutrd);
190                 WReqn(b.Belem);
191                 printf("\n");
192                 vec_xorass(b.Binrd,b.Boutrd);
193                 j = cast(int)vec_index(0,b.Binrd);
194                 WReqn(go.defnod[j].DNelem);
195                 printf("\n");
196             }
197 
198             assert(vec_equal(b.Binrd,b.Boutrd));
199         }
200     }
201 }
202 
203 /***************************
204  * Support routine for constprop().
205  *      Visit each elem in order
206  *              If elem is a reference to a variable, and
207  *              all the reaching defs of that variable are
208  *              defining it to be a specific constant,
209  *                      Replace reference with that constant.
210  *              Generate warning if no reaching defs for a
211  *              variable, and the variable is on the stack
212  *              or in a register.
213  *              If elem is an assignment or function call or OPasm
214  *                      Modify vector of reaching defs.
215  */
216 
217 private void conpropwalk(elem *n,vec_t IN)
218 {
219     Elemdata *pdata;
220     vec_t L,R;
221     elem *t;
222 
223     assert(n && IN);
224     //printf("conpropwalk()\n"),elem_print(n);
225     const op = n.Eoper;
226     if (op == OPcolon || op == OPcolon2)
227     {
228         L = vec_clone(IN);
229         switch (el_returns(n.EV.E1) * 2 | el_returns(n.EV.E2))
230         {
231             case 3: // E1 and E2 return
232                 conpropwalk(n.EV.E1,L);
233                 conpropwalk(n.EV.E2,IN);
234                 vec_orass(IN,L);                // IN = L | R
235                 break;
236 
237             case 2: // E1 returns
238                 conpropwalk(n.EV.E1,IN);
239                 conpropwalk(n.EV.E2,L);
240                 break;
241 
242             case 1: // E2 returns
243                 conpropwalk(n.EV.E1,L);
244                 conpropwalk(n.EV.E2,IN);
245                 break;
246 
247             case 0: // neither returns
248                 conpropwalk(n.EV.E1,L);
249                 vec_copy(L,IN);
250                 conpropwalk(n.EV.E2,L);
251                 break;
252 
253             default:
254                 break;
255         }
256         vec_free(L);
257     }
258     else if (op == OPandand || op == OPoror)
259     {
260         conpropwalk(n.EV.E1,IN);
261         R = vec_clone(IN);
262         conpropwalk(n.EV.E2,R);
263         if (el_returns(n.EV.E2))
264             vec_orass(IN,R);                // IN |= R
265         vec_free(R);
266     }
267     else if (OTunary(op))
268         goto L3;
269     else if (ERTOL(n))
270     {
271         conpropwalk(n.EV.E2,IN);
272       L3:
273         t = n.EV.E1;
274         if (OTassign(op))
275         {
276             if (t.Eoper == OPvar)
277             {
278                 // Note that the following ignores OPnegass
279                 if (OTopeq(op) && sytab[t.EV.Vsym.Sclass] & SCRD)
280                 {
281                     elem *e;
282                     list_t rdl;
283 
284                     rdl = listrds(IN,t,null);
285                     if (!(config.flags & CFGnowarning)) // if warnings are enabled
286                         chkrd(t,rdl);
287                     e = chkprop(t,rdl);
288                     if (e)
289                     {   // Replace (t op= exp) with (t = e op exp)
290 
291                         e = el_copytree(e);
292                         e.Ety = t.Ety;
293                         n.EV.E2 = el_bin(opeqtoop(op),n.Ety,e,n.EV.E2);
294                         n.Eoper = OPeq;
295                     }
296                     list_free(&rdl);
297                 }
298             }
299             else
300                 conpropwalk(t,IN);
301         }
302         else
303             conpropwalk(t,IN);
304     }
305     else if (OTbinary(op))
306     {
307         if (OTassign(op))
308         {   t = n.EV.E1;
309             if (t.Eoper != OPvar)
310                 conpropwalk(t,IN);
311         }
312         else
313             conpropwalk(n.EV.E1,IN);
314         conpropwalk(n.EV.E2,IN);
315     }
316 
317     // Collect data for subsequent optimizations
318     if (OTbinary(op) && n.EV.E1.Eoper == OPvar && n.EV.E2.Eoper == OPconst)
319     {
320         switch (op)
321         {
322             case OPlt:
323             case OPgt:
324             case OPle:
325             case OPge:
326                 // Collect compare elems and their rd's in the rellist list
327                 if (tyintegral(n.EV.E1.Ety) &&
328                     tyintegral(n.EV.E2.Ety)
329                    )
330                 {
331                     //printf("appending to rellist\n"); elem_print(n);
332                     //printf("\trellist IN: "); vec_print(IN); printf("\n");
333                     pdata = Elemdata.ctor(n,thisblock,listrds(IN,n.EV.E1,null));
334                     pdata.next = rellist;
335                     rellist = pdata;
336                 }
337                 break;
338 
339             case OPaddass:
340             case OPminass:
341             case OPpostinc:
342             case OPpostdec:
343                 // Collect increment elems and their rd's in the inclist list
344                 if (tyintegral(n.EV.E1.Ety))
345                 {
346                     //printf("appending to inclist\n"); elem_print(n);
347                     //printf("\tinclist IN: "); vec_print(IN); printf("\n");
348                     pdata = Elemdata.ctor(n,thisblock,listrds(IN,n.EV.E1,null));
349                     pdata.next = inclist;
350                     inclist = pdata;
351                 }
352                 break;
353 
354             case OPne:
355             case OPeqeq:
356                 // Collect compare elems and their rd's in the rellist list
357                 if (tyintegral(n.EV.E1.Ety))
358                 {   //printf("appending to eqeqlist\n"); elem_print(n);
359                     pdata = Elemdata.ctor(n,thisblock,listrds(IN,n.EV.E1,null));
360                     pdata.next = eqeqlist;
361                     eqeqlist = pdata;
362                 }
363                 break;
364 
365             default:
366                 break;
367         }
368     }
369 
370 
371     if (OTdef(op))                  /* if definition elem           */
372         updaterd(n,IN,null);        /* then update IN vector        */
373 
374     /* now we get to the part that checks to see if we can  */
375     /* propagate a constant.                                */
376     if (op == OPvar && sytab[n.EV.Vsym.Sclass] & SCRD)
377     {
378         list_t rdl;
379 
380         //printf("const prop: %s\n", n.EV.Vsym.Sident);
381         rdl = listrds(IN,n,null);
382 
383         if (!(config.flags & CFGnowarning))     // if warnings are enabled
384             chkrd(n,rdl);
385         elem *e = chkprop(n,rdl);
386         if (e)
387         {   tym_t nty;
388 
389             nty = n.Ety;
390             el_copy(n,e);
391             n.Ety = nty;                       // retain original type
392         }
393         list_free(&rdl);
394     }
395 }
396 
397 /******************************
398  * Give error if there are no reaching defs for variable v.
399  */
400 
401 private void chkrd(elem *n,list_t rdlist)
402 {
403     Symbol *sv;
404     int unambig;
405 
406     sv = n.EV.Vsym;
407     assert(sytab[sv.Sclass] & SCRD);
408     if (sv.Sflags & SFLnord)           // if already printed a warning
409         return;
410     if (sv.ty() & (mTYvolatile | mTYshared))
411         return;
412     unambig = sv.Sflags & SFLunambig;
413     foreach (l; ListRange(rdlist))
414     {   elem *d = cast(elem *) list_ptr(l);
415 
416         elem_debug(d);
417         if (d.Eoper == OPasm)          /* OPasm elems ruin everything  */
418             return;
419         if (OTassign(d.Eoper))
420         {
421             if (d.EV.E1.Eoper == OPvar)
422             {
423                 if (d.EV.E1.EV.Vsym == sv)
424                     return;
425             }
426             else if (!unambig)
427                 return;
428         }
429         else
430         {
431             if (!unambig)
432                 return;
433         }
434     }
435 
436     // If there are any asm blocks, don't print the message
437     foreach (b; dfo[])
438         if (b.BC == BCasm)
439             return;
440 
441     // If variable contains bit fields, don't print message (because if
442     // bit field is the first set, then we get a spurious warning).
443     // STL uses 0 sized structs to transmit type information, so
444     // don't complain about them being used before set.
445     if (type_struct(sv.Stype))
446     {
447         if (sv.Stype.Ttag.Sstruct.Sflags & (STRbitfields | STR0size))
448             return;
449     }
450 
451     static if (0)
452     {
453         // If variable is zero length static array, don't print message.
454         // BUG: Suppress error even if variable is initialized with void.
455         if (sv.Stype.Tty == TYarray && sv.Stype.Tdim == 0)
456         {
457             printf("sv.Sident = %s\n", sv.Sident);
458             return;
459         }
460     }
461 
462     version (SCPP)
463     {
464         {   Outbuffer buf;
465             char *p2;
466 
467             type_tostring(&buf, sv.Stype);
468             buf.writeByte(' ');
469             buf.write(sv.Sident.ptr);
470             p2 = buf.toString();
471             warerr(WM.WM_used_b4_set, p2);     // variable used before set
472         }
473     }
474 
475     version (MARS)
476     {
477         /* Watch out for:
478             void test()
479             {
480                 void[0] x;
481                 auto y = x;
482             }
483          */
484         if (type_size(sv.Stype) != 0)
485         {
486             error(n.Esrcpos.Sfilename, n.Esrcpos.Slinnum, n.Esrcpos.Scharnum,
487                 "variable %s used before set", sv.Sident.ptr);
488         }
489     }
490 
491     sv.Sflags |= SFLnord;              // no redundant messages
492     //elem_print(n);
493 }
494 
495 /**********************************
496  * Look through the vector of reaching defs (IN) to see
497  * if all defs of n are of the same constant. If so, replace
498  * n with that constant.
499  * Bit fields are gross, so don't propagate anything with assignments
500  * to a bit field.
501  * Note the flaw in the reaching def vector. There is currently no way
502  * to detect RDs from when the function is invoked, i.e. RDs for parameters,
503  * statics and globals. This could be fixed by adding dummy defs for
504  * them before startblock, but we just kludge it and don't propagate
505  * stuff for them.
506  * Returns:
507  *      null    do not propagate constant
508  *      e       constant elem that we should replace n with
509  */
510 
511 private elem * chkprop(elem *n,list_t rdlist)
512 {
513     elem *foundelem = null;
514     int unambig;
515     Symbol *sv;
516     tym_t nty;
517     uint nsize;
518     targ_size_t noff;
519 
520     //printf("checkprop: "); WReqn(n); printf("\n");
521     assert(n && n.Eoper == OPvar);
522     elem_debug(n);
523     sv = n.EV.Vsym;
524     assert(sytab[sv.Sclass] & SCRD);
525     nty = n.Ety;
526     if (!tyscalar(nty))
527         goto noprop;
528     nsize = cast(uint)size(nty);
529     noff = n.EV.Voffset;
530     unambig = sv.Sflags & SFLunambig;
531     foreach (l; ListRange(rdlist))
532     {
533         elem *d = cast(elem *) list_ptr(l);
534 
535         elem_debug(d);
536 
537         //printf("\trd: "); WReqn(d); printf("\n");
538         if (d.Eoper == OPasm)          /* OPasm elems ruin everything  */
539             goto noprop;
540 
541         // Runs afoul of Buzilla 4506
542         /*if (OTassign(d.Eoper) && EBIN(d))*/      // if assignment elem
543 
544         if (OTassign(d.Eoper))      // if assignment elem
545         {
546             elem *t = d.EV.E1;
547 
548             if (t.Eoper == OPvar)
549             {
550                 assert(t.EV.Vsym == sv);
551 
552                 if (d.Eoper == OPstreq ||
553                     !tyscalar(t.Ety))
554                     goto noprop;        // not worth bothering with these cases
555 
556                 if (d.Eoper == OPnegass)
557                     goto noprop;        // don't bother with this case, either
558 
559                 /* Everything must match or we must skip this variable  */
560                 /* (in case of assigning to overlapping unions, etc.)   */
561                 if (t.EV.Voffset != noff ||
562                     /* If sizes match, we are ok        */
563                     size(t.Ety) != nsize &&
564                         !(d.EV.E2.Eoper == OPconst && size(t.Ety) > nsize && !tyfloating(d.EV.E2.Ety)))
565                     goto noprop;
566             }
567             else
568             {
569                 if (unambig)            /* unambiguous assignments only */
570                     continue;
571                 goto noprop;
572             }
573             if (d.Eoper != OPeq)
574                 goto noprop;
575         }
576         else                            /* must be a call elem          */
577         {
578             if (unambig)
579                 continue;
580             else
581                 goto noprop;            /* could be affected            */
582         }
583 
584         if (d.EV.E2.Eoper == OPconst || d.EV.E2.Eoper == OPrelconst)
585         {
586             if (foundelem)              /* already found one            */
587             {                           /* then they must be the same   */
588                 if (!el_match(foundelem,d.EV.E2))
589                     goto noprop;
590             }
591             else                        /* else this is it              */
592                 foundelem = d.EV.E2;
593         }
594         else
595             goto noprop;
596     }
597 
598     if (foundelem)                      /* if we got one                 */
599     {                                   /* replace n with foundelem      */
600         debug if (debugc)
601         {
602             printf("const prop (");
603             WReqn(n);
604             printf(" replaced by ");
605             WReqn(foundelem);
606             printf("), %p to %p\n",foundelem,n);
607         }
608         go.changes++;
609         return foundelem;
610     }
611 noprop:
612     return null;
613 }
614 
615 /***********************************
616  * Find all the reaching defs of OPvar e.
617  * Put into a linked list, or just set the RD bits in a vector.
618  *
619  */
620 
621 extern (C) list_t listrds(vec_t IN,elem *e,vec_t f)
622 {
623     uint i;
624     uint unambig;
625     Symbol *s;
626     uint nsize;
627     targ_size_t noff;
628     tym_t ty;
629 
630     //printf("listrds: "); WReqn(e); printf("\n");
631     assert(IN);
632     list_t rdlist = null;
633     assert(e.Eoper == OPvar);
634     s = e.EV.Vsym;
635     ty = e.Ety;
636     if (tyscalar(ty))
637         nsize = cast(uint)size(ty);
638     noff = e.EV.Voffset;
639     unambig = s.Sflags & SFLunambig;
640     if (f)
641         vec_clear(f);
642     for (i = 0; (i = cast(uint) vec_index(i, IN)) < go.defnod.length; ++i)
643     {
644         elem *d = go.defnod[i].DNelem;
645         //printf("\tlooking at "); WReqn(d); printf("\n");
646         const op = d.Eoper;
647         if (op == OPasm)                // assume ASM elems define everything
648             goto listit;
649         if (OTassign(op))
650         {   elem *t = d.EV.E1;
651 
652             if (t.Eoper == OPvar && t.EV.Vsym == s)
653             {   if (op == OPstreq)
654                     goto listit;
655                 if (!tyscalar(ty) || !tyscalar(t.Ety))
656                     goto listit;
657                 // If t does not overlap e, then it doesn't affect things
658                 if (noff + nsize > t.EV.Voffset &&
659                     t.EV.Voffset + size(t.Ety) > noff)
660                     goto listit;                // it's an assignment to s
661             }
662             else if (t.Eoper != OPvar && !unambig)
663                 goto listit;            /* assignment through pointer   */
664         }
665         else if (!unambig)
666             goto listit;                /* probably a function call     */
667         continue;
668 
669     listit:
670         //printf("\tlisting "); WReqn(d); printf("\n");
671         if (f)
672             vec_setbit(i,f);
673         else
674             list_prepend(&rdlist,d);     // add the definition node
675     }
676     return rdlist;
677 }
678 
679 /********************************************
680  * Look at reaching defs for expressions of the form (v == c) and (v != c).
681  * If all definitions of v are c or are not c, then we can replace the
682  * expression with 1 or 0.
683  */
684 
685 private void eqeqranges()
686 {
687     Symbol *v;
688     int sz;
689     elem *e;
690     targ_llong c;
691     int result;
692 
693     for (Elemdata *rel = eqeqlist; rel; rel = rel.next)
694     {
695         e = rel.pelem;
696         v = e.EV.E1.EV.Vsym;
697         if (!(sytab[v.Sclass] & SCRD))
698             continue;
699         sz = tysize(e.EV.E1.Ety);
700         c = el_tolong(e.EV.E2);
701 
702         result = -1;                    // result not known yet
703         foreach (rdl; ListRange(rel.rdlist))
704         {
705             elem *erd = cast(elem *) list_ptr(rdl);
706             elem *erd1;
707             int szrd;
708             int tmp;
709 
710             elem_debug(erd);
711             if (erd.Eoper != OPeq ||
712                 (erd1 = erd.EV.E1).Eoper != OPvar ||
713                 erd.EV.E2.Eoper != OPconst
714                )
715                 goto L1;
716             szrd = tysize(erd1.Ety);
717             if (erd1.EV.Voffset + szrd <= e.EV.E1.EV.Voffset ||
718                 e.EV.E1.EV.Voffset + sz <= erd1.EV.Voffset)
719                 continue;               // doesn't affect us, skip it
720             if (szrd != sz || e.EV.E1.EV.Voffset != erd1.EV.Voffset)
721                 goto L1;                // overlapping - forget it
722 
723             tmp = (c == el_tolong(erd.EV.E2));
724             if (result == -1)
725                 result = tmp;
726             else if (result != tmp)
727                 goto L1;
728         }
729         if (result >= 0)
730         {
731             //printf("replacing with %d\n",result);
732             el_free(e.EV.E1);
733             el_free(e.EV.E2);
734             e.EV.Vint = (e.Eoper == OPeqeq) ? result : result ^ 1;
735             e.Eoper = OPconst;
736         }
737     L1:
738     }
739 }
740 
741 /******************************
742  * Examine rellist and inclist to determine if any of the signed compare
743  * elems in rellist can be replace by unsigned compares.
744  * rellist is list of relationals in function.
745  * inclist is list of increment elems in function.
746  */
747 
748 private void intranges()
749 {
750     block *rb;
751     block *ib;
752     Symbol *v;
753     elem *rdeq;
754     elem *rdinc;
755     uint incop,relatop;
756     targ_llong initial,increment,final_;
757 
758     if (debugc) printf("intranges()\n");
759     for (Elemdata *rel = rellist; rel; rel = rel.next)
760     {
761         rb = rel.pblock;
762         //printf("rel.pelem: "); WReqn(rel.pelem); printf("\n");
763         assert(rel.pelem.EV.E1.Eoper == OPvar);
764         v = rel.pelem.EV.E1.EV.Vsym;
765 
766         // RD info is only reliable for registers and autos
767         if (!(sytab[v.Sclass] & SCRD))
768             continue;
769 
770         /* Look for two rd's: an = and an increment     */
771         if (list_nitems(rel.rdlist) != 2)
772             continue;
773         rdeq = list_elem(list_next(rel.rdlist));
774         if (rdeq.Eoper != OPeq)
775         {   rdinc = rdeq;
776             rdeq = list_elem(rel.rdlist);
777             if (rdeq.Eoper != OPeq)
778                 continue;
779         }
780         else
781             rdinc = list_elem(rel.rdlist);
782 
783         static if (0)
784         {
785             printf("\neq:  "); WReqn(rdeq); printf("\n");
786             printf("rel: "); WReqn(rel.pelem); printf("\n");
787             printf("inc: "); WReqn(rdinc); printf("\n");
788         }
789 
790         incop = rdinc.Eoper;
791         if (!OTpost(incop) && incop != OPaddass && incop != OPminass)
792             continue;
793 
794         /* lvalues should be unambiguous defs   */
795         if (rdeq.EV.E1.Eoper != OPvar || rdinc.EV.E1.Eoper != OPvar)
796             continue;
797         /* rvalues should be constants          */
798         if (rdeq.EV.E2.Eoper != OPconst || rdinc.EV.E2.Eoper != OPconst)
799             continue;
800 
801         /* Ensure that the only defs reaching the increment elem (rdinc) */
802         /* are rdeq and rdinc.                                          */
803         for (Elemdata *iel = inclist; true; iel = iel.next)
804         {
805             elem *rd1;
806             elem *rd2;
807 
808             if (!iel)
809                 goto nextrel;
810             ib = iel.pblock;
811             if (iel.pelem != rdinc)
812                 continue;               /* not our increment elem       */
813             if (list_nitems(iel.rdlist) != 2)
814             {
815                 //printf("!= 2\n");
816                 goto nextrel;
817             }
818             rd1 = list_elem(iel.rdlist);
819             rd2 = list_elem(list_next(iel.rdlist));
820             /* The rd's for the relational elem (rdeq,rdinc) must be    */
821             /* the same as the rd's for tne increment elem (rd1,rd2).   */
822             if (rd1 == rdeq && rd2 == rdinc || rd1 == rdinc && rd2 == rdeq)
823                 break;
824         }
825 
826         // Check that all paths from rdinc to rdinc must pass through rdrel
827         {
828             int i;
829 
830             // ib:      block of increment
831             // rb:      block of relational
832             i = loopcheck(ib,ib,rb);
833             block_clearvisit();
834             if (i)
835                 continue;
836         }
837 
838         /* Gather initial, increment, and final values for loop */
839         initial = el_tolong(rdeq.EV.E2);
840         increment = el_tolong(rdinc.EV.E2);
841         if (incop == OPpostdec || incop == OPminass)
842             increment = -increment;
843         relatop = rel.pelem.Eoper;
844         final_ = el_tolong(rel.pelem.EV.E2);
845         //printf("initial = %d, increment = %d, final_ = %d\n",initial,increment,final_);
846 
847         /* Determine if we can make the relational an unsigned  */
848         if (initial >= 0)
849         {
850             if (final_ >= initial)
851             {
852                 if (increment > 0 && ((final_ - initial) % increment) == 0)
853                     goto makeuns;
854             }
855             else if (final_ >= 0)
856             {   /* 0 <= final_ < initial */
857                 if (increment < 0 && ((final_ - initial) % increment) == 0 &&
858                     !(final_ + increment < 0 &&
859                         (relatop == OPge || relatop == OPlt)
860                      )
861                    )
862                 {
863                 makeuns:
864                     if (!tyuns(rel.pelem.EV.E2.Ety))
865                     {
866                         rel.pelem.EV.E2.Ety = touns(rel.pelem.EV.E2.Ety);
867                         rel.pelem.Nflags |= NFLtouns;
868 
869                         debug
870                         if (debugc)
871                         {   WReqn(rel.pelem);
872                             printf(" made unsigned, initial = %lld, increment = %lld," ~
873                                    " final_ = %lld\n",cast(long)initial,cast(long)increment,cast(long)final_);
874                         }
875                         go.changes++;
876                     }
877 
878                     static if (0)
879                     {
880                         // Eliminate loop if it is empty
881                         if (relatop == OPlt &&
882                             rb.BC == BCiftrue &&
883                             list_block(rb.Bsucc) == rb &&
884                             rb.Belem.Eoper == OPcomma &&
885                             rb.Belem.EV.E1 == rdinc &&
886                             rb.Belem.EV.E2 == rel.pelem
887                            )
888                         {
889                             rel.pelem.Eoper = OPeq;
890                             rel.pelem.Ety = rel.pelem.EV.E1.Ety;
891                             rb.BC = BCgoto;
892                             list_subtract(&rb.Bsucc,rb);
893                             list_subtract(&rb.Bpred,rb);
894 
895                             debug
896                                 if (debugc)
897                                 {
898                                     WReqn(rel.pelem);
899                                     printf(" eliminated loop\n");
900                                 }
901 
902                             go.changes++;
903                         }
904                     }
905                 }
906             }
907         }
908 
909       nextrel:
910     }
911 }
912 
913 /******************************
914  * Look for initialization and increment expressions in loop.
915  * Very similar to intranges().
916  * Params:
917  *   rellist = list of relationals in function
918  *   inclist = list of increment elems in function.
919  *   erel = loop compare expression of the form (v < c)
920  *   rdeq = set to loop initialization of v
921  *   rdinc = set to loop increment of v
922  * Returns:
923  *   false if cannot find rdeq or rdinc
924  */
925 
926 private bool returnResult(bool result)
927 {
928     elemdatafree(&eqeqlist);
929     elemdatafree(&rellist);
930     elemdatafree(&inclist);
931     return result;
932 }
933 
934 bool findloopparameters(elem* erel, ref elem* rdeq, ref elem* rdinc)
935 {
936     if (debugc) printf("findloopparameters()\n");
937     const bool log = false;
938 
939     assert(erel.EV.E1.Eoper == OPvar);
940     Symbol* v = erel.EV.E1.EV.Vsym;
941 
942     // RD info is only reliable for registers and autos
943     if (!(sytab[v.Sclass] & SCRD))
944         return false;
945 
946     rd_compute();       // compute rellist, inclist, eqeqlist
947 
948     /* Find `erel` in `rellist`
949      */
950     Elemdata* rel = rellist.find(erel);
951     if (!rel)
952     {
953         if (log) printf("\trel not found\n");
954         return returnResult(false);
955     }
956 
957     block* rb = rel.pblock;
958     //printf("rel.pelem: "); WReqn(rel.pelem); printf("\n");
959 
960 
961     // Look for one reaching definition: an increment
962     if (list_nitems(rel.rdlist) != 1)
963     {
964         if (log) printf("\tnitems = %d\n", list_nitems(rel.rdlist));
965         return returnResult(false);
966     }
967 
968     rdinc = list_elem(rel.rdlist);
969 
970     static if (0)
971     {
972         printf("\neq:  "); WReqn(rdeq); printf("\n");
973         printf("rel: "); WReqn(rel.pelem); printf("\n");
974         printf("inc: "); WReqn(rdinc); printf("\n");
975     }
976 
977     uint incop = rdinc.Eoper;
978     if (!OTpost(incop) && incop != OPaddass && incop != OPminass)
979     {
980         if (log) printf("\tnot += or -=\n");
981         return returnResult(false);
982     }
983 
984     Elemdata* iel = inclist.find(rdinc);
985     if (!iel)
986     {
987         if (log) printf("\trdinc not found\n");
988         return returnResult(false);
989     }
990 
991     /* The increment should have two reaching definitions:
992      *   the initialization
993      *   the increment itself
994      * We already have the increment (as rdinc), but need the initialization (rdeq)
995      */
996     if (list_nitems(iel.rdlist) != 2)
997     {
998         if (log) printf("nitems != 2\n");
999         return returnResult(false);
1000     }
1001     elem *rd1 = list_elem(iel.rdlist);
1002     elem *rd2 = list_elem(list_next(iel.rdlist));
1003     if (rd1 == rdinc)
1004         rdeq = rd2;
1005     else if (rd2 == rdinc)
1006         rdeq = rd1;
1007     else
1008     {
1009         if (log) printf("\tnot (rdeq,rdinc)\n");
1010         return returnResult(false);
1011     }
1012 
1013     // lvalues should be unambiguous defs
1014     if (rdeq.Eoper != OPeq || rdeq.EV.E1.Eoper != OPvar || rdinc.EV.E1.Eoper != OPvar)
1015     {
1016         if (log) printf("\tnot OPvar\n");
1017         return returnResult(false);
1018     }
1019 
1020     // rvalues should be constants
1021     if (rdeq.EV.E2.Eoper != OPconst || rdinc.EV.E2.Eoper != OPconst)
1022     {
1023         if (log) printf("\tnot OPconst\n");
1024         return returnResult(false);
1025     }
1026 
1027     /* Check that all paths from rdinc to rdinc must pass through rdrel
1028      * iel.pblock = block of increment
1029      * rel.pblock = block of relational
1030      */
1031     int i = loopcheck(iel.pblock,iel.pblock,rel.pblock);
1032     block_clearvisit();
1033     if (i)
1034     {
1035         if (log) printf("\tnot loopcheck()\n");
1036         return returnResult(false);
1037     }
1038 
1039     return returnResult(true);
1040 }
1041 
1042 /***********************
1043  * Return true if there is a path from start to inc without
1044  * passing through rel.
1045  */
1046 
1047 private int loopcheck(block *start,block *inc,block *rel)
1048 {
1049     if (!(start.Bflags & BFLvisited))
1050     {   start.Bflags |= BFLvisited;    /* guarantee eventual termination */
1051         foreach (list; ListRange(start.Bsucc))
1052         {
1053             block *b = cast(block *) list_ptr(list);
1054             if (b != rel && (b == inc || loopcheck(b,inc,rel)))
1055                 return true;
1056         }
1057     }
1058     return false;
1059 }
1060 
1061 /****************************
1062  * Do copy propagation.
1063  * Copy propagation elems are of the form OPvar=OPvar, and they are
1064  * in go.expnod[].
1065  */
1066 
1067 
1068 void copyprop()
1069 {
1070     out_regcand(&globsym);
1071     if (debugc) printf("copyprop()\n");
1072     assert(dfo);
1073 
1074 Louter:
1075     while (1)
1076     {
1077         flowcp();               /* compute available copy statements    */
1078         if (go.exptop <= 1)
1079             return;             // none available
1080         static if (0)
1081         {
1082             foreach (i; 1 .. go.exptop)
1083             {
1084                 printf("go.expnod[%d] = (",i);
1085                 WReqn(go.expnod[i]);
1086                 printf(");\n");
1087             }
1088         }
1089         foreach (i, b; dfo[])    // for each block
1090         {
1091             if (b.Belem)
1092             {
1093                 bool recalc;
1094                 static if (0)
1095                 {
1096                     printf("B%d, elem (",i);
1097                     WReqn(b.Belem); printf(")\nBin  ");
1098                     vec_println(b.Bin);
1099                     recalc = copyPropWalk(b.Belem,b.Bin);
1100                     printf("Bino ");
1101                     vec_println(b.Bin);
1102                     printf("Bout ");
1103                     vec_println(b.Bout);
1104                 }
1105                 else
1106                 {
1107                     recalc = copyPropWalk(b.Belem,b.Bin);
1108                 }
1109                 /*assert(vec_equal(b.Bin,b.Bout));              */
1110                 /* The previous assert() is correct except      */
1111                 /* for the following case:                      */
1112                 /*      a=b; d=a; a=b;                          */
1113                 /* The vectors don't match because the          */
1114                 /* equations changed to:                        */
1115                 /*      a=b; d=b; a=b;                          */
1116                 /* and the d=b copy elem now reaches the end    */
1117                 /* of the block (the d=a elem didn't).          */
1118                 if (recalc)
1119                     continue Louter;
1120             }
1121         }
1122         return;
1123     }
1124 }
1125 
1126 /*****************************
1127  * Walk tree n, doing copy propagation as we go.
1128  * Keep IN up to date.
1129  * Params:
1130  *      n = tree to walk & do copy propagation in
1131  *      IN = vector of live copy expressions, updated as progress is made
1132  * Returns:
1133  *      true if need to recalculate data flow equations and try again
1134  */
1135 
1136 private bool copyPropWalk(elem *n,vec_t IN)
1137 {
1138     bool recalc = false;
1139     int nocp = 0;
1140 
1141     void cpwalk(elem* n, vec_t IN)
1142     {
1143         assert(n && IN);
1144         /*chkvecdim(go.exptop,0);*/
1145         if (recalc)
1146             return;
1147 
1148         elem *t;
1149         const op = n.Eoper;
1150         if (op == OPcolon || op == OPcolon2)
1151         {
1152             vec_t L = vec_clone(IN);
1153             cpwalk(n.EV.E1,L);
1154             cpwalk(n.EV.E2,IN);
1155             vec_andass(IN,L);               // IN = L & R
1156             vec_free(L);
1157         }
1158         else if (op == OPandand || op == OPoror)
1159         {
1160             cpwalk(n.EV.E1,IN);
1161             vec_t L = vec_clone(IN);
1162             cpwalk(n.EV.E2,L);
1163             vec_andass(IN,L);               // IN = L & R
1164             vec_free(L);
1165         }
1166         else if (OTunary(op))
1167         {
1168             t = n.EV.E1;
1169             if (OTassign(op))
1170             {
1171                 if (t.Eoper == OPind)
1172                     cpwalk(t.EV.E1,IN);
1173             }
1174             else if (op == OPctor || op == OPdtor)
1175             {
1176                 /* This kludge is necessary because in except_pop()
1177                  * an el_match is done on the lvalue. If copy propagation
1178                  * changes the OPctor but not the corresponding OPdtor,
1179                  * then the match won't happen and except_pop()
1180                  * will fail.
1181                  */
1182                 nocp++;
1183                 cpwalk(t,IN);
1184                 nocp--;
1185             }
1186             else
1187                 cpwalk(t,IN);
1188         }
1189         else if (OTassign(op))
1190         {
1191             cpwalk(n.EV.E2,IN);
1192             t = n.EV.E1;
1193             if (t.Eoper == OPind)
1194                 cpwalk(t,IN);
1195             else
1196             {
1197                 debug if (t.Eoper != OPvar) elem_print(n);
1198                 assert(t.Eoper == OPvar);
1199             }
1200         }
1201         else if (ERTOL(n))
1202         {
1203             cpwalk(n.EV.E2,IN);
1204             cpwalk(n.EV.E1,IN);
1205         }
1206         else if (OTbinary(op))
1207         {
1208             cpwalk(n.EV.E1,IN);
1209             cpwalk(n.EV.E2,IN);
1210         }
1211 
1212         if (OTdef(op))                  // if definition elem
1213         {
1214             int ambig;              /* true if ambiguous def        */
1215 
1216             ambig = !OTassign(op) || t.Eoper == OPind;
1217             uint i;
1218             for (i = 0; (i = cast(uint) vec_index(i, IN)) < go.exptop; ++i) // for each active copy elem
1219             {
1220                 Symbol *v;
1221 
1222                 if (op == OPasm)
1223                     goto clr;
1224 
1225                 /* If this elem could kill the lvalue or the rvalue, */
1226                 /*      Clear bit in IN.                        */
1227                 v = go.expnod[i].EV.E1.EV.Vsym;
1228                 if (ambig)
1229                 {
1230                     if (!(v.Sflags & SFLunambig))
1231                         goto clr;
1232                 }
1233                 else
1234                 {
1235                     if (v == t.EV.Vsym)
1236                         goto clr;
1237                 }
1238                 v = go.expnod[i].EV.E2.EV.Vsym;
1239                 if (ambig)
1240                 {
1241                     if (!(v.Sflags & SFLunambig))
1242                         goto clr;
1243                 }
1244                 else
1245                 {
1246                     if (v == t.EV.Vsym)
1247                         goto clr;
1248                 }
1249                 continue;
1250 
1251             clr:                        /* this copy elem is not available */
1252                 vec_clearbit(i,IN);     /* so remove it from the vector */
1253             } /* foreach */
1254 
1255             /* If this is a copy elem in go.expnod[]   */
1256             /*      Set bit in IN.                     */
1257             if ((op == OPeq || op == OPstreq) && n.EV.E1.Eoper == OPvar &&
1258                 n.EV.E2.Eoper == OPvar && n.Eexp)
1259                 vec_setbit(n.Eexp,IN);
1260         }
1261         else if (op == OPvar && !nocp)  // if reference to variable v
1262         {
1263             Symbol *v = n.EV.Vsym;
1264 
1265             //printf("Checking copyprop for '%s', ty=x%x\n",v.Sident,n.Ety);
1266             symbol_debug(v);
1267             const ty = n.Ety;
1268             uint sz = tysize(n.Ety);
1269             if (sz == -1 && !tyfunc(n.Ety))
1270                 sz = cast(uint)type_size(v.Stype);
1271 
1272             elem *foundelem = null;
1273             Symbol *f;
1274             for (uint i = 0; (i = cast(uint) vec_index(i, IN)) < go.exptop; ++i) // for all active copy elems
1275             {
1276                 elem* c = go.expnod[i];
1277                 assert(c);
1278 
1279                 uint csz = tysize(c.EV.E1.Ety);
1280                 if (c.Eoper == OPstreq)
1281                     csz = cast(uint)type_size(c.ET);
1282                 assert(cast(int)csz >= 0);
1283 
1284                 //printf("looking at: ("); WReqn(c); printf("), ty=x%x\n",c.EV.E1.Ety);
1285                 /* Not only must symbol numbers match, but      */
1286                 /* offsets too (in case of arrays) and sizes    */
1287                 /* (in case of unions).                         */
1288                 if (v == c.EV.E1.EV.Vsym &&
1289                     n.EV.Voffset >= c.EV.E1.EV.Voffset &&
1290                     n.EV.Voffset + sz <= c.EV.E1.EV.Voffset + csz)
1291                 {
1292                     if (foundelem)
1293                     {
1294                         if (c.EV.E2.EV.Vsym != f)
1295                             goto noprop;
1296                     }
1297                     else
1298                     {
1299                         foundelem = c;
1300                         f = foundelem.EV.E2.EV.Vsym;
1301                     }
1302                 }
1303             }
1304             if (foundelem)          /* if we can do the copy prop   */
1305             {
1306                 debug if (debugc)
1307                 {
1308                     printf("Copyprop, from '%s'(%d) to '%s'(%d)\n",
1309                         (v.Sident[0]) ? cast(char *)v.Sident.ptr : "temp".ptr, v.Ssymnum,
1310                         (f.Sident[0]) ? cast(char *)f.Sident.ptr : "temp".ptr, f.Ssymnum);
1311                 }
1312 
1313                 type *nt = n.ET;
1314                 targ_size_t noffset = n.EV.Voffset;
1315                 el_copy(n,foundelem.EV.E2);
1316                 n.Ety = ty;    // retain original type
1317                 n.ET = nt;
1318                 n.EV.Voffset += noffset - foundelem.EV.E1.EV.Voffset;
1319 
1320                 /* original => rewrite
1321                  *  v = f
1322                  *  g = v   => g = f
1323                  *  f = x
1324                  *  d = g   => d = f !!error
1325                  * Therefore, if n appears as an rvalue in go.expnod[], then recalc
1326                  */
1327                 for (size_t j = 1; j < go.exptop; ++j)
1328                 {
1329                     //printf("go.expnod[%d]: ", j); elem_print(go.expnod[j]);
1330                     if (go.expnod[j].EV.E2 == n)
1331                     {
1332                         recalc = true;
1333                         break;
1334                     }
1335                 }
1336 
1337                 go.changes++;
1338             }
1339             //else printf("not found\n");
1340         noprop:
1341             {   }
1342         }
1343     }
1344 
1345     cpwalk(n, IN);
1346     return recalc;
1347 }
1348 
1349 /********************************
1350  * Remove dead assignments. Those are assignments to a variable v
1351  * for which there are no subsequent uses of v.
1352  */
1353 
1354 private __gshared
1355 {
1356     Barray!(elem*) assnod;      /* array of pointers to asg elems       */
1357     vec_t ambigref;             /* vector of assignment elems that      */
1358                                 /* are referenced when an ambiguous     */
1359                                 /* reference is done (as in *p or call) */
1360 }
1361 
1362 void rmdeadass()
1363 {
1364     if (debugc) printf("rmdeadass()\n");
1365     flowlv();                       /* compute live variables       */
1366     foreach (b; dfo[])         // for each block b
1367     {
1368         if (!b.Belem)          /* if no elems at all           */
1369             continue;
1370         if (b.Btry)            // if in try-block guarded body
1371             continue;
1372         const assnum = numasg(b.Belem);   // # of assignment elems
1373         if (assnum == 0)                  // if no assignment elems
1374             continue;
1375 
1376         assnod.setLength(assnum);         // pre-allocate sufficient room
1377         vec_t DEAD = vec_calloc(assnum);
1378         vec_t POSS = vec_calloc(assnum);
1379 
1380         ambigref = vec_calloc(assnum);
1381         assnod.setLength(0);
1382         accumda(b.Belem,DEAD,POSS);    // fill assnod[], compute DEAD and POSS
1383         assert(assnum == assnod.length);
1384         vec_free(ambigref);
1385 
1386         vec_orass(POSS,DEAD);   /* POSS |= DEAD                 */
1387         for (uint j = 0; (j = cast(uint) vec_index(j, POSS)) < assnum; ++j) // for each possible dead asg.
1388         {
1389             Symbol *v;      /* v = target of assignment     */
1390             elem *n;
1391             elem *nv;
1392 
1393             n = assnod[j];
1394             nv = n.EV.E1;
1395             v = nv.EV.Vsym;
1396             if (!symbol_isintab(v)) // not considered
1397                 continue;
1398             //printf("assnod[%d]: ",j); WReqn(n); printf("\n");
1399             //printf("\tPOSS\n");
1400             /* If not positively dead but v is live on a    */
1401             /* successor to b, then v is live.              */
1402             //printf("\tDEAD=%d, live=%d\n",vec_testbit(j,DEAD),vec_testbit(v.Ssymnum,b.Boutlv));
1403             if (!vec_testbit(j,DEAD) && vec_testbit(v.Ssymnum,b.Boutlv))
1404                 continue;
1405             /* volatile/shared variables are not dead              */
1406             if ((v.ty() | nv.Ety) & (mTYvolatile | mTYshared))
1407                 continue;
1408             debug if (debugc)
1409             {
1410                 printf("dead assignment (");
1411                 WReqn(n);
1412                 if (vec_testbit(j,DEAD))
1413                     printf(") DEAD\n");
1414                 else
1415                     printf(") Boutlv\n");
1416             }
1417             elimass(n);
1418             go.changes++;
1419         } /* foreach */
1420         vec_free(DEAD);
1421         vec_free(POSS);
1422     } /* for */
1423 }
1424 
1425 /***************************
1426  * Remove side effect of assignment elem.
1427  */
1428 
1429 void elimass(elem *n)
1430 {   elem *e1;
1431 
1432     switch (n.Eoper)
1433     {
1434         case OPvecsto:
1435             n.EV.E2.Eoper = OPcomma;
1436             goto case OPeq;
1437 
1438         case OPeq:
1439         case OPstreq:
1440             /* (V=e) => (random constant,e)     */
1441             /* Watch out for (a=b=c) stuff!     */
1442             /* Don't screw up assnod[]. */
1443             n.Eoper = OPcomma;
1444             n.Ety |= n.EV.E2.Ety & (mTYconst | mTYvolatile | mTYimmutable | mTYshared
1445                  | mTYfar
1446                 );
1447             n.EV.E1.Eoper = OPconst;
1448             break;
1449 
1450         /* Convert (V op= e) to (V op e)        */
1451         case OPaddass:
1452         case OPminass:
1453         case OPmulass:
1454         case OPdivass:
1455         case OPorass:
1456         case OPandass:
1457         case OPxorass:
1458         case OPmodass:
1459         case OPshlass:
1460         case OPshrass:
1461         case OPashrass:
1462             n.Eoper = cast(ubyte)opeqtoop(n.Eoper);
1463             break;
1464 
1465         case OPpostinc: /* (V i++ c) => V       */
1466         case OPpostdec: /* (V i-- c) => V       */
1467             e1 = n.EV.E1;
1468             el_free(n.EV.E2);
1469             el_copy(n,e1);
1470             el_free(e1);
1471             break;
1472 
1473         case OPnegass:
1474             n.Eoper = OPneg;
1475             break;
1476 
1477         case OPbtc:
1478         case OPbtr:
1479         case OPbts:
1480             n.Eoper = OPbt;
1481             break;
1482 
1483         case OPcmpxchg:
1484             n.Eoper = OPcomma;
1485             n.EV.E2.Eoper = OPcomma;
1486             break;
1487 
1488         default:
1489             assert(0);
1490     }
1491 }
1492 
1493 /************************
1494  * Compute number of =,op=,i++,i--,--i,++i elems.
1495  * (Unambiguous assignments only. Ambiguous ones would always be live.)
1496  * Some compilers generate better code for ?: than if-then-else.
1497  */
1498 
1499 private uint numasg(elem *e)
1500 {
1501     assert(e);
1502     if (OTassign(e.Eoper) && e.EV.E1.Eoper == OPvar)
1503     {
1504         e.Nflags |= NFLassign;
1505         return 1 + numasg(e.EV.E1) + (OTbinary(e.Eoper) ? numasg(e.EV.E2) : 0);
1506     }
1507     e.Nflags &= ~NFLassign;
1508     return OTunary(e.Eoper) ? numasg(e.EV.E1) :
1509            OTbinary(e.Eoper) ? numasg(e.EV.E1) + numasg(e.EV.E2) : 0;
1510 }
1511 
1512 /******************************
1513  * Tree walk routine for rmdeadass().
1514  *      DEAD    =       assignments which are dead
1515  *      POSS    =       assignments which are possibly dead
1516  * The algorithm is basically:
1517  *      if we have an assignment to v,
1518  *              for all defs of v in POSS
1519  *                      set corresponding bits in DEAD
1520  *              set bit for this def in POSS
1521  *      if we have a reference to v,
1522  *              clear all bits in POSS that are refs of v
1523  */
1524 
1525 private void accumda(elem *n,vec_t DEAD, vec_t POSS)
1526 {
1527     assert(n && DEAD && POSS);
1528     const op = n.Eoper;
1529     switch (op)
1530     {
1531         case OPcolon:
1532         case OPcolon2:
1533         {
1534             vec_t Pl = vec_clone(POSS);
1535             vec_t Pr = vec_clone(POSS);
1536             vec_t Dl = vec_calloc(vec_numbits(POSS));
1537             vec_t Dr = vec_calloc(vec_numbits(POSS));
1538             accumda(n.EV.E1,Dl,Pl);
1539             accumda(n.EV.E2,Dr,Pr);
1540 
1541             /* D |= P & (Dl & Dr) | ~P & (Dl | Dr)  */
1542             /* P = P & (Pl & Pr) | ~P & (Pl | Pr)   */
1543             /*   = Pl & Pr | ~P & (Pl | Pr)         */
1544             const vecdim = cast(uint)vec_dim(DEAD);
1545             for (uint i = 0; i < vecdim; i++)
1546             {
1547                 DEAD[i] |= (POSS[i] & Dl[i] & Dr[i]) |
1548                            (~POSS[i] & (Dl[i] | Dr[i]));
1549                 POSS[i] = (Pl[i] & Pr[i]) | (~POSS[i] & (Pl[i] | Pr[i]));
1550             }
1551             vec_free(Pl); vec_free(Pr); vec_free(Dl); vec_free(Dr);
1552             break;
1553         }
1554 
1555         case OPandand:
1556         case OPoror:
1557         {
1558             accumda(n.EV.E1,DEAD,POSS);
1559             // Substituting into the above equations Pl=P and Dl=0:
1560             // D |= Dr - P
1561             // P = Pr
1562             vec_t Pr = vec_clone(POSS);
1563             vec_t Dr = vec_calloc(vec_numbits(POSS));
1564             accumda(n.EV.E2,Dr,Pr);
1565             vec_subass(Dr,POSS);
1566             vec_orass(DEAD,Dr);
1567             vec_copy(POSS,Pr);
1568             vec_free(Pr); vec_free(Dr);
1569             break;
1570         }
1571 
1572         case OPvar:
1573         {
1574             Symbol *v = n.EV.Vsym;
1575             targ_size_t voff = n.EV.Voffset;
1576             uint vsize = tysize(n.Ety);
1577 
1578             // We have a reference. Clear all bits in POSS that
1579             // could be referenced.
1580 
1581             foreach (const i; 0 .. cast(uint)assnod.length)
1582             {
1583                 elem *ti = assnod[i].EV.E1;
1584                 if (v == ti.EV.Vsym &&
1585                     ((vsize == -1 || tysize(ti.Ety) == -1) ||
1586                      // If symbol references overlap
1587                      (voff + vsize > ti.EV.Voffset &&
1588                       ti.EV.Voffset + tysize(ti.Ety) > voff)
1589                     )
1590                    )
1591                 {
1592                     vec_clearbit(i,POSS);
1593                 }
1594             }
1595             break;
1596         }
1597 
1598         case OPasm:         // reference everything
1599             foreach (const i; 0 .. cast(uint)assnod.length)
1600                 vec_clearbit(i,POSS);
1601             break;
1602 
1603         case OPbt:
1604             accumda(n.EV.E1,DEAD,POSS);
1605             accumda(n.EV.E2,DEAD,POSS);
1606             vec_subass(POSS,ambigref);      // remove possibly refed
1607             break;
1608 
1609         case OPind:
1610         case OPucall:
1611         case OPucallns:
1612         case OPvp_fp:
1613             accumda(n.EV.E1,DEAD,POSS);
1614             vec_subass(POSS,ambigref);      // remove possibly refed
1615                                             // assignments from list
1616                                             // of possibly dead ones
1617             break;
1618 
1619         case OPconst:
1620             break;
1621 
1622         case OPcall:
1623         case OPcallns:
1624         case OPmemcpy:
1625         case OPstrcpy:
1626         case OPmemset:
1627             accumda(n.EV.E2,DEAD,POSS);
1628             goto case OPstrlen;
1629 
1630         case OPstrlen:
1631             accumda(n.EV.E1,DEAD,POSS);
1632             vec_subass(POSS,ambigref);      // remove possibly refed
1633                                             // assignments from list
1634                                             // of possibly dead ones
1635             break;
1636 
1637         case OPstrcat:
1638         case OPstrcmp:
1639         case OPmemcmp:
1640             accumda(n.EV.E1,DEAD,POSS);
1641             accumda(n.EV.E2,DEAD,POSS);
1642             vec_subass(POSS,ambigref);      // remove possibly refed
1643                                             // assignments from list
1644                                             // of possibly dead ones
1645             break;
1646 
1647         default:
1648             if (OTassign(op))
1649             {
1650                 elem *t;
1651 
1652                 if (ERTOL(n))
1653                     accumda(n.EV.E2,DEAD,POSS);
1654                 t = n.EV.E1;
1655                 // if not (v = expression) then gen refs of left tree
1656                 if (op != OPeq && op != OPstreq)
1657                     accumda(n.EV.E1,DEAD,POSS);
1658                 else if (OTunary(t.Eoper))         // if (*e = expression)
1659                     accumda(t.EV.E1,DEAD,POSS);
1660                 else if (OTbinary(t.Eoper))
1661                 {
1662                     accumda(t.EV.E1,DEAD,POSS);
1663                     accumda(t.EV.E2,DEAD,POSS);
1664                 }
1665                 if (!ERTOL(n) && op != OPnegass)
1666                     accumda(n.EV.E2,DEAD,POSS);
1667 
1668                 // if unambiguous assignment, post all possibilities
1669                 // to DEAD
1670                 if ((op == OPeq || op == OPstreq) && t.Eoper == OPvar)
1671                 {
1672                     uint tsz = tysize(t.Ety);
1673                     if (n.Eoper == OPstreq)
1674                         tsz = cast(uint)type_size(n.ET);
1675                     foreach (const i; 0 .. cast(uint)assnod.length)
1676                     {
1677                         elem *ti = assnod[i].EV.E1;
1678 
1679                         uint tisz = tysize(ti.Ety);
1680                         if (assnod[i].Eoper == OPstreq)
1681                             tisz = cast(uint)type_size(assnod[i].ET);
1682 
1683                         // There may be some problem with this next
1684                         // statement with unions.
1685                         if (ti.EV.Vsym == t.EV.Vsym &&
1686                             ti.EV.Voffset == t.EV.Voffset &&
1687                             tisz == tsz &&
1688                             !(t.Ety & (mTYvolatile | mTYshared)) &&
1689                             //t.EV.Vsym.Sflags & SFLunambig &&
1690                             vec_testbit(i,POSS))
1691                         {
1692                             vec_setbit(i,DEAD);
1693                         }
1694                     }
1695                 }
1696 
1697                 // if assignment operator, post this def to POSS
1698                 if (n.Nflags & NFLassign)
1699                 {
1700                     const i = cast(uint)assnod.length;
1701                     vec_setbit(i,POSS);
1702 
1703                     // if variable could be referenced by a pointer
1704                     // or a function call, mark the assignment in
1705                     // ambigref
1706                     if (!(t.EV.Vsym.Sflags & SFLunambig))
1707                     {
1708                         vec_setbit(i,ambigref);
1709 
1710                         debug if (debugc)
1711                         {
1712                             printf("ambiguous lvalue: ");
1713                             WReqn(n);
1714                             printf("\n");
1715                         }
1716                     }
1717 
1718                     assnod.push(n);
1719                 }
1720             }
1721             else if (OTrtol(op))
1722             {
1723                 accumda(n.EV.E2,DEAD,POSS);
1724                 accumda(n.EV.E1,DEAD,POSS);
1725             }
1726             else if (OTbinary(op))
1727             {
1728                 accumda(n.EV.E1,DEAD,POSS);
1729                 accumda(n.EV.E2,DEAD,POSS);
1730             }
1731             else if (OTunary(op))
1732                 accumda(n.EV.E1,DEAD,POSS);
1733             break;
1734     }
1735 }
1736 
1737 
1738 /***************************
1739  * Mark all dead variables. Only worry about register candidates.
1740  * Compute live ranges for register candidates.
1741  * Be careful not to compute live ranges for members of structures (CLMOS).
1742  */
1743 void deadvar()
1744 {
1745         assert(dfo);
1746 
1747         /* First, mark each candidate as dead.  */
1748         /* Initialize vectors for live ranges.  */
1749         for (SYMIDX i = 0; i < globsym.top; i++)
1750         {
1751             Symbol *s = globsym.tab[i];
1752 
1753             if (s.Sflags & SFLunambig)
1754             {
1755                 s.Sflags |= SFLdead;
1756                 if (s.Sflags & GTregcand)
1757                 {
1758                     s.Srange = vec_realloc(s.Srange, maxblks);
1759                     vec_clear(s.Srange);
1760                 }
1761             }
1762         }
1763 
1764         /* Go through trees and "liven" each one we see.        */
1765         foreach (i, b; dfo[])
1766             if (b.Belem)
1767                 dvwalk(b.Belem,cast(uint)i);
1768 
1769         /* Compute live variables. Set bit for block in live range      */
1770         /* if variable is in the IN set for that block.                 */
1771         flowlv();                       /* compute live variables       */
1772         for (SYMIDX i = 0; i < globsym.top; i++)
1773         {
1774             if (globsym.tab[i].Srange /*&& globsym.tab[i].Sclass != CLMOS*/)
1775                 foreach (j, b; dfo[])
1776                     if (vec_testbit(i,b.Binlv))
1777                         vec_setbit(cast(uint)j,globsym.tab[i].Srange);
1778         }
1779 
1780         /* Print results        */
1781         for (SYMIDX i = 0; i < globsym.top; i++)
1782         {
1783             char *p;
1784             Symbol *s = globsym.tab[i];
1785 
1786             if (s.Sflags & SFLdead && s.Sclass != SCparameter && s.Sclass != SCregpar)
1787                 s.Sflags &= ~GTregcand;    // do not put dead variables in registers
1788             debug
1789             {
1790                 p = cast(char *) s.Sident.ptr ;
1791                 if (s.Sflags & SFLdead)
1792                     if (debugc) printf("Symbol %d '%s' is dead\n",i,p);
1793                 if (debugc && s.Srange /*&& s.Sclass != CLMOS*/)
1794                 {
1795                     printf("Live range for %d '%s': ",i,p);
1796                     vec_println(s.Srange);
1797                 }
1798             }
1799         }
1800 }
1801 
1802 
1803 /*****************************
1804  * Tree walk support routine for deadvar().
1805  * Input:
1806  *      n = elem to look at
1807  *      i = block index
1808  */
1809 private void dvwalk(elem *n,uint i)
1810 {
1811     for (; true; n = n.EV.E1)
1812     {
1813         assert(n);
1814         if (n.Eoper == OPvar || n.Eoper == OPrelconst)
1815         {
1816             Symbol *s = n.EV.Vsym;
1817 
1818             s.Sflags &= ~SFLdead;
1819             if (s.Srange)
1820                 vec_setbit(i,s.Srange);
1821         }
1822         else if (!OTleaf(n.Eoper))
1823         {
1824             if (OTbinary(n.Eoper))
1825                 dvwalk(n.EV.E2,i);
1826             continue;
1827         }
1828         break;
1829     }
1830 }
1831 
1832 /*********************************
1833  * Optimize very busy expressions (VBEs).
1834  */
1835 
1836 private __gshared vec_t blockseen; /* which blocks we have visited         */
1837 
1838 void verybusyexp()
1839 {
1840     elem **pn;
1841     uint j,l;
1842 
1843     if (debugc) printf("verybusyexp()\n");
1844     flowvbe();                      /* compute VBEs                 */
1845     if (go.exptop <= 1) return;        /* if no VBEs                   */
1846     assert(go.expblk.length);
1847     if (blockinit())
1848         return;                     // can't handle ASM blocks
1849     compdom();                      /* compute dominators           */
1850     /*setvecdim(go.exptop);*/
1851     genkillae();                    /* compute Bgen and Bkill for   */
1852                                     /* AEs                          */
1853     /*chkvecdim(go.exptop,0);*/
1854     blockseen = vec_calloc(dfo.length);
1855 
1856     /* Go backwards through dfo so that VBEs are evaluated as       */
1857     /* close as possible to where they are used.                    */
1858     foreach_reverse (i, b; dfo[])     // for each block
1859     {
1860         int done;
1861 
1862         /* Do not hoist things to blocks that do not            */
1863         /* divide the flow of control.                          */
1864 
1865         switch (b.BC)
1866         {
1867             case BCiftrue:
1868             case BCswitch:
1869                 break;
1870 
1871             default:
1872                 continue;
1873         }
1874 
1875         /* Find pointer to last statement in current elem */
1876         pn = &(b.Belem);
1877         if (*pn)
1878         {
1879             while ((*pn).Eoper == OPcomma)
1880                 pn = &((*pn).EV.E2);
1881             /* If last statement has side effects,  */
1882             /* don't do these VBEs. Potentially we  */
1883             /* could by assigning the result to     */
1884             /* a temporary, and rewriting the tree  */
1885             /* from (n) to (T=n,T) and installing   */
1886             /* the VBE as (T=n,VBE,T). This         */
1887             /* may not buy us very much, so we will */
1888             /* just skip it for now.                */
1889             /*if (sideeffect(*pn))*/
1890             if (!(*pn).Eexp)
1891                 continue;
1892         }
1893 
1894         /* Eliminate all elems that have already been           */
1895         /* hoisted (indicated by go.expnod[] == 0).                */
1896         /* Constants are not useful as VBEs.                    */
1897         /* Eliminate all elems from Bout that are not in blocks */
1898         /* that are dominated by b.                             */
1899         static if (0)
1900         {
1901             printf("block %d Bout = ",i);
1902             vec_println(b.Bout);
1903         }
1904         done = true;
1905         for (j = 0; (j = cast(uint) vec_index(j, b.Bout)) < go.exptop; ++j)
1906         {
1907             if (go.expnod[j] == null ||
1908                 !!OTleaf(go.expnod[j].Eoper) ||
1909                 !dom(b,go.expblk[j]))
1910                 vec_clearbit(j,b.Bout);
1911             else
1912                 done = false;
1913         }
1914         if (done) continue;
1915 
1916         /* Eliminate from Bout all elems that are killed by     */
1917         /* a block between b and that elem.                     */
1918         static if (0)
1919         {
1920             printf("block %d Bout = ",i);
1921             vec_println(b.Bout);
1922         }
1923         for (j = 0; (j = cast(uint) vec_index(j, b.Bout)) < go.exptop; ++j)
1924         {
1925             vec_clear(blockseen);
1926             foreach (bl; ListRange(go.expblk[j].Bpred))
1927             {
1928                 if (killed(j,list_block(bl),b))
1929                 {
1930                     vec_clearbit(j,b.Bout);
1931                     break;
1932                 }
1933             }
1934         }
1935 
1936         /* For each elem still left, make sure that there       */
1937         /* exists a path from b to j along which there is       */
1938         /* no other use of j (else it would be a CSE, and       */
1939         /* it would be a waste of time to hoist it).            */
1940         static if (0)
1941         {
1942             printf("block %d Bout = ",i);
1943             vec_println(b.Bout);
1944         }
1945 
1946         for (j = 0; (j = cast(uint) vec_index(j, b.Bout)) < go.exptop; ++j)
1947         {
1948             vec_clear(blockseen);
1949             foreach (bl; ListRange(go.expblk[j].Bpred))
1950             {
1951                 if (ispath(j,list_block(bl),b))
1952                     goto L2;
1953             }
1954             vec_clearbit(j,b.Bout);        /* thar ain't no path   */
1955         L2:
1956         }
1957 
1958 
1959         /* For each elem that appears more than once in Bout    */
1960         /*      We have a VBE.                                  */
1961         static if (0)
1962         {
1963             printf("block %d Bout = ",i);
1964             vec_println(b.Bout);
1965         }
1966 
1967         for (j = 0; (j = cast(uint) vec_index(j, b.Bout)) < go.exptop; ++j)
1968         {
1969             uint k;
1970             for (k = j + 1; k < go.exptop; k++)
1971             {   if (vec_testbit(k,b.Bout) &&
1972                         el_match(go.expnod[j],go.expnod[k]))
1973                             goto foundvbe;
1974             }
1975             continue;               /* no VBE here          */
1976 
1977         foundvbe:                   /* we got one           */
1978             debug
1979             {
1980                 if (debugc)
1981                 {   printf("VBE %d,%d, block %d (",j,k, cast(int) i);
1982                     WReqn(go.expnod[j]);
1983                     printf(");\n");
1984                 }
1985             }
1986             *pn = el_bin(OPcomma,(*pn).Ety,
1987                          el_copytree(go.expnod[j]),*pn);
1988 
1989             /* Mark all the vbe elems found but one (the    */
1990             /* go.expnod[j] one) so that the expression will   */
1991             /* only be hoisted again if other occurrences   */
1992             /* of the expression are found later. This      */
1993             /* will substitute for the fact that the        */
1994             /* el_copytree() expression does not appear in go.expnod[]. */
1995             l = k;
1996             do
1997             {
1998                 if (k == l || (vec_testbit(k,b.Bout) &&
1999                     el_match(go.expnod[j],go.expnod[k])))
2000                 {
2001                     /* Fix so nobody else will      */
2002                     /* vbe this elem                */
2003                     go.expnod[k] = null;
2004                     vec_clearbit(k,b.Bout);
2005                 }
2006             } while (++k < go.exptop);
2007             go.changes++;
2008         } /* foreach */
2009     } /* for */
2010     vec_free(blockseen);
2011 }
2012 
2013 /****************************
2014  * Return true if elem j is killed somewhere
2015  * between b and bp.
2016  */
2017 
2018 private int killed(uint j,block *bp,block *b)
2019 {
2020     if (bp == b || vec_testbit(bp.Bdfoidx,blockseen))
2021         return false;
2022     if (vec_testbit(j,bp.Bkill))
2023         return true;
2024     vec_setbit(bp.Bdfoidx,blockseen);      /* mark as visited              */
2025     foreach (bl; ListRange(bp.Bpred))
2026         if (killed(j,list_block(bl),b))
2027             return true;
2028     return false;
2029 }
2030 
2031 /***************************
2032  * Return true if there is a path from b to bp along which
2033  * elem j is not used.
2034  * Input:
2035  *      b .    block where we want to put the VBE
2036  *      bp .   block somewhere between b and block containing j
2037  *      j =     VBE expression elem candidate (index into go.expnod[])
2038  */
2039 
2040 private int ispath(uint j,block *bp,block *b)
2041 {
2042     /*chkvecdim(go.exptop,0);*/
2043     if (bp == b) return true;              /* the trivial case             */
2044     if (vec_testbit(bp.Bdfoidx,blockseen))
2045         return false;                      /* already seen this block      */
2046     vec_setbit(bp.Bdfoidx,blockseen);      /* we've visited this block     */
2047 
2048     /* false if elem j is used in block bp (and reaches the end     */
2049     /* of bp, indicated by it being an AE in Bgen)                  */
2050     uint i;
2051     for (i = 0; (i = cast(uint) vec_index(i, bp.Bgen)) < go.exptop; ++i) // look thru used expressions
2052     {
2053         if (i != j && go.expnod[i] && el_match(go.expnod[i],go.expnod[j]))
2054             return false;
2055     }
2056 
2057     /* Not used in bp, see if there is a path through a predecessor */
2058     /* of bp                                                        */
2059     foreach (bl; ListRange(bp.Bpred))
2060         if (ispath(j,list_block(bl),b))
2061             return true;
2062 
2063     return false;           /* j is used along all paths            */
2064 }
2065 
2066 }