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