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-2021 by The D Language Foundation, All Rights Reserved
7  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
8  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
9  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/gdag.d, backend/gdag.d)
10  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/gdag.d
11  */
12 
13 module dmd.backend.gdag;
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.time;
25 
26 import dmd.backend.cc;
27 import dmd.backend.cdef;
28 import dmd.backend.code_x86;
29 import dmd.backend.oper;
30 import dmd.backend.global;
31 import dmd.backend.goh;
32 import dmd.backend.el;
33 import dmd.backend.ty;
34 import dmd.backend.type;
35 
36 import dmd.backend.dlist;
37 import dmd.backend.dvec;
38 
39 extern (C++):
40 
41 nothrow:
42 
43 enum Aetype { cse, arraybounds }
44 
45 private __gshared Aetype aetype;
46 
47 bool Eunambig(elem* e) { return OTassign(e.Eoper) && e.EV.E1.Eoper == OPvar; }
48 
49 /*************************************
50  * Determine if floating point should be cse'd.
51  * Returns:
52  *      true if should be cse'd
53  */
54 
55 private bool cse_float(elem *e)
56 {
57     // Don't CSE floating stuff if generating
58     // inline 8087 code, the code generator
59     // can't handle it yet
60     return !(tyfloating(e.Ety) && config.inline8087 &&
61              e.Eoper != OPvar && e.Eoper != OPconst) ||
62            (tyxmmreg(e.Ety) && config.fpxmmregs);
63 }
64 
65 /************************************
66  * Build DAGs (basically find all the common subexpressions).
67  * Must be done after all other optimizations, because most
68  * of them depend on the trees being trees, not DAGs.
69  * The general strategy is:
70  *      Compute available expressions (AEs)
71  *      For each block
72  *              stick together nodes that match, keeping AEs up to date
73  *      For each block
74  *              unstick unprofitable common subexpressions
75  *              (this is generally target-dependent)
76  */
77 
78 void builddags()
79 {
80     vec_t aevec;
81 
82     debug if (debugc) printf("builddags()\n");
83     assert(dfo);
84     flowae();                       /* compute available expressions */
85     if (go.exptop <= 1)             /* if no AEs                     */
86         return;
87     aetype = Aetype.cse;
88 
89     debug
90         foreach (i, e; go.expnod[])
91         {
92             //printf("go.expnod[%d] = %p\n",i,e);
93             if (e)
94                 elem_debug(e);
95         }
96 
97     static if (0)
98     {
99         printf("defkill  "); vec_println(go.defkill,go.exptop);
100         printf("starkill "); vec_println(go.starkill,go.exptop);
101         printf("vptrkill "); vec_println(go.vptrkill,go.exptop);
102     }
103 
104     static if (0)
105     {
106         /* This is the 'correct' algorithm for CSEs. We can't use it    */
107         /* till we fix the code generator.                              */
108         foreach (i, b; dfo[])
109         {
110             if (b.Belem)
111             {
112                 static if (0)
113                 {
114                     printf("dfo[%d] = %p\n",i,b);
115                     printf("b.Bin   "); vec_println(b.Bin,go.exptop);
116                     printf("b.Bout  "); vec_println(b.Bout,go.exptop);
117                     aewalk(&(b.Belem),b.Bin);
118                     printf("b.Bin   "); vec_println(b.Bin,go.exptop);
119                     printf("b.Bout  "); vec_println(b.Bout,go.exptop);
120                 }
121                 else
122                 {
123                     aewalk(&(b.Belem),b.Bin);
124                 }
125                 /* Bin and Bout would be equal at this point  */
126                 /* except that we deleted some elems from     */
127                 /* go.expnod[] and so it's a subset of Bout   */
128                 /* assert(veceq(b.Bin,b.Bout));               */
129             }
130         }
131     }
132     else
133     {
134         /* Do CSEs across extended basic blocks only. This is because   */
135         /* the code generator can only track register contents          */
136         /* properly across extended basic blocks.                       */
137         aevec = vec_calloc(go.exptop);
138         foreach (i, b; dfo[])
139         {
140             /* if not first block and (there are more than one      */
141             /* predecessor or the only predecessor is not the       */
142             /* previous block), then zero out the available         */
143             /* expressions.                                         */
144             if ((i != 0 &&
145                  (list_block(b.Bpred) != dfo[i - 1] ||
146                   list_next(b.Bpred) != null))
147                 || b.BC == BCasm
148                 || b.BC == BC_finally
149                 || b.BC == BC_lpad
150                 || b.BC == BCcatch
151                 || b.BC == BCjcatch
152                )
153                 vec_clear(aevec);
154             if (b.Belem)           /* if there is an expression    */
155                 aewalk(&(b.Belem),aevec);
156         }
157         vec_free(aevec);
158     }
159 
160     // Need 2 passes to converge on solution
161     foreach (j; 0 .. 2)
162         foreach (b; dfo[])
163         {
164             if (b.Belem)
165             {
166                 //printf("b = 0x%x\n",b);
167                 removecses(&(b.Belem));
168             }
169         }
170 }
171 
172 
173 /****************************
174  * Walk tree, rewriting *pn into a DAG as we go.
175  * Params:
176  *      pn = pointer to expression tree to convert to DAG
177  *      ae = vector of available expressions
178  */
179 
180 private void aewalk(elem **pn,vec_t ae)
181 {
182     elem* n = *pn;
183     assert(n && ae);
184     //printf("visiting  %d: (",n.Eexp); WReqn(*pn); printf(")\n");
185     //chkvecdim(go.exptop);
186     const op = n.Eoper;
187     if (n.Eexp)                            // if an AE
188     {   // Try to find an equivalent AE, and point to it instead
189         assert(go.expnod[n.Eexp] == n);
190         if (aetype == Aetype.cse)
191         {
192             for (uint i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i)
193             {   elem *e = go.expnod[i];
194 
195                 // Attempt to replace n with e
196                 if (e == null)              // if elem no longer exists
197                     vec_clearbit(i,ae);     // it's not available
198                 else if (n != e &&
199                     el_match(n,e) &&
200                     e.Ecount < 0xFF-1 &&   // must fit in unsigned char
201                     cse_float(n)
202                     )
203                 {
204                     *pn = e;                // replace n with e
205                     //printf("cse: %p (",n); WReqn(*pn); printf(")\n");
206                     e.Ecount++;
207                     debug assert(e.Ecount != 0);
208 
209                     void aeclear(elem *n)
210                     {
211                         while (1)
212                         {
213                             const i = n.Eexp;
214                             assert(i);
215                             if (n.Ecount)
216                                 break;
217 
218                             go.expnod[i] = null;
219                             vec_clearbit(i,ae);
220                             if (OTunary(n.Eoper))
221                             {
222                                 n = n.EV.E1;
223                                 continue;
224                             }
225                             else if (OTbinary(n.Eoper))
226                             {
227                                 aeclear(n.EV.E1);
228                                 n = n.EV.E2;
229                                 continue;
230                             }
231                             break;
232                         }
233                     }
234 
235                     aeclear(n);
236                     el_free(n);
237                     return;
238                 }
239             }
240         }
241     }
242 
243     elem *t;
244     switch (op)
245     {
246         case OPcolon:
247         case OPcolon2:
248         {
249             // ae = ae & ael & aer
250             // AEs gened by ael and aer are mutually exclusive
251             vec_t aer = vec_clone(ae);
252             aewalk(&(n.EV.E1),ae);
253             aewalk(&(n.EV.E2),aer);
254             vec_andass(ae,aer);
255             vec_free(aer);
256             break;
257         }
258 
259         case OPandand:
260         case OPoror:
261         {
262             aewalk(&(n.EV.E1),ae);
263             /* ae &= aer    */
264             vec_t aer = vec_clone(ae);
265             aewalk(&(n.EV.E2),aer);
266             if (el_returns(n.EV.E2))
267                 vec_andass(ae,aer);
268             vec_free(aer);
269             break;
270         }
271 
272         case OPnegass:
273             t = n.EV.E1;
274             if (t.Eoper == OPind)
275                 aewalk(&(t.EV.E1),ae);
276             break;
277 
278         case OPctor:
279         case OPdtor:
280         case OPdctor:
281             break;
282 
283         case OPasm:
284         case OPddtor:
285             vec_clear(ae);          // kill everything
286             return;
287 
288         default:
289             if (OTbinary(op))
290             {
291                 if (ERTOL(n))
292                 {
293                     // Don't CSE constants that will turn into
294                     // an INC or DEC anyway
295                     if (n.EV.E2.Eoper == OPconst &&
296                         n.EV.E2.EV.Vint == 1 &&
297                         (op == OPaddass || op == OPminass ||
298                          op == OPpostinc || op == OPpostdec)
299                        )
300                     {   }
301                     else
302                         aewalk(&(n.EV.E2),ae);
303                 }
304                 if (OTassign(op))
305                 {
306                     t = n.EV.E1;
307                     if (t.Eoper == OPind)
308                         aewalk(&(t.EV.E1),ae);
309                 }
310                 else
311                     aewalk(&(n.EV.E1),ae);
312                 if (!ERTOL(n))
313                     aewalk(&(n.EV.E2),ae);
314             }
315             else if (OTunary(op))
316             {
317                 assert(op != OPnegass);
318                 aewalk(&(n.EV.E1),ae);
319             }
320     }
321 
322     if (OTdef(op))
323     {
324         assert(n.Eexp == 0);   // should not be an AE
325         /* remove all AEs that could be affected by this def    */
326         if (Eunambig(n))        // if unambiguous definition
327         {
328             assert(t.Eoper == OPvar);
329             Symbol* s = t.EV.Vsym;
330             if (!(s.Sflags & SFLunambig))
331                 vec_subass(ae,go.starkill);
332             for (uint i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) // for each ae elem
333             {
334                 elem *e = go.expnod[i];
335 
336                 if (!e) continue;
337                 if (OTunary(e.Eoper))
338                 {
339                     if (vec_testbit(e.EV.E1.Eexp,ae))
340                         continue;
341                 }
342                 else if (OTbinary(e.Eoper))
343                 {
344                     if (vec_testbit(e.EV.E1.Eexp,ae) &&
345                         vec_testbit(e.EV.E2.Eexp,ae))
346                         continue;
347                 }
348                 else if (e.Eoper == OPvar)
349                 {
350                     if (e.EV.Vsym != s)
351                         continue;
352                 }
353                 else
354                     continue;
355                 vec_clearbit(i,ae);
356             }
357         }
358         else                    /* else ambiguous definition    */
359         {
360             vec_subass(ae,go.defkill);
361             if (OTcalldef(op))
362                 vec_subass(ae,go.vptrkill);
363         }
364 
365         // GEN the lvalue of an assignment operator
366         if (OTassign(op) && !OTpost(op) && t.Eexp)
367             vec_setbit(t.Eexp,ae);
368     }
369     if (n.Eexp)            // if an AE
370     {
371         if (op == OPvp_fp || op == OPcvp_fp)
372             /* Invalidate all other OPvp_fps     */
373             vec_subass(ae,go.vptrkill);
374 
375         /*printf("available: ("); WReqn(n); printf(")\n");
376         elem_print(n);*/
377         vec_setbit(n.Eexp,ae);     /* mark this elem as available  */
378     }
379 }
380 
381 
382 /**************************
383  * Remove a CSE.
384  * Input:
385  *      pe      pointer to pointer to CSE
386  * Output:
387  *      *pe     new elem to replace the old
388  * Returns:
389  *      *pe
390  */
391 private elem * delcse(elem **pe)
392 {
393     elem *e;
394 
395     e = el_calloc();
396     el_copy(e,*pe);
397 
398     debug if (debugc)
399     {
400         printf("deleting unprofitable CSE %p (", *pe);
401         WReqn(e);
402         printf(")\n");
403     }
404 
405     assert(e.Ecount != 0);
406     if (!OTleaf(e.Eoper))
407     {
408         if (e.EV.E1.Ecount == 0xFF-1)
409         {
410             elem *ereplace;
411             ereplace = el_calloc();
412             el_copy(ereplace,e.EV.E1);
413             e.EV.E1 = ereplace;
414             ereplace.Ecount = 0;
415         }
416         else
417         {
418             e.EV.E1.Ecount++;
419             debug assert(e.EV.E1.Ecount != 0);
420         }
421         if (OTbinary(e.Eoper))
422         {
423             if (e.EV.E2.Ecount == 0xFF-1)
424             {
425                 elem *ereplace;
426                 ereplace = el_calloc();
427                 el_copy(ereplace,e.EV.E2);
428                 e.EV.E2 = ereplace;
429                 ereplace.Ecount = 0;
430             }
431             else
432             {
433                 e.EV.E2.Ecount++;
434                 debug assert(e.EV.E2.Ecount != 0);
435             }
436         }
437     }
438     --(*pe).Ecount;
439     debug assert((*pe).Ecount != 0xFF);
440     (*pe).Nflags |= NFLdelcse;     // not generating node
441     e.Ecount = 0;
442     *pe = e;
443     return *pe;
444 }
445 
446 
447 /******************************
448  * 'Unstick' CSEs that would be unprofitable to do. These are usually
449  * things like addressing modes, and are usually target-dependent.
450  */
451 
452 private void removecses(elem **pe)
453 {
454 L1:
455     elem* e = *pe;
456     //printf("  removecses(%p) ", e); WReqn(e); printf("\n");
457     assert(e);
458     elem_debug(e);
459     if (e.Nflags & NFLdelcse && e.Ecount)
460     {
461         delcse(pe);
462         goto L1;
463     }
464     const op = e.Eoper;
465     if (OTunary(op))
466     {
467         if (op == OPind)
468         {
469             bool scaledIndex = I32 || I64;      // if scaled index addressing mode support
470             elem *e1 = e.EV.E1;
471             if (e1.Eoper == OPadd &&
472                 e1.Ecount
473                )
474             {
475                 if (scaledIndex)
476                 {
477                     e1 = delcse(&e.EV.E1);
478                     if (e1.EV.E1.Ecount) // == 1)
479                         delcse(&e1.EV.E1);
480                     if (e1.EV.E2.Ecount && e1.EV.E2.Eoper != OPind)
481                         delcse(&e1.EV.E2);
482                 }
483                 /* *(v +. c)
484                  * *(*pc +. c)
485                  * The + and the const shouldn't be CSEs.
486                  */
487                 else if (e1.EV.E2.Eoper == OPconst &&
488                     (e1.EV.E1.Eoper == OPvar || (e1.EV.E1.Eoper == OPind && e1.EV.E1.Ety & (mTYconst | mTYimmutable)))
489                    )
490                 {
491                     e1 = delcse(&e.EV.E1);
492                 }
493             }
494 
495             /* *(((e <<. 3) + e) + e)
496              */
497             if (scaledIndex && e1.Eoper == OPadd &&
498                 e1.EV.E1.Eoper == OPadd &&
499                 e1.EV.E1.EV.E1.Ecount &&
500                 e1.EV.E1.EV.E1.Eoper == OPshl &&
501                 e1.EV.E1.EV.E1.EV.E2.Eoper == OPconst &&
502                 e1.EV.E1.EV.E1.EV.E2.EV.Vuns <= 3
503                )
504             {
505                 delcse(&e1.EV.E1.EV.E1);        // the <<. operator
506             }
507 
508             /* *(((e << 3) +. e) + e)
509             */
510             if (scaledIndex && e1.Eoper == OPadd &&
511                 e1.EV.E1.Eoper == OPadd &&
512                 e1.EV.E1.Ecount &&
513                 e1.EV.E1.EV.E1.Eoper == OPshl &&
514                 e1.EV.E1.EV.E1.EV.E2.Eoper == OPconst &&
515                 e1.EV.E1.EV.E1.EV.E2.EV.Vuns <= 3
516                )
517             {
518                 delcse(&e1.EV.E1);              // the +. operator
519             }
520 
521             /* *((e <<. 3) + e)
522              */
523             else if (scaledIndex && e1.Eoper == OPadd &&
524                 e1.EV.E1.Ecount &&
525                 e1.EV.E1.Eoper == OPshl &&
526                 e1.EV.E1.EV.E2.Eoper == OPconst &&
527                 e1.EV.E1.EV.E2.EV.Vuns <= 3
528                )
529             {
530                 delcse(&e1.EV.E1);              // the <<. operator
531             }
532 
533             // Remove *e1 where it's a double
534             if (e.Ecount && tyfloating(e.Ety))
535                 e = delcse(pe);
536         }
537         // This CSE is too easy to regenerate
538         else if (op == OPu16_32 && I16 && e.Ecount)
539             e = delcse(pe);
540 
541         else if (op == OPd_ld && e.EV.E1.Ecount > 0)
542             delcse(&e.EV.E1);
543 
544         // OPremquo is only worthwhile if its result is used more than once
545         else if (e.EV.E1.Eoper == OPremquo &&
546                  (op == OP64_32 || op == OP128_64 || op == OPmsw) &&
547                  e.EV.E1.Ecount == 0)
548         {   // Convert back to OPdiv or OPmod
549             elem *e1 = e.EV.E1;
550             e.Eoper = (op == OPmsw) ? OPmod : OPdiv;
551             e.EV.E1 = e1.EV.E1;
552             e.EV.E2 = e1.EV.E2;
553             e1.EV.E1 = null;
554             e1.EV.E2 = null;
555             el_free(e1);
556 
557             removecses(&(e.EV.E1));
558             pe = &(e.EV.E2);
559             goto L1;
560         }
561     }
562     else if (OTbinary(op))
563     {
564         if (e.Ecount > 0 && OTrel(op) && e.Ecount < 4
565             /* Don't CSE floating stuff if generating   */
566             /* inline 8087 code, the code generator     */
567             /* can't handle it yet                      */
568             && !(tyfloating(e.EV.E1.Ety) && config.inline8087)
569            )
570                 e = delcse(pe);
571         if (ERTOL(e))
572         {
573             removecses(&(e.EV.E2));
574             pe = &(e.EV.E1);
575         }
576         else
577         {
578             removecses(&(e.EV.E1));
579             pe = &(e.EV.E2);
580         }
581         goto L1;
582     }
583     else /* leaf node */
584     {
585         return;
586     }
587     pe = &(e.EV.E1);
588     goto L1;
589 }
590 
591 /*****************************************
592  * Do optimizations based on if we know an expression is
593  * 0 or !=0, even though we don't know anything else.
594  */
595 
596 void boolopt()
597 {
598     vec_t aevec;
599     vec_t aevecval;
600 
601     debug if (debugc) printf("boolopt()\n");
602     if (!dfo.length)
603         compdfo();
604     flowae();                       /* compute available expressions */
605     if (go.exptop <= 1)             /* if no AEs                     */
606         return;
607     static if (0)
608     {
609         for (uint i = 0; i < go.exptop; i++)
610                 printf("go.expnod[%d] = 0x%x\n",i,go.expnod[i]);
611         printf("defkill  "); vec_println(go.defkill,go.exptop);
612         printf("starkill "); vec_println(go.starkill,go.exptop);
613         printf("vptrkill "); vec_println(go.vptrkill,go.exptop);
614     }
615 
616     /* Do CSEs across extended basic blocks only. This is because   */
617     /* the code generator can only track register contents          */
618     /* properly across extended basic blocks.                       */
619     aevec = vec_calloc(go.exptop);
620     aevecval = vec_calloc(go.exptop);
621 
622     // Mark each expression that we know starts off with a non-zero value
623     for (uint i = 0; i < go.exptop; i++)
624     {
625         elem *e = go.expnod[i];
626         if (e)
627         {
628             elem_debug(e);
629             if (e.Eoper == OPvar && e.EV.Vsym.Sflags & SFLtrue)
630             {
631                 vec_setbit(i,aevec);
632                 vec_setbit(i,aevecval);
633             }
634         }
635     }
636 
637     foreach (i, b; dfo[])
638     {
639         /* if not first block and (there are more than one      */
640         /* predecessor or the only predecessor is not the       */
641         /* previous block), then zero out the available         */
642         /* expressions.                                         */
643         if ((i != 0 &&
644              (list_block(b.Bpred) != dfo[i - 1] ||
645               list_next(b.Bpred) != null))
646             || b.BC == BCasm
647             || b.BC == BC_finally
648             || b.BC == BC_lpad
649             || b.BC == BCcatch
650             || b.BC == BCjcatch
651            )
652             vec_clear(aevec);
653         if (b.Belem)           /* if there is an expression    */
654             abewalk(b.Belem,aevec,aevecval);
655     }
656     vec_free(aevec);
657     vec_free(aevecval);
658 }
659 
660 /****************************
661  * Walk tree, replacing bool expressions that we know
662  *      ae = vector of available boolean expressions
663  *      aeval = parallel vector of values corresponding to whether bool
664  *               value is 1 or 0
665  *      n = elem tree to look at
666  */
667 
668 private void abewalk(elem *n,vec_t ae,vec_t aeval)
669 {
670     elem *t;
671 
672     assert(n && ae);
673     elem_debug(n);
674     /*printf("visiting: ("); WReqn(*pn); printf("), Eexp = %d\n",n.Eexp);*/
675     /*chkvecdim(go.exptop);*/
676     const op = n.Eoper;
677     switch (op)
678     {
679         case OPcond:
680         {
681             assert(n.EV.E2.Eoper == OPcolon || n.EV.E2.Eoper == OPcolon2);
682             abewalk(n.EV.E1,ae,aeval);
683             abeboolres(n.EV.E1,ae,aeval);
684             vec_t aer = vec_clone(ae);
685             vec_t aerval = vec_clone(aeval);
686             if (!el_returns(n.EV.E2.EV.E1))
687             {
688                 abeset(n.EV.E1,aer,aerval,true);
689                 abewalk(n.EV.E2.EV.E1,aer,aerval);
690                 abeset(n.EV.E1,ae,aeval,false);
691                 abewalk(n.EV.E2.EV.E2,ae,aeval);
692             }
693             else if (!el_returns(n.EV.E2.EV.E2))
694             {
695                 abeset(n.EV.E1,ae,aeval,true);
696                 abewalk(n.EV.E2.EV.E1,ae,aeval);
697                 abeset(n.EV.E1,aer,aerval,false);
698                 abewalk(n.EV.E2.EV.E2,aer,aerval);
699             }
700             else
701             {
702                 /* ae = ae & ael & aer
703                  * AEs gened by ael and aer are mutually exclusive
704                  */
705                 abeset(n.EV.E1,aer,aerval,true);
706                 abewalk(n.EV.E2.EV.E1,aer,aerval);
707                 abeset(n.EV.E1,ae,aeval,false);
708                 abewalk(n.EV.E2.EV.E2,ae,aeval);
709 
710                 vec_xorass(aerval,aeval);
711                 vec_subass(aer,aerval);
712                 vec_andass(ae,aer);
713             }
714             vec_free(aer);
715             vec_free(aerval);
716             break;
717         }
718 
719         case OPcolon:
720         case OPcolon2:
721             assert(0);
722 
723         case OPandand:
724         case OPoror:
725         {
726             //printf("test1 %p: ", n); WReqn(n); printf("\n");
727             abewalk(n.EV.E1,ae,aeval);
728             abeboolres(n.EV.E1,ae,aeval);
729             vec_t aer = vec_clone(ae);
730             vec_t aerval = vec_clone(aeval);
731             if (!el_returns(n.EV.E2))
732             {
733                 abeset(n.EV.E1,aer,aerval,(op == OPandand));
734                 abewalk(n.EV.E2,aer,aerval);
735                 abeset(n.EV.E1,ae,aeval,(op != OPandand));
736             }
737             else
738             {
739                 /* ae &= aer
740                  */
741                 abeset(n.EV.E1,aer,aerval,(op == OPandand));
742                 abewalk(n.EV.E2,aer,aerval);
743 
744                 vec_xorass(aerval,aeval);
745                 vec_subass(aer,aerval);
746                 vec_andass(ae,aer);
747             }
748 
749             vec_free(aer);
750             vec_free(aerval);
751             break;
752         }
753 
754         case OPbool:
755         case OPnot:
756             abewalk(n.EV.E1,ae,aeval);
757             abeboolres(n.EV.E1,ae,aeval);
758             break;
759 
760         case OPeqeq:
761         case OPne:
762         case OPlt:
763         case OPle:
764         case OPgt:
765         case OPge:
766         case OPunord:   case OPlg:      case OPleg:     case OPule:
767         case OPul:      case OPuge:     case OPug:      case OPue:
768         case OPngt:     case OPnge:     case OPnlt:     case OPnle:
769         case OPord:     case OPnlg:     case OPnleg:    case OPnule:
770         case OPnul:     case OPnuge:    case OPnug:     case OPnue:
771             abewalk(n.EV.E1,ae,aeval);
772             abewalk(n.EV.E2,ae,aeval);
773             abeboolres(n,ae,aeval);
774             break;
775 
776         case OPnegass:
777             t = n.EV.E1;
778             if (t.Eoper == OPind)
779                 abewalk(t.EV.E1,ae,aeval);
780             break;
781 
782         case OPasm:
783             vec_clear(ae);      // kill everything
784             return;
785 
786         default:
787             if (OTbinary(op))
788             {   if (ERTOL(n))
789                     abewalk(n.EV.E2,ae,aeval);
790                 if (OTassign(op))
791                 {   t = n.EV.E1;
792                     if (t.Eoper == OPind)
793                         abewalk(t.EV.E1,ae,aeval);
794                 }
795                 else
796                         abewalk(n.EV.E1,ae,aeval);
797                 if (!ERTOL(n))
798                     abewalk(n.EV.E2,ae,aeval);
799             }
800             else if (OTunary(op))
801                 abewalk(n.EV.E1,ae,aeval);
802             break;
803     }
804 
805     if (OTdef(op))
806     {
807         assert(n.Eexp == 0);           // should not be an AE
808         /* remove all AEs that could be affected by this def    */
809         if (Eunambig(n))        /* if unambiguous definition    */
810         {
811             Symbol *s;
812 
813             assert(t.Eoper == OPvar);
814             s = t.EV.Vsym;
815             if (!(s.Sflags & SFLunambig))
816                 vec_subass(ae,go.starkill);
817             for (uint i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) // for each ae elem
818             {
819                 elem *e = go.expnod[i];
820 
821                 if (!e) continue;
822                 if (el_appears(e,s))
823                     vec_clearbit(i,ae);
824             }
825         }
826         else                    /* else ambiguous definition    */
827         {
828             vec_subass(ae,go.defkill);
829             if (OTcalldef(op))
830                 vec_subass(ae,go.vptrkill);
831         }
832         /* GEN the lvalue of an assignment operator     */
833         uint i1, i2;
834         if (op == OPeq && (i1 = t.Eexp) != 0 && (i2 = n.EV.E2.Eexp) != 0)
835         {
836             if (vec_testbit(i2,ae))
837             {
838                 vec_setbit(i1,ae);
839                 if (vec_testbit(i2,aeval))
840                     vec_setbit(i1,aeval);
841                 else
842                     vec_clearbit(i1,aeval);
843             }
844         }
845     }
846     else if (n.Eexp)           /* if an AE                     */
847     {
848         if (op == OPvp_fp || op == OPcvp_fp)
849             /* Invalidate all other OPvp_fps */
850             vec_subass(ae,go.vptrkill);
851 
852         /*printf("available: ("); WReqn(n); printf(")\n");
853         elem_print(n);*/
854 //      vec_setbit(n.Eexp,ae); /* mark this elem as available  */
855     }
856 }
857 
858 /************************************
859  * Elem e is to be evaluated for a boolean result.
860  * See if we already know its value.
861  */
862 
863 private void abeboolres(elem *n,vec_t ae,vec_t aeval)
864 {
865     //printf("abeboolres()[%d %p] ", n.Eexp, go.expnod[n.Eexp]); WReqn(n); printf("\n");
866     elem_debug(n);
867     if (n.Eexp && go.expnod[n.Eexp])
868     {   /* Try to find an equivalent AE, and point to it instead */
869         assert(go.expnod[n.Eexp] == n);
870         uint i;
871         for (i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) // for each ae elem
872         {   elem *e = go.expnod[i];
873 
874             // Attempt to replace n with the boolean result of e
875             //printf("Looking at go.expnod[%d] = %p\n",i,e);
876             assert(e);
877             elem_debug(e);
878             if (n != e && el_match(n,e))
879             {
880                 debug if (debugc)
881                 {   printf("Elem %p: ",n);
882                     WReqn(n);
883                     printf(" is replaced by %d\n",vec_testbit(i,aeval) != 0);
884                 }
885 
886                 abefree(n,ae);
887                 n.EV.Vlong = vec_testbit(i,aeval) != 0;
888                 n.Eoper = OPconst;
889                 n.Ety = TYint;
890                 go.changes++;
891                 break;
892             }
893         }
894     }
895 }
896 
897 /****************************
898  * Remove e from available expressions, and its children.
899  */
900 
901 private void abefree(elem *e,vec_t ae)
902 {
903     //printf("abefree [%d %p]: ", e.Eexp, e); WReqn(e); printf("\n");
904     assert(e.Eexp);
905     vec_clearbit(e.Eexp,ae);
906     go.expnod[e.Eexp] = null;
907     if (!OTleaf(e.Eoper))
908     {
909         if (OTbinary(e.Eoper))
910         {
911             abefree(e.EV.E2,ae);
912             el_free(e.EV.E2);
913             e.EV.E2 = null;
914         }
915         abefree(e.EV.E1,ae);
916         el_free(e.EV.E1);
917         e.EV.E1 = null;
918     }
919 }
920 
921 /************************************
922  * Elem e is to be evaluated for a boolean result.
923  * Set its result according to flag.
924  */
925 
926 private void abeset(elem *e,vec_t ae,vec_t aeval,int flag)
927 {
928     while (1)
929     {
930         uint i = e.Eexp;
931         if (i && go.expnod[i])
932         {
933             //printf("abeset for go.expnod[%d] = %p: ",i,e); WReqn(e); printf("\n");
934             vec_setbit(i,ae);
935             if (flag)
936                 vec_setbit(i,aeval);
937             else
938                 vec_clearbit(i,aeval);
939         }
940         switch (e.Eoper)
941         {   case OPnot:
942                 flag ^= 1;
943                 e = e.EV.E1;
944                 continue;
945 
946             case OPbool:
947             case OPeq:
948                 e = e.EV.E1;
949                 continue;
950 
951             default:
952                 break;
953         }
954         break;
955     }
956 }
957 
958 }