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