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