1 /**
2  * Convert to Intermediate Representation (IR) for the back-end.
3  *
4  * Copyright:   Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved
5  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
6  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
7  * Source:      $(LINK2 https://github.com/dlang/dmd/blob/master/src/_tocsym.d, _toir.d)
8  * Documentation:  https://dlang.org/phobos/dmd_toir.html
9  * Coverage:    https://codecov.io/gh/dlang/dmd/src/master/src/dmd/toir.d
10  */
11 
12 module dmd.toir;
13 
14 import core.checkedint;
15 import core.stdc.stdio;
16 import core.stdc.string;
17 import core.stdc.stdlib;
18 
19 import dmd.root.array;
20 import dmd.root.outbuffer;
21 import dmd.root.rmem;
22 
23 import dmd.backend.cdef;
24 import dmd.backend.cc;
25 import dmd.backend.dt;
26 import dmd.backend.el;
27 import dmd.backend.global;
28 import dmd.backend.oper;
29 import dmd.backend.rtlsym;
30 import dmd.backend.ty;
31 import dmd.backend.type;
32 
33 import dmd.aggregate;
34 import dmd.arraytypes;
35 import dmd.dclass;
36 import dmd.declaration;
37 import dmd.dmangle;
38 import dmd.dmodule;
39 import dmd.dstruct;
40 import dmd.dsymbol;
41 import dmd.dtemplate;
42 import dmd.toctype;
43 import dmd.e2ir;
44 import dmd.func;
45 import dmd.globals;
46 import dmd.glue;
47 import dmd.identifier;
48 import dmd.id;
49 import dmd.mtype;
50 import dmd.target;
51 import dmd.tocvdebug;
52 import dmd.tocsym;
53 
54 alias toSymbol = dmd.tocsym.toSymbol;
55 alias toSymbol = dmd.glue.toSymbol;
56 
57 /****************************************
58  * Our label symbol
59  */
60 
61 struct Label
62 {
63     block *lblock;      // The block to which the label is defined.
64 }
65 
66 /***********************************************************
67  * Collect state variables needed by the intermediate representation (IR)
68  */
69 struct IRState
70 {
71     Module m;                       // module
72     private FuncDeclaration symbol; // function that code is being generate for
73     Symbol* shidden;                // hidden parameter to function
74     Symbol* sthis;                  // 'this' parameter to function (member and nested)
75     Symbol* sclosure;               // pointer to closure instance
76     Blockx* blx;
77     Dsymbols* deferToObj;           // array of Dsymbol's to run toObjFile(bool multiobj) on later
78     elem* ehidden;                  // transmit hidden pointer to CallExp::toElem()
79     Symbol* startaddress;
80     Array!(elem*)* varsInScope;     // variables that are in scope that will need destruction later
81     Label*[void*]* labels;          // table of labels used/declared in function
82     const Param* params;            // command line parameters
83     bool mayThrow;                  // the expression being evaluated may throw
84 
85     this(Module m, FuncDeclaration fd, Array!(elem*)* varsInScope, Dsymbols* deferToObj, Label*[void*]* labels,
86         const Param* params)
87     {
88         this.m = m;
89         this.symbol = fd;
90         this.varsInScope = varsInScope;
91         this.deferToObj = deferToObj;
92         this.labels = labels;
93         this.params = params;
94         mayThrow = global.params.useExceptions
95             && ClassDeclaration.throwable
96             && !(fd && fd.eh_none);
97     }
98 
99     FuncDeclaration getFunc()
100     {
101         return symbol;
102     }
103 
104     /**********************
105      * Returns:
106      *    true if do array bounds checking for the current function
107      */
108     bool arrayBoundsCheck()
109     {
110         bool result;
111         final switch (global.params.useArrayBounds)
112         {
113         case CHECKENABLE.off:
114             result = false;
115             break;
116         case CHECKENABLE.on:
117             result = true;
118             break;
119         case CHECKENABLE.safeonly:
120             {
121                 result = false;
122                 FuncDeclaration fd = getFunc();
123                 if (fd)
124                 {
125                     Type t = fd.type;
126                     if (t.ty == Tfunction && (cast(TypeFunction)t).trust == TRUST.safe)
127                         result = true;
128                 }
129                 break;
130             }
131         case CHECKENABLE._default:
132             assert(0);
133         }
134         return result;
135     }
136 
137     /****************************
138      * Returns:
139      *  true if in a nothrow section of code
140      */
141     bool isNothrow()
142     {
143         return !mayThrow;
144     }
145 }
146 
147 extern (C++):
148 
149 /*********************************************
150  * Produce elem which increments the usage count for a particular line.
151  * Sets corresponding bit in bitmap `m.covb[linnum]`.
152  * Used to implement -cov switch (coverage analysis).
153  * Params:
154  *      irs = context
155  *      loc = line and file of what line to show usage for
156  * Returns:
157  *      elem that increments the line count
158  * References:
159  * https://dlang.org/dmd-windows.html#switch-cov
160  */
161 extern (D) elem *incUsageElem(IRState *irs, const ref Loc loc)
162 {
163     uint linnum = loc.linnum;
164 
165     Module m = cast(Module)irs.blx._module;
166     if (!m.cov || !linnum ||
167         loc.filename != m.srcfile.toChars())
168         return null;
169 
170     //printf("cov = %p, covb = %p, linnum = %u\n", m.cov, m.covb, p, linnum);
171 
172     linnum--;           // from 1-based to 0-based
173 
174     /* Set bit in covb[] indicating this is a valid code line number
175      */
176     uint *p = m.covb;
177     if (p)      // covb can be null if it has already been written out to its .obj file
178     {
179         assert(linnum < m.numlines);
180         p += linnum / ((*p).sizeof * 8);
181         *p |= 1 << (linnum & ((*p).sizeof * 8 - 1));
182     }
183 
184     /* Generate: *(m.cov + linnum * 4) += 1
185      */
186     elem *e;
187     e = el_ptr(m.cov);
188     e = el_bin(OPadd, TYnptr, e, el_long(TYuint, linnum * 4));
189     e = el_una(OPind, TYuint, e);
190     e = el_bin(OPaddass, TYuint, e, el_long(TYuint, 1));
191     return e;
192 }
193 
194 /******************************************
195  * Return elem that evaluates to the static frame pointer for function fd.
196  * If fd is a member function, the returned expression will compute the value
197  * of fd's 'this' variable.
198  * 'fdp' is the parent of 'fd' if the frame pointer is being used to call 'fd'.
199  * 'origSc' is the original scope we inlined from.
200  * This routine is critical for implementing nested functions.
201  */
202 elem *getEthis(const ref Loc loc, IRState *irs, Dsymbol fd, Dsymbol fdp = null, Dsymbol origSc = null)
203 {
204     elem *ethis;
205     FuncDeclaration thisfd = irs.getFunc();
206     Dsymbol ctxt0 = fdp ? fdp : fd;                     // follow either of these two
207     Dsymbol ctxt1 = origSc ? origSc.toParent2() : null; // contexts from template arguments
208     if (!fdp) fdp = fd.toParent2();
209     Dsymbol fdparent = fdp;
210 
211     /* These two are compiler generated functions for the in and out contracts,
212      * and are called from an overriding function, not just the one they're
213      * nested inside, so this hack sets fdparent so it'll pass
214      */
215     if (fdparent != thisfd && (fd.ident == Id.require || fd.ident == Id.ensure))
216     {
217         FuncDeclaration fdthis = thisfd;
218         for (size_t i = 0; ; )
219         {
220             if (i == fdthis.foverrides.dim)
221             {
222                 if (i == 0)
223                     break;
224                 fdthis = fdthis.foverrides[0];
225                 i = 0;
226                 continue;
227             }
228             if (fdthis.foverrides[i] == fdp)
229             {
230                 fdparent = thisfd;
231                 break;
232             }
233             i++;
234         }
235     }
236 
237     //printf("[%s] getEthis(thisfd = '%s', fd = '%s', fdparent = '%s')\n", loc.toChars(), thisfd.toPrettyChars(), fd.toPrettyChars(), fdparent.toPrettyChars());
238     if (fdparent == thisfd)
239     {
240         /* Going down one nesting level, i.e. we're calling
241          * a nested function from its enclosing function.
242          */
243         if (irs.sclosure && !(fd.ident == Id.require || fd.ident == Id.ensure))
244         {
245             ethis = el_var(irs.sclosure);
246         }
247         else if (irs.sthis)
248         {
249             // We have a 'this' pointer for the current function
250 
251             if (fdp != thisfd)
252             {
253                 /* fdparent (== thisfd) is a derived member function,
254                  * fdp is the overridden member function in base class, and
255                  * fd is the nested function '__require' or '__ensure'.
256                  * Even if there's a closure environment, we should give
257                  * original stack data as the nested function frame.
258                  * See also: SymbolExp.toElem() in e2ir.c (https://issues.dlang.org/show_bug.cgi?id=9383 fix)
259                  */
260                 /* Address of 'sthis' gives the 'this' for the nested
261                  * function.
262                  */
263                 //printf("L%d fd = %s, fdparent = %s, fd.toParent2() = %s\n",
264                 //    __LINE__, fd.toPrettyChars(), fdparent.toPrettyChars(), fdp.toPrettyChars());
265                 assert(fd.ident == Id.require || fd.ident == Id.ensure);
266                 assert(thisfd.hasNestedFrameRefs());
267 
268                 ClassDeclaration cdp = fdp.isThis().isClassDeclaration();
269                 ClassDeclaration cd = thisfd.isThis().isClassDeclaration();
270                 assert(cdp && cd);
271 
272                 int offset;
273                 cdp.isBaseOf(cd, &offset);
274                 assert(offset != ClassDeclaration.OFFSET_RUNTIME);
275                 //printf("%s to %s, offset = %d\n", cd.toChars(), cdp.toChars(), offset);
276                 if (offset)
277                 {
278                     /* https://issues.dlang.org/show_bug.cgi?id=7517: If fdp is declared in interface, offset the
279                      * 'this' pointer to get correct interface type reference.
280                      */
281                     Symbol *stmp = symbol_genauto(TYnptr);
282                     ethis = el_bin(OPadd, TYnptr, el_var(irs.sthis), el_long(TYsize_t, offset));
283                     ethis = el_bin(OPeq, TYnptr, el_var(stmp), ethis);
284                     ethis = el_combine(ethis, el_ptr(stmp));
285                     //elem_print(ethis);
286                 }
287                 else
288                     ethis = el_ptr(irs.sthis);
289             }
290             else if (thisfd.hasNestedFrameRefs())
291             {
292                 /* Local variables are referenced, can't skip.
293                  * Address of 'sthis' gives the 'this' for the nested
294                  * function.
295                  */
296                 ethis = el_ptr(irs.sthis);
297             }
298             else
299             {
300                 /* If no variables in the current function's frame are
301                  * referenced by nested functions, then we can 'skip'
302                  * adding this frame into the linked list of stack
303                  * frames.
304                  */
305                 ethis = el_var(irs.sthis);
306             }
307         }
308         else
309         {
310             /* No 'this' pointer for current function,
311              */
312             if (thisfd.hasNestedFrameRefs())
313             {
314                 /* OPframeptr is an operator that gets the frame pointer
315                  * for the current function, i.e. for the x86 it gets
316                  * the value of EBP
317                  */
318                 ethis = el_long(TYnptr, 0);
319                 ethis.Eoper = OPframeptr;
320             }
321             else
322             {
323                 /* Use null if no references to the current function's frame
324                  */
325                 ethis = el_long(TYnptr, 0);
326             }
327         }
328     }
329     else
330     {
331         if (!irs.sthis)                // if no frame pointer for this function
332         {
333             fd.error(loc, "is a nested function and cannot be accessed from `%s`", irs.getFunc().toPrettyChars());
334             return el_long(TYnptr, 0); // error recovery
335         }
336 
337         /* Go up a nesting level, i.e. we need to find the 'this'
338          * of an enclosing function.
339          * Our 'enclosing function' may also be an inner class.
340          */
341         ethis = el_var(irs.sthis);
342         Dsymbol s = thisfd;
343         while (fd != s)
344         {
345             //printf("\ts = '%s'\n", s.toChars());
346             thisfd = s.isFuncDeclaration();
347 
348             if (thisfd)
349             {
350                 /* Enclosing function is a function.
351                  */
352                 // Error should have been caught by front end
353                 assert(thisfd.isNested() || thisfd.vthis);
354 
355                 // pick one context
356                 ethis = fixEthis2(ethis, thisfd, thisfd.followInstantiationContext(ctxt0, ctxt1));
357             }
358             else
359             {
360                 /* Enclosed by an aggregate. That means the current
361                  * function must be a member function of that aggregate.
362                  */
363                 AggregateDeclaration ad = s.isAggregateDeclaration();
364                 if (!ad)
365                 {
366                   Lnoframe:
367                     irs.getFunc().error(loc, "cannot get frame pointer to `%s`", fd.toPrettyChars());
368                     return el_long(TYnptr, 0);      // error recovery
369                 }
370                 ClassDeclaration cd = ad.isClassDeclaration();
371                 ClassDeclaration cdx = fd.isClassDeclaration();
372                 if (cd && cdx && cdx.isBaseOf(cd, null))
373                     break;
374                 StructDeclaration sd = ad.isStructDeclaration();
375                 if (fd == sd)
376                     break;
377                 if (!ad.isNested() || !(ad.vthis || ad.vthis2))
378                     goto Lnoframe;
379 
380                 bool i = ad.followInstantiationContext(ctxt0, ctxt1);
381                 const voffset = i ? ad.vthis2.offset : ad.vthis.offset;
382                 ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYsize_t, voffset));
383                 ethis = el_una(OPind, TYnptr, ethis);
384             }
385             if (fdparent == s.toParentP(ctxt0, ctxt1))
386                 break;
387 
388             /* Remember that frames for functions that have no
389              * nested references are skipped in the linked list
390              * of frames.
391              */
392             FuncDeclaration fdp2 = s.toParentP(ctxt0, ctxt1).isFuncDeclaration();
393             if (fdp2 && fdp2.hasNestedFrameRefs())
394                 ethis = el_una(OPind, TYnptr, ethis);
395 
396             s = s.toParentP(ctxt0, ctxt1);
397             assert(s);
398         }
399     }
400     version (none)
401     {
402         printf("ethis:\n");
403         elem_print(ethis);
404         printf("\n");
405     }
406     return ethis;
407 }
408 
409 /************************
410  * Select one context pointer from a dual-context array
411  * Returns:
412  *      *(ethis + offset);
413  */
414 elem *fixEthis2(elem *ethis, FuncDeclaration fd, bool ctxt2 = false)
415 {
416     if (fd && fd.isThis2)
417     {
418         if (ctxt2)
419             ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYsize_t, tysize(TYnptr)));
420         ethis = el_una(OPind, TYnptr, ethis);
421     }
422     return ethis;
423 }
424 
425 /*************************
426  * Initialize the hidden aggregate member, vthis, with
427  * the context pointer.
428  * Returns:
429  *      *(ey + (ethis2 ? ad.vthis2 : ad.vthis).offset) = this;
430  */
431 elem *setEthis(const ref Loc loc, IRState *irs, elem *ey, AggregateDeclaration ad, bool setthis2 = false)
432 {
433     elem *ethis;
434     FuncDeclaration thisfd = irs.getFunc();
435     int offset = 0;
436     Dsymbol adp = setthis2 ? ad.toParent2(): ad.toParentLocal();     // class/func we're nested in
437 
438     //printf("[%s] setEthis(ad = %s, adp = %s, thisfd = %s)\n", loc.toChars(), ad.toChars(), adp.toChars(), thisfd.toChars());
439 
440     if (adp == thisfd)
441     {
442         ethis = getEthis(loc, irs, ad);
443     }
444     else if (thisfd.vthis && !thisfd.isThis2 &&
445           (adp == thisfd.toParent2() ||
446            (adp.isClassDeclaration() &&
447             adp.isClassDeclaration().isBaseOf(thisfd.toParent2().isClassDeclaration(), &offset)
448            )
449           )
450         )
451     {
452         /* Class we're new'ing is at the same level as thisfd
453          */
454         assert(offset == 0);    // BUG: should handle this case
455         ethis = el_var(irs.sthis);
456     }
457     else
458     {
459         ethis = getEthis(loc, irs, adp);
460         FuncDeclaration fdp = adp.isFuncDeclaration();
461         if (fdp && fdp.hasNestedFrameRefs())
462             ethis = el_una(OPaddr, TYnptr, ethis);
463     }
464 
465     assert(!setthis2 || ad.vthis2);
466     const voffset = setthis2 ? ad.vthis2.offset : ad.vthis.offset;
467     ey = el_bin(OPadd, TYnptr, ey, el_long(TYsize_t, voffset));
468     ey = el_una(OPind, TYnptr, ey);
469     ey = el_bin(OPeq, TYnptr, ey, ethis);
470     return ey;
471 }
472 
473 enum NotIntrinsic = -1;
474 enum OPtoPrec = OPMAX + 1; // front end only
475 
476 /*******************************************
477  * Convert intrinsic function to operator.
478  * Returns:
479  *      the operator as backend OPER,
480  *      NotIntrinsic if not an intrinsic function,
481  *      OPtoPrec if frontend-only intrinsic
482  */
483 int intrinsic_op(FuncDeclaration fd)
484 {
485     int op = NotIntrinsic;
486     fd = fd.toAliasFunc();
487     if (fd.isDeprecated())
488         return op;
489     //printf("intrinsic_op(%s)\n", name);
490 
491     // Look for [core|std].module.function as id3.id2.id1 ...
492     const Identifier id3 = fd.ident;
493     auto m = fd.getModule();
494     if (!m || !m.md)
495         return op;
496 
497     const md = m.md;
498     const Identifier id2 = md.id;
499 
500     if (md.packages.length == 0)
501         return op;
502 
503     // get type of first argument
504     auto tf = fd.type ? fd.type.isTypeFunction() : null;
505     auto param1 = tf && tf.parameterList.length > 0 ? tf.parameterList[0] : null;
506     auto argtype1 = param1 ? param1.type : null;
507 
508     const Identifier id1 = md.packages[0];
509     // ... except std.math package and core.stdc.stdarg.va_start.
510     if (md.packages.length == 2)
511     {
512         if (id2 == Id.trig &&
513             md.packages[1] == Id.math &&
514             id1 == Id.std)
515         {
516             goto Lstdmath;
517         }
518         goto Lva_start;
519     }
520 
521     if (id1 == Id.std && id2 == Id.math)
522     {
523     Lstdmath:
524         if (argtype1 is Type.tfloat80 || id3 == Id._sqrt)
525             goto Lmath;
526         if (id3 == Id.fabs &&
527             (argtype1 is Type.tfloat32 || argtype1 is Type.tfloat64))
528         {
529             op = OPabs;
530         }
531     }
532     else if (id1 == Id.core)
533     {
534         if (id2 == Id.math)
535         {
536         Lmath:
537             if (argtype1 is Type.tfloat80 || argtype1 is Type.tfloat32 || argtype1 is Type.tfloat64)
538             {
539                      if (id3 == Id.cos)    op = OPcos;
540                 else if (id3 == Id.sin)    op = OPsin;
541                 else if (id3 == Id.fabs)   op = OPabs;
542                 else if (id3 == Id.rint)   op = OPrint;
543                 else if (id3 == Id._sqrt)  op = OPsqrt;
544                 else if (id3 == Id.yl2x)   op = OPyl2x;
545                 else if (id3 == Id.ldexp)  op = OPscale;
546                 else if (id3 == Id.rndtol) op = OPrndtol;
547                 else if (id3 == Id.yl2xp1) op = OPyl2xp1;
548                 else if (id3 == Id.toPrec) op = OPtoPrec;
549             }
550         }
551         else if (id2 == Id.simd)
552         {
553                  if (id3 == Id.__prefetch) op = OPprefetch;
554             else if (id3 == Id.__simd_sto) op = OPvector;
555             else if (id3 == Id.__simd)     op = OPvector;
556             else if (id3 == Id.__simd_ib)  op = OPvector;
557         }
558         else if (id2 == Id.bitop)
559         {
560                  if (id3 == Id.volatileLoad)  op = OPind;
561             else if (id3 == Id.volatileStore) op = OPeq;
562 
563             else if (id3 == Id.bsf) op = OPbsf;
564             else if (id3 == Id.bsr) op = OPbsr;
565             else if (id3 == Id.btc) op = OPbtc;
566             else if (id3 == Id.btr) op = OPbtr;
567             else if (id3 == Id.bts) op = OPbts;
568 
569             else if (id3 == Id.inp)  op = OPinp;
570             else if (id3 == Id.inpl) op = OPinp;
571             else if (id3 == Id.inpw) op = OPinp;
572 
573             else if (id3 == Id.outp)  op = OPoutp;
574             else if (id3 == Id.outpl) op = OPoutp;
575             else if (id3 == Id.outpw) op = OPoutp;
576 
577             else if (id3 == Id.bswap)   op = OPbswap;
578             else if (id3 == Id._popcnt) op = OPpopcnt;
579         }
580         else if (id2 == Id..volatile)
581         {
582                  if (id3 == Id.volatileLoad)  op = OPind;
583             else if (id3 == Id.volatileStore) op = OPeq;
584         }
585     }
586 
587     if (!global.params.is64bit)
588     // No 64-bit bsf bsr in 32bit mode
589     {
590         if ((op == OPbsf || op == OPbsr) && argtype1 is Type.tuns64)
591             return NotIntrinsic;
592     }
593     return op;
594 
595 Lva_start:
596     if (global.params.is64bit &&
597         fd.toParent().isTemplateInstance() &&
598         id3 == Id.va_start &&
599         id2 == Id.stdarg &&
600         md.packages[1] == Id.stdc &&
601         id1 == Id.core)
602     {
603         return OPva_start;
604     }
605     return op;
606 }
607 
608 /**************************************
609  * Given an expression e that is an array,
610  * determine and set the 'length' variable.
611  * Input:
612  *      lengthVar       Symbol of 'length' variable
613  *      &e      expression that is the array
614  *      t1      Type of the array
615  * Output:
616  *      e       is rewritten to avoid side effects
617  * Returns:
618  *      expression that initializes 'length'
619  */
620 elem *resolveLengthVar(VarDeclaration lengthVar, elem **pe, Type t1)
621 {
622     //printf("resolveLengthVar()\n");
623     elem *einit = null;
624 
625     if (lengthVar && !(lengthVar.storage_class & STC.const_))
626     {
627         elem *elength;
628         Symbol *slength;
629 
630         if (t1.ty == Tsarray)
631         {
632             TypeSArray tsa = cast(TypeSArray)t1;
633             dinteger_t length = tsa.dim.toInteger();
634 
635             elength = el_long(TYsize_t, length);
636             goto L3;
637         }
638         else if (t1.ty == Tarray)
639         {
640             elength = *pe;
641             *pe = el_same(&elength);
642             elength = el_una(global.params.is64bit ? OP128_64 : OP64_32, TYsize_t, elength);
643 
644         L3:
645             slength = toSymbol(lengthVar);
646             //symbol_add(slength);
647 
648             einit = el_bin(OPeq, TYsize_t, el_var(slength), elength);
649         }
650     }
651     return einit;
652 }
653 
654 /*************************************
655  * for a nested function 'fd' return the type of the closure
656  * of an outer function or aggregate. If the function is a member function
657  * the 'this' type is expected to be stored in 'sthis.Sthis'.
658  * It is always returned if it is not a void pointer.
659  * buildClosure() must have been called on the outer function before.
660  *
661  * Params:
662  *      sthis = the symbol of the current 'this' derived from fd.vthis
663  *      fd = the nested function
664  */
665 TYPE* getParentClosureType(Symbol* sthis, FuncDeclaration fd)
666 {
667     if (sthis)
668     {
669         // only replace void*
670         if (sthis.Stype.Tty != TYnptr || sthis.Stype.Tnext.Tty != TYvoid)
671             return sthis.Stype;
672     }
673     for (Dsymbol sym = fd.toParent2(); sym; sym = sym.toParent2())
674     {
675         if (auto fn = sym.isFuncDeclaration())
676             if (fn.csym && fn.csym.Sscope)
677                 return fn.csym.Sscope.Stype;
678         if (sym.isAggregateDeclaration())
679             break;
680     }
681     return sthis ? sthis.Stype : Type_toCtype(Type.tvoidptr);
682 }
683 
684 /**************************************
685  * Go through the variables in function fd that are
686  * to be allocated in a closure, and set the .offset fields
687  * for those variables to their positions relative to the start
688  * of the closure instance.
689  * Also turns off nrvo for closure variables.
690  * Params:
691  *      fd = function
692  */
693 void setClosureVarOffset(FuncDeclaration fd)
694 {
695     // Nothing to do
696     if (!fd.needsClosure())
697         return;
698 
699     uint offset = target.ptrsize;      // leave room for previous sthis
700 
701     foreach (v; fd.closureVars)
702     {
703         /* Align and allocate space for v in the closure
704          * just like AggregateDeclaration.addField() does.
705          */
706         uint memsize;
707         uint memalignsize;
708         structalign_t xalign;
709         if (v.storage_class & STC.lazy_)
710         {
711             /* Lazy variables are really delegates,
712              * so give same answers that TypeDelegate would
713              */
714             memsize = target.ptrsize * 2;
715             memalignsize = memsize;
716             xalign = STRUCTALIGN_DEFAULT;
717         }
718         else if (v.storage_class & (STC.out_ | STC.ref_))
719         {
720             // reference parameters are just pointers
721             memsize = target.ptrsize;
722             memalignsize = memsize;
723             xalign = STRUCTALIGN_DEFAULT;
724         }
725         else
726         {
727             memsize = cast(uint)v.type.size();
728             memalignsize = v.type.alignsize();
729             xalign = v.alignment;
730         }
731         AggregateDeclaration.alignmember(xalign, memalignsize, &offset);
732         v.offset = offset;
733         //printf("closure var %s, offset = %d\n", v.toChars(), v.offset);
734 
735         offset += memsize;
736 
737         /* Can't do nrvo if the variable is put in a closure, since
738          * what the shidden points to may no longer exist.
739          */
740         if (fd.nrvo_can && fd.nrvo_var == v)
741         {
742             fd.nrvo_can = false;
743         }
744     }
745 }
746 
747 /*************************************
748  * Closures are implemented by taking the local variables that
749  * need to survive the scope of the function, and copying them
750  * into a gc allocated chuck of memory. That chunk, called the
751  * closure here, is inserted into the linked list of stack
752  * frames instead of the usual stack frame.
753  *
754  * buildClosure() inserts code just after the function prolog
755  * is complete. It allocates memory for the closure, allocates
756  * a local variable (sclosure) to point to it, inserts into it
757  * the link to the enclosing frame, and copies into it the parameters
758  * that are referred to in nested functions.
759  * In VarExp::toElem and SymOffExp::toElem, when referring to a
760  * variable that is in a closure, takes the offset from sclosure rather
761  * than from the frame pointer.
762  *
763  * getEthis() and NewExp::toElem need to use sclosure, if set, rather
764  * than the current frame pointer.
765  */
766 void buildClosure(FuncDeclaration fd, IRState *irs)
767 {
768     //printf("buildClosure(fd = %s)\n", fd.toChars());
769     if (fd.needsClosure())
770     {
771         setClosureVarOffset(fd);
772 
773         // Generate closure on the heap
774         // BUG: doesn't capture variadic arguments passed to this function
775 
776         /* BUG: doesn't handle destructors for the local variables.
777          * The way to do it is to make the closure variables the fields
778          * of a class object:
779          *    class Closure {
780          *        vtbl[]
781          *        monitor
782          *        ptr to destructor
783          *        sthis
784          *        ... closure variables ...
785          *        ~this() { call destructor }
786          *    }
787          */
788         //printf("FuncDeclaration.buildClosure() %s\n", fd.toChars());
789 
790         /* Generate type name for closure struct */
791         const char *name1 = "CLOSURE.";
792         const char *name2 = fd.toPrettyChars();
793         size_t namesize = strlen(name1)+strlen(name2)+1;
794         char *closname = cast(char *)Mem.check(calloc(namesize, char.sizeof));
795         strcat(strcat(closname, name1), name2);
796 
797         /* Build type for closure */
798         type *Closstru = type_struct_class(closname, target.ptrsize, 0, null, null, false, false, true, false);
799         free(closname);
800         auto chaintype = getParentClosureType(irs.sthis, fd);
801         symbol_struct_addField(Closstru.Ttag, "__chain", chaintype, 0);
802 
803         Symbol *sclosure;
804         sclosure = symbol_name("__closptr", SCauto, type_pointer(Closstru));
805         sclosure.Sflags |= SFLtrue | SFLfree;
806         symbol_add(sclosure);
807         irs.sclosure = sclosure;
808 
809         assert(fd.closureVars.dim);
810         assert(fd.closureVars[0].offset >= target.ptrsize);
811         foreach (v; fd.closureVars)
812         {
813             //printf("closure var %s\n", v.toChars());
814 
815             // Hack for the case fail_compilation/fail10666.d,
816             // until proper issue 5730 fix will come.
817             bool isScopeDtorParam = v.edtor && (v.storage_class & STC.parameter);
818             if (v.needsScopeDtor() || isScopeDtorParam)
819             {
820                 /* Because the value needs to survive the end of the scope!
821                  */
822                 v.error("has scoped destruction, cannot build closure");
823             }
824             if (v.isargptr)
825             {
826                 /* See https://issues.dlang.org/show_bug.cgi?id=2479
827                  * This is actually a bug, but better to produce a nice
828                  * message at compile time rather than memory corruption at runtime
829                  */
830                 v.error("cannot reference variadic arguments from closure");
831             }
832 
833             /* Set Sscope to closure */
834             Symbol *vsym = toSymbol(v);
835             assert(vsym.Sscope == null);
836             vsym.Sscope = sclosure;
837 
838             /* Add variable as closure type member */
839             symbol_struct_addField(Closstru.Ttag, &vsym.Sident[0], vsym.Stype, v.offset);
840             //printf("closure field %s: memalignsize: %i, offset: %i\n", &vsym.Sident[0], memalignsize, v.offset);
841         }
842 
843         // Calculate the size of the closure
844         VarDeclaration  vlast = fd.closureVars[fd.closureVars.dim - 1];
845         typeof(Type.size()) lastsize;
846         if (vlast.storage_class & STC.lazy_)
847             lastsize = target.ptrsize * 2;
848         else if (vlast.isRef() || vlast.isOut())
849             lastsize = target.ptrsize;
850         else
851             lastsize = vlast.type.size();
852         bool overflow;
853         const structsize = addu(vlast.offset, lastsize, overflow);
854         assert(!overflow && structsize <= uint.max);
855         //printf("structsize = %d\n", cast(uint)structsize);
856 
857         Closstru.Ttag.Sstruct.Sstructsize = cast(uint)structsize;
858         fd.csym.Sscope = sclosure;
859 
860         if (global.params.symdebug)
861             toDebugClosure(Closstru.Ttag);
862 
863         // Allocate memory for the closure
864         elem *e = el_long(TYsize_t, structsize);
865         e = el_bin(OPcall, TYnptr, el_var(getRtlsym(RTLSYM_ALLOCMEMORY)), e);
866         toTraceGC(irs, e, fd.loc);
867 
868         // Assign block of memory to sclosure
869         //    sclosure = allocmemory(sz);
870         e = el_bin(OPeq, TYvoid, el_var(sclosure), e);
871 
872         // Set the first element to sthis
873         //    *(sclosure + 0) = sthis;
874         elem *ethis;
875         if (irs.sthis)
876             ethis = el_var(irs.sthis);
877         else
878             ethis = el_long(TYnptr, 0);
879         elem *ex = el_una(OPind, TYnptr, el_var(sclosure));
880         ex = el_bin(OPeq, TYnptr, ex, ethis);
881         e = el_combine(e, ex);
882 
883         // Copy function parameters into closure
884         foreach (v; fd.closureVars)
885         {
886             if (!v.isParameter())
887                 continue;
888             tym_t tym = totym(v.type);
889             const x64ref = ISX64REF(v);
890             if (x64ref && config.exe == EX_WIN64)
891             {
892                 if (v.storage_class & STC.lazy_)
893                     tym = TYdelegate;
894             }
895             else if (ISREF(v) && !x64ref)
896                 tym = TYnptr;   // reference parameters are just pointers
897             else if (v.storage_class & STC.lazy_)
898                 tym = TYdelegate;
899             ex = el_bin(OPadd, TYnptr, el_var(sclosure), el_long(TYsize_t, v.offset));
900             ex = el_una(OPind, tym, ex);
901             elem *ev = el_var(toSymbol(v));
902             if (x64ref)
903             {
904                 ev.Ety = TYnref;
905                 ev = el_una(OPind, tym, ev);
906                 if (tybasic(ev.Ety) == TYstruct || tybasic(ev.Ety) == TYarray)
907                     ev.ET = Type_toCtype(v.type);
908             }
909             if (tybasic(ex.Ety) == TYstruct || tybasic(ex.Ety) == TYarray)
910             {
911                 .type *t = Type_toCtype(v.type);
912                 ex.ET = t;
913                 ex = el_bin(OPstreq, tym, ex, ev);
914                 ex.ET = t;
915             }
916             else
917                 ex = el_bin(OPeq, tym, ex, ev);
918 
919             e = el_combine(e, ex);
920         }
921 
922         block_appendexp(irs.blx.curblock, e);
923     }
924 }
925 
926 /*************************************
927  * build a debug info struct for variables captured by nested functions,
928  * but not in a closure.
929  * must be called after generating the function to fill stack offsets
930  * Params:
931  *      fd = function
932  */
933 void buildCapture(FuncDeclaration fd)
934 {
935     if (!global.params.symdebug)
936         return;
937     if (!global.params.mscoff)  // toDebugClosure only implemented for CodeView,
938         return;                 //  but optlink crashes for negative field offsets
939 
940     if (fd.closureVars.dim && !fd.needsClosure)
941     {
942         /* Generate type name for struct with captured variables */
943         const char *name1 = "CAPTURE.";
944         const char *name2 = fd.toPrettyChars();
945         size_t namesize = strlen(name1)+strlen(name2)+1;
946         char *capturename = cast(char *)Mem.check(calloc(namesize, char.sizeof));
947         strcat(strcat(capturename, name1), name2);
948 
949         /* Build type for struct */
950         type *capturestru = type_struct_class(capturename, target.ptrsize, 0, null, null, false, false, true, false);
951         free(capturename);
952 
953         foreach (v; fd.closureVars)
954         {
955             Symbol *vsym = toSymbol(v);
956 
957             /* Add variable as capture type member */
958             auto soffset = vsym.Soffset;
959             if (fd.vthis)
960                 soffset -= toSymbol(fd.vthis).Soffset; // see toElem.ToElemVisitor.visit(SymbolExp)
961             symbol_struct_addField(capturestru.Ttag, &vsym.Sident[0], vsym.Stype, cast(uint)soffset);
962             //printf("capture field %s: offset: %i\n", &vsym.Sident[0], v.offset);
963         }
964 
965         // generate pseudo symbol to put into functions' Sscope
966         Symbol *scapture = symbol_name("__captureptr", SCalias, type_pointer(capturestru));
967         scapture.Sflags |= SFLtrue | SFLfree;
968         //symbol_add(scapture);
969         fd.csym.Sscope = scapture;
970 
971         toDebugClosure(capturestru.Ttag);
972     }
973 }
974 
975 
976 /***************************
977  * Determine return style of function - whether in registers or
978  * through a hidden pointer to the caller's stack.
979  * Params:
980  *   tf = function type to check
981  *   needsThis = true if the function type is for a non-static member function
982  * Returns:
983  *   RET.stack if return value from function is on the stack, RET.regs otherwise
984  */
985 RET retStyle(TypeFunction tf, bool needsThis)
986 {
987     //printf("TypeFunction.retStyle() %s\n", toChars());
988     return target.isReturnOnStack(tf, needsThis) ? RET.stack : RET.regs;
989 }