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