1 /**
2  * Converts expressions to Intermediate Representation (IR) for the backend.
3  *
4  * Copyright:   Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/e2ir.d, _e2ir.d)
8  * Documentation: https://dlang.org/phobos/dmd_e2ir.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/e2ir.d
10  */
11 
12 module dmd.e2ir;
13 
14 import core.stdc.stdio;
15 import core.stdc.stddef;
16 import core.stdc.string;
17 import core.stdc.time;
18 
19 import dmd.root.array;
20 import dmd.root.ctfloat;
21 import dmd.root.rmem;
22 import dmd.root.rootobject;
23 import dmd.root.stringtable;
24 
25 import dmd.aggregate;
26 import dmd.arraytypes;
27 import dmd.attrib;
28 import dmd.canthrow;
29 import dmd.ctfeexpr;
30 import dmd.dclass;
31 import dmd.declaration;
32 import dmd.denum;
33 import dmd.dmodule;
34 import dmd.dscope;
35 import dmd.dstruct;
36 import dmd.dsymbol;
37 import dmd.dtemplate;
38 import dmd.errors;
39 import dmd.expression;
40 import dmd.func;
41 import dmd.globals;
42 import dmd.glue;
43 import dmd.id;
44 import dmd.init;
45 import dmd.mtype;
46 import dmd.objc_glue;
47 import dmd.s2ir;
48 import dmd.sideeffect;
49 import dmd.statement;
50 import dmd.target;
51 import dmd.tocsym;
52 import dmd.toctype;
53 import dmd.toir;
54 import dmd.tokens;
55 import dmd.toobj;
56 import dmd.typinf;
57 import dmd.visitor;
58 
59 import dmd.backend.cc;
60 import dmd.backend.cdef;
61 import dmd.backend.cgcv;
62 import dmd.backend.code;
63 import dmd.backend.code_x86;
64 import dmd.backend.cv4;
65 import dmd.backend.dt;
66 import dmd.backend.el;
67 import dmd.backend.global;
68 import dmd.backend.obj;
69 import dmd.backend.oper;
70 import dmd.backend.rtlsym;
71 import dmd.backend.symtab;
72 import dmd.backend.ty;
73 import dmd.backend.type;
74 
75 extern (C++):
76 
77 alias Elems = Array!(elem *);
78 
79 alias toSymbol = dmd.tocsym.toSymbol;
80 alias toSymbol = dmd.glue.toSymbol;
81 
82 void* mem_malloc2(uint);
83 
84 
85 @property int REGSIZE() { return _tysize[TYnptr]; }
86 
87 /* If variable var is a reference
88  */
89 bool ISREF(Declaration var)
90 {
91     if (var.isOut() || var.isRef())
92     {
93         return true;
94     }
95 
96     return ISX64REF(var);
97 }
98 
99 /* If variable var of type typ is a reference due to x64 calling conventions
100  */
101 bool ISX64REF(Declaration var)
102 {
103     if (var.isOut() || var.isRef())
104     {
105         return false;
106     }
107 
108     if (var.isParameter())
109     {
110         if (config.exe == EX_WIN64)
111         {
112             return var.type.size(Loc.initial) > REGSIZE
113                 || (var.storage_class & STC.lazy_)
114                 || (var.type.isTypeStruct() && !var.type.isTypeStruct().sym.isPOD());
115         }
116         else if (!global.params.isWindows)
117         {
118             return !(var.storage_class & STC.lazy_) && var.type.isTypeStruct() && !var.type.isTypeStruct().sym.isPOD();
119         }
120     }
121 
122     return false;
123 }
124 
125 /* If variable exp of type typ is a reference due to x64 calling conventions
126  */
127 bool ISX64REF(IRState* irs, Expression exp)
128 {
129     if (config.exe == EX_WIN64)
130     {
131         return exp.type.size(Loc.initial) > REGSIZE
132             || (exp.type.isTypeStruct() && !exp.type.isTypeStruct().sym.isPOD());
133     }
134     else if (!irs.params.isWindows)
135     {
136         return exp.type.isTypeStruct() && !exp.type.isTypeStruct().sym.isPOD();
137     }
138 
139     return false;
140 }
141 
142 /******************************************
143  * If argument to a function should use OPstrpar,
144  * fix it so it does and return it.
145  */
146 private elem *useOPstrpar(elem *e)
147 {
148     tym_t ty = tybasic(e.Ety);
149     if (ty == TYstruct || ty == TYarray)
150     {
151         e = el_una(OPstrpar, TYstruct, e);
152         e.ET = e.EV.E1.ET;
153         assert(e.ET);
154     }
155     return e;
156 }
157 
158 /************************************
159  * Call a function.
160  */
161 
162 private elem *callfunc(const ref Loc loc,
163         IRState *irs,
164         int directcall,         // 1: don't do virtual call
165         Type tret,              // return type
166         elem *ec,               // evaluates to function address
167         Type ectype,            // original type of ec
168         FuncDeclaration fd,     // if !=NULL, this is the function being called
169         Type t,                 // TypeDelegate or TypeFunction for this function
170         elem *ehidden,          // if !=null, this is the 'hidden' argument
171         Expressions *arguments,
172         elem *esel = null,      // selector for Objective-C methods (when not provided by fd)
173         elem *ethis2 = null)    // multi-context array
174 {
175     elem *ethis = null;
176     elem *eside = null;
177     elem *eresult = ehidden;
178 
179     version (none)
180     {
181         printf("callfunc(directcall = %d, tret = '%s', ec = %p, fd = %p)\n",
182             directcall, tret.toChars(), ec, fd);
183         printf("ec: "); elem_print(ec);
184         if (fd)
185             printf("fd = '%s', vtblIndex = %d, isVirtual() = %d\n", fd.toChars(), fd.vtblIndex, fd.isVirtual());
186         if (ehidden)
187         {   printf("ehidden: "); elem_print(ehidden); }
188     }
189 
190     t = t.toBasetype();
191     TypeFunction tf = t.isTypeFunction();
192     if (!tf)
193     {
194         assert(t.ty == Tdelegate);
195         // A delegate consists of:
196         //      { Object *this; Function *funcptr; }
197         assert(!fd);
198         tf = t.nextOf().isTypeFunction();
199         assert(tf);
200         ethis = ec;
201         ec = el_same(&ethis);
202         ethis = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYnptr, ethis); // get this
203         ec = array_toPtr(t, ec);                // get funcptr
204         ec = el_una(OPind, totym(tf), ec);
205     }
206 
207     const ty = fd ? toSymbol(fd).Stype.Tty : ec.Ety;
208     const left_to_right = tyrevfunc(ty);   // left-to-right parameter evaluation
209                                            // (TYnpfunc, TYjfunc, TYfpfunc, TYf16func)
210     elem* ep = null;
211     const op = fd ? intrinsic_op(fd) : NotIntrinsic;
212     if (arguments && arguments.dim)
213     {
214         if (op == OPvector)
215         {
216             Expression arg = (*arguments)[0];
217             if (arg.op != TOK.int64)
218                 arg.error("simd operator must be an integer constant, not `%s`", arg.toChars());
219         }
220 
221         /* Convert arguments[] to elems[] in left-to-right order
222          */
223         const n = arguments.dim;
224         debug
225             elem*[2] elems_array = void;
226         else
227             elem*[10] elems_array = void;
228         import core.stdc.stdlib : malloc, free;
229         auto pe = (n <= elems_array.length)
230                   ? elems_array.ptr
231                   : cast(elem**)Mem.check(malloc(arguments.dim * (elem*).sizeof));
232         elem*[] elems = pe[0 .. n];
233 
234         /* Fill elems[] with arguments converted to elems
235          */
236 
237         // j=1 if _arguments[] is first argument
238         const int j = tf.isDstyleVariadic();
239 
240         foreach (const i, arg; *arguments)
241         {
242             elem *ea = toElem(arg, irs);
243 
244             //printf("\targ[%d]: %s\n", i, arg.toChars());
245 
246             if (i - j < tf.parameterList.length &&
247                 i >= j &&
248                 tf.parameterList[i - j].isReference())
249             {
250                 /* `ref` and `out` parameters mean convert
251                  * corresponding argument to a pointer
252                  */
253                 elems[i] = addressElem(ea, arg.type.pointerTo());
254                 continue;
255             }
256 
257             if (ISX64REF(irs, arg) && op == NotIntrinsic)
258             {
259                 /* Copy to a temporary, and make the argument a pointer
260                  * to that temporary.
261                  */
262                 elems[i] = addressElem(ea, arg.type, true);
263                 continue;
264             }
265 
266             if (config.exe == EX_WIN64 && tybasic(ea.Ety) == TYcfloat)
267             {
268                 /* Treat a cfloat like it was a struct { float re,im; }
269                  */
270                 ea.Ety = TYllong;
271             }
272             elems[i] = ea;
273         }
274         if (!left_to_right)
275         {
276             eside = fixArgumentEvaluationOrder(elems);
277         }
278 
279         foreach (ref e; elems)
280         {
281             e = useOPstrpar(e);
282         }
283 
284         if (!left_to_right)   // swap order if right-to-left
285             reverse(elems);
286 
287         ep = el_params(cast(void**)elems.ptr, cast(int)n);
288 
289         if (elems.ptr != elems_array.ptr)
290             free(elems.ptr);
291     }
292 
293     objc.setupMethodSelector(fd, &esel);
294     objc.setupEp(esel, &ep, left_to_right);
295 
296     const retmethod = retStyle(tf, fd && fd.needThis());
297     if (retmethod == RET.stack)
298     {
299         if (!ehidden)
300         {
301             // Don't have one, so create one
302             type *tc;
303 
304             Type tret2 = tf.next;
305             if (tret2.toBasetype().ty == Tstruct ||
306                 tret2.toBasetype().ty == Tsarray)
307                 tc = Type_toCtype(tret2);
308             else
309                 tc = type_fake(totym(tret2));
310             Symbol *stmp = symbol_genauto(tc);
311             ehidden = el_ptr(stmp);
312             eresult = ehidden;
313         }
314         if (target.isPOSIX && tf.linkage != LINK.d)
315         {
316                 // ehidden goes last on Linux/OSX C++
317         }
318         else
319         {
320             if (ep)
321             {
322                 /* // BUG: implement
323                 if (left_to_right && type_mangle(tfunc) == mTYman_cpp)
324                     ep = el_param(ehidden,ep);
325                 else
326                 */
327                     ep = el_param(ep,ehidden);
328             }
329             else
330                 ep = ehidden;
331             ehidden = null;
332         }
333     }
334 
335     if (fd && fd.isMemberLocal())
336     {
337         assert(op == NotIntrinsic);       // members should not be intrinsics
338 
339         AggregateDeclaration ad = fd.isThis();
340         if (ad)
341         {
342             ethis = ec;
343             if (ad.isStructDeclaration() && tybasic(ec.Ety) != TYnptr)
344             {
345                 ethis = addressElem(ec, ectype);
346             }
347             if (ethis2)
348             {
349                 ethis2 = setEthis2(loc, irs, fd, ethis2, &ethis, &eside);
350             }
351             if (el_sideeffect(ethis))
352             {
353                 elem *ex = ethis;
354                 ethis = el_copytotmp(&ex);
355                 eside = el_combine(ex, eside);
356             }
357         }
358         else
359         {
360             // Evaluate ec for side effects
361             eside = el_combine(ec, eside);
362         }
363         Symbol *sfunc = toSymbol(fd);
364 
365         if (esel)
366         {
367             auto result = objc.setupMethodCall(fd, tf, directcall != 0, ec, ehidden, ethis);
368             ec = result.ec;
369             ethis = result.ethis;
370         }
371         else if (!fd.isVirtual() ||
372             directcall ||               // BUG: fix
373             fd.isFinalFunc()
374            /* Future optimization: || (whole program analysis && not overridden)
375             */
376            )
377         {
378             // make static call
379             ec = el_var(sfunc);
380         }
381         else
382         {
383             // make virtual call
384             assert(ethis);
385             elem *ev = el_same(&ethis);
386             ev = el_una(OPind, TYnptr, ev);
387             uint vindex = fd.vtblIndex;
388             assert(cast(int)vindex >= 0);
389 
390             // Build *(ev + vindex * 4)
391 if (!irs.params.is64bit) assert(tysize(TYnptr) == 4);
392             ec = el_bin(OPadd,TYnptr,ev,el_long(TYsize_t, vindex * tysize(TYnptr)));
393             ec = el_una(OPind,TYnptr,ec);
394             ec = el_una(OPind,tybasic(sfunc.Stype.Tty),ec);
395         }
396     }
397     else if (fd && fd.isNested())
398     {
399         assert(!ethis);
400         ethis = getEthis(loc, irs, fd, fd.toParentLocal());
401         if (ethis2)
402             ethis2 = setEthis2(loc, irs, fd, ethis2, &ethis, &eside);
403     }
404 
405     ep = el_param(ep, ethis2 ? ethis2 : ethis);
406     if (ehidden)
407         ep = el_param(ep, ehidden);     // if ehidden goes last
408 
409     const tyret = totym(tret);
410 
411     // Look for intrinsic functions and construct result into e
412     elem *e;
413     if (ec.Eoper == OPvar && op != NotIntrinsic)
414     {
415         el_free(ec);
416         if (op != OPtoPrec && OTbinary(op))
417         {
418             ep.Eoper = cast(ubyte)op;
419             ep.Ety = tyret;
420             e = ep;
421             if (op == OPeq)
422             {   /* This was a volatileStore(ptr, value) operation, rewrite as:
423                  *   *ptr = value
424                  */
425                 e.EV.E1 = el_una(OPind, e.EV.E2.Ety | mTYvolatile, e.EV.E1);
426             }
427             if (op == OPscale)
428             {
429                 elem *et = e.EV.E1;
430                 e.EV.E1 = el_una(OPs32_d, TYdouble, e.EV.E2);
431                 e.EV.E1 = el_una(OPd_ld, TYldouble, e.EV.E1);
432                 e.EV.E2 = et;
433             }
434             else if (op == OPyl2x || op == OPyl2xp1)
435             {
436                 elem *et = e.EV.E1;
437                 e.EV.E1 = e.EV.E2;
438                 e.EV.E2 = et;
439             }
440         }
441         else if (op == OPvector)
442         {
443             e = ep;
444             /* Recognize store operations as:
445              *  (op OPparam (op1 OPparam op2))
446              * Rewrite as:
447              *  (op1 OPvecsto (op OPparam op2))
448              * A separate operation is used for stores because it
449              * has a side effect, and so takes a different path through
450              * the optimizer.
451              */
452             if (e.Eoper == OPparam &&
453                 e.EV.E1.Eoper == OPconst &&
454                 isXMMstore(cast(uint)el_tolong(e.EV.E1)))
455             {
456                 //printf("OPvecsto\n");
457                 elem *tmp = e.EV.E1;
458                 e.EV.E1 = e.EV.E2.EV.E1;
459                 e.EV.E2.EV.E1 = tmp;
460                 e.Eoper = OPvecsto;
461                 e.Ety = tyret;
462             }
463             else
464                 e = el_una(op,tyret,ep);
465         }
466         else if (op == OPind)
467             e = el_una(op,mTYvolatile | tyret,ep);
468         else if (op == OPva_start && irs.params.is64bit)
469         {
470             // (OPparam &va &arg)
471             // call as (OPva_start &va)
472             ep.Eoper = cast(ubyte)op;
473             ep.Ety = tyret;
474             e = ep;
475 
476             elem *earg = e.EV.E2;
477             e.EV.E2 = null;
478             e = el_combine(earg, e);
479         }
480         else if (op == OPtoPrec)
481         {
482             static int X(int fty, int tty) { return fty * TMAX + tty; }
483 
484             final switch (X(tybasic(ep.Ety), tybasic(tyret)))
485             {
486             case X(TYfloat, TYfloat):     // float -> float
487             case X(TYdouble, TYdouble):   // double -> double
488             case X(TYldouble, TYldouble): // real -> real
489                 e = ep;
490                 break;
491 
492             case X(TYfloat, TYdouble):    // float -> double
493                 e = el_una(OPf_d, tyret, ep);
494                 break;
495 
496             case X(TYfloat, TYldouble):   // float -> real
497                 e = el_una(OPf_d, TYdouble, ep);
498                 e = el_una(OPd_ld, tyret, e);
499                 break;
500 
501             case X(TYdouble, TYfloat):    // double -> float
502                 e = el_una(OPd_f, tyret, ep);
503                 break;
504 
505             case X(TYdouble, TYldouble):  // double -> real
506                 e = el_una(OPd_ld, tyret, ep);
507                 break;
508 
509             case X(TYldouble, TYfloat):   // real -> float
510                 e = el_una(OPld_d, TYdouble, ep);
511                 e = el_una(OPd_f, tyret, e);
512                 break;
513 
514             case X(TYldouble, TYdouble):  // real -> double
515                 e = el_una(OPld_d, tyret, ep);
516                 break;
517             }
518         }
519         else
520             e = el_una(op,tyret,ep);
521     }
522     else
523     {
524         /* Do not do "no side effect" calls if a hidden parameter is passed,
525          * as the return value is stored through the hidden parameter, which
526          * is a side effect.
527          */
528         //printf("1: fd = %p prity = %d, nothrow = %d, retmethod = %d, use-assert = %d\n",
529         //       fd, (fd ? fd.isPure() : tf.purity), tf.isnothrow, retmethod, irs.params.useAssert);
530         //printf("\tfd = %s, tf = %s\n", fd.toChars(), tf.toChars());
531         /* assert() has 'implicit side effect' so disable this optimization.
532          */
533         int ns = ((fd ? callSideEffectLevel(fd)
534                       : callSideEffectLevel(t)) == 2 &&
535                   retmethod != RET.stack &&
536                   irs.params.useAssert == CHECKENABLE.off && irs.params.optimize);
537         if (ep)
538             e = el_bin(ns ? OPcallns : OPcall, tyret, ec, ep);
539         else
540             e = el_una(ns ? OPucallns : OPucall, tyret, ec);
541 
542         if (tf.parameterList.varargs != VarArg.none)
543             e.Eflags |= EFLAGS_variadic;
544     }
545 
546     const isCPPCtor = fd && fd.linkage == LINK.cpp && fd.isCtorDeclaration();
547     if (isCPPCtor && target.isPOSIX)
548     {
549         // CPP constructor returns void on Posix
550         // https://itanium-cxx-abi.github.io/cxx-abi/abi.html#return-value-ctor
551         e.Ety = TYvoid;
552         e = el_combine(e, el_same(&ethis));
553     }
554     else if (retmethod == RET.stack)
555     {
556         if (irs.params.isOSX && eresult)
557         {
558             /* ABI quirk: hidden pointer is not returned in registers
559              */
560             if (tyaggregate(tyret))
561                 e.ET = Type_toCtype(tret);
562             e = el_combine(e, el_copytree(eresult));
563         }
564         e.Ety = TYnptr;
565         e = el_una(OPind, tyret, e);
566     }
567 
568     if (tf.isref)
569     {
570         e.Ety = TYnptr;
571         e = el_una(OPind, tyret, e);
572     }
573 
574     if (tybasic(tyret) == TYstruct)
575     {
576         e.ET = Type_toCtype(tret);
577     }
578     e = el_combine(eside, e);
579     return e;
580 }
581 
582 /**********************************
583  * D presumes left-to-right argument evaluation, but we're evaluating things
584  * right-to-left here.
585  * 1. determine if this matters
586  * 2. fix it if it does
587  * Params:
588  *      arguments = function arguments, these will get rewritten in place
589  * Returns:
590  *      elem that evaluates the side effects
591  */
592 private extern (D) elem *fixArgumentEvaluationOrder(elem*[] elems)
593 {
594     /* It matters if all are true:
595      * 1. at least one argument has side effects
596      * 2. at least one other argument may depend on side effects
597      */
598     if (elems.length <= 1)
599         return null;
600 
601     size_t ifirstside = 0;      // index-1 of first side effect
602     size_t ifirstdep = 0;       // index-1 of first dependency on side effect
603     foreach (i, e; elems)
604     {
605         switch (e.Eoper)
606         {
607             case OPconst:
608             case OPrelconst:
609             case OPstring:
610                 continue;
611 
612             default:
613                 break;
614         }
615 
616         if (el_sideeffect(e))
617         {
618             if (!ifirstside)
619                 ifirstside = i + 1;
620             else if (!ifirstdep)
621                 ifirstdep = i + 1;
622         }
623         else
624         {
625             if (!ifirstdep)
626                 ifirstdep = i + 1;
627         }
628         if (ifirstside && ifirstdep)
629             break;
630     }
631 
632     if (!ifirstdep || !ifirstside)
633         return null;
634 
635     /* Now fix by appending side effects and dependencies to eside and replacing
636      * argument with a temporary.
637      * Rely on the optimizer removing some unneeded ones using flow analysis.
638      */
639     elem* eside = null;
640     foreach (i, e; elems)
641     {
642         while (e.Eoper == OPcomma)
643         {
644             eside = el_combine(eside, e.EV.E1);
645             e = e.EV.E2;
646             elems[i] = e;
647         }
648 
649         switch (e.Eoper)
650         {
651             case OPconst:
652             case OPrelconst:
653             case OPstring:
654                 continue;
655 
656             default:
657                 break;
658         }
659 
660         elem *es = e;
661         elems[i] = el_copytotmp(&es);
662         eside = el_combine(eside, es);
663     }
664 
665     return eside;
666 }
667 
668 /*******************************************
669  * Take address of an elem.
670  */
671 
672 elem *addressElem(elem *e, Type t, bool alwaysCopy = false)
673 {
674     //printf("addressElem()\n");
675 
676     elem **pe;
677     for (pe = &e; (*pe).Eoper == OPcomma; pe = &(*pe).EV.E2)
678     {
679     }
680 
681     // For conditional operator, both branches need conversion.
682     if ((*pe).Eoper == OPcond)
683     {
684         elem *ec = (*pe).EV.E2;
685 
686         ec.EV.E1 = addressElem(ec.EV.E1, t, alwaysCopy);
687         ec.EV.E2 = addressElem(ec.EV.E2, t, alwaysCopy);
688 
689         (*pe).Ejty = (*pe).Ety = cast(ubyte)ec.EV.E1.Ety;
690         (*pe).ET = ec.EV.E1.ET;
691 
692         e.Ety = TYnptr;
693         return e;
694     }
695 
696     if (alwaysCopy || ((*pe).Eoper != OPvar && (*pe).Eoper != OPind))
697     {
698         elem *e2 = *pe;
699         type *tx;
700 
701         // Convert to ((tmp=e2),tmp)
702         TY ty;
703         if (t && ((ty = t.toBasetype().ty) == Tstruct || ty == Tsarray))
704             tx = Type_toCtype(t);
705         else if (tybasic(e2.Ety) == TYstruct)
706         {
707             assert(t);                  // don't know of a case where this can be null
708             tx = Type_toCtype(t);
709         }
710         else
711             tx = type_fake(e2.Ety);
712         Symbol *stmp = symbol_genauto(tx);
713 
714         elem *eeq = elAssign(el_var(stmp), e2, t, tx);
715         *pe = el_bin(OPcomma,e2.Ety,eeq,el_var(stmp));
716     }
717     tym_t typ = TYnptr;
718     if (e.Eoper == OPind && tybasic(e.EV.E1.Ety) == TYimmutPtr)
719         typ = TYimmutPtr;
720     e = el_una(OPaddr,typ,e);
721     return e;
722 }
723 
724 /***************************************
725  * Return `true` if elem is a an lvalue.
726  * Lvalue elems are OPvar and OPind.
727  */
728 
729 bool elemIsLvalue(elem* e)
730 {
731     while (e.Eoper == OPcomma || e.Eoper == OPinfo)
732         e = e.EV.E2;
733 
734     // For conditional operator, both branches need to be lvalues.
735     if (e.Eoper == OPcond)
736     {
737         elem* ec = e.EV.E2;
738         return elemIsLvalue(ec.EV.E1) && elemIsLvalue(ec.EV.E2);
739     }
740 
741     return e.Eoper == OPvar || e.Eoper == OPind;
742 }
743 
744 /*****************************************
745  * Convert array to a pointer to the data.
746  * Params:
747  *      t = array type
748  *      e = array to convert, it is "consumed" by the function
749  * Returns:
750  *      e rebuilt into a pointer to the data
751  */
752 
753 elem *array_toPtr(Type t, elem *e)
754 {
755     //printf("array_toPtr()\n");
756     //elem_print(e);
757     t = t.toBasetype();
758     switch (t.ty)
759     {
760         case Tpointer:
761             break;
762 
763         case Tarray:
764         case Tdelegate:
765             if (e.Eoper == OPcomma)
766             {
767                 e.Ety = TYnptr;
768                 e.EV.E2 = array_toPtr(t, e.EV.E2);
769             }
770             else if (e.Eoper == OPpair)
771             {
772                 if (el_sideeffect(e.EV.E1))
773                 {
774                     e.Eoper = OPcomma;
775                     e.Ety = TYnptr;
776                 }
777                 else
778                 {
779                     auto r = e;
780                     e = e.EV.E2;
781                     e.Ety = TYnptr;
782                     r.EV.E2 = null;
783                     el_free(r);
784                 }
785             }
786             else
787             {
788 version (all)
789                 e = el_una(OPmsw, TYnptr, e);
790 else
791 {
792                 e = el_una(OPaddr, TYnptr, e);
793                 e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, 4));
794                 e = el_una(OPind, TYnptr, e);
795 }
796             }
797             break;
798 
799         case Tsarray:
800             //e = el_una(OPaddr, TYnptr, e);
801             e = addressElem(e, t);
802             break;
803 
804         default:
805             printf("%s\n", t.toChars());
806             assert(0);
807     }
808     return e;
809 }
810 
811 /*****************************************
812  * Convert array to a dynamic array.
813  */
814 
815 elem *array_toDarray(Type t, elem *e)
816 {
817     uint dim;
818     elem *ef = null;
819     elem *ex;
820 
821     //printf("array_toDarray(t = %s)\n", t.toChars());
822     //elem_print(e);
823     t = t.toBasetype();
824     switch (t.ty)
825     {
826         case Tarray:
827             break;
828 
829         case Tsarray:
830             e = addressElem(e, t);
831             dim = cast(uint)(cast(TypeSArray)t).dim.toInteger();
832             e = el_pair(TYdarray, el_long(TYsize_t, dim), e);
833             break;
834 
835         default:
836         L1:
837             switch (e.Eoper)
838             {
839                 case OPconst:
840                 {
841                     size_t len = tysize(e.Ety);
842                     elem *es = el_calloc();
843                     es.Eoper = OPstring;
844 
845                     // freed in el_free
846                     es.EV.Vstring = cast(char*)mem_malloc2(cast(uint)len);
847                     memcpy(es.EV.Vstring, &e.EV, len);
848 
849                     es.EV.Vstrlen = len;
850                     es.Ety = TYnptr;
851                     e = es;
852                     break;
853                 }
854 
855                 case OPvar:
856                     e = el_una(OPaddr, TYnptr, e);
857                     break;
858 
859                 case OPcomma:
860                     ef = el_combine(ef, e.EV.E1);
861                     ex = e;
862                     e = e.EV.E2;
863                     ex.EV.E1 = null;
864                     ex.EV.E2 = null;
865                     el_free(ex);
866                     goto L1;
867 
868                 case OPind:
869                     ex = e;
870                     e = e.EV.E1;
871                     ex.EV.E1 = null;
872                     ex.EV.E2 = null;
873                     el_free(ex);
874                     break;
875 
876                 default:
877                 {
878                     // Copy expression to a variable and take the
879                     // address of that variable.
880                     e = addressElem(e, t);
881                     break;
882                 }
883             }
884             dim = 1;
885             e = el_pair(TYdarray, el_long(TYsize_t, dim), e);
886             break;
887     }
888     return el_combine(ef, e);
889 }
890 
891 /************************************
892  */
893 
894 elem *sarray_toDarray(const ref Loc loc, Type tfrom, Type tto, elem *e)
895 {
896     //printf("sarray_toDarray()\n");
897     //elem_print(e);
898 
899     dinteger_t dim = (cast(TypeSArray)tfrom).dim.toInteger();
900 
901     if (tto)
902     {
903         uint fsize = cast(uint)tfrom.nextOf().size();
904         uint tsize = cast(uint)tto.nextOf().size();
905 
906         if ((dim * fsize) % tsize != 0)
907         {
908             // have to change to Internal Compiler Error?
909             error(loc, "cannot cast %s to %s since sizes don't line up", tfrom.toChars(), tto.toChars());
910         }
911         dim = (dim * fsize) / tsize;
912     }
913     elem *elen = el_long(TYsize_t, dim);
914     e = addressElem(e, tfrom);
915     e = el_pair(TYdarray, elen, e);
916     return e;
917 }
918 
919 /************************************
920  */
921 
922 elem *getTypeInfo(Loc loc, Type t, IRState *irs)
923 {
924     assert(t.ty != Terror);
925     genTypeInfo(loc, t, null);
926     elem *e = el_ptr(toSymbol(t.vtinfo));
927     return e;
928 }
929 
930 /********************************************
931  * Determine if t is a struct that has postblit.
932  */
933 StructDeclaration needsPostblit(Type t)
934 {
935     if (auto ts = t.baseElemOf().isTypeStruct())
936     {
937         StructDeclaration sd = ts.sym;
938         if (sd.postblit)
939             return sd;
940     }
941     return null;
942 }
943 
944 /********************************************
945  * Determine if t is a struct that has destructor.
946  */
947 StructDeclaration needsDtor(Type t)
948 {
949     if (auto ts = t.baseElemOf().isTypeStruct())
950     {
951         StructDeclaration sd = ts.sym;
952         if (sd.dtor)
953             return sd;
954     }
955     return null;
956 }
957 
958 /*******************************************
959  * Set an array pointed to by eptr to evalue:
960  *      eptr[0..edim] = evalue;
961  * Params:
962  *      exp    = the expression for which this operation is performed
963  *      eptr   = where to write the data to
964  *      edim   = number of times to write evalue to eptr[]
965  *      tb     = type of evalue
966  *      evalue = value to write
967  *      irs    = context
968  *      op     = TOK.blit, TOK.assign, or TOK.construct
969  * Returns:
970  *      created IR code
971  */
972 private elem *setArray(Expression exp, elem *eptr, elem *edim, Type tb, elem *evalue, IRState *irs, int op)
973 {
974     assert(op == TOK.blit || op == TOK.assign || op == TOK.construct);
975     const sz = cast(uint)tb.size();
976     Type tb2 = tb;
977 
978 Lagain:
979     int r;
980     switch (tb2.ty)
981     {
982         case Tfloat80:
983         case Timaginary80:
984             r = RTLSYM_MEMSET80;
985             break;
986         case Tcomplex80:
987             r = RTLSYM_MEMSET160;
988             break;
989         case Tcomplex64:
990             r = RTLSYM_MEMSET128;
991             break;
992         case Tfloat32:
993         case Timaginary32:
994             if (!irs.params.is64bit)
995                 goto default;          // legacy binary compatibility
996             r = RTLSYM_MEMSETFLOAT;
997             break;
998         case Tfloat64:
999         case Timaginary64:
1000             if (!irs.params.is64bit)
1001                 goto default;          // legacy binary compatibility
1002             r = RTLSYM_MEMSETDOUBLE;
1003             break;
1004 
1005         case Tstruct:
1006         {
1007             if (!irs.params.is64bit)
1008                 goto default;
1009 
1010             TypeStruct tc = cast(TypeStruct)tb2;
1011             StructDeclaration sd = tc.sym;
1012             if (sd.numArgTypes() == 1)
1013             {
1014                 tb2 = sd.argType(0);
1015                 goto Lagain;
1016             }
1017             goto default;
1018         }
1019 
1020         case Tvector:
1021             r = RTLSYM_MEMSETSIMD;
1022             break;
1023 
1024         default:
1025             switch (sz)
1026             {
1027                 case 1:      r = RTLSYM_MEMSET8;    break;
1028                 case 2:      r = RTLSYM_MEMSET16;   break;
1029                 case 4:      r = RTLSYM_MEMSET32;   break;
1030                 case 8:      r = RTLSYM_MEMSET64;   break;
1031                 case 16:     r = irs.params.is64bit ? RTLSYM_MEMSET128ii : RTLSYM_MEMSET128; break;
1032                 default:     r = RTLSYM_MEMSETN;    break;
1033             }
1034 
1035             /* Determine if we need to do postblit
1036              */
1037             if (op != TOK.blit)
1038             {
1039                 if (needsPostblit(tb) || needsDtor(tb))
1040                 {
1041                     /* Need to do postblit/destructor.
1042                      *   void *_d_arraysetassign(void *p, void *value, int dim, TypeInfo ti);
1043                      */
1044                     r = (op == TOK.construct) ? RTLSYM_ARRAYSETCTOR : RTLSYM_ARRAYSETASSIGN;
1045                     evalue = el_una(OPaddr, TYnptr, evalue);
1046                     // This is a hack so we can call postblits on const/immutable objects.
1047                     elem *eti = getTypeInfo(exp.loc, tb.unSharedOf().mutableOf(), irs);
1048                     elem *e = el_params(eti, edim, evalue, eptr, null);
1049                     e = el_bin(OPcall,TYnptr,el_var(getRtlsym(r)),e);
1050                     return e;
1051                 }
1052             }
1053 
1054             if (irs.params.is64bit && tybasic(evalue.Ety) == TYstruct && r != RTLSYM_MEMSETN)
1055             {
1056                 /* If this struct is in-memory only, i.e. cannot necessarily be passed as
1057                  * a gp register parameter.
1058                  * The trouble is that memset() is expecting the argument to be in a gp
1059                  * register, but the argument pusher may have other ideas on I64.
1060                  * MEMSETN is inefficient, though.
1061                  */
1062                 if (tybasic(evalue.ET.Tty) == TYstruct)
1063                 {
1064                     type *t1 = evalue.ET.Ttag.Sstruct.Sarg1type;
1065                     type *t2 = evalue.ET.Ttag.Sstruct.Sarg2type;
1066                     if (!t1 && !t2)
1067                     {
1068                         if (config.exe != EX_WIN64 || sz > 8)
1069                             r = RTLSYM_MEMSETN;
1070                     }
1071                     else if (config.exe != EX_WIN64 &&
1072                              r == RTLSYM_MEMSET128ii &&
1073                              tyfloating(t1.Tty) &&
1074                              tyfloating(t2.Tty))
1075                         r = RTLSYM_MEMSET128;
1076                 }
1077             }
1078 
1079             if (r == RTLSYM_MEMSETN)
1080             {
1081                 // void *_memsetn(void *p, void *value, int dim, int sizelem)
1082                 evalue = addressElem(evalue, tb);
1083                 elem *esz = el_long(TYsize_t, sz);
1084                 elem *e = el_params(esz, edim, evalue, eptr, null);
1085                 e = el_bin(OPcall,TYnptr,el_var(getRtlsym(r)),e);
1086                 return e;
1087             }
1088             break;
1089     }
1090     if (sz > 1 && sz <= 8 &&
1091         evalue.Eoper == OPconst && el_allbits(evalue, 0))
1092     {
1093         r = RTLSYM_MEMSET8;
1094         edim = el_bin(OPmul, TYsize_t, edim, el_long(TYsize_t, sz));
1095     }
1096 
1097     if (config.exe == EX_WIN64 && sz > REGSIZE)
1098     {
1099         evalue = addressElem(evalue, tb);
1100     }
1101     // cast to the proper parameter type
1102     else if (r != RTLSYM_MEMSETN)
1103     {
1104         tym_t tym;
1105         switch (r)
1106         {
1107             case RTLSYM_MEMSET8:      tym = TYchar;     break;
1108             case RTLSYM_MEMSET16:     tym = TYshort;    break;
1109             case RTLSYM_MEMSET32:     tym = TYlong;     break;
1110             case RTLSYM_MEMSET64:     tym = TYllong;    break;
1111             case RTLSYM_MEMSET80:     tym = TYldouble;  break;
1112             case RTLSYM_MEMSET160:    tym = TYcldouble; break;
1113             case RTLSYM_MEMSET128:    tym = TYcdouble;  break;
1114             case RTLSYM_MEMSET128ii:  tym = TYucent;    break;
1115             case RTLSYM_MEMSETFLOAT:  tym = TYfloat;    break;
1116             case RTLSYM_MEMSETDOUBLE: tym = TYdouble;   break;
1117             case RTLSYM_MEMSETSIMD:   tym = TYfloat4;   break;
1118             default:
1119                 assert(0);
1120         }
1121         tym = tym | (evalue.Ety & ~mTYbasic);
1122         evalue = addressElem(evalue, tb);
1123         evalue = el_una(OPind, tym, evalue);
1124     }
1125 
1126     evalue = useOPstrpar(evalue);
1127 
1128     // Be careful about parameter side effect ordering
1129     if (r == RTLSYM_MEMSET8)
1130     {
1131         elem *e = el_param(edim, evalue);
1132         return el_bin(OPmemset,TYnptr,eptr,e);
1133     }
1134     else
1135     {
1136         elem *e = el_params(edim, evalue, eptr, null);
1137         return el_bin(OPcall,TYnptr,el_var(getRtlsym(r)),e);
1138     }
1139 }
1140 
1141 
1142 __gshared StringTable!(Symbol*) *stringTab;
1143 
1144 /********************************
1145  * Reset stringTab[] between object files being emitted, because the symbols are local.
1146  */
1147 void clearStringTab()
1148 {
1149     //printf("clearStringTab()\n");
1150     if (stringTab)
1151         stringTab.reset(1000);             // 1000 is arbitrary guess
1152     else
1153     {
1154         stringTab = new StringTable!(Symbol*)();
1155         stringTab._init(1000);
1156     }
1157 }
1158 
1159 
1160 elem *toElem(Expression e, IRState *irs)
1161 {
1162     extern (C++) class ToElemVisitor : Visitor
1163     {
1164         IRState *irs;
1165         elem *result;
1166 
1167         this(IRState *irs)
1168         {
1169             this.irs = irs;
1170             result = null;
1171         }
1172 
1173         alias visit = Visitor.visit;
1174 
1175         /***************************************
1176          */
1177 
1178         override void visit(Expression e)
1179         {
1180             printf("[%s] %s: %s\n", e.loc.toChars(), Token.toChars(e.op), e.toChars());
1181             assert(0);
1182         }
1183 
1184         /************************************
1185          */
1186         override void visit(SymbolExp se)
1187         {
1188             elem *e;
1189             Type tb = (se.op == TOK.symbolOffset) ? se.var.type.toBasetype() : se.type.toBasetype();
1190             int offset = (se.op == TOK.symbolOffset) ? cast(int)(cast(SymOffExp)se).offset : 0;
1191             VarDeclaration v = se.var.isVarDeclaration();
1192 
1193             //printf("[%s] SymbolExp.toElem('%s') %p, %s\n", se.loc.toChars(), se.toChars(), se, se.type.toChars());
1194             //printf("\tparent = '%s'\n", se.var.parent ? se.var.parent.toChars() : "null");
1195             if (se.op == TOK.variable && se.var.needThis())
1196             {
1197                 se.error("need `this` to access member `%s`", se.toChars());
1198                 result = el_long(TYsize_t, 0);
1199                 return;
1200             }
1201 
1202             /* The magic variable __ctfe is always false at runtime
1203              */
1204             if (se.op == TOK.variable && v && v.ident == Id.ctfe)
1205             {
1206                 result = el_long(totym(se.type), 0);
1207                 return;
1208             }
1209 
1210             if (FuncLiteralDeclaration fld = se.var.isFuncLiteralDeclaration())
1211             {
1212                 if (fld.tok == TOK.reserved)
1213                 {
1214                     // change to non-nested
1215                     fld.tok = TOK.function_;
1216                     fld.vthis = null;
1217                 }
1218                 if (!fld.deferToObj)
1219                 {
1220                     fld.deferToObj = true;
1221                     irs.deferToObj.push(fld);
1222                 }
1223             }
1224 
1225             Symbol *s = toSymbol(se.var);
1226             FuncDeclaration fd = null;
1227             if (se.var.toParent2())
1228                 fd = se.var.toParent2().isFuncDeclaration();
1229 
1230             const bool nrvo = fd && fd.nrvo_can && fd.nrvo_var == se.var;
1231             if (nrvo)
1232                 s = fd.shidden;
1233 
1234             if (s.Sclass == SCauto || s.Sclass == SCparameter || s.Sclass == SCshadowreg)
1235             {
1236                 if (fd && fd != irs.getFunc())
1237                 {
1238                     // 'var' is a variable in an enclosing function.
1239                     elem *ethis = getEthis(se.loc, irs, fd, null, se.originalScope);
1240                     ethis = el_una(OPaddr, TYnptr, ethis);
1241 
1242                     /* https://issues.dlang.org/show_bug.cgi?id=9383
1243                      * If 's' is a virtual function parameter
1244                      * placed in closure, and actually accessed from in/out
1245                      * contract, instead look at the original stack data.
1246                      */
1247                     bool forceStackAccess = false;
1248                     if (fd.isVirtual() && (fd.fdrequire || fd.fdensure))
1249                     {
1250                         Dsymbol sx = irs.getFunc();
1251                         while (sx != fd)
1252                         {
1253                             if (sx.ident == Id.require || sx.ident == Id.ensure)
1254                             {
1255                                 forceStackAccess = true;
1256                                 break;
1257                             }
1258                             sx = sx.toParent2();
1259                         }
1260                     }
1261 
1262                     int soffset;
1263                     if (v && v.offset && !forceStackAccess)
1264                         soffset = v.offset;
1265                     else
1266                     {
1267                         soffset = cast(int)s.Soffset;
1268                         /* If fd is a non-static member function of a class or struct,
1269                          * then ethis isn't the frame pointer.
1270                          * ethis is the 'this' pointer to the class/struct instance.
1271                          * We must offset it.
1272                          */
1273                         if (fd.vthis)
1274                         {
1275                             Symbol *vs = toSymbol(fd.vthis);
1276                             //printf("vs = %s, offset = %x, %p\n", vs.Sident, (int)vs.Soffset, vs);
1277                             soffset -= vs.Soffset;
1278                         }
1279                         //printf("\tSoffset = x%x, sthis.Soffset = x%x\n", s.Soffset, irs.sthis.Soffset);
1280                     }
1281 
1282                     if (!nrvo)
1283                         soffset += offset;
1284 
1285                     e = el_bin(OPadd, TYnptr, ethis, el_long(TYnptr, soffset));
1286                     if (se.op == TOK.variable)
1287                         e = el_una(OPind, TYnptr, e);
1288                     if (ISREF(se.var) && !(ISX64REF(se.var) && v && v.offset && !forceStackAccess))
1289                         e = el_una(OPind, s.Stype.Tty, e);
1290                     else if (se.op == TOK.symbolOffset && nrvo)
1291                     {
1292                         e = el_una(OPind, TYnptr, e);
1293                         e = el_bin(OPadd, e.Ety, e, el_long(TYsize_t, offset));
1294                     }
1295                     goto L1;
1296                 }
1297             }
1298 
1299             /* If var is a member of a closure
1300              */
1301             if (v && v.offset)
1302             {
1303                 assert(irs.sclosure);
1304                 e = el_var(irs.sclosure);
1305                 e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, v.offset));
1306                 if (se.op == TOK.variable)
1307                 {
1308                     e = el_una(OPind, totym(se.type), e);
1309                     if (tybasic(e.Ety) == TYstruct)
1310                         e.ET = Type_toCtype(se.type);
1311                     elem_setLoc(e, se.loc);
1312                 }
1313                 if (ISREF(se.var) && !ISX64REF(se.var))
1314                 {
1315                     e.Ety = TYnptr;
1316                     e = el_una(OPind, s.Stype.Tty, e);
1317                 }
1318                 else if (se.op == TOK.symbolOffset && nrvo)
1319                 {
1320                     e = el_una(OPind, TYnptr, e);
1321                     e = el_bin(OPadd, e.Ety, e, el_long(TYsize_t, offset));
1322                 }
1323                 else if (se.op == TOK.symbolOffset)
1324                 {
1325                     e = el_bin(OPadd, e.Ety, e, el_long(TYsize_t, offset));
1326                 }
1327                 goto L1;
1328             }
1329 
1330             if (s.Sclass == SCauto && s.Ssymnum == SYMIDX.max)
1331             {
1332                 //printf("\tadding symbol %s\n", s.Sident);
1333                 symbol_add(s);
1334             }
1335 
1336             if (se.var.isImportedSymbol())
1337             {
1338                 assert(se.op == TOK.variable);
1339                 e = el_var(toImport(se.var));
1340                 e = el_una(OPind,s.Stype.Tty,e);
1341             }
1342             else if (ISREF(se.var))
1343             {
1344                 // Out parameters are really references
1345                 e = el_var(s);
1346                 e.Ety = TYnptr;
1347                 if (se.op == TOK.variable)
1348                     e = el_una(OPind, s.Stype.Tty, e);
1349                 else if (offset)
1350                     e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, offset));
1351             }
1352             else if (se.op == TOK.variable)
1353                 e = el_var(s);
1354             else
1355             {
1356                 e = nrvo ? el_var(s) : el_ptr(s);
1357                 e = el_bin(OPadd, e.Ety, e, el_long(TYsize_t, offset));
1358             }
1359         L1:
1360             if (se.op == TOK.variable)
1361             {
1362                 if (nrvo)
1363                 {
1364                     e.Ety = TYnptr;
1365                     e = el_una(OPind, 0, e);
1366                 }
1367 
1368                 tym_t tym;
1369                 if (se.var.storage_class & STC.lazy_)
1370                     tym = TYdelegate;       // Tdelegate as C type
1371                 else if (tb.ty == Tfunction)
1372                     tym = s.Stype.Tty;
1373                 else
1374                     tym = totym(se.type);
1375 
1376                 e.Ejty = cast(ubyte)(e.Ety = tym);
1377 
1378                 if (tybasic(tym) == TYstruct)
1379                 {
1380                     e.ET = Type_toCtype(se.type);
1381                 }
1382                 else if (tybasic(tym) == TYarray)
1383                 {
1384                     e.Ejty = e.Ety = TYstruct;
1385                     e.ET = Type_toCtype(se.type);
1386                 }
1387                 else if (tysimd(tym))
1388                 {
1389                     e.ET = Type_toCtype(se.type);
1390                 }
1391             }
1392             elem_setLoc(e,se.loc);
1393             result = e;
1394         }
1395 
1396         /**************************************
1397          */
1398 
1399         override void visit(FuncExp fe)
1400         {
1401             //printf("FuncExp.toElem() %s\n", fe.toChars());
1402             FuncLiteralDeclaration fld = fe.fd;
1403 
1404             if (fld.tok == TOK.reserved && fe.type.ty == Tpointer)
1405             {
1406                 // change to non-nested
1407                 fld.tok = TOK.function_;
1408                 fld.vthis = null;
1409             }
1410             if (!fld.deferToObj)
1411             {
1412                 fld.deferToObj = true;
1413                 irs.deferToObj.push(fld);
1414             }
1415 
1416             Symbol *s = toSymbol(fld);
1417             elem *e = el_ptr(s);
1418             if (fld.isNested())
1419             {
1420                 elem *ethis;
1421                 // Delegate literals report isNested() even if they are in global scope,
1422                 // so we need to check that the parent is a function.
1423                 if (!fld.toParent2().isFuncDeclaration())
1424                     ethis = el_long(TYnptr, 0);
1425                 else
1426                     ethis = getEthis(fe.loc, irs, fld);
1427                 e = el_pair(TYdelegate, ethis, e);
1428             }
1429             elem_setLoc(e, fe.loc);
1430             result = e;
1431         }
1432 
1433         override void visit(DeclarationExp de)
1434         {
1435             //printf("DeclarationExp.toElem() %s\n", de.toChars());
1436             result = Dsymbol_toElem(de.declaration);
1437         }
1438 
1439         /***************************************
1440          */
1441 
1442         override void visit(TypeidExp e)
1443         {
1444             //printf("TypeidExp.toElem() %s\n", e.toChars());
1445             if (Type t = isType(e.obj))
1446             {
1447                 result = getTypeInfo(e.loc, t, irs);
1448                 result = el_bin(OPadd, result.Ety, result, el_long(TYsize_t, t.vtinfo.offset));
1449                 return;
1450             }
1451             if (Expression ex = isExpression(e.obj))
1452             {
1453                 auto tc = ex.type.toBasetype().isTypeClass();
1454                 assert(tc);
1455                 // generate **classptr to get the classinfo
1456                 result = toElem(ex, irs);
1457                 result = el_una(OPind,TYnptr,result);
1458                 result = el_una(OPind,TYnptr,result);
1459                 // Add extra indirection for interfaces
1460                 if (tc.sym.isInterfaceDeclaration())
1461                     result = el_una(OPind,TYnptr,result);
1462                 return;
1463             }
1464             assert(0);
1465         }
1466 
1467         /***************************************
1468          */
1469 
1470         override void visit(ThisExp te)
1471         {
1472             //printf("ThisExp.toElem()\n");
1473             assert(irs.sthis);
1474 
1475             elem *ethis;
1476             if (te.var)
1477             {
1478                 assert(te.var.parent);
1479                 FuncDeclaration fd = te.var.toParent2().isFuncDeclaration();
1480                 assert(fd);
1481                 ethis = getEthis(te.loc, irs, fd);
1482                 ethis = fixEthis2(ethis, fd);
1483             }
1484             else
1485             {
1486                 ethis = el_var(irs.sthis);
1487                 ethis = fixEthis2(ethis, irs.getFunc());
1488             }
1489 
1490             if (te.type.ty == Tstruct)
1491             {
1492                 ethis = el_una(OPind, TYstruct, ethis);
1493                 ethis.ET = Type_toCtype(te.type);
1494             }
1495             elem_setLoc(ethis,te.loc);
1496             result = ethis;
1497         }
1498 
1499         /***************************************
1500          */
1501 
1502         override void visit(IntegerExp ie)
1503         {
1504             elem *e = el_long(totym(ie.type), ie.getInteger());
1505             elem_setLoc(e,ie.loc);
1506             result = e;
1507         }
1508 
1509         /***************************************
1510          */
1511 
1512         override void visit(RealExp re)
1513         {
1514             //printf("RealExp.toElem(%p) %s\n", re, re.toChars());
1515             elem *e = el_long(TYint, 0);
1516             tym_t ty = totym(re.type.toBasetype());
1517             switch (tybasic(ty))
1518             {
1519                 case TYfloat:
1520                 case TYifloat:
1521                     e.EV.Vfloat = cast(float) re.value;
1522                     break;
1523 
1524                 case TYdouble:
1525                 case TYidouble:
1526                     e.EV.Vdouble = cast(double) re.value;
1527                     break;
1528 
1529                 case TYldouble:
1530                 case TYildouble:
1531                     e.EV.Vldouble = re.value;
1532                     break;
1533 
1534                 default:
1535                     printf("ty = %d, tym = %x, re=%s, re.type=%s, re.type.toBasetype=%s\n",
1536                            re.type.ty, ty, re.toChars(), re.type.toChars(), re.type.toBasetype().toChars());
1537                     assert(0);
1538             }
1539             e.Ety = ty;
1540             result = e;
1541         }
1542 
1543         /***************************************
1544          */
1545 
1546         override void visit(ComplexExp ce)
1547         {
1548 
1549             //printf("ComplexExp.toElem(%p) %s\n", ce, ce.toChars());
1550 
1551             elem *e = el_long(TYint, 0);
1552             real_t re = ce.value.re;
1553             real_t im = ce.value.im;
1554 
1555             tym_t ty = totym(ce.type);
1556             switch (tybasic(ty))
1557             {
1558                 case TYcfloat:
1559                     union UF { float f; uint i; }
1560                     e.EV.Vcfloat.re = cast(float) re;
1561                     if (CTFloat.isSNaN(re))
1562                     {
1563                         UF u;
1564                         u.f = e.EV.Vcfloat.re;
1565                         u.i &= 0xFFBFFFFFL;
1566                         e.EV.Vcfloat.re = u.f;
1567                     }
1568                     e.EV.Vcfloat.im = cast(float) im;
1569                     if (CTFloat.isSNaN(im))
1570                     {
1571                         UF u;
1572                         u.f = e.EV.Vcfloat.im;
1573                         u.i &= 0xFFBFFFFFL;
1574                         e.EV.Vcfloat.im = u.f;
1575                     }
1576                     break;
1577 
1578                 case TYcdouble:
1579                     union UD { double d; ulong i; }
1580                     e.EV.Vcdouble.re = cast(double) re;
1581                     if (CTFloat.isSNaN(re))
1582                     {
1583                         UD u;
1584                         u.d = e.EV.Vcdouble.re;
1585                         u.i &= 0xFFF7FFFFFFFFFFFFUL;
1586                         e.EV.Vcdouble.re = u.d;
1587                     }
1588                     e.EV.Vcdouble.im = cast(double) im;
1589                     if (CTFloat.isSNaN(re))
1590                     {
1591                         UD u;
1592                         u.d = e.EV.Vcdouble.im;
1593                         u.i &= 0xFFF7FFFFFFFFFFFFUL;
1594                         e.EV.Vcdouble.im = u.d;
1595                     }
1596                     break;
1597 
1598                 case TYcldouble:
1599                     e.EV.Vcldouble.re = re;
1600                     e.EV.Vcldouble.im = im;
1601                     break;
1602 
1603                 default:
1604                     assert(0);
1605             }
1606             e.Ety = ty;
1607             result = e;
1608         }
1609 
1610         /***************************************
1611          */
1612 
1613         override void visit(NullExp ne)
1614         {
1615             result = el_long(totym(ne.type), 0);
1616         }
1617 
1618         /***************************************
1619          */
1620 
1621         override void visit(StringExp se)
1622         {
1623             //printf("StringExp.toElem() %s, type = %s\n", se.toChars(), se.type.toChars());
1624 
1625             elem *e;
1626             Type tb = se.type.toBasetype();
1627             if (tb.ty == Tarray)
1628             {
1629                 Symbol *si = toStringSymbol(se);
1630                 e = el_pair(TYdarray, el_long(TYsize_t, se.numberOfCodeUnits()), el_ptr(si));
1631             }
1632             else if (tb.ty == Tsarray)
1633             {
1634                 Symbol *si = toStringSymbol(se);
1635                 e = el_var(si);
1636                 e.Ejty = e.Ety = TYstruct;
1637                 e.ET = si.Stype;
1638                 e.ET.Tcount++;
1639             }
1640             else if (tb.ty == Tpointer)
1641             {
1642                 e = el_calloc();
1643                 e.Eoper = OPstring;
1644                 // freed in el_free
1645                 uint len = cast(uint)((se.numberOfCodeUnits() + 1) * se.sz);
1646                 e.EV.Vstring = cast(char *)mem_malloc2(cast(uint)len);
1647                 se.writeTo(e.EV.Vstring, true);
1648                 e.EV.Vstrlen = len;
1649                 e.Ety = TYnptr;
1650             }
1651             else
1652             {
1653                 printf("type is %s\n", se.type.toChars());
1654                 assert(0);
1655             }
1656             elem_setLoc(e,se.loc);
1657             result = e;
1658         }
1659 
1660         override void visit(NewExp ne)
1661         {
1662             //printf("NewExp.toElem() %s\n", ne.toChars());
1663             Type t = ne.type.toBasetype();
1664             //printf("\ttype = %s\n", t.toChars());
1665             //if (ne.member)
1666                 //printf("\tmember = %s\n", ne.member.toChars());
1667             elem *e;
1668             Type ectype;
1669             if (t.ty == Tclass)
1670             {
1671                 auto tclass = ne.newtype.toBasetype().isTypeClass();
1672                 assert(tclass);
1673                 ClassDeclaration cd = tclass.sym;
1674 
1675                 /* Things to do:
1676                  * 1) ex: call allocator
1677                  * 2) ey: set vthis for nested classes
1678                  * 2) ew: set vthis2 for nested classes
1679                  * 3) ez: call constructor
1680                  */
1681 
1682                 elem *ex = null;
1683                 elem *ey = null;
1684                 elem *ew = null;
1685                 elem *ezprefix = null;
1686                 elem *ez = null;
1687 
1688                 if (ne.allocator || ne.onstack)
1689                 {
1690                     if (ne.onstack)
1691                     {
1692                         /* Create an instance of the class on the stack,
1693                          * and call it stmp.
1694                          * Set ex to be the &stmp.
1695                          */
1696                         .type *tc = type_struct_class(tclass.sym.toChars(),
1697                                 tclass.sym.alignsize, tclass.sym.structsize,
1698                                 null, null,
1699                                 false, false, true, false);
1700                         tc.Tcount--;
1701                         Symbol *stmp = symbol_genauto(tc);
1702                         ex = el_ptr(stmp);
1703                     }
1704                     else
1705                     {
1706                         ex = el_var(toSymbol(ne.allocator));
1707                         ex = callfunc(ne.loc, irs, 1, ne.type, ex, ne.allocator.type,
1708                                 ne.allocator, ne.allocator.type, null, ne.newargs);
1709                     }
1710 
1711                     Symbol *si = toInitializer(tclass.sym);
1712                     elem *ei = el_var(si);
1713 
1714                     if (cd.isNested())
1715                     {
1716                         ey = el_same(&ex);
1717                         ez = el_copytree(ey);
1718                         if (cd.vthis2)
1719                             ew = el_copytree(ey);
1720                     }
1721                     else if (ne.member)
1722                         ez = el_same(&ex);
1723 
1724                     ex = el_una(OPind, TYstruct, ex);
1725                     ex = elAssign(ex, ei, null, Type_toCtype(tclass).Tnext);
1726                     ex = el_una(OPaddr, TYnptr, ex);
1727                     ectype = tclass;
1728                 }
1729                 else
1730                 {
1731                     Symbol *csym = toSymbol(cd);
1732                     const rtl = global.params.ehnogc && ne.thrownew ? RTLSYM_NEWTHROW : RTLSYM_NEWCLASS;
1733                     ex = el_bin(OPcall,TYnptr,el_var(getRtlsym(rtl)),el_ptr(csym));
1734                     toTraceGC(irs, ex, ne.loc);
1735                     ectype = null;
1736 
1737                     if (cd.isNested())
1738                     {
1739                         ey = el_same(&ex);
1740                         ez = el_copytree(ey);
1741                         if (cd.vthis2)
1742                             ew = el_copytree(ey);
1743                     }
1744                     else if (ne.member)
1745                         ez = el_same(&ex);
1746                     //elem_print(ex);
1747                     //elem_print(ey);
1748                     //elem_print(ez);
1749                 }
1750 
1751                 if (ne.thisexp)
1752                 {
1753                     ClassDeclaration cdthis = ne.thisexp.type.isClassHandle();
1754                     assert(cdthis);
1755                     //printf("cd = %s\n", cd.toChars());
1756                     //printf("cdthis = %s\n", cdthis.toChars());
1757                     assert(cd.isNested());
1758                     int offset = 0;
1759                     Dsymbol cdp = cd.toParentLocal();     // class we're nested in
1760 
1761                     //printf("member = %p\n", member);
1762                     //printf("cdp = %s\n", cdp.toChars());
1763                     //printf("cdthis = %s\n", cdthis.toChars());
1764                     if (cdp != cdthis)
1765                     {
1766                         int i = cdp.isClassDeclaration().isBaseOf(cdthis, &offset);
1767                         assert(i);
1768                     }
1769                     elem *ethis = toElem(ne.thisexp, irs);
1770                     if (offset)
1771                         ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYsize_t, offset));
1772 
1773                     if (!cd.vthis)
1774                     {
1775                         ne.error("forward reference to `%s`", cd.toChars());
1776                     }
1777                     else
1778                     {
1779                         ey = el_bin(OPadd, TYnptr, ey, el_long(TYsize_t, cd.vthis.offset));
1780                         ey = el_una(OPind, TYnptr, ey);
1781                         ey = el_bin(OPeq, TYnptr, ey, ethis);
1782                     }
1783                     //printf("ex: "); elem_print(ex);
1784                     //printf("ey: "); elem_print(ey);
1785                     //printf("ez: "); elem_print(ez);
1786                 }
1787                 else if (cd.isNested())
1788                 {
1789                     /* Initialize cd.vthis:
1790                      *  *(ey + cd.vthis.offset) = this;
1791                      */
1792                     ey = setEthis(ne.loc, irs, ey, cd);
1793                 }
1794 
1795                 if (cd.vthis2)
1796                 {
1797                     /* Initialize cd.vthis2:
1798                      *  *(ew + cd.vthis2.offset) = this;
1799                      */
1800                     assert(ew);
1801                     ew = setEthis(ne.loc, irs, ew, cd, true);
1802                 }
1803 
1804                 if (ne.member)
1805                 {
1806                     if (ne.argprefix)
1807                         ezprefix = toElem(ne.argprefix, irs);
1808                     // Call constructor
1809                     ez = callfunc(ne.loc, irs, 1, ne.type, ez, ectype, ne.member, ne.member.type, null, ne.arguments);
1810                 }
1811 
1812                 e = el_combine(ex, ey);
1813                 e = el_combine(e, ew);
1814                 e = el_combine(e, ezprefix);
1815                 e = el_combine(e, ez);
1816             }
1817             else if (t.ty == Tpointer && t.nextOf().toBasetype().ty == Tstruct)
1818             {
1819                 t = ne.newtype.toBasetype();
1820                 TypeStruct tclass = t.isTypeStruct();
1821                 StructDeclaration sd = tclass.sym;
1822 
1823                 /* Things to do:
1824                  * 1) ex: call allocator
1825                  * 2) ey: set vthis for nested structs
1826                  * 2) ew: set vthis2 for nested structs
1827                  * 3) ez: call constructor
1828                  */
1829 
1830                 elem *ex = null;
1831                 elem *ey = null;
1832                 elem *ew = null;
1833                 elem *ezprefix = null;
1834                 elem *ez = null;
1835 
1836                 if (ne.allocator)
1837                 {
1838 
1839                     ex = el_var(toSymbol(ne.allocator));
1840                     ex = callfunc(ne.loc, irs, 1, ne.type, ex, ne.allocator.type,
1841                                 ne.allocator, ne.allocator.type, null, ne.newargs);
1842 
1843                     ectype = tclass;
1844                 }
1845                 else
1846                 {
1847                     // call _d_newitemT(ti)
1848                     e = getTypeInfo(ne.loc, ne.newtype, irs);
1849 
1850                     int rtl = t.isZeroInit(Loc.initial) ? RTLSYM_NEWITEMT : RTLSYM_NEWITEMIT;
1851                     ex = el_bin(OPcall,TYnptr,el_var(getRtlsym(rtl)),e);
1852                     toTraceGC(irs, ex, ne.loc);
1853 
1854                     ectype = null;
1855                 }
1856 
1857                 elem *ev = el_same(&ex);
1858 
1859                 if (ne.argprefix)
1860                         ezprefix = toElem(ne.argprefix, irs);
1861                 if (ne.member)
1862                 {
1863                     if (sd.isNested())
1864                     {
1865                         ey = el_copytree(ev);
1866 
1867                         /* Initialize sd.vthis:
1868                          *  *(ey + sd.vthis.offset) = this;
1869                          */
1870                         ey = setEthis(ne.loc, irs, ey, sd);
1871                         if (sd.vthis2)
1872                         {
1873                             /* Initialize sd.vthis2:
1874                              *  *(ew + sd.vthis2.offset) = this1;
1875                              */
1876                             ew = el_copytree(ev);
1877                             ew = setEthis(ne.loc, irs, ew, sd, true);
1878                         }
1879                     }
1880 
1881                     // Call constructor
1882                     ez = callfunc(ne.loc, irs, 1, ne.type, ev, ectype, ne.member, ne.member.type, null, ne.arguments);
1883                     /* Structs return a ref, which gets automatically dereferenced.
1884                      * But we want a pointer to the instance.
1885                      */
1886                     ez = el_una(OPaddr, TYnptr, ez);
1887                 }
1888                 else
1889                 {
1890                     StructLiteralExp sle = StructLiteralExp.create(ne.loc, sd, ne.arguments, t);
1891                     ez = toElemStructLit(sle, irs, TOK.construct, ev.EV.Vsym, false);
1892                 }
1893                 //elem_print(ex);
1894                 //elem_print(ey);
1895                 //elem_print(ez);
1896 
1897                 e = el_combine(ex, ey);
1898                 e = el_combine(e, ew);
1899                 e = el_combine(e, ezprefix);
1900                 e = el_combine(e, ez);
1901             }
1902             else if (auto tda = t.isTypeDArray())
1903             {
1904                 elem *ezprefix = ne.argprefix ? toElem(ne.argprefix, irs) : null;
1905 
1906                 assert(ne.arguments && ne.arguments.dim >= 1);
1907                 if (ne.arguments.dim == 1)
1908                 {
1909                     // Single dimension array allocations
1910                     Expression arg = (*ne.arguments)[0]; // gives array length
1911                     e = toElem(arg, irs);
1912 
1913                     // call _d_newT(ti, arg)
1914                     e = el_param(e, getTypeInfo(ne.loc, ne.type, irs));
1915                     int rtl = tda.next.isZeroInit(Loc.initial) ? RTLSYM_NEWARRAYT : RTLSYM_NEWARRAYIT;
1916                     e = el_bin(OPcall,TYdarray,el_var(getRtlsym(rtl)),e);
1917                     toTraceGC(irs, e, ne.loc);
1918                 }
1919                 else
1920                 {
1921                     // Multidimensional array allocations
1922                     foreach (i; 0 .. ne.arguments.dim)
1923                     {
1924                         assert(t.ty == Tarray);
1925                         t = t.nextOf();
1926                         assert(t);
1927                     }
1928 
1929                     // Allocate array of dimensions on the stack
1930                     Symbol *sdata = null;
1931                     elem *earray = ExpressionsToStaticArray(ne.loc, ne.arguments, &sdata);
1932 
1933                     e = el_pair(TYdarray, el_long(TYsize_t, ne.arguments.dim), el_ptr(sdata));
1934                     if (config.exe == EX_WIN64)
1935                         e = addressElem(e, Type.tsize_t.arrayOf());
1936                     e = el_param(e, getTypeInfo(ne.loc, ne.type, irs));
1937                     int rtl = t.isZeroInit(Loc.initial) ? RTLSYM_NEWARRAYMTX : RTLSYM_NEWARRAYMITX;
1938                     e = el_bin(OPcall,TYdarray,el_var(getRtlsym(rtl)),e);
1939                     toTraceGC(irs, e, ne.loc);
1940 
1941                     e = el_combine(earray, e);
1942                 }
1943                 e = el_combine(ezprefix, e);
1944             }
1945             else if (auto tp = t.isTypePointer())
1946             {
1947                 elem *ezprefix = ne.argprefix ? toElem(ne.argprefix, irs) : null;
1948 
1949                 // call _d_newitemT(ti)
1950                 e = getTypeInfo(ne.loc, ne.newtype, irs);
1951 
1952                 int rtl = tp.next.isZeroInit(Loc.initial) ? RTLSYM_NEWITEMT : RTLSYM_NEWITEMIT;
1953                 e = el_bin(OPcall,TYnptr,el_var(getRtlsym(rtl)),e);
1954                 toTraceGC(irs, e, ne.loc);
1955 
1956                 if (ne.arguments && ne.arguments.dim == 1)
1957                 {
1958                     /* ezprefix, ts=_d_newitemT(ti), *ts=arguments[0], ts
1959                      */
1960                     elem *e2 = toElem((*ne.arguments)[0], irs);
1961 
1962                     Symbol *ts = symbol_genauto(Type_toCtype(tp));
1963                     elem *eeq1 = el_bin(OPeq, TYnptr, el_var(ts), e);
1964 
1965                     elem *ederef = el_una(OPind, e2.Ety, el_var(ts));
1966                     elem *eeq2 = el_bin(OPeq, e2.Ety, ederef, e2);
1967 
1968                     e = el_combine(eeq1, eeq2);
1969                     e = el_combine(e, el_var(ts));
1970                     //elem_print(e);
1971                 }
1972                 e = el_combine(ezprefix, e);
1973             }
1974             else
1975             {
1976                 ne.error("Internal Compiler Error: cannot new type `%s`\n", t.toChars());
1977                 assert(0);
1978             }
1979 
1980             elem_setLoc(e,ne.loc);
1981             result = e;
1982         }
1983 
1984         //////////////////////////// Unary ///////////////////////////////
1985 
1986         /***************************************
1987          */
1988 
1989         override void visit(NegExp ne)
1990         {
1991             elem *e = toElem(ne.e1, irs);
1992             Type tb1 = ne.e1.type.toBasetype();
1993 
1994             assert(tb1.ty != Tarray && tb1.ty != Tsarray);
1995 
1996             switch (tb1.ty)
1997             {
1998                 case Tvector:
1999                 {
2000                     // rewrite (-e) as (0-e)
2001                     elem *ez = el_calloc();
2002                     ez.Eoper = OPconst;
2003                     ez.Ety = e.Ety;
2004                     ez.EV.Vcent.lsw = 0;
2005                     ez.EV.Vcent.msw = 0;
2006                     e = el_bin(OPmin, totym(ne.type), ez, e);
2007                     break;
2008                 }
2009 
2010                 default:
2011                     e = el_una(OPneg, totym(ne.type), e);
2012                     break;
2013             }
2014 
2015             elem_setLoc(e,ne.loc);
2016             result = e;
2017         }
2018 
2019         /***************************************
2020          */
2021 
2022         override void visit(ComExp ce)
2023         {
2024             elem *e1 = toElem(ce.e1, irs);
2025             Type tb1 = ce.e1.type.toBasetype();
2026             tym_t ty = totym(ce.type);
2027 
2028             assert(tb1.ty != Tarray && tb1.ty != Tsarray);
2029 
2030             elem *e;
2031             switch (tb1.ty)
2032             {
2033                 case Tbool:
2034                     e = el_bin(OPxor, ty, e1, el_long(ty, 1));
2035                     break;
2036 
2037                 case Tvector:
2038                 {
2039                     // rewrite (~e) as (e^~0)
2040                     elem *ec = el_calloc();
2041                     ec.Eoper = OPconst;
2042                     ec.Ety = e1.Ety;
2043                     ec.EV.Vcent.lsw = ~0L;
2044                     ec.EV.Vcent.msw = ~0L;
2045                     e = el_bin(OPxor, ty, e1, ec);
2046                     break;
2047                 }
2048 
2049                 default:
2050                     e = el_una(OPcom,ty,e1);
2051                     break;
2052             }
2053 
2054             elem_setLoc(e,ce.loc);
2055             result = e;
2056         }
2057 
2058         /***************************************
2059          */
2060 
2061         override void visit(NotExp ne)
2062         {
2063             elem *e = el_una(OPnot, totym(ne.type), toElem(ne.e1, irs));
2064             elem_setLoc(e,ne.loc);
2065             result = e;
2066         }
2067 
2068 
2069         /***************************************
2070          */
2071 
2072         override void visit(HaltExp he)
2073         {
2074             result = genHalt(he.loc);
2075         }
2076 
2077         /********************************************
2078          */
2079 
2080         override void visit(AssertExp ae)
2081         {
2082             // https://dlang.org/spec/expression.html#assert_expressions
2083             //printf("AssertExp.toElem() %s\n", toChars());
2084             elem *e;
2085             if (irs.params.useAssert == CHECKENABLE.on)
2086             {
2087                 if (irs.params.checkAction == CHECKACTION.C)
2088                 {
2089                     auto econd = toElem(ae.e1, irs);
2090                     auto ea = callCAssert(irs, ae.e1.loc, ae.e1, ae.msg, null);
2091                     auto eo = el_bin(OPoror, TYvoid, econd, ea);
2092                     elem_setLoc(eo, ae.loc);
2093                     result = eo;
2094                     return;
2095                 }
2096 
2097                 if (irs.params.checkAction == CHECKACTION.halt)
2098                 {
2099                     /* Generate:
2100                      *  ae.e1 || halt
2101                      */
2102                     auto econd = toElem(ae.e1, irs);
2103                     auto ea = genHalt(ae.loc);
2104                     auto eo = el_bin(OPoror, TYvoid, econd, ea);
2105                     elem_setLoc(eo, ae.loc);
2106                     result = eo;
2107                     return;
2108                 }
2109 
2110                 e = toElem(ae.e1, irs);
2111                 Symbol *ts = null;
2112                 elem *einv = null;
2113                 Type t1 = ae.e1.type.toBasetype();
2114 
2115                 FuncDeclaration inv;
2116 
2117                 // If e1 is a class object, call the class invariant on it
2118                 if (irs.params.useInvariants == CHECKENABLE.on && t1.ty == Tclass &&
2119                     !(cast(TypeClass)t1).sym.isInterfaceDeclaration() &&
2120                     !(cast(TypeClass)t1).sym.isCPPclass())
2121                 {
2122                     ts = symbol_genauto(Type_toCtype(t1));
2123                     einv = el_bin(OPcall, TYvoid, el_var(getRtlsym(RTLSYM_DINVARIANT)), el_var(ts));
2124                 }
2125                 else if (irs.params.useInvariants == CHECKENABLE.on &&
2126                     t1.ty == Tpointer &&
2127                     t1.nextOf().ty == Tstruct &&
2128                     (inv = (cast(TypeStruct)t1.nextOf()).sym.inv) !is null)
2129                 {
2130                     // If e1 is a struct object, call the struct invariant on it
2131                     ts = symbol_genauto(Type_toCtype(t1));
2132                     einv = callfunc(ae.loc, irs, 1, inv.type.nextOf(), el_var(ts), ae.e1.type, inv, inv.type, null, null);
2133                 }
2134 
2135                 // Construct: (e1 || ModuleAssert(line))
2136                 Module m = cast(Module)irs.blx._module;
2137                 char *mname = cast(char*)m.srcfile.toChars();
2138 
2139                 //printf("filename = '%s'\n", ae.loc.filename);
2140                 //printf("module = '%s'\n", m.srcfile.toChars());
2141 
2142                 /* Determine if we are in a unittest
2143                  */
2144                 FuncDeclaration fd = irs.getFunc();
2145                 UnitTestDeclaration ud = fd ? fd.isUnitTestDeclaration() : null;
2146 
2147                 /* If the source file name has changed, probably due
2148                  * to a #line directive.
2149                  */
2150                 elem *ea;
2151                 if (ae.loc.filename && (ae.msg || strcmp(ae.loc.filename, mname) != 0))
2152                 {
2153                     const(char)* id = ae.loc.filename;
2154                     size_t len = strlen(id);
2155                     Symbol *si = toStringSymbol(id, len, 1);
2156                     elem *efilename = el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(si));
2157                     if (config.exe == EX_WIN64)
2158                         efilename = addressElem(efilename, Type.tstring, true);
2159 
2160                     if (ae.msg)
2161                     {
2162                         /* https://issues.dlang.org/show_bug.cgi?id=8360
2163                          * If the condition is evalated to true,
2164                          * msg is not evaluated at all. so should use
2165                          * toElemDtor(msg, irs) instead of toElem(msg, irs).
2166                          */
2167                         elem *emsg = toElemDtor(ae.msg, irs);
2168                         emsg = array_toDarray(ae.msg.type, emsg);
2169                         if (config.exe == EX_WIN64)
2170                             emsg = addressElem(emsg, Type.tvoid.arrayOf(), false);
2171 
2172                         ea = el_var(getRtlsym(ud ? RTLSYM_DUNITTEST_MSG : RTLSYM_DASSERT_MSG));
2173                         ea = el_bin(OPcall, TYvoid, ea, el_params(el_long(TYint, ae.loc.linnum), efilename, emsg, null));
2174                     }
2175                     else
2176                     {
2177                         ea = el_var(getRtlsym(ud ? RTLSYM_DUNITTEST : RTLSYM_DASSERT));
2178                         ea = el_bin(OPcall, TYvoid, ea, el_param(el_long(TYint, ae.loc.linnum), efilename));
2179                     }
2180                 }
2181                 else
2182                 {
2183                     auto eassert = el_var(getRtlsym(ud ? RTLSYM_DUNITTESTP : RTLSYM_DASSERTP));
2184                     auto efile = toEfilenamePtr(m);
2185                     auto eline = el_long(TYint, ae.loc.linnum);
2186                     ea = el_bin(OPcall, TYvoid, eassert, el_param(eline, efile));
2187                 }
2188                 if (einv)
2189                 {
2190                     // tmp = e, e || assert, e.inv
2191                     elem *eassign = el_bin(OPeq, e.Ety, el_var(ts), e);
2192                     e = el_combine(eassign, el_bin(OPoror, TYvoid, el_var(ts), ea));
2193                     e = el_combine(e, einv);
2194                 }
2195                 else
2196                     e = el_bin(OPoror,TYvoid,e,ea);
2197             }
2198             else
2199             {
2200                 // BUG: should replace assert(0); with a HLT instruction
2201                 e = el_long(TYint, 0);
2202             }
2203             elem_setLoc(e,ae.loc);
2204             result = e;
2205         }
2206 
2207         override void visit(PostExp pe)
2208         {
2209             //printf("PostExp.toElem() '%s'\n", pe.toChars());
2210             elem *e = toElem(pe.e1, irs);
2211             elem *einc = toElem(pe.e2, irs);
2212             e = el_bin((pe.op == TOK.plusPlus) ? OPpostinc : OPpostdec,
2213                         e.Ety,e,einc);
2214             elem_setLoc(e,pe.loc);
2215             result = e;
2216         }
2217 
2218         //////////////////////////// Binary ///////////////////////////////
2219 
2220         /********************************************
2221          */
2222         elem *toElemBin(BinExp be, int op)
2223         {
2224             //printf("toElemBin() '%s'\n", be.toChars());
2225 
2226             Type tb1 = be.e1.type.toBasetype();
2227             Type tb2 = be.e2.type.toBasetype();
2228 
2229             assert(!((tb1.ty == Tarray || tb1.ty == Tsarray ||
2230                       tb2.ty == Tarray || tb2.ty == Tsarray) &&
2231                      tb2.ty != Tvoid &&
2232                      op != OPeq && op != OPandand && op != OPoror));
2233 
2234             tym_t tym = totym(be.type);
2235 
2236             elem *el = toElem(be.e1, irs);
2237             elem *er = toElem(be.e2, irs);
2238             elem *e = el_bin(op,tym,el,er);
2239 
2240             elem_setLoc(e,be.loc);
2241             return e;
2242         }
2243 
2244         elem *toElemBinAssign(BinAssignExp be, int op)
2245         {
2246             //printf("toElemBinAssign() '%s'\n", be.toChars());
2247 
2248             Type tb1 = be.e1.type.toBasetype();
2249             Type tb2 = be.e2.type.toBasetype();
2250 
2251             assert(!((tb1.ty == Tarray || tb1.ty == Tsarray ||
2252                       tb2.ty == Tarray || tb2.ty == Tsarray) &&
2253                      tb2.ty != Tvoid &&
2254                      op != OPeq && op != OPandand && op != OPoror));
2255 
2256             tym_t tym = totym(be.type);
2257 
2258             elem *el;
2259             elem *ev;
2260             if (be.e1.op == TOK.cast_)
2261             {
2262                 int depth = 0;
2263                 Expression e1 = be.e1;
2264                 while (e1.op == TOK.cast_)
2265                 {
2266                     ++depth;
2267                     e1 = (cast(CastExp)e1).e1;
2268                 }
2269                 assert(depth > 0);
2270 
2271                 el = toElem(e1, irs);
2272                 el = addressElem(el, e1.type.pointerTo());
2273                 ev = el_same(&el);
2274 
2275                 el = el_una(OPind, totym(e1.type), el);
2276 
2277                 ev = el_una(OPind, tym, ev);
2278 
2279                 foreach (d; 0 .. depth)
2280                 {
2281                     e1 = be.e1;
2282                     foreach (i; 1 .. depth - d)
2283                         e1 = (cast(CastExp)e1).e1;
2284 
2285                     el = toElemCast(cast(CastExp)e1, el, true);
2286                 }
2287             }
2288             else
2289             {
2290                 el = toElem(be.e1, irs);
2291                 el = addressElem(el, be.e1.type.pointerTo());
2292                 ev = el_same(&el);
2293 
2294                 el = el_una(OPind, tym, el);
2295                 ev = el_una(OPind, tym, ev);
2296             }
2297             elem *er = toElem(be.e2, irs);
2298             elem *e = el_bin(op, tym, el, er);
2299             e = el_combine(e, ev);
2300 
2301             elem_setLoc(e,be.loc);
2302             return e;
2303         }
2304 
2305         /***************************************
2306          */
2307 
2308         override void visit(AddExp e)
2309         {
2310             result = toElemBin(e, OPadd);
2311         }
2312 
2313         /***************************************
2314          */
2315 
2316         override void visit(MinExp e)
2317         {
2318             result = toElemBin(e, OPmin);
2319         }
2320 
2321         /*****************************************
2322          * Evaluate elem and convert to dynamic array suitable for a function argument.
2323          */
2324         elem *eval_Darray(Expression e)
2325         {
2326             elem *ex = toElem(e, irs);
2327             ex = array_toDarray(e.type, ex);
2328             if (config.exe == EX_WIN64)
2329             {
2330                 ex = addressElem(ex, Type.tvoid.arrayOf(), false);
2331             }
2332             return ex;
2333         }
2334 
2335         /***************************************
2336          * http://dlang.org/spec/expression.html#cat_expressions
2337          */
2338 
2339         override void visit(CatExp ce)
2340         {
2341             /* Do this check during code gen rather than semantic() because concatenation is
2342              * allowed in CTFE, and cannot distinguish that in semantic().
2343              */
2344             if (irs.params.betterC)
2345             {
2346                 error(ce.loc, "array concatenation of expression `%s` requires the GC which is not available with -betterC", ce.toChars());
2347                 result = el_long(TYint, 0);
2348                 return;
2349             }
2350 
2351             Type tb1 = ce.e1.type.toBasetype();
2352             Type tb2 = ce.e2.type.toBasetype();
2353 
2354             Type ta = (tb1.ty == Tarray || tb1.ty == Tsarray) ? tb1 : tb2;
2355 
2356             elem *e;
2357             if (ce.e1.op == TOK.concatenate)
2358             {
2359                 CatExp ex = ce;
2360 
2361                 // Flatten ((a ~ b) ~ c) to [a, b, c]
2362                 Elems elems;
2363                 elems.shift(array_toDarray(ex.e2.type, toElem(ex.e2, irs)));
2364                 do
2365                 {
2366                     ex = cast(CatExp)ex.e1;
2367                     elems.shift(array_toDarray(ex.e2.type, toElem(ex.e2, irs)));
2368                 } while (ex.e1.op == TOK.concatenate);
2369                 elems.shift(array_toDarray(ex.e1.type, toElem(ex.e1, irs)));
2370 
2371                 // We can't use ExpressionsToStaticArray because each exp needs
2372                 // to have array_toDarray called on it first, as some might be
2373                 // single elements instead of arrays.
2374                 Symbol *sdata;
2375                 elem *earr = ElemsToStaticArray(ce.loc, ce.type, &elems, &sdata);
2376 
2377                 elem *ep = el_pair(TYdarray, el_long(TYsize_t, elems.dim), el_ptr(sdata));
2378                 if (config.exe == EX_WIN64)
2379                     ep = addressElem(ep, Type.tvoid.arrayOf());
2380                 ep = el_param(ep, getTypeInfo(ce.loc, ta, irs));
2381                 e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYCATNTX)), ep);
2382                 toTraceGC(irs, e, ce.loc);
2383                 e = el_combine(earr, e);
2384             }
2385             else
2386             {
2387                 elem *e1 = eval_Darray(ce.e1);
2388                 elem *e2 = eval_Darray(ce.e2);
2389                 elem *ep = el_params(e2, e1, getTypeInfo(ce.loc, ta, irs), null);
2390                 e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYCATT)), ep);
2391                 toTraceGC(irs, e, ce.loc);
2392             }
2393             elem_setLoc(e,ce.loc);
2394             result = e;
2395         }
2396 
2397         /***************************************
2398          */
2399 
2400         override void visit(MulExp e)
2401         {
2402             result = toElemBin(e, OPmul);
2403         }
2404 
2405         /************************************
2406          */
2407 
2408         override void visit(DivExp e)
2409         {
2410             result = toElemBin(e, OPdiv);
2411         }
2412 
2413         /***************************************
2414          */
2415 
2416         override void visit(ModExp e)
2417         {
2418             result = toElemBin(e, OPmod);
2419         }
2420 
2421         /***************************************
2422          */
2423 
2424         override void visit(CmpExp ce)
2425         {
2426             //printf("CmpExp.toElem() %s\n", ce.toChars());
2427 
2428             OPER eop;
2429             Type t1 = ce.e1.type.toBasetype();
2430             Type t2 = ce.e2.type.toBasetype();
2431 
2432             switch (ce.op)
2433             {
2434                 case TOK.lessThan:     eop = OPlt;     break;
2435                 case TOK.greaterThan:     eop = OPgt;     break;
2436                 case TOK.lessOrEqual:     eop = OPle;     break;
2437                 case TOK.greaterOrEqual:     eop = OPge;     break;
2438                 case TOK.equal:  eop = OPeqeq;   break;
2439                 case TOK.notEqual: eop = OPne;   break;
2440 
2441                 default:
2442                     printf("%s\n", ce.toChars());
2443                     assert(0);
2444             }
2445             if (!t1.isfloating())
2446             {
2447                 // Convert from floating point compare to equivalent
2448                 // integral compare
2449                 eop = cast(OPER)rel_integral(eop);
2450             }
2451             elem *e;
2452             if (cast(int)eop > 1 && t1.ty == Tclass && t2.ty == Tclass)
2453             {
2454                 // Should have already been lowered
2455                 assert(0);
2456             }
2457             else if (cast(int)eop > 1 &&
2458                 (t1.ty == Tarray || t1.ty == Tsarray) &&
2459                 (t2.ty == Tarray || t2.ty == Tsarray))
2460             {
2461                 // This codepath was replaced by lowering during semantic
2462                 // to object.__cmp in druntime.
2463                 assert(0);
2464             }
2465             else
2466             {
2467                 if (cast(int)eop <= 1)
2468                 {
2469                     /* The result is determinate, create:
2470                      *   (e1 , e2) , eop
2471                      */
2472                     e = toElemBin(ce,OPcomma);
2473                     e = el_bin(OPcomma,e.Ety,e,el_long(e.Ety,cast(int)eop));
2474                 }
2475                 else
2476                     e = toElemBin(ce,eop);
2477             }
2478             result = e;
2479         }
2480 
2481         override void visit(EqualExp ee)
2482         {
2483             //printf("EqualExp.toElem() %s\n", ee.toChars());
2484 
2485             Type t1 = ee.e1.type.toBasetype();
2486             Type t2 = ee.e2.type.toBasetype();
2487 
2488             OPER eop;
2489             switch (ee.op)
2490             {
2491                 case TOK.equal:          eop = OPeqeq;   break;
2492                 case TOK.notEqual:       eop = OPne;     break;
2493                 default:
2494                     printf("%s\n", ee.toChars());
2495                     assert(0);
2496             }
2497 
2498             //printf("EqualExp.toElem()\n");
2499             elem *e;
2500             if (t1.ty == Tstruct)
2501             {
2502                 // Rewritten to IdentityExp or memberwise-compare
2503                 assert(0);
2504             }
2505             else if ((t1.ty == Tarray || t1.ty == Tsarray) &&
2506                      (t2.ty == Tarray || t2.ty == Tsarray))
2507             {
2508                 Type telement  = t1.nextOf().toBasetype();
2509                 Type telement2 = t2.nextOf().toBasetype();
2510 
2511                 if ((telement.isintegral() || telement.ty == Tvoid) && telement.ty == telement2.ty)
2512                 {
2513                     // Optimize comparisons of arrays of basic types
2514                     // For arrays of integers/characters, and void[],
2515                     // replace druntime call with:
2516                     // For a==b: a.length==b.length && (a.length == 0 || memcmp(a.ptr, b.ptr, size)==0)
2517                     // For a!=b: a.length!=b.length || (a.length != 0 || memcmp(a.ptr, b.ptr, size)!=0)
2518                     // size is a.length*sizeof(a[0]) for dynamic arrays, or sizeof(a) for static arrays.
2519 
2520                     elem* earr1 = toElem(ee.e1, irs);
2521                     elem* earr2 = toElem(ee.e2, irs);
2522                     elem* eptr1, eptr2; // Pointer to data, to pass to memcmp
2523                     elem* elen1, elen2; // Length, for comparison
2524                     elem* esiz1, esiz2; // Data size, to pass to memcmp
2525                     d_uns64 sz = telement.size(); // Size of one element
2526 
2527                     if (t1.ty == Tarray)
2528                     {
2529                         elen1 = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, el_same(&earr1));
2530                         esiz1 = el_bin(OPmul, TYsize_t, el_same(&elen1), el_long(TYsize_t, sz));
2531                         eptr1 = array_toPtr(t1, el_same(&earr1));
2532                     }
2533                     else
2534                     {
2535                         elen1 = el_long(TYsize_t, (cast(TypeSArray)t1).dim.toInteger());
2536                         esiz1 = el_long(TYsize_t, t1.size());
2537                         earr1 = addressElem(earr1, t1);
2538                         eptr1 = el_same(&earr1);
2539                     }
2540 
2541                     if (t2.ty == Tarray)
2542                     {
2543                         elen2 = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, el_same(&earr2));
2544                         esiz2 = el_bin(OPmul, TYsize_t, el_same(&elen2), el_long(TYsize_t, sz));
2545                         eptr2 = array_toPtr(t2, el_same(&earr2));
2546                     }
2547                     else
2548                     {
2549                         elen2 = el_long(TYsize_t, (cast(TypeSArray)t2).dim.toInteger());
2550                         esiz2 = el_long(TYsize_t, t2.size());
2551                         earr2 = addressElem(earr2, t2);
2552                         eptr2 = el_same(&earr2);
2553                     }
2554 
2555                     elem *esize = t2.ty == Tsarray ? esiz2 : esiz1;
2556 
2557                     e = el_param(eptr1, eptr2);
2558                     e = el_bin(OPmemcmp, TYint, e, esize);
2559                     e = el_bin(eop, TYint, e, el_long(TYint, 0));
2560 
2561                     elem *elen = t2.ty == Tsarray ? elen2 : elen1;
2562                     elem *esizecheck = el_bin(eop, TYint, el_same(&elen), el_long(TYsize_t, 0));
2563                     e = el_bin(ee.op == TOK.equal ? OPoror : OPandand, TYint, esizecheck, e);
2564 
2565                     if (t1.ty == Tsarray && t2.ty == Tsarray)
2566                         assert(t1.size() == t2.size());
2567                     else
2568                     {
2569                         elem *elencmp = el_bin(eop, TYint, elen1, elen2);
2570                         e = el_bin(ee.op == TOK.equal ? OPandand : OPoror, TYint, elencmp, e);
2571                     }
2572 
2573                     // Ensure left-to-right order of evaluation
2574                     e = el_combine(earr2, e);
2575                     e = el_combine(earr1, e);
2576                     elem_setLoc(e, ee.loc);
2577                     result = e;
2578                     return;
2579                 }
2580 
2581                 elem *ea1 = eval_Darray(ee.e1);
2582                 elem *ea2 = eval_Darray(ee.e2);
2583 
2584                 elem *ep = el_params(getTypeInfo(ee.loc, telement.arrayOf(), irs),
2585                         ea2, ea1, null);
2586                 int rtlfunc = RTLSYM_ARRAYEQ2;
2587                 e = el_bin(OPcall, TYint, el_var(getRtlsym(rtlfunc)), ep);
2588                 if (ee.op == TOK.notEqual)
2589                     e = el_bin(OPxor, TYint, e, el_long(TYint, 1));
2590                 elem_setLoc(e,ee.loc);
2591             }
2592             else if (t1.ty == Taarray && t2.ty == Taarray)
2593             {
2594                 TypeAArray taa = cast(TypeAArray)t1;
2595                 Symbol *s = aaGetSymbol(taa, "Equal", 0);
2596                 elem *ti = getTypeInfo(ee.loc, taa, irs);
2597                 elem *ea1 = toElem(ee.e1, irs);
2598                 elem *ea2 = toElem(ee.e2, irs);
2599                 // aaEqual(ti, e1, e2)
2600                 elem *ep = el_params(ea2, ea1, ti, null);
2601                 e = el_bin(OPcall, TYnptr, el_var(s), ep);
2602                 if (ee.op == TOK.notEqual)
2603                     e = el_bin(OPxor, TYint, e, el_long(TYint, 1));
2604                 elem_setLoc(e, ee.loc);
2605                 result = e;
2606                 return;
2607             }
2608             else
2609                 e = toElemBin(ee, eop);
2610             result = e;
2611         }
2612 
2613         override void visit(IdentityExp ie)
2614         {
2615             Type t1 = ie.e1.type.toBasetype();
2616             Type t2 = ie.e2.type.toBasetype();
2617 
2618             OPER eop;
2619             switch (ie.op)
2620             {
2621                 case TOK.identity:       eop = OPeqeq;   break;
2622                 case TOK.notIdentity:    eop = OPne;     break;
2623                 default:
2624                     printf("%s\n", ie.toChars());
2625                     assert(0);
2626             }
2627 
2628             //printf("IdentityExp.toElem() %s\n", ie.toChars());
2629 
2630             /* Fix Issue 18746 : https://issues.dlang.org/show_bug.cgi?id=18746
2631              * Before skipping the comparison for empty structs
2632              * it is necessary to check whether the expressions involved
2633              * have any sideeffects
2634              */
2635 
2636             const canSkipCompare = isTrivialExp(ie.e1) && isTrivialExp(ie.e2);
2637             elem *e;
2638             if (t1.ty == Tstruct && (cast(TypeStruct)t1).sym.fields.dim == 0 && canSkipCompare)
2639             {
2640                 // we can skip the compare if the structs are empty
2641                 e = el_long(TYbool, ie.op == TOK.identity);
2642             }
2643             else if (t1.ty == Tstruct || t1.isfloating())
2644             {
2645                 // Do bit compare of struct's
2646                 elem *es1 = toElem(ie.e1, irs);
2647                 es1 = addressElem(es1, ie.e1.type);
2648                 elem *es2 = toElem(ie.e2, irs);
2649                 es2 = addressElem(es2, ie.e2.type);
2650                 e = el_param(es1, es2);
2651                 elem *ecount = el_long(TYsize_t, t1.size());
2652                 e = el_bin(OPmemcmp, TYint, e, ecount);
2653                 e = el_bin(eop, TYint, e, el_long(TYint, 0));
2654                 elem_setLoc(e, ie.loc);
2655             }
2656             else if ((t1.ty == Tarray || t1.ty == Tsarray) &&
2657                      (t2.ty == Tarray || t2.ty == Tsarray))
2658             {
2659 
2660                 elem *ea1 = toElem(ie.e1, irs);
2661                 ea1 = array_toDarray(t1, ea1);
2662                 elem *ea2 = toElem(ie.e2, irs);
2663                 ea2 = array_toDarray(t2, ea2);
2664 
2665                 e = el_bin(eop, totym(ie.type), ea1, ea2);
2666                 elem_setLoc(e, ie.loc);
2667             }
2668             else
2669                 e = toElemBin(ie, eop);
2670 
2671             result = e;
2672         }
2673 
2674         /***************************************
2675          */
2676 
2677         override void visit(InExp ie)
2678         {
2679             elem *key = toElem(ie.e1, irs);
2680             elem *aa = toElem(ie.e2, irs);
2681             TypeAArray taa = cast(TypeAArray)ie.e2.type.toBasetype();
2682 
2683             // aaInX(aa, keyti, key);
2684             key = addressElem(key, ie.e1.type);
2685             Symbol *s = aaGetSymbol(taa, "InX", 0);
2686             elem *keyti = getTypeInfo(ie.loc, taa.index, irs);
2687             elem *ep = el_params(key, keyti, aa, null);
2688             elem *e = el_bin(OPcall, totym(ie.type), el_var(s), ep);
2689 
2690             elem_setLoc(e, ie.loc);
2691             result = e;
2692         }
2693 
2694         /***************************************
2695          */
2696 
2697         override void visit(RemoveExp re)
2698         {
2699             auto taa = re.e1.type.toBasetype().isTypeAArray();
2700             assert(taa);
2701             elem *ea = toElem(re.e1, irs);
2702             elem *ekey = toElem(re.e2, irs);
2703 
2704             ekey = addressElem(ekey, re.e2.type);
2705             Symbol *s = aaGetSymbol(taa, "DelX", 0);
2706             elem *keyti = getTypeInfo(re.loc, taa.index, irs);
2707             elem *ep = el_params(ekey, keyti, ea, null);
2708             elem *e = el_bin(OPcall, TYnptr, el_var(s), ep);
2709 
2710             elem_setLoc(e, re.loc);
2711             result = e;
2712         }
2713 
2714         /***************************************
2715          */
2716 
2717         override void visit(AssignExp ae)
2718         {
2719             version (none)
2720             {
2721                 if (ae.op == TOK.blit)      printf("BlitExp.toElem('%s')\n", ae.toChars());
2722                 if (ae.op == TOK.assign)    printf("AssignExp.toElem('%s')\n", ae.toChars());
2723                 if (ae.op == TOK.construct) printf("ConstructExp.toElem('%s')\n", ae.toChars());
2724             }
2725 
2726             void setResult(elem* e)
2727             {
2728                 elem_setLoc(e, ae.loc);
2729                 result = e;
2730             }
2731 
2732             Type t1b = ae.e1.type.toBasetype();
2733 
2734             // Look for array.length = n
2735             if (auto ale = ae.e1.isArrayLengthExp())
2736             {
2737                 assert(0, "This case should have been rewritten to `_d_arraysetlengthT` in the semantic phase");
2738             }
2739 
2740             // Look for array[]=n
2741             if (auto are = ae.e1.isSliceExp())
2742             {
2743                 Type t1 = t1b;
2744                 Type ta = are.e1.type.toBasetype();
2745 
2746                 // which we do if the 'next' types match
2747                 if (ae.memset == MemorySet.blockAssign)
2748                 {
2749                     // Do a memset for array[]=v
2750                     //printf("Lpair %s\n", ae.toChars());
2751                     Type tb = ta.nextOf().toBasetype();
2752                     uint sz = cast(uint)tb.size();
2753 
2754                     elem *n1 = toElem(are.e1, irs);
2755                     elem *elwr = are.lwr ? toElem(are.lwr, irs) : null;
2756                     elem *eupr = are.upr ? toElem(are.upr, irs) : null;
2757 
2758                     elem *n1x = n1;
2759 
2760                     elem *enbytes;
2761                     elem *einit;
2762                     // Look for array[]=n
2763                     if (auto ts = ta.isTypeSArray())
2764                     {
2765                         n1 = array_toPtr(ta, n1);
2766                         enbytes = toElem(ts.dim, irs);
2767                         n1x = n1;
2768                         n1 = el_same(&n1x);
2769                         einit = resolveLengthVar(are.lengthVar, &n1, ta);
2770                     }
2771                     else if (ta.ty == Tarray)
2772                     {
2773                         n1 = el_same(&n1x);
2774                         einit = resolveLengthVar(are.lengthVar, &n1, ta);
2775                         enbytes = el_copytree(n1);
2776                         n1 = array_toPtr(ta, n1);
2777                         enbytes = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, enbytes);
2778                     }
2779                     else if (ta.ty == Tpointer)
2780                     {
2781                         n1 = el_same(&n1x);
2782                         enbytes = el_long(TYsize_t, -1);   // largest possible index
2783                         einit = null;
2784                     }
2785 
2786                     // Enforce order of evaluation of n1[elwr..eupr] as n1,elwr,eupr
2787                     elem *elwrx = elwr;
2788                     if (elwr) elwr = el_same(&elwrx);
2789                     elem *euprx = eupr;
2790                     if (eupr) eupr = el_same(&euprx);
2791 
2792                     version (none)
2793                     {
2794                         printf("sz = %d\n", sz);
2795                         printf("n1x\n");        elem_print(n1x);
2796                         printf("einit\n");      elem_print(einit);
2797                         printf("elwrx\n");      elem_print(elwrx);
2798                         printf("euprx\n");      elem_print(euprx);
2799                         printf("n1\n");         elem_print(n1);
2800                         printf("elwr\n");       elem_print(elwr);
2801                         printf("eupr\n");       elem_print(eupr);
2802                         printf("enbytes\n");    elem_print(enbytes);
2803                     }
2804                     einit = el_combine(n1x, einit);
2805                     einit = el_combine(einit, elwrx);
2806                     einit = el_combine(einit, euprx);
2807 
2808                     elem *evalue = toElem(ae.e2, irs);
2809 
2810                     version (none)
2811                     {
2812                         printf("n1\n");         elem_print(n1);
2813                         printf("enbytes\n");    elem_print(enbytes);
2814                     }
2815 
2816                     if (irs.arrayBoundsCheck() && eupr && ta.ty != Tpointer)
2817                     {
2818                         assert(elwr);
2819                         elem *enbytesx = enbytes;
2820                         enbytes = el_same(&enbytesx);
2821                         elem *c1 = el_bin(OPle, TYint, el_copytree(eupr), enbytesx);
2822                         elem *c2 = el_bin(OPle, TYint, el_copytree(elwr), el_copytree(eupr));
2823                         c1 = el_bin(OPandand, TYint, c1, c2);
2824 
2825                         // Construct: (c1 || arrayBoundsError)
2826                         auto ea = buildArrayBoundsError(irs, ae.loc, el_copytree(elwr), el_copytree(eupr), el_copytree(enbytesx));
2827                         elem *eb = el_bin(OPoror,TYvoid,c1,ea);
2828                         einit = el_combine(einit, eb);
2829                     }
2830 
2831                     elem *elength;
2832                     if (elwr)
2833                     {
2834                         el_free(enbytes);
2835                         elem *elwr2 = el_copytree(elwr);
2836                         elwr2 = el_bin(OPmul, TYsize_t, elwr2, el_long(TYsize_t, sz));
2837                         n1 = el_bin(OPadd, TYnptr, n1, elwr2);
2838                         enbytes = el_bin(OPmin, TYsize_t, eupr, elwr);
2839                         elength = el_copytree(enbytes);
2840                     }
2841                     else
2842                         elength = el_copytree(enbytes);
2843                     elem* e = setArray(are.e1, n1, enbytes, tb, evalue, irs, ae.op);
2844                     e = el_pair(TYdarray, elength, e);
2845                     e = el_combine(einit, e);
2846                     //elem_print(e);
2847                     return setResult(e);
2848                 }
2849                 else
2850                 {
2851                     /* It's array1[]=array2[]
2852                      * which is a memcpy
2853                      */
2854                     elem *eto = toElem(ae.e1, irs);
2855                     elem *efrom = toElem(ae.e2, irs);
2856 
2857                     uint size = cast(uint)t1.nextOf().size();
2858                     elem *esize = el_long(TYsize_t, size);
2859 
2860                     /* Determine if we need to do postblit
2861                      */
2862                     bool postblit = false;
2863                     if (needsPostblit(t1.nextOf()) &&
2864                         (ae.e2.op == TOK.slice && (cast(UnaExp)ae.e2).e1.isLvalue() ||
2865                          ae.e2.op == TOK.cast_  && (cast(UnaExp)ae.e2).e1.isLvalue() ||
2866                          ae.e2.op != TOK.slice && ae.e2.isLvalue()))
2867                     {
2868                         postblit = true;
2869                     }
2870                     bool destructor = needsDtor(t1.nextOf()) !is null;
2871 
2872                     assert(ae.e2.type.ty != Tpointer);
2873 
2874                     if (!postblit && !destructor)
2875                     {
2876                         elem *ex = el_same(&eto);
2877 
2878                         /* Returns: length of array ex
2879                          */
2880                         static elem *getDotLength(IRState* irs, elem *eto, elem *ex)
2881                         {
2882                             if (eto.Eoper == OPpair &&
2883                                 eto.EV.E1.Eoper == OPconst)
2884                             {
2885                                 // It's a constant, so just pull it from eto
2886                                 return el_copytree(eto.EV.E1);
2887                             }
2888                             else
2889                             {
2890                                 // It's not a constant, so pull it from the dynamic array
2891                                 return el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, el_copytree(ex));
2892                             }
2893                         }
2894 
2895                         auto elen = getDotLength(irs, eto, ex);
2896                         auto nbytes = el_bin(OPmul, TYsize_t, elen, esize);  // number of bytes to memcpy
2897                         auto epto = array_toPtr(ae.e1.type, ex);
2898 
2899                         elem *epfr;
2900                         elem *echeck;
2901                         if (irs.arrayBoundsCheck()) // check array lengths match and do not overlap
2902                         {
2903                             auto ey = el_same(&efrom);
2904                             auto eleny = getDotLength(irs, efrom, ey);
2905                             epfr = array_toPtr(ae.e2.type, ey);
2906 
2907                             // length check: (eleny == elen)
2908                             auto c = el_bin(OPeqeq, TYint, eleny, el_copytree(elen));
2909 
2910                             /* Don't check overlap if epto and epfr point to different symbols
2911                              */
2912                             if (!(epto.Eoper == OPaddr && epto.EV.E1.Eoper == OPvar &&
2913                                   epfr.Eoper == OPaddr && epfr.EV.E1.Eoper == OPvar &&
2914                                   epto.EV.E1.EV.Vsym != epfr.EV.E1.EV.Vsym))
2915                             {
2916                                 // Add overlap check (c && (px + nbytes <= py || py + nbytes <= px))
2917                                 auto c2 = el_bin(OPle, TYint, el_bin(OPadd, TYsize_t, el_copytree(epto), el_copytree(nbytes)), el_copytree(epfr));
2918                                 auto c3 = el_bin(OPle, TYint, el_bin(OPadd, TYsize_t, el_copytree(epfr), el_copytree(nbytes)), el_copytree(epto));
2919                                 c = el_bin(OPandand, TYint, c, el_bin(OPoror, TYint, c2, c3));
2920                             }
2921 
2922                             // Construct: (c || arrayBoundsError)
2923                             echeck = el_bin(OPoror, TYvoid, c, buildArrayBoundsError(irs, ae.loc, null, el_copytree(eleny), el_copytree(elen)));
2924                         }
2925                         else
2926                         {
2927                             epfr = array_toPtr(ae.e2.type, efrom);
2928                             efrom = null;
2929                             echeck = null;
2930                         }
2931 
2932                         /* Construct:
2933                          *   memcpy(ex.ptr, ey.ptr, nbytes)[0..elen]
2934                          */
2935                         elem* e = el_bin(OPmemcpy, TYnptr, epto, el_param(epfr, nbytes));
2936                         //elem* e = el_params(nbytes, epfr, epto, null);
2937                         //e = el_bin(OPcall,TYnptr,el_var(getRtlsym(RTLSYM_MEMCPY)),e);
2938                         e = el_pair(eto.Ety, el_copytree(elen), e);
2939 
2940                         /* Combine: eto, efrom, echeck, e
2941                          */
2942                         e = el_combine(el_combine(eto, efrom), el_combine(echeck, e));
2943                         return setResult(e);
2944                     }
2945                     else if ((postblit || destructor) && ae.op != TOK.blit)
2946                     {
2947                         /* Generate:
2948                          *      _d_arrayassign(ti, efrom, eto)
2949                          * or:
2950                          *      _d_arrayctor(ti, efrom, eto)
2951                          */
2952                         el_free(esize);
2953                         elem *eti = getTypeInfo(ae.e1.loc, t1.nextOf().toBasetype(), irs);
2954                         if (config.exe == EX_WIN64)
2955                         {
2956                             eto   = addressElem(eto,   Type.tvoid.arrayOf());
2957                             efrom = addressElem(efrom, Type.tvoid.arrayOf());
2958                         }
2959                         elem *ep = el_params(eto, efrom, eti, null);
2960                         int rtl = (ae.op == TOK.construct) ? RTLSYM_ARRAYCTOR : RTLSYM_ARRAYASSIGN;
2961                         elem* e = el_bin(OPcall, totym(ae.type), el_var(getRtlsym(rtl)), ep);
2962                         return setResult(e);
2963                     }
2964                     else
2965                     {
2966                         // Generate:
2967                         //      _d_arraycopy(eto, efrom, esize)
2968 
2969                         if (config.exe == EX_WIN64)
2970                         {
2971                             eto   = addressElem(eto,   Type.tvoid.arrayOf());
2972                             efrom = addressElem(efrom, Type.tvoid.arrayOf());
2973                         }
2974                         elem *ep = el_params(eto, efrom, esize, null);
2975                         elem* e = el_bin(OPcall, totym(ae.type), el_var(getRtlsym(RTLSYM_ARRAYCOPY)), ep);
2976                         return setResult(e);
2977                     }
2978                 }
2979                 assert(0);
2980             }
2981 
2982             /* Look for initialization of an `out` or `ref` variable
2983              */
2984             if (ae.memset == MemorySet.referenceInit)
2985             {
2986                 assert(ae.op == TOK.construct || ae.op == TOK.blit);
2987                 auto ve = ae.e1.isVarExp();
2988                 assert(ve);
2989                 assert(ve.var.storage_class & (STC.out_ | STC.ref_));
2990 
2991                 // It'll be initialized to an address
2992                 elem* e = toElem(ae.e2, irs);
2993                 e = addressElem(e, ae.e2.type);
2994                 elem *es = toElem(ae.e1, irs);
2995                 if (es.Eoper == OPind)
2996                     es = es.EV.E1;
2997                 else
2998                     es = el_una(OPaddr, TYnptr, es);
2999                 es.Ety = TYnptr;
3000                 e = el_bin(OPeq, TYnptr, es, e);
3001                 assert(!(t1b.ty == Tstruct && ae.e2.op == TOK.int64));
3002 
3003                 return setResult(e);
3004             }
3005 
3006             tym_t tym = totym(ae.type);
3007             elem *e1 = toElem(ae.e1, irs);
3008 
3009             elem *e1x;
3010 
3011             void setResult2(elem* e)
3012             {
3013                 return setResult(el_combine(e, e1x));
3014             }
3015 
3016             // Create a reference to e1.
3017             if (e1.Eoper == OPvar)
3018                 e1x = el_copytree(e1);
3019             else
3020             {
3021                 /* Rewrite to:
3022                  *  e1  = *((tmp = &e1), tmp)
3023                  *  e1x = *tmp
3024                  */
3025                 e1 = addressElem(e1, null);
3026                 e1x = el_same(&e1);
3027                 e1 = el_una(OPind, tym, e1);
3028                 if (tybasic(tym) == TYstruct)
3029                     e1.ET = Type_toCtype(ae.e1.type);
3030                 e1x = el_una(OPind, tym, e1x);
3031                 if (tybasic(tym) == TYstruct)
3032                     e1x.ET = Type_toCtype(ae.e1.type);
3033                 //printf("e1  = \n"); elem_print(e1);
3034                 //printf("e1x = \n"); elem_print(e1x);
3035             }
3036 
3037             // inlining may generate lazy variable initialization
3038             if (auto ve = ae.e1.isVarExp())
3039                 if (ve.var.storage_class & STC.lazy_)
3040                 {
3041                     assert(ae.op == TOK.construct || ae.op == TOK.blit);
3042                     elem* e = el_bin(OPeq, tym, e1, toElem(ae.e2, irs));
3043                     return setResult2(e);
3044                 }
3045 
3046             /* This will work if we can distinguish an assignment from
3047              * an initialization of the lvalue. It'll work if the latter.
3048              * If the former, because of aliasing of the return value with
3049              * function arguments, it'll fail.
3050              */
3051             if (ae.op == TOK.construct && ae.e2.op == TOK.call)
3052             {
3053                 CallExp ce = cast(CallExp)ae.e2;
3054                 TypeFunction tf = cast(TypeFunction)ce.e1.type.toBasetype();
3055                 if (tf.ty == Tfunction && retStyle(tf, ce.f && ce.f.needThis()) == RET.stack)
3056                 {
3057                     elem *ehidden = e1;
3058                     ehidden = el_una(OPaddr, TYnptr, ehidden);
3059                     assert(!irs.ehidden);
3060                     irs.ehidden = ehidden;
3061                     elem* e = toElem(ae.e2, irs);
3062                     return setResult2(e);
3063                 }
3064 
3065                 /* Look for:
3066                  *  v = structliteral.ctor(args)
3067                  * and have the structliteral write into v, rather than create a temporary
3068                  * and copy the temporary into v
3069                  */
3070                 if (e1.Eoper == OPvar && // no closure variables https://issues.dlang.org/show_bug.cgi?id=17622
3071                     ae.e1.op == TOK.variable && ce.e1.op == TOK.dotVariable)
3072                 {
3073                     auto dve = cast(DotVarExp)ce.e1;
3074                     auto fd = dve.var.isFuncDeclaration();
3075                     if (fd && fd.isCtorDeclaration())
3076                     {
3077                         if (auto sle = dve.e1.isStructLiteralExp())
3078                         {
3079                             sle.sym = toSymbol((cast(VarExp)ae.e1).var);
3080                             elem* e = toElem(ae.e2, irs);
3081                             return setResult2(e);
3082                         }
3083                     }
3084                 }
3085             }
3086 
3087             //if (ae.op == TOK.construct) printf("construct\n");
3088             if (auto t1s = t1b.isTypeStruct())
3089             {
3090                 if (ae.e2.op == TOK.int64)
3091                 {
3092                     assert(ae.op == TOK.blit);
3093 
3094                     /* Implement:
3095                      *  (struct = 0)
3096                      * with:
3097                      *  memset(&struct, 0, struct.sizeof)
3098                      */
3099                     uint sz = cast(uint)ae.e1.type.size();
3100 
3101                     elem *el = e1;
3102                     elem *enbytes = el_long(TYsize_t, sz);
3103                     elem *evalue = el_long(TYsize_t, 0);
3104 
3105                     el = el_una(OPaddr, TYnptr, el);
3106                     elem* e = el_param(enbytes, evalue);
3107                     e = el_bin(OPmemset,TYnptr,el,e);
3108                     return setResult2(e);
3109                 }
3110 
3111                 //printf("toElemBin() '%s'\n", ae.toChars());
3112 
3113                 if (auto sle = ae.e2.isStructLiteralExp())
3114                 {
3115                     auto ex = e1.Eoper == OPind ? e1.EV.E1 : e1;
3116                     if (ex.Eoper == OPvar && ex.EV.Voffset == 0 &&
3117                         (ae.op == TOK.construct || ae.op == TOK.blit))
3118                     {
3119                         elem* e = toElemStructLit(sle, irs, ae.op, ex.EV.Vsym, true);
3120                         el_free(e1);
3121                         return setResult2(e);
3122                     }
3123 
3124                     static bool allZeroBits(ref Expressions exps)
3125                     {
3126                         foreach (e; exps[])
3127                         {
3128                             /* The expression types checked can be expanded to include
3129                              * floating point, struct literals, and array literals.
3130                              * Just be careful to return false for -0.0
3131                              */
3132                             if (!e ||
3133                                 e.op == TOK.int64 && e.isIntegerExp().toInteger() == 0 ||
3134                                 e.op == TOK.null_)
3135                                 continue;
3136                             return false;
3137                         }
3138                         return true;
3139                     }
3140 
3141                     /* Use a memset to 0
3142                      */
3143                     if ((sle.useStaticInit ||
3144                          sle.elements && allZeroBits(*sle.elements) && !sle.sd.isNested()) &&
3145                         ae.e2.type.isZeroInit(ae.e2.loc))
3146                     {
3147                         elem* enbytes = el_long(TYsize_t, ae.e1.type.size());
3148                         elem* evalue = el_long(TYsize_t, 0);
3149                         elem* el = el_una(OPaddr, TYnptr, e1);
3150                         elem* e = el_bin(OPmemset,TYnptr, el, el_param(enbytes, evalue));
3151                         return setResult2(e);
3152                     }
3153                 }
3154 
3155                 /* Implement:
3156                  *  (struct = struct)
3157                  */
3158                 elem *e2 = toElem(ae.e2, irs);
3159 
3160                 elem* e = elAssign(e1, e2, ae.e1.type, null);
3161                 return setResult2(e);
3162             }
3163             else if (t1b.ty == Tsarray)
3164             {
3165                 if (ae.op == TOK.blit && ae.e2.op == TOK.int64)
3166                 {
3167                     /* Implement:
3168                      *  (sarray = 0)
3169                      * with:
3170                      *  memset(&sarray, 0, struct.sizeof)
3171                      */
3172                     elem *ey = null;
3173                     targ_size_t sz = ae.e1.type.size();
3174 
3175                     elem *el = e1;
3176                     elem *enbytes = el_long(TYsize_t, sz);
3177                     elem *evalue = el_long(TYsize_t, 0);
3178 
3179                     el = el_una(OPaddr, TYnptr, el);
3180                     elem* e = el_param(enbytes, evalue);
3181                     e = el_bin(OPmemset,TYnptr,el,e);
3182                     e = el_combine(ey, e);
3183                     return setResult2(e);
3184                 }
3185 
3186                 /* Implement:
3187                  *  (sarray = sarray)
3188                  */
3189                 assert(ae.e2.type.toBasetype().ty == Tsarray);
3190 
3191                 bool postblit = needsPostblit(t1b.nextOf()) !is null;
3192                 bool destructor = needsDtor(t1b.nextOf()) !is null;
3193 
3194                 /* Optimize static array assignment with array literal.
3195                  * Rewrite:
3196                  *      e1 = [a, b, ...];
3197                  * as:
3198                  *      e1[0] = a, e1[1] = b, ...;
3199                  *
3200                  * If the same values are contiguous, that will be rewritten
3201                  * to block assignment.
3202                  * Rewrite:
3203                  *      e1 = [x, a, a, b, ...];
3204                  * as:
3205                  *      e1[0] = x, e1[1..2] = a, e1[3] = b, ...;
3206                  */
3207                 if (ae.op == TOK.construct &&   // https://issues.dlang.org/show_bug.cgi?id=11238
3208                                                // avoid aliasing issue
3209                     ae.e2.op == TOK.arrayLiteral)
3210                 {
3211                     ArrayLiteralExp ale = cast(ArrayLiteralExp)ae.e2;
3212                     elem* e;
3213                     if (ale.elements.dim == 0)
3214                     {
3215                         e = e1;
3216                     }
3217                     else
3218                     {
3219                         Symbol *stmp = symbol_genauto(TYnptr);
3220                         e1 = addressElem(e1, t1b);
3221                         e1 = el_bin(OPeq, TYnptr, el_var(stmp), e1);
3222 
3223                         // Eliminate _d_arrayliteralTX call in ae.e2.
3224                         e = ExpressionsToStaticArray(ale.loc, ale.elements, &stmp, 0, ale.basis);
3225                         e = el_combine(e1, e);
3226                     }
3227                     return setResult2(e);
3228                 }
3229 
3230                 /* https://issues.dlang.org/show_bug.cgi?id=13661
3231                  * Even if the elements in rhs are all rvalues and
3232                  * don't have to call postblits, this assignment should call
3233                  * destructors on old assigned elements.
3234                  */
3235                 bool lvalueElem = false;
3236                 if (ae.e2.op == TOK.slice && (cast(UnaExp)ae.e2).e1.isLvalue() ||
3237                     ae.e2.op == TOK.cast_  && (cast(UnaExp)ae.e2).e1.isLvalue() ||
3238                     ae.e2.op != TOK.slice && ae.e2.isLvalue())
3239                 {
3240                     lvalueElem = true;
3241                 }
3242 
3243                 elem *e2 = toElem(ae.e2, irs);
3244 
3245                 if (!postblit && !destructor ||
3246                     ae.op == TOK.construct && !lvalueElem && postblit ||
3247                     ae.op == TOK.blit ||
3248                     type_size(e1.ET) == 0)
3249                 {
3250                     elem* e = elAssign(e1, e2, ae.e1.type, null);
3251                     return setResult2(e);
3252                 }
3253                 else if (ae.op == TOK.construct)
3254                 {
3255                     e1 = sarray_toDarray(ae.e1.loc, ae.e1.type, null, e1);
3256                     e2 = sarray_toDarray(ae.e2.loc, ae.e2.type, null, e2);
3257 
3258                     /* Generate:
3259                      *      _d_arrayctor(ti, e2, e1)
3260                      */
3261                     elem *eti = getTypeInfo(ae.e1.loc, t1b.nextOf().toBasetype(), irs);
3262                     if (config.exe == EX_WIN64)
3263                     {
3264                         e1 = addressElem(e1, Type.tvoid.arrayOf());
3265                         e2 = addressElem(e2, Type.tvoid.arrayOf());
3266                     }
3267                     elem *ep = el_params(e1, e2, eti, null);
3268                     elem* e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYCTOR)), ep);
3269                     return setResult2(e);
3270                 }
3271                 else
3272                 {
3273                     e1 = sarray_toDarray(ae.e1.loc, ae.e1.type, null, e1);
3274                     e2 = sarray_toDarray(ae.e2.loc, ae.e2.type, null, e2);
3275 
3276                     Symbol *stmp = symbol_genauto(Type_toCtype(t1b.nextOf()));
3277                     elem *etmp = el_una(OPaddr, TYnptr, el_var(stmp));
3278 
3279                     /* Generate:
3280                      *      _d_arrayassign_l(ti, e2, e1, etmp)
3281                      * or:
3282                      *      _d_arrayassign_r(ti, e2, e1, etmp)
3283                      */
3284                     elem *eti = getTypeInfo(ae.e1.loc, t1b.nextOf().toBasetype(), irs);
3285                     if (config.exe == EX_WIN64)
3286                     {
3287                         e1 = addressElem(e1, Type.tvoid.arrayOf());
3288                         e2 = addressElem(e2, Type.tvoid.arrayOf());
3289                     }
3290                     elem *ep = el_params(etmp, e1, e2, eti, null);
3291                     int rtl = lvalueElem ? RTLSYM_ARRAYASSIGN_L : RTLSYM_ARRAYASSIGN_R;
3292                     elem* e = el_bin(OPcall, TYdarray, el_var(getRtlsym(rtl)), ep);
3293                     return setResult2(e);
3294                 }
3295             }
3296             else
3297             {
3298                 elem* e = el_bin(OPeq, tym, e1, toElem(ae.e2, irs));
3299                 return setResult2(e);
3300             }
3301             assert(0);
3302         }
3303 
3304         /***************************************
3305          */
3306 
3307         override void visit(AddAssignExp e)
3308         {
3309             //printf("AddAssignExp.toElem() %s\n", e.toChars());
3310             result = toElemBinAssign(e, OPaddass);
3311         }
3312 
3313 
3314         /***************************************
3315          */
3316 
3317         override void visit(MinAssignExp e)
3318         {
3319             result = toElemBinAssign(e, OPminass);
3320         }
3321 
3322         /***************************************
3323          */
3324 
3325         override void visit(CatAssignExp ce)
3326         {
3327             //printf("CatAssignExp.toElem('%s')\n", ce.toChars());
3328             elem *e;
3329             Type tb1 = ce.e1.type.toBasetype();
3330             Type tb2 = ce.e2.type.toBasetype();
3331             assert(tb1.ty == Tarray);
3332             Type tb1n = tb1.nextOf().toBasetype();
3333 
3334             elem *e1 = toElem(ce.e1, irs);
3335             elem *e2 = toElem(ce.e2, irs);
3336 
3337             switch (ce.op)
3338             {
3339                 case TOK.concatenateDcharAssign:
3340                 {
3341                     // Append dchar to char[] or wchar[]
3342                     assert(tb2.ty == Tdchar &&
3343                           (tb1n.ty == Tchar || tb1n.ty == Twchar));
3344 
3345                     e1 = el_una(OPaddr, TYnptr, e1);
3346 
3347                     elem *ep = el_params(e2, e1, null);
3348                     int rtl = (tb1.nextOf().ty == Tchar)
3349                             ? RTLSYM_ARRAYAPPENDCD
3350                             : RTLSYM_ARRAYAPPENDWD;
3351                     e = el_bin(OPcall, TYdarray, el_var(getRtlsym(rtl)), ep);
3352                     toTraceGC(irs, e, ce.loc);
3353                     elem_setLoc(e, ce.loc);
3354                     break;
3355                 }
3356 
3357                 case TOK.concatenateAssign:
3358                 {
3359                     // Append array
3360                     assert(tb2.ty == Tarray || tb2.ty == Tsarray);
3361 
3362                     assert(tb1n.equals(tb2.nextOf().toBasetype()));
3363 
3364                     e1 = el_una(OPaddr, TYnptr, e1);
3365                     if (config.exe == EX_WIN64)
3366                         e2 = addressElem(e2, tb2, true);
3367                     else
3368                         e2 = useOPstrpar(e2);
3369                     elem *ep = el_params(e2, e1, getTypeInfo(ce.e1.loc, ce.e1.type, irs), null);
3370                     e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYAPPENDT)), ep);
3371                     toTraceGC(irs, e, ce.loc);
3372                     break;
3373                 }
3374 
3375                 case TOK.concatenateElemAssign:
3376                 {
3377                     // Append element
3378                     assert(tb1n.equals(tb2));
3379 
3380                     elem *e2x = null;
3381 
3382                     if (e2.Eoper != OPvar && e2.Eoper != OPconst)
3383                     {
3384                         // Evaluate e2 and assign result to temporary s2.
3385                         // Do this because of:
3386                         //    a ~= a[$-1]
3387                         // because $ changes its value
3388                         type* tx = Type_toCtype(tb2);
3389                         Symbol *s2 = symbol_genauto(tx);
3390                         e2x = elAssign(el_var(s2), e2, tb1n, tx);
3391 
3392                         e2 = el_var(s2);
3393                     }
3394 
3395                     // Extend array with _d_arrayappendcTX(TypeInfo ti, e1, 1)
3396                     e1 = el_una(OPaddr, TYnptr, e1);
3397                     elem *ep = el_param(e1, getTypeInfo(ce.e1.loc, ce.e1.type, irs));
3398                     ep = el_param(el_long(TYsize_t, 1), ep);
3399                     e = el_bin(OPcall, TYdarray, el_var(getRtlsym(RTLSYM_ARRAYAPPENDCTX)), ep);
3400                     toTraceGC(irs, e, ce.loc);
3401                     Symbol *stmp = symbol_genauto(Type_toCtype(tb1));
3402                     e = el_bin(OPeq, TYdarray, el_var(stmp), e);
3403 
3404                     // Assign e2 to last element in stmp[]
3405                     // *(stmp.ptr + (stmp.length - 1) * szelem) = e2
3406 
3407                     elem *eptr = array_toPtr(tb1, el_var(stmp));
3408                     elem *elength = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, el_var(stmp));
3409                     elength = el_bin(OPmin, TYsize_t, elength, el_long(TYsize_t, 1));
3410                     elength = el_bin(OPmul, TYsize_t, elength, el_long(TYsize_t, ce.e2.type.size()));
3411                     eptr = el_bin(OPadd, TYnptr, eptr, elength);
3412                     elem *ederef = el_una(OPind, e2.Ety, eptr);
3413 
3414                     elem *eeq = elAssign(ederef, e2, tb1n, null);
3415                     e = el_combine(e2x, e);
3416                     e = el_combine(e, eeq);
3417                     e = el_combine(e, el_var(stmp));
3418                     break;
3419                 }
3420 
3421                 default:
3422                     assert(0);
3423             }
3424             elem_setLoc(e, ce.loc);
3425             result = e;
3426         }
3427 
3428         /***************************************
3429          */
3430 
3431         override void visit(DivAssignExp e)
3432         {
3433             result = toElemBinAssign(e, OPdivass);
3434         }
3435 
3436         /***************************************
3437          */
3438 
3439         override void visit(ModAssignExp e)
3440         {
3441             result = toElemBinAssign(e, OPmodass);
3442         }
3443 
3444         /***************************************
3445          */
3446 
3447         override void visit(MulAssignExp e)
3448         {
3449             result = toElemBinAssign(e, OPmulass);
3450         }
3451 
3452         /***************************************
3453          */
3454 
3455         override void visit(ShlAssignExp e)
3456         {
3457             result = toElemBinAssign(e, OPshlass);
3458         }
3459 
3460         /***************************************
3461          */
3462 
3463         override void visit(ShrAssignExp e)
3464         {
3465             //printf("ShrAssignExp.toElem() %s, %s\n", e.e1.type.toChars(), e.e1.toChars());
3466             Type t1 = e.e1.type;
3467             if (e.e1.op == TOK.cast_)
3468             {
3469                 /* Use the type before it was integrally promoted to int
3470                  */
3471                 CastExp ce = cast(CastExp)e.e1;
3472                 t1 = ce.e1.type;
3473             }
3474             result = toElemBinAssign(e, t1.isunsigned() ? OPshrass : OPashrass);
3475         }
3476 
3477         /***************************************
3478          */
3479 
3480         override void visit(UshrAssignExp e)
3481         {
3482             result = toElemBinAssign(e, OPshrass);
3483         }
3484 
3485         /***************************************
3486          */
3487 
3488         override void visit(AndAssignExp e)
3489         {
3490             result = toElemBinAssign(e, OPandass);
3491         }
3492 
3493         /***************************************
3494          */
3495 
3496         override void visit(OrAssignExp e)
3497         {
3498             result = toElemBinAssign(e, OPorass);
3499         }
3500 
3501         /***************************************
3502          */
3503 
3504         override void visit(XorAssignExp e)
3505         {
3506             result = toElemBinAssign(e, OPxorass);
3507         }
3508 
3509         /***************************************
3510          */
3511 
3512         override void visit(LogicalExp aae)
3513         {
3514             tym_t tym = totym(aae.type);
3515 
3516             elem *el = toElem(aae.e1, irs);
3517             elem *er = toElemDtor(aae.e2, irs);
3518             elem *e = el_bin(aae.op == TOK.andAnd ? OPandand : OPoror,tym,el,er);
3519 
3520             elem_setLoc(e, aae.loc);
3521 
3522             if (irs.params.cov && aae.e2.loc.linnum)
3523                 e.EV.E2 = el_combine(incUsageElem(irs, aae.e2.loc), e.EV.E2);
3524             result = e;
3525         }
3526 
3527         /***************************************
3528          */
3529 
3530         override void visit(XorExp e)
3531         {
3532             result = toElemBin(e, OPxor);
3533         }
3534 
3535         /***************************************
3536          */
3537 
3538         override void visit(AndExp e)
3539         {
3540             result = toElemBin(e, OPand);
3541         }
3542 
3543         /***************************************
3544          */
3545 
3546         override void visit(OrExp e)
3547         {
3548             result = toElemBin(e, OPor);
3549         }
3550 
3551         /***************************************
3552          */
3553 
3554         override void visit(ShlExp e)
3555         {
3556             result = toElemBin(e, OPshl);
3557         }
3558 
3559         /***************************************
3560          */
3561 
3562         override void visit(ShrExp e)
3563         {
3564             result = toElemBin(e, e.e1.type.isunsigned() ? OPshr : OPashr);
3565         }
3566 
3567         /***************************************
3568          */
3569 
3570         override void visit(UshrExp se)
3571         {
3572             elem *eleft  = toElem(se.e1, irs);
3573             eleft.Ety = touns(eleft.Ety);
3574             elem *eright = toElem(se.e2, irs);
3575             elem *e = el_bin(OPshr, totym(se.type), eleft, eright);
3576             elem_setLoc(e, se.loc);
3577             result = e;
3578         }
3579 
3580         /****************************************
3581          */
3582 
3583         override void visit(CommaExp ce)
3584         {
3585             assert(ce.e1 && ce.e2);
3586             elem *eleft  = toElem(ce.e1, irs);
3587             elem *eright = toElem(ce.e2, irs);
3588             elem *e = el_combine(eleft, eright);
3589             if (e)
3590                 elem_setLoc(e, ce.loc);
3591             result = e;
3592         }
3593 
3594         /***************************************
3595          */
3596 
3597         override void visit(CondExp ce)
3598         {
3599             elem *ec = toElem(ce.econd, irs);
3600 
3601             elem *eleft = toElem(ce.e1, irs);
3602             if (irs.params.cov && ce.e1.loc.linnum)
3603                 eleft = el_combine(incUsageElem(irs, ce.e1.loc), eleft);
3604 
3605             elem *eright = toElem(ce.e2, irs);
3606             if (irs.params.cov && ce.e2.loc.linnum)
3607                 eright = el_combine(incUsageElem(irs, ce.e2.loc), eright);
3608 
3609             tym_t ty = eleft.Ety;
3610             if (ce.e1.type.toBasetype().ty == Tvoid ||
3611                 ce.e2.type.toBasetype().ty == Tvoid)
3612                 ty = TYvoid;
3613 
3614             elem *e = el_bin(OPcond, ty, ec, el_bin(OPcolon, ty, eleft, eright));
3615             if (tybasic(ty) == TYstruct)
3616                 e.ET = Type_toCtype(ce.e1.type);
3617             elem_setLoc(e, ce.loc);
3618             result = e;
3619         }
3620 
3621         /***************************************
3622          */
3623 
3624         override void visit(TypeExp e)
3625         {
3626             //printf("TypeExp.toElem()\n");
3627             e.error("type `%s` is not an expression", e.toChars());
3628             result = el_long(TYint, 0);
3629         }
3630 
3631         override void visit(ScopeExp e)
3632         {
3633             e.error("`%s` is not an expression", e.sds.toChars());
3634             result = el_long(TYint, 0);
3635         }
3636 
3637         override void visit(DotVarExp dve)
3638         {
3639             // *(&e + offset)
3640 
3641             //printf("[%s] DotVarExp.toElem('%s')\n", dve.loc.toChars(), dve.toChars());
3642 
3643             VarDeclaration v = dve.var.isVarDeclaration();
3644             if (!v)
3645             {
3646                 dve.error("`%s` is not a field, but a %s", dve.var.toChars(), dve.var.kind());
3647                 result = el_long(TYint, 0);
3648                 return;
3649             }
3650 
3651             // https://issues.dlang.org/show_bug.cgi?id=12900
3652             Type txb = dve.type.toBasetype();
3653             Type tyb = v.type.toBasetype();
3654             if (auto tv = txb.isTypeVector()) txb = tv.basetype;
3655             if (auto tv = tyb.isTypeVector()) tyb = tv.basetype;
3656 
3657             debug if (txb.ty != tyb.ty)
3658                 printf("[%s] dve = %s, dve.type = %s, v.type = %s\n", dve.loc.toChars(), dve.toChars(), dve.type.toChars(), v.type.toChars());
3659 
3660             assert(txb.ty == tyb.ty);
3661 
3662             // https://issues.dlang.org/show_bug.cgi?id=14730
3663             if (v.offset == 0)
3664             {
3665                 FuncDeclaration fd = v.parent.isFuncDeclaration();
3666                 if (fd && fd.semanticRun < PASS.obj)
3667                     setClosureVarOffset(fd);
3668             }
3669 
3670             elem *e = toElem(dve.e1, irs);
3671             Type tb1 = dve.e1.type.toBasetype();
3672             tym_t typ = TYnptr;
3673             if (tb1.ty != Tclass && tb1.ty != Tpointer)
3674             {
3675                 e = addressElem(e, tb1);
3676                 typ = tybasic(e.Ety);
3677             }
3678             auto offset = el_long(TYsize_t, v.offset);
3679             offset = objc.getOffset(v, tb1, offset);
3680             e = el_bin(OPadd, typ, e, offset);
3681             if (v.storage_class & (STC.out_ | STC.ref_))
3682                 e = el_una(OPind, TYnptr, e);
3683             e = el_una(OPind, totym(dve.type), e);
3684             if (tybasic(e.Ety) == TYstruct)
3685             {
3686                 e.ET = Type_toCtype(dve.type);
3687             }
3688             elem_setLoc(e,dve.loc);
3689             result = e;
3690         }
3691 
3692         override void visit(DelegateExp de)
3693         {
3694             int directcall = 0;
3695             //printf("DelegateExp.toElem() '%s'\n", de.toChars());
3696 
3697             if (de.func.semanticRun == PASS.semantic3done)
3698             {
3699                 // Bug 7745 - only include the function if it belongs to this module
3700                 // ie, it is a member of this module, or is a template instance
3701                 // (the template declaration could come from any module).
3702                 Dsymbol owner = de.func.toParent();
3703                 while (!owner.isTemplateInstance() && owner.toParent())
3704                     owner = owner.toParent();
3705                 if (owner.isTemplateInstance() || owner == irs.m )
3706                 {
3707                     irs.deferToObj.push(de.func);
3708                 }
3709             }
3710 
3711             elem *eeq = null;
3712             elem *ethis;
3713             Symbol *sfunc = toSymbol(de.func);
3714             elem *ep;
3715 
3716             elem *ethis2 = null;
3717             if (de.vthis2)
3718             {
3719                 // avoid using toSymbol directly because vthis2 may be a closure var
3720                 Expression ve = new VarExp(de.loc, de.vthis2);
3721                 ve.type = de.vthis2.type;
3722                 ve = new AddrExp(de.loc, ve);
3723                 ve.type = de.vthis2.type.pointerTo();
3724                 ethis2 = toElem(ve, irs);
3725             }
3726 
3727             if (de.func.isNested() && !de.func.isThis())
3728             {
3729                 ep = el_ptr(sfunc);
3730                 if (de.e1.op == TOK.null_)
3731                     ethis = toElem(de.e1, irs);
3732                 else
3733                     ethis = getEthis(de.loc, irs, de.func, de.func.toParentLocal());
3734 
3735                 if (ethis2)
3736                     ethis2 = setEthis2(de.loc, irs, de.func, ethis2, &ethis, &eeq);
3737             }
3738             else
3739             {
3740                 ethis = toElem(de.e1, irs);
3741                 if (de.e1.type.ty != Tclass && de.e1.type.ty != Tpointer)
3742                     ethis = addressElem(ethis, de.e1.type);
3743 
3744                 if (ethis2)
3745                     ethis2 = setEthis2(de.loc, irs, de.func, ethis2, &ethis, &eeq);
3746 
3747                 if (de.e1.op == TOK.super_ || de.e1.op == TOK.dotType)
3748                     directcall = 1;
3749 
3750                 if (!de.func.isThis())
3751                     de.error("delegates are only for non-static functions");
3752 
3753                 if (!de.func.isVirtual() ||
3754                     directcall ||
3755                     de.func.isFinalFunc())
3756                 {
3757                     ep = el_ptr(sfunc);
3758                 }
3759                 else
3760                 {
3761                     // Get pointer to function out of virtual table
3762 
3763                     assert(ethis);
3764                     ep = el_same(&ethis);
3765                     ep = el_una(OPind, TYnptr, ep);
3766                     uint vindex = de.func.vtblIndex;
3767 
3768                     assert(cast(int)vindex >= 0);
3769 
3770                     // Build *(ep + vindex * 4)
3771                     ep = el_bin(OPadd,TYnptr,ep,el_long(TYsize_t, vindex * target.ptrsize));
3772                     ep = el_una(OPind,TYnptr,ep);
3773                 }
3774 
3775                 //if (func.tintro)
3776                 //    func.error(loc, "cannot form delegate due to covariant return type");
3777             }
3778 
3779             elem *e;
3780             if (ethis2)
3781                 ethis = ethis2;
3782             if (ethis.Eoper == OPcomma)
3783             {
3784                 ethis.EV.E2 = el_pair(TYdelegate, ethis.EV.E2, ep);
3785                 ethis.Ety = TYdelegate;
3786                 e = ethis;
3787             }
3788             else
3789                 e = el_pair(TYdelegate, ethis, ep);
3790             elem_setLoc(e, de.loc);
3791             if (eeq)
3792                 e = el_combine(eeq, e);
3793             result = e;
3794         }
3795 
3796         override void visit(DotTypeExp dte)
3797         {
3798             // Just a pass-thru to e1
3799             //printf("DotTypeExp.toElem() %s\n", dte.toChars());
3800             elem *e = toElem(dte.e1, irs);
3801             elem_setLoc(e, dte.loc);
3802             result = e;
3803         }
3804 
3805         override void visit(CallExp ce)
3806         {
3807             //printf("[%s] CallExp.toElem('%s') %p, %s\n", ce.loc.toChars(), ce.toChars(), ce, ce.type.toChars());
3808             assert(ce.e1.type);
3809             Type t1 = ce.e1.type.toBasetype();
3810             Type ectype = t1;
3811             elem *eeq = null;
3812 
3813             elem *ehidden = irs.ehidden;
3814             irs.ehidden = null;
3815 
3816             elem *ec;
3817             FuncDeclaration fd = null;
3818             bool dctor = false;
3819             if (ce.e1.op == TOK.dotVariable && t1.ty != Tdelegate)
3820             {
3821                 DotVarExp dve = cast(DotVarExp)ce.e1;
3822 
3823                 fd = dve.var.isFuncDeclaration();
3824 
3825                 if (auto sle = dve.e1.isStructLiteralExp())
3826                 {
3827                     if (fd && fd.isCtorDeclaration() ||
3828                         fd.type.isMutable() ||
3829                         sle.type.size() <= 8)          // more efficient than fPIC
3830                         sle.useStaticInit = false;     // don't modify initializer, so make copy
3831                 }
3832 
3833                 ec = toElem(dve.e1, irs);
3834                 ectype = dve.e1.type.toBasetype();
3835 
3836                 /* Recognize:
3837                  *   [1] ce:  ((S __ctmp = initializer),__ctmp).ctor(args)
3838                  * where the left of the . was turned into [2] or [3] for EH_DWARF:
3839                  *   [2] ec:  (dctor info ((__ctmp = initializer),__ctmp)), __ctmp
3840                  *   [3] ec:  (dctor info ((_flag=0),((__ctmp = initializer),__ctmp))), __ctmp
3841                  * The trouble
3842                  * https://issues.dlang.org/show_bug.cgi?id=13095
3843                  * is if ctor(args) throws, then __ctmp is destructed even though __ctmp
3844                  * is not a fully constructed object yet. The solution is to move the ctor(args) itno the dctor tree.
3845                  * But first, detect [1], then [2], then split up [2] into:
3846                  *   eeq: (dctor info ((__ctmp = initializer),__ctmp))
3847                  *   eeq: (dctor info ((_flag=0),((__ctmp = initializer),__ctmp)))   for EH_DWARF
3848                  *   ec:  __ctmp
3849                  */
3850                 if (fd && fd.isCtorDeclaration())
3851                 {
3852                     //printf("test30 %s\n", dve.e1.toChars());
3853                     if (dve.e1.op == TOK.comma)
3854                     {
3855                         //printf("test30a\n");
3856                         if ((cast(CommaExp)dve.e1).e1.op == TOK.declaration && (cast(CommaExp)dve.e1).e2.op == TOK.variable)
3857                         {   // dve.e1: (declaration , var)
3858 
3859                             //printf("test30b\n");
3860                             if (ec.Eoper == OPcomma &&
3861                                 ec.EV.E1.Eoper == OPinfo &&
3862                                 ec.EV.E1.EV.E1.Eoper == OPdctor &&
3863                                 ec.EV.E1.EV.E2.Eoper == OPcomma)
3864                             {   // ec: ((dctor info (* , *)) , *)
3865 
3866                                 //printf("test30c\n");
3867                                 dctor = true;                   // remember we detected it
3868 
3869                                 // Split ec into eeq and ec per comment above
3870                                 eeq = ec.EV.E1;                   // (dctor info (*, *))
3871                                 ec.EV.E1 = null;
3872                                 ec = el_selecte2(ec);           // *
3873                             }
3874                         }
3875                     }
3876                 }
3877 
3878 
3879                 if (dctor)
3880                 {
3881                 }
3882                 else if (ce.arguments && ce.arguments.dim && ec.Eoper != OPvar)
3883                 {
3884                     if (ec.Eoper == OPind && el_sideeffect(ec.EV.E1))
3885                     {
3886                         /* Rewrite (*exp)(arguments) as:
3887                          * tmp = exp, (*tmp)(arguments)
3888                          */
3889                         elem *ec1 = ec.EV.E1;
3890                         Symbol *stmp = symbol_genauto(type_fake(ec1.Ety));
3891                         eeq = el_bin(OPeq, ec.Ety, el_var(stmp), ec1);
3892                         ec.EV.E1 = el_var(stmp);
3893                     }
3894                     else if (tybasic(ec.Ety) != TYnptr)
3895                     {
3896                         /* Rewrite (exp)(arguments) as:
3897                          * tmp=&exp, (*tmp)(arguments)
3898                          */
3899                         ec = addressElem(ec, ectype);
3900 
3901                         Symbol *stmp = symbol_genauto(type_fake(ec.Ety));
3902                         eeq = el_bin(OPeq, ec.Ety, el_var(stmp), ec);
3903                         ec = el_una(OPind, totym(ectype), el_var(stmp));
3904                     }
3905                 }
3906             }
3907             else if (ce.e1.op == TOK.variable)
3908             {
3909                 fd = (cast(VarExp)ce.e1).var.isFuncDeclaration();
3910                 version (none)
3911                 {
3912                     // This optimization is not valid if alloca can be called
3913                     // multiple times within the same function, eg in a loop
3914                     // see issue 3822
3915                     if (fd && fd.ident == Id.__alloca &&
3916                         !fd.fbody && fd.linkage == LINK.c &&
3917                         arguments && arguments.dim == 1)
3918                     {   Expression arg = (*arguments)[0];
3919                         arg = arg.optimize(WANTvalue);
3920                         if (arg.isConst() && arg.type.isintegral())
3921                         {   dinteger_t sz = arg.toInteger();
3922                             if (sz > 0 && sz < 0x40000)
3923                             {
3924                                 // It's an alloca(sz) of a fixed amount.
3925                                 // Replace with an array allocated on the stack
3926                                 // of the same size: char[sz] tmp;
3927 
3928                                 assert(!ehidden);
3929                                 .type *t = type_static_array(sz, tschar);  // BUG: fix extra Tcount++
3930                                 Symbol *stmp = symbol_genauto(t);
3931                                 ec = el_ptr(stmp);
3932                                 elem_setLoc(ec,loc);
3933                                 return ec;
3934                             }
3935                         }
3936                     }
3937                 }
3938 
3939                 ec = toElem(ce.e1, irs);
3940             }
3941             else
3942             {
3943                 ec = toElem(ce.e1, irs);
3944                 if (ce.arguments && ce.arguments.dim)
3945                 {
3946                     /* The idea is to enforce expressions being evaluated left to right,
3947                      * even though call trees are evaluated parameters first.
3948                      * We just do a quick hack to catch the more obvious cases, though
3949                      * we need to solve this generally.
3950                      */
3951                     if (ec.Eoper == OPind && el_sideeffect(ec.EV.E1))
3952                     {
3953                         /* Rewrite (*exp)(arguments) as:
3954                          * tmp=exp, (*tmp)(arguments)
3955                          */
3956                         elem *ec1 = ec.EV.E1;
3957                         Symbol *stmp = symbol_genauto(type_fake(ec1.Ety));
3958                         eeq = el_bin(OPeq, ec.Ety, el_var(stmp), ec1);
3959                         ec.EV.E1 = el_var(stmp);
3960                     }
3961                     else if (tybasic(ec.Ety) == TYdelegate && el_sideeffect(ec))
3962                     {
3963                         /* Rewrite (exp)(arguments) as:
3964                          * tmp=exp, (tmp)(arguments)
3965                          */
3966                         Symbol *stmp = symbol_genauto(type_fake(ec.Ety));
3967                         eeq = el_bin(OPeq, ec.Ety, el_var(stmp), ec);
3968                         ec = el_var(stmp);
3969                     }
3970                 }
3971             }
3972             elem *ethis2 = null;
3973             if (ce.vthis2)
3974             {
3975                 // avoid using toSymbol directly because vthis2 may be a closure var
3976                 Expression ve = new VarExp(ce.loc, ce.vthis2);
3977                 ve.type = ce.vthis2.type;
3978                 ve = new AddrExp(ce.loc, ve);
3979                 ve.type = ce.vthis2.type.pointerTo();
3980                 ethis2 = toElem(ve, irs);
3981             }
3982             elem *ecall = callfunc(ce.loc, irs, ce.directcall, ce.type, ec, ectype, fd, t1, ehidden, ce.arguments, null, ethis2);
3983 
3984             if (dctor && ecall.Eoper == OPind)
3985             {
3986                 /* Continuation of fix outlined above for moving constructor call into dctor tree.
3987                  * Given:
3988                  *   eeq:   (dctor info ((__ctmp = initializer),__ctmp))
3989                  *   eeq:   (dctor info ((_flag=0),((__ctmp = initializer),__ctmp)))   for EH_DWARF
3990                  *   ecall: * call(ce, args)
3991                  * Rewrite ecall as:
3992                  *    * (dctor info ((__ctmp = initializer),call(ce, args)))
3993                  *    * (dctor info ((_flag=0),(__ctmp = initializer),call(ce, args)))
3994                  */
3995                 elem *ea = ecall.EV.E1;           // ea: call(ce,args)
3996                 tym_t ty = ea.Ety;
3997                 ecall.EV.E1 = eeq;
3998                 assert(eeq.Eoper == OPinfo);
3999                 elem *eeqcomma = eeq.EV.E2;
4000                 assert(eeqcomma.Eoper == OPcomma);
4001                 while (eeqcomma.EV.E2.Eoper == OPcomma)
4002                 {
4003                     eeqcomma.Ety = ty;
4004                     eeqcomma = eeqcomma.EV.E2;
4005                 }
4006                 eeq.Ety = ty;
4007                 el_free(eeqcomma.EV.E2);
4008                 eeqcomma.EV.E2 = ea;               // replace ,__ctmp with ,call(ce,args)
4009                 eeqcomma.Ety = ty;
4010                 eeq = null;
4011             }
4012 
4013             elem_setLoc(ecall, ce.loc);
4014             if (eeq)
4015                 ecall = el_combine(eeq, ecall);
4016             result = ecall;
4017         }
4018 
4019         override void visit(AddrExp ae)
4020         {
4021             //printf("AddrExp.toElem('%s')\n", ae.toChars());
4022             if (auto sle = ae.e1.isStructLiteralExp())
4023             {
4024                 //printf("AddrExp.toElem('%s') %d\n", ae.toChars(), ae);
4025                 //printf("StructLiteralExp(%p); origin:%p\n", sle, sle.origin);
4026                 //printf("sle.toSymbol() (%p)\n", sle.toSymbol());
4027                 elem *e = el_ptr(toSymbol(sle.origin));
4028                 e.ET = Type_toCtype(ae.type);
4029                 elem_setLoc(e, ae.loc);
4030                 result = e;
4031                 return;
4032             }
4033             else
4034             {
4035                 elem *e = toElem(ae.e1, irs);
4036                 e = addressElem(e, ae.e1.type);
4037                 e.Ety = totym(ae.type);
4038                 elem_setLoc(e, ae.loc);
4039                 result = e;
4040                 return;
4041             }
4042         }
4043 
4044         override void visit(PtrExp pe)
4045         {
4046             //printf("PtrExp.toElem() %s\n", pe.toChars());
4047             elem *e = toElem(pe.e1, irs);
4048             if (tybasic(e.Ety) == TYnptr &&
4049                 pe.e1.type.nextOf() &&
4050                 pe.e1.type.nextOf().isImmutable())
4051             {
4052                 e.Ety = TYimmutPtr;     // pointer to immutable
4053             }
4054             e = el_una(OPind,totym(pe.type),e);
4055             if (tybasic(e.Ety) == TYstruct)
4056             {
4057                 e.ET = Type_toCtype(pe.type);
4058             }
4059             elem_setLoc(e, pe.loc);
4060             result = e;
4061         }
4062 
4063         override void visit(DeleteExp de)
4064         {
4065             Type tb;
4066 
4067             //printf("DeleteExp.toElem()\n");
4068             if (de.e1.op == TOK.index)
4069             {
4070                 IndexExp ae = cast(IndexExp)de.e1;
4071                 tb = ae.e1.type.toBasetype();
4072                 assert(tb.ty != Taarray);
4073             }
4074             //e1.type.print();
4075             elem *e = toElem(de.e1, irs);
4076             tb = de.e1.type.toBasetype();
4077             int rtl;
4078             switch (tb.ty)
4079             {
4080                 case Tarray:
4081                 {
4082                     e = addressElem(e, de.e1.type);
4083                     rtl = RTLSYM_DELARRAYT;
4084 
4085                     /* See if we need to run destructors on the array contents
4086                      */
4087                     elem *et = null;
4088                     Type tv = tb.nextOf().baseElemOf();
4089                     if (auto ts = tv.isTypeStruct())
4090                     {
4091                         // FIXME: ts can be non-mutable, but _d_delarray_t requests TypeInfo_Struct.
4092                         StructDeclaration sd = ts.sym;
4093                         if (sd.dtor)
4094                             et = getTypeInfo(de.e1.loc, tb.nextOf(), irs);
4095                     }
4096                     if (!et)                            // if no destructors needed
4097                         et = el_long(TYnptr, 0);        // pass null for TypeInfo
4098                     e = el_params(et, e, null);
4099                     // call _d_delarray_t(e, et);
4100                     break;
4101                 }
4102                 case Tclass:
4103                     if (de.e1.op == TOK.variable)
4104                     {
4105                         VarExp ve = cast(VarExp)de.e1;
4106                         if (ve.var.isVarDeclaration() &&
4107                             ve.var.isVarDeclaration().onstack)
4108                         {
4109                             rtl = RTLSYM_CALLFINALIZER;
4110                             if (tb.isClassHandle().isInterfaceDeclaration())
4111                                 rtl = RTLSYM_CALLINTERFACEFINALIZER;
4112                             break;
4113                         }
4114                     }
4115                     e = addressElem(e, de.e1.type);
4116                     rtl = RTLSYM_DELCLASS;
4117                     if (tb.isClassHandle().isInterfaceDeclaration())
4118                         rtl = RTLSYM_DELINTERFACE;
4119                     break;
4120 
4121                 case Tpointer:
4122                     e = addressElem(e, de.e1.type);
4123                     rtl = RTLSYM_DELMEMORY;
4124                     tb = (cast(TypePointer)tb).next.toBasetype();
4125                     if (auto ts = tb.isTypeStruct())
4126                     {
4127                         if (ts.sym.dtor)
4128                         {
4129                             rtl = RTLSYM_DELSTRUCT;
4130                             elem *et = getTypeInfo(de.e1.loc, tb, irs);
4131                             e = el_params(et, e, null);
4132                         }
4133                     }
4134                     break;
4135 
4136                 default:
4137                     assert(0);
4138             }
4139             e = el_bin(OPcall, TYvoid, el_var(getRtlsym(rtl)), e);
4140             toTraceGC(irs, e, de.loc);
4141             elem_setLoc(e, de.loc);
4142             result = e;
4143         }
4144 
4145         override void visit(VectorExp ve)
4146         {
4147             version (none)
4148             {
4149                 printf("VectorExp.toElem()\n");
4150                 ve.print();
4151                 printf("\tfrom: %s\n", ve.e1.type.toChars());
4152                 printf("\tto  : %s\n", ve.to.toChars());
4153             }
4154 
4155             elem* e;
4156             if (ve.e1.op == TOK.arrayLiteral)
4157             {
4158                 e = el_calloc();
4159                 e.Eoper = OPconst;
4160                 e.Ety = totym(ve.type);
4161 
4162                 foreach (const i; 0 .. ve.dim)
4163                 {
4164                     Expression elem = ve.e1.isArrayLiteralExp()[i];
4165                     const complex = elem.toComplex();
4166                     const integer = elem.toInteger();
4167                     switch (elem.type.toBasetype().ty)
4168                     {
4169                         case Tfloat32:
4170                             // Must not call toReal directly, to avoid dmd bug 14203 from breaking dmd
4171                             e.EV.Vfloat8[i] = cast(float) complex.re;
4172                             break;
4173 
4174                         case Tfloat64:
4175                             // Must not call toReal directly, to avoid dmd bug 14203 from breaking dmd
4176                             e.EV.Vdouble4[i] = cast(double) complex.re;
4177                             break;
4178 
4179                         case Tint64:
4180                         case Tuns64:
4181                             e.EV.Vullong4[i] = integer;
4182                             break;
4183 
4184                         case Tint32:
4185                         case Tuns32:
4186                             e.EV.Vulong8[i] = cast(uint)integer;
4187                             break;
4188 
4189                         case Tint16:
4190                         case Tuns16:
4191                             e.EV.Vushort16[i] = cast(ushort)integer;
4192                             break;
4193 
4194                         case Tint8:
4195                         case Tuns8:
4196                             e.EV.Vuchar32[i] = cast(ubyte)integer;
4197                             break;
4198 
4199                         default:
4200                             assert(0);
4201                     }
4202                 }
4203             }
4204             else
4205             {
4206                 // Create vecfill(e1)
4207                 elem* e1 = toElem(ve.e1, irs);
4208                 e = el_una(OPvecfill, totym(ve.type), e1);
4209             }
4210             elem_setLoc(e, ve.loc);
4211             result = e;
4212         }
4213 
4214         override void visit(VectorArrayExp vae)
4215         {
4216             // Generate code for `vec.array`
4217             if (auto ve = vae.e1.isVectorExp())
4218             {
4219                 // https://issues.dlang.org/show_bug.cgi?id=19607
4220                 // When viewing a vector literal as an array, build the underlying array directly.
4221                 if (ve.e1.op == TOK.arrayLiteral)
4222                     result = toElem(ve.e1, irs);
4223                 else
4224                 {
4225                     // Generate: stmp[0 .. dim] = e1
4226                     type* tarray = Type_toCtype(vae.type);
4227                     Symbol* stmp = symbol_genauto(tarray);
4228                     result = setArray(ve.e1, el_ptr(stmp), el_long(TYsize_t, tarray.Tdim),
4229                                       ve.e1.type, toElem(ve.e1, irs), irs, TOK.blit);
4230                     result = el_combine(result, el_var(stmp));
4231                     result.ET = tarray;
4232                 }
4233             }
4234             else
4235             {
4236                 // For other vector expressions this just a paint operation.
4237                 elem* e = toElem(vae.e1, irs);
4238                 type* tarray = Type_toCtype(vae.type);
4239                 // Take the address then repaint,
4240                 // this makes it swap to the right registers
4241                 e = addressElem(e, vae.e1.type);
4242                 e = el_una(OPind, tarray.Tty, e);
4243                 e.ET = tarray;
4244                 result = e;
4245             }
4246             result.Ety = totym(vae.type);
4247             elem_setLoc(result, vae.loc);
4248         }
4249 
4250         override void visit(CastExp ce)
4251         {
4252             version (none)
4253             {
4254                 printf("CastExp.toElem()\n");
4255                 ce.print();
4256                 printf("\tfrom: %s\n", ce.e1.type.toChars());
4257                 printf("\tto  : %s\n", ce.to.toChars());
4258             }
4259             elem *e = toElem(ce.e1, irs);
4260 
4261             result = toElemCast(ce, e, false);
4262         }
4263 
4264         elem *toElemCast(CastExp ce, elem *e, bool isLvalue)
4265         {
4266             tym_t ftym;
4267             tym_t ttym;
4268             OPER eop;
4269 
4270             Type tfrom = ce.e1.type.toBasetype();
4271             Type t = ce.to.toBasetype();         // skip over typedef's
4272 
4273             TY fty;
4274             TY tty;
4275             if (t.equals(tfrom) ||
4276                 t.equals(Type.tvoid)) // https://issues.dlang.org/show_bug.cgi?id=18573
4277                                       // Remember to pop value left on FPU stack
4278                 return e;
4279 
4280             fty = tfrom.ty;
4281             tty = t.ty;
4282             //printf("fty = %d\n", fty);
4283 
4284             static elem* Lret(CastExp ce, elem* e)
4285             {
4286                 // Adjust for any type paints
4287                 Type t = ce.type.toBasetype();
4288                 e.Ety = totym(t);
4289                 if (tyaggregate(e.Ety))
4290                     e.ET = Type_toCtype(t);
4291 
4292                 elem_setLoc(e, ce.loc);
4293                 return e;
4294             }
4295 
4296             static elem* Lpaint(CastExp ce, elem* e, tym_t ttym)
4297             {
4298                 e.Ety = ttym;
4299                 return Lret(ce, e);
4300             }
4301 
4302             static elem* Lzero(CastExp ce, elem* e, tym_t ttym)
4303             {
4304                 e = el_bin(OPcomma, ttym, e, el_long(ttym, 0));
4305                 return Lret(ce, e);
4306             }
4307 
4308             static elem* Leop(CastExp ce, elem* e, OPER eop, tym_t ttym)
4309             {
4310                 e = el_una(eop, ttym, e);
4311                 return Lret(ce, e);
4312             }
4313 
4314             if (tty == Tpointer && fty == Tarray)
4315             {
4316                 if (e.Eoper == OPvar)
4317                 {
4318                     // e1 . *(&e1 + 4)
4319                     e = el_una(OPaddr, TYnptr, e);
4320                     e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, tysize(TYnptr)));
4321                     e = el_una(OPind,totym(t),e);
4322                 }
4323                 else
4324                 {
4325                     // e1 . (uint)(e1 >> 32)
4326                     if (irs.params.is64bit)
4327                     {
4328                         e = el_bin(OPshr, TYucent, e, el_long(TYint, 64));
4329                         e = el_una(OP128_64, totym(t), e);
4330                     }
4331                     else
4332                     {
4333                         e = el_bin(OPshr, TYullong, e, el_long(TYint, 32));
4334                         e = el_una(OP64_32, totym(t), e);
4335                     }
4336                 }
4337                 return Lret(ce, e);
4338             }
4339 
4340             if (tty == Tpointer && fty == Tsarray)
4341             {
4342                 // e1 . &e1
4343                 e = el_una(OPaddr, TYnptr, e);
4344                 return Lret(ce, e);
4345             }
4346 
4347             // Convert from static array to dynamic array
4348             if (tty == Tarray && fty == Tsarray)
4349             {
4350                 e = sarray_toDarray(ce.loc, tfrom, t, e);
4351                 return Lret(ce, e);
4352             }
4353 
4354             // Convert from dynamic array to dynamic array
4355             if (tty == Tarray && fty == Tarray)
4356             {
4357                 uint fsize = cast(uint)tfrom.nextOf().size();
4358                 uint tsize = cast(uint)t.nextOf().size();
4359 
4360                 if (fsize != tsize)
4361                 {   // Array element sizes do not match, so we must adjust the dimensions
4362                     if (tsize != 0 && fsize % tsize == 0)
4363                     {
4364                         // Set array dimension to (length * (fsize / tsize))
4365                         // Generate pair(e.length * (fsize/tsize), es.ptr)
4366 
4367                         elem *es = el_same(&e);
4368 
4369                         elem *eptr = el_una(OPmsw, TYnptr, es);
4370                         elem *elen = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, e);
4371                         elem *elen2 = el_bin(OPmul, TYsize_t, elen, el_long(TYsize_t, fsize / tsize));
4372                         e = el_pair(totym(ce.type), elen2, eptr);
4373                     }
4374                     else
4375                     {
4376                         assert(false, "This case should have been rewritten to `__ArrayCast` in the semantic phase");
4377                     }
4378                 }
4379                 return Lret(ce, e);
4380             }
4381 
4382             // Casting between class/interface may require a runtime check
4383             if (fty == Tclass && tty == Tclass)
4384             {
4385                 ClassDeclaration cdfrom = tfrom.isClassHandle();
4386                 ClassDeclaration cdto   = t.isClassHandle();
4387 
4388                 int offset;
4389                 if (cdto.isBaseOf(cdfrom, &offset) && offset != ClassDeclaration.OFFSET_RUNTIME)
4390                 {
4391                     /* The offset from cdfrom => cdto is known at compile time.
4392                      * Cases:
4393                      *  - class => base class (upcast)
4394                      *  - class => base interface (upcast)
4395                      */
4396 
4397                     //printf("offset = %d\n", offset);
4398                     if (offset == ClassDeclaration.OFFSET_FWDREF)
4399                     {
4400                         assert(0, "unexpected forward reference");
4401                     }
4402                     else if (offset)
4403                     {
4404                         /* Rewrite cast as (e ? e + offset : null)
4405                          */
4406                         if (ce.e1.op == TOK.this_)
4407                         {
4408                             // Assume 'this' is never null, so skip null check
4409                             e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, offset));
4410                         }
4411                         else
4412                         {
4413                             elem *etmp = el_same(&e);
4414                             elem *ex = el_bin(OPadd, TYnptr, etmp, el_long(TYsize_t, offset));
4415                             ex = el_bin(OPcolon, TYnptr, ex, el_long(TYnptr, 0));
4416                             e = el_bin(OPcond, TYnptr, e, ex);
4417                         }
4418                     }
4419                     else
4420                     {
4421                         // Casting from derived class to base class is a no-op
4422                     }
4423                 }
4424                 else if (cdfrom.classKind == ClassKind.cpp)
4425                 {
4426                     if (cdto.classKind == ClassKind.cpp)
4427                     {
4428                         /* Casting from a C++ interface to a C++ interface
4429                          * is always a 'paint' operation
4430                          */
4431                         return Lret(ce, e);                  // no-op
4432                     }
4433 
4434                     /* Casting from a C++ interface to a class
4435                      * always results in null because there is no runtime
4436                      * information available to do it.
4437                      *
4438                      * Casting from a C++ interface to a non-C++ interface
4439                      * always results in null because there's no way one
4440                      * can be derived from the other.
4441                      */
4442                     e = el_bin(OPcomma, TYnptr, e, el_long(TYnptr, 0));
4443                     return Lret(ce, e);
4444                 }
4445                 else
4446                 {
4447                     /* The offset from cdfrom => cdto can only be determined at runtime.
4448                      * Cases:
4449                      *  - class     => derived class (downcast)
4450                      *  - interface => derived class (downcast)
4451                      *  - class     => foreign interface (cross cast)
4452                      *  - interface => base or foreign interface (cross cast)
4453                      */
4454                     int rtl = cdfrom.isInterfaceDeclaration()
4455                                 ? RTLSYM_INTERFACE_CAST
4456                                 : RTLSYM_DYNAMIC_CAST;
4457                     elem *ep = el_param(el_ptr(toSymbol(cdto)), e);
4458                     e = el_bin(OPcall, TYnptr, el_var(getRtlsym(rtl)), ep);
4459                 }
4460                 return Lret(ce, e);
4461             }
4462 
4463             if (fty == Tvector && tty == Tsarray)
4464             {
4465                 if (tfrom.size() == t.size())
4466                 {
4467                     if (e.Eoper != OPvar && e.Eoper != OPind)
4468                     {
4469                         // can't perform array ops on it unless it's in memory
4470                         e = addressElem(e, tfrom);
4471                         e = el_una(OPind, TYarray, e);
4472                         e.ET = Type_toCtype(t);
4473                     }
4474                     return Lret(ce, e);
4475                 }
4476             }
4477 
4478             ftym = tybasic(e.Ety);
4479             ttym = tybasic(totym(t));
4480             if (ftym == ttym)
4481                 return Lret(ce, e);
4482 
4483             /* Reduce combinatorial explosion by rewriting the 'to' and 'from' types to a
4484              * generic equivalent (as far as casting goes)
4485              */
4486             switch (tty)
4487             {
4488                 case Tpointer:
4489                     if (fty == Tdelegate)
4490                         return Lpaint(ce, e, ttym);
4491                     tty = irs.params.is64bit ? Tuns64 : Tuns32;
4492                     break;
4493 
4494                 case Tchar:     tty = Tuns8;    break;
4495                 case Twchar:    tty = Tuns16;   break;
4496                 case Tdchar:    tty = Tuns32;   break;
4497                 case Tvoid:     return Lpaint(ce, e, ttym);
4498 
4499                 case Tbool:
4500                 {
4501                     // Construct e?true:false
4502                     e = el_una(OPbool, ttym, e);
4503                     return Lret(ce, e);
4504                 }
4505 
4506                 default:
4507                     break;
4508             }
4509 
4510             switch (fty)
4511             {
4512                 case Tnull:
4513                 {
4514                     // typeof(null) is same with void* in binary level.
4515                     return Lzero(ce, e, ttym);
4516                 }
4517                 case Tpointer:  fty = irs.params.is64bit ? Tuns64 : Tuns32;  break;
4518                 case Tchar:     fty = Tuns8;    break;
4519                 case Twchar:    fty = Tuns16;   break;
4520                 case Tdchar:    fty = Tuns32;   break;
4521 
4522                 default:
4523                     break;
4524             }
4525 
4526             static int X(int fty, int tty) { return fty * TMAX + tty; }
4527 
4528             while (true)
4529             {
4530                 switch (X(fty,tty))
4531                 {
4532                     /* ============================= */
4533 
4534                     case X(Tbool,Tint8):
4535                     case X(Tbool,Tuns8):
4536                         return Lpaint(ce, e, ttym);
4537                     case X(Tbool,Tint16):
4538                     case X(Tbool,Tuns16):
4539                     case X(Tbool,Tint32):
4540                     case X(Tbool,Tuns32):
4541                         if (isLvalue)
4542                         {
4543                             eop = OPu8_16;
4544                             return Leop(ce, e, eop, ttym);
4545                         }
4546                         else
4547                         {
4548                             e = el_bin(OPand, TYuchar, e, el_long(TYuchar, 1));
4549                             fty = Tuns8;
4550                             continue;
4551                         }
4552 
4553                     case X(Tbool,Tint64):
4554                     case X(Tbool,Tuns64):
4555                     case X(Tbool,Tfloat32):
4556                     case X(Tbool,Tfloat64):
4557                     case X(Tbool,Tfloat80):
4558                     case X(Tbool,Tcomplex32):
4559                     case X(Tbool,Tcomplex64):
4560                     case X(Tbool,Tcomplex80):
4561                         e = el_bin(OPand, TYuchar, e, el_long(TYuchar, 1));
4562                         fty = Tuns8;
4563                         continue;
4564 
4565                     case X(Tbool,Timaginary32):
4566                     case X(Tbool,Timaginary64):
4567                     case X(Tbool,Timaginary80):
4568                         return Lzero(ce, e, ttym);
4569 
4570                         /* ============================= */
4571 
4572                     case X(Tint8,Tuns8):    return Lpaint(ce, e, ttym);
4573                     case X(Tint8,Tint16):
4574                     case X(Tint8,Tuns16):
4575                     case X(Tint8,Tint32):
4576                     case X(Tint8,Tuns32):   eop = OPs8_16;  return Leop(ce, e, eop, ttym);
4577                     case X(Tint8,Tint64):
4578                     case X(Tint8,Tuns64):
4579                     case X(Tint8,Tfloat32):
4580                     case X(Tint8,Tfloat64):
4581                     case X(Tint8,Tfloat80):
4582                     case X(Tint8,Tcomplex32):
4583                     case X(Tint8,Tcomplex64):
4584                     case X(Tint8,Tcomplex80):
4585                         e = el_una(OPs8_16, TYint, e);
4586                         fty = Tint32;
4587                         continue;
4588                     case X(Tint8,Timaginary32):
4589                     case X(Tint8,Timaginary64):
4590                     case X(Tint8,Timaginary80): return Lzero(ce, e, ttym);
4591 
4592                         /* ============================= */
4593 
4594                     case X(Tuns8,Tint8):    return Lpaint(ce, e, ttym);
4595                     case X(Tuns8,Tint16):
4596                     case X(Tuns8,Tuns16):
4597                     case X(Tuns8,Tint32):
4598                     case X(Tuns8,Tuns32):   eop = OPu8_16;  return Leop(ce, e, eop, ttym);
4599                     case X(Tuns8,Tint64):
4600                     case X(Tuns8,Tuns64):
4601                     case X(Tuns8,Tfloat32):
4602                     case X(Tuns8,Tfloat64):
4603                     case X(Tuns8,Tfloat80):
4604                     case X(Tuns8,Tcomplex32):
4605                     case X(Tuns8,Tcomplex64):
4606                     case X(Tuns8,Tcomplex80):
4607                         e = el_una(OPu8_16, TYuint, e);
4608                         fty = Tuns32;
4609                         continue;
4610                     case X(Tuns8,Timaginary32):
4611                     case X(Tuns8,Timaginary64):
4612                     case X(Tuns8,Timaginary80): return Lzero(ce, e, ttym);
4613 
4614                         /* ============================= */
4615 
4616                     case X(Tint16,Tint8):
4617                     case X(Tint16,Tuns8):   eop = OP16_8;   return Leop(ce, e, eop, ttym);
4618                     case X(Tint16,Tuns16):  return Lpaint(ce, e, ttym);
4619                     case X(Tint16,Tint32):
4620                     case X(Tint16,Tuns32):  eop = OPs16_32; return Leop(ce, e, eop, ttym);
4621                     case X(Tint16,Tint64):
4622                     case X(Tint16,Tuns64):  e = el_una(OPs16_32, TYint, e);
4623                         fty = Tint32;
4624                         continue;
4625                     case X(Tint16,Tfloat32):
4626                     case X(Tint16,Tfloat64):
4627                     case X(Tint16,Tfloat80):
4628                     case X(Tint16,Tcomplex32):
4629                     case X(Tint16,Tcomplex64):
4630                     case X(Tint16,Tcomplex80):
4631                         e = el_una(OPs16_d, TYdouble, e);
4632                         fty = Tfloat64;
4633                         continue;
4634                     case X(Tint16,Timaginary32):
4635                     case X(Tint16,Timaginary64):
4636                     case X(Tint16,Timaginary80): return Lzero(ce, e, ttym);
4637 
4638                         /* ============================= */
4639 
4640                     case X(Tuns16,Tint8):
4641                     case X(Tuns16,Tuns8):   eop = OP16_8;   return Leop(ce, e, eop, ttym);
4642                     case X(Tuns16,Tint16):  return Lpaint(ce, e, ttym);
4643                     case X(Tuns16,Tint32):
4644                     case X(Tuns16,Tuns32):  eop = OPu16_32; return Leop(ce, e, eop, ttym);
4645                     case X(Tuns16,Tint64):
4646                     case X(Tuns16,Tuns64):
4647                     case X(Tuns16,Tfloat64):
4648                     case X(Tuns16,Tfloat32):
4649                     case X(Tuns16,Tfloat80):
4650                     case X(Tuns16,Tcomplex32):
4651                     case X(Tuns16,Tcomplex64):
4652                     case X(Tuns16,Tcomplex80):
4653                         e = el_una(OPu16_32, TYuint, e);
4654                         fty = Tuns32;
4655                         continue;
4656                     case X(Tuns16,Timaginary32):
4657                     case X(Tuns16,Timaginary64):
4658                     case X(Tuns16,Timaginary80): return Lzero(ce, e, ttym);
4659 
4660                         /* ============================= */
4661 
4662                     case X(Tint32,Tint8):
4663                     case X(Tint32,Tuns8):   e = el_una(OP32_16, TYshort, e);
4664                         fty = Tint16;
4665                         continue;
4666                     case X(Tint32,Tint16):
4667                     case X(Tint32,Tuns16):  eop = OP32_16;  return Leop(ce, e, eop, ttym);
4668                     case X(Tint32,Tuns32):  return Lpaint(ce, e, ttym);
4669                     case X(Tint32,Tint64):
4670                     case X(Tint32,Tuns64):  eop = OPs32_64; return Leop(ce, e, eop, ttym);
4671                     case X(Tint32,Tfloat32):
4672                     case X(Tint32,Tfloat64):
4673                     case X(Tint32,Tfloat80):
4674                     case X(Tint32,Tcomplex32):
4675                     case X(Tint32,Tcomplex64):
4676                     case X(Tint32,Tcomplex80):
4677                         e = el_una(OPs32_d, TYdouble, e);
4678                         fty = Tfloat64;
4679                         continue;
4680                     case X(Tint32,Timaginary32):
4681                     case X(Tint32,Timaginary64):
4682                     case X(Tint32,Timaginary80): return Lzero(ce, e, ttym);
4683 
4684                         /* ============================= */
4685 
4686                     case X(Tuns32,Tint8):
4687                     case X(Tuns32,Tuns8):   e = el_una(OP32_16, TYshort, e);
4688                         fty = Tuns16;
4689                         continue;
4690                     case X(Tuns32,Tint16):
4691                     case X(Tuns32,Tuns16):  eop = OP32_16;  return Leop(ce, e, eop, ttym);
4692                     case X(Tuns32,Tint32):  return Lpaint(ce, e, ttym);
4693                     case X(Tuns32,Tint64):
4694                     case X(Tuns32,Tuns64):  eop = OPu32_64; return Leop(ce, e, eop, ttym);
4695                     case X(Tuns32,Tfloat32):
4696                     case X(Tuns32,Tfloat64):
4697                     case X(Tuns32,Tfloat80):
4698                     case X(Tuns32,Tcomplex32):
4699                     case X(Tuns32,Tcomplex64):
4700                     case X(Tuns32,Tcomplex80):
4701                         e = el_una(OPu32_d, TYdouble, e);
4702                         fty = Tfloat64;
4703                         continue;
4704                     case X(Tuns32,Timaginary32):
4705                     case X(Tuns32,Timaginary64):
4706                     case X(Tuns32,Timaginary80): return Lzero(ce, e, ttym);
4707 
4708                         /* ============================= */
4709 
4710                     case X(Tint64,Tint8):
4711                     case X(Tint64,Tuns8):
4712                     case X(Tint64,Tint16):
4713                     case X(Tint64,Tuns16):  e = el_una(OP64_32, TYint, e);
4714                         fty = Tint32;
4715                         continue;
4716                     case X(Tint64,Tint32):
4717                     case X(Tint64,Tuns32):  eop = OP64_32; return Leop(ce, e, eop, ttym);
4718                     case X(Tint64,Tuns64):  return Lpaint(ce, e, ttym);
4719                     case X(Tint64,Tfloat32):
4720                     case X(Tint64,Tfloat64):
4721                     case X(Tint64,Tfloat80):
4722                     case X(Tint64,Tcomplex32):
4723                     case X(Tint64,Tcomplex64):
4724                     case X(Tint64,Tcomplex80):
4725                         e = el_una(OPs64_d, TYdouble, e);
4726                         fty = Tfloat64;
4727                         continue;
4728                     case X(Tint64,Timaginary32):
4729                     case X(Tint64,Timaginary64):
4730                     case X(Tint64,Timaginary80): return Lzero(ce, e, ttym);
4731 
4732                         /* ============================= */
4733 
4734                     case X(Tuns64,Tint8):
4735                     case X(Tuns64,Tuns8):
4736                     case X(Tuns64,Tint16):
4737                     case X(Tuns64,Tuns16):  e = el_una(OP64_32, TYint, e);
4738                         fty = Tint32;
4739                         continue;
4740                     case X(Tuns64,Tint32):
4741                     case X(Tuns64,Tuns32):  eop = OP64_32;  return Leop(ce, e, eop, ttym);
4742                     case X(Tuns64,Tint64):  return Lpaint(ce, e, ttym);
4743                     case X(Tuns64,Tfloat32):
4744                     case X(Tuns64,Tfloat64):
4745                     case X(Tuns64,Tfloat80):
4746                     case X(Tuns64,Tcomplex32):
4747                     case X(Tuns64,Tcomplex64):
4748                     case X(Tuns64,Tcomplex80):
4749                         e = el_una(OPu64_d, TYdouble, e);
4750                         fty = Tfloat64;
4751                         continue;
4752                     case X(Tuns64,Timaginary32):
4753                     case X(Tuns64,Timaginary64):
4754                     case X(Tuns64,Timaginary80): return Lzero(ce, e, ttym);
4755 
4756                         /* ============================= */
4757 
4758                     case X(Tfloat32,Tint8):
4759                     case X(Tfloat32,Tuns8):
4760                     case X(Tfloat32,Tint16):
4761                     case X(Tfloat32,Tuns16):
4762                     case X(Tfloat32,Tint32):
4763                     case X(Tfloat32,Tuns32):
4764                     case X(Tfloat32,Tint64):
4765                     case X(Tfloat32,Tuns64):
4766                     case X(Tfloat32,Tfloat80): e = el_una(OPf_d, TYdouble, e);
4767                         fty = Tfloat64;
4768                         continue;
4769                     case X(Tfloat32,Tfloat64): eop = OPf_d; return Leop(ce, e, eop, ttym);
4770                     case X(Tfloat32,Timaginary32):
4771                     case X(Tfloat32,Timaginary64):
4772                     case X(Tfloat32,Timaginary80): return Lzero(ce, e, ttym);
4773                     case X(Tfloat32,Tcomplex32):
4774                     case X(Tfloat32,Tcomplex64):
4775                     case X(Tfloat32,Tcomplex80):
4776                         e = el_bin(OPadd,TYcfloat,el_long(TYifloat,0),e);
4777                         fty = Tcomplex32;
4778                         continue;
4779 
4780                         /* ============================= */
4781 
4782                     case X(Tfloat64,Tint8):
4783                     case X(Tfloat64,Tuns8):    e = el_una(OPd_s16, TYshort, e);
4784                         fty = Tint16;
4785                         continue;
4786                     case X(Tfloat64,Tint16):   eop = OPd_s16; return Leop(ce, e, eop, ttym);
4787                     case X(Tfloat64,Tuns16):   eop = OPd_u16; return Leop(ce, e, eop, ttym);
4788                     case X(Tfloat64,Tint32):   eop = OPd_s32; return Leop(ce, e, eop, ttym);
4789                     case X(Tfloat64,Tuns32):   eop = OPd_u32; return Leop(ce, e, eop, ttym);
4790                     case X(Tfloat64,Tint64):   eop = OPd_s64; return Leop(ce, e, eop, ttym);
4791                     case X(Tfloat64,Tuns64):   eop = OPd_u64; return Leop(ce, e, eop, ttym);
4792                     case X(Tfloat64,Tfloat32): eop = OPd_f;   return Leop(ce, e, eop, ttym);
4793                     case X(Tfloat64,Tfloat80): eop = OPd_ld;  return Leop(ce, e, eop, ttym);
4794                     case X(Tfloat64,Timaginary32):
4795                     case X(Tfloat64,Timaginary64):
4796                     case X(Tfloat64,Timaginary80):  return Lzero(ce, e, ttym);
4797                     case X(Tfloat64,Tcomplex32):
4798                     case X(Tfloat64,Tcomplex64):
4799                     case X(Tfloat64,Tcomplex80):
4800                         e = el_bin(OPadd,TYcdouble,el_long(TYidouble,0),e);
4801                         fty = Tcomplex64;
4802                         continue;
4803 
4804                         /* ============================= */
4805 
4806                     case X(Tfloat80,Tint8):
4807                     case X(Tfloat80,Tuns8):
4808                     case X(Tfloat80,Tint16):
4809                     case X(Tfloat80,Tuns16):
4810                     case X(Tfloat80,Tint32):
4811                     case X(Tfloat80,Tuns32):
4812                     case X(Tfloat80,Tint64):
4813                     case X(Tfloat80,Tfloat32): e = el_una(OPld_d, TYdouble, e);
4814                         fty = Tfloat64;
4815                         continue;
4816                     case X(Tfloat80,Tuns64):
4817                         eop = OPld_u64; return Leop(ce, e, eop, ttym);
4818                     case X(Tfloat80,Tfloat64): eop = OPld_d; return Leop(ce, e, eop, ttym);
4819                     case X(Tfloat80,Timaginary32):
4820                     case X(Tfloat80,Timaginary64):
4821                     case X(Tfloat80,Timaginary80): return Lzero(ce, e, ttym);
4822                     case X(Tfloat80,Tcomplex32):
4823                     case X(Tfloat80,Tcomplex64):
4824                     case X(Tfloat80,Tcomplex80):
4825                         e = el_bin(OPadd,TYcldouble,e,el_long(TYildouble,0));
4826                         fty = Tcomplex80;
4827                         continue;
4828 
4829                         /* ============================= */
4830 
4831                     case X(Timaginary32,Tint8):
4832                     case X(Timaginary32,Tuns8):
4833                     case X(Timaginary32,Tint16):
4834                     case X(Timaginary32,Tuns16):
4835                     case X(Timaginary32,Tint32):
4836                     case X(Timaginary32,Tuns32):
4837                     case X(Timaginary32,Tint64):
4838                     case X(Timaginary32,Tuns64):
4839                     case X(Timaginary32,Tfloat32):
4840                     case X(Timaginary32,Tfloat64):
4841                     case X(Timaginary32,Tfloat80):  return Lzero(ce, e, ttym);
4842                     case X(Timaginary32,Timaginary64): eop = OPf_d; return Leop(ce, e, eop, ttym);
4843                     case X(Timaginary32,Timaginary80):
4844                         e = el_una(OPf_d, TYidouble, e);
4845                         fty = Timaginary64;
4846                         continue;
4847                     case X(Timaginary32,Tcomplex32):
4848                     case X(Timaginary32,Tcomplex64):
4849                     case X(Timaginary32,Tcomplex80):
4850                         e = el_bin(OPadd,TYcfloat,el_long(TYfloat,0),e);
4851                         fty = Tcomplex32;
4852                         continue;
4853 
4854                         /* ============================= */
4855 
4856                     case X(Timaginary64,Tint8):
4857                     case X(Timaginary64,Tuns8):
4858                     case X(Timaginary64,Tint16):
4859                     case X(Timaginary64,Tuns16):
4860                     case X(Timaginary64,Tint32):
4861                     case X(Timaginary64,Tuns32):
4862                     case X(Timaginary64,Tint64):
4863                     case X(Timaginary64,Tuns64):
4864                     case X(Timaginary64,Tfloat32):
4865                     case X(Timaginary64,Tfloat64):
4866                     case X(Timaginary64,Tfloat80):  return Lzero(ce, e, ttym);
4867                     case X(Timaginary64,Timaginary32): eop = OPd_f;   return Leop(ce, e, eop, ttym);
4868                     case X(Timaginary64,Timaginary80): eop = OPd_ld;  return Leop(ce, e, eop, ttym);
4869                     case X(Timaginary64,Tcomplex32):
4870                     case X(Timaginary64,Tcomplex64):
4871                     case X(Timaginary64,Tcomplex80):
4872                         e = el_bin(OPadd,TYcdouble,el_long(TYdouble,0),e);
4873                         fty = Tcomplex64;
4874                         continue;
4875 
4876                         /* ============================= */
4877 
4878                     case X(Timaginary80,Tint8):
4879                     case X(Timaginary80,Tuns8):
4880                     case X(Timaginary80,Tint16):
4881                     case X(Timaginary80,Tuns16):
4882                     case X(Timaginary80,Tint32):
4883                     case X(Timaginary80,Tuns32):
4884                     case X(Timaginary80,Tint64):
4885                     case X(Timaginary80,Tuns64):
4886                     case X(Timaginary80,Tfloat32):
4887                     case X(Timaginary80,Tfloat64):
4888                     case X(Timaginary80,Tfloat80):  return Lzero(ce, e, ttym);
4889                     case X(Timaginary80,Timaginary32): e = el_una(OPld_d, TYidouble, e);
4890                         fty = Timaginary64;
4891                         continue;
4892                     case X(Timaginary80,Timaginary64): eop = OPld_d; return Leop(ce, e, eop, ttym);
4893                     case X(Timaginary80,Tcomplex32):
4894                     case X(Timaginary80,Tcomplex64):
4895                     case X(Timaginary80,Tcomplex80):
4896                         e = el_bin(OPadd,TYcldouble,el_long(TYldouble,0),e);
4897                         fty = Tcomplex80;
4898                         continue;
4899 
4900                         /* ============================= */
4901 
4902                     case X(Tcomplex32,Tint8):
4903                     case X(Tcomplex32,Tuns8):
4904                     case X(Tcomplex32,Tint16):
4905                     case X(Tcomplex32,Tuns16):
4906                     case X(Tcomplex32,Tint32):
4907                     case X(Tcomplex32,Tuns32):
4908                     case X(Tcomplex32,Tint64):
4909                     case X(Tcomplex32,Tuns64):
4910                     case X(Tcomplex32,Tfloat32):
4911                     case X(Tcomplex32,Tfloat64):
4912                     case X(Tcomplex32,Tfloat80):
4913                         e = el_una(OPc_r, TYfloat, e);
4914                         fty = Tfloat32;
4915                         continue;
4916                     case X(Tcomplex32,Timaginary32):
4917                     case X(Tcomplex32,Timaginary64):
4918                     case X(Tcomplex32,Timaginary80):
4919                         e = el_una(OPc_i, TYifloat, e);
4920                         fty = Timaginary32;
4921                         continue;
4922                     case X(Tcomplex32,Tcomplex64):
4923                     case X(Tcomplex32,Tcomplex80):
4924                         e = el_una(OPf_d, TYcdouble, e);
4925                         fty = Tcomplex64;
4926                         continue;
4927 
4928                         /* ============================= */
4929 
4930                     case X(Tcomplex64,Tint8):
4931                     case X(Tcomplex64,Tuns8):
4932                     case X(Tcomplex64,Tint16):
4933                     case X(Tcomplex64,Tuns16):
4934                     case X(Tcomplex64,Tint32):
4935                     case X(Tcomplex64,Tuns32):
4936                     case X(Tcomplex64,Tint64):
4937                     case X(Tcomplex64,Tuns64):
4938                     case X(Tcomplex64,Tfloat32):
4939                     case X(Tcomplex64,Tfloat64):
4940                     case X(Tcomplex64,Tfloat80):
4941                         e = el_una(OPc_r, TYdouble, e);
4942                         fty = Tfloat64;
4943                         continue;
4944                     case X(Tcomplex64,Timaginary32):
4945                     case X(Tcomplex64,Timaginary64):
4946                     case X(Tcomplex64,Timaginary80):
4947                         e = el_una(OPc_i, TYidouble, e);
4948                         fty = Timaginary64;
4949                         continue;
4950                     case X(Tcomplex64,Tcomplex32):   eop = OPd_f;   return Leop(ce, e, eop, ttym);
4951                     case X(Tcomplex64,Tcomplex80):   eop = OPd_ld;  return Leop(ce, e, eop, ttym);
4952 
4953                         /* ============================= */
4954 
4955                     case X(Tcomplex80,Tint8):
4956                     case X(Tcomplex80,Tuns8):
4957                     case X(Tcomplex80,Tint16):
4958                     case X(Tcomplex80,Tuns16):
4959                     case X(Tcomplex80,Tint32):
4960                     case X(Tcomplex80,Tuns32):
4961                     case X(Tcomplex80,Tint64):
4962                     case X(Tcomplex80,Tuns64):
4963                     case X(Tcomplex80,Tfloat32):
4964                     case X(Tcomplex80,Tfloat64):
4965                     case X(Tcomplex80,Tfloat80):
4966                         e = el_una(OPc_r, TYldouble, e);
4967                         fty = Tfloat80;
4968                         continue;
4969                     case X(Tcomplex80,Timaginary32):
4970                     case X(Tcomplex80,Timaginary64):
4971                     case X(Tcomplex80,Timaginary80):
4972                         e = el_una(OPc_i, TYildouble, e);
4973                         fty = Timaginary80;
4974                         continue;
4975                     case X(Tcomplex80,Tcomplex32):
4976                     case X(Tcomplex80,Tcomplex64):
4977                         e = el_una(OPld_d, TYcdouble, e);
4978                         fty = Tcomplex64;
4979                         continue;
4980 
4981                         /* ============================= */
4982 
4983                     default:
4984                         if (fty == tty)
4985                             return Lpaint(ce, e, ttym);
4986                         //dump(0);
4987                         //printf("fty = %d, tty = %d, %d\n", fty, tty, t.ty);
4988                         // This error should really be pushed to the front end
4989                         ce.error("e2ir: cannot cast `%s` of type `%s` to type `%s`", ce.e1.toChars(), ce.e1.type.toChars(), t.toChars());
4990                         e = el_long(TYint, 0);
4991                         return e;
4992 
4993                 }
4994             }
4995         }
4996 
4997         override void visit(ArrayLengthExp ale)
4998         {
4999             elem *e = toElem(ale.e1, irs);
5000             e = el_una(irs.params.is64bit ? OP128_64 : OP64_32, totym(ale.type), e);
5001             elem_setLoc(e, ale.loc);
5002             result = e;
5003         }
5004 
5005         override void visit(DelegatePtrExp dpe)
5006         {
5007             // *cast(void**)(&dg)
5008             elem *e = toElem(dpe.e1, irs);
5009             Type tb1 = dpe.e1.type.toBasetype();
5010             e = addressElem(e, tb1);
5011             e = el_una(OPind, totym(dpe.type), e);
5012             elem_setLoc(e, dpe.loc);
5013             result = e;
5014         }
5015 
5016         override void visit(DelegateFuncptrExp dfpe)
5017         {
5018             // *cast(void**)(&dg + size_t.sizeof)
5019             elem *e = toElem(dfpe.e1, irs);
5020             Type tb1 = dfpe.e1.type.toBasetype();
5021             e = addressElem(e, tb1);
5022             e = el_bin(OPadd, TYnptr, e, el_long(TYsize_t, irs.params.is64bit ? 8 : 4));
5023             e = el_una(OPind, totym(dfpe.type), e);
5024             elem_setLoc(e, dfpe.loc);
5025             result = e;
5026         }
5027 
5028         override void visit(SliceExp se)
5029         {
5030             //printf("SliceExp.toElem() se = %s %s\n", se.type.toChars(), se.toChars());
5031             Type tb = se.type.toBasetype();
5032             assert(tb.ty == Tarray || tb.ty == Tsarray);
5033             Type t1 = se.e1.type.toBasetype();
5034             elem *e = toElem(se.e1, irs);
5035             if (se.lwr)
5036             {
5037                 uint sz = cast(uint)t1.nextOf().size();
5038 
5039                 elem *einit = resolveLengthVar(se.lengthVar, &e, t1);
5040                 if (t1.ty == Tsarray)
5041                     e = array_toPtr(se.e1.type, e);
5042                 if (!einit)
5043                 {
5044                     einit = e;
5045                     e = el_same(&einit);
5046                 }
5047                 // e is a temporary, typed:
5048                 //  TYdarray if t.ty == Tarray
5049                 //  TYptr if t.ty == Tsarray or Tpointer
5050 
5051                 elem *elwr = toElem(se.lwr, irs);
5052                 elem *eupr = toElem(se.upr, irs);
5053                 elem *elwr2 = el_sideeffect(eupr) ? el_copytotmp(&elwr) : el_same(&elwr);
5054                 elem *eupr2 = eupr;
5055 
5056                 //printf("upperIsInBounds = %d lowerIsLessThanUpper = %d\n", se.upperIsInBounds, se.lowerIsLessThanUpper);
5057                 if (irs.arrayBoundsCheck())
5058                 {
5059                     // Checks (unsigned compares):
5060                     //  upr <= array.length
5061                     //  lwr <= upr
5062 
5063                     elem *c1 = null;
5064                     elem *elen;
5065                     if (!se.upperIsInBounds)
5066                     {
5067                         eupr2 = el_same(&eupr);
5068                         eupr2.Ety = TYsize_t;  // make sure unsigned comparison
5069 
5070                         if (auto tsa = t1.isTypeSArray())
5071                         {
5072                             elen = el_long(TYsize_t, tsa.dim.toInteger());
5073                         }
5074                         else if (t1.ty == Tarray)
5075                         {
5076                             if (se.lengthVar && !(se.lengthVar.storage_class & STC.const_))
5077                                 elen = el_var(toSymbol(se.lengthVar));
5078                             else
5079                             {
5080                                 elen = e;
5081                                 e = el_same(&elen);
5082                                 elen = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, elen);
5083                             }
5084                         }
5085 
5086                         c1 = el_bin(OPle, TYint, eupr, elen);
5087 
5088                         if (!se.lowerIsLessThanUpper)
5089                         {
5090                             c1 = el_bin(OPandand, TYint,
5091                                 c1, el_bin(OPle, TYint, elwr2, eupr2));
5092                             elwr2 = el_copytree(elwr2);
5093                             eupr2 = el_copytree(eupr2);
5094                         }
5095                     }
5096                     else if (!se.lowerIsLessThanUpper)
5097                     {
5098                         eupr2 = el_same(&eupr);
5099                         eupr2.Ety = TYsize_t;  // make sure unsigned comparison
5100 
5101                         c1 = el_bin(OPle, TYint, elwr2, eupr);
5102                         elwr2 = el_copytree(elwr2);
5103                     }
5104 
5105                     if (c1)
5106                     {
5107                         // Construct: (c1 || arrayBoundsError)
5108                         auto ea = buildArrayBoundsError(irs, se.loc, el_copytree(elwr2), el_copytree(eupr2), el_copytree(elen));
5109                         elem *eb = el_bin(OPoror, TYvoid, c1, ea);
5110 
5111                         elwr = el_combine(elwr, eb);
5112                     }
5113                 }
5114                 if (t1.ty != Tsarray)
5115                     e = array_toPtr(se.e1.type, e);
5116 
5117                 // Create an array reference where:
5118                 // length is (upr - lwr)
5119                 // pointer is (ptr + lwr*sz)
5120                 // Combine as (length pair ptr)
5121 
5122                 elem *eofs = el_bin(OPmul, TYsize_t, elwr2, el_long(TYsize_t, sz));
5123                 elem *eptr = el_bin(OPadd, TYnptr, e, eofs);
5124 
5125                 if (tb.ty == Tarray)
5126                 {
5127                     elem *elen = el_bin(OPmin, TYsize_t, eupr2, el_copytree(elwr2));
5128                     e = el_pair(TYdarray, elen, eptr);
5129                 }
5130                 else
5131                 {
5132                     assert(tb.ty == Tsarray);
5133                     e = el_una(OPind, totym(se.type), eptr);
5134                     if (tybasic(e.Ety) == TYstruct)
5135                         e.ET = Type_toCtype(se.type);
5136                 }
5137                 e = el_combine(elwr, e);
5138                 e = el_combine(einit, e);
5139                 //elem_print(e);
5140             }
5141             else if (t1.ty == Tsarray && tb.ty == Tarray)
5142             {
5143                 e = sarray_toDarray(se.loc, t1, null, e);
5144             }
5145             else
5146             {
5147                 assert(t1.ty == tb.ty);   // Tarray or Tsarray
5148 
5149                 // https://issues.dlang.org/show_bug.cgi?id=14672
5150                 // If se is in left side operand of element-wise
5151                 // assignment, the element type can be painted to the base class.
5152                 int offset;
5153                 assert(t1.nextOf().equivalent(tb.nextOf()) ||
5154                        tb.nextOf().isBaseOf(t1.nextOf(), &offset) && offset == 0);
5155             }
5156             elem_setLoc(e, se.loc);
5157             result = e;
5158         }
5159 
5160         override void visit(IndexExp ie)
5161         {
5162             elem *e;
5163             elem *n1 = toElem(ie.e1, irs);
5164             elem *eb = null;
5165 
5166             //printf("IndexExp.toElem() %s\n", ie.toChars());
5167             Type t1 = ie.e1.type.toBasetype();
5168             if (auto taa = t1.isTypeAArray())
5169             {
5170                 // set to:
5171                 //      *aaGetY(aa, aati, valuesize, &key);
5172                 // or
5173                 //      *aaGetRvalueX(aa, keyti, valuesize, &key);
5174 
5175                 uint vsize = cast(uint)taa.next.size();
5176 
5177                 // n2 becomes the index, also known as the key
5178                 elem *n2 = toElem(ie.e2, irs);
5179 
5180                 /* Turn n2 into a pointer to the index.  If it's an lvalue,
5181                  * take the address of it. If not, copy it to a temp and
5182                  * take the address of that.
5183                  */
5184                 n2 = addressElem(n2, taa.index);
5185 
5186                 elem *valuesize = el_long(TYsize_t, vsize);
5187                 //printf("valuesize: "); elem_print(valuesize);
5188                 Symbol *s;
5189                 elem *ti;
5190                 if (ie.modifiable)
5191                 {
5192                     n1 = el_una(OPaddr, TYnptr, n1);
5193                     s = aaGetSymbol(taa, "GetY", 1);
5194                     ti = getTypeInfo(ie.e1.loc, taa.unSharedOf().mutableOf(), irs);
5195                 }
5196                 else
5197                 {
5198                     s = aaGetSymbol(taa, "GetRvalueX", 1);
5199                     ti = getTypeInfo(ie.e1.loc, taa.index, irs);
5200                 }
5201                 //printf("taa.index = %s\n", taa.index.toChars());
5202                 //printf("ti:\n"); elem_print(ti);
5203                 elem *ep = el_params(n2, valuesize, ti, n1, null);
5204                 e = el_bin(OPcall, TYnptr, el_var(s), ep);
5205                 if (irs.arrayBoundsCheck())
5206                 {
5207                     elem *n = el_same(&e);
5208 
5209                     // Construct: ((e || arrayBoundsError), n)
5210                     auto ea = buildArrayBoundsError(irs, ie.loc, null, null, null); // FIXME
5211                     e = el_bin(OPoror,TYvoid,e,ea);
5212                     e = el_bin(OPcomma, TYnptr, e, n);
5213                 }
5214                 e = el_una(OPind, totym(ie.type), e);
5215                 if (tybasic(e.Ety) == TYstruct)
5216                     e.ET = Type_toCtype(ie.type);
5217             }
5218             else
5219             {
5220                 elem *einit = resolveLengthVar(ie.lengthVar, &n1, t1);
5221                 elem *n2 = toElem(ie.e2, irs);
5222 
5223                 if (irs.arrayBoundsCheck() && !ie.indexIsInBounds)
5224                 {
5225                     elem *elength;
5226 
5227                     if (auto tsa = t1.isTypeSArray())
5228                     {
5229                         const length = tsa.dim.toInteger();
5230 
5231                         elength = el_long(TYsize_t, length);
5232                         goto L1;
5233                     }
5234                     else if (t1.ty == Tarray)
5235                     {
5236                         elength = n1;
5237                         n1 = el_same(&elength);
5238                         elength = el_una(irs.params.is64bit ? OP128_64 : OP64_32, TYsize_t, elength);
5239                     L1:
5240                         elem *n2x = n2;
5241                         n2 = el_same(&n2x);
5242                         n2x = el_bin(OPlt, TYint, n2x, elength);
5243 
5244                         // Construct: (n2x || arrayBoundsError)
5245                         auto ea = buildArrayBoundsError(irs, ie.loc, null, el_copytree(n2), el_copytree(elength));
5246                         eb = el_bin(OPoror,TYvoid,n2x,ea);
5247                     }
5248                 }
5249 
5250                 n1 = array_toPtr(t1, n1);
5251 
5252                 {
5253                     elem *escale = el_long(TYsize_t, t1.nextOf().size());
5254                     n2 = el_bin(OPmul, TYsize_t, n2, escale);
5255                     e = el_bin(OPadd, TYnptr, n1, n2);
5256                     e = el_una(OPind, totym(ie.type), e);
5257                     if (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray)
5258                     {
5259                         e.Ety = TYstruct;
5260                         e.ET = Type_toCtype(ie.type);
5261                     }
5262                 }
5263 
5264                 eb = el_combine(einit, eb);
5265                 e = el_combine(eb, e);
5266             }
5267             elem_setLoc(e, ie.loc);
5268             result = e;
5269         }
5270 
5271 
5272         override void visit(TupleExp te)
5273         {
5274             //printf("TupleExp.toElem() %s\n", te.toChars());
5275             elem *e = null;
5276             if (te.e0)
5277                 e = toElem(te.e0, irs);
5278             foreach (el; *te.exps)
5279             {
5280                 elem *ep = toElem(el, irs);
5281                 e = el_combine(e, ep);
5282             }
5283             result = e;
5284         }
5285 
5286         static elem *tree_insert(Elems *args, size_t low, size_t high)
5287         {
5288             assert(low < high);
5289             if (low + 1 == high)
5290                 return (*args)[low];
5291             int mid = cast(int)((low + high) >> 1);
5292             return el_param(tree_insert(args, low, mid),
5293                             tree_insert(args, mid, high));
5294         }
5295 
5296         override void visit(ArrayLiteralExp ale)
5297         {
5298             size_t dim = ale.elements ? ale.elements.dim : 0;
5299 
5300             //printf("ArrayLiteralExp.toElem() %s, type = %s\n", ale.toChars(), ale.type.toChars());
5301             Type tb = ale.type.toBasetype();
5302             if (tb.ty == Tsarray && tb.nextOf().toBasetype().ty == Tvoid)
5303             {
5304                 // Convert void[n] to ubyte[n]
5305                 tb = Type.tuns8.sarrayOf((cast(TypeSArray)tb).dim.toUInteger());
5306             }
5307 
5308             elem *e;
5309             if (tb.ty == Tsarray && dim)
5310             {
5311                 Symbol *stmp = null;
5312                 e = ExpressionsToStaticArray(ale.loc, ale.elements, &stmp, 0, ale.basis);
5313                 e = el_combine(e, el_ptr(stmp));
5314             }
5315             else if (ale.elements)
5316             {
5317                 /* Instead of passing the initializers on the stack, allocate the
5318                  * array and assign the members inline.
5319                  * Avoids the whole variadic arg mess.
5320                  */
5321 
5322                 // call _d_arrayliteralTX(ti, dim)
5323                 e = el_bin(OPcall, TYnptr,
5324                     el_var(getRtlsym(RTLSYM_ARRAYLITERALTX)),
5325                     el_param(el_long(TYsize_t, dim), getTypeInfo(ale.loc, ale.type, irs)));
5326                 toTraceGC(irs, e, ale.loc);
5327 
5328                 Symbol *stmp = symbol_genauto(Type_toCtype(Type.tvoid.pointerTo()));
5329                 e = el_bin(OPeq, TYnptr, el_var(stmp), e);
5330 
5331                 /* Note: Even if dm == 0, the druntime function will be called so
5332                  * GC heap may be allocated. However, currently it's implemented
5333                  * to return null for 0 length.
5334                  */
5335                 if (dim)
5336                     e = el_combine(e, ExpressionsToStaticArray(ale.loc, ale.elements, &stmp, 0, ale.basis));
5337 
5338                 e = el_combine(e, el_var(stmp));
5339             }
5340             else
5341             {
5342                 e = el_long(TYsize_t, 0);
5343             }
5344 
5345             if (tb.ty == Tarray)
5346             {
5347                 e = el_pair(TYdarray, el_long(TYsize_t, dim), e);
5348             }
5349             else if (tb.ty == Tpointer)
5350             {
5351             }
5352             else
5353             {
5354                 e = el_una(OPind, TYstruct, e);
5355                 e.ET = Type_toCtype(ale.type);
5356             }
5357 
5358             elem_setLoc(e, ale.loc);
5359             result = e;
5360         }
5361 
5362         /**************************************
5363          * Mirrors logic in Dsymbol_canThrow().
5364          */
5365         elem *Dsymbol_toElem(Dsymbol s)
5366         {
5367             elem *e = null;
5368 
5369             void symbolDg(Dsymbol s)
5370             {
5371                 e = el_combine(e, Dsymbol_toElem(s));
5372             }
5373 
5374             //printf("Dsymbol_toElem() %s\n", s.toChars());
5375             if (auto vd = s.isVarDeclaration())
5376             {
5377                 s = s.toAlias();
5378                 if (s != vd)
5379                     return Dsymbol_toElem(s);
5380                 if (vd.storage_class & STC.manifest)
5381                     return null;
5382                 else if (vd.isStatic() || vd.storage_class & (STC.extern_ | STC.tls | STC.gshared))
5383                     toObjFile(vd, false);
5384                 else
5385                 {
5386                     Symbol *sp = toSymbol(s);
5387                     symbol_add(sp);
5388                     //printf("\tadding symbol '%s'\n", sp.Sident);
5389                     if (vd._init)
5390                     {
5391                         if (auto ie = vd._init.isExpInitializer())
5392                             e = toElem(ie.exp, irs);
5393                     }
5394 
5395                     /* Mark the point of construction of a variable that needs to be destructed.
5396                      */
5397                     if (vd.needsScopeDtor())
5398                     {
5399                         elem *edtor = toElem(vd.edtor, irs);
5400                         elem *ed = null;
5401                         if (irs.isNothrow())
5402                         {
5403                             ed = edtor;
5404                         }
5405                         else
5406                         {
5407                             // Construct special elems to deal with exceptions
5408                             e = el_ctor_dtor(e, edtor, &ed);
5409                         }
5410 
5411                         // ed needs to be inserted into the code later
5412                         irs.varsInScope.push(ed);
5413                     }
5414                 }
5415             }
5416             else if (auto cd = s.isClassDeclaration())
5417             {
5418                 irs.deferToObj.push(s);
5419             }
5420             else if (auto sd = s.isStructDeclaration())
5421             {
5422                 irs.deferToObj.push(sd);
5423             }
5424             else if (auto fd = s.isFuncDeclaration())
5425             {
5426                 //printf("function %s\n", fd.toChars());
5427                 irs.deferToObj.push(fd);
5428             }
5429             else if (auto ad = s.isAttribDeclaration())
5430             {
5431                 ad.include(null).foreachDsymbol(&symbolDg);
5432             }
5433             else if (auto tm = s.isTemplateMixin())
5434             {
5435                 //printf("%s\n", tm.toChars());
5436                 tm.members.foreachDsymbol(&symbolDg);
5437             }
5438             else if (auto td = s.isTupleDeclaration())
5439             {
5440                 foreach (o; *td.objects)
5441                 {
5442                     if (o.dyncast() == DYNCAST.expression)
5443                     {   Expression eo = cast(Expression)o;
5444                         if (eo.op == TOK.dSymbol)
5445                         {   DsymbolExp se = cast(DsymbolExp)eo;
5446                             e = el_combine(e, Dsymbol_toElem(se.s));
5447                         }
5448                     }
5449                 }
5450             }
5451             else if (auto ed = s.isEnumDeclaration())
5452             {
5453                 irs.deferToObj.push(ed);
5454             }
5455             else if (auto ti = s.isTemplateInstance())
5456             {
5457                 irs.deferToObj.push(ti);
5458             }
5459             return e;
5460         }
5461 
5462         /*************************************************
5463          * Allocate a static array, and initialize its members with elems[].
5464          * Return the initialization expression, and the symbol for the static array in *psym.
5465          */
5466         elem *ElemsToStaticArray(const ref Loc loc, Type telem, Elems *elems, Symbol **psym)
5467         {
5468             // Create a static array of type telem[dim]
5469             const dim = elems.dim;
5470             assert(dim);
5471 
5472             Type tsarray = telem.sarrayOf(dim);
5473             const szelem = telem.size();
5474             .type *te = Type_toCtype(telem);   // stmp[] element type
5475 
5476             Symbol *stmp = symbol_genauto(Type_toCtype(tsarray));
5477             *psym = stmp;
5478 
5479             elem *e = null;
5480             foreach (i, ep; *elems)
5481             {
5482                 /* Generate: *(&stmp + i * szelem) = element[i]
5483                  */
5484                 elem *ev = el_ptr(stmp);
5485                 ev = el_bin(OPadd, TYnptr, ev, el_long(TYsize_t, i * szelem));
5486                 ev = el_una(OPind, te.Tty, ev);
5487                 elem *eeq = elAssign(ev, ep, null, te);
5488                 e = el_combine(e, eeq);
5489             }
5490             return e;
5491         }
5492 
5493         /*************************************************
5494          * Allocate a static array, and initialize its members with
5495          * exps[].
5496          * Return the initialization expression, and the symbol for the static array in *psym.
5497          */
5498         elem *ExpressionsToStaticArray(const ref Loc loc, Expressions *exps, Symbol **psym, size_t offset = 0, Expression basis = null)
5499         {
5500             // Create a static array of type telem[dim]
5501             const dim = exps.dim;
5502             assert(dim);
5503 
5504             Type telem = ((*exps)[0] ? (*exps)[0] : basis).type;
5505             const szelem = telem.size();
5506             .type *te = Type_toCtype(telem);   // stmp[] element type
5507 
5508             if (!*psym)
5509             {
5510                 Type tsarray2 = telem.sarrayOf(dim);
5511                 *psym = symbol_genauto(Type_toCtype(tsarray2));
5512                 offset = 0;
5513             }
5514             Symbol *stmp = *psym;
5515 
5516             elem *e = null;
5517             for (size_t i = 0; i < dim; )
5518             {
5519                 Expression el = (*exps)[i];
5520                 if (!el)
5521                     el = basis;
5522                 if (el.op == TOK.arrayLiteral &&
5523                     el.type.toBasetype().ty == Tsarray)
5524                 {
5525                     ArrayLiteralExp ale = cast(ArrayLiteralExp)el;
5526                     if (ale.elements && ale.elements.dim)
5527                     {
5528                         elem *ex = ExpressionsToStaticArray(
5529                             ale.loc, ale.elements, &stmp, cast(uint)(offset + i * szelem), ale.basis);
5530                         e = el_combine(e, ex);
5531                     }
5532                     i++;
5533                     continue;
5534                 }
5535 
5536                 size_t j = i + 1;
5537                 if (el.isConst() || el.op == TOK.null_)
5538                 {
5539                     // If the trivial elements are same values, do memcpy.
5540                     while (j < dim)
5541                     {
5542                         Expression en = (*exps)[j];
5543                         if (!en)
5544                             en = basis;
5545                         if (!el.equals(en))
5546                             break;
5547                         j++;
5548                     }
5549                 }
5550 
5551                 /* Generate: *(&stmp + i * szelem) = element[i]
5552                  */
5553                 elem *ep = toElem(el, irs);
5554                 elem *ev = tybasic(stmp.Stype.Tty) == TYnptr ? el_var(stmp) : el_ptr(stmp);
5555                 ev = el_bin(OPadd, TYnptr, ev, el_long(TYsize_t, offset + i * szelem));
5556 
5557                 elem *eeq;
5558                 if (j == i + 1)
5559                 {
5560                     ev = el_una(OPind, te.Tty, ev);
5561                     eeq = elAssign(ev, ep, null, te);
5562                 }
5563                 else
5564                 {
5565                     elem *edim = el_long(TYsize_t, j - i);
5566                     eeq = setArray(el, ev, edim, telem, ep, irs, TOK.blit);
5567                 }
5568                 e = el_combine(e, eeq);
5569                 i = j;
5570             }
5571             return e;
5572         }
5573 
5574         override void visit(AssocArrayLiteralExp aale)
5575         {
5576             //printf("AssocArrayLiteralExp.toElem() %s\n", aale.toChars());
5577 
5578             Type t = aale.type.toBasetype().mutableOf();
5579 
5580             size_t dim = aale.keys.dim;
5581             if (dim)
5582             {
5583                 // call _d_assocarrayliteralTX(TypeInfo_AssociativeArray ti, void[] keys, void[] values)
5584                 // Prefer this to avoid the varargs fiasco in 64 bit code
5585 
5586                 assert(t.ty == Taarray);
5587                 Type ta = t;
5588 
5589                 Symbol *skeys = null;
5590                 elem *ekeys = ExpressionsToStaticArray(aale.loc, aale.keys, &skeys);
5591 
5592                 Symbol *svalues = null;
5593                 elem *evalues = ExpressionsToStaticArray(aale.loc, aale.values, &svalues);
5594 
5595                 elem *ev = el_pair(TYdarray, el_long(TYsize_t, dim), el_ptr(svalues));
5596                 elem *ek = el_pair(TYdarray, el_long(TYsize_t, dim), el_ptr(skeys  ));
5597                 if (config.exe == EX_WIN64)
5598                 {
5599                     ev = addressElem(ev, Type.tvoid.arrayOf());
5600                     ek = addressElem(ek, Type.tvoid.arrayOf());
5601                 }
5602                 elem *e = el_params(ev, ek,
5603                                     getTypeInfo(aale.loc, ta, irs),
5604                                     null);
5605 
5606                 // call _d_assocarrayliteralTX(ti, keys, values)
5607                 e = el_bin(OPcall,TYnptr,el_var(getRtlsym(RTLSYM_ASSOCARRAYLITERALTX)),e);
5608                 toTraceGC(irs, e, aale.loc);
5609                 if (t != ta)
5610                     e = addressElem(e, ta);
5611                 elem_setLoc(e, aale.loc);
5612 
5613                 e = el_combine(evalues, e);
5614                 e = el_combine(ekeys, e);
5615                 result = e;
5616                 return;
5617             }
5618             else
5619             {
5620                 elem *e = el_long(TYnptr, 0);      // empty associative array is the null pointer
5621                 if (t.ty != Taarray)
5622                     e = addressElem(e, Type.tvoidptr);
5623                 result = e;
5624                 return;
5625             }
5626         }
5627 
5628         override void visit(StructLiteralExp sle)
5629         {
5630             //printf("[%s] StructLiteralExp.toElem() %s\n", sle.loc.toChars(), sle.toChars());
5631             result = toElemStructLit(sle, irs, TOK.construct, sle.sym, true);
5632         }
5633 
5634         override void visit(ObjcClassReferenceExp e)
5635         {
5636             result = objc.toElem(e);
5637         }
5638 
5639         /*****************************************************/
5640         /*                   CTFE stuff                      */
5641         /*****************************************************/
5642 
5643         override void visit(ClassReferenceExp e)
5644         {
5645             //printf("ClassReferenceExp.toElem() %p, value=%p, %s\n", e, e.value, e.toChars());
5646             result = el_ptr(toSymbol(e));
5647         }
5648     }
5649 
5650     scope v = new ToElemVisitor(irs);
5651     e.accept(v);
5652     return v.result;
5653 }
5654 
5655 /*******************************************
5656  * Generate elem to zero fill contents of Symbol stmp
5657  * from *poffset..offset2.
5658  * May store anywhere from 0..maxoff, as this function
5659  * tries to use aligned int stores whereever possible.
5660  * Update *poffset to end of initialized hole; *poffset will be >= offset2.
5661  */
5662 private elem *fillHole(Symbol *stmp, size_t *poffset, size_t offset2, size_t maxoff)
5663 {
5664     elem *e = null;
5665     bool basealign = true;
5666 
5667     while (*poffset < offset2)
5668     {
5669         elem *e1;
5670         if (tybasic(stmp.Stype.Tty) == TYnptr)
5671             e1 = el_var(stmp);
5672         else
5673             e1 = el_ptr(stmp);
5674         if (basealign)
5675             *poffset &= ~3;
5676         basealign = true;
5677         size_t sz = maxoff - *poffset;
5678         tym_t ty;
5679         switch (sz)
5680         {
5681             case 1: ty = TYchar;        break;
5682             case 2: ty = TYshort;       break;
5683             case 3:
5684                 ty = TYshort;
5685                 basealign = false;
5686                 break;
5687             default:
5688                 ty = TYlong;
5689                 // TODO: OPmemset is better if sz is much bigger than 4?
5690                 break;
5691         }
5692         e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, *poffset));
5693         e1 = el_una(OPind, ty, e1);
5694         e1 = el_bin(OPeq, ty, e1, el_long(ty, 0));
5695         e = el_combine(e, e1);
5696         *poffset += tysize(ty);
5697     }
5698     return e;
5699 }
5700 
5701 /*************************************************
5702  * Params:
5703  *      op = TOK.assign, TOK.construct, TOK.blit
5704  *      fillHoles = Fill in alignment holes with zero. Set to
5705  *                  false if allocated by operator new, as the holes are already zeroed.
5706  */
5707 
5708 private elem *toElemStructLit(StructLiteralExp sle, IRState *irs, TOK op, Symbol *sym, bool fillHoles)
5709 {
5710     //printf("[%s] StructLiteralExp.toElem() %s\n", sle.loc.toChars(), sle.toChars());
5711     //printf("\tblit = %s, sym = %p fillHoles = %d\n", op == TOK.blit, sym, fillHoles);
5712 
5713     if (sle.useStaticInit)
5714     {
5715         /* Use the struct declaration's init symbol
5716          */
5717         elem *e = el_var(toInitializer(sle.sd));
5718         e.ET = Type_toCtype(sle.sd.type);
5719         elem_setLoc(e, sle.loc);
5720 
5721         if (sym)
5722         {
5723             elem *ev = el_var(sym);
5724             if (tybasic(ev.Ety) == TYnptr)
5725                 ev = el_una(OPind, e.Ety, ev);
5726             ev.ET = e.ET;
5727             e = elAssign(ev, e, null, ev.ET);
5728 
5729             //ev = el_var(sym);
5730             //ev.ET = e.ET;
5731             //e = el_combine(e, ev);
5732             elem_setLoc(e, sle.loc);
5733         }
5734         return e;
5735     }
5736 
5737     // struct symbol to initialize with the literal
5738     Symbol *stmp = sym ? sym : symbol_genauto(Type_toCtype(sle.sd.type));
5739 
5740     elem *e = null;
5741 
5742     /* If a field has explicit initializer (*sle.elements)[i] != null),
5743      * any other overlapped fields won't have initializer. It's asserted by
5744      * StructDeclaration.fill() function.
5745      *
5746      *  union U { int x; long y; }
5747      *  U u1 = U(1);        // elements = [`1`, null]
5748      *  U u2 = {y:2};       // elements = [null, `2`];
5749      *  U u3 = U(1, 2);     // error
5750      *  U u4 = {x:1, y:2};  // error
5751      */
5752     size_t dim = sle.elements ? sle.elements.dim : 0;
5753     assert(dim <= sle.sd.fields.dim);
5754 
5755     if (fillHoles)
5756     {
5757         /* Initialize all alignment 'holes' to zero.
5758          * Do before initializing fields, as the hole filling process
5759          * can spill over into the fields.
5760          */
5761         const size_t structsize = sle.sd.structsize;
5762         size_t offset = 0;
5763         //printf("-- %s - fillHoles, structsize = %d\n", sle.toChars(), structsize);
5764         for (size_t i = 0; i < sle.sd.fields.dim && offset < structsize; )
5765         {
5766             VarDeclaration v = sle.sd.fields[i];
5767 
5768             /* If the field v has explicit initializer, [offset .. v.offset]
5769              * is a hole divided by the initializer.
5770              * However if the field size is zero (e.g. int[0] v;), we can merge
5771              * the two holes in the front and the back of the field v.
5772              */
5773             if (i < dim && (*sle.elements)[i] && v.type.size())
5774             {
5775                 //if (offset != v.offset) printf("  1 fillHole, %d .. %d\n", offset, v.offset);
5776                 e = el_combine(e, fillHole(stmp, &offset, v.offset, structsize));
5777                 offset = cast(uint)(v.offset + v.type.size());
5778                 i++;
5779                 continue;
5780             }
5781             if (!v.overlapped)
5782             {
5783                 i++;
5784                 continue;
5785             }
5786 
5787             /* AggregateDeclaration.fields holds the fields by the lexical order.
5788              * This code will minimize each hole sizes. For example:
5789              *
5790              *  struct S {
5791              *    union { uint f1; ushort f2; }   // f1: 0..4,  f2: 0..2
5792              *    union { uint f3; ulong f4; }    // f3: 8..12, f4: 8..16
5793              *  }
5794              *  S s = {f2:x, f3:y};     // filled holes: 2..8 and 12..16
5795              */
5796             size_t vend = sle.sd.fields.dim;
5797             size_t holeEnd = structsize;
5798             size_t offset2 = structsize;
5799             foreach (j; i + 1 .. vend)
5800             {
5801                 VarDeclaration vx = sle.sd.fields[j];
5802                 if (!vx.overlapped)
5803                 {
5804                     vend = j;
5805                     break;
5806                 }
5807                 if (j < dim && (*sle.elements)[j] && vx.type.size())
5808                 {
5809                     // Find the lowest end offset of the hole.
5810                     if (offset <= vx.offset && vx.offset < holeEnd)
5811                     {
5812                         holeEnd = vx.offset;
5813                         offset2 = cast(uint)(vx.offset + vx.type.size());
5814                     }
5815                 }
5816             }
5817             if (holeEnd < structsize)
5818             {
5819                 //if (offset != holeEnd) printf("  2 fillHole, %d .. %d\n", offset, holeEnd);
5820                 e = el_combine(e, fillHole(stmp, &offset, holeEnd, structsize));
5821                 offset = offset2;
5822                 continue;
5823             }
5824             i = vend;
5825         }
5826         //if (offset != sle.sd.structsize) printf("  3 fillHole, %d .. %d\n", offset, sle.sd.structsize);
5827         e = el_combine(e, fillHole(stmp, &offset, sle.sd.structsize, sle.sd.structsize));
5828     }
5829 
5830     // CTFE may fill the hidden pointer by NullExp.
5831     {
5832         foreach (i, el; *sle.elements)
5833         {
5834             if (!el)
5835                 continue;
5836 
5837             VarDeclaration v = sle.sd.fields[i];
5838             assert(!v.isThisDeclaration() || el.op == TOK.null_);
5839 
5840             elem *e1;
5841             if (tybasic(stmp.Stype.Tty) == TYnptr)
5842             {
5843                 e1 = el_var(stmp);
5844             }
5845             else
5846             {
5847                 e1 = el_ptr(stmp);
5848             }
5849             e1 = el_bin(OPadd, TYnptr, e1, el_long(TYsize_t, v.offset));
5850 
5851             elem *ep = toElem(el, irs);
5852 
5853             Type t1b = v.type.toBasetype();
5854             Type t2b = el.type.toBasetype();
5855             if (t1b.ty == Tsarray)
5856             {
5857                 if (t2b.implicitConvTo(t1b))
5858                 {
5859                     elem *esize = el_long(TYsize_t, t1b.size());
5860                     ep = array_toPtr(el.type, ep);
5861                     e1 = el_bin(OPmemcpy, TYnptr, e1, el_param(ep, esize));
5862                 }
5863                 else
5864                 {
5865                     elem *edim = el_long(TYsize_t, t1b.size() / t2b.size());
5866                     e1 = setArray(el, e1, edim, t2b, ep, irs, op == TOK.construct ? TOK.blit : op);
5867                 }
5868             }
5869             else
5870             {
5871                 tym_t ty = totym(v.type);
5872                 e1 = el_una(OPind, ty, e1);
5873                 if (tybasic(ty) == TYstruct)
5874                     e1.ET = Type_toCtype(v.type);
5875                 e1 = elAssign(e1, ep, v.type, e1.ET);
5876             }
5877             e = el_combine(e, e1);
5878         }
5879     }
5880 
5881     if (sle.sd.isNested() && dim != sle.sd.fields.dim)
5882     {
5883         // Initialize the hidden 'this' pointer
5884         assert(sle.sd.fields.dim);
5885 
5886         elem* e1, e2;
5887         if (tybasic(stmp.Stype.Tty) == TYnptr)
5888         {
5889             e1 = el_var(stmp);
5890         }
5891         else
5892         {
5893             e1 = el_ptr(stmp);
5894         }
5895         if (sle.sd.vthis2)
5896         {
5897             /* Initialize sd.vthis2:
5898              *  *(e2 + sd.vthis2.offset) = this1;
5899              */
5900             e2 = el_copytree(e1);
5901             e2 = setEthis(sle.loc, irs, e2, sle.sd, true);
5902         }
5903         /* Initialize sd.vthis:
5904          *  *(e1 + sd.vthis.offset) = this;
5905          */
5906         e1 = setEthis(sle.loc, irs, e1, sle.sd);
5907 
5908         e = el_combine(e, e1);
5909         e = el_combine(e, e2);
5910     }
5911 
5912     elem *ev = el_var(stmp);
5913     ev.ET = Type_toCtype(sle.sd.type);
5914     e = el_combine(e, ev);
5915     elem_setLoc(e, sle.loc);
5916     return e;
5917 }
5918 
5919 /********************************************
5920  * Append destructors for varsInScope[starti..endi] to er.
5921  * Params:
5922  *      irs = context
5923  *      er = elem to append destructors to
5924  *      starti = starting index in varsInScope[]
5925  *      endi = ending index in varsInScope[]
5926  * Returns:
5927  *      er with destructors appended
5928  */
5929 
5930 private elem *appendDtors(IRState *irs, elem *er, size_t starti, size_t endi)
5931 {
5932     //printf("appendDtors(%d .. %d)\n", starti, endi);
5933 
5934     /* Code gen can be improved by determining if no exceptions can be thrown
5935      * between the OPdctor and OPddtor, and eliminating the OPdctor and OPddtor.
5936      */
5937 
5938     /* Build edtors, an expression that calls destructors on all the variables
5939      * going out of the scope starti..endi
5940      */
5941     elem *edtors = null;
5942     foreach (i; starti .. endi)
5943     {
5944         elem *ed = (*irs.varsInScope)[i];
5945         if (ed)                                 // if not skipped
5946         {
5947             //printf("appending dtor\n");
5948             (*irs.varsInScope)[i] = null;       // so these are skipped by outer scopes
5949             edtors = el_combine(ed, edtors);    // execute in reverse order
5950         }
5951     }
5952 
5953     if (edtors)
5954     {
5955         if (irs.params.isWindows && !irs.params.is64bit) // Win32
5956         {
5957             Blockx *blx = irs.blx;
5958             nteh_declarvars(blx);
5959         }
5960 
5961         /* Append edtors to er, while preserving the value of er
5962          */
5963         if (tybasic(er.Ety) == TYvoid)
5964         {
5965             /* No value to preserve, so simply append
5966              */
5967             er = el_combine(er, edtors);
5968         }
5969         else
5970         {
5971             elem **pe;
5972             for (pe = &er; (*pe).Eoper == OPcomma; pe = &(*pe).EV.E2)
5973             {
5974             }
5975             elem *erx = *pe;
5976 
5977             if (erx.Eoper == OPconst || erx.Eoper == OPrelconst)
5978             {
5979                 *pe = el_combine(edtors, erx);
5980             }
5981             else if (elemIsLvalue(erx))
5982             {
5983                 /* Lvalue, take a pointer to it
5984                  */
5985                 elem *ep = el_una(OPaddr, TYnptr, erx);
5986                 elem *e = el_same(&ep);
5987                 ep = el_combine(ep, edtors);
5988                 ep = el_combine(ep, e);
5989                 e = el_una(OPind, erx.Ety, ep);
5990                 e.ET = erx.ET;
5991                 *pe = e;
5992             }
5993             else
5994             {
5995                 elem *e = el_same(&erx);
5996                 erx = el_combine(erx, edtors);
5997                 *pe = el_combine(erx, e);
5998             }
5999         }
6000     }
6001     return er;
6002 }
6003 
6004 
6005 /*******************************************
6006  * Convert Expression to elem, then append destructors for any
6007  * temporaries created in elem.
6008  * Params:
6009  *      e = Expression to convert
6010  *      irs = context
6011  * Returns:
6012  *      generated elem tree
6013  */
6014 
6015 elem *toElemDtor(Expression e, IRState *irs)
6016 {
6017     //printf("Expression.toElemDtor() %s\n", e.toChars());
6018 
6019     /* "may" throw may actually be false if we look at a subset of
6020      * the function. Here, the subset is `e`. If that subset is nothrow,
6021      * we can generate much better code for the destructors for that subset,
6022      * even if the rest of the function throws.
6023      * If mayThrow is false, it cannot be true for some subset of the function,
6024      * so no need to check.
6025      * If calling canThrow() here turns out to be too expensive,
6026      * it can be enabled only for optimized builds.
6027      */
6028     const mayThrowSave = irs.mayThrow;
6029     if (irs.mayThrow && !canThrow(e, irs.getFunc(), false))
6030         irs.mayThrow = false;
6031 
6032     const starti = irs.varsInScope.dim;
6033     elem* er = toElem(e, irs);
6034     const endi = irs.varsInScope.dim;
6035 
6036     irs.mayThrow = mayThrowSave;
6037 
6038     // Add destructors
6039     elem* ex = appendDtors(irs, er, starti, endi);
6040     return ex;
6041 }
6042 
6043 
6044 /*******************************************************
6045  * Write read-only string to object file, create a local symbol for it.
6046  * Makes a copy of str's contents, does not keep a reference to it.
6047  * Params:
6048  *      str = string
6049  *      len = number of code units in string
6050  *      sz = number of bytes per code unit
6051  * Returns:
6052  *      Symbol
6053  */
6054 
6055 Symbol *toStringSymbol(const(char)* str, size_t len, size_t sz)
6056 {
6057     //printf("toStringSymbol() %p\n", stringTab);
6058     auto sv = stringTab.update(str, len * sz);
6059     if (!sv.value)
6060     {
6061         Symbol* si;
6062 
6063         if (global.params.isWindows)
6064         {
6065             /* This should be in the back end, but mangleToBuffer() is
6066              * in the front end.
6067              */
6068             /* The stringTab pools common strings within an object file.
6069              * Win32 and Win64 use COMDATs to pool common strings across object files.
6070              */
6071             import dmd.root.outbuffer : OutBuffer;
6072             import dmd.dmangle;
6073 
6074             scope StringExp se = new StringExp(Loc.initial, str[0 .. len], len, cast(ubyte)sz, 'c');
6075 
6076             /* VC++ uses a name mangling scheme, for example, "hello" is mangled to:
6077              * ??_C@_05CJBACGMB@hello?$AA@
6078              *        ^ length
6079              *         ^^^^^^^^ 8 byte checksum
6080              * But the checksum algorithm is unknown. Just invent our own.
6081              */
6082             OutBuffer buf;
6083             buf.writestring("__");
6084             mangleToBuffer(se, &buf);   // recycle how strings are mangled for templates
6085 
6086             if (buf.length >= 32 + 2)
6087             {   // Replace long string with hash of that string
6088                 import dmd.backend.md5;
6089                 MD5_CTX mdContext = void;
6090                 MD5Init(&mdContext);
6091                 MD5Update(&mdContext, cast(ubyte*)buf.peekChars(), cast(uint)buf.length);
6092                 MD5Final(&mdContext);
6093                 buf.setsize(2);
6094                 foreach (u; mdContext.digest)
6095                 {
6096                     ubyte u1 = u >> 4;
6097                     buf.writeByte((u1 < 10) ? u1 + '0' : u1 + 'A' - 10);
6098                     u1 = u & 0xF;
6099                     buf.writeByte((u1 < 10) ? u1 + '0' : u1 + 'A' - 10);
6100                 }
6101             }
6102 
6103             si = symbol_calloc(buf.peekChars(), cast(uint)buf.length);
6104             si.Sclass = SCcomdat;
6105             si.Stype = type_static_array(cast(uint)(len * sz), tstypes[TYchar]);
6106             si.Stype.Tcount++;
6107             type_setmangle(&si.Stype, mTYman_c);
6108             si.Sflags |= SFLnodebug | SFLartifical;
6109             si.Sfl = FLdata;
6110             si.Salignment = cast(ubyte)sz;
6111             out_readonly_comdat(si, str, cast(uint)(len * sz), cast(uint)sz);
6112         }
6113         else
6114         {
6115             si = out_string_literal(str, cast(uint)len, cast(uint)sz);
6116         }
6117 
6118         sv.value = si;
6119     }
6120     return sv.value;
6121 }
6122 
6123 /*******************************************************
6124  * Turn StringExp into Symbol.
6125  */
6126 
6127 Symbol *toStringSymbol(StringExp se)
6128 {
6129     Symbol *si;
6130     const n = cast(int)se.numberOfCodeUnits();
6131     if (se.sz == 1)
6132     {
6133         const slice = se.peekString();
6134         si = toStringSymbol(slice.ptr, slice.length, 1);
6135     }
6136     else
6137     {
6138         auto p = cast(char *)mem.xmalloc(n * se.sz);
6139         se.writeTo(p, false);
6140         si = toStringSymbol(p, n, se.sz);
6141         mem.xfree(p);
6142     }
6143     return si;
6144 }
6145 
6146 /******************************************************
6147  * Return an elem that is the file, line, and function suitable
6148  * for insertion into the parameter list.
6149  */
6150 
6151 private elem *filelinefunction(IRState *irs, const ref Loc loc)
6152 {
6153     const(char)* id = loc.filename;
6154     size_t len = strlen(id);
6155     Symbol *si = toStringSymbol(id, len, 1);
6156     elem *efilename = el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(si));
6157     if (config.exe == EX_WIN64)
6158         efilename = addressElem(efilename, Type.tstring, true);
6159 
6160     elem *elinnum = el_long(TYint, loc.linnum);
6161 
6162     const(char)* s = "";
6163     FuncDeclaration fd = irs.getFunc();
6164     if (fd)
6165     {
6166         s = fd.toPrettyChars();
6167     }
6168 
6169     len = strlen(s);
6170     si = toStringSymbol(s, len, 1);
6171     elem *efunction = el_pair(TYdarray, el_long(TYsize_t, len), el_ptr(si));
6172     if (config.exe == EX_WIN64)
6173         efunction = addressElem(efunction, Type.tstring, true);
6174 
6175     return el_params(efunction, elinnum, efilename, null);
6176 }
6177 
6178 /******************************************************
6179  * Construct elem to run when an array bounds check fails.
6180  * Params:
6181  *      irs = to get function from
6182  *      loc = to get file/line from
6183  *      lwr = lower bound passed, if slice (array[lwr .. upr]). null otherwise.
6184  *      upr = upper bound passed if slice (array[lwr .. upr]), index if not a slice (array[upr])
6185  *      elength = length of array
6186  * Returns:
6187  *      elem generated
6188  */
6189 elem *buildArrayBoundsError(IRState *irs, const ref Loc loc, elem* lwr, elem* upr, elem* elength)
6190 {
6191     if (irs.params.checkAction == CHECKACTION.C)
6192     {
6193         return callCAssert(irs, loc, null, null, "array overflow");
6194     }
6195     if (irs.params.checkAction == CHECKACTION.halt)
6196     {
6197         return genHalt(loc);
6198     }
6199     auto eassert = el_var(getRtlsym(RTLSYM_DARRAYP));
6200     auto efile = toEfilenamePtr(cast(Module)irs.blx._module);
6201     auto eline = el_long(TYint, loc.linnum);
6202     if(upr is null)
6203     {
6204         upr = el_long(TYsize_t, 0);
6205     }
6206     if(lwr is null)
6207     {
6208         lwr = el_long(TYsize_t, 0);
6209     }
6210     if(elength is null)
6211     {
6212         elength = el_long(TYsize_t, 0);
6213     }
6214     return el_bin(OPcall, TYvoid, eassert, el_params(elength, upr, lwr, eline, efile, null));
6215 }
6216 
6217 /******************************************************
6218  * Replace call to GC allocator with call to tracing GC allocator.
6219  * Params:
6220  *      irs = to get function from
6221  *      e = elem to modify in place
6222  *      loc = to get file/line from
6223  */
6224 
6225 void toTraceGC(IRState *irs, elem *e, const ref Loc loc)
6226 {
6227     static immutable int[2][25] map =
6228     [
6229         [ RTLSYM_NEWCLASS, RTLSYM_TRACENEWCLASS ],
6230         [ RTLSYM_NEWITEMT, RTLSYM_TRACENEWITEMT ],
6231         [ RTLSYM_NEWITEMIT, RTLSYM_TRACENEWITEMIT ],
6232         [ RTLSYM_NEWARRAYT, RTLSYM_TRACENEWARRAYT ],
6233         [ RTLSYM_NEWARRAYIT, RTLSYM_TRACENEWARRAYIT ],
6234         [ RTLSYM_NEWARRAYMTX, RTLSYM_TRACENEWARRAYMTX ],
6235         [ RTLSYM_NEWARRAYMITX, RTLSYM_TRACENEWARRAYMITX ],
6236 
6237         [ RTLSYM_DELCLASS, RTLSYM_TRACEDELCLASS ],
6238         [ RTLSYM_CALLFINALIZER, RTLSYM_TRACECALLFINALIZER ],
6239         [ RTLSYM_CALLINTERFACEFINALIZER, RTLSYM_TRACECALLINTERFACEFINALIZER ],
6240         [ RTLSYM_DELINTERFACE, RTLSYM_TRACEDELINTERFACE ],
6241         [ RTLSYM_DELARRAYT, RTLSYM_TRACEDELARRAYT ],
6242         [ RTLSYM_DELMEMORY, RTLSYM_TRACEDELMEMORY ],
6243         [ RTLSYM_DELSTRUCT, RTLSYM_TRACEDELSTRUCT ],
6244 
6245         [ RTLSYM_ARRAYLITERALTX, RTLSYM_TRACEARRAYLITERALTX ],
6246         [ RTLSYM_ASSOCARRAYLITERALTX, RTLSYM_TRACEASSOCARRAYLITERALTX ],
6247 
6248         [ RTLSYM_ARRAYCATT, RTLSYM_TRACEARRAYCATT ],
6249         [ RTLSYM_ARRAYCATNTX, RTLSYM_TRACEARRAYCATNTX ],
6250 
6251         [ RTLSYM_ARRAYAPPENDCD, RTLSYM_TRACEARRAYAPPENDCD ],
6252         [ RTLSYM_ARRAYAPPENDWD, RTLSYM_TRACEARRAYAPPENDWD ],
6253         [ RTLSYM_ARRAYAPPENDT, RTLSYM_TRACEARRAYAPPENDT ],
6254         [ RTLSYM_ARRAYAPPENDCTX, RTLSYM_TRACEARRAYAPPENDCTX ],
6255 
6256         [ RTLSYM_ARRAYSETLENGTHT, RTLSYM_TRACEARRAYSETLENGTHT ],
6257         [ RTLSYM_ARRAYSETLENGTHIT, RTLSYM_TRACEARRAYSETLENGTHIT ],
6258 
6259         [ RTLSYM_ALLOCMEMORY, RTLSYM_TRACEALLOCMEMORY ],
6260     ];
6261 
6262     if (irs.params.tracegc && loc.filename)
6263     {
6264         assert(e.Eoper == OPcall);
6265         elem *e1 = e.EV.E1;
6266         assert(e1.Eoper == OPvar);
6267 
6268         auto s = e1.EV.Vsym;
6269         /* In -dip1008 code the allocation of exceptions is no longer done by the
6270          * gc, but by a manual reference counting mechanism implementend in druntime.
6271          * If that is the case, then there is nothing to trace.
6272          */
6273         if (s == getRtlsym(RTLSYM_NEWTHROW))
6274             return;
6275         foreach (ref m; map)
6276         {
6277             if (s == getRtlsym(m[0]))
6278             {
6279                 e1.EV.Vsym = getRtlsym(m[1]);
6280                 e.EV.E2 = el_param(e.EV.E2, filelinefunction(irs, loc));
6281                 return;
6282             }
6283         }
6284         assert(0);
6285     }
6286 }
6287 
6288 
6289 /****************************************
6290  * Generate call to C's assert failure function.
6291  * One of exp, emsg, or str must not be null.
6292  * Params:
6293  *      irs = context
6294  *      loc = location to use for assert message
6295  *      exp = if not null expression to test (not evaluated, but converted to a string)
6296  *      emsg = if not null then informative message to be computed at run time
6297  *      str = if not null then informative message string
6298  * Returns:
6299  *      generated call
6300  */
6301 elem *callCAssert(IRState *irs, const ref Loc loc, Expression exp, Expression emsg, const(char)* str)
6302 {
6303     //printf("callCAssert.toElem() %s\n", e.toChars());
6304     Module m = cast(Module)irs.blx._module;
6305     const(char)* mname = m.srcfile.toChars();
6306 
6307     elem* getFuncName()
6308     {
6309         const(char)* id = "";
6310         FuncDeclaration fd = irs.getFunc();
6311         if (fd)
6312             id = fd.toPrettyChars();
6313         const len = strlen(id);
6314         Symbol *si = toStringSymbol(id, len, 1);
6315         return el_ptr(si);
6316     }
6317 
6318     //printf("filename = '%s'\n", loc.filename);
6319     //printf("module = '%s'\n", mname);
6320 
6321     /* If the source file name has changed, probably due
6322      * to a #line directive.
6323      */
6324     elem *efilename;
6325     if (loc.filename && strcmp(loc.filename, mname) != 0)
6326     {
6327         const(char)* id = loc.filename;
6328         size_t len = strlen(id);
6329         Symbol *si = toStringSymbol(id, len, 1);
6330         efilename = el_ptr(si);
6331     }
6332     else
6333     {
6334         efilename = toEfilenamePtr(m);
6335     }
6336 
6337     elem *elmsg;
6338     if (emsg)
6339     {
6340         // Assuming here that emsg generates a 0 terminated string
6341         auto e = toElemDtor(emsg, irs);
6342         elmsg = array_toPtr(Type.tvoid.arrayOf(), e);
6343     }
6344     else if (exp)
6345     {
6346         // Generate a message out of the assert expression
6347         const(char)* id = exp.toChars();
6348         const len = strlen(id);
6349         Symbol *si = toStringSymbol(id, len, 1);
6350         elmsg = el_ptr(si);
6351     }
6352     else
6353     {
6354         assert(str);
6355         const len = strlen(str);
6356         Symbol *si = toStringSymbol(str, len, 1);
6357         elmsg = el_ptr(si);
6358     }
6359 
6360     auto eline = el_long(TYint, loc.linnum);
6361 
6362     elem *ea;
6363     if (irs.params.isOSX)
6364     {
6365         // __assert_rtn(func, file, line, msg);
6366         elem* efunc = getFuncName();
6367         auto eassert = el_var(getRtlsym(RTLSYM_C__ASSERT_RTN));
6368         ea = el_bin(OPcall, TYvoid, eassert, el_params(elmsg, eline, efilename, efunc, null));
6369     }
6370     else
6371     {
6372         version (CRuntime_Musl)
6373         {
6374             // __assert_fail(exp, file, line, func);
6375             elem* efunc = getFuncName();
6376             auto eassert = el_var(getRtlsym(RTLSYM_C__ASSERT_FAIL));
6377             ea = el_bin(OPcall, TYvoid, eassert, el_params(elmsg, efilename, eline, efunc, null));
6378         }
6379         else
6380         {
6381             // [_]_assert(msg, file, line);
6382             const rtlsym = (irs.params.isWindows) ? RTLSYM_C_ASSERT : RTLSYM_C__ASSERT;
6383             auto eassert = el_var(getRtlsym(rtlsym));
6384             ea = el_bin(OPcall, TYvoid, eassert, el_params(eline, efilename, elmsg, null));
6385         }
6386     }
6387     return ea;
6388 }
6389 
6390 /********************************************
6391  * Generate HALT instruction.
6392  * Params:
6393  *      loc = location to use for debug info
6394  * Returns:
6395  *      generated instruction
6396  */
6397 elem *genHalt(const ref Loc loc)
6398 {
6399     elem *e = el_calloc();
6400     e.Ety = TYvoid;
6401     e.Eoper = OPhalt;
6402     elem_setLoc(e, loc);
6403     return e;
6404 }
6405 
6406 /*************************************************
6407  * Determine if zero bits need to be copied for this backend type
6408  * Params:
6409  *      t = backend type
6410  * Returns:
6411  *      true if 0 bits
6412  */
6413 bool type_zeroCopy(type* t)
6414 {
6415     return type_size(t) == 0 ||
6416         (tybasic(t.Tty) == TYstruct &&
6417          (t.Ttag.Stype.Ttag.Sstruct.Sflags & STR0size));
6418 }
6419 
6420 /**************************************************
6421  * Generate a copy from e2 to e1.
6422  * Params:
6423  *      e1 = lvalue
6424  *      e2 = rvalue
6425  *      t = value type
6426  *      tx = if !null, then t converted to C type
6427  * Returns:
6428  *      generated elem
6429  */
6430 elem* elAssign(elem* e1, elem* e2, Type t, type* tx)
6431 {
6432     elem *e = el_bin(OPeq, e2.Ety, e1, e2);
6433     switch (tybasic(e2.Ety))
6434     {
6435         case TYarray:
6436             e.Ejty = e.Ety = TYstruct;
6437             goto case TYstruct;
6438 
6439         case TYstruct:
6440             e.Eoper = OPstreq;
6441             if (!tx)
6442                 tx = Type_toCtype(t);
6443             e.ET = tx;
6444 //            if (type_zeroCopy(tx))
6445 //                e.Eoper = OPcomma;
6446             break;
6447 
6448         default:
6449             break;
6450     }
6451     return e;
6452 }
6453 
6454 /**************************************************
6455  * Initialize the dual-context array with the context pointers.
6456  * Params:
6457  *      loc = line and file of what line to show usage for
6458  *      irs = current context to get the second context from
6459  *      fd = the target function
6460  *      ethis2 = dual-context array
6461  *      ethis = the first context
6462  *      eside = where to store the assignment expressions
6463  * Returns:
6464  *      `ethis2` if successful, null otherwise
6465  */
6466 elem* setEthis2(const ref Loc loc, IRState* irs, FuncDeclaration fd, elem* ethis2, elem** ethis, elem** eside)
6467 {
6468     if (!fd.isThis2)
6469         return null;
6470 
6471     assert(ethis2 && ethis && *ethis);
6472 
6473     elem* ectx0 = el_una(OPind, (*ethis).Ety, el_copytree(ethis2));
6474     elem* eeq0 = el_bin(OPeq, (*ethis).Ety, ectx0, *ethis);
6475     *ethis = el_copytree(ectx0);
6476     *eside = el_combine(eeq0, *eside);
6477 
6478     elem* ethis1 = getEthis(loc, irs, fd, fd.toParent2());
6479     elem* ectx1 = el_bin(OPadd, TYnptr, el_copytree(ethis2), el_long(TYsize_t, tysize(TYnptr)));
6480     ectx1 = el_una(OPind, TYnptr, ectx1);
6481     elem* eeq1 = el_bin(OPeq, ethis1.Ety, ectx1, ethis1);
6482     *eside = el_combine(eeq1, *eside);
6483 
6484     return ethis2;
6485 }