1 /**
2  * Local optimizations of elem trees
3  *
4  * Compiler implementation of the
5  * $(LINK2 https://www.dlang.org, D programming language).
6  *
7  * Does strength reduction optimizations on the elem trees,
8  * i.e. rewriting trees to less expensive trees.
9  *
10  * Copyright:   Copyright (C) 1985-1998 by Symantec
11  *              Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved
12  * Authors:     $(LINK2 https://www.digitalmars.com, Walter Bright)
13  * License:     $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
14  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cgelem.d, backend/cgelem.d)
15  * Documentation:  https://dlang.org/phobos/dmd_backend_cgelem.html
16  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/cgelem.d
17  *              Add coverage tests to https://github.com/dlang/dmd/blob/master/test/runnable/testcgelem.d
18  */
19 
20 module dmd.backend.cgelem;
21 
22 import core.stdc.stdio;
23 import core.stdc.stdlib;
24 import core.stdc.string;
25 
26 import dmd.backend.cc;
27 import dmd.backend.code;
28 import dmd.backend.cdef;
29 import dmd.backend.code_x86;
30 import dmd.backend.oper;
31 import dmd.backend.global;
32 import dmd.backend.goh;
33 import dmd.backend.el;
34 import dmd.backend.rtlsym;
35 import dmd.backend.symtab;
36 import dmd.backend.ty;
37 import dmd.backend.type;
38 
39 import dmd.backend.dlist;
40 import dmd.backend.dvec;
41 
42 version (SCPP)
43     import tk.mem;
44 else
45 {
46     extern (C)
47     {
48         nothrow void *mem_calloc(size_t);
49     }
50 }
51 
52 extern (C++):
53 
54 nothrow:
55 @safe:
56 
57 elem * evalu8(elem *e, goal_t goal);
58 
59 
60 /* Masks so we can easily check size */
61 enum CHARMASK  = 0xFF;
62 enum SHORTMASK = 0xFFFF;
63 enum INTMASK   = SHORTMASK;
64 enum LONGMASK  = 0xFFFFFFFF;
65 
66 /* Common constants often checked for */
67 enum LLONGMASK = 0xFFFFFFFFFFFFFFFFL;
68 enum ZEROLL    = 0L;
69 
70 private __gshared
71 {
72     bool again;
73     bool topair;
74     tym_t global_tyf;
75 }
76 
77 private bool cnst(const elem* e) { return e.Eoper == OPconst; }
78 int REGSIZE();
79 
80 version (MARS)
81 {
82     import dmd.backend.errors;
83 }
84 
85 /*****************************
86  */
87 
88 @trusted
89 private elem * cgel_lvalue(elem *e)
90 {
91     //printf("cgel_lvalue()\n"); elem_print(e);
92     elem *e1 = e.EV.E1;
93     if (e1.Eoper == OPbit)
94     {
95         elem *e11 = e1.EV.E1;
96 
97         if (e11.Eoper == OPcomma)
98         {
99             // Replace (((e,v) bit x) op e2) with (e,((v bit x) op e2))
100             e1.EV.E1 = e11.EV.E2;
101             e11.EV.E2 = e;
102             e11.Ety = e.Ety;
103             e11.ET = e.ET;
104             e = e11;
105             goto L1;
106         }
107         else if (OTassign(e11.Eoper))
108         {
109             // Replace (((e op= v) bit x) op e2) with ((e op= v) , ((e bit x) op e2))
110             e1.EV.E1 = el_copytree(e11.EV.E1);
111             e = el_bin(OPcomma,e.Ety,e11,e);
112             goto L1;
113         }
114     }
115     else if (e1.Eoper == OPcomma)
116     {
117         // Replace ((e,v) op e2) with (e,(v op e2))
118         const op = e.Eoper;
119         e.Eoper = OPcomma;
120         e1.Eoper = op;
121         e1.Ety = e.Ety;
122         e1.ET = e.ET;
123         e.EV.E1 = e1.EV.E1;
124         e1.EV.E1 = e1.EV.E2;
125         e1.EV.E2 = e.EV.E2;
126         e.EV.E2 = e1;
127         goto L1;
128     }
129     else if (OTassign(e1.Eoper))
130     {
131         // Replace ((e op= v) op e2) with ((e op= v) , (e op e2))
132         e.EV.E1 = el_copytree(e1.EV.E1);
133         e = el_bin(OPcomma,e.Ety,e1,e);
134     L1:
135         e = optelem(e,GOALvalue);
136     }
137     return e;
138 }
139 
140 
141 /******************************
142  * Scan down commas.
143  */
144 
145 @trusted
146 private elem * elscancommas(elem *e)
147 {
148     while (e.Eoper == OPcomma
149            || e.Eoper == OPinfo
150           )
151         e = e.EV.E2;
152     return e;
153 }
154 
155 /*************************
156  * Returns:
157  *    true if elem is the constant 1.
158  */
159 
160 int elemisone(elem *e)
161 {
162     if (e.Eoper == OPconst)
163     {
164         switch (tybasic(e.Ety))
165         {
166             case TYchar:
167             case TYuchar:
168             case TYschar:
169             case TYchar16:
170             case TYshort:
171             case TYushort:
172             case TYint:
173             case TYuint:
174             case TYlong:
175             case TYulong:
176             case TYllong:
177             case TYullong:
178             case TYnullptr:
179             case TYsptr:
180             case TYcptr:
181             case TYhptr:
182             case TYfptr:
183             case TYvptr:
184             case TYnptr:
185             case TYimmutPtr:
186             case TYsharePtr:
187             case TYrestrictPtr:
188             case TYfgPtr:
189             case TYbool:
190             case TYwchar_t:
191             case TYdchar:
192                 if (el_tolong(e) != 1)
193                     goto nomatch;
194                 break;
195             case TYldouble:
196             case TYildouble:
197                 if (e.EV.Vldouble != 1)
198                     goto nomatch;
199                 break;
200             case TYdouble:
201             case TYidouble:
202             case TYdouble_alias:
203                 if (e.EV.Vdouble != 1)
204                         goto nomatch;
205                 break;
206             case TYfloat:
207             case TYifloat:
208                 if (e.EV.Vfloat != 1)
209                         goto nomatch;
210                 break;
211             default:
212                 goto nomatch;
213         }
214         return true;
215     }
216 
217 nomatch:
218     return false;
219 }
220 
221 /*************************
222  * Returns: true if elem is the constant -1.
223  */
224 
225 int elemisnegone(elem *e)
226 {
227     if (e.Eoper == OPconst)
228     {
229         switch (tybasic(e.Ety))
230         {
231             case TYchar:
232             case TYuchar:
233             case TYschar:
234             case TYchar16:
235             case TYshort:
236             case TYushort:
237             case TYint:
238             case TYuint:
239             case TYlong:
240             case TYulong:
241             case TYllong:
242             case TYullong:
243             case TYnullptr:
244             case TYnptr:
245             case TYsptr:
246             case TYcptr:
247             case TYhptr:
248             case TYfptr:
249             case TYvptr:
250             case TYimmutPtr:
251             case TYsharePtr:
252             case TYrestrictPtr:
253             case TYfgPtr:
254             case TYbool:
255             case TYwchar_t:
256             case TYdchar:
257                 if (el_tolong(e) != -1)
258                     goto nomatch;
259                 break;
260             case TYldouble:
261             //case TYildouble:
262                 if (e.EV.Vldouble != -1)
263                     goto nomatch;
264                 break;
265             case TYdouble:
266             //case TYidouble:
267             case TYdouble_alias:
268                 if (e.EV.Vdouble != -1)
269                         goto nomatch;
270                 break;
271             case TYfloat:
272             //case TYifloat:
273                 if (e.EV.Vfloat != -1)
274                         goto nomatch;
275                 break;
276             default:
277                 goto nomatch;
278         }
279         return true;
280     }
281 
282 nomatch:
283     return false;
284 }
285 
286 /**********************************
287  * Swap relational operators (like if we swapped the leaves).
288  */
289 
290 OPER swaprel(OPER op)
291 {
292     assert(op < OPMAX);
293     if (OTrel(op))
294         op = rel_swap(op);
295     return op;
296 }
297 
298 /**************************
299  * Replace e1 by t=e1, replace e2 by t.
300  */
301 
302 private void fixside(elem **pe1,elem **pe2)
303 {
304     const tym = (*pe1).Ety;
305     elem *tmp = el_alloctmp(tym);
306     *pe1 = el_bin(OPeq,tym,tmp,*pe1);
307     elem *e2 = el_copytree(tmp);
308     el_free(*pe2);
309     *pe2 = e2;
310 }
311 
312 
313 
314 /****************************
315  * Compute the 'cost' of evaluating a elem. Could be done
316  * as Sethi-Ullman numbers, but that ain't worth the bother.
317  * We'll fake it.
318  */
319 
320 private int cost(const elem* n) { return opcost[n.Eoper]; }
321 
322 /*******************************
323  * For floating point expressions, the cost would be the number
324  * of registers in the FPU stack needed.
325  */
326 
327 @trusted
328 private int fcost(const elem *e)
329 {
330     int cost;
331 
332     //printf("fcost()\n");
333     switch (e.Eoper)
334     {
335         case OPadd:
336         case OPmin:
337         case OPmul:
338         case OPdiv:
339         {
340             const int cost1 = fcost(e.EV.E1);
341             const int cost2 = fcost(e.EV.E2);
342             cost = cost2 + 1;
343             if (cost1 > cost)
344                 cost = cost1;
345             break;
346         }
347 
348         case OPcall:
349         case OPucall:
350             cost = 8;
351             break;
352 
353         case OPneg:
354         case OPabs:
355         case OPtoprec:
356             return fcost(e.EV.E1);
357 
358         case OPvar:
359         case OPconst:
360         case OPind:
361         default:
362             return 1;
363     }
364     if (cost > 8)
365         cost = 8;
366     return cost;
367 }
368 
369 /*******************************
370  * The lvalue of an op= is a conversion operator. Since the code
371  * generator cannot handle this, we will have to fix it here. The
372  * general strategy is:
373  *      (conv) e1 op= e2        =>      e1 = (conv) e1 op e2
374  * Since e1 can only be evaluated once, if it is an expression we
375  * must use a temporary.
376  */
377 
378 @trusted
379 private elem *fixconvop(elem *e)
380 {
381     static immutable ubyte[CNVOPMAX - CNVOPMIN + 1] invconvtab =
382     [
383         OPbool,         // OPb_8
384         OPs32_d,        // OPd_s32
385         OPd_s32,        // OPs32_d
386         OPs16_d,        /* OPd_s16      */
387         OPd_s16,        /* OPs16_d      */
388         OPu16_d,        // OPd_u16
389         OPd_u16,        // OPu16_d
390         OPu32_d,        /* OPd_u32      */
391         OPd_u32,        /* OPu32_d      */
392         OPs64_d,        // OPd_s64
393         OPd_s64,        // OPs64_d
394         OPu64_d,        // OPd_u64
395         OPd_u64,        // OPu64_d
396         OPf_d,          // OPd_f
397         OPd_f,          // OPf_d
398         OP32_16,        // OPs16_32
399         OP32_16,        // OPu16_32
400         OPs16_32,       // OP32_16
401         OP16_8,         // OPu8_16
402         OP16_8,         // OPs8_16
403         OPs8_16,        // OP16_8
404         OP64_32,        // OPu32_64
405         OP64_32,        // OPs32_64
406         OPs32_64,       // OP64_32
407         OP128_64,       // OPu64_128
408         OP128_64,       // OPs64_128
409         OPs64_128,      // OP128_64
410 
411         0,              /* OPvp_fp      */
412         0,              /* OPcvp_fp     */
413         OPnp_fp,        /* OPoffset     */
414         OPoffset,       /* OPnp_fp      */
415         OPf16p_np,      /* OPnp_f16p    */
416         OPnp_f16p,      /* OPf16p_np    */
417 
418         OPd_ld,         // OPld_d
419         OPld_d,         // OPd_ld
420         OPu64_d,        // OPld_u64
421     ];
422 
423     //printf("fixconvop before\n");
424     //elem_print(e);
425     assert(invconvtab.length == CNVOPMAX - CNVOPMIN + 1);
426     assert(e);
427     tym_t tyme = e.Ety;
428     const cop = e.EV.E1.Eoper;             /* the conversion operator      */
429     assert(cop <= CNVOPMAX);
430 
431     elem *econv = e.EV.E1;
432     while (OTconv(econv.Eoper))
433     {
434         if (econv.EV.E1.Eoper != OPcomma)
435         {
436             econv = econv.EV.E1;
437             continue;
438         }
439         /* conv(a,b) op= e2     or     conv(conv(a,b)) op= e2
440          *   =>                 many:    =>
441          * a, (conv(b) op= e2)         a, (conv(conv(b)) op= e2)
442          */
443         elem *ecomma = econv.EV.E1;
444         econv.EV.E1 = ecomma.EV.E2;
445         econv.EV.E1.Ety = ecomma.Ety;
446         ecomma.EV.E2 = e;
447         ecomma.Ety = e.Ety;
448         //printf("fixconvop comma\n");
449         //elem_print(ecomma);
450         return optelem(ecomma, GOALvalue);
451     }
452 
453     if (e.EV.E1.Eoper == OPd_f && OTconv(e.EV.E1.EV.E1.Eoper) && tyintegral(tyme))
454     {
455         elem *e1 = e.EV.E1;
456         e.EV.E1 = e1.EV.E1;
457         e.EV.E2 = el_una(OPf_d, e.EV.E1.Ety, e.EV.E2);
458         e1.EV.E1 = null;
459         el_free(e1);
460         return fixconvop(e);
461     }
462 
463     tym_t tycop = e.EV.E1.Ety;
464     tym_t tym = e.EV.E1.EV.E1.Ety;
465     e.EV.E1 = el_selecte1(e.EV.E1);     /* dump it for now              */
466     elem *e1 = e.EV.E1;
467     e1.Ety = tym;
468     elem *e2 = e.EV.E2;
469     assert(e1 && e2);
470     /* select inverse conversion operator   */
471     const icop = invconvtab[convidx(cop)];
472 
473     /* First, let's see if we can just throw it away.       */
474     /* (unslng or shtlng) e op= e2  => e op= (lngsht) e2    */
475     if (OTwid(e.Eoper) &&
476             (cop == OPs16_32 || cop == OPu16_32 ||
477              cop == OPu8_16 || cop == OPs8_16))
478     {   if (e.Eoper != OPshlass && e.Eoper != OPshrass && e.Eoper != OPashrass)
479             e.EV.E2 = el_una(icop,tym,e2);
480 
481         version (MARS)
482         {
483             // https://issues.dlang.org/show_bug.cgi?id=23618
484             if ((cop == OPu16_32 || cop == OPu8_16) && e.Eoper == OPashrass)
485                 e.Eoper = OPshrass;     // always unsigned right shift for MARS
486         }
487 
488         return e;
489     }
490 
491     /* Oh well, just split up the op and the =.                     */
492     const op = opeqtoop(e.Eoper); // convert op= to op
493     e.Eoper = OPeq;                  // just plain =
494     elem *ed = el_copytree(e1);       // duplicate e1
495                                       // make: e1 = (icop) ((cop) ed op e2)
496     e.EV.E2 = el_una(icop,e1.Ety,
497                              el_bin(op,tycop,el_una(cop,tycop,ed),
498                                                   e2));
499 
500     //printf("after1\n");
501     //elem_print(e);
502 
503     if (op == OPdiv &&
504         tybasic(e2.Ety) == TYcdouble)
505     {
506         if (tycop == TYdouble)
507         {
508             e.EV.E2.EV.E1.Ety = tybasic(e2.Ety);
509             e.EV.E2.EV.E1 = el_una(OPc_r, tycop, e.EV.E2.EV.E1);
510         }
511         else if (tycop == TYidouble)
512         {
513             e.EV.E2.EV.E1.Ety = tybasic(e2.Ety);
514             e.EV.E2.EV.E1 = el_una(OPc_i, tycop, e.EV.E2.EV.E1);
515         }
516     }
517 
518     if (op == OPdiv &&
519         tybasic(e2.Ety) == TYcfloat)
520     {
521         if (tycop == TYfloat)
522         {
523             e.EV.E2.EV.E1.Ety = tybasic(e2.Ety);
524             e.EV.E2.EV.E1 = el_una(OPc_r, tycop, e.EV.E2.EV.E1);
525         }
526         else if (tycop == TYifloat)
527         {
528             e.EV.E2.EV.E1.Ety = tybasic(e2.Ety);
529             e.EV.E2.EV.E1 = el_una(OPc_i, tycop, e.EV.E2.EV.E1);
530         }
531     }
532 
533     // Handle case of multiple conversion operators on lvalue
534     // (such as (intdbl 8int char += double))
535     elem *ex = e;
536     elem **pe = &e;
537     while (OTconv(ed.Eoper))
538     {
539         const uint copx = ed.Eoper;
540         const uint icopx = invconvtab[convidx(copx)];
541         tym_t tymx = ex.EV.E1.EV.E1.Ety;
542         ex.EV.E1 = el_selecte1(ex.EV.E1);       // dump it for now
543         e1 = ex.EV.E1;
544         e1.Ety = tymx;
545         ex.EV.E2 = el_una(icopx,e1.Ety,ex.EV.E2);
546         ex.Ety = tymx;
547         tym = tymx;
548 
549         if (ex.Ety != tyme)
550         {   *pe = el_una(copx, ed.Ety, ex);
551             pe = &(*pe).EV.E1;
552         }
553 
554         ed = ed.EV.E1;
555     }
556     //printf("after2\n");
557     //elem_print(e);
558 
559     e.Ety = tym;
560     if (tym != tyme &&
561         !(tyintegral(tym) && tyintegral(tyme) && tysize(tym) == tysize(tyme)))
562         e = el_una(cop, tyme, e);
563 
564     if (ed.Eoper == OPbit)         // special handling
565     {
566         ed = ed.EV.E1;
567         e1 = e1.EV.E1;            // go down one
568     }
569 
570     /* If we have a *, must assign a temporary to the expression
571      * underneath it (even if it's a var, as e2 may modify the var)
572      */
573     if (ed.Eoper == OPind)
574     {
575         elem *T = el_alloctmp(ed.EV.E1.Ety);    // make temporary
576         ed.EV.E1 = el_bin(OPeq,T.Ety,T,ed.EV.E1); // ed: *(T=e)
577         el_free(e1.EV.E1);
578         e1.EV.E1 = el_copytree(T);
579     }
580     //printf("after3\n");
581     //elem_print(e);
582     return e;
583 }
584 
585 private elem * elerr(elem *e, goal_t goal)
586 {
587     debug elem_print(e);
588     assert(0);
589 }
590 
591 /* For ops with no optimizations */
592 
593 private elem * elzot(elem *e, goal_t goal)
594 {
595     return e;
596 }
597 
598 /****************************
599  */
600 
601 private elem * elstring(elem *e, goal_t goal)
602 {
603     return e;
604 }
605 
606 /************************
607  */
608 
609 /************************
610  * Convert far pointer to pointer.
611  */
612 
613 @trusted
614 private void eltonear(elem **pe)
615 {
616     elem *e = *pe;
617     const tym_t ty = e.EV.E1.Ety;
618     e = el_selecte1(e);
619     e.Ety = ty;
620     *pe = optelem(e,GOALvalue);
621 }
622 
623 /************************
624  */
625 
626 @trusted
627 private elem * elstrcpy(elem *e, goal_t goal)
628 {
629     elem_debug(e);
630     switch (e.EV.E2.Eoper)
631     {
632         case OPnp_fp:
633             if (OPTIMIZER)
634             {
635                 eltonear(&e.EV.E2);
636                 e = optelem(e,GOALvalue);
637             }
638             break;
639 
640         case OPstring:
641             /* Replace strcpy(e1,"string") with memcpy(e1,"string",sizeof("string")) */
642             // As streq
643             e.Eoper = OPstreq;
644             type *t = type_allocn(TYarray, tstypes[TYchar]);
645             t.Tdim = strlen(e.EV.E2.EV.Vstring) + 1;
646             e.ET = t;
647             t.Tcount++;
648             e.EV.E1 = el_una(OPind,TYstruct,e.EV.E1);
649             e.EV.E2 = el_una(OPind,TYstruct,e.EV.E2);
650 
651             e = el_bin(OPcomma,e.Ety,e,el_copytree(e.EV.E1.EV.E1));
652             if (el_sideeffect(e.EV.E2))
653                 fixside(&e.EV.E1.EV.E1.EV.E1,&e.EV.E2);
654             e = optelem(e,GOALvalue);
655             break;
656 
657         default:
658             break;
659     }
660     return e;
661 }
662 
663 /************************
664  */
665 
666 @trusted
667 private elem * elstrcmp(elem *e, goal_t goal)
668 {
669     elem_debug(e);
670     if (OPTIMIZER)
671     {
672         if (e.EV.E1.Eoper == OPnp_fp)
673             eltonear(&e.EV.E1);
674         switch (e.EV.E2.Eoper)
675         {
676             case OPnp_fp:
677                 eltonear(&e.EV.E2);
678                 break;
679 
680             case OPstring:
681                 // Replace strcmp(e1,"string") with memcmp(e1,"string",sizeof("string"))
682                 e.Eoper = OPparam;
683                 e = el_bin(OPmemcmp,e.Ety,e,el_long(TYint,strlen(e.EV.E2.EV.Vstring) + 1));
684                 e = optelem(e,GOALvalue);
685                 break;
686 
687             default:
688                 break;
689         }
690     }
691     return e;
692 }
693 
694 /****************************
695  * For OPmemcmp
696  * memcmp(a, b, nbytes) => ((a param b) OPmemcmp nbytes)
697  */
698 @trusted
699 
700 private elem * elmemcmp(elem *e, goal_t goal)
701 {
702     elem_debug(e);
703     if (!OPTIMIZER)
704         return e;
705 
706     /* Hoist comma operators in `a` out of OPmemcmp
707      */
708     {
709         elem* ec = e.EV.E1.EV.E1;
710         if (ec.Eoper == OPcomma)
711         {
712             /* Rewrite: (((a,b) param c) OPmemcmp nbytes)
713              * As: a,((b param c) OPmemcmp nbytes)
714              */
715             e.EV.E1.EV.E1 = ec.EV.E2;
716             e.EV.E1.EV.E1.Ety = ec.Ety;
717             e.EV.E1.EV.E1.ET = ec.ET;
718             ec.EV.E2 = e;
719             ec.Ety = e.Ety;
720             return optelem(ec, goal);
721         }
722     }
723 
724     /* Hoist comma operators in `b` out of OPmemcmp
725      */
726     {
727         elem* ec = e.EV.E1.EV.E2;
728         if (ec.Eoper == OPcomma)
729         {
730             /* Have: ((a param (b,c)) OPmemcmp nbytes)
731              */
732             elem* a = e.EV.E1.EV.E1;
733             elem* b = ec.EV.E1;
734             if (a.canHappenAfter(b))
735             {
736                 /* Rewrite: ((a param (b,c)) OPmemcmp nbytes)
737                  * As: b,((a param c) OPmemcmp nbytes)
738                  */
739                 e.EV.E1.EV.E2 = ec.EV.E2;
740                 e.EV.E1.EV.E2.Ety = ec.Ety;
741                 e.EV.E1.EV.E2.ET = ec.ET;
742                 ec.EV.E2 = e;
743                 ec.Ety = e.Ety;
744                 return optelem(ec, goal);
745             }
746         }
747     }
748 
749     elem *ex = e.EV.E1;
750     if (ex.EV.E1.Eoper == OPnp_fp)
751         eltonear(&ex.EV.E1);
752     if (ex.EV.E2.Eoper == OPnp_fp)
753         eltonear(&ex.EV.E2);
754 
755     return e;
756 }
757 
758 /****************************
759  * For OPmemset
760  */
761 
762 @trusted
763 private elem * elmemset(elem *e, goal_t goal)
764 {
765     //printf("elmemset()\n");
766     elem_debug(e);
767 
768     elem *ex = e.EV.E1;
769     if (ex.Eoper == OPnp_fp)
770     {
771         eltonear(&ex);
772         return e;
773     }
774 
775     // lvalue OPmemset (nelems param value)
776     elem *enelems = e.EV.E2.EV.E1;
777     elem *evalue = e.EV.E2.EV.E2;
778 
779     if (!(enelems.Eoper == OPconst && evalue.Eoper == OPconst && REGSIZE >= 4))
780         return e;
781 
782     elem *e1 = e.EV.E1;
783 
784     if (e1.Eoper == OPcomma || OTassign(e1.Eoper))
785         return cgel_lvalue(e);    // replace ((e,v) memset e2) with (e,(v memset e2))
786 
787     /* Attempt to replace OPmemset with a sequence of ordinary assignments,
788      * so cdmemset() will have fewer cases to deal with
789      */
790 
791     const sz = tysize(evalue.Ety);
792     int nelems = cast(int)el_tolong(enelems);
793     ulong value = el_tolong(evalue);
794 
795     if (sz * nelems > REGSIZE * 4)
796         return e;
797 
798     switch (sz)
799     {
800         case 1:  value = 0x0101_0101_0101_0101 * (value & 0xFF);       break;
801         case 2:  value = 0x0001_0001_0001_0001 * (value & 0xFFFF);     break;
802         case 4:  value = 0x0000_0001_0000_0001 * (value & 0xFFFFFFFF); break;
803         case 8:  break;
804         default:
805             return e;
806     }
807 
808     ulong valuexor = 0;
809     if (sz == 8 && REGSIZE == 4)
810         valuexor = (value ^ (value >> 32)) & 0xFFFF_FFFF;
811 
812     elem* ey = null;
813     if (e1.Eoper != OPrelconst)
814     {
815         ey = e1;
816         e1 = el_same(&ey);
817     }
818     e.EV.E1 = null;             // so we can free e later
819 
820     for (int offset = 0; offset < sz * nelems; )
821     {
822         int left = sz * nelems - offset;
823         if (left > REGSIZE)
824             left = REGSIZE;
825         tym_t tyv;
826         switch (left)
827         {
828             case 0: assert(0);
829             case 1: tyv = TYchar;  left = 1; break;
830             case 2:
831             case 3: tyv = TYshort; left = 2; break;
832             case 4:
833             case 5:
834             case 6:
835             case 7: tyv = TYlong;  left = 4; break;
836             default:
837             case 8: tyv = TYllong; left = 8; break;
838         }
839         auto e1a = el_copytree(e1);
840         assert(tybasic(e1a.Ety) != TYstruct);
841         e1a = el_bin(OPadd, TYnptr, e1a, el_long(TYsize_t, offset));
842         e1a = el_una(OPind, tyv, e1a);
843         auto ea = el_bin(OPeq, tyv, e1a, el_long(tyv, value));
844         if (sz * nelems - offset >= REGSIZE)
845             value ^= valuexor;          // flip between low and high 32 bits of 8 byte value
846         offset += left;
847         ey = el_combine(ey, ea);
848     }
849     ey = el_combine(ey, e1);
850     el_free(e);
851     e = optelem(ey,GOALvalue);
852     return e;
853 }
854 
855 
856 /****************************
857  * For OPmemcpy
858  *  OPmemcpy
859  *   /   \
860  * s1   OPparam
861  *       /   \
862  *      s2    n
863  */
864 
865 @trusted
866 private elem * elmemcpy(elem *e, goal_t goal)
867 {
868     elem_debug(e);
869     if (OPTIMIZER)
870     {
871         elem *ex = e.EV.E1;
872         if (ex.Eoper == OPnp_fp)
873             eltonear(&e.EV.E1);
874         ex = e.EV.E2;
875         if (ex.EV.E1.Eoper == OPnp_fp)
876             eltonear(&ex.EV.E1);
877         if (ex.EV.E2.Eoper == OPconst)
878         {
879             if (!boolres(ex.EV.E2))
880             {   // Copying 0 bytes, so remove memcpy
881                 e.EV.E2 = e.EV.E1;
882                 e.EV.E1 = ex.EV.E1;
883                 ex.EV.E1 = null;
884                 e.Eoper = OPcomma;
885                 el_free(ex);
886                 return optelem(e, GOALvalue);
887             }
888             // Convert OPmemcpy to OPstreq
889             e.Eoper = OPstreq;
890             type *t = type_allocn(TYarray, tstypes[TYchar]);
891             t.Tdim = cast(uint)el_tolong(ex.EV.E2);
892             e.ET = t;
893             t.Tcount++;
894             e.EV.E1 = el_una(OPind,TYstruct,e.EV.E1);
895             e.EV.E2 = el_una(OPind,TYstruct,ex.EV.E1);
896             ex.EV.E1 = null;
897             el_free(ex);
898             ex = el_copytree(e.EV.E1.EV.E1);
899             if (tysize(e.Ety) > tysize(ex.Ety))
900                 ex = el_una(OPnp_fp,e.Ety,ex);
901             e = el_bin(OPcomma,e.Ety,e,ex);
902             if (el_sideeffect(e.EV.E2))
903                 fixside(&e.EV.E1.EV.E1.EV.E1,&e.EV.E2);
904             return optelem(e,GOALvalue);
905         }
906 
907         /+ The following fails the autotester for Linux32 and FreeBSD32
908          + for unknown reasons I cannot reproduce
909         // Convert to memcpy(s1, s2, n)
910         elem* ep = el_params(e.EV.E2.EV.E2, e.EV.E2.EV.E1, e.EV.E1, null);
911         const ty = e.Ety;
912         e.EV.E1 = null;
913         e.EV.E2.EV.E1 = null;
914         e.EV.E2.EV.E2 = null;
915         el_free(e);
916         e = el_bin(OPcall, ty, el_var(getRtlsym(RTLSYM.MEMCPY)), ep);
917          +/
918     }
919     return e;
920 }
921 
922 
923 /***********************
924  *        +             #       (combine offsets with addresses)
925  *       / \    =>      |
926  *      #   c          v,c
927  *      |
928  *      v
929  */
930 
931 @trusted
932 private elem * eladd(elem *e, goal_t goal)
933 {
934     //printf("eladd(%p)\n",e);
935     targ_size_t ptrmask = ~cast(targ_size_t)0;
936     if (_tysize[TYnptr] <= 4)
937         ptrmask = 0xFFFFFFFF;
938 L1:
939     elem *e1 = e.EV.E1;
940     elem *e2 = e.EV.E2;
941     if (e2.Eoper == OPconst)
942     {
943         if (e1.Eoper == OPrelconst && e1.EV.Vsym.Sfl == FLgot)
944             return e;
945         if (e1.Eoper == OPrelconst ||          // if (&v) + c
946             e1.Eoper == OPstring)
947         {
948             e1.EV.Voffset += e2.EV.Vpointer;
949             e1.EV.Voffset &= ptrmask;
950             e = el_selecte1(e);
951             return e;
952         }
953     }
954     else if (e1.Eoper == OPconst)
955     {
956         if (e2.Eoper == OPrelconst && e2.EV.Vsym.Sfl == FLgot)
957             return e;
958         if (e2.Eoper == OPrelconst ||          // if c + (&v)
959             e2.Eoper == OPstring)
960         {
961             e2.EV.Voffset += e1.EV.Vpointer;
962             e2.EV.Voffset &= ptrmask;
963             e = el_selecte2(e);
964             return e;
965         }
966     }
967 
968     if (!OPTIMIZER)
969         return e;
970 
971     // Replace ((e + &v) + c) with (e + (&v+c))
972     if (e2.Eoper == OPconst && e1.Eoper == OPadd &&
973        (e1.EV.E2.Eoper == OPrelconst || e1.EV.E2.Eoper == OPstring))
974     {
975         e1.EV.E2.EV.Voffset += e2.EV.Vpointer;
976         e1.EV.E2.EV.Voffset &= ptrmask;
977         e = el_selecte1(e);
978         goto L1;
979     }
980     // Replace ((e + c) + &v) with (e + (&v+c))
981     else if ((e2.Eoper == OPrelconst || e2.Eoper == OPstring) &&
982              e1.Eoper == OPadd && cnst(e1.EV.E2))
983     {
984         e2.EV.Voffset += e1.EV.E2.EV.Vpointer;
985         e2.EV.Voffset &= ptrmask;
986         e.EV.E1 = el_selecte1(e1);
987         goto L1;                        /* try and find some more       */
988     }
989     // Replace (e1 + -e) with (e1 - e)
990     else if (e2.Eoper == OPneg)
991     {
992         e.EV.E2 = el_selecte1(e2);
993         e.Eoper = OPmin;
994         again = 1;
995         return e;
996     }
997     // Replace (-v + e) with (e + -v)
998     else if (e1.Eoper == OPneg && OTleaf(e1.EV.E1.Eoper))
999     {
1000         e.EV.E1 = e2;
1001         e.EV.E2 = e1;                     /* swap leaves                  */
1002         goto L1;
1003     }
1004     /* Replace ((e - e2) + e2) with (e)
1005      * The optimizer sometimes generates this case
1006      */
1007     else if (!tyfloating(e.Ety) &&       /* no floating bugs             */
1008         e1.Eoper == OPmin &&
1009         el_match(e1.EV.E2,e2) &&
1010         !el_sideeffect(e2))
1011     {
1012         tym_t tym = e.Ety;
1013         e = el_selecte1(el_selecte1(e));
1014         e.Ety = tym;                   /* retain original type         */
1015         return e;
1016     }
1017     // Replace ((e - #v+c1) + #v+c2) with ((e - c1) + c2)
1018     else if (e2.Eoper == OPrelconst &&
1019            e1.Eoper == OPmin &&
1020            e1.EV.E2.Eoper == OPrelconst &&
1021            e1.EV.E2.EV.Vsym == e2.EV.Vsym)
1022     {
1023         e2.Eoper = OPconst;
1024         e2.Ety = TYint;
1025         e1.Ety = e1.EV.E1.Ety;
1026         e1.EV.E2.Eoper = OPconst;
1027         e1.EV.E2.Ety = TYint;
1028         {
1029             /* Watch out for pointer types changing, requiring a conversion */
1030             tym_t ety = tybasic(e.Ety);
1031             tym_t e11ty = tybasic(e1.EV.E1.Ety);
1032             if (typtr(ety) && typtr(e11ty) &&
1033                 _tysize[ety] != _tysize[e11ty])
1034             {
1035                 e = el_una((_tysize[ety] > _tysize[e11ty]) ? OPnp_fp : OPoffset,
1036                             e.Ety,e);
1037                 e.EV.E1.Ety = e1.Ety;
1038             }
1039         }
1040         again = 1;
1041         return e;
1042     }
1043     // Replace (e + e) with (e * 2)
1044     else if (el_match(e1,e2) && !el_sideeffect(e1) && !tyfloating(e1.Ety) &&
1045         !tyvector(e1.Ety))      // not all CPUs support XMM multiply
1046     {
1047         e.Eoper = OPmul;
1048         el_free(e2);
1049         e.EV.E2 = el_long(e1.Ety,2);
1050         again = 1;
1051         return e;
1052     }
1053 
1054     // Replace ((e11 + c) + e2) with ((e11 + e2) + c)
1055     if (e1.Eoper == OPadd && e1.EV.E2.Eoper == OPconst &&
1056         (e2.Eoper == OPvar || !OTleaf(e2.Eoper)) &&
1057         tysize(e1.Ety) == tysize(e2.Ety) &&
1058         tysize(e1.EV.E2.Ety) == tysize(e2.Ety))
1059     {
1060         e.EV.E2 = e1.EV.E2;
1061         e1.EV.E2 = e2;
1062         e1.Ety = e.Ety;
1063         return e;
1064     }
1065 
1066     // Replace (~e1 + 1) with (-e1)
1067     if (e1.Eoper == OPcom && e2.Eoper == OPconst && el_tolong(e2) == 1)
1068     {
1069         e = el_selecte1(e);
1070         e.Eoper = OPneg;
1071         e = optelem(e, goal);
1072         return e;
1073     }
1074 
1075     // Replace ((e11 - e12) + e2) with ((e11 + e2) - e12)
1076     // (this should increase the number of LEA possibilities)
1077     int sz = tysize(e.Ety);
1078     if (e1.Eoper == OPmin &&
1079         tysize(e1.Ety) == sz &&
1080         tysize(e2.Ety) == sz &&
1081         tysize(e1.EV.E1.Ety) == sz &&
1082         tysize(e1.EV.E2.Ety) == sz &&
1083         !tyfloating(e.Ety)
1084        )
1085     {
1086         e.Eoper = OPmin;
1087         e.EV.E2 = e1.EV.E2;
1088         e1.EV.E2 = e2;
1089         e1.Eoper = OPadd;
1090     }
1091 
1092     return e;
1093 }
1094 
1095 
1096 /************************
1097  * Multiply (for OPmul && OPmulass)
1098  *      e * (c**2) => e << c    ;replace multiply by power of 2 with shift
1099  */
1100 
1101 @trusted
1102 private elem * elmul(elem *e, goal_t goal)
1103 {
1104     tym_t tym = e.Ety;
1105 
1106     if (OPTIMIZER)
1107     {
1108         // Replace -a*-b with a*b.
1109         // This is valid for all floating point types as well as integers.
1110         if (tyarithmetic(tym) && e.EV.E2.Eoper == OPneg && e.EV.E1.Eoper == OPneg)
1111         {
1112             e.EV.E1 = el_selecte1(e.EV.E1);
1113             e.EV.E2 = el_selecte1(e.EV.E2);
1114         }
1115     }
1116 
1117     elem *e2 = e.EV.E2;
1118     if (e2.Eoper == OPconst)           // try to replace multiplies with shifts
1119     {
1120         if (OPTIMIZER)
1121         {
1122             elem *e1 = e.EV.E1;
1123             uint op1 = e1.Eoper;
1124 
1125             if (tyintegral(tym) &&              // skip floating types
1126                 OTbinary(op1) &&
1127                 e1.EV.E2.Eoper == OPconst
1128                )
1129             {
1130                 /* Attempt to replace ((e + c1) * c2) with (e * c2 + (c1 * c2))
1131                  * because the + can be frequently folded out (merged into an
1132                  * array offset, for example.
1133                  */
1134                 if (op1 == OPadd)
1135                 {
1136                     e.Eoper = OPadd;
1137                     e1.Eoper = OPmul;
1138                     e.EV.E2 = el_bin(OPmul,tym,e1.EV.E2,e2);
1139                     e1.EV.E2 = el_copytree(e2);
1140                     again = 1;
1141                     return e;
1142                 }
1143 
1144                 // ((e << c1) * c2) => e * ((1 << c1) * c2)
1145                 if (op1 == OPshl)
1146                 {
1147                     e2.EV.Vullong *= cast(targ_ullong)1 << el_tolong(e1.EV.E2);
1148                     e1.EV.E2.EV.Vullong = 0;
1149                     again = 1;
1150                     return e;
1151                 }
1152             }
1153 
1154             if (elemisnegone(e2))
1155             {
1156                 e.Eoper = (e.Eoper == OPmul) ? OPneg : OPnegass;
1157                 e.EV.E2 = null;
1158                 el_free(e2);
1159                 return e;
1160             }
1161         }
1162 
1163         if (tyintegral(tym) && !tyvector(tym))
1164         {
1165             int i = ispow2(el_tolong(e2));      // check for power of 2
1166             if (i != -1)                        // if it is a power of 2
1167             {   e2.EV.Vint = i;
1168                 e2.Ety = TYint;
1169                 e.Eoper = (e.Eoper == OPmul)  /* convert to shift left */
1170                         ? OPshl : OPshlass;
1171                 again = 1;
1172                 return e;
1173             }
1174             else if (el_allbits(e2,-1))
1175                 goto Lneg;
1176         }
1177         else if (elemisnegone(e2) && !tycomplex(e.EV.E1.Ety))
1178         {
1179             goto Lneg;
1180         }
1181     }
1182     return e;
1183 
1184 Lneg:
1185     e.Eoper = (e.Eoper == OPmul)      /* convert to negate */
1186             ? OPneg : OPnegass;
1187     el_free(e.EV.E2);
1188     e.EV.E2 = null;
1189     again = 1;
1190     return e;
1191 }
1192 
1193 /************************
1194  * Subtract
1195  *        -               +
1196  *       / \    =>       / \            (propagate minuses)
1197  *      e   c           e   -c
1198  */
1199 
1200 @trusted
1201 private elem * elmin(elem *e, goal_t goal)
1202 {
1203     elem *e2 = e.EV.E2;
1204 
1205     if (OPTIMIZER)
1206     {
1207         tym_t tym = e.Ety;
1208         elem *e1 = e.EV.E1;
1209         if (e2.Eoper == OPrelconst)
1210         {
1211             if (e1.Eoper == OPrelconst && e1.EV.Vsym == e2.EV.Vsym)
1212             {
1213                 e.Eoper = OPconst;
1214                 e.EV.Vllong = e1.EV.Voffset - e2.EV.Voffset;
1215                 el_free(e1);
1216                 el_free(e2);
1217                 return e;
1218             }
1219         }
1220 
1221         // Convert subtraction of long pointers to subtraction of integers
1222         if (tyfv(e2.Ety) && tyfv(e1.Ety))
1223         {
1224             e.EV.E1 = el_una(OP32_16,tym,e1);
1225             e.EV.E2 = el_una(OP32_16,tym,e2);
1226             return optelem(e,GOALvalue);
1227         }
1228 
1229         // Replace (0 - e2) with (-e2)
1230         if (cnst(e1) && !boolres(e1) &&
1231             !(tycomplex(tym) && !tycomplex(e1.Ety) && !tycomplex(e2.Ety)) &&
1232             !tyvector(e1.Ety)
1233            )
1234         {
1235             e.EV.E1 = e2;
1236             e.EV.E2 = null;
1237             e.Eoper = OPneg;
1238             el_free(e1);
1239             return optelem(e,GOALvalue);
1240         }
1241 
1242         // Replace (e - e) with (0)
1243         if (el_match(e1,e2) && !el_sideeffect(e1))
1244         {
1245             el_free(e);
1246             e = el_calloc();
1247             e.Eoper = OPconst;
1248             e.Ety = tym;
1249             return e;
1250         }
1251 
1252         // Replace ((e1 + c) - e2) with ((e1 - e2) + c), but not
1253         // for floating or far or huge pointers!
1254         if (e1.Eoper == OPadd &&
1255             cnst(e1.EV.E2) &&
1256             (tyintegral(tym) ||
1257              tybasic(tym) == TYnptr ||
1258              tybasic(tym) == TYsptr ||
1259              tybasic(tym) == TYfgPtr ||
1260              tybasic(tym) == TYimmutPtr ||
1261              tybasic(tym) == TYrestrictPtr ||
1262              tybasic(tym) == TYsharePtr)
1263            )
1264         {
1265             e.Eoper = OPadd;
1266             e1.Eoper = OPmin;
1267             elem* c = e1.EV.E2;
1268             e1.EV.E2 = e2;
1269             e.EV.E2 = c;
1270             return optelem(e,GOALvalue);
1271         }
1272 
1273         // Replace (e1 + c1) - (e2 + c2) with (e1 - e2) + (c1 - c2), but not
1274         // for floating or far or huge pointers!
1275         if (e1.Eoper == OPadd && e2.Eoper == OPadd &&
1276             cnst(e1.EV.E2) && cnst(e2.EV.E2) &&
1277             (tyintegral(tym) ||
1278              tybasic(tym) == TYnptr ||
1279              tybasic(tym) == TYsptr ||
1280              tybasic(tym) == TYfgPtr ||
1281              tybasic(tym) == TYimmutPtr ||
1282              tybasic(tym) == TYrestrictPtr ||
1283              tybasic(tym) == TYsharePtr)
1284            )
1285         {
1286             e.Eoper = OPadd;
1287             e1.Eoper = OPmin;
1288             e2.Eoper = OPmin;
1289             elem *tmp = e1.EV.E2;
1290             e1.EV.E2 = e2.EV.E1;
1291             e2.EV.E1 = tmp;
1292             return optelem(e,GOALvalue);
1293         }
1294 
1295         // Replace (-e1 - 1) with (~e1)
1296         if (e1.Eoper == OPneg && e2.Eoper == OPconst && tyintegral(tym) && el_tolong(e2) == 1)
1297         {
1298             e = el_selecte1(e);
1299             e.Eoper = OPcom;
1300             e = optelem(e, goal);
1301             return e;
1302         }
1303 
1304         // Replace (-1 - e2) with (~e2)
1305         if (e1.Eoper == OPconst && tyintegral(tym) && !tyvector(tym) && el_tolong(e1) == -1)
1306         {
1307             el_free(e1);
1308             e.EV.E1 = e.EV.E2;
1309             e.EV.E2 = null;
1310             e.Eoper = OPcom;
1311             e = optelem(e, goal);
1312             return e;
1313         }
1314 
1315         /* Replace e1 - (v * c) with e1 + (v * -c)
1316          */
1317         if (e2.Eoper == OPmul &&
1318             e2.EV.E2.Eoper == OPconst)
1319         {
1320             e.Eoper = OPadd;
1321             e2.EV.E2 = el_una(OPneg, e2.EV.E2.Ety, e2.EV.E2);
1322             return optelem(e, goal);
1323         }
1324     }
1325 
1326     if (I16 && tybasic(e2.Ety) == TYhptr && tybasic(e.EV.E1.Ety) == TYhptr)
1327     {   // Convert to _aNahdiff(e1,e2)
1328         __gshared Symbol *hdiff;
1329         if (!hdiff)
1330         {
1331             Symbol *s = symbol_calloc(LARGECODE ? "_aFahdiff" : "_aNahdiff");
1332             s.Stype = tsclib;
1333             s.Sclass = SC.extern_;
1334             s.Sfl = FLfunc;
1335             s.Ssymnum = 0;
1336             s.Sregsaved = mBX|mCX|mSI|mDI|mBP|mES;
1337             hdiff = s;
1338         }
1339         e.Eoper = OPcall;
1340         e.EV.E2 = el_bin(OPparam,TYint,e2,e.EV.E1);
1341         e.EV.E1 = el_var(hdiff);
1342         return e;
1343     }
1344 
1345     /* Disallow the optimization on doubles. The - operator is not
1346      * rearrangable by K+R, and can cause floating point problems if
1347      * converted to an add ((a + 1.0) - 1.0 shouldn't be folded).
1348      */
1349     if (cnst(e2) && !tyfloating(e2.Ety) &&
1350         !tyvector(e2.Ety)) // don't do vectors until we get constant folding for them
1351     {
1352         e.EV.E2 = el_una(OPneg,e2.Ety,e2);
1353         e.Eoper = OPadd;
1354         return optelem(e,GOALvalue);
1355     }
1356     return e;
1357 }
1358 
1359 /*****************************
1360  * OPand,OPor,OPxor
1361  * This should be expanded to include long type stuff.
1362  */
1363 
1364 @trusted
1365 private elem * elbitwise(elem *e, goal_t goal)
1366 {
1367     //printf("elbitwise(e = %p, goal = x%x)\n", e, goal);
1368 
1369     elem *e2 = e.EV.E2;
1370     elem *e1 = e.EV.E1;
1371     const op = e1.Eoper;
1372     uint sz = tysize(e2.Ety);
1373 
1374     if (e2.Eoper == OPconst)
1375     {
1376         switch (sz)
1377         {
1378             case CHARSIZE:
1379                 /* Replace (c & 0xFF) with (c)  */
1380                 if (OPTIMIZER && e2.EV.Vuchar == CHARMASK)
1381                 {
1382                 L1:
1383                     switch (e.Eoper)
1384                     {   case OPand:     /* (c & 0xFF) => (c)    */
1385                             return el_selecte1(e);
1386                         case OPor:      /* (c | 0xFF) => (0xFF) */
1387                             return el_selecte2(e);
1388                         case OPxor:     /* (c ^ 0xFF) => (~c)   */
1389                             return el_una(OPcom,e.Ety,el_selecte1(e));
1390                         default:
1391                             assert(0);
1392                     }
1393                 }
1394                 break;
1395 
1396             case LONGSIZE:
1397             {
1398                 if (!OPTIMIZER)
1399                     break;
1400                 targ_ulong ul = e2.EV.Vulong;
1401 
1402                 if (ul == 0xFFFFFFFF)           /* if e1 & 0xFFFFFFFF   */
1403                     goto L1;
1404                 /* (x >> 16) & 0xFFFF => (cast(uint)x >> 16)       */
1405                 if (ul == 0xFFFF && e.Eoper == OPand && (op == OPshr || op == OPashr) &&
1406                     e1.EV.E2.Eoper == OPconst && el_tolong(e1.EV.E2) == 16)
1407                 {
1408                     elem *e11 = e1.EV.E1;
1409                     e11.Ety = touns(e11.Ety) | (e11.Ety & ~mTYbasic);
1410                     goto L1;
1411                 }
1412 
1413                 /* Replace (L & 0x0000XXXX) with (unslng)((lngsht) & 0xXXXX) */
1414                 if (_tysize[TYint] < LONGSIZE &&
1415                     e.Eoper == OPand &&
1416                     ul <= SHORTMASK)
1417                 {
1418                     tym_t tym = e.Ety;
1419                     e.EV.E1 = el_una(OP32_16,TYushort,e.EV.E1);
1420                     e.EV.E2 = el_una(OP32_16,TYushort,e.EV.E2);
1421                     e.Ety = TYushort;
1422                     e = el_una(OPu16_32,tym,e);
1423                     goto Lopt;
1424                 }
1425 
1426                 // Replace ((s8sht)L & 0xFF) with (u8sht)L
1427                 if (ul == 0xFF && _tysize[TYint] == LONGSIZE && e.Eoper == OPand &&
1428                     (op == OPs8_16 || op == OPu8_16)
1429                    )
1430                 {
1431                     e1.Eoper = OPu8_16;
1432                     e = el_selecte1(e);
1433                     goto Lopt;
1434                 }
1435                 break;
1436             }
1437 
1438             case SHORTSIZE:
1439             {
1440                 targ_short i = e2.EV.Vshort;
1441                 if (i == cast(targ_short)SHORTMASK) // e2 & 0xFFFF
1442                     goto L1;
1443 
1444                 /* (x >> 8) & 0xFF => ((uint short)x >> 8)          */
1445                 if (OPTIMIZER && i == 0xFF && e.Eoper == OPand &&
1446                     (op == OPshr || op == OPashr) && e1.EV.E2.Eoper == OPconst && e1.EV.E2.EV.Vint == 8)
1447                 {
1448                     elem *e11 = e1.EV.E1;
1449                     e11.Ety = touns(e11.Ety) | (e11.Ety & ~mTYbasic);
1450                     goto L1;
1451                 }
1452 
1453                 // (s8_16(e) & 0xFF) => u8_16(e)
1454                 if (OPTIMIZER && op == OPs8_16 && e.Eoper == OPand &&
1455                     i == 0xFF)
1456                 {
1457                     e1.Eoper = OPu8_16;
1458                     e = el_selecte1(e);
1459                     goto Lopt;
1460                 }
1461 
1462                 if (
1463                     /* OK for uint if AND or high bits of i are 0   */
1464                     op == OPu8_16 && (e.Eoper == OPand || !(i & ~0xFF)) ||
1465                     /* OK for signed if i is 'sign-extended'    */
1466                     op == OPs8_16 && cast(targ_short)cast(targ_schar)i == i
1467                    )
1468                 {
1469                     /* Convert ((u8int) e) & i) to (u8int)(e & (int8) i) */
1470                     /* or similar for s8int                              */
1471                     e = el_una(e1.Eoper,e.Ety,e);
1472                     e.EV.E1.Ety = e1.Ety = e1.EV.E1.Ety;
1473                     e.EV.E1.EV.E1 = el_selecte1(e1);
1474                     e.EV.E1.EV.E2 = el_una(OP16_8,e.EV.E1.Ety,e.EV.E1.EV.E2);
1475                     goto Lopt;
1476                 }
1477                 break;
1478             }
1479 
1480             case LLONGSIZE:
1481                 if (OPTIMIZER)
1482                 {
1483                     if (e2.EV.Vullong == LLONGMASK)
1484                         goto L1;
1485                 }
1486                 break;
1487 
1488             default:
1489                 break;
1490         }
1491         if (OPTIMIZER && sz < 16)
1492         {
1493             targ_ullong ul = el_tolong(e2);
1494 
1495             if (e.Eoper == OPor && op == OPand && e1.EV.E2.Eoper == OPconst)
1496             {
1497                 // ((x & c1) | c2) => (x | c2)
1498                 targ_ullong c3;
1499 
1500                 c3 = ul | e1.EV.E2.EV.Vullong;
1501                 switch (sz)
1502                 {
1503                     case CHARSIZE:
1504                         if ((c3 & CHARMASK) == CHARMASK)
1505                             goto L2;
1506                         break;
1507 
1508                     case SHORTSIZE:
1509                         if ((c3 & SHORTMASK) == SHORTMASK)
1510                             goto L2;
1511                         break;
1512 
1513                     case LONGSIZE:
1514                         if ((c3 & LONGMASK) == LONGMASK)
1515                         {
1516                         L2:
1517                             e1.EV.E2.EV.Vullong = c3;
1518                             e.EV.E1 = elbitwise(e1, GOALvalue);
1519                             goto Lopt;
1520                         }
1521                         break;
1522 
1523                     case LLONGSIZE:
1524                         if ((c3 & LLONGMASK) == LLONGMASK)
1525                             goto L2;
1526                         break;
1527 
1528                     default:
1529                         assert(0);
1530                 }
1531             }
1532 
1533             if (op == OPs16_32 && (ul & 0xFFFFFFFFFFFF8000L) == 0 ||
1534                 op == OPu16_32 && (ul & 0xFFFFFFFFFFFF0000L) == 0 ||
1535                 op == OPs8_16  && (ul & 0xFFFFFFFFFFFFFF80L) == 0 ||
1536                 op == OPu8_16  && (ul & 0xFFFFFFFFFFFFFF00L) == 0 ||
1537                 op == OPs32_64 && (ul & 0xFFFFFFFF80000000L) == 0 ||
1538                 op == OPu32_64 && (ul & 0xFFFFFFFF00000000L) == 0
1539                )
1540             {
1541                 if (e.Eoper == OPand)
1542                 {
1543                     if (op == OPs16_32 && (ul & 0x8000) == 0)
1544                         e1.Eoper = OPu16_32;
1545                     else if (op == OPs8_16  && (ul & 0x80) == 0)
1546                         e1.Eoper = OPu8_16;
1547                     else if (op == OPs32_64 && (ul & 0x80000000) == 0)
1548                         e1.Eoper = OPu32_64;
1549                 }
1550 
1551                 // ((shtlng)s & c) => ((shtlng)(s & c)
1552                 e1.Ety = e.Ety;
1553                 e.Ety = e2.Ety = e1.EV.E1.Ety;
1554                 e.EV.E1 = e1.EV.E1;
1555                 e1.EV.E1 = e;
1556                 e = e1;
1557                 goto Lopt;
1558             }
1559 
1560             // Replace (((a & b) ^ c) & d) with ((a ^ c) & e), where
1561             // e is (b&d).
1562             if (e.Eoper == OPand && op == OPxor && e1.EV.E1.Eoper == OPand &&
1563                 e1.EV.E1.EV.E2.Eoper == OPconst)
1564             {
1565                 e2.EV.Vullong &= e1.EV.E1.EV.E2.EV.Vullong;
1566                 e1.EV.E1 = el_selecte1(e1.EV.E1);
1567                 goto Lopt;
1568             }
1569 
1570             // Replace ((a >> b) & 1) with (a btst b)
1571             if ((I32 || I64) &&
1572                 e.Eoper == OPand &&
1573                 ul == 1 &&
1574                 (e.EV.E1.Eoper == OPshr || e.EV.E1.Eoper == OPashr) &&
1575                 sz <= REGSIZE &&
1576                 tysize(e1.Ety) >= 2     // BT doesn't work on byte operands
1577                )
1578             {
1579                 e.EV.E1.Eoper = OPbtst;
1580                 e = el_selecte1(e);
1581                 goto Lopt;
1582             }
1583         }
1584     }
1585 
1586     if (OPTIMIZER && goal & GOALflags && (I32 || I64) && e.Eoper == OPand &&
1587         (sz == 4 || sz == 8))
1588     {
1589         /* These should all compile to a BT instruction when -O, for -m32 and -m64
1590          * int bt32(uint *p, uint b) { return ((p[b >> 5] & (1 << (b & 0x1F)))) != 0; }
1591          * int bt64a(ulong *p, uint b) { return ((p[b >> 6] & (1L << (b & 63)))) != 0; }
1592          * int bt64b(ulong *p, size_t b) { return ((p[b >> 6] & (1L << (b & 63)))) != 0; }
1593          */
1594 
1595         static bool ELCONST(elem* e, long c) { return e.Eoper == OPconst && el_tolong(e) == c; }
1596         int pow2sz = ispow2(sz);
1597 
1598         if (e1.Eoper == OPind)
1599         {   // Swap e1 and e2 so that e1 is the mask and e2 is the memory location
1600             e2 = e1;
1601             e1 = e.EV.E2;
1602         }
1603 
1604         /* Replace:
1605          *  ((1 << (b & 31))   &   *(((b >>> 5) << 2) + p)
1606          * with:
1607          *  p bt b
1608          */
1609         elem *e12;              // the (b & 31), which may be preceded by (64_32)
1610         elem *e2111;            // the (b >>> 5), which may be preceded by (u32_64)
1611         if (e1.Eoper == OPshl &&
1612             ELCONST(e1.EV.E1,1) &&
1613             (((e12 = e1.EV.E2).Eoper == OP64_32 ? (e12 = e12.EV.E1) : e12).Eoper == OPand) &&
1614             ELCONST(e12.EV.E2,sz * 8 - 1) &&
1615             tysize(e12.Ety) <= sz &&
1616 
1617             e2.Eoper == OPind &&
1618             e2.EV.E1.Eoper == OPadd &&
1619             e2.EV.E1.EV.E1.Eoper == OPshl &&
1620             ELCONST(e2.EV.E1.EV.E1.EV.E2,pow2sz) &&
1621             (((e2111 = e2.EV.E1.EV.E1.EV.E1).Eoper == OPu32_64 ? (e2111 = e2111.EV.E1) : e2111).Eoper == OPshr) &&
1622             ELCONST(e2111.EV.E2,pow2sz + 3)
1623            )
1624         {
1625             elem **pb1 = &e12.EV.E1;
1626             elem **pb2 = &e2111.EV.E1;
1627             elem **pp  = &e2.EV.E1.EV.E2;
1628 
1629             if (el_match(*pb1, *pb2) &&
1630                 !el_sideeffect(*pb1))
1631             {
1632                 e.Eoper = OPbt;
1633                 e.EV.E1 = *pp;            // p
1634                 *pp = null;
1635                 e.EV.E2 = *pb1;           // b
1636                 *pb1 = null;
1637                 *pb2 = null;
1638                 el_free(e1);
1639                 el_free(e2);
1640                 return optelem(e,goal);
1641             }
1642         }
1643 
1644         /* Replace:
1645          *  (1 << a) & b
1646          * with:
1647          *  b btst a
1648          */
1649         if (e1.Eoper == OPshl &&
1650             ELCONST(e1.EV.E1,1) &&
1651             tysize(e.EV.E1.Ety) <= REGSIZE)
1652         {
1653             const int sz1 = tysize(e.EV.E1.Ety);
1654             e.Eoper = OPbtst;
1655             e.Ety = TYbool;
1656             e.EV.E1 = e2;
1657             e.EV.E2 = e1.EV.E2;
1658             //e.EV.E2.Ety = e.EV.E1.Ety; // leave type as int
1659             e1.EV.E2 = null;
1660             el_free(e1);
1661 
1662             if (sz1 >= 2)
1663                 e = el_una(OPu8_16, TYushort, e);
1664             if (sz1 >= 4)
1665                 e = el_una(OPu16_32, TYulong, e);
1666             if (sz1 >= 8)
1667                 e = el_una(OPu32_64, TYullong, e);
1668 
1669             return optelem(e, goal);
1670         }
1671     }
1672 
1673     return e;
1674 
1675 Lopt:
1676     debug
1677     {
1678         __gshared int nest;
1679         nest++;
1680         if (nest > 100)
1681         {   elem_print(e);
1682             assert(0);
1683         }
1684         e = optelem(e,GOALvalue);
1685         nest--;
1686         return e;
1687     }
1688     else
1689         return optelem(e,GOALvalue);
1690 }
1691 
1692 /***************************************
1693  * Fill in ops[maxops] with operands of repeated operator oper.
1694  * Returns:
1695  *      true    didn't fail
1696  *      false   more than maxops operands
1697  */
1698 
1699 @trusted
1700 bool fillinops(elem **ops, int *opsi, int maxops, int oper, elem *e)
1701 {
1702     if (e.Eoper == oper)
1703     {
1704         if (!fillinops(ops, opsi, maxops, oper, e.EV.E1) ||
1705             !fillinops(ops, opsi, maxops, oper, e.EV.E2))
1706             return false;
1707     }
1708     else
1709     {
1710         if (*opsi >= maxops)
1711             return false;       // error, too many
1712         ops[*opsi] = e;
1713         *opsi += 1;
1714     }
1715     return true;
1716 }
1717 
1718 
1719 /*************************************
1720  * Replace shift|shift with rotate.
1721  */
1722 
1723 @trusted
1724 private elem *elor(elem *e, goal_t goal)
1725 {
1726     //printf("elor()\n");
1727     /* ROL:     (a << shift) | (a >> (sizeof(a) * 8 - shift))
1728      * ROR:     (a >> shift) | (a << (sizeof(a) * 8 - shift))
1729      */
1730     elem *e1 = e.EV.E1;
1731     elem *e2 = e.EV.E2;
1732     uint sz = tysize(e.Ety);
1733     if (sz <= REGSIZE)
1734     {
1735         if (e1.Eoper == OPshl && e2.Eoper == OPshr &&
1736             tyuns(e2.EV.E1.Ety) && e2.EV.E2.Eoper == OPmin &&
1737             e2.EV.E2.EV.E1.Eoper == OPconst &&
1738             el_tolong(e2.EV.E2.EV.E1) == sz * 8 &&
1739             el_match5(e1.EV.E1, e2.EV.E1) &&
1740             el_match5(e1.EV.E2, e2.EV.E2.EV.E2) &&
1741             !el_sideeffect(e)
1742            )
1743         {
1744             e1.Eoper = OProl;
1745             return el_selecte1(e);
1746         }
1747         if (e1.Eoper == OPshr && e2.Eoper == OPshl &&
1748             tyuns(e1.EV.E1.Ety) && e2.EV.E2.Eoper == OPmin &&
1749             e2.EV.E2.EV.E1.Eoper == OPconst &&
1750             el_tolong(e2.EV.E2.EV.E1) == sz * 8 &&
1751             el_match5(e1.EV.E1, e2.EV.E1) &&
1752             el_match5(e1.EV.E2, e2.EV.E2.EV.E2) &&
1753             !el_sideeffect(e)
1754            )
1755         {
1756             e1.Eoper = OPror;
1757             return el_selecte1(e);
1758         }
1759         // rotate left by a constant
1760         if (e1.Eoper == OPshl && e2.Eoper == OPshr &&
1761             tyuns(e2.EV.E1.Ety) &&
1762             e1.EV.E2.Eoper == OPconst &&
1763             e2.EV.E2.Eoper == OPconst &&
1764             el_tolong(e2.EV.E2) == sz * 8 - el_tolong(e1.EV.E2) &&
1765             el_match5(e1.EV.E1, e2.EV.E1) &&
1766             !el_sideeffect(e)
1767            )
1768         {
1769             e1.Eoper = OProl;
1770             return el_selecte1(e);
1771         }
1772         // rotate right by a constant
1773         if (e1.Eoper == OPshr && e2.Eoper == OPshl &&
1774             tyuns(e2.EV.E1.Ety) &&
1775             e1.EV.E2.Eoper == OPconst &&
1776             e2.EV.E2.Eoper == OPconst &&
1777             el_tolong(e2.EV.E2) == sz * 8 - el_tolong(e1.EV.E2) &&
1778             el_match5(e1.EV.E1, e2.EV.E1) &&
1779             !el_sideeffect(e)
1780            )
1781         {
1782             e1.Eoper = OPror;
1783             return el_selecte1(e);
1784         }
1785     }
1786 
1787     /* Recognize the following function and replace it with OPbswap:
1788         ushort byteswap(ushort x) { return cast(ushort)(((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)); }
1789 
1790          |  TYunsigned short
1791           &  TYshort
1792            32_16  TYshort
1793             >>  TYint
1794              u16_32  TYint
1795               var  TYunsigned short  x
1796              const  TYint 8L
1797            const  TYshort 255
1798           &  TYshort
1799            <<  TYshort
1800             var  TYshort  x
1801             const  TYshort 8
1802            const  TYshort 0xFF00
1803      */
1804     if (sz == 2 && OPTIMIZER)
1805     {
1806         if (e.Eoper == OPor &&
1807             e1.Eoper == OPand &&
1808             e2.Eoper == OPand)
1809         {
1810             elem* evar;
1811             elem* evar2;
1812             auto e11 = e1.EV.E1;
1813             auto e12 = e1.EV.E2;
1814             if (e11.Eoper == OP32_16 &&
1815                 e12.Eoper == OPconst && el_tolong(e12) == 0xFF)
1816             {
1817                 auto e111 = e11.EV.E1;
1818                 if (e111.Eoper == OPshr || e111.Eoper == OPashr)
1819                 {
1820                     auto e1111 = e111.EV.E1;
1821                     auto e1112 = e111.EV.E2;
1822                     if (e1112.Eoper == OPconst && el_tolong(e1112) == 8 &&
1823                         e1111.Eoper == OPu16_32)
1824                         evar = e1111.EV.E1;
1825                 }
1826             }
1827 
1828             if (evar)
1829             {
1830                 auto e22 = e2.EV.E2;
1831                 if (e22.Eoper == OPconst && el_tolong(e22) == 0xFF00)
1832                 {
1833                     auto e21 = e2.EV.E1;
1834                     if (e21.Eoper == OPshl)
1835                     {
1836                         auto e211 = e21.EV.E1;
1837                         auto e212 = e21.EV.E2;
1838                         if (e212.Eoper == OPconst && el_tolong(e212) == 8)
1839                         {
1840                             if (el_match5(evar, e211) && !el_sideeffect(e211))
1841                             {
1842                                 evar2 = e211;
1843                                 e21.EV.E1 = null;
1844                             }
1845                         }
1846                     }
1847                 }
1848             }
1849 
1850             if (evar2)
1851             {
1852                 el_free(e1);
1853                 el_free(e2);
1854                 e.Eoper = OPbswap;
1855                 e.EV.E1 = evar2;
1856                 e.EV.E2 = null;
1857                 //printf("Matched byteswap(ushort)\n");
1858                 return e;
1859             }
1860         }
1861     }
1862 
1863     /* BSWAP: (data[0]<< 24) | (data[1]<< 16) | (data[2]<< 8) | (data[3]<< 0)
1864      */
1865     if (sz == 4 && OPTIMIZER)
1866     {
1867         elem*[4] ops;
1868         int opsi = 0;
1869         if (fillinops(ops.ptr, &opsi, 4, OPor, e) && opsi == 4)
1870         {
1871             elem *ex = null;
1872             uint bmask = 0;
1873             for (int i = 0; i < 4; i++)
1874             {
1875                 elem *eo = ops[i];
1876                 elem *eo2;
1877                 int shift;
1878                 elem *eo111;
1879                 if (eo.Eoper == OPu8_16 &&
1880                     eo.EV.E1.Eoper == OPind)
1881                 {
1882                     eo111 = eo.EV.E1.EV.E1;
1883                     shift = 0;
1884                 }
1885                 else if (eo.Eoper == OPshl &&
1886                     eo.EV.E1.Eoper == OPu8_16 &&
1887                     (eo2 = eo.EV.E2).Eoper == OPconst &&
1888                     eo.EV.E1.EV.E1.Eoper == OPind)
1889                 {
1890                     shift = cast(int)el_tolong(eo2);
1891                     switch (shift)
1892                     {
1893                         case 8:
1894                         case 16:
1895                         case 24:
1896                             break;
1897 
1898                         default:
1899                             goto L1;
1900                     }
1901                     eo111 = eo.EV.E1.EV.E1.EV.E1;
1902                 }
1903                 else
1904                     goto L1;
1905 
1906                 uint off;
1907                 elem *ed;
1908                 if (eo111.Eoper == OPadd)
1909                 {
1910                     ed = eo111.EV.E1;
1911                     if (eo111.EV.E2.Eoper != OPconst)
1912                         goto L1;
1913                     off = cast(uint)el_tolong(eo111.EV.E2);
1914                     if (off < 1 || off > 3)
1915                         goto L1;
1916                 }
1917                 else
1918                 {
1919                     ed = eo111;
1920                     off = 0;
1921                 }
1922                 switch ((off << 5) | shift)
1923                 {
1924                     // BSWAP
1925                     case (0 << 5) | 24: bmask |= 1; break;
1926                     case (1 << 5) | 16: bmask |= 2; break;
1927                     case (2 << 5) |  8: bmask |= 4; break;
1928                     case (3 << 5) |  0: bmask |= 8; break;
1929 
1930                     // No swap
1931                     case (0 << 5) |  0: bmask |= 0x10; break;
1932                     case (1 << 5) |  8: bmask |= 0x20; break;
1933                     case (2 << 5) | 16: bmask |= 0x40; break;
1934                     case (3 << 5) | 24: bmask |= 0x80; break;
1935 
1936                     default:
1937                         goto L1;
1938                 }
1939                 if (ex)
1940                 {
1941                     if (!el_match(ex, ed))
1942                         goto L1;
1943                 }
1944                 else
1945                 {   if (el_sideeffect(ed))
1946                         goto L1;
1947                     ex = ed;
1948                 }
1949             }
1950             /* Got a match, build:
1951              *   BSWAP(*ex)
1952              */
1953             if (bmask == 0x0F)
1954                 e = el_una(OPbswap, e.Ety, el_una(OPind, e.Ety, ex));
1955             else if (bmask == 0xF0)
1956                 e = el_una(OPind, e.Ety, ex);
1957             else
1958                 goto L1;
1959             return e;
1960         }
1961     }
1962   L1:
1963 
1964     return elbitwise(e, goal);
1965 }
1966 
1967 /*************************************
1968  */
1969 
1970 @trusted
1971 private elem *elxor(elem *e, goal_t goal)
1972 {
1973     if (OPTIMIZER)
1974     {
1975         elem *e1 = e.EV.E1;
1976         elem *e2 = e.EV.E2;
1977 
1978         /* Recognize:
1979          *    (a & c) ^ (b & c)  =>  (a ^ b) & c
1980          */
1981         if (e1.Eoper == OPand && e2.Eoper == OPand &&
1982             el_match5(e1.EV.E2, e2.EV.E2) &&
1983             (e2.EV.E2.Eoper == OPconst || (!el_sideeffect(e2.EV.E1) && !el_sideeffect(e2.EV.E2))))
1984         {
1985             el_free(e1.EV.E2);
1986             e1.EV.E2 = e2.EV.E1;
1987             e1.Eoper = OPxor;
1988             e.Eoper = OPand;
1989             e.EV.E2 = e2.EV.E2;
1990             e2.EV.E1 = null;
1991             e2.EV.E2 = null;
1992             el_free(e2);
1993             return optelem(e, GOALvalue);
1994         }
1995     }
1996     return elbitwise(e, goal);
1997 }
1998 
1999 /**************************
2000  * Optimize nots.
2001  *      ! ! e => bool e
2002  *      ! bool e => ! e
2003  *      ! OTrel => !OTrel       (invert the condition)
2004  *      ! OTconv => !
2005  */
2006 
2007 @trusted
2008 private elem * elnot(elem *e, goal_t goal)
2009 {
2010     elem *e1 = e.EV.E1;
2011     const op = e1.Eoper;
2012     switch (op)
2013     {
2014         case OPnot:                     // ! ! e => bool e
2015         case OPbool:                    // ! bool e => ! e
2016             e1.Eoper = cast(ubyte)(op ^ (OPbool ^ OPnot));
2017             /* That was a clever substitute for the following:  */
2018             /* e.Eoper = (op == OPnot) ? OPbool : OPnot;               */
2019             e = optelem(el_selecte1(e), goal);
2020             break;
2021 
2022         default:
2023             if (OTrel(op))                      /* ! OTrel => !OTrel            */
2024             {
2025                   /* Find the logical negation of the operator  */
2026                   auto op2 = rel_not(op);
2027                   if (!tyfloating(e1.EV.E1.Ety))
2028                   {   op2 = rel_integral(op2);
2029                       assert(OTrel(op2));
2030                   }
2031                   e1.Eoper = cast(ubyte)op2;
2032                   e = optelem(el_selecte1(e), goal);
2033             }
2034             else if (tybasic(e1.Ety) == TYbool && tysize(e.Ety) == 1)
2035             {
2036                 // !e1 => (e1 ^ 1)
2037                 e.Eoper = OPxor;
2038                 e.EV.E2 = el_long(e1.Ety,1);
2039                 e = optelem(e, goal);
2040             }
2041             else
2042             {
2043                 static if (0)
2044                 {
2045                     // Can't use this because what if OPd_s32?
2046                     // Note: !(long)(.1) != !(.1)
2047                     if (OTconv(op))             // don't use case because of differ target
2048                     {   // conversion operators
2049                         e1.Eoper = e.Eoper;
2050                         e = optelem(el_selecte1(e), goal);
2051                         break;
2052                     }
2053                 }
2054             }
2055             break;
2056 
2057         case OPs32_d:
2058         case OPs16_d:
2059         case OPu16_d:
2060         case OPu32_d:
2061         case OPf_d:
2062         case OPd_ld:
2063         case OPs16_32:
2064         case OPu16_32:
2065         case OPu8_16:
2066         case OPs8_16:
2067         case OPu32_64:
2068         case OPs32_64:
2069         case OPvp_fp:
2070         case OPcvp_fp:
2071         case OPnp_fp:
2072             e1.Eoper = e.Eoper;
2073             e = optelem(el_selecte1(e), goal);
2074             break;
2075     }
2076     return e;
2077 }
2078 
2079 /*************************
2080  * Complement
2081  *      ~ ~ e => e
2082  */
2083 
2084 @trusted
2085 private elem * elcom(elem *e, goal_t goal)
2086 {
2087     elem *e1 = e.EV.E1;
2088     if (e1.Eoper == OPcom)                       // ~ ~ e => e
2089         // Typing problem here
2090         e = el_selecte1(el_selecte1(e));
2091     return e;
2092 }
2093 
2094 /*************************
2095  * If it is a conditional of a constant
2096  * then we know which exp to evaluate.
2097  * BUG:
2098  *      doesn't detect ("string" ? et : ef)
2099  */
2100 
2101 @trusted
2102 private elem * elcond(elem *e, goal_t goal)
2103 {
2104     //printf("elcond() goal = %d\n", goal);
2105     //elem_print(e);
2106     elem *e1 = e.EV.E1;
2107     switch (e1.Eoper)
2108     {
2109         case OPconst:
2110             if (boolres(e1))
2111             L1:
2112                 e = el_selecte1(el_selecte2(e));
2113             else
2114                 e = el_selecte2(el_selecte2(e));
2115             break;
2116 
2117         case OPrelconst:
2118         case OPstring:
2119             goto L1;
2120 
2121         case OPcomma:
2122             // ((a,b) ? c) => (a,(b ? c))
2123             e.Eoper = OPcomma;
2124             e.EV.E1 = e1.EV.E1;
2125             e1.EV.E1 = e1.EV.E2;
2126             e1.EV.E2 = e.EV.E2;
2127             e.EV.E2 = e1;
2128             e1.Eoper = OPcond;
2129             e1.Ety = e.Ety;
2130             return optelem(e,GOALvalue);
2131 
2132         case OPnot:
2133         {
2134             // (!a ? b : c) => (a ? c : b)
2135             elem *ex = e.EV.E2.EV.E1;
2136             e.EV.E2.EV.E1 = e.EV.E2.EV.E2;
2137             e.EV.E2.EV.E2 = ex;
2138             goto L2;
2139         }
2140 
2141         default:
2142             if (OTboolnop(e1.Eoper))
2143             {
2144         L2:
2145                 e.EV.E1 = e1.EV.E1;
2146                 e1.EV.E1 = null;
2147                 el_free(e1);
2148                 return elcond(e,goal);
2149             }
2150             if (!OPTIMIZER)
2151                 break;
2152 
2153         {
2154             tym_t ty = e.Ety;
2155             elem *ec1 = e.EV.E2.EV.E1;
2156             elem *ec2 = e.EV.E2.EV.E2;
2157 
2158             if (tyintegral(ty) && ec1.Eoper == OPconst && ec2.Eoper == OPconst)
2159             {
2160                 targ_llong i1 = el_tolong(ec1);
2161                 targ_llong i2 = el_tolong(ec2);
2162                 tym_t ty1 = tybasic(e1.Ety);
2163 
2164                 if ((ty1 == TYbool && !OTlogical(e1.Eoper) || e1.Eoper == OPand && e1.EV.E2.Eoper == OPconst) &&
2165                     tysize(ty) == tysize(ec1.Ety))
2166                 {
2167                     targ_llong b = ty1 == TYbool ? 1 : el_tolong(e1.EV.E2);
2168 
2169                     if (b == 1 && ispow2(i1 - i2) != -1)
2170                     {
2171                         // replace (e1 ? i1 : i2) with (i1 + (e1 ^ 1) * (i2 - i1))
2172                         // replace (e1 ? i2 : i1) with (i1 + e1 * (i2 - i1))
2173                         int sz = tysize(e1.Ety);
2174                         while (sz < tysize(ec1.Ety))
2175                         {
2176                             // Increase the size of e1 until it matches the size of ec1
2177                             switch (sz)
2178                             {
2179                                 case 1:
2180                                     e1 = el_una(OPu8_16, TYushort, e1);
2181                                     sz = 2;
2182                                     break;
2183                                 case 2:
2184                                     e1 = el_una(OPu16_32, TYulong, e1);
2185                                     sz = 4;
2186                                     break;
2187                                 case 4:
2188                                     e1 = el_una(OPu32_64, TYullong, e1);
2189                                     sz = 8;
2190                                     break;
2191                                 default:
2192                                     assert(0);
2193                             }
2194                         }
2195                         if (i1 < i2)
2196                         {
2197                             ec2.EV.Vllong = i2 - i1;
2198                             e1 = el_bin(OPxor,e1.Ety,e1,el_long(e1.Ety,1));
2199                         }
2200                         else
2201                         {
2202                             ec1.EV.Vllong = i2;
2203                             ec2.EV.Vllong = i1 - i2;
2204                         }
2205                         e.EV.E1 = ec1;
2206                         e.EV.E2.Eoper = OPmul;
2207                         e.EV.E2.Ety = ty;
2208                         e.EV.E2.EV.E1 = e1;
2209                         e.Eoper = OPadd;
2210                         return optelem(e,GOALvalue);
2211                     }
2212 
2213                     /* If b is an integer with only 1 bit set then
2214                      *   replace ((a & b) ? b : 0) with (a & b)
2215                      *   replace ((a & b) ? 0 : b) with ((a & b) ^ b)
2216                      */
2217                     if (e1.Eoper == OPand && e1.EV.E2.Eoper == OPconst && ispow2(b) != -1) // if only 1 bit is set
2218                     {
2219                         if (b == i1 && i2 == 0)
2220                         {   e = el_selecte1(e);
2221                             e.EV.E1.Ety = ty;
2222                             e.EV.E2.Ety = ty;
2223                             e.EV.E2.EV.Vllong = b;
2224                             return optelem(e,GOALvalue);
2225                         }
2226                         else if (i1 == 0 && b == i2)
2227                         {
2228                             e1.Ety = ty;
2229                             e1.EV.E1.Ety = ty;
2230                             e1.EV.E2.Ety = ty;
2231                             e1.EV.E2.EV.Vllong = b;
2232                             e.EV.E1 = el_bin(OPxor,ty,e1,el_long(ty,b));
2233                             e = el_selecte1(e);
2234                             return optelem(e,GOALvalue);
2235                         }
2236                     }
2237                 }
2238 
2239                 /* Replace ((a relop b) ? 1 : 0) with (a relop b)       */
2240                 else if (OTrel(e1.Eoper) &&
2241                     tysize(ty) <= tysize(TYint))
2242                 {
2243                     if (i1 == 1 && i2 == 0)
2244                         e = el_selecte1(e);
2245                     else if (i1 == 0 && i2 == 1)
2246                     {
2247                         e.EV.E1 = el_una(OPnot,ty,e1);
2248                         e = optelem(el_selecte1(e),GOALvalue);
2249                     }
2250                 }
2251 
2252                 // The next two optimizations attempt to replace with an
2253                 // uint compare, which the code generator can generate
2254                 // code for without using jumps.
2255 
2256                 // Try to replace (!e1) with (e1 < 1)
2257                 else if (e1.Eoper == OPnot && !OTrel(e1.EV.E1.Eoper) && e1.EV.E1.Eoper != OPand)
2258                 {
2259                     e.EV.E1 = el_bin(OPlt,TYint,e1.EV.E1,el_long(touns(e1.EV.E1.Ety),1));
2260                     e1.EV.E1 = null;
2261                     el_free(e1);
2262                 }
2263                 // Try to replace (e1) with (e1 >= 1)
2264                 else if (!OTrel(e1.Eoper) && e1.Eoper != OPand)
2265                 {
2266                     if (tyfv(e1.Ety))
2267                     {
2268                         if (tysize(e.Ety) == tysize(TYint))
2269                         {
2270                             if (i1 == 1 && i2 == 0)
2271                             {   e.Eoper = OPbool;
2272                                 el_free(e.EV.E2);
2273                                 e.EV.E2 = null;
2274                             }
2275                             else if (i1 == 0 && i2 == 1)
2276                             {   e.Eoper = OPnot;
2277                                 el_free(e.EV.E2);
2278                                 e.EV.E2 = null;
2279                             }
2280                         }
2281                     }
2282                     else if(tyintegral(e1.Ety))
2283                         e.EV.E1 = el_bin(OPge,TYint,e1,el_long(touns(e1.Ety),1));
2284                 }
2285             }
2286 
2287             // Try to detect absolute value expression
2288             // (a < 0) -a : a
2289             else if ((e1.Eoper == OPlt || e1.Eoper == OPle) &&
2290                 e1.EV.E2.Eoper == OPconst &&
2291                 !boolres(e1.EV.E2) &&
2292                 !tyuns(e1.EV.E1.Ety) &&
2293                 !tyuns(e1.EV.E2.Ety) &&
2294                 ec1.Eoper == OPneg &&
2295                 !el_sideeffect(ec2) &&
2296                 el_match(e.EV.E1.EV.E1,ec2) &&
2297                 el_match(ec1.EV.E1,ec2) &&
2298                 tysize(ty) >= _tysize[TYint]
2299                )
2300             {   e.EV.E2.EV.E2 = null;
2301                 el_free(e);
2302                 e = el_una(OPabs,ty,ec2);
2303             }
2304             // (a >= 0) a : -a
2305             else if ((e1.Eoper == OPge || e1.Eoper == OPgt) &&
2306                 e1.EV.E2.Eoper == OPconst &&
2307                 !boolres(e1.EV.E2) &&
2308                 !tyuns(e1.EV.E1.Ety) &&
2309                 !tyuns(e1.EV.E2.Ety) &&
2310                 ec2.Eoper == OPneg &&
2311                 !el_sideeffect(ec1) &&
2312                 el_match(e.EV.E1.EV.E1,ec1) &&
2313                 el_match(ec2.EV.E1,ec1) &&
2314                 tysize(ty) >= _tysize[TYint]
2315                )
2316             {   e.EV.E2.EV.E1 = null;
2317                 el_free(e);
2318                 e = el_una(OPabs,ty,ec1);
2319             }
2320 
2321             /* Replace:
2322              *    a ? noreturn : c
2323              * with:
2324              *    (a && noreturn), c
2325              * because that means fewer noreturn cases for the data flow analysis to deal with
2326              */
2327             else if (!el_returns(ec1))
2328             {
2329                 e.Eoper = OPcomma;
2330                 e.EV.E1 = e.EV.E2;
2331                 e.EV.E2 = ec2;
2332                 e.EV.E1.Eoper = OPandand;
2333                 e.EV.E1.Ety = TYvoid;
2334                 e.EV.E1.EV.E2 = ec1;
2335                 e.EV.E1.EV.E1 = e1;
2336             }
2337 
2338             /* Replace:
2339              *    a ? b : noreturn
2340              * with:
2341              *    (a || noreturn), b
2342              */
2343             else if (!el_returns(ec2))
2344             {
2345                 e.Eoper = OPcomma;
2346                 e.EV.E1 = e.EV.E2;
2347                 e.EV.E2 = ec1;
2348                 e.EV.E1.Eoper = OPoror;
2349                 e.EV.E1.Ety = TYvoid;
2350                 e.EV.E1.EV.E2 = ec2;
2351                 e.EV.E1.EV.E1 = e1;
2352             }
2353 
2354             /* Replace:
2355              *   *p op e ? p : false
2356              * with:
2357              *   bool
2358              */
2359             else if (goal == GOALflags &&
2360                 ec2.Eoper == OPconst && !boolres(ec2) &&
2361                 typtr(ec1.Ety) &&
2362                 ec1.Eoper == OPvar &&
2363                 OTbinary(e1.Eoper) &&
2364                 !OTsideff(e1.Eoper) &&
2365                 e1.EV.E1.Eoper == OPind &&
2366                 el_match(findPointer(e1.EV.E1.EV.E1), ec1) &&
2367                 !el_sideeffect(e))
2368             {
2369                 /* NOTE: should optimize other cases of this
2370                  */
2371                 el_free(e.EV.E2);
2372                 e.EV.E2 = null;
2373                 e.Eoper = OPbool;
2374                 e.Ety = TYint;
2375             }
2376             break;
2377         }
2378     }
2379     return e;
2380 }
2381 
2382 /******************************
2383  * Given an elem that is the operand to OPind,
2384  * find the expression representing the pointer.
2385  * Params:
2386  *      e = operand to OPind
2387  * Returns:
2388  *      expression that represents the pointer
2389  */
2390 @trusted
2391 private elem* findPointer(elem* e)
2392 {
2393     if (e.Eoper == OPvar)
2394         return e;
2395     if (OTleaf(e.Eoper) || !(e.Eoper == OPadd || e.Eoper == OPmin))
2396         return null;
2397 
2398     if (typtr(e.EV.E1.Ety))
2399         return findPointer(e.EV.E1);
2400     if (OTbinary(e.Eoper))
2401     {
2402         if (typtr(e.EV.E2.Ety))
2403             return findPointer(e.EV.E2);
2404     }
2405     return null;
2406 }
2407 
2408 
2409 /****************************
2410  * Comma operator.
2411  *        ,      e
2412  *       / \  =>                expression with no effect
2413  *      c   e
2414  *        ,               ,
2415  *       / \    =>       / \    operators with no effect
2416  *      +   e           ,   e
2417  *     / \             / \
2418  *    e   e           e   e
2419  */
2420 
2421 @trusted
2422 private elem * elcomma(elem *e, goal_t goal)
2423 {
2424     int changes = -1;
2425 L1:
2426     changes++;
2427 L2:
2428     //printf("elcomma()\n");
2429     elem *e2 = e.EV.E2;
2430     elem **pe1 = &(e.EV.E1);
2431     elem *e1 = *pe1;
2432     int e1op = e1.Eoper;
2433 
2434   // c,e => e
2435     if (OTleaf(e1op) && !OTsideff(e1op) && !(e1.Ety & (mTYvolatile | mTYshared)))
2436     {
2437         e2.Ety = e.Ety;
2438         e = el_selecte2(e);
2439         goto Lret;
2440     }
2441 
2442     // ((a op b),e2) => ((a,b),e2)        if op has no side effects
2443     if (!el_sideeffect(e1) && e1op != OPcomma && e1op != OPandand &&
2444         e1op != OPoror && e1op != OPcond)
2445     {
2446         if (OTunary(e1op))
2447             *pe1 = el_selecte1(e1); /* get rid of e1                */
2448         else
2449         {
2450             e1.Eoper = OPcomma;
2451             e1.Ety = e1.EV.E2.Ety;
2452         }
2453         goto L1;
2454     }
2455 
2456     if (!OPTIMIZER)
2457         goto Lret;
2458 
2459     /* Replace (a,b),e2 with a,(b,e2)   */
2460     if (e1op == OPcomma)
2461     {
2462         e1.Ety = e.Ety;
2463         e.EV.E1 = e1.EV.E1;
2464         e1.EV.E1 = e1.EV.E2;
2465         e1.EV.E2 = e2;
2466         e.EV.E2 = elcomma(e1, GOALvalue);
2467         goto L2;
2468     }
2469 
2470     if ((OTopeq(e1op) || e1op == OPeq) &&
2471         (e1.EV.E1.Eoper == OPvar || e1.EV.E1.Eoper == OPind) &&
2472         !el_sideeffect(e1.EV.E1)
2473        )
2474     {
2475         if (el_match(e1.EV.E1,e2))
2476             // ((a = b),a) => (a = b)
2477             e = el_selecte1(e);
2478         else if (OTrel(e2.Eoper) &&
2479                  OTleaf(e2.EV.E2.Eoper) &&
2480                  el_match(e1.EV.E1,e2.EV.E1)
2481                 )
2482         {   // ((a = b),(a < 0)) => ((a = b) < 0)
2483             e1.Ety = e2.EV.E1.Ety;
2484             e.EV.E1 = e2.EV.E1;
2485             e2.EV.E1 = e1;
2486             goto L1;
2487         }
2488         else if ((e2.Eoper == OPandand ||
2489                   e2.Eoper == OPoror   ||
2490                   e2.Eoper == OPcond) &&
2491                  el_match(e1.EV.E1,e2.EV.E1)
2492                 )
2493         {
2494             /* ((a = b),(a || c)) => ((a = b) || c)     */
2495             e1.Ety = e2.EV.E1.Ety;
2496             e.EV.E1 = e2.EV.E1;
2497             e2.EV.E1 = e1;
2498             e = el_selecte2(e);
2499             changes++;
2500             goto Lret;
2501         }
2502         else if (e1op == OPeq)
2503         {
2504             /* Replace ((a = b),(c = a)) with a,(c = (a = b))   */
2505             for (; e2.Eoper == OPcomma; e2 = e2.EV.E1)
2506             { }
2507             if ((OTopeq(e2.Eoper) || e2.Eoper == OPeq) &&
2508                 el_match(e1.EV.E1,e2.EV.E2) &&
2509                 //!(e1.EV.E1.Eoper == OPvar && el_appears(e2.EV.E1,e1.EV.E1.EV.Vsym)) &&
2510                 ERTOL(e2))
2511             {
2512                 e.EV.E1 = e2.EV.E2;
2513                 e1.Ety = e2.EV.E2.Ety;
2514                 e2.EV.E2 = e1;
2515                 goto L1;
2516             }
2517         }
2518         else
2519         {
2520           static if (1) // This optimization is undone in eleq().
2521           {
2522             // Replace ((a op= b),(a op= c)) with (0,a = (a op b) op c)
2523             for (; e2.Eoper == OPcomma; e2 = e2.EV.E1)
2524             { }
2525             if ((OTopeq(e2.Eoper)) &&
2526                 el_match(e1.EV.E1,e2.EV.E1))
2527             {
2528                 elem *ex;
2529                 e.EV.E1 = el_long(TYint,0);
2530                 e1.Eoper = cast(ubyte)opeqtoop(e1op);
2531                 e2.EV.E2 = el_bin(opeqtoop(e2.Eoper),e2.Ety,e1,e2.EV.E2);
2532                 e2.Eoper = OPeq;
2533                 goto L1;
2534             }
2535           }
2536         }
2537     }
2538 Lret:
2539     again = changes != 0;
2540     return e;
2541 }
2542 
2543 /********************************
2544  */
2545 
2546 private elem * elremquo(elem *e, goal_t goal)
2547 {
2548     static if (0) version (MARS)
2549     if (cnst(e.EV.E2) && !boolres(e.EV.E2))
2550         error(e.Esrcpos.Sfilename, e.Esrcpos.Slinnum, e.Esrcpos.Scharnum, "divide by zero\n");
2551 
2552     return e;
2553 }
2554 
2555 /********************************
2556  */
2557 
2558 @trusted
2559 private elem * elmod(elem *e, goal_t goal)
2560 {
2561     tym_t tym = e.EV.E1.Ety;
2562     if (!tyfloating(tym))
2563         return eldiv(e, goal);
2564     return e;
2565 }
2566 
2567 /*****************************
2568  * Convert divides to >> if power of 2.
2569  * Can handle OPdiv, OPdivass, OPmod.
2570  */
2571 
2572 @trusted
2573 private elem * eldiv(elem *e, goal_t goal)
2574 {
2575     //printf("eldiv()\n");
2576     elem *e2 = e.EV.E2;
2577     tym_t tym = e.EV.E1.Ety;
2578     int uns = tyuns(tym) | tyuns(e2.Ety);
2579     if (cnst(e2))
2580     {
2581         static if (0) version (MARS)
2582         if (!boolres(e2))
2583             error(e.Esrcpos.Sfilename, e.Esrcpos.Slinnum, e.Esrcpos.Scharnum, "divide by zero\n");
2584 
2585         if (uns)
2586         {
2587             e2.Ety = touns(e2.Ety);
2588             int i = ispow2(el_tolong(e2));
2589             if (i != -1)
2590             {
2591                 OPER op;
2592                 switch (e.Eoper)
2593                 {   case OPdiv:
2594                         op = OPshr;
2595                         goto L1;
2596 
2597                     case OPdivass:
2598                         op = OPshrass;
2599                     L1:
2600                         e2.EV.Vint = i;
2601                         e2.Ety = TYint;
2602                         e.EV.E1.Ety = touns(tym);
2603                         break;
2604 
2605                     case OPmod:
2606                         op = OPand;
2607                         goto L3;
2608                     case OPmodass:
2609                         op = OPandass;
2610                     L3:
2611                         e2.EV.Vullong = el_tolong(e2) - 1;
2612                         break;
2613 
2614                     default:
2615                         assert(0);
2616                 }
2617                 e.Eoper = cast(ubyte)op;
2618                 return optelem(e,GOALvalue);
2619             }
2620         }
2621     }
2622 
2623     if (OPTIMIZER)
2624     {
2625         const int SQRT_INT_MAX = 0xB504;
2626         const uint SQRT_UINT_MAX = 0x10000;
2627         elem *e1 = e.EV.E1;
2628         if (tyintegral(tym) && e.Eoper == OPdiv && e2.Eoper == OPconst &&
2629             e1.Eoper == OPdiv && e1.EV.E2.Eoper == OPconst)
2630         {
2631             /* Replace:
2632              *   (e / c1) / c2
2633              * With:
2634              *   e / (c1 * c2)
2635              */
2636             targ_llong c1 = el_tolong(e1.EV.E2);
2637             targ_llong c2 = el_tolong(e2);
2638             bool uns1 = tyuns(e1.EV.E1.Ety) || tyuns(e1.EV.E2.Ety);
2639             bool uns2 = tyuns(e1.Ety) || tyuns(e2.Ety);
2640             if (uns1 == uns2)   // identity doesn't hold for mixed sign case
2641             {
2642                 // The transformation will fail if c1*c2 overflows. This substitutes
2643                 // for a proper overflow check.
2644                 if (uns1 ? (c1 < SQRT_UINT_MAX && c2 < SQRT_UINT_MAX)
2645                          : (-SQRT_INT_MAX < c1 && c1 < SQRT_INT_MAX && -SQRT_INT_MAX < c2 && c2 < SQRT_INT_MAX))
2646                 {
2647                     e.EV.E1 = e1.EV.E1;
2648                     e1.EV.E1 = e1.EV.E2;
2649                     e1.EV.E2 = e2;
2650                     e.EV.E2 = e1;
2651                     e1.Eoper = OPmul;
2652                     return optelem(e, GOALvalue);
2653                 }
2654             }
2655         }
2656 
2657         if (tyintegral(tym) && e.Eoper == OPdiv && e2.Eoper == OPconst &&
2658             e1.Eoper == OP64_32 &&
2659             e1.EV.E1.Eoper == OPremquo && e1.EV.E1.EV.E2.Eoper == OPconst)
2660         {
2661             /* Replace:
2662              *   (64_32 (e /% c1)) / c2
2663              * With:
2664              *   e / (c1 * c2)
2665              */
2666             elem *erq = e1.EV.E1;
2667             targ_llong c1 = el_tolong(erq.EV.E2);
2668             targ_llong c2 = el_tolong(e2);
2669             bool uns1 = tyuns(erq.EV.E1.Ety) || tyuns(erq.EV.E2.Ety);
2670             bool uns2 = tyuns(e1.Ety) || tyuns(e2.Ety);
2671             if (uns1 == uns2)   // identity doesn't hold for mixed sign case
2672             {
2673                 // The transformation will fail if c1*c2 overflows. This substitutes
2674                 // for a proper overflow check.
2675                 if (uns1 ? (c1 < SQRT_UINT_MAX && c2 < SQRT_UINT_MAX)
2676                          : (-SQRT_INT_MAX < c1 && c1 < SQRT_INT_MAX && -SQRT_INT_MAX < c2 && c2 < SQRT_INT_MAX))
2677                 {
2678                     e.EV.E1 = erq.EV.E1;
2679                     erq.EV.E1 = erq.EV.E2;
2680                     erq.EV.E2 = e2;
2681                     e.EV.E2 = erq;
2682                     erq.Eoper = OPmul;
2683                     erq.Ety = e1.Ety;
2684                     e1.EV.E1 = null;
2685                     el_free(e1);
2686                     return optelem(e, GOALvalue);
2687                 }
2688             }
2689         }
2690 
2691         /* Convert if(e1/e2) to if(e1>=e2) iff uint division.
2692          */
2693         if (goal == GOALflags && uns && e.Eoper == OPdiv)
2694         {
2695             e.Eoper = OPge;
2696             e.Ety = TYbool;
2697             return e;
2698         }
2699 
2700         /* TODO: (i*c1)/c2 => i*(c1/c2) if (c1%c2)==0
2701          * TODO: i/(x?c1:c2) => i>>(x?log2(c1):log2(c2)) if c1 and c2 are powers of 2
2702          */
2703 
2704         if (tyintegral(tym) && (e.Eoper == OPdiv || e.Eoper == OPmod))
2705         {
2706             int sz = tysize(tym);
2707 
2708             // See if we can replace with OPremquo
2709             if (sz == REGSIZE
2710                 // Currently don't allow this because OPmsw doesn't work for the case
2711                 //|| (I64 && sz == 4)
2712                 )
2713             {
2714                 // Don't do it if there are special code sequences in the
2715                 // code generator (see cdmul())
2716                 int pow2;
2717                 if (e2.Eoper == OPconst &&
2718                     !uns &&
2719                     (pow2 = ispow2(el_tolong(e2))) != -1 &&
2720                     !(config.target_cpu < TARGET_80286 && pow2 != 1 && e.Eoper == OPdiv)
2721                    )
2722                 { }
2723                 else
2724                 {
2725                     assert(sz == 2 || sz == 4 || sz == 8);
2726                     OPER op = OPmsw;
2727                     if (e.Eoper == OPdiv)
2728                     {
2729                         op = (sz == 2) ? OP32_16 : (sz == 4) ? OP64_32 : OP128_64;
2730                     }
2731                     e.Eoper = OPremquo;
2732                     e = el_una(op, tym, e);
2733                     e.EV.E1.Ety = (sz == 2) ? TYlong : (sz == 4) ? TYllong : TYcent;
2734                     return e;
2735                 }
2736             }
2737         }
2738     }
2739 
2740     return e;
2741 }
2742 
2743 /**************************
2744  * Convert (a op b) op c to a op (b op c).
2745  */
2746 
2747 @trusted
2748 private elem * swaplog(elem *e, goal_t goal)
2749 {
2750     elem *e1 = e.EV.E1;
2751     e.EV.E1 = e1.EV.E2;
2752     e1.EV.E2 = e;
2753     return optelem(e1,goal);
2754 }
2755 
2756 @trusted
2757 private elem * eloror(elem *e, goal_t goal)
2758 {
2759     tym_t ty1,ty2;
2760 
2761     elem *e1 = e.EV.E1;
2762     if (OTboolnop(e1.Eoper))
2763     {
2764         e.EV.E1 = e1.EV.E1;
2765         e1.EV.E1 = null;
2766         el_free(e1);
2767         return eloror(e, goal);
2768     }
2769 
2770     elem *e2 = e.EV.E2;
2771     if (OTboolnop(e2.Eoper))
2772     {
2773         e.EV.E2 = e2.EV.E1;
2774         e2.EV.E1 = null;
2775         el_free(e2);
2776         return eloror(e, goal);
2777     }
2778 
2779     if (OPTIMIZER)
2780     {
2781         if (e1.Eoper == OPbool)
2782         {   ty1 = e1.EV.E1.Ety;
2783             e1 = e.EV.E1 = el_selecte1(e1);
2784             e1.Ety = ty1;
2785         }
2786         if (e1.Eoper == OPoror)
2787         {   /* convert (a||b)||c to a||(b||c). This will find more CSEs.    */
2788             return swaplog(e, goal);
2789         }
2790         e2 = elscancommas(e2);
2791         e1 = elscancommas(e1);
2792     }
2793 
2794     tym_t t = e.Ety;
2795     if (e2.Eoper == OPconst || e2.Eoper == OPrelconst || e2.Eoper == OPstring)
2796     {
2797         if (boolres(e2))                /* e1 || 1  => e1 , 1           */
2798         {
2799             if (e.EV.E2 == e2)
2800                 goto L2;
2801         }
2802         else                            /* e1 || 0  =>  bool e1         */
2803         {
2804             if (e.EV.E2 == e2)
2805             {
2806                 el_free(e.EV.E2);
2807                 e.EV.E2 = null;
2808                 e.Eoper = OPbool;
2809                 goto L3;
2810             }
2811         }
2812     }
2813 
2814     if (e1.Eoper == OPconst || e1.Eoper == OPrelconst || e1.Eoper == OPstring)
2815     {
2816         if (boolres(e1))                /* (x,1) || e2  =>  (x,1),1     */
2817         {
2818             if (tybasic(e.EV.E2.Ety) == TYvoid)
2819             {
2820                 assert(!goal);
2821                 el_free(e);
2822                 return null;
2823             }
2824             else
2825             {
2826             L2:
2827                 e.Eoper = OPcomma;
2828                 el_free(e.EV.E2);
2829                 e.EV.E2 = el_long(t,1);
2830             }
2831         }
2832         else                            /* (x,0) || e2  =>  (x,0),(bool e2) */
2833         {
2834             e.Eoper = OPcomma;
2835             if (tybasic(e.EV.E2.Ety) != TYvoid)
2836                 e.EV.E2 = el_una(OPbool,t,e.EV.E2);
2837         }
2838   }
2839   else if (OPTIMIZER &&
2840         e.EV.E2.Eoper == OPvar &&
2841         !OTlogical(e1.Eoper) &&
2842         tysize(ty2 = e2.Ety) == tysize(ty1 = e1.Ety) &&
2843         tysize(ty1) <= _tysize[TYint] &&
2844         !tyfloating(ty2) &&
2845         !tyfloating(ty1) &&
2846         !(ty2 & (mTYvolatile | mTYshared)))
2847     {   /* Convert (e1 || e2) => (e1 | e2)      */
2848         e.Eoper = OPor;
2849         e.Ety = ty1;
2850         e = el_una(OPbool,t,e);
2851     }
2852     else if (OPTIMIZER &&
2853              e1.Eoper == OPand && e2.Eoper == OPand &&
2854              tysize(e1.Ety) == tysize(e2.Ety) &&
2855              el_match(e1.EV.E1,e2.EV.E1) && !el_sideeffect(e1.EV.E1) &&
2856              !el_sideeffect(e2.EV.E2)
2857             )
2858     {   // Convert ((a & b) || (a & c)) => bool(a & (b | c))
2859         e.Eoper = OPbool;
2860         e.EV.E2 = null;
2861         e2.Eoper = OPor;
2862         el_free(e2.EV.E1);
2863         e2.EV.E1 = e1.EV.E2;
2864         e1.EV.E2 = e2;
2865     }
2866     else
2867         goto L1;
2868 L3:
2869     e = optelem(e,GOALvalue);
2870 L1:
2871     return e;
2872 }
2873 
2874 /**********************************************
2875  * Try to rewrite sequence of || and && with faster operations, such as BT.
2876  * Returns:
2877  *      false   nothing changed
2878  *      true    *pe is rewritten
2879  */
2880 
2881 @trusted
2882 private bool optim_loglog(elem **pe)
2883 {
2884     if (I16)
2885         return false;
2886     elem *e = *pe;
2887     const op = e.Eoper;
2888     assert(op == OPandand || op == OPoror);
2889     size_t n = el_opN(e, op);
2890     if (n <= 3)
2891         return false;
2892     uint ty = e.Ety;
2893     assert(n < size_t.max / (2 * (elem *).sizeof));   // conservative overflow check
2894     elem **array = cast(elem **)malloc(n * (elem *).sizeof);
2895     assert(array);
2896     elem **p = array;
2897     el_opArray(&p, e, op);
2898 
2899     bool any = false;
2900     size_t first, last;
2901     targ_ullong emin, emax;
2902     int cmpop = op == OPandand ? OPne : OPeqeq;
2903     for (size_t i = 0; i < n; ++i)
2904     {
2905         elem *eq = array[i];
2906         if (eq.Eoper == cmpop &&
2907             eq.EV.E2.Eoper == OPconst &&
2908             tyintegral(eq.EV.E2.Ety) &&
2909             !el_sideeffect(eq.EV.E1))
2910         {
2911             targ_ullong m = el_tolong(eq.EV.E2);
2912             if (any)
2913             {
2914                 if (el_match(array[first].EV.E1, eq.EV.E1))
2915                 {
2916                     last = i;
2917                     if (m < emin)
2918                         emin = m;
2919                     if (m > emax)
2920                         emax = m;
2921                 }
2922                 else if (last - first > 2)
2923                     break;
2924                 else
2925                 {
2926                     first = last = i;
2927                     emin = emax = m;
2928                 }
2929             }
2930             else
2931             {
2932                 any = true;
2933                 first = last = i;
2934                 emin = emax = m;
2935             }
2936         }
2937         else if (any && last - first > 2)
2938             break;
2939         else
2940             any = false;
2941     }
2942 
2943     //printf("n = %d, count = %d, min = %d, max = %d\n", cast(int)n, last - first + 1, cast(int)emin, cast(int)emax);
2944     if (any && last - first > 2 && emax - emin < REGSIZE * 8)
2945     {
2946         /**
2947          * Transforms expressions of the form x==c1 || x==c2 || x==c3 || ... into a single
2948          * comparison by using a bitmapped representation of data, as follows. First, the
2949          * smallest constant of c1, c2, ... (call it min) is subtracted from all constants
2950          * and also from x (this step may be elided if all constants are small enough). Then,
2951          * the test is expressed as
2952          *   (1 << (x-min)) | ((1 << (c1-min)) | (1 << (c2-min)) | ...)
2953          * The test is guarded for overflow (x must be no larger than the largest of c1, c2, ...).
2954          * Since each constant is encoded as a displacement in a bitmap, hitting any bit yields
2955          * true for the expression.
2956          *
2957          * I.e. replace:
2958          *   e==c1 || e==c2 || e==c3 ...
2959          * with:
2960          *   (e - emin) <= (emax - emin) && (1 << (int)(e - emin)) & bits
2961          * where bits is:
2962          *   (1<<(c1-emin)) | (1<<(c2-emin)) | (1<<(c3-emin)) ...
2963          *
2964          * For the case of:
2965          *  x!=c1 && x!=c2 && x!=c3 && ...
2966          * using De Morgan's theorem, rewrite as:
2967          *   (e - emin) > (emax - emin) || ((1 << (int)(e - emin)) & ~bits)
2968          */
2969 
2970         // Delete all the || nodes that are no longer referenced
2971         el_opFree(e, op);
2972 
2973         if (emax < 32)                  // if everything fits in a 32 bit register
2974             emin = 0;                   // no need for bias
2975 
2976         // Compute bit mask
2977         targ_ullong bits = 0;
2978         for (size_t i = first; i <= last; ++i)
2979         {
2980             elem *eq = array[i];
2981             if (0 && eq.EV.E2.Eoper != OPconst)
2982             {
2983                 printf("eq = %p, eq.EV.E2 = %p\n", eq, eq.EV.E2);
2984                 printf("first = %d, i = %d, last = %d, Eoper = %d\n", cast(int)first, cast(int)i, cast(int)last, eq.EV.E2.Eoper);
2985                 printf("any = %d, n = %d, count = %d, min = %d, max = %d\n", any, cast(int)n, cast(int)(last - first + 1), cast(int)emin, cast(int)emax);
2986             }
2987             assert(eq.EV.E2.Eoper == OPconst);
2988             bits |= cast(targ_ullong)1 << (el_tolong(eq.EV.E2) - emin);
2989         }
2990         //printf("n = %d, count = %d, min = %d, max = %d\n", cast(int)n, last - first + 1, cast(int)emin, cast(int)emax);
2991         //printf("bits = x%llx\n", bits);
2992 
2993         if (op == OPandand)
2994             bits = ~bits;
2995 
2996         uint tyc = array[first].EV.E1.Ety;
2997 
2998         elem *ex = el_bin(OPmin, tyc, array[first].EV.E1, el_long(tyc,emin));
2999         ex = el_bin(op == OPandand ? OPgt : OPle, TYbool, ex, el_long(touns(tyc), emax - emin));
3000         elem *ey = el_bin(OPmin, tyc, array[first + 1].EV.E1, el_long(tyc,emin));
3001 
3002         tym_t tybits = TYuint;
3003         if ((emax - emin) >= 32)
3004         {
3005             assert(I64);                // need 64 bit BT
3006             tybits = TYullong;
3007         }
3008 
3009         // Shift count must be an int
3010         switch (tysize(tyc))
3011         {
3012             case 1:
3013                 ey = el_una(OPu8_16,TYint,ey);
3014                 goto case 2;
3015 
3016             case 2:
3017                 ey = el_una(OPu16_32,TYint,ey);
3018                 break;
3019 
3020             case 4:
3021                 break;
3022 
3023             case 8:
3024                 ey = el_una(OP64_32,TYint,ey);
3025                 break;
3026 
3027             default:
3028                 assert(0);
3029         }
3030         ey = el_bin(OPbtst,TYbool,el_long(tybits,bits),ey);
3031         ex = el_bin(op == OPandand ? OPoror : OPandand, ty, ex, ey);
3032 
3033         /* Free unneeded nodes
3034          */
3035         array[first].EV.E1 = null;
3036         el_free(array[first]);
3037         array[first + 1].EV.E1 = null;
3038         el_free(array[first + 1]);
3039         for (size_t i = first + 2; i <= last; ++i)
3040             el_free(array[i]);
3041 
3042         array[first] = ex;
3043 
3044         for (size_t i = first + 1; i + (last - first) < n; ++i)
3045             array[i] = array[i + (last - first)];
3046         n -= last - first;
3047         (*pe) = el_opCombine(array, n, op, ty);
3048 
3049         free(array);
3050         return true;
3051     }
3052 
3053     free(array);
3054     return false;
3055 }
3056 
3057 @trusted
3058 private elem * elandand(elem *e, goal_t goal)
3059 {
3060     elem *e1 = e.EV.E1;
3061     if (OTboolnop(e1.Eoper))
3062     {
3063         e.EV.E1 = e1.EV.E1;
3064         e1.EV.E1 = null;
3065         el_free(e1);
3066         return elandand(e, goal);
3067     }
3068     elem *e2 = e.EV.E2;
3069     if (OTboolnop(e2.Eoper))
3070     {
3071         e.EV.E2 = e2.EV.E1;
3072         e2.EV.E1 = null;
3073         el_free(e2);
3074         return elandand(e, goal);
3075     }
3076     if (OPTIMIZER)
3077     {
3078         /* Recognize: (a >= c1 && a < c2)
3079          */
3080         if ((e1.Eoper == OPge || e1.Eoper == OPgt) &&
3081             (e2.Eoper == OPlt || e2.Eoper == OPle) &&
3082             e1.EV.E2.Eoper == OPconst && e2.EV.E2.Eoper == OPconst &&
3083             !el_sideeffect(e1.EV.E1) && el_match(e1.EV.E1, e2.EV.E1) &&
3084             tyintegral(e1.EV.E1.Ety) &&
3085             tybasic(e1.EV.E2.Ety) == tybasic(e2.EV.E2.Ety) &&
3086             tysize(e1.EV.E1.Ety) == _tysize[TYnptr])
3087         {
3088             /* Replace with: ((a - c1) < (c2 - c1))
3089              */
3090             targ_llong c1 = el_tolong(e1.EV.E2);
3091             if (e1.Eoper == OPgt)
3092                 ++c1;
3093             targ_llong c2 = el_tolong(e2.EV.E2);
3094             if (0 <= c1 && c1 <= c2)
3095             {
3096                 e1.Eoper = OPmin;
3097                 e1.Ety = e1.EV.E1.Ety;
3098                 e1.EV.E2.EV.Vllong = c1;
3099                 e.EV.E2 = el_long(touns(e2.EV.E2.Ety), c2 - c1);
3100                 e.Eoper = e2.Eoper;
3101                 el_free(e2);
3102                 return optelem(e, GOALvalue);
3103             }
3104         }
3105 
3106         // Look for (!(e >>> c) && ...)
3107         if (e1.Eoper == OPnot && e1.EV.E1.Eoper == OPshr &&
3108             e1.EV.E1.EV.E2.Eoper == OPconst)
3109         {
3110             // Replace (e >>> c) with (e & x)
3111             elem *e11 = e1.EV.E1;
3112 
3113             targ_ullong shift = el_tolong(e11.EV.E2);
3114             if (shift < _tysize[TYint] * 8)
3115             {
3116                 targ_ullong m;
3117                 m = ~0L << cast(int)shift;
3118                 e11.Eoper = OPand;
3119                 e11.EV.E2.EV.Vullong = m;
3120                 e11.EV.E2.Ety = e11.Ety;
3121                 return optelem(e,GOALvalue);
3122             }
3123         }
3124 
3125         if (e1.Eoper == OPbool)
3126         {
3127             tym_t t = e1.EV.E1.Ety;
3128             e1 = e.EV.E1 = el_selecte1(e1);
3129             e1.Ety = t;
3130         }
3131         if (e1.Eoper == OPandand)
3132         {   // convert (a&&b)&&c to a&&(b&&c). This will find more CSEs.
3133             return swaplog(e, goal);
3134         }
3135         e2 = elscancommas(e2);
3136 
3137         while (1)
3138         {
3139             e1 = elscancommas(e1);
3140             if (e1.Eoper == OPeq)
3141                 e1 = e1.EV.E2;
3142             else
3143                 break;
3144         }
3145     }
3146 
3147     if (e2.Eoper == OPconst || e2.Eoper == OPrelconst || e2.Eoper == OPstring)
3148     {
3149         if (boolres(e2))        // e1 && (x,1)  =>  e1 ? ((x,1),1) : 0
3150         {
3151             if (e2 == e.EV.E2)    // if no x, replace e with (bool e1)
3152             {
3153                 el_free(e2);
3154                 e.EV.E2 = null;
3155                 e.Eoper = OPbool;
3156                 goto L3;
3157             }
3158         }
3159         else                            // e1 && (x,0)  =>  e1 , (x,0)
3160         {
3161             if (e2 == e.EV.E2)
3162             {   e.Eoper = OPcomma;
3163                 goto L3;
3164             }
3165         }
3166     }
3167 
3168   if (e1.Eoper == OPconst || e1.Eoper == OPrelconst || e1.Eoper == OPstring)
3169   {
3170         e.Eoper = OPcomma;
3171         if (boolres(e1))                // (x,1) && e2  =>  (x,1),bool e2
3172         {
3173             if (tybasic(e.EV.E2.Ety) != TYvoid)
3174                 e.EV.E2 = el_una(OPbool,e.Ety,e.EV.E2);
3175         }
3176         else                            // (x,0) && e2  =>  (x,0),0
3177         {
3178             if (tybasic(e.EV.E2.Ety) == TYvoid)
3179             {
3180                 assert(!goal);
3181                 el_free(e);
3182                 return null;
3183             }
3184             else
3185             {
3186                 el_free(e.EV.E2);
3187                 e.EV.E2 = el_long(e.Ety,0);
3188             }
3189         }
3190     }
3191     else
3192         goto L1;
3193 L3:
3194     e = optelem(e,GOALvalue);
3195 L1:
3196     return e;
3197 }
3198 
3199 /**************************
3200  * Reference to bit field
3201  *       bit
3202  *       / \    =>      ((e << c) >> b) & m
3203  *      e  w,b
3204  *
3205  * Note that this routine can handle long bit fields, though this may
3206  * not be supported later on.
3207  */
3208 
3209 @trusted
3210 private elem * elbit(elem *e, goal_t goal)
3211 {
3212     tym_t tym1 = e.EV.E1.Ety;
3213     uint sz = tysize(tym1) * 8;
3214     elem *e2 = e.EV.E2;
3215     uint wb = e2.EV.Vuns;
3216 
3217     uint w = (wb >> 8) & 0xFF;               // width in bits of field
3218     targ_ullong m = (cast(targ_ullong)1 << w) - 1;   // mask w bits wide
3219     uint b = wb & 0xFF;                      // bits to right of field
3220     uint c = 0;
3221     //printf("w %u + b %u <= sz %u\n", w, b, sz);
3222     assert(w + b <= sz);
3223 
3224     if (tyuns(tym1))                      // if uint bit field
3225     {
3226         // Should use a more general solution to this
3227         if (w == 8 && sz == 16 && b == 0)
3228         {
3229             e.EV.E1 = el_una(OP16_8,TYuchar,e.EV.E1);
3230             e.Eoper = OPu8_16;
3231             e.EV.E2 = null;
3232             el_free(e2);
3233             return optelem(e,GOALvalue);         // optimize result
3234         }
3235 
3236         if (w + b == sz)                // if field is left-justified
3237             m = ~cast(targ_ullong)0;    // no need to mask
3238     }
3239     else                                // signed bit field
3240     {
3241         if (w == 8 && sz == 16 && b == 0)
3242         {
3243             e.EV.E1 = el_una(OP16_8,TYschar,e.EV.E1);
3244             e.Eoper = OPs8_16;
3245             e.EV.E2 = null;
3246             el_free(e2);
3247             return optelem(e,GOALvalue);         // optimize result
3248         }
3249         m = ~cast(targ_ullong)0;
3250         c = sz - (w + b);
3251         b = sz - w;
3252     }
3253 
3254     e.Eoper = OPand;
3255 
3256     e2.EV.Vullong = m;                   // mask w bits wide
3257     e2.Ety = e.Ety;
3258 
3259     OPER shift = OPshr;
3260     version (MARS)
3261     {
3262         if (!tyuns(tym1))
3263             shift = OPashr;
3264     }
3265     e.EV.E1 = el_bin(shift,tym1,
3266                 el_bin(OPshl,tym1,e.EV.E1,el_long(TYint,c)),
3267                 el_long(TYint,b));
3268     return optelem(e,GOALvalue);         // optimize result
3269 }
3270 
3271 /*****************
3272  * Indirection
3273  *      * & e => e
3274  */
3275 
3276 @trusted
3277 private elem * elind(elem *e, goal_t goal)
3278 {
3279     tym_t tym = e.Ety;
3280     elem *e1 = e.EV.E1;
3281     switch (e1.Eoper)
3282     {
3283         case OPrelconst:
3284             e.EV.E1.ET = e.ET;
3285             e = el_selecte1(e);
3286             e.Eoper = OPvar;
3287             e.Ety = tym;               /* preserve original type       */
3288             break;
3289 
3290         case OPadd:
3291             if (OPTIMIZER)
3292             {   /* Try to convert far pointer to stack pointer  */
3293                 elem *e12 = e1.EV.E2;
3294 
3295                 if (e12.Eoper == OPrelconst &&
3296                     tybasic(e12.Ety) == TYfptr &&
3297                     /* If symbol is located on the stack        */
3298                     sytab[e12.EV.Vsym.Sclass] & SCSS)
3299                 {   e1.Ety = (e1.Ety & (mTYconst | mTYvolatile | mTYimmutable | mTYshared | mTYLINK)) | TYsptr;
3300                     e12.Ety = (e12.Ety & (mTYconst | mTYvolatile | mTYimmutable | mTYshared | mTYLINK)) | TYsptr;
3301                 }
3302             }
3303             break;
3304 
3305         case OPcomma:
3306             // Replace (*(ea,eb)) with (ea,*eb)
3307             e.EV.E1.ET = e.ET;
3308             type *t = e.ET;
3309             e = el_selecte1(e);
3310             e.Ety = tym;
3311             e.EV.E2 = el_una(OPind,tym,e.EV.E2);
3312             e.EV.E2.ET = t;
3313             again = 1;
3314             return e;
3315 
3316         default:
3317             break;
3318     }
3319     topair |= (config.fpxmmregs && tycomplex(tym));
3320     return e;
3321 }
3322 
3323 /*****************
3324  * Address of.
3325  *      & v => &v
3326  *      & * e => e
3327  *      & (v1 = v2) => ((v1 = v2), &v1)
3328  */
3329 
3330 @trusted
3331 private elem * eladdr(elem *e, goal_t goal)
3332 {
3333     tym_t tym = e.Ety;
3334     elem *e1 = e.EV.E1;
3335     elem_debug(e1);
3336     switch (e1.Eoper)
3337     {
3338         case OPvar:
3339             e1.Eoper = OPrelconst;
3340             e1.EV.Vsym.Sflags &= ~(SFLunambig | GTregcand);
3341             e1.Ety = tym;
3342             e = optelem(el_selecte1(e),GOALvalue);
3343             break;
3344 
3345         case OPind:
3346         {
3347             tym_t tym2 = e1.EV.E1.Ety;
3348 
3349             // Watch out for conversions between near and far pointers
3350             int sz = tysize(tym) - tysize(tym2);
3351             if (sz != 0)
3352             {
3353                 OPER op;
3354                 if (sz > 0)                         // if &far * near
3355                     op = OPnp_fp;
3356                 else                                // else &near * far
3357                     op = OPoffset;
3358                 e.Ety = tym2;
3359                 e = el_una(op,tym,e);
3360                 goto L1;
3361             }
3362 
3363             e = el_selecte1(el_selecte1(e));
3364             e.Ety = tym;
3365             break;
3366         }
3367 
3368         case OPcomma:
3369             // Replace (&(ea,eb)) with (ea,&eb)
3370             e = el_selecte1(e);
3371             e.Ety = tym;
3372             e.EV.E2 = el_una(OPaddr,tym,e.EV.E2);
3373         L1:
3374             e = optelem(e,GOALvalue);
3375             break;
3376 
3377         case OPnegass:
3378             assert(0);
3379 
3380         default:
3381             if (OTassign(e1.Eoper))
3382             {
3383         case OPstreq:
3384                 //  & (v1 = e) => ((v1 = e), &v1)
3385                 if (e1.EV.E1.Eoper == OPvar)
3386                 {
3387                     e.Eoper = OPcomma;
3388                     e.EV.E2 = el_una(OPaddr,tym,el_copytree(e1.EV.E1));
3389                     goto L1;
3390                 }
3391                 //  & (*p1 = e) => ((*(t = p1) = e), t)
3392                 else if (e1.EV.E1.Eoper == OPind)
3393                 {
3394                     const tym_t tym111 = e1.EV.E1.EV.E1.Ety;
3395                     elem *tmp = el_alloctmp(tym111);
3396                     e1.EV.E1.EV.E1 = el_bin(OPeq,tym111,tmp,e1.EV.E1.EV.E1);
3397                     e.Eoper = OPcomma;
3398                     e.EV.E2 = el_copytree(tmp);
3399                     goto L1;
3400                 }
3401             }
3402             break;
3403 
3404         case OPcond:
3405         {   // Replace &(x ? y : z) with (x ? &y : &z)
3406             elem *ecolon = e1.EV.E2;
3407             ecolon.Ety = tym;
3408             ecolon.EV.E1 = el_una(OPaddr,tym,ecolon.EV.E1);
3409             ecolon.EV.E2 = el_una(OPaddr,tym,ecolon.EV.E2);
3410             e = el_selecte1(e);
3411             e = optelem(e,GOALvalue);
3412             break;
3413         }
3414 
3415         case OPinfo:
3416             // Replace &(e1 info e2) with (e1 info &e2)
3417             e = el_selecte1(e);
3418             e.EV.E2 = el_una(OPaddr,tym,e.EV.E2);
3419             e = optelem(e,GOALvalue);
3420             break;
3421     }
3422     return e;
3423 }
3424 
3425 /*******************************************
3426  */
3427 
3428 @trusted
3429 private elem * elneg(elem *e, goal_t goal)
3430 {
3431     if (e.EV.E1.Eoper == OPneg)
3432     {
3433         e = el_selecte1(e);
3434         e = el_selecte1(e);
3435     }
3436     /* Convert -(e1 + c) to (-e1 - c)
3437      */
3438     else if (e.EV.E1.Eoper == OPadd && e.EV.E1.EV.E2.Eoper == OPconst)
3439     {
3440         e.Eoper = OPmin;
3441         e.EV.E2 = e.EV.E1.EV.E2;
3442         e.EV.E1.Eoper = OPneg;
3443         e.EV.E1.EV.E2 = null;
3444         e = optelem(e,goal);
3445     }
3446     else
3447         e = evalu8(e, goal);
3448     return e;
3449 }
3450 
3451 @trusted
3452 private elem * elcall(elem *e, goal_t goal)
3453 {
3454     if (e.EV.E1.Eoper == OPcomma || OTassign(e.EV.E1.Eoper))
3455         e = cgel_lvalue(e);
3456     return e;
3457 }
3458 
3459 /***************************
3460  * Walk tree, converting types to tym.
3461  */
3462 
3463 @trusted
3464 private void elstructwalk(elem *e,tym_t tym)
3465 {
3466     tym_t ety;
3467 
3468     while ((ety = tybasic(e.Ety)) == TYstruct ||
3469            ety == TYarray)
3470     {   elem_debug(e);
3471         e.Ety = (e.Ety & ~mTYbasic) | tym;
3472         switch (e.Eoper)
3473         {
3474             case OPcomma:
3475             case OPcond:
3476             case OPinfo:
3477                 break;
3478 
3479             case OPeq:
3480             case OPcolon:
3481             case OPcolon2:
3482                 elstructwalk(e.EV.E1,tym);
3483                 break;
3484 
3485             default:
3486                 return;
3487         }
3488         e = e.EV.E2;
3489     }
3490 }
3491 
3492 /*******************************
3493  * See if we can replace struct operations with simpler ones.
3494  * For OPstreq and OPstrpar.
3495  */
3496 
3497 @trusted
3498 elem * elstruct(elem *e, goal_t goal)
3499 {
3500     //printf("elstruct(%p)\n", e);
3501     //elem_print(e);
3502     if (e.Eoper == OPstreq && (e.EV.E1.Eoper == OPcomma || OTassign(e.EV.E1.Eoper)))
3503         return cgel_lvalue(e);
3504 
3505     if (e.Eoper == OPstreq && e.EV.E2.Eoper == OPcomma)
3506     {
3507         /* Replace (e1 streq (e21, e22)) with (e21, (e1 streq e22))
3508          */
3509         e.EV.E2.Eoper = e.Eoper;
3510         e.EV.E2.Ety = e.Ety;
3511         e.EV.E2.ET = e.ET;
3512         e.Eoper = OPcomma;
3513         elem *etmp = e.EV.E1;
3514         e.EV.E1 = e.EV.E2.EV.E1;
3515         e.EV.E2.EV.E1 = etmp;
3516         return optelem(e, goal);
3517     }
3518 
3519     if (!e.ET)
3520         return e;
3521     //printf("\tnumbytes = %d\n", cast(int)type_size(e.ET));
3522 
3523     type *t = e.ET;
3524     tym_t tym = ~0;
3525     tym_t ty = tybasic(t.Tty);
3526 
3527     uint sz = (e.Eoper == OPstrpar && type_zeroSize(t, global_tyf)) ? 0 : cast(uint)type_size(t);
3528     //printf("\tsz = %d\n", cast(int)sz);
3529 
3530     type *targ1 = null;
3531     type *targ2 = null;
3532     if (ty == TYstruct)
3533     {   // If a struct is a wrapper for another type, prefer that other type
3534         targ1 = t.Ttag.Sstruct.Sarg1type;
3535         targ2 = t.Ttag.Sstruct.Sarg2type;
3536     }
3537 
3538     if (ty == TYarray && sz && config.exe != EX_WIN64)
3539     {
3540         argtypes(t, targ1, targ2);
3541         if (!targ1)
3542             goto Ldefault;
3543         goto L1;
3544     }
3545     //if (targ1) { printf("targ1\n"); type_print(targ1); }
3546     //if (targ2) { printf("targ2\n"); type_print(targ2); }
3547     switch (cast(int)sz)
3548     {
3549         case 1:  tym = TYchar;   goto L1;
3550         case 2:  tym = TYshort;  goto L1;
3551         case 4:  tym = TYlong;   goto L1;
3552         case 8:  if (_tysize[TYint] == 2)
3553                      goto Ldefault;
3554                  tym = TYllong;  goto L1;
3555 
3556         case 3:  tym = TYlong;  goto L2;
3557         case 5:
3558         case 6:
3559         case 7:  tym = TYllong;
3560         L2:
3561             if (e.Eoper == OPstrpar && config.exe == EX_WIN64)
3562             {
3563                  goto L1;
3564             }
3565             if (I64 && config.exe != EX_WIN64)
3566             {
3567                 goto L1;
3568             }
3569             tym = ~0;
3570             goto Ldefault;
3571 
3572         case 10:
3573         case 12:
3574             if (tysize(TYldouble) == sz && targ1 && !targ2 && tybasic(targ1.Tty) == TYldouble)
3575             {
3576                 tym = TYldouble;
3577                 goto L1;
3578             }
3579             goto case 9;
3580 
3581         case 9:
3582         case 11:
3583         case 13:
3584         case 14:
3585         case 15:
3586             if (I64 && config.exe != EX_WIN64)
3587             {
3588                 goto L1;
3589             }
3590             goto Ldefault;
3591 
3592         case 16:
3593             if (I64 && (ty == TYstruct || (ty == TYarray && config.exe == EX_WIN64)))
3594             {
3595                 tym = TYucent;
3596                 goto L1;
3597             }
3598             if (config.exe == EX_WIN64)
3599                 goto Ldefault;
3600             if (targ1 && !targ2)
3601                 goto L1;
3602             goto Ldefault;
3603 
3604         L1:
3605             if (ty == TYstruct || ty == TYarray)
3606             {
3607                 // This needs to match what TypeFunction::retStyle() does
3608                 if (config.exe == EX_WIN64)
3609                 {
3610                     //if (t.Ttag.Sstruct.Sflags & STRnotpod)
3611                         //goto Ldefault;
3612                 }
3613                 // If a struct is a wrapper for another type, prefer that other type
3614                 else if (targ1 && !targ2)
3615                     tym = targ1.Tty;
3616                 else if (I64 && !targ1 && !targ2)
3617                 {
3618                     if (t.Ttag.Sstruct.Sflags & STRnotpod)
3619                     {
3620                         // In-memory only
3621                         goto Ldefault;
3622                     }
3623 //                    if (type_size(t) == 16)
3624                         goto Ldefault;
3625                 }
3626                 else if (I64 && targ1 && targ2)
3627                 {
3628                     if (tyfloating(tybasic(targ1.Tty)))
3629                         tym = TYcdouble;
3630                     else
3631                         tym = TYucent;
3632                     if ((0 == tyfloating(targ1.Tty)) ^ (0 == tyfloating(targ2.Tty)))
3633                     {
3634                         tym |= tyfloating(targ1.Tty) ? mTYxmmgpr : mTYgprxmm;
3635                     }
3636                 }
3637                 else if (I32 && targ1 && targ2)
3638                 {
3639                     tym = TYllong;
3640                 }
3641                 assert(tym != TYstruct);
3642             }
3643             assert(tym != ~0);
3644             switch (e.Eoper)
3645             {
3646                 case OPstreq:
3647                     if (sz != tysize(tym))
3648                     {
3649                         // we can't optimize OPstreq in this case,
3650                         // there will be memory corruption in the assignment
3651                         elem *e2 = e.EV.E2;
3652                         if (e2.Eoper != OPvar && e2.Eoper != OPind)
3653                         {
3654                             // the source may come in registers. ex: returned from a function.
3655                             assert(tyaggregate(e2.Ety));
3656                             e2 = optelem(e2, GOALvalue);
3657                             e2 = elstruct(e2, GOALvalue);
3658                             e2 = exp2_copytotemp(e2); // (tmp = e2, tmp)
3659                             e2.EV.E2.EV.Vsym.Sfl = FLauto;
3660                             e2.Ety = e2.EV.E2.Ety = e.Ety;
3661                             e2.ET = e2.EV.E2.ET = e.ET;
3662                             e.EV.E2 = e2;
3663                         }
3664                         break;
3665                     }
3666                     e.Eoper = OPeq;
3667                     e.Ety = (e.Ety & ~mTYbasic) | tym;
3668                     elstructwalk(e.EV.E1,tym);
3669                     elstructwalk(e.EV.E2,tym);
3670                     e = optelem(e,GOALvalue);
3671                     break;
3672 
3673                 case OPstrpar:
3674                     e = el_selecte1(e);
3675                     goto default;
3676 
3677                 default:                /* called by doptelem()         */
3678                     elstructwalk(e,tym);
3679                     break;
3680             }
3681             break;
3682 
3683         case 0:
3684             if (e.Eoper == OPstreq)
3685             {
3686                 e.Eoper = OPcomma;
3687                 e = optelem(e,GOALvalue);
3688                 again = 1;
3689             }
3690             else
3691                 goto Ldefault;
3692             break;
3693 
3694         default:
3695         Ldefault:
3696         {
3697             elem **pe2;
3698             if (e.Eoper == OPstreq)
3699                 pe2 = &e.EV.E2;
3700             else if (e.Eoper == OPstrpar)
3701                 pe2 = &e.EV.E1;
3702             else
3703                 break;
3704             while ((*pe2).Eoper == OPcomma)
3705                 pe2 = &(*pe2).EV.E2;
3706             elem *e2 = *pe2;
3707 
3708             if (e2.Eoper == OPvar)
3709                 e2.EV.Vsym.Sflags &= ~GTregcand;
3710 
3711             // Convert (x streq (a?y:z)) to (x streq *(a ? &y : &z))
3712             if (e2.Eoper == OPcond)
3713             {
3714                 tym_t ty2 = e2.Ety;
3715 
3716                 /* We should do the analysis to see if we can use
3717                    something simpler than TYfptr.
3718                  */
3719                 tym_t typ = (_tysize[TYint] == LONGSIZE) ? TYnptr : TYfptr;
3720                 e2 = el_una(OPaddr,typ,e2);
3721                 e2 = optelem(e2,GOALvalue);          /* distribute & to x and y leaves */
3722                 *pe2 = el_una(OPind,ty2,e2);
3723                 break;
3724             }
3725             break;
3726         }
3727     }
3728     //printf("elstruct return\n");
3729     //elem_print(e);
3730     return e;
3731 }
3732 
3733 /**************************
3734  * Assignment. Replace bit field assignment with
3735  * equivalent tree.
3736  *              =
3737  *            /  \
3738  *           /    r
3739  *        bit
3740  *       /   \
3741  *      l     w,b
3742  *
3743  * becomes:
3744  *          ,
3745  *         / \
3746  *        =   (r&m)
3747  *       / \
3748  *      l   |
3749  *         / \
3750  *  (r&m)<<b  &
3751  *           / \
3752  *          l  ~(m<<b)
3753  * Note:
3754  *      This depends on the expression (r&m)<<b before l. This is because
3755  *      of expressions like (l.a = l.b = n). It is an artifact of the way
3756  *      we do things that this works (cost() will rate the << as more
3757  *      expensive than the &, and so it will wind up on the left).
3758  */
3759 
3760 @trusted
3761 private elem * eleq(elem *e, goal_t goal)
3762 {
3763     goal_t wantres = goal;
3764     elem *e1 = e.EV.E1;
3765 
3766     if (e1.Eoper == OPcomma || OTassign(e1.Eoper))
3767         return cgel_lvalue(e);
3768 
3769 static if (0)  // Doesn't work too well, removed
3770 {
3771     // Replace (*p++ = e2) with ((*p = e2),*p++)
3772     if (OPTIMIZER && e1.Eoper == OPind &&
3773       (e1.EV.E1.Eoper == OPpostinc || e1.EV.E1.Eoper == OPpostdec) &&
3774       !el_sideeffect(e1.EV.E1.EV.E1)
3775        )
3776     {
3777         e = el_bin(OPcomma,e.Ety,e,e1);
3778         e.EV.E1.EV.E1 = el_una(OPind,e1.Ety,el_copytree(e1.EV.E1.EV.E1));
3779         return optelem(e,GOALvalue);
3780     }
3781 }
3782 
3783     if (OPTIMIZER)
3784     {
3785         elem *e2 = e.EV.E2;
3786         int op2 = e2.Eoper;
3787 
3788         // Replace (e1 = *p++) with (e1 = *p, p++, e1)
3789         elem *ei = e2;
3790         if (e1.Eoper == OPvar &&
3791             (op2 == OPind || (OTunary(op2) && (ei = e2.EV.E1).Eoper == OPind)) &&
3792             (ei.EV.E1.Eoper == OPpostinc || ei.EV.E1.Eoper == OPpostdec) &&
3793             !el_sideeffect(e1) &&
3794             !el_sideeffect(ei.EV.E1.EV.E1)
3795            )
3796         {
3797            e = el_bin(OPcomma,e.Ety,
3798                 e,
3799                 el_bin(OPcomma,e.Ety,ei.EV.E1,el_copytree(e1)));
3800            ei.EV.E1 = el_copytree(ei.EV.E1.EV.E1);            // copy p
3801            return optelem(e,GOALvalue);
3802         }
3803 
3804         /* Replace (e = e) with (e,e)   */
3805         if (el_match(e1,e2))
3806         {
3807             e.Eoper = OPcomma;
3808         L1:
3809             return optelem(e,GOALvalue);
3810         }
3811 
3812         // Replace (e1 = (e21 , e22)) with (e21 , (e1 = e22))
3813         if (op2 == OPcomma)
3814         {
3815             e2.Ety = e.Ety;
3816             e.EV.E2 = e2.EV.E2;
3817             e2.EV.E2 = e;
3818             e = e2;
3819             goto L1;
3820         }
3821 
3822         if (OTop(op2) && !el_sideeffect(e1)
3823             && op2 != OPdiv && op2 != OPmod
3824            )
3825         {
3826             tym_t ty;
3827 
3828             version (MARS)
3829                 enum side = false; // don't allow side effects in e2.EV.E2 because of
3830                                    // D order-of-evaluation rules
3831             else
3832                 enum side = true;  // ok in C and C++
3833 
3834             // Replace (e1 = e1 op e) with (e1 op= e)
3835             if (el_match(e1,e2.EV.E1) &&
3836                 (side || !el_sideeffect(e2.EV.E2)))
3837             {
3838                 ty = e2.EV.E2.Ety;
3839                 e.EV.E2 = el_selecte2(e2);
3840             L2:
3841                 e.EV.E2.Ety = ty;
3842                 e.Eoper = cast(ubyte)optoopeq(op2);
3843                 goto L1;
3844             }
3845             if (OTcommut(op2))
3846             {
3847                 /* Replace (e1 = e op e1) with (e1 op= e)       */
3848                 if (el_match(e1,e2.EV.E2))
3849                 {   ty = e2.EV.E1.Ety;
3850                     e.EV.E2 = el_selecte1(e2);
3851                     goto L2;
3852                 }
3853             }
3854 
3855 static if (0)
3856 {
3857 // Note that this optimization is undone in elcomma(), this results in an
3858 // infinite loop. This optimization is preferable if e1 winds up a register
3859 // variable, the inverse in elcomma() is preferable if e1 winds up in memory.
3860             // Replace (e1 = (e1 op3 ea) op2 eb) with (e1 op3= ea),(e1 op2= eb)
3861             int op3 = e2.EV.E1.Eoper;
3862             if (OTop(op3) && el_match(e1,e2.EV.E1.EV.E1) && !el_depends(e1,e2.EV.E2))
3863             {
3864                 e.Eoper = OPcomma;
3865                 e.EV.E1 = e2.EV.E1;
3866                 e.EV.E1.Eoper = optoopeq(op3);
3867                 e2.EV.E1 = e1;
3868                 e1.Ety = e.EV.E1.Ety;
3869                 e2.Eoper = optoopeq(op2);
3870                 e2.Ety = e.Ety;
3871                 goto L1;
3872             }
3873 }
3874         }
3875 
3876         if (op2 == OPneg && el_match(e1,e2.EV.E1) && !el_sideeffect(e1))
3877         {
3878             // Replace (i = -i) with (negass i)
3879             e.Eoper = OPnegass;
3880             e.EV.E2 = null;
3881             el_free(e2);
3882             return optelem(e, GOALvalue);
3883         }
3884 
3885         // Replace (x = (y ? z : x)) with ((y && (x = z)),x)
3886         if (op2 == OPcond && el_match(e1,e2.EV.E2.EV.E2))
3887         {
3888             elem *e22 = e2.EV.E2;         // e22 is the OPcond
3889             e.Eoper = OPcomma;
3890             e.EV.E2 = e1;
3891             e.EV.E1 = e2;
3892             e2.Eoper = OPandand;
3893             e2.Ety = TYint;
3894             e22.Eoper = OPeq;
3895             e22.Ety = e.Ety;
3896             e1 = e22.EV.E1;
3897             e22.EV.E1 = e22.EV.E2;
3898             e22.EV.E2 = e1;
3899             return optelem(e,GOALvalue);
3900         }
3901 
3902         // Replace (x = (y ? x : z)) with ((y || (x = z)),x)
3903         if (op2 == OPcond && el_match(e1,e2.EV.E2.EV.E1))
3904         {
3905             elem *e22 = e2.EV.E2;         // e22 is the OPcond
3906             e.Eoper = OPcomma;
3907             e.EV.E2 = e1;
3908             e.EV.E1 = e2;
3909             e2.Eoper = OPoror;
3910             e2.Ety = TYint;
3911             e22.Eoper = OPeq;
3912             e22.Ety = e.Ety;
3913             return optelem(e,GOALvalue);
3914         }
3915 
3916         // If floating point, replace (x = -y) with (x = y ^ signbit)
3917         if (op2 == OPneg && (tyreal(e2.Ety) || tyimaginary(e2.Ety)) &&
3918             (e2.EV.E1.Eoper == OPvar || e2.EV.E1.Eoper == OPind) &&
3919            /* Turned off for XMM registers because they don't play well with
3920             * int registers.
3921             */
3922            !config.fpxmmregs)
3923         {
3924             tym_t ty;
3925 
3926             elem *es = el_calloc();
3927             es.Eoper = OPconst;
3928             switch (tysize(e2.Ety))
3929             {
3930                 case FLOATSIZE:
3931                     ty = TYlong;
3932                     es.EV.Vlong = 0x80000000;
3933                     break;
3934 
3935                 case DOUBLESIZE:
3936                     if (I32)
3937                     {
3938                         ty = TYllong;
3939                         es.EV.Vllong = 0x8000000000000000L;
3940                         break;
3941                     }
3942                     goto default;
3943 
3944                 default:
3945                     el_free(es);
3946                     goto L8;
3947             }
3948             es.Ety = ty;
3949             e1.Ety = ty;
3950             e2.Ety = ty;
3951             e2.EV.E1.Ety = ty;
3952             e2.EV.E2 = es;
3953             e2.Eoper = OPxor;
3954             return optelem(e,GOALvalue);
3955 
3956         L8:
3957         }
3958 
3959         // Replace (a=(r1 pair r2)) with (a1=r1), (a2=r2)
3960         if (tysize(e1.Ety) == 2 * REGSIZE &&
3961             e1.Eoper == OPvar &&
3962             (e2.Eoper == OPpair || e2.Eoper == OPrpair) &&
3963             goal == GOALnone &&
3964             !el_appears(e2, e1.EV.Vsym) &&
3965 // this clause needs investigation because the code doesn't match the comment
3966             // Disable this rewrite if we're using x87 and `e1` is a FP-value
3967             // but `e2` is not, or vice versa
3968             // https://issues.dlang.org/show_bug.cgi?id=18197
3969             (config.fpxmmregs ||
3970              (tyfloating(e2.EV.E1.Ety) != 0) == (tyfloating(e2.Ety) != 0))
3971            )
3972         {
3973             // printf("** before:\n"); elem_print(e); printf("\n");
3974             tym_t ty = (REGSIZE == 8) ? TYllong : TYint;
3975             if (tyfloating(e1.Ety) && REGSIZE >= 4)
3976                 ty = (REGSIZE == 8) ? TYdouble : TYfloat;
3977             ty |= e1.Ety & ~mTYbasic;
3978             e2.Ety = ty;
3979             e.Ety = ty;
3980             e1.Ety = ty;
3981             elem *eb = el_copytree(e1);
3982             eb.EV.Voffset += REGSIZE;
3983 
3984             if (e2.Eoper == OPpair)
3985             {
3986                 e.EV.E2 = e2.EV.E1;
3987                 eb = el_bin(OPeq,ty,eb,e2.EV.E2);
3988                 e2.EV.E1 = e;
3989                 e2.EV.E2 = eb;
3990             }
3991             else
3992             {
3993                 e.EV.E2 = e2.EV.E2;
3994                 eb = el_bin(OPeq,ty,eb,e2.EV.E1);
3995                 e2.EV.E1 = eb;
3996                 e2.EV.E2 = e;
3997             }
3998 
3999             e2.Eoper = OPcomma;
4000             // printf("** after:\n"); elem_print(e2); printf("\n");
4001             return optelem(e2,goal);
4002         }
4003 
4004         // Replace (a=b) with (a1=b1),(a2=b2)
4005         if (tysize(e1.Ety) == 2 * REGSIZE &&
4006             e1.Eoper == OPvar &&
4007             e2.Eoper == OPvar &&
4008             goal == GOALnone &&
4009             !tyfloating(e1.Ety) && !tyvector(e1.Ety)
4010            )
4011         {
4012             tym_t ty = (REGSIZE == 8) ? TYllong : TYint;
4013             ty |= e1.Ety & ~mTYbasic;
4014             e2.Ety = ty;
4015             e.Ety = ty;
4016             e1.Ety = ty;
4017 
4018             elem *eb = el_copytree(e);
4019             eb.EV.E1.EV.Voffset += REGSIZE;
4020             eb.EV.E2.EV.Voffset += REGSIZE;
4021 
4022             e = el_bin(OPcomma,ty,e,eb);
4023             return optelem(e,goal);
4024         }
4025     }
4026 
4027    if (e1.Eoper == OPcomma)
4028         return cgel_lvalue(e);
4029   if (e1.Eoper != OPbit)
4030         return e;
4031   if (e1.EV.E1.Eoper == OPcomma || OTassign(e1.EV.E1.Eoper))
4032         return cgel_lvalue(e);
4033 
4034     uint t = e.Ety;
4035     elem *l = e1.EV.E1;                           // lvalue
4036     elem *r = e.EV.E2;
4037     tym_t tyl = l.Ety;
4038     uint sz = tysize(tyl) * 8;
4039     uint w = (e1.EV.E2.EV.Vuns >> 8);        // width in bits of field
4040     targ_ullong m = (cast(targ_ullong)1 << w) - 1;  // mask w bits wide
4041     uint b = e1.EV.E2.EV.Vuns & 0xFF;        // bits to shift
4042 
4043     elem *l2;
4044     elem *r2;
4045     elem *eres =  el_bin(OPeq,t,
4046                 l,
4047                 el_bin(OPor,t,
4048                         el_bin(OPshl,t,
4049                                 (r2 = el_bin(OPand,t,r,el_long(t,m))),
4050                                 el_long(TYint,b)
4051                         ),
4052                         el_bin(OPand,t,
4053                                 (l2 = el_copytree(l)),
4054                                 el_long(t,~(m << b))
4055                         )
4056                 )
4057           );
4058     eres.Esrcpos = e.Esrcpos;           // save line information
4059     if (OPTIMIZER && w + b == sz)
4060         r2.EV.E2.EV.Vllong = ~ZEROLL;    // no need to mask if left justified
4061     if (wantres)
4062     {
4063         uint c;
4064         elem **pe;
4065         elem *e2;
4066 
4067         r = el_copytree(r);
4068         if (tyuns(tyl))                 /* uint bit field           */
4069         {
4070             e2 = el_bin(OPand,t,r,el_long(t,m));
4071             pe = &e2.EV.E1;
4072         }
4073         else                            /* signed bit field             */
4074         {
4075             OPER shift = OPshr;
4076             version (MARS)
4077             {
4078                 shift = OPashr;
4079             }
4080             c = sz - w;                 /* e2 = (r << c) >> c           */
4081             e2 = el_bin(shift,t,el_bin(OPshl,tyl,r,el_long(TYint,c)),el_long(TYint,c));
4082             pe = &e2.EV.E1.EV.E1;
4083         }
4084         eres = el_bin(OPcomma,t,eres,e2);
4085         if (!OTleaf(r.Eoper))
4086             fixside(&(r2.EV.E1),pe);
4087     }
4088 
4089     if (!OTleaf(l.Eoper) && !OTleaf(l.EV.E1.Eoper))
4090         fixside(&(l2.EV.E1),&(l.EV.E1));
4091     e1.EV.E1 = e.EV.E2 = null;
4092     el_free(e);
4093     return optelem(eres,GOALvalue);
4094 }
4095 
4096 /**********************************
4097  */
4098 
4099 private elem * elnegass(elem *e, goal_t goal)
4100 {
4101     e = cgel_lvalue(e);
4102     return e;
4103 }
4104 
4105 /**************************
4106  * Add assignment. Replace bit field assignment with
4107  * equivalent tree.
4108  *             +=
4109  *            /  \
4110  *           /    r
4111  *        bit
4112  *       /   \
4113  *      l     w,b
4114  *
4115  * becomes:
4116  *                   =
4117  *                  / \
4118  *                 l   |
4119  *                    / \
4120  *                  <<   \
4121  *                 /  \   \
4122  *                &    b   &
4123  *               / \      / \
4124  *             op   m    l   ~(m<<b)
4125  *            /  \
4126  *           &    r
4127  *          / \
4128  *        >>   m
4129  *       /  \
4130  *      l    b
4131  */
4132 
4133 @trusted
4134 private elem * elopass(elem *e, goal_t goal)
4135 {
4136     elem *e1 = e.EV.E1;
4137     if (OTconv(e1.Eoper))
4138     {   e = fixconvop(e);
4139         return optelem(e,GOALvalue);
4140     }
4141 
4142     goal_t wantres = goal;
4143     if (e1.Eoper == OPbit)
4144     {
4145         const op = opeqtoop(e.Eoper);
4146 
4147         // Make sure t is uint
4148         // so >> doesn't have to be masked
4149         tym_t t = touns(e.Ety);
4150 
4151         assert(tyintegral(t));
4152         elem *l = e1.EV.E1;                       // lvalue
4153         tym_t tyl = l.Ety;
4154         elem *r = e.EV.E2;
4155         uint w = (e1.EV.E2.EV.Vuns >> 8) & 0xFF; // width in bits of field
4156         targ_llong m = (cast(targ_llong)1 << w) - 1;    // mask w bits wide
4157         uint b = e1.EV.E2.EV.Vuns & 0xFF;        // bits to shift
4158 
4159         elem* l2,l3,op2,eres;
4160 
4161         if (tyuns(tyl))
4162         {
4163             eres = el_bin(OPeq,t,
4164                     l,
4165                     el_bin(OPor,t,
4166                             (op2=el_bin(OPshl,t,
4167                                     el_bin(OPand,t,
4168                                             el_bin(op,t,
4169                                                     el_bin(OPand,t,
4170                                                         el_bin(OPshr,t,
4171                                                             (l2=el_copytree(l)),
4172                                                             el_long(TYint,b)
4173                                                         ),
4174                                                         el_long(t,m)
4175                                                     ),
4176                                                     r
4177                                             ),
4178                                             el_long(t,m)
4179                                     ),
4180                                     el_long(TYint,b)
4181                             )),
4182                             el_bin(OPand,t,
4183                                     l3=el_copytree(l),
4184                                     el_long(t,~(m << b))
4185                             )
4186                     )
4187                 );
4188 
4189             if (wantres)
4190             {
4191                 eres = el_bin(OPcomma,t,eres,el_copytree(op2.EV.E1));
4192                 fixside(&(op2.EV.E1),&(eres.EV.E2));
4193             }
4194         }
4195         else
4196         {   /* signed bit field
4197                rewrite to:      (l bit w,b) = ((l bit w,b) op r)
4198              */
4199             e.Eoper = OPeq;
4200             e.EV.E2 = el_bin(op,t,el_copytree(e1),r);
4201             if (l.Eoper == OPind)
4202                 fixside(&e.EV.E2.EV.E1.EV.E1.EV.E1,&l.EV.E1);
4203             eres = e;
4204             goto ret;
4205         }
4206 
4207         if (!OTleaf(l.Eoper) && !OTleaf(l.EV.E1.Eoper))
4208         {
4209             fixside(&(l2.EV.E1),&(l.EV.E1));
4210             el_free(l3.EV.E1);
4211             l3.EV.E1 = el_copytree(l.EV.E1);
4212         }
4213 
4214         e1.EV.E1 = e.EV.E2 = null;
4215         el_free(e);
4216     ret:
4217         e = optelem(eres,GOALvalue);
4218         return e;
4219     }
4220 
4221     {
4222         if (e1.Eoper == OPcomma || OTassign(e1.Eoper))
4223             e = cgel_lvalue(e);    // replace (e,v)op=e2 with e,(v op= e2)
4224         else
4225         {
4226             switch (e.Eoper)
4227             {
4228                 case OPmulass:
4229                     e = elmul(e,GOALvalue);
4230                     break;
4231 
4232                 case OPdivass:
4233                     // Replace r/=c with r=r/c
4234                     if (tycomplex(e.EV.E2.Ety) && !tycomplex(e1.Ety))
4235                     {
4236                         elem *ed;
4237                         e.Eoper = OPeq;
4238                         if (e1.Eoper == OPind)
4239                         {   // ed: *(tmp=e1.EV.E1)
4240                             // e1: *tmp
4241                             elem *tmp = el_alloctmp(e1.EV.E1.Ety);
4242                             ed = el_bin(OPeq, tmp.Ety, tmp, e1.EV.E1);
4243                             e1.EV.E1 = el_copytree(tmp);
4244                             ed = el_una(OPind, e1.Ety, ed);
4245                         }
4246                         else
4247                             ed = el_copytree(e1);
4248                         // e: e1=ed/e2
4249                         e.EV.E2 = el_bin(OPdiv, e.EV.E2.Ety, ed, e.EV.E2);
4250                         if (tyreal(e1.Ety))
4251                             e.EV.E2 = el_una(OPc_r, e1.Ety, e.EV.E2);
4252                         else
4253                             e.EV.E2 = el_una(OPc_i, e1.Ety, e.EV.E2);
4254                         return optelem(e, GOALvalue);
4255                     }
4256                     // Replace x/=y with x=x/y
4257                     if (OPTIMIZER &&
4258                         tyintegral(e.EV.E1.Ety) &&
4259                         e.EV.E1.Eoper == OPvar &&
4260                         !el_sideeffect(e.EV.E1))
4261                     {
4262                         e.Eoper = OPeq;
4263                         e.EV.E2 = el_bin(OPdiv, e.EV.E2.Ety, el_copytree(e.EV.E1), e.EV.E2);
4264                         return optelem(e, GOALvalue);
4265                     }
4266                     e = eldiv(e, GOALvalue);
4267                     break;
4268 
4269                 case OPmodass:
4270                     // Replace x%=y with x=x%y
4271                     if (OPTIMIZER &&
4272                         tyintegral(e.EV.E1.Ety) &&
4273                         e.EV.E1.Eoper == OPvar &&
4274                         !el_sideeffect(e.EV.E1))
4275                     {
4276                         e.Eoper = OPeq;
4277                         e.EV.E2 = el_bin(OPmod, e.EV.E2.Ety, el_copytree(e.EV.E1), e.EV.E2);
4278                         return optelem(e, GOALvalue);
4279                     }
4280                     break;
4281 
4282                 default:
4283                     break;
4284             }
4285         }
4286     }
4287     return e;
4288 }
4289 
4290 /**************************
4291  * Add assignment. Replace bit field post assignment with
4292  * equivalent tree.
4293  *      (l bit w,b) ++ r
4294  * becomes:
4295  *      (((l bit w,b) += r) - r) & m
4296  */
4297 
4298 @trusted
4299 private elem * elpost(elem *e, goal_t goal)
4300 {
4301     elem *e1 = e.EV.E1;
4302     if (e1.Eoper != OPbit)
4303     {
4304         if (e1.Eoper == OPcomma || OTassign(e1.Eoper))
4305             return cgel_lvalue(e);    // replace (e,v)op=e2 with e,(v op= e2)
4306         return e;
4307     }
4308 
4309     assert(e.EV.E2.Eoper == OPconst);
4310     targ_llong r = el_tolong(e.EV.E2);
4311 
4312     uint w = (e1.EV.E2.EV.Vuns >> 8) & 0xFF;  // width in bits of field
4313     targ_llong m = (cast(targ_llong)1 << w) - 1;     // mask w bits wide
4314 
4315     tym_t ty = e.Ety;
4316     if (e.Eoper != OPpostinc)
4317         r = -r;
4318     e.Eoper = (e.Eoper == OPpostinc) ? OPaddass : OPminass;
4319     e = el_bin(OPmin,ty,e,el_long(ty,r));
4320     if (tyuns(e1.EV.E1.Ety))             /* if uint bit field        */
4321         e = el_bin(OPand,ty,e,el_long(ty,m));
4322     return optelem(e,GOALvalue);
4323 }
4324 
4325 /***************************
4326  * Take care of compares.
4327  *      (e == 0) => (!e)
4328  *      (e != 0) => (bool e)
4329  */
4330 
4331 @trusted
4332 private elem * elcmp(elem *e, goal_t goal)
4333 {
4334     elem *e2 = e.EV.E2;
4335     elem *e1 = e.EV.E1;
4336 
4337     //printf("elcmp(%p)\n",e); elem_print(e);
4338 
4339     if (tyvector(e1.Ety))       // vectors don't give boolean result
4340         return e;
4341 
4342     if (OPTIMIZER)
4343     {
4344         auto op = e.Eoper;
4345 
4346         // Convert comparison of OPrelconsts of the same symbol to comparisons
4347         // of their offsets.
4348         if (e1.Eoper == OPrelconst && e2.Eoper == OPrelconst &&
4349             e1.EV.Vsym == e2.EV.Vsym)
4350         {
4351             e1.Eoper = OPconst;
4352             e1.Ety = TYptrdiff;
4353             e2.Eoper = OPconst;
4354             e2.Ety = TYptrdiff;
4355             return optelem(e,GOALvalue);
4356         }
4357 
4358         // Convert comparison of long pointers to comparison of integers
4359         if ((op == OPlt || op == OPle || op == OPgt || op == OPge) &&
4360             tyfv(e2.Ety) && tyfv(e1.Ety))
4361         {
4362             e.EV.E1 = el_una(OP32_16,e.Ety,e1);
4363             e.EV.E2 = el_una(OP32_16,e.Ety,e2);
4364             return optelem(e,GOALvalue);
4365         }
4366 
4367         // Convert ((e & 1) == 1) => (e & 1)
4368         if (op == OPeqeq && e2.Eoper == OPconst && e1.Eoper == OPand)
4369         {
4370             elem *e12 = e1.EV.E2;
4371 
4372             if (e12.Eoper == OPconst && el_tolong(e2) == 1 && el_tolong(e12) == 1)
4373             {
4374                 tym_t ty = e.Ety;
4375                 tym_t ty1 = e1.Ety;
4376                 e = el_selecte1(e);
4377                 e.Ety = ty1;
4378                 int sz = tysize(ty);
4379                 for (int sz1 = tysize(ty1); sz1 != sz; sz1 = tysize(e.Ety))
4380                 {
4381                     switch (sz1)
4382                     {
4383                         case 1:
4384                             e = el_una(OPu8_16,TYshort,e);
4385                             break;
4386                         case 2:
4387                             if (sz > 2)
4388                                 e = el_una(OPu16_32,TYlong,e);
4389                             else
4390                                 e = el_una(OP16_8,TYuchar,e);
4391                             break;
4392                         case 4:
4393                             if (sz > 2)
4394                                 e = el_una(OPu32_64,TYshort,e);
4395                             else
4396                                 e = el_una(OP32_16,TYshort,e);
4397                             break;
4398                         case 8:
4399                             e = el_una(OP64_32,TYlong,e);
4400                             break;
4401                         default:
4402                             assert(0);
4403                     }
4404                 }
4405                 e.Ety = ty;
4406                 return optelem(e,GOALvalue);
4407             }
4408         }
4409     }
4410 
4411     int uns = tyuns(e1.Ety) | tyuns(e2.Ety);
4412     if (cnst(e2))
4413     {
4414         tym_t tym;
4415         int sz = tysize(e2.Ety);
4416 
4417         if (e1.Eoper == OPu16_32 && e2.EV.Vulong <= cast(targ_ulong) SHORTMASK ||
4418             e1.Eoper == OPs16_32 &&
4419             e2.EV.Vlong == cast(targ_short) e2.EV.Vlong)
4420         {
4421             tym = (uns || e1.Eoper == OPu16_32) ? TYushort : TYshort;
4422             e.EV.E2 = el_una(OP32_16,tym,e2);
4423             goto L2;
4424         }
4425 
4426         /* Try to convert to byte/word comparison for ((x & c)==d)
4427            when mask c essentially casts x to a smaller type
4428          */
4429         if (OPTIMIZER &&
4430             e1.Eoper == OPand &&
4431             e1.EV.E2.Eoper == OPconst &&
4432             sz > CHARSIZE)
4433         {
4434             OPER op;
4435             assert(tyintegral(e2.Ety) || typtr(e2.Ety));
4436             /* ending up with byte ops in A regs */
4437             if (!(el_tolong(e2) & ~CHARMASK) &&
4438                 !(el_tolong(e1.EV.E2) & ~CHARMASK)
4439                )
4440             {
4441                 if (sz == LLONGSIZE)
4442                 {
4443                     e1.EV.E1 = el_una(OP64_32,TYulong,e1.EV.E1);
4444                     e1.EV.E1 = el_una(OP32_16,TYushort,e1.EV.E1);
4445                 }
4446                 else if (sz == LONGSIZE)
4447                     e1.EV.E1 = el_una(OP32_16,TYushort,e1.EV.E1);
4448                 tym = TYuchar;
4449                 op = OP16_8;
4450                 goto L4;
4451             }
4452             if (_tysize[TYint] == SHORTSIZE && /* not a win when regs are long */
4453                 sz == LONGSIZE &&
4454                 !(e2.EV.Vulong & ~SHORTMASK) &&
4455                 !(e1.EV.E2.EV.Vulong & ~SHORTMASK)
4456                )
4457             {
4458                 tym = TYushort;
4459                 op = OP32_16;
4460             L4:
4461                 e2.Ety = tym;
4462                 e1.Ety = tym;
4463                 e1.EV.E2.Ety = tym;
4464                 e1.EV.E1 = el_una(op,tym,e1.EV.E1);
4465                 e = optelem(e,GOALvalue);
4466                 goto ret;
4467             }
4468         }
4469 
4470         if (e1.Eoper == OPf_d && tysize(e1.Ety) == 8 && cast(targ_float)e2.EV.Vdouble == e2.EV.Vdouble)
4471         {
4472             /* Remove unnecessary OPf_d operator
4473              */
4474             e.EV.E1 = e1.EV.E1;
4475             e1.EV.E1 = null;
4476             el_free(e1);
4477             e2.Ety = e.EV.E1.Ety;
4478             e2.EV.Vfloat = cast(targ_float)e2.EV.Vdouble;
4479             return optelem(e,GOALvalue);
4480         }
4481 
4482         if (e1.Eoper == OPd_ld && tysize(e1.Ety) == tysize(TYldouble) && cast(targ_double)e2.EV.Vldouble == e2.EV.Vldouble)
4483         {
4484             /* Remove unnecessary OPd_ld operator
4485              */
4486             e.EV.E1 = e1.EV.E1;
4487             e1.EV.E1 = null;
4488             el_free(e1);
4489             e2.Ety = e.EV.E1.Ety;
4490             e2.EV.Vdouble = cast(targ_double)e2.EV.Vldouble;
4491             return optelem(e,GOALvalue);
4492         }
4493 
4494         /* Convert (ulong > uint.max) to (msw(ulong) != 0)
4495          */
4496         if (OPTIMIZER && I32 && e.Eoper == OPgt && sz == LLONGSIZE && e2.EV.Vullong == 0xFFFFFFFF)
4497         {
4498             e.Eoper = OPne;
4499             e2.Ety = TYulong;
4500             e2.EV.Vulong = 0;
4501             e.EV.E1 = el_una(OPmsw,TYulong,e1);
4502             e = optelem(e,GOALvalue);
4503             goto ret;
4504         }
4505 
4506         if (e1.Eoper == OPu8_16 && e2.EV.Vuns < 256 ||
4507             e1.Eoper == OPs8_16 &&
4508             e2.EV.Vint == cast(targ_schar) e2.EV.Vint)
4509         {
4510             tym = (uns || e1.Eoper == OPu8_16) ? TYuchar : TYschar;
4511             e.EV.E2 = el_una(OP16_8,tym,e2);
4512         L2:
4513             tym |= e1.Ety & ~mTYbasic;
4514             e.EV.E1 = el_selecte1(e1);
4515             e.EV.E1.Ety = tym;
4516             e = optelem(e,GOALvalue);
4517         }
4518         else if (!boolres(e2))
4519         {
4520             targ_int i;
4521             switch (e.Eoper)
4522             {
4523                 case OPle:              // (u <= 0) becomes (u == 0)
4524                     if (!uns)
4525                         break;
4526                     goto case OPeqeq;
4527 
4528                 case OPeqeq:
4529                     e.Eoper = OPnot;
4530                     goto L5;
4531 
4532                 case OPgt:              // (u > 0) becomes (u != 0)
4533                     if (!uns)
4534                         break;
4535                     goto case OPne;
4536 
4537                 case OPne:
4538                     e.Eoper = OPbool;
4539                 L5: el_free(e2);
4540                     e.EV.E2 = null;
4541                     e = optelem(e,GOALvalue);
4542                     break;
4543 
4544                 case OPge:
4545                     i = 1;              // (u >= 0) becomes (u,1)
4546                     goto L3;
4547 
4548                 case OPlt:              // (u < 0) becomes (u,0)
4549                     i = 0;
4550                 L3:
4551                     if (uns)
4552                     {
4553                         e2.EV.Vint = i;
4554                         e2.Ety = TYint;
4555                         e.Eoper = OPcomma;
4556                         e = optelem(e,GOALvalue);
4557                     }
4558                     else
4559                     {
4560                         if (tyintegral(e1.Ety) && sz == 2 * REGSIZE)
4561                         {
4562                             // Only need to examine MSW
4563                             tym_t ty = sz == 4 ? TYint :
4564                                        sz == 8 ? TYint :
4565                                                  TYlong;        // for TYcent's
4566                             e.EV.E1 = el_una(OPmsw, ty, e1);
4567                             e2.Ety = ty;
4568                             return optelem(e, GOALvalue);
4569                         }
4570                     }
4571                     break;
4572 
4573                 default:
4574                     break;
4575             }
4576         }
4577         else if (OPTIMIZER && uns && tysize(e2.Ety) == 2 &&
4578                  cast(ushort)e2.EV.Vuns == 0x8000 &&
4579                  (e.Eoper == OPlt || e.Eoper == OPge)
4580                 )
4581         {
4582             // Convert to signed comparison against 0
4583             tym_t ty = tybasic(e2.Ety);
4584             switch (_tysize[ty])
4585             {
4586                 case 1:     ty = TYschar;   break;
4587                 case 2:     ty = TYshort;   break;
4588                 default:    assert(0);
4589             }
4590             e.Eoper ^= (OPlt ^ OPge);      // switch between them
4591             e2.EV.Vuns = 0;
4592             e2.Ety = ty | (e2.Ety & ~mTYbasic);
4593             e1.Ety = ty | (e1.Ety & ~mTYbasic);
4594         }
4595         else if (OPTIMIZER && e1.Eoper == OPeq &&
4596                  e1.EV.E2.Eoper == OPconst)
4597         {    // Convert ((x = c1) rel c2) to ((x = c1),(c1 rel c2)
4598              elem *ec = el_copytree(e1.EV.E2);
4599              ec.Ety = e1.Ety;
4600              e.EV.E1 = ec;
4601              e = el_bin(OPcomma,e.Ety,e1,e);
4602              e = optelem(e,GOALvalue);
4603         }
4604     }
4605     else if ((
4606              (e1.Eoper == OPu8_16 ||
4607               e1.Eoper == OPs8_16)||
4608              (e1.Eoper == OPu16_32 ||
4609               e1.Eoper == OPs16_32)
4610              ) &&
4611              e1.Eoper == e2.Eoper)
4612     {
4613         if (uns)
4614         {
4615             e1.EV.E1.Ety = touns(e1.EV.E1.Ety);
4616             e2.EV.E1.Ety = touns(e2.EV.E1.Ety);
4617         }
4618         e1.Ety = e1.EV.E1.Ety;
4619         e2.Ety = e2.EV.E1.Ety;
4620         e.EV.E1 = el_selecte1(e1);
4621         e.EV.E2 = el_selecte1(e2);
4622         e = optelem(e,GOALvalue);
4623     }
4624 ret:
4625     return e;
4626 }
4627 
4628 /*****************************
4629  * Boolean operator.
4630  *      OPbool
4631  */
4632 
4633 @trusted
4634 private elem * elbool(elem *e, goal_t goal)
4635 {
4636     //printf("elbool()\n");
4637     elem* e1 = e.EV.E1;
4638     const op = e1.Eoper;
4639 
4640     if (OTlogical(op) ||
4641         // bool bool => bool
4642         (tybasic(e1.Ety) == TYbool && tysize(e.Ety) == 1)
4643        )
4644         return el_selecte1(e);
4645 
4646     switch (op)
4647     {
4648         case OPs32_d:
4649         case OPs16_d:
4650         case OPu16_d:
4651         case OPu32_d:
4652         case OPf_d:
4653         case OPd_ld:
4654         case OPs16_32:
4655         case OPu16_32:
4656         case OPu8_16:
4657         case OPs8_16:
4658         case OPu32_64:
4659         case OPs32_64:
4660         case OPvp_fp:
4661         case OPcvp_fp:
4662         case OPnp_fp:
4663             e1.Eoper = e.Eoper;
4664             return optelem(el_selecte1(e), goal);
4665 
4666         default:
4667             break;
4668     }
4669 
4670     if (OPTIMIZER)
4671     {
4672         int shift;
4673 
4674         // Replace bool(x,1) with (x,1),1
4675         e1 = elscancommas(e1);
4676         if (cnst(e1) || e1.Eoper == OPrelconst)
4677         {
4678             int i = boolres(e1) != 0;
4679             e.Eoper = OPcomma;
4680             e.EV.E2 = el_long(e.Ety,i);
4681             e = optelem(e,GOALvalue);
4682             return e;
4683         }
4684 
4685         // Replace bool(e & 1) with (uint char)(e & 1)
4686         else if (e.EV.E1.Eoper == OPand && e.EV.E1.EV.E2.Eoper == OPconst && el_tolong(e.EV.E1.EV.E2) == 1)
4687         {
4688         L1:
4689             uint sz = tysize(e.EV.E1.Ety);
4690             tym_t ty = e.Ety;
4691             switch (sz)
4692             {
4693                 case 1:
4694                     e = el_selecte1(e);
4695                     break;
4696 
4697                 case 2:
4698                     e.Eoper = OP16_8;
4699                     break;
4700 
4701                 case 4:
4702                     e.Eoper = OP32_16;
4703                     e.Ety = TYushort;
4704                     e = el_una(OP16_8, ty, e);
4705                     break;
4706 
4707                 case 8:
4708                     e.Eoper = OP64_32;
4709                     e.Ety = TYulong;
4710                     e = el_una(OP32_16, TYushort, e);
4711                     e = el_una(OP16_8, ty, e);
4712                     break;
4713 
4714                 default:
4715                     assert(0);
4716             }
4717             e = optelem(e,GOALvalue);
4718         }
4719 
4720         // Replace bool(e % 2) with (uint char)(e & 1)
4721         else if (e.EV.E1.Eoper == OPmod && e.EV.E1.EV.E2.Eoper == OPconst && el_tolong(e.EV.E1.EV.E2) == 2
4722             && !tyfloating(e.EV.E1.Ety)) // dont optimize fmod()
4723         {
4724             uint sz = tysize(e.EV.E1.Ety);
4725             tym_t ty = e.Ety;
4726             e.EV.E1.Eoper = OPand;
4727             e.EV.E1.EV.E2.EV.Vullong = 1;
4728             switch (sz)
4729             {
4730                 case 1:
4731                     e = el_selecte1(e);
4732                     break;
4733 
4734                 case 2:
4735                     e.Eoper = OP16_8;
4736                     break;
4737 
4738                 case 4:
4739                     e.Eoper = OP32_16;
4740                     e.Ety = TYushort;
4741                     e = el_una(OP16_8, ty, e);
4742                     break;
4743 
4744                 case 8:
4745                     e.Eoper = OP64_32;
4746                     e.Ety = TYulong;
4747                     e = el_una(OP32_16, TYushort, e);
4748                     e = el_una(OP16_8, ty, e);
4749                     break;
4750 
4751                 default:
4752                     assert(0);
4753             }
4754             e = optelem(e,GOALvalue);
4755         }
4756 
4757         // Replace bool((1<<c)&b) with -(b btst c)
4758         else if ((I32 || I64) &&
4759                  e.EV.E1.Eoper == OPand &&
4760                  e.EV.E1.EV.E1.Eoper == OPshl &&
4761                  e.EV.E1.EV.E1.EV.E1.Eoper == OPconst && el_tolong(e.EV.E1.EV.E1.EV.E1) == 1 &&
4762                  tysize(e.EV.E1.Ety) <= REGSIZE
4763                 )
4764         {
4765             tym_t ty = e.Ety;
4766             elem *ex = e.EV.E1.EV.E1;
4767             ex.Eoper = OPbtst;
4768             e.EV.E1.EV.E1 = null;
4769             ex.EV.E1 = e.EV.E1.EV.E2;
4770             e.EV.E1.EV.E2 = null;
4771             ex.Ety = e.Ety;
4772             el_free(e);
4773             e = ex;
4774             return optelem(e,GOALvalue);
4775         }
4776 
4777         // Replace bool(a & c) when c is a power of 2 with ((a >> shift) & 1)
4778         else if (e.EV.E1.Eoper == OPand &&
4779                  e.EV.E1.EV.E2.Eoper == OPconst &&
4780                  (shift = ispow2(el_tolong(e.EV.E1.EV.E2))) != -1
4781                 )
4782         {
4783             e.EV.E1.EV.E1 = el_bin(OPshr, e.EV.E1.EV.E1.Ety, e.EV.E1.EV.E1, el_long(TYint, shift));
4784             e.EV.E1.EV.E2.EV.Vullong = 1;
4785             goto L1;
4786         }
4787     }
4788     return e;
4789 }
4790 
4791 
4792 /*********************************
4793  * Conversions of pointers to far pointers.
4794  */
4795 
4796 @trusted
4797 private elem * elptrlptr(elem *e, goal_t goal)
4798 {
4799     if (e.EV.E1.Eoper == OPrelconst || e.EV.E1.Eoper == OPstring)
4800     {
4801         e.EV.E1.Ety = e.Ety;
4802         e = el_selecte1(e);
4803     }
4804     return e;
4805 }
4806 
4807 
4808 /*********************************
4809  * Conversions of handle pointers to far pointers.
4810  */
4811 @trusted
4812 private elem * elvptrfptr(elem *e, goal_t goal)
4813 {
4814     elem *e1 = e.EV.E1;
4815     if (e1.Eoper == OPadd || e1.Eoper == OPmin)
4816     {
4817         elem *e12 = e1.EV.E2;
4818         if (tybasic(e12.Ety) != TYvptr)
4819         {
4820             /* Rewrite (vtof(e11 + e12)) to (vtof(e11) + e12)   */
4821             const op = e.Eoper;
4822             e.Eoper = e1.Eoper;
4823             e.EV.E2 = e12;
4824             e1.Ety = e.Ety;
4825             e1.Eoper = cast(ubyte)op;
4826             e1.EV.E2 = null;
4827             e = optelem(e,GOALvalue);
4828         }
4829     }
4830     return e;
4831 }
4832 
4833 
4834 /************************
4835  * Optimize conversions of longs to ints.
4836  * Also used for (OPoffset) (TYfptr|TYvptr).
4837  * Also used for conversions of ints to bytes.
4838  */
4839 
4840 @trusted
4841 private elem * ellngsht(elem *e, goal_t goal)
4842 {
4843     //printf("ellngsht()\n");
4844     tym_t ty = e.Ety;
4845     elem *e1 = e.EV.E1;
4846     switch (e1.Eoper)
4847     {
4848     case OPs16_32:
4849     case OPu16_32:
4850     case OPu8_16:
4851     case OPs8_16:
4852         // This fix is not quite right. For example, it fails
4853         // if e.Ety != e.EV.E1.EV.E1.Ety. The difference is when
4854         // one is uint and the other isn't.
4855         if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety))
4856             break;
4857         e = el_selecte1(el_selecte1(e));
4858         e.Ety = ty;
4859         return e;
4860 
4861     case OPvar:                 // simply paint type of variable
4862         // Do not paint type of ints into bytes, as this causes
4863         // many CSEs to be missed, resulting in bad code.
4864         // Loading a word anyway is just as fast as loading a byte.
4865         // for 68000 byte is swapped, load byte != load word
4866         if (e.Eoper == OP16_8)
4867         {
4868             // Mark symbol as being used sometimes as a byte to
4869             // 80X86 - preclude using SI or DI
4870             // 68000 - preclude using An
4871             e1.EV.Vsym.Sflags |= GTbyte;
4872         }
4873         else
4874             e1.Ety = ty;
4875         e = el_selecte1(e);
4876         break;
4877 
4878     case OPind:
4879         e = el_selecte1(e);
4880         break;
4881 
4882     case OPnp_fp:
4883         if (e.Eoper != OPoffset)
4884             goto case_default;
4885         // Replace (offset)(ptrlptr)e11 with e11
4886         e = el_selecte1(el_selecte1(e));
4887         e.Ety = ty;                    // retain original type
4888         break;
4889 
4890     case OPbtst:
4891         e = el_selecte1(e);
4892         break;
4893 
4894     default: // operator
4895     case_default:
4896         // Attempt to replace (lngsht)(a op b) with
4897         // ((lngsht)a op (lngsht)b).
4898         // op is now an integer op, which is cheaper.
4899         if (OTwid(e1.Eoper) && !OTassign(e1.Eoper))
4900         {
4901             tym_t ty1 = e1.EV.E1.Ety;
4902             switch (e.Eoper)
4903             {
4904                 case OP16_8:
4905                     // Make sure e1.EV.E1 is of the type we're converting from
4906                     if (tysize(ty1) <= _tysize[TYint])
4907                     {
4908                         ty1 = (tyuns(ty1) ? TYuchar : TYschar) |
4909                                     (ty1 & ~mTYbasic);
4910                         e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1);
4911                     }
4912                     // Rvalue may be an int if it is a shift operator
4913                     if (OTbinary(e1.Eoper))
4914                     {   tym_t ty2 = e1.EV.E2.Ety;
4915 
4916                         if (tysize(ty2) <= _tysize[TYint])
4917                         {
4918                             ty2 = (tyuns(ty2) ? TYuchar : TYschar) |
4919                                         (ty2 & ~mTYbasic);
4920                             e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2);
4921                         }
4922                     }
4923                     break;
4924 
4925                 case OPoffset:
4926                     if (_tysize[TYint] == LONGSIZE)
4927                     {
4928                         // Make sure e1.EV.E1 is of the type we're converting from
4929                         if (tysize(ty1) > LONGSIZE)
4930                         {
4931                             ty1 = (tyuns(ty1) ? TYuint : TYint) | (ty1 & ~mTYbasic);
4932                             e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1);
4933                         }
4934                         // Rvalue may be an int if it is a shift operator
4935                         if (OTbinary(e1.Eoper))
4936                         {   tym_t ty2 = e1.EV.E2.Ety;
4937 
4938                             if (tysize(ty2) > LONGSIZE)
4939                             {
4940                                 ty2 = (tyuns(ty2) ? TYuint : TYint) |
4941                                             (ty2 & ~mTYbasic);
4942                                 e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2);
4943                             }
4944                         }
4945                         break;
4946                     }
4947                     goto case OP32_16;
4948 
4949                 case OP32_16:
4950                     // Make sure e1.EV.E1 is of the type we're converting from
4951                     if (tysize(ty1) == LONGSIZE)
4952                     {
4953                         ty1 = (tyuns(ty1) ? TYushort : TYshort) | (ty1 & ~mTYbasic);
4954                         e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1);
4955                     }
4956                     // Rvalue may be an int if it is a shift operator
4957                     if (OTbinary(e1.Eoper))
4958                     {   tym_t ty2 = e1.EV.E2.Ety;
4959 
4960                         if (tysize(ty2) == LONGSIZE)
4961                         {
4962                             ty2 = (tyuns(ty2) ? TYushort : TYshort) |
4963                                         (ty2 & ~mTYbasic);
4964                             e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2);
4965                         }
4966                     }
4967                     break;
4968 
4969                 default:
4970                     assert(0);
4971             }
4972             e1.Ety = ty;
4973             e = el_selecte1(e);
4974             again = 1;
4975             return e;
4976         }
4977         break;
4978     }
4979     return e;
4980 }
4981 
4982 
4983 /************************
4984  * Optimize conversions of long longs to ints.
4985  * OP64_32, OP128_64
4986  */
4987 
4988 @trusted
4989 private elem * el64_32(elem *e, goal_t goal)
4990 {
4991     tym_t ty = e.Ety;
4992     elem *e1 = e.EV.E1;
4993     switch (e1.Eoper)
4994     {
4995     case OPs32_64:
4996     case OPu32_64:
4997     case OPs64_128:
4998     case OPu64_128:
4999         if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety))
5000             break;
5001         e = el_selecte1(el_selecte1(e));
5002         e.Ety = ty;
5003         break;
5004 
5005     case OPpair:
5006         if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety))
5007             break;
5008         if (el_sideeffect(e1.EV.E2))
5009         {
5010             // Rewrite (OP64_32(a pair b)) as ((t=a),(b,t))
5011             elem *a = e1.EV.E1;
5012             elem *b = e1.EV.E2;
5013             elem *t = el_alloctmp(a.Ety);
5014 
5015             e.Eoper = OPcomma;
5016             e.EV.E1 = el_bin(OPeq,a.Ety,t,a);
5017             e.EV.E2 = e1;
5018 
5019             e1.Eoper = OPcomma;
5020             e1.EV.E1 = b;
5021             e1.EV.E2 = el_copytree(t);
5022             e1.Ety = e.Ety;
5023             break;
5024         }
5025         e = el_selecte1(el_selecte1(e));
5026         e.Ety = ty;
5027         break;
5028 
5029     case OPrpair:
5030         if (tysize(ty) != tysize(e.EV.E1.EV.E2.Ety))
5031             break;
5032         if (el_sideeffect(e1.EV.E1))
5033         {
5034             // Rewrite (OP64_32(a rpair b)) as (a,b)
5035             e = el_selecte1(e);
5036             e.Eoper = OPcomma;
5037             e.Ety = ty;
5038             break;
5039         }
5040         e = el_selecte2(el_selecte1(e));
5041         e.Ety = ty;
5042         break;
5043 
5044     case OPvar:                 // simply paint type of variable
5045     case OPind:
5046         e = el_selecte1(e);
5047         break;
5048 
5049     case OPshr:                 // OP64_32(x >> 32) => OPmsw(x)
5050         if (e1.EV.E2.Eoper == OPconst &&
5051             (e.Eoper == OP64_32 && el_tolong(e1.EV.E2) == 32 && !I64 ||
5052              e.Eoper == OP128_64 && el_tolong(e1.EV.E2) == 64 && I64)
5053            )
5054         {
5055             e.Eoper = OPmsw;
5056             e.EV.E1 = el_selecte1(e.EV.E1);
5057         }
5058         break;
5059 
5060     case OPmul:
5061         if (config.exe & (EX_OSX | EX_OSX64)) // https://issues.dlang.org/show_bug.cgi?id=21047
5062             break;
5063         else
5064             goto case;
5065 
5066     case OPadd:
5067     case OPmin:
5068     case OPor:
5069     case OPand:
5070     case OPxor:
5071         // OP64_32(a op b) => (OP64_32(a) op OP64_32(b))
5072         e1.EV.E1 = el_una(e.Eoper, ty, e1.EV.E1);
5073         e1.EV.E2 = el_una(e.Eoper, ty, e1.EV.E2);
5074         e = el_selecte1(e);
5075         break;
5076 
5077     default:
5078         break;
5079     }
5080     return e;
5081 }
5082 
5083 
5084 /*******************************
5085  * Convert complex to real.
5086  */
5087 
5088 @trusted
5089 private elem *elc_r(elem *e, goal_t goal)
5090 {
5091     elem *e1 = e.EV.E1;
5092 
5093     if (e1.Eoper == OPvar || e1.Eoper == OPind)
5094     {
5095         e1.Ety = e.Ety;
5096         e = el_selecte1(e);
5097     }
5098     return e;
5099 }
5100 
5101 /*******************************
5102  * Convert complex to imaginary.
5103  */
5104 
5105 @trusted
5106 private elem *elc_i(elem *e, goal_t goal)
5107 {
5108     elem *e1 = e.EV.E1;
5109 
5110     if (e1.Eoper == OPvar)
5111     {
5112         e1.Ety = e.Ety;
5113         e1.EV.Voffset += tysize(e.Ety);
5114         e = el_selecte1(e);
5115     }
5116     else if (e1.Eoper == OPind)
5117     {
5118         e1.Ety = e.Ety;
5119         e = el_selecte1(e);
5120         e.EV.E1 = el_bin(OPadd, e.EV.E1.Ety, e.EV.E1, el_long(TYint, tysize(e.Ety)));
5121         return optelem(e, GOALvalue);
5122     }
5123 
5124     return e;
5125 }
5126 
5127 /******************************
5128  * Handle OPu8_16 and OPs8_16.
5129  */
5130 
5131 @trusted
5132 private elem * elbyteint(elem *e, goal_t goal)
5133 {
5134     if (OTlogical(e.EV.E1.Eoper) || e.EV.E1.Eoper == OPbtst)
5135     {
5136         e.EV.E1.Ety = e.Ety;
5137         e = el_selecte1(e);
5138         return e;
5139     }
5140     return evalu8(e, goal);
5141 }
5142 
5143 /******************************
5144  * OPs32_64
5145  * OPu32_64
5146  */
5147 @trusted
5148 private elem * el32_64(elem *e, goal_t goal)
5149 {
5150     if (REGSIZE == 8 && e.EV.E1.Eoper == OPbtst)
5151     {
5152         e.EV.E1.Ety = e.Ety;
5153         e = el_selecte1(e);
5154         return e;
5155     }
5156     return evalu8(e, goal);
5157 }
5158 
5159 /****************************
5160  * Handle OPu64_d,
5161  *      OPd_ld OPu64_d,
5162  *      OPd_f OPu64_d
5163  */
5164 
5165 @trusted
5166 private elem *elu64_d(elem *e, goal_t goal)
5167 {
5168     tym_t ty;
5169     elem** pu;
5170     if (e.Eoper == OPu64_d)
5171     {
5172         pu = &e.EV.E1;
5173         ty = TYdouble;
5174     }
5175     else if (e.Eoper == OPd_ld && e.EV.E1.Eoper == OPu64_d)
5176     {
5177         pu = &e.EV.E1.EV.E1;
5178         *pu = optelem(*pu, GOALvalue);
5179         ty = TYldouble;
5180     }
5181     else if (e.Eoper == OPd_f && e.EV.E1.Eoper == OPu64_d)
5182     {
5183         pu = &e.EV.E1.EV.E1;
5184         *pu = optelem(*pu, GOALvalue);
5185         ty = TYfloat;
5186     }
5187 
5188     if (!pu || (*pu).Eoper == OPconst)
5189         return evalu8(e, goal);
5190 
5191     elem* u = *pu;
5192     if (config.fpxmmregs && I64 && (ty == TYfloat || ty == TYdouble))
5193     {
5194         /* Rewrite for SIMD as:
5195          *    u >= 0 ? OPs64_d(u) : OPs64_d((u >> 1) | (u & 1)) * 2
5196          */
5197         u.Ety = TYllong;
5198         elem *u1 = el_copytree(u);
5199         if (!OTleaf(u.Eoper))
5200             fixside(&u, &u1);
5201         elem *u2 = el_copytree(u1);
5202 
5203         u = el_bin(OPge, TYint, u, el_long(TYllong, 0));
5204 
5205         u1 = el_una(OPs64_d, TYdouble, u1);
5206         if (ty == TYfloat)
5207             u1 = el_una(OPd_f, TYfloat, u1);
5208 
5209         elem* u3 = el_copytree(u2);
5210         u2 = el_bin(OPshr, TYullong, u2, el_long(TYullong, 1));
5211         u3 = el_bin(OPand, TYullong, u3, el_long(TYullong, 1));
5212         u2 = el_bin(OPor, TYllong, u2, u3);
5213 
5214         u2 = el_una(OPs64_d, TYdouble, u2);
5215         if (ty == TYfloat)
5216             u2 = el_una(OPd_f, TYfloat, u2);
5217 
5218         u2 = el_bin(OPmul, ty, u2, el_long(ty, 2));
5219 
5220         elem* r = el_bin(OPcond, e.Ety, u, el_bin(OPcolon, e.Ety, u1, u2));
5221         *pu = null;
5222         el_free(e);
5223         return optelem(r, GOALvalue);
5224     }
5225     if (config.inline8087)
5226     {
5227         /* Rewrite for x87 as:
5228          *  u < 0 ? OPs64_d(u) : OPs64_d(u) + 0x1p+64
5229          */
5230         u.Ety = TYllong;
5231         elem *u1 = el_copytree(u);
5232         if (!OTleaf(u.Eoper))
5233             fixside(&u, &u1);
5234 
5235         elem* eop1 = el_una(OPs64_d, TYdouble, u1);
5236         eop1 = el_una(OPd_ld, TYldouble, eop1);
5237 
5238         elem* eoff = el_calloc();
5239         eoff.Eoper = OPconst;
5240         eoff.Ety = TYldouble;
5241         eoff.EV.Vldouble = 0x1p+64;
5242 
5243         elem* u2 = el_copytree(u1);
5244         u2 = el_una(OPs64_d, TYdouble, u2);
5245         u2 = el_una(OPd_ld, TYldouble, u2);
5246 
5247         elem* eop2 = el_bin(OPadd, TYldouble, u2, eoff);
5248 
5249         elem* r = el_bin(OPcond, TYldouble,
5250                         el_bin(OPge, OPbool, u, el_long(TYllong, 0)),
5251                         el_bin(OPcolon, TYldouble, eop1, eop2));
5252 
5253         if (ty != TYldouble)
5254             r = el_una(OPtoprec, e.Ety, r);
5255 
5256         *pu = null;
5257         el_free(e);
5258 
5259         return optelem(r, GOALvalue);
5260     }
5261 
5262     return evalu8(e, goal);
5263 }
5264 
5265 
5266 /************************
5267  * Handle <<, OProl and OPror
5268  */
5269 
5270 @trusted
5271 private elem *elshl(elem *e, goal_t goal)
5272 {
5273     tym_t ty = e.Ety;
5274     elem *e1 = e.EV.E1;
5275     elem *e2 = e.EV.E2;
5276 
5277     if (e1.Eoper == OPconst && !boolres(e1))             // if e1 is 0
5278     {
5279         e1.Ety = ty;
5280         e = el_selecte1(e);             // (0 << e2) => 0
5281     }
5282     else if (OPTIMIZER &&
5283         e2.Eoper == OPconst &&
5284         (e1.Eoper == OPshr || e1.Eoper == OPashr) &&
5285         e1.EV.E2.Eoper == OPconst &&
5286         el_tolong(e2) == el_tolong(e1.EV.E2))
5287     {   /* Rewrite:
5288          *  (x >> c) << c)
5289          * with:
5290          *  x & ~((1 << c) - 1);
5291          */
5292         targ_ullong c = el_tolong(e.EV.E2);
5293         e = el_selecte1(e);
5294         e = el_selecte1(e);
5295         e = el_bin(OPand, e.Ety, e, el_long(e.Ety, ~((1UL << c) - 1)));
5296         return optelem(e, goal);
5297     }
5298     return e;
5299 }
5300 
5301 /************************
5302  * Handle >>
5303  * OPshr, OPashr
5304  */
5305 
5306 @trusted
5307 private elem * elshr(elem *e, goal_t goal)
5308 {
5309     tym_t ty = e.Ety;
5310     elem *e1 = e.EV.E1;
5311     elem *e2 = e.EV.E2;
5312 
5313     // (x >> 16) replaced with ((shtlng) x+2)
5314     if (OPTIMIZER &&
5315         e2.Eoper == OPconst && e2.EV.Vshort == SHORTSIZE * 8 &&
5316         tysize(ty) == LONGSIZE)
5317     {
5318         if (e1.Eoper == OPvar)
5319         {
5320             Symbol *s = e1.EV.Vsym;
5321 
5322             if (s.Sclass != SC.fastpar && s.Sclass != SC.shadowreg)
5323             {
5324                 e1.EV.Voffset += SHORTSIZE; // address high word in long
5325                 if (I32)
5326                     // Cannot independently address high word of register
5327                     s.Sflags &= ~GTregcand;
5328                 goto L1;
5329             }
5330         }
5331         else if (e1.Eoper == OPind)
5332         {
5333             /* Replace (*p >> 16) with (shtlng)(*(&*p + 2))     */
5334             e.EV.E1 = el_una(OPind,TYshort,
5335                         el_bin(OPadd,e1.EV.E1.Ety,
5336                                 el_una(OPaddr,e1.EV.E1.Ety,e1),
5337                                 el_long(TYint,SHORTSIZE)));
5338         L1:
5339             e.Eoper = tyuns(e1.Ety) ? OPu16_32 : OPs16_32;
5340             el_free(e2);
5341             e.EV.E2 = null;
5342             e1.Ety = TYshort;
5343             e = optelem(e,GOALvalue);
5344         }
5345     }
5346 
5347     // (x >> 32) replaced with ((lngllng) x+4)
5348     if (e2.Eoper == OPconst && e2.EV.Vlong == LONGSIZE * 8 &&
5349         tysize(ty) == LLONGSIZE)
5350     {
5351         if (e1.Eoper == OPvar)
5352         {
5353             e1.EV.Voffset += LONGSIZE;      // address high dword in longlong
5354             if (I64)
5355                 // Cannot independently address high word of register
5356                 e1.EV.Vsym.Sflags &= ~GTregcand;
5357             goto L2;
5358         }
5359         else if (e1.Eoper == OPind)
5360         {
5361             // Replace (*p >> 32) with (lngllng)(*(&*p + 4))
5362             e.EV.E1 = el_una(OPind,TYlong,
5363                         el_bin(OPadd,e1.EV.E1.Ety,
5364                                 el_una(OPaddr,e1.EV.E1.Ety,e1),
5365                                 el_long(TYint,LONGSIZE)));
5366         L2:
5367             e.Eoper = tyuns(e1.Ety) ? OPu32_64 : OPs32_64;
5368             el_free(e2);
5369             e.EV.E2 = null;
5370             e1.Ety = TYlong;
5371             e = optelem(e,GOALvalue);
5372         }
5373     }
5374     return e;
5375 }
5376 
5377 /***********************************
5378  * Handle OPmsw.
5379  */
5380 
5381 @trusted
5382 elem *elmsw(elem *e, goal_t goal)
5383 {
5384     tym_t ty = e.Ety;
5385     elem *e1 = e.EV.E1;
5386 
5387     if (OPTIMIZER &&
5388         tysize(e1.Ety) == LLONGSIZE &&
5389         tysize(ty) == LONGSIZE)
5390     {
5391         // Replace (int)(msw (long)x) with (int)*(&x+4)
5392         if (e1.Eoper == OPvar)
5393         {
5394             e1.EV.Voffset += LONGSIZE;      // address high dword in longlong
5395             if (I64)
5396                 // Cannot independently address high word of register
5397                 e1.EV.Vsym.Sflags &= ~GTregcand;
5398             e1.Ety = ty;
5399             e = optelem(e1,GOALvalue);
5400         }
5401         // Replace (int)(msw (long)*x) with (int)*(&*x+4)
5402         else if (e1.Eoper == OPind)
5403         {
5404             e1 = el_una(OPind,ty,
5405                 el_bin(OPadd,e1.EV.E1.Ety,
5406                     el_una(OPaddr,e1.EV.E1.Ety,e1),
5407                     el_long(TYint,LONGSIZE)));
5408             e = optelem(e1,GOALvalue);
5409         }
5410         else
5411         {
5412             e = evalu8(e, goal);
5413         }
5414     }
5415     else if (OPTIMIZER && I64 &&
5416         tysize(e1.Ety) == CENTSIZE &&
5417         tysize(ty) == LLONGSIZE)
5418     {
5419         // Replace (long)(msw (cent)x) with (long)*(&x+8)
5420         if (e1.Eoper == OPvar)
5421         {
5422             e1.EV.Voffset += LLONGSIZE;      // address high dword in longlong
5423             e1.Ety = ty;
5424             e = optelem(e1,GOALvalue);
5425         }
5426         // Replace (long)(msw (cent)*x) with (long)*(&*x+8)
5427         else if (e1.Eoper == OPind)
5428         {
5429             e1 = el_una(OPind,ty,
5430                 el_bin(OPadd,e1.EV.E1.Ety,
5431                     el_una(OPaddr,e1.EV.E1.Ety,e1),
5432                     el_long(TYint,LLONGSIZE)));
5433             e = optelem(e1,GOALvalue);
5434         }
5435         else
5436         {
5437             e = evalu8(e, goal);
5438         }
5439     }
5440     else
5441     {
5442         e = evalu8(e, goal);
5443     }
5444 
5445     return e;
5446 }
5447 
5448 /***********************************
5449  * Handle OPpair, OPrpair.
5450  */
5451 
5452 @trusted
5453 elem *elpair(elem *e, goal_t goal)
5454 {
5455     //printf("elpair()\n");
5456     elem *e1 = e.EV.E1;
5457     if (e1.Eoper == OPconst)
5458     {
5459         e.EV.E1 = e.EV.E2;
5460         e.EV.E2 = e1;
5461         e.Eoper ^= OPpair ^ OPrpair;
5462     }
5463     return e;
5464 }
5465 
5466 /********************************
5467  * Handle OPddtor
5468  */
5469 
5470 elem *elddtor(elem *e, goal_t goal)
5471 {
5472     return e;
5473 }
5474 
5475 /********************************
5476  * Handle OPinfo, OPmark, OPctor, OPdtor
5477  */
5478 
5479 private elem * elinfo(elem *e, goal_t goal)
5480 {
5481     //printf("elinfo()\n");
5482     version (SCPP)
5483     static if (NTEXCEPTIONS)
5484     {
5485         if (funcsym_p.Sfunc.Fflags3 & Fnteh)
5486         {   // Eliminate cleanup info if using NT structured EH
5487             if (e.Eoper == OPinfo)
5488                 e = el_selecte2(e);
5489             else
5490             {   el_free(e);
5491                 e = el_long(TYint,0);
5492             }
5493         }
5494     }
5495     return e;
5496 }
5497 
5498 /********************************************
5499  */
5500 
5501 private elem * elclassinit(elem *e, goal_t goal)
5502 {
5503     return e;
5504 }
5505 
5506 /********************************************
5507  */
5508 
5509 @trusted
5510 private elem * elvalist(elem *e, goal_t goal)
5511 {
5512     assert(e.Eoper == OPva_start);
5513 
5514     if (funcsym_p.ty() & mTYnaked)
5515     {   // do not generate prolog
5516         el_free(e);
5517         e = el_long(TYint, 0);
5518         return e;
5519     }
5520 
5521     if (I32)
5522     {
5523         // (OPva_start &va)
5524         // (OPeq (OPind E1) (OPptr lastNamed+T.sizeof))
5525         //elem_print(e);
5526 
5527         // Find last named parameter
5528         Symbol *lastNamed = null;
5529         Symbol *arguments_typeinfo = null;
5530         for (SYMIDX si = 0; si < globsym.length; si++)
5531         {
5532             Symbol *s = globsym[si];
5533 
5534             if (s.Sclass == SC.parameter || s.Sclass == SC.regpar)
5535                 lastNamed = s;
5536             if (s.Sident[0] == '_' && strcmp(s.Sident.ptr, "_arguments_typeinfo") == 0)
5537                 arguments_typeinfo = s;
5538         }
5539 
5540         if (!lastNamed)
5541             lastNamed = arguments_typeinfo;
5542 
5543         e.Eoper = OPeq;
5544         e.EV.E1 = el_una(OPind, TYnptr, e.EV.E1);
5545         if (lastNamed)
5546         {
5547             e.EV.E2 = el_ptr(lastNamed);
5548             e.EV.E2.EV.Voffset = (type_size(lastNamed.Stype) + 3) & ~3;
5549         }
5550         else
5551             e.EV.E2 = el_long(TYnptr, 0);
5552         // elem_print(e);
5553 
5554         return e;
5555     }
5556 
5557 if (config.exe & EX_windos)
5558 {
5559     assert(config.exe == EX_WIN64); // va_start is not an intrinsic on 32-bit
5560 
5561     // (OPva_start &va)
5562     // (OPeq (OPind E1) (OPptr &lastNamed+8))
5563     //elem_print(e);
5564 
5565     // Find last named parameter
5566     Symbol *lastNamed = null;
5567     for (SYMIDX si = 0; si < globsym.length; si++)
5568     {
5569         Symbol *s = globsym[si];
5570 
5571         if (s.Sclass == SC.fastpar || s.Sclass == SC.shadowreg || s.Sclass == SC.parameter)
5572             lastNamed = s;
5573     }
5574 
5575     e.Eoper = OPeq;
5576     e.EV.E1 = el_una(OPind, TYnptr, e.EV.E1);
5577     if (lastNamed)
5578     {
5579         e.EV.E2 = el_ptr(lastNamed);
5580         e.EV.E2.EV.Voffset = 8;
5581     }
5582     else
5583         e.EV.E2 = el_long(TYnptr, 0);
5584     //elem_print(e);
5585 
5586 }
5587 
5588 if (config.exe & EX_posix)
5589 {
5590     assert(I64); // va_start is not an intrinsic on 32-bit
5591     // (OPva_start &va)
5592     // (OPeq (OPind E1) __va_argsave+offset)
5593     //elem_print(e);
5594 
5595     // Find __va_argsave
5596     Symbol *va_argsave = null;
5597     for (SYMIDX si = 0; si < globsym.length; si++)
5598     {
5599         Symbol *s = globsym[si];
5600         if (s.Sident[0] == '_' && strcmp(s.Sident.ptr, "__va_argsave") == 0)
5601         {
5602             va_argsave = s;
5603             break;
5604         }
5605     }
5606 
5607     e.Eoper = OPeq;
5608     e.EV.E1 = el_una(OPind, TYnptr, e.EV.E1);
5609     if (va_argsave)
5610     {
5611         e.EV.E2 = el_ptr(va_argsave);
5612         e.EV.E2.EV.Voffset = 6 * 8 + 8 * 16;
5613     }
5614     else
5615         e.EV.E2 = el_long(TYnptr, 0);
5616     //elem_print(e);
5617 }
5618 
5619     return e;
5620 }
5621 
5622 /******************************************
5623  * OPparam
5624  */
5625 
5626 @trusted
5627 private void elparamx(elem *e)
5628 {
5629     //printf("elparam()\n");
5630     if (e.EV.E1.Eoper == OPrpair)
5631     {
5632         e.EV.E1.Eoper = OPparam;
5633     }
5634     else if (e.EV.E1.Eoper == OPpair && !el_sideeffect(e.EV.E1))
5635     {
5636         e.EV.E1.Eoper = OPparam;
5637         elem *ex = e.EV.E1.EV.E2;
5638         e.EV.E1.EV.E2 = e.EV.E1.EV.E1;
5639         e.EV.E1.EV.E1 = ex;
5640     }
5641     else
5642     {
5643         static if (0)
5644         {
5645             // Unfortunately, these don't work because if the last parameter
5646             // is a pair, and it is a D function, the last parameter will get
5647             // passed in EAX.
5648             if (e.EV.E2.Eoper == OPrpair)
5649             {
5650                 e.EV.E2.Eoper = OPparam;
5651             }
5652             else if (e.EV.E2.Eoper == OPpair)
5653             {
5654                 e.EV.E2.Eoper = OPparam;
5655                 elem *ex = e.EV.E2.EV.E2;
5656                 e.EV.E2.EV.E2 = e.EV.E2.EV.E1;
5657                 e.EV.E2.EV.E1 = ex;
5658             }
5659         }
5660     }
5661 }
5662 
5663 @trusted
5664 private elem * elparam(elem *e, goal_t goal)
5665 {
5666     if (!OPTIMIZER)
5667     {
5668         if (!I64)
5669             elparamx(e);
5670     }
5671     return e;
5672 }
5673 
5674 /********************************
5675  * Optimize an element. This routine is recursive!
5676  * Be careful not to do this if VBEs have been done (else the VBE
5677  * work will be undone), or if DAGs have been built (will crash if
5678  * there is more than one parent for an elem).
5679  * If (goal)
5680  *      we care about the result.
5681  */
5682 
5683 @trusted
5684 private elem * optelem(elem *e, goal_t goal)
5685 {
5686 beg:
5687     //__gshared uint count;
5688     //printf("count: %u\n", ++count);
5689     //{ printf("xoptelem: %p %s goal x%x\n",e, oper_str(e.Eoper), goal); }
5690     assert(e);
5691     elem_debug(e);
5692     assert(e.Ecount == 0);             // no CSEs
5693 
5694     if (OPTIMIZER)
5695     {
5696         if (goal)
5697             e.Nflags &= ~NFLnogoal;
5698         else
5699             e.Nflags |= NFLnogoal;
5700     }
5701 
5702     auto op = e.Eoper;
5703     if (OTleaf(op))                     // if not an operator node
5704     {
5705         if (goal || OTsideff(op) || e.Ety & (mTYvolatile | mTYshared))
5706         {
5707             return e;
5708         }
5709         else
5710         {
5711             retnull:
5712                 el_free(e);
5713                 return null;
5714         }
5715     }
5716     else if (OTbinary(op))              // if binary operator
5717     {
5718         /* Determine goals for left and right subtrees  */
5719         goal_t leftgoal = GOALvalue;
5720         goal_t rightgoal = (goal || OTsideff(op)) ? GOALvalue : GOALnone;
5721         switch (op)
5722         {
5723             case OPcomma:
5724             {
5725                 elem *e1 = e.EV.E1 = optelem(e.EV.E1,GOALnone);
5726 //              if (e1 && !OTsideff(e1.Eoper))
5727 //                  e1 = e.EV.E1 = optelem(e1, GOALnone);
5728                 elem *e2 = e.EV.E2 = optelem(e.EV.E2,goal);
5729                 if (!e1)
5730                 {
5731                     if (!e2)
5732                         goto retnull;
5733                     if (!goal)
5734                         e.Ety = e.EV.E2.Ety;
5735                     e = el_selecte2(e);
5736                     return e;
5737                 }
5738                 if (!e2)
5739                 {
5740                     e.Ety = e.EV.E1.Ety;
5741                     return el_selecte1(e);
5742                 }
5743                 if (!goal)
5744                     e.Ety = e2.Ety;
5745                 return e;
5746             }
5747 
5748             case OPcond:
5749                 if (!goal)
5750                 {   // Transform x?y:z into x&&y or x||z
5751                     elem *e2 = e.EV.E2;
5752                     if (!el_sideeffect(e2.EV.E1))
5753                     {
5754                         e.Eoper = OPoror;
5755                         e.EV.E2 = el_selecte2(e2);
5756                         e.Ety = TYint;
5757                         goto beg;
5758                     }
5759                     else if (!el_sideeffect(e2.EV.E2))
5760                     {
5761                         e.Eoper = OPandand;
5762                         e.EV.E2 = el_selecte1(e2);
5763                         e.Ety = TYint;
5764                         goto beg;
5765                     }
5766                     assert(e2.Eoper == OPcolon || e2.Eoper == OPcolon2);
5767                     elem *e21 = e2.EV.E1 = optelem(e2.EV.E1, goal);
5768                     elem *e22 = e2.EV.E2 = optelem(e2.EV.E2, goal);
5769                     if (!e21)
5770                     {
5771                         if (!e22)
5772                         {
5773                             e = el_selecte1(e);
5774                             goto beg;
5775                         }
5776                         // Rewrite (e1 ? null : e22) as (e1 || e22)
5777                         e.Eoper = OPoror;
5778                         e.EV.E2 = el_selecte2(e2);
5779                         goto beg;
5780                     }
5781                     if (!e22)
5782                     {
5783                         // Rewrite (e1 ? e21 : null) as (e1 && e21)
5784                         e.Eoper = OPandand;
5785                         e.EV.E2 = el_selecte1(e2);
5786                         goto beg;
5787                     }
5788                     if (!rightgoal)
5789                         rightgoal = GOALvalue;
5790                 }
5791                 goto Llog;
5792 
5793             case OPoror:
5794                 if (rightgoal)
5795                     rightgoal = GOALflags;
5796                 if (OPTIMIZER && optim_loglog(&e))
5797                     goto beg;
5798                 goto Llog;
5799 
5800             case OPandand:
5801                 if (rightgoal)
5802                     rightgoal = GOALflags;
5803                 if (OPTIMIZER && optim_loglog(&e))
5804                     goto beg;
5805                 goto Llog;
5806 
5807             Llog:               // case (c log f()) with no goal
5808                 if (goal || el_sideeffect(e.EV.E2))
5809                     leftgoal = GOALflags;
5810                 break;
5811 
5812             default:
5813                 leftgoal = rightgoal;
5814                 break;
5815 
5816             case OPcolon:
5817             case OPcolon2:
5818                 if (!goal && !el_sideeffect(e))
5819                     goto retnull;
5820                 leftgoal = rightgoal;
5821                 break;
5822 
5823             case OPmemcmp:
5824                 if (!goal)
5825                 {   // So OPmemcmp is removed cleanly
5826                     assert(e.EV.E1.Eoper == OPparam);
5827                     e.EV.E1.Eoper = OPcomma;
5828                 }
5829                 leftgoal = rightgoal;
5830                 break;
5831 
5832             case OPcall:
5833             case OPcallns:
5834             {
5835                 const tyf = tybasic(e.EV.E1.Ety);
5836                 leftgoal = rightgoal;
5837                 elem *e1 = e.EV.E1 = optelem(e.EV.E1, leftgoal);
5838 
5839                 // Need argument to type_zeroSize()
5840                 const tyf_save = global_tyf;
5841                 global_tyf = tyf;
5842                 elem *e2 = e.EV.E2 = optelem(e.EV.E2, rightgoal);
5843                 global_tyf = tyf_save;
5844 
5845                 if (!e1)
5846                 {
5847                     if (!e2)
5848                         goto retnull;
5849                     return el_selecte2(e);
5850                 }
5851                 if (!e2)
5852                 {
5853                     if (!leftgoal)
5854                         e.Ety = e1.Ety;
5855                     return el_selecte1(e);
5856                 }
5857                 return (*elxxx[op])(e, goal);
5858             }
5859         }
5860 
5861         elem *e1 = e.EV.E1;
5862         if (OTassign(op))
5863         {
5864             elem *ex = e1;
5865             while (OTconv(ex.Eoper))
5866                 ex = ex.EV.E1;
5867             if (ex.Eoper == OPbit)
5868                 ex.EV.E1 = optelem(ex.EV.E1, leftgoal);
5869             else if (e1.Eoper == OPu64_d)
5870                 e1.EV.E1 = optelem(e1.EV.E1, leftgoal);
5871             else if ((e1.Eoper == OPd_ld || e1.Eoper == OPd_f) && e1.EV.E1.Eoper == OPu64_d)
5872                 e1.EV.E1.EV.E1 = optelem(e1.EV.E1.EV.E1, leftgoal);
5873             else
5874                 e1 = e.EV.E1 = optelem(e1,leftgoal);
5875         }
5876         else
5877             e1 = e.EV.E1 = optelem(e1,leftgoal);
5878 
5879         if ((op == OPandand || op == OPoror || op == OPcond) && e1) // short circuit evaluations
5880         {
5881             switch (op)
5882             {
5883                 case OPandand:
5884                     if (iffalse(e1))
5885                     {
5886                         // Do not evaluate E2
5887                         el_free(e.EV.E2);
5888                         e.EV.E2 = null;
5889                         e.Eoper = OPbool;
5890                         goto beg;
5891                     }
5892                     break;
5893 
5894                 case OPoror:
5895                     if (iftrue(e1))
5896                     {
5897                         // Do not evaluate E2
5898                         el_free(e.EV.E2);
5899                         e.EV.E2 = null;
5900                         e.Eoper = OPbool;
5901                         goto beg;
5902                     }
5903                     break;
5904 
5905                 case OPcond:
5906                     if (iftrue(e1))
5907                     {
5908                         e.EV.E2 = el_selecte1(e.EV.E2);
5909                         e.EV.E2.Ety = e.Ety;
5910                         e.EV.E2.ET = e.ET;
5911                         e.Eoper = OPcomma;
5912                         goto beg;
5913                     }
5914                     if (iffalse(e1))
5915                     {
5916                         e.EV.E2 = el_selecte2(e.EV.E2);
5917                         e.EV.E2.Ety = e.Ety;
5918                         e.EV.E2.ET = e.ET;
5919                         e.Eoper = OPcomma;
5920                         goto beg;
5921                     }
5922                     break;
5923 
5924                 default:
5925                     assert(0);
5926             }
5927         }
5928 
5929         elem *e2 = e.EV.E2 = optelem(e.EV.E2,rightgoal);
5930         if (!e1)
5931         {
5932             if (!e2)
5933                 goto retnull;
5934             return el_selecte2(e);
5935         }
5936         if (!e2)
5937         {
5938             if (!leftgoal)
5939                 e.Ety = e1.Ety;
5940             return el_selecte1(e);
5941         }
5942 
5943         if (op == OPparam && !goal)
5944             e.Eoper = OPcomma; // DMD bug 6733
5945 
5946         if (cnst(e1) && cnst(e2))
5947         {
5948             e = evalu8(e, GOALvalue);
5949             return e;
5950         }
5951         if (OPTIMIZER)
5952         {
5953             if (OTassoc(op))
5954             {
5955                 /* Replace (a op1 (b op2 c)) with ((a op2 b) op1 c)
5956                    (this must come before the leaf swapping, or we could cause
5957                    infinite loops)
5958                  */
5959                 if (e2.Eoper == op &&
5960                     e2.EV.E2.Eoper == OPconst &&
5961                     tysize(e2.EV.E1.Ety) == tysize(e2.EV.E2.Ety) &&
5962                     (!tyfloating(e1.Ety) || e1.Ety == e2.Ety)
5963                    )
5964                 {
5965                   e.EV.E1 = e2;
5966                   e.EV.E2 = e2.EV.E2;
5967                   e2.EV.E2 = e2.EV.E1;
5968                   e2.EV.E1 = e1;
5969                   if (op == OPadd)  /* fix types                    */
5970                   {
5971                       e1 = e.EV.E1;
5972                       if (typtr(e1.EV.E2.Ety))
5973                           e1.Ety = e1.EV.E2.Ety;
5974                       else
5975                           /* suppose a and b are ints, and c is a pointer   */
5976                           /* then this will fix the type of op2 to be int   */
5977                           e1.Ety = e1.EV.E1.Ety;
5978                   }
5979                   goto beg;
5980                 }
5981 
5982                 // Replace ((a op c1) op c2) with (a op (c2 op c1))
5983                 if (e1.Eoper == op &&
5984                     e2.Eoper == OPconst &&
5985                     e1.EV.E2.Eoper == OPconst &&
5986                     e1.EV.E1.Eoper != OPconst &&
5987                     tysize(e2.Ety) == tysize(e1.EV.E2.Ety))
5988                 {
5989                     e.EV.E1 = e1.EV.E1;
5990                     e1.EV.E1 = e2;
5991                     e1.Ety = e2.Ety;
5992                     e.EV.E2 = e1;
5993 
5994                     if (tyfloating(e1.Ety))
5995                     {
5996                         e1 = evalu8(e1, GOALvalue);
5997                         if (!OTleaf(e1.Eoper))        // if failed to fold the constants
5998                         {   // Undo the changes so we don't infinite loop
5999                             e.EV.E2 = e1.EV.E1;
6000                             e1.EV.E1 = e.EV.E1;
6001                             e.EV.E1 = e1;
6002                         }
6003                         else
6004                         {   e.EV.E2 = e1;
6005                             goto beg;
6006                         }
6007                     }
6008                     else
6009                         goto beg;
6010                 }
6011           }
6012 
6013           if (!OTrtol(op) && op != OPparam && op != OPcolon && op != OPcolon2 &&
6014               e1.Eoper == OPcomma)
6015           {     // Convert ((a,b) op c) to (a,(b op c))
6016                 e1.EV.E2.Ety = e1.Ety;
6017                 e1.EV.E2.ET = e1.ET;
6018 
6019                 e1.Ety = e.Ety;
6020                 e1.ET = e.ET;
6021 
6022                 e.EV.E1 = e1.EV.E2;
6023                 e1.EV.E2 = e;
6024                 e = e1;
6025                 goto beg;
6026           }
6027         }
6028 
6029         if (OTcommut(op))                // if commutative
6030         {
6031               /* see if we should swap the leaves       */
6032               version (MARS) { enum MARS = true; } else { enum MARS = false; }
6033               if (
6034                 MARS ? (
6035                 cost(e2) > cost(e1) &&
6036                 !(tyvector(e1.Ety) && op == OPgt)
6037                 /* Swap only if order of evaluation can be proved
6038                  * to not matter, as we must evaluate Left-to-Right
6039                  */
6040                 && e1.canHappenAfter(e2)
6041                  )
6042                  : cost(e2) > cost(e1) && !(tyvector(e1.Ety) && op == OPgt)
6043                  )
6044               {
6045                     e.EV.E1 = e2;
6046                     e2 = e.EV.E2 = e1;
6047                     e1 = e.EV.E1;         // reverse the leaves
6048                     op = e.Eoper = cast(ubyte)swaprel(op);
6049               }
6050               if (OTassoc(op))          // if commutative and associative
6051               {
6052                   if (!OTleaf(e1.Eoper) &&
6053                       op == e1.Eoper &&
6054                       e1.EV.E2.Eoper == OPconst &&
6055                       e.Ety == e1.Ety &&
6056                       tysize(e1.EV.E2.Ety) == tysize(e2.Ety)
6057 
6058                       // Reordering floating point can change the semantics
6059                       && (!MARS || !tyfloating(e1.Ety))
6060                      )
6061                   {
6062                         // look for ((e op c1) op c2),
6063                         // replace with (e op (c1 op c2))
6064                         if (e2.Eoper == OPconst)
6065                         {
6066                             e.EV.E1 = e1.EV.E1;
6067                             e.EV.E2 = e1;
6068                             e1.EV.E1 = e1.EV.E2;
6069                             e1.EV.E2 = e2;
6070                             e1.Ety = e2.Ety;
6071 
6072                             e1 = e.EV.E1;
6073                             e2 = e.EV.E2 = evalu8(e.EV.E2, GOALvalue);
6074                         }
6075                         else
6076                         {   // Replace ((e op c) op e2) with ((e op e2) op c)
6077                             e.EV.E2 = e1.EV.E2;
6078                             e1.EV.E2 = e2;
6079                             e2 = e.EV.E2;
6080                         }
6081                   }
6082               }
6083         }
6084 
6085         if (e2.Eoper == OPconst &&             // if right operand is a constant
6086             !(OTopeq(op) && OTconv(e1.Eoper))
6087            )
6088         {
6089             debug assert(!(OTeop0e(op) && (OTeop00(op))));
6090             if (OTeop0e(op))            /* if e1 op 0 => e1             */
6091             {
6092                 if (!boolres(e2))       /* if e2 is 0                   */
6093                 {
6094                     // Don't do it for ANSI floating point
6095                     if (tyfloating(e1.Ety) && !(config.flags4 & CFG4fastfloat))
6096                     { }
6097                     // Don't do it if we're assembling a complex value
6098                     else if ((tytab[e.EV.E1.Ety & 0xFF] ^
6099                          tytab[e.EV.E2.Ety & 0xFF]) == (TYFLreal | TYFLimaginary))
6100                     { }
6101                     else
6102                         return optelem(el_selecte1(e),goal);
6103                 }
6104             }
6105             else if (OTeop00(op) && !boolres(e2) && !tyfloating(e.Ety))
6106             {
6107                 if (OTassign(op))
6108                     op = e.Eoper = OPeq;
6109                 else
6110                     op = e.Eoper = OPcomma;
6111             }
6112 
6113             if (OTeop1e(op))            /* if e1 op 1 => e1             */
6114             {
6115                 if (elemisone(e2) && !tyimaginary(e2.Ety))
6116                     return optelem(el_selecte1(e),goal);
6117             }
6118         }
6119 
6120         if (OTpost(op) && !goal)
6121         {
6122             op = e.Eoper = (op == OPpostinc) ? OPaddass : OPminass;
6123         }
6124   }
6125   else /* unary operator */
6126   {
6127         elem* e1 = e.EV.E1;
6128 
6129         /* op(a,b) => a,(op b)
6130          */
6131         if (e1.Eoper == OPcomma && op != OPstrpar && op != OPddtor)
6132         {
6133             e.Eoper = e1.Eoper;
6134             e.EV.E1 = e1.EV.E1;
6135             e.EV.E2 = e1;
6136             e1.Eoper = op;
6137             e1.Ety = e.Ety;
6138             e1.ET = e.ET;
6139             e1.EV.E1 = e1.EV.E2;
6140             e1.EV.E2 = null;
6141             return optelem(e, goal);
6142         }
6143 
6144         assert(!e.EV.E2 || op == OPinfo || op == OPddtor);
6145         if (!goal && !OTsideff(op) && !(e.Ety & (mTYvolatile | mTYshared)))
6146         {
6147             tym_t tym = e1.Ety;
6148 
6149             e = el_selecte1(e);
6150             e.Ety = tym;
6151             return optelem(e,GOALnone);
6152         }
6153 
6154         if ((op == OPd_f || op == OPd_ld) && e1.Eoper == OPu64_d)
6155         {
6156             return elu64_d(e, goal);
6157         }
6158 
6159         e1 = e.EV.E1 = optelem(e1, (op == OPddtor)
6160                                      ? GOALnone
6161                                      : (op == OPbool || op == OPnot) ? GOALflags : GOALvalue);
6162         if (!e1)
6163             goto retnull;
6164         if (e1.Eoper == OPconst)
6165         {
6166             if (!(op == OPnp_fp && el_tolong(e1) != 0))
6167                 return evalu8(e, GOALvalue);
6168         }
6169   }
6170 
6171 //  if (debugb)
6172 //  {   print("optelem: %p %s\n",e, oper_str(op)); }
6173 
6174     static if (0)
6175     {
6176         printf("xoptelem: %p %s\n", e, oper_str(e.Eoper));
6177         elem_print(e);
6178         e = (*elxxx[op])(e, goal);
6179         printf("After:\n");
6180         elem_print(e);
6181         return e;
6182     }
6183     else
6184     {
6185         return (*elxxx[op])(e, goal);
6186     }
6187 }
6188 
6189 
6190 /********************************
6191  * Optimize and canonicalize an expression tree.
6192  * Fiddle with double operators so that the rvalue is a pointer
6193  * (this is needed by the 8086 code generator).
6194  *
6195  *         op                      op
6196  *        /  \                    /  \
6197  *      e1    e2                e1    ,
6198  *                                   / \
6199  *                                  =   &
6200  *                                 / \   \
6201  *                               fr   e2  fr
6202  *
6203  *      e1 op (*p)              e1 op p
6204  *      e1 op c                 e1 op &dc
6205  *      e1 op v                 e1 op &v
6206  */
6207 
6208 @trusted
6209 elem *doptelem(elem *e, goal_t goal)
6210 {
6211     //printf("doptelem(e = %p, goal = x%x)\n", e, goal);
6212     assert(!PARSER);
6213     do
6214     {   again = false;
6215         topair = false;
6216         e = optelem(e,goal & (GOALflags | GOALvalue | GOALnone));
6217     } while (again && goal & GOALagain && e);
6218 
6219     /* If entire expression is a struct, and we can replace it with     */
6220     /* something simpler, do so.                                        */
6221     if (goal & GOALstruct && e && (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray))
6222         e = elstruct(e, goal);
6223 
6224     if (topair && e)
6225         e = elToPair(e);
6226 
6227     return e;
6228 }
6229 
6230 /****************************************
6231  * Do optimizations after bltailrecursion() and before common subexpressions.
6232  */
6233 
6234 @trusted
6235 void postoptelem(elem *e)
6236 {
6237     Srcpos pos = {0};
6238 
6239     elem_debug(e);
6240     while (1)
6241     {
6242         if (OTunary(e.Eoper))
6243         {
6244             /* This is necessary as the optimizer tends to lose this information
6245              */
6246             version (MARS)
6247             if (e.Esrcpos.Slinnum > pos.Slinnum)
6248                 pos = e.Esrcpos;
6249 
6250             if (e.Eoper == OPind)
6251             {
6252                 version (MARS)
6253                 if (e.EV.E1.Eoper == OPconst &&
6254                     /* Allow TYfgptr to reference GS:[0000] etc.
6255                      */
6256                     tybasic(e.EV.E1.Ety) == TYnptr)
6257                 {
6258                     /* Disallow anything in the range [0..4096]
6259                      * Let volatile pointers dereference null
6260                      */
6261                     const targ_ullong v = el_tolong(e.EV.E1);
6262                     if (v < 4096 && !(e.Ety & mTYvolatile))
6263                     {
6264                         error(pos.Sfilename, pos.Slinnum, pos.Scharnum, "null dereference in function %s", funcsym_p.Sident.ptr);
6265                         e.EV.E1.EV.Vlong = 4096;     // suppress redundant messages
6266                     }
6267                 }
6268             }
6269             e = e.EV.E1;
6270         }
6271         else if (OTbinary(e.Eoper))
6272         {
6273             /* This is necessary as the optimizer tends to lose this information
6274              */
6275             version (MARS)
6276             if (e.Esrcpos.Slinnum > pos.Slinnum)
6277                 pos = e.Esrcpos;
6278 
6279             if (e.Eoper == OPparam)
6280             {
6281                 if (!I64)
6282                     elparamx(e);
6283             }
6284             postoptelem(e.EV.E2);
6285             e = e.EV.E1;
6286         }
6287         else
6288             break;
6289     }
6290 }
6291 
6292 /***********************************
6293  * Rewrite rvalues of complex numbers to pairs of floating point numbers.
6294  */
6295 @trusted
6296 private elem *elToPair(elem *e)
6297 {
6298     switch (e.Eoper)
6299     {
6300         case OPvar:
6301         {
6302             /* Rewrite complex number loads as a pair of loads
6303              * e => (e.0 pair e.offset)
6304              */
6305             tym_t ty0;
6306             tym_t ty = e.Ety;
6307             if (ty & (mTYxmmgpr | mTYgprxmm))
6308                 break; // register allocation doesn't support it yet.
6309             switch (tybasic(ty))
6310             {
6311                 case TYcfloat:      ty0 = TYfloat  | (ty & ~mTYbasic); goto L1;
6312                 case TYcdouble:     ty0 = TYdouble | (ty & ~mTYbasic); goto L1;
6313                 L1:
6314                     if (_tysize[tybasic(ty0)] < REGSIZE)
6315                         break;                          // func parameters, for example, can't handle this
6316                     e.Ety = ty0;
6317                     elem *e2 = el_copytree(e);
6318                     e2.EV.Voffset += _tysize[tybasic(ty0)];
6319                     return el_bin(OPpair, ty, e, e2);
6320 
6321                 default:
6322                     break;
6323             }
6324             break;
6325         }
6326 
6327         case OPind:
6328         {
6329             e.EV.E1 = elToPair(e.EV.E1);
6330             /* Rewrite complex number loads as a pair of loads
6331              * *e1 => (*e1 pair *(e1 + offset))
6332              */
6333             tym_t ty0;
6334             tym_t ty = e.Ety;
6335             if (ty & (mTYxmmgpr | mTYgprxmm))
6336                 break; // register allocation doesn't support it yet.
6337             switch (tybasic(ty))
6338             {
6339                 case TYcfloat:      ty0 = TYfloat  | (ty & ~mTYbasic); goto L2;
6340                 case TYcdouble:     ty0 = TYdouble | (ty & ~mTYbasic); goto L2;
6341                 L2:
6342                     if (_tysize[tybasic(ty0)] < REGSIZE)
6343                         break;                          // func parameters, for example, can't handle this
6344                     e.Ety = ty0;
6345                     elem *e2 = el_copytree(e.EV.E1);
6346                     if (el_sideeffect(e2))
6347                         fixside(&e.EV.E1, &e2);
6348                     e2 = el_bin(OPadd,e2.Ety,e2,el_long(TYsize, _tysize[tybasic(ty0)]));
6349                     e2 = el_una(OPind, ty0, e2);
6350                     return el_bin(OPpair, ty, e, e2);
6351 
6352                 default:
6353                     break;
6354             }
6355             break;
6356         }
6357 
6358         default:
6359             if (OTassign(e.Eoper))
6360             {
6361                 // Skip over OPvar and OPind lvalues
6362                 if (OTbinary(e.Eoper))
6363                     e.EV.E2 = elToPair(e.EV.E2);
6364                 if (e.EV.E1.Eoper == OPvar)
6365                 {
6366                 }
6367                 else if (e.EV.E1.Eoper == OPind)
6368                     e.EV.E1.EV.E1 = elToPair(e.EV.E1.EV.E1);
6369                 else
6370                     e.EV.E1 = elToPair(e.EV.E1);
6371             }
6372             else if (OTunary(e.Eoper))
6373             {
6374                 e.EV.E1 = elToPair(e.EV.E1);
6375             }
6376             else if (OTbinary(e.Eoper))
6377             {
6378                 e.EV.E2 = elToPair(e.EV.E2);
6379                 e.EV.E1 = elToPair(e.EV.E1);
6380             }
6381             break;
6382     }
6383     return e;
6384 }
6385 
6386 /******************************************
6387  * Determine if `b` can be moved before `a` without disturbing
6388  * order-of-evaluation semantics.
6389  */
6390 
6391 @trusted
6392 private bool canHappenAfter(elem* a, elem* b)
6393 {
6394     return a.Eoper == OPconst ||
6395            a.Eoper == OPrelconst ||
6396 
6397            /* a is a variable that is not aliased
6398             * and is not assigned to in b
6399             */
6400            (a.Eoper == OPvar && a.EV.Vsym.Sflags & SFLunambig && !el_appears(b, a.EV.Vsym)) ||
6401 
6402            !(el_sideeffect(a) || el_sideeffect(b));
6403 }
6404 
6405 
6406 /***************************************************
6407  * Call table, index is OPER
6408  */
6409 
6410 private extern (C++) alias elfp_t = elem *function(elem *, goal_t) nothrow;
6411 
6412 private extern (D) immutable elfp_t[OPMAX] elxxx =
6413 [
6414     OPunde:    &elerr,
6415     OPadd:     &eladd,
6416     OPmul:     &elmul,
6417     OPand:     &elbitwise,
6418     OPmin:     &elmin,
6419     OPnot:     &elnot,
6420     OPcom:     &elcom,
6421     OPcond:    &elcond,
6422     OPcomma:   &elcomma,
6423     OPremquo:  &elremquo,
6424     OPdiv:     &eldiv,
6425     OPmod:     &elmod,
6426     OPxor:     &elxor,
6427     OPstring:  &elstring,
6428     OPrelconst: &elzot,
6429     OPinp:     &elzot,
6430     OPoutp:    &elzot,
6431     OPasm:     &elzot,
6432     OPinfo:    &elinfo,
6433     OPdctor:   &elzot,
6434     OPddtor:   &elddtor,
6435     OPctor:    &elinfo,
6436     OPdtor:    &elinfo,
6437     OPmark:    &elinfo,
6438     OPvoid:    &elzot,
6439     OPhalt:    &elzot,
6440     OPnullptr: &elerr,
6441     OPpair:    &elpair,
6442     OPrpair:   &elpair,
6443 
6444     OPor:      &elor,
6445     OPoror:    &eloror,
6446     OPandand:  &elandand,
6447     OProl:     &elshl,
6448     OPror:     &elshl,
6449     OPshl:     &elshl,
6450     OPshr:     &elshr,
6451     OPashr:    &elshr,
6452     OPbit:     &elbit,
6453     OPind:     &elind,
6454     OPaddr:    &eladdr,
6455     OPneg:     &elneg,
6456     OPuadd:    &elzot,
6457     OPabs:     &evalu8,
6458     OPsqrt:    &evalu8,
6459     OPsin:     &evalu8,
6460     OPcos:     &evalu8,
6461     OPscale:   &elzot,
6462     OPyl2x:    &elzot,
6463     OPyl2xp1:  &elzot,
6464     OPcmpxchg:     &elzot,
6465     OPtoprec:  &elzot,
6466     OPrint:    &evalu8,
6467     OPrndtol:  &evalu8,
6468     OPstrlen:  &elzot,
6469     OPstrcpy:  &elstrcpy,
6470     OPmemcpy:  &elmemcpy,
6471     OPmemset:  &elmemset,
6472     OPstrcat:  &elzot,
6473     OPstrcmp:  &elstrcmp,
6474     OPmemcmp:  &elmemcmp,
6475     OPsetjmp:  &elzot,
6476     OPnegass:  &elnegass,
6477     OPpreinc:  &elzot,
6478     OPpredec:  &elzot,
6479     OPstreq:   &elstruct,
6480     OPpostinc: &elpost,
6481     OPpostdec: &elpost,
6482     OPeq:      &eleq,
6483     OPaddass:  &elopass,
6484     OPminass:  &elopass,
6485     OPmulass:  &elopass,
6486     OPdivass:  &elopass,
6487     OPmodass:  &elopass,
6488     OPshrass:  &elopass,
6489     OPashrass: &elopass,
6490     OPshlass:  &elopass,
6491     OPandass:  &elopass,
6492     OPxorass:  &elopass,
6493     OPorass:   &elopass,
6494 
6495     OPle:      &elcmp,
6496     OPgt:      &elcmp,
6497     OPlt:      &elcmp,
6498     OPge:      &elcmp,
6499     OPeqeq:    &elcmp,
6500     OPne:      &elcmp,
6501 
6502     OPunord:   &elcmp,
6503     OPlg:      &elcmp,
6504     OPleg:     &elcmp,
6505     OPule:     &elcmp,
6506     OPul:      &elcmp,
6507     OPuge:     &elcmp,
6508     OPug:      &elcmp,
6509     OPue:      &elcmp,
6510     OPngt:     &elcmp,
6511     OPnge:     &elcmp,
6512     OPnlt:     &elcmp,
6513     OPnle:     &elcmp,
6514     OPord:     &elcmp,
6515     OPnlg:     &elcmp,
6516     OPnleg:    &elcmp,
6517     OPnule:    &elcmp,
6518     OPnul:     &elcmp,
6519     OPnuge:    &elcmp,
6520     OPnug:     &elcmp,
6521     OPnue:     &elcmp,
6522 
6523     OPvp_fp:   &elvptrfptr,
6524     OPcvp_fp:  &elvptrfptr,
6525     OPoffset:  &ellngsht,
6526     OPnp_fp:   &elptrlptr,
6527     OPnp_f16p: &elzot,
6528     OPf16p_np: &elzot,
6529 
6530     OPs16_32:  &evalu8,
6531     OPu16_32:  &evalu8,
6532     OPd_s32:   &evalu8,
6533     OPb_8:     &evalu8,
6534     OPs32_d:   &evalu8,
6535     OPd_s16:   &evalu8,
6536     OPs16_d:   &evalu8,
6537     OPd_u16:   &evalu8,
6538     OPu16_d:   &evalu8,
6539     OPd_u32:   &evalu8,
6540     OPu32_d:   &evalu8,
6541     OP32_16:   &ellngsht,
6542     OPd_f:     &evalu8,
6543     OPf_d:     &evalu8,
6544     OPd_ld:    &evalu8,
6545     OPld_d:    &evalu8,
6546     OPc_r:     &elc_r,
6547     OPc_i:     &elc_i,
6548     OPu8_16:   &elbyteint,
6549     OPs8_16:   &elbyteint,
6550     OP16_8:    &ellngsht,
6551     OPu32_64:  &el32_64,
6552     OPs32_64:  &el32_64,
6553     OP64_32:   &el64_32,
6554     OPu64_128: &evalu8,
6555     OPs64_128: &evalu8,
6556     OP128_64:  &el64_32,
6557     OPmsw:     &elmsw,
6558 
6559     OPd_s64:   &evalu8,
6560     OPs64_d:   &evalu8,
6561     OPd_u64:   &evalu8,
6562     OPu64_d:   &elu64_d,
6563     OPld_u64:  &evalu8,
6564     OPparam:   &elparam,
6565     OPsizeof:  &elzot,
6566     OParrow:   &elzot,
6567     OParrowstar: &elzot,
6568     OPcolon:   &elzot,
6569     OPcolon2:  &elzot,
6570     OPbool:    &elbool,
6571     OPcall:    &elcall,
6572     OPucall:   &elcall,
6573     OPcallns:  &elcall,
6574     OPucallns: &elcall,
6575     OPstrpar:  &elstruct,
6576     OPstrctor: &elzot,
6577     OPstrthis: &elzot,
6578     OPconst:   &elerr,
6579     OPvar:     &elerr,
6580     OPreg:     &elerr,
6581     OPnew:     &elerr,
6582     OPanew:    &elerr,
6583     OPdelete:  &elerr,
6584     OPadelete: &elerr,
6585     OPbrack:   &elerr,
6586     OPframeptr: &elzot,
6587     OPgot:     &elzot,
6588 
6589     OPbsf:     &elzot,
6590     OPbsr:     &elzot,
6591     OPbtst:    &elzot,
6592     OPbt:      &elzot,
6593     OPbtc:     &elzot,
6594     OPbtr:     &elzot,
6595     OPbts:     &elzot,
6596 
6597     OPbswap:   &evalu8,
6598     OPpopcnt:  &evalu8,
6599     OPvector:  &elzot,
6600     OPvecsto:  &elzot,
6601     OPvecfill: &elzot,
6602     OPva_start: &elvalist,
6603     OPprefetch: &elzot,
6604 ];