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