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