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