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