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