1:
2: // Compiler implementation of the D programming language
3: // Copyright (c) 1999-2010 by Digital Mars
4: // All Rights Reserved
5: // written by Walter Bright
6: // http://www.digitalmars.com
7: // License for redistribution is by either the Artistic License
8: // in artistic.txt, or the GNU General Public License in gnu.txt.
9: // See the included readme.txt for details.
10:
11: /* Code to help convert to the intermediate representation
12: * of the compiler back end.
13: */
14:
15: #include <stdio.h>
16: #include <string.h>
17: #include <time.h>
18: //#include <complex.h>
19:
20: #include "lexer.h"
21: #include "expression.h"
22: #include "mtype.h"
23: #include "dsymbol.h"
24: #include "declaration.h"
25: #include "enum.h"
26: #include "aggregate.h"
27: #include "attrib.h"
28: #include "module.h"
29: #include "init.h"
30: #include "template.h"
31:
32: #include "mem.h" // for mem_malloc
33:
34: #include "cc.h"
35: #include "el.h"
36: #include "oper.h"
37: #include "global.h"
38: #include "code.h"
39: #include "type.h"
40: #include "dt.h"
41: #include "irstate.h"
42: #include "id.h"
43: #include "type.h"
44: #include "toir.h"
45:
46: static char __file__[] = __FILE__; /* for tassert.h */
47: #include "tassert.h"
48:
49: /*********************************************
50: * Produce elem which increments the usage count for a particular line.
51: * Used to implement -cov switch (coverage analysis).
52: */
53:
54: elem *incUsageElem(IRState *irs, Loc loc)
55: {
56: unsigned linnum = loc.linnum;
57:
58: if (!irs->blx->module->cov || !linnum ||
59: loc.filename != irs->blx->module->srcfile->toChars())
60: return NULL;
61:
62: //printf("cov = %p, covb = %p, linnum = %u\n", irs->blx->module->cov, irs->blx->module->covb, p, linnum);
63:
64: linnum--; // from 1-based to 0-based
65:
66: /* Set bit in covb[] indicating this is a valid code line number
67: */
68: unsigned *p = irs->blx->module->covb;
69: if (p) // covb can be NULL if it has already been written out to its .obj file
70: {
71: p += linnum / (sizeof(*p) * 8);
72: *p |= 1 << (linnum & (sizeof(*p) * 8 - 1));
73: }
74:
75: elem *e;
76: e = el_ptr(irs->blx->module->cov);
77: e = el_bin(OPadd, TYnptr, e, el_long(TYuint, linnum * 4));
78: e = el_una(OPind, TYuint, e);
79: e = el_bin(OPaddass, TYuint, e, el_long(TYuint, 1));
80: return e;
81: }
82:
83: /******************************************
84: * Return elem that evaluates to the static frame pointer for function fd.
85: * If fd is a member function, the returned expression will compute the value
86: * of fd's 'this' variable.
87: * This routine is critical for implementing nested functions.
88: */
89:
90: elem *getEthis(Loc loc, IRState *irs, Dsymbol *fd)
91: {
92: elem *ethis;
93: FuncDeclaration *thisfd = irs->getFunc();
94: Dsymbol *fdparent = fd->toParent2();
95:
96: //printf("getEthis(thisfd = '%s', fd = '%s', fdparent = '%s')\n", thisfd->toPrettyChars(), fd->toPrettyChars(), fdparent->toPrettyChars());
97: if (fdparent == thisfd ||
98: /* These two are compiler generated functions for the in and out contracts,
99: * and are called from an overriding function, not just the one they're
100: * nested inside, so this hack is so they'll pass
101: */
102: fd->ident == Id::require || fd->ident == Id::ensure)
103: { /* Going down one nesting level, i.e. we're calling
104: * a nested function from its enclosing function.
105: */
106: #if DMDV2
107: if (irs->sclosure)
108: ethis = el_var(irs->sclosure);
109: else
110: #endif
111: if (irs->sthis)
112: { // We have a 'this' pointer for the current function
113: ethis = el_var(irs->sthis);
114:
115: /* If no variables in the current function's frame are
116: * referenced by nested functions, then we can 'skip'
117: * adding this frame into the linked list of stack
118: * frames.
119: */
120: #if DMDV2
121: if (thisfd->closureVars.dim)
122: #else
123: if (thisfd->nestedFrameRef)
124: #endif
125: { /* Local variables are referenced, can't skip.
126: * Address of 'this' gives the 'this' for the nested
127: * function
128: */
129: ethis = el_una(OPaddr, TYnptr, ethis);
130: }
131: }
132: else
133: { /* No 'this' pointer for current function,
134: * use NULL if no references to the current function's frame
135: */
136: ethis = el_long(TYnptr, 0);
137: #if DMDV2
138: if (thisfd->closureVars.dim)
139: #else
140: if (thisfd->nestedFrameRef)
141: #endif
142: { /* OPframeptr is an operator that gets the frame pointer
143: * for the current function, i.e. for the x86 it gets
144: * the value of EBP
145: */
146: ethis->Eoper = OPframeptr;
147: }
148: }
149: //if (fdparent != thisfd) ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYint, 0x18));
150: }
151: else
152: {
153: if (!irs->sthis) // if no frame pointer for this function
154: {
155: fd->error(loc, "is a nested function and cannot be accessed from %s", irs->getFunc()->toChars());
156: ethis = el_long(TYnptr, 0); // error recovery
157: }
158: else
159: {
160: ethis = el_var(irs->sthis);
161: Dsymbol *s = thisfd;
162: while (fd != s)
163: { /* Go up a nesting level, i.e. we need to find the 'this'
164: * of an enclosing function.
165: * Our 'enclosing function' may also be an inner class.
166: */
167:
168: //printf("\ts = '%s'\n", s->toChars());
169: thisfd = s->isFuncDeclaration();
170: if (thisfd)
171: { /* Enclosing function is a function.
172: */
173: if (fdparent == s->toParent2())
174: break;
175: if (thisfd->isNested())
176: {
177: FuncDeclaration *p = s->toParent2()->isFuncDeclaration();
178: #if DMDV2
179: if (!p || p->closureVars.dim)
180: #else
181: if (!p || p->nestedFrameRef)
182: #endif
183: ethis = el_una(OPind, TYnptr, ethis);
184: }
185: else if (thisfd->vthis)
186: {
187: }
188: else
189: // Error should have been caught by front end
190: assert(0);
191: }
192: else
193: { /* Enclosed by an aggregate. That means the current
194: * function must be a member function of that aggregate.
195: */
196: ClassDeclaration *cd;
197: StructDeclaration *sd;
198: AggregateDeclaration *ad = s->isAggregateDeclaration();
199: if (!ad)
200: goto Lnoframe;
201: cd = s->isClassDeclaration();
202: if (cd && fd->isClassDeclaration() &&
203: fd->isClassDeclaration()->isBaseOf(cd, NULL))
204: break;
205: sd = s->isStructDeclaration();
206: if (fd == sd)
207: break;
208: if (!ad->isNested() || !ad->vthis)
209: {
210: Lnoframe:
211: irs->getFunc()->error(loc, "cannot get frame pointer to %s", fd->toChars());
212: return el_long(TYnptr, 0); // error recovery
213: }
214: ethis = el_bin(OPadd, TYnptr, ethis, el_long(TYsize_t, ad->vthis->offset));
215: ethis = el_una(OPind, TYnptr, ethis);
216: if (fdparent == s->toParent2())
217: break;
218: if (fd == s->toParent2())
219: {
220: /* Remember that frames for functions that have no
221: * nested references are skipped in the linked list
222: * of frames.
223: */
224: #if DMDV2
225: if (s->toParent2()->isFuncDeclaration()->closureVars.dim)
226: #else
227: if (s->toParent2()->isFuncDeclaration()->nestedFrameRef)
228: #endif
229: ethis = el_una(OPind, TYnptr, ethis);
230: break;
231: }
232: if (s->toParent2()->isFuncDeclaration())
233: {
234: /* Remember that frames for functions that have no
235: * nested references are skipped in the linked list
236: * of frames.
237: */
238: #if DMDV2
239: if (s->toParent2()->isFuncDeclaration()->closureVars.dim)
240: #else
241: if (s->toParent2()->isFuncDeclaration()->nestedFrameRef)
242: #endif
243: ethis = el_una(OPind, TYnptr, ethis);
244: }
245: }
246: s = s->toParent2();
247: assert(s);
248: }
249: }
250: }
251: #if 0
252: printf("ethis:\n");
253: elem_print(ethis);
254: printf("\n");
255: #endif
256: return ethis;
257: }
258:
259:
260: /*************************
261: * Initialize the hidden aggregate member, vthis, with
262: * the context pointer.
263: * Returns:
264: * *(ey + ad.vthis.offset) = this;
265: */
266: #if DMDV2
267: elem *setEthis(Loc loc, IRState *irs, elem *ey, AggregateDeclaration *ad)
268: {
269: elem *ethis;
270: FuncDeclaration *thisfd = irs->getFunc();
271: int offset = 0;
272: Dsymbol *cdp = ad->toParent2(); // class/func we're nested in
273:
274: //printf("setEthis(ad = %s, cdp = %s, thisfd = %s)\n", ad->toChars(), cdp->toChars(), thisfd->toChars());
275:
276: if (cdp == thisfd)
277: { /* Class we're new'ing is a local class in this function:
278: * void thisfd() { class ad { } }
279: */
280: if (irs->sclosure)
281: ethis = el_var(irs->sclosure);
282: else if (irs->sthis)
283: {
284: #if DMDV2
285: if (thisfd->closureVars.dim)
286: #else
287: if (thisfd->nestedFrameRef)
288: #endif
289: {
290: ethis = el_ptr(irs->sthis);
291: }
292: else
293: ethis = el_var(irs->sthis);
294: }
295: else
296: {
297: ethis = el_long(TYnptr, 0);
298: #if DMDV2
299: if (thisfd->closureVars.dim)
300: #else
301: if (thisfd->nestedFrameRef)
302: #endif
303: {
304: ethis->Eoper = OPframeptr;
305: }
306: }
307: }
308: else if (thisfd->vthis &&
309: (cdp == thisfd->toParent2() ||
310: (cdp->isClassDeclaration() &&
311: cdp->isClassDeclaration()->isBaseOf(thisfd->toParent2()->isClassDeclaration(), &offset)
312: )
313: )
314: )
315: { /* Class we're new'ing is at the same level as thisfd
316: */
317: assert(offset == 0); // BUG: should handle this case
318: ethis = el_var(irs->sthis);
319: }
320: else
321: {
322: ethis = getEthis(loc, irs, ad->toParent2());
323: ethis = el_una(OPaddr, TYnptr, ethis);
324: }
325:
326: ey = el_bin(OPadd, TYnptr, ey, el_long(TYsize_t, ad->vthis->offset));
327: ey = el_una(OPind, TYnptr, ey);
328: ey = el_bin(OPeq, TYnptr, ey, ethis);
329: return ey;
330: }
331: #endif
332:
333: /*******************************************
334: * Convert intrinsic function to operator.
335: * Returns that operator, -1 if not an intrinsic function.
336: */
337:
338: int intrinsic_op(char *name)
339: {
340: //printf("intrinsic_op(%s)\n", name);
341: static const char *std_namearray[] =
342: {
343: #if DMDV1
344: "4math3cosFeZe",
345: "4math3sinFeZe",
346: "4math4fabsFeZe",
347: "4math4rintFeZe",
348: "4math4sqrtFdZd",
349: "4math4sqrtFeZe",
350: "4math4sqrtFfZf",
351: "4math4yl2xFeeZe",
352: "4math5ldexpFeiZe",
353: "4math6rndtolFeZl",
354: "4math6yl2xp1FeeZe",
355:
356: "9intrinsic2btFPkkZi",
357: "9intrinsic3bsfFkZi",
358: "9intrinsic3bsrFkZi",
359: "9intrinsic3btcFPkkZi",
360: "9intrinsic3btrFPkkZi",
361: "9intrinsic3btsFPkkZi",
362: "9intrinsic3inpFkZh",
363: "9intrinsic4inplFkZk",
364: "9intrinsic4inpwFkZt",
365: "9intrinsic4outpFkhZh",
366: "9intrinsic5bswapFkZk",
367: "9intrinsic5outplFkkZk",
368: "9intrinsic5outpwFktZt",
369: #elif DMDV2
370: /* The names are mangled differently because of the pure and
371: * nothrow attributes.
372: */
373: "4math3cosFNaNbNfeZe",
374: "4math3sinFNaNbNfeZe",
375: "4math4fabsFNaNbNfeZe",
376: "4math4rintFNaNbNfeZe",
377: "4math4sqrtFNaNbNfdZd",
378: "4math4sqrtFNaNbNfeZe",
379: "4math4sqrtFNaNbNffZf",
380: "4math4yl2xFNaNbNfeeZe",
381: "4math5ldexpFNaNbNfeiZe",
382: "4math6rndtolFNaNbNfeZl",
383: "4math6yl2xp1FNaNbNfeeZe",
384:
385: "9intrinsic2btFNaNbxPkkZi",
386: "9intrinsic3bsfFNaNbkZi",
387: "9intrinsic3bsrFNaNbkZi",
388: "9intrinsic3btcFNbPkkZi",
389: "9intrinsic3btrFNbPkkZi",
390: "9intrinsic3btsFNbPkkZi",
391: "9intrinsic3inpFNbkZh",
392: "9intrinsic4inplFNbkZk",
393: "9intrinsic4inpwFNbkZt",
394: "9intrinsic4outpFNbkhZh",
395: "9intrinsic5bswapFNaNbkZk",
396: "9intrinsic5outplFNbkkZk",
397: "9intrinsic5outpwFNbktZt",
398: #endif
399: };
400: static const char *std_namearray64[] =
401: {
402: #if DMDV1
403: "4math3cosFeZe",
404: "4math3sinFeZe",
405: "4math4fabsFeZe",
406: "4math4rintFeZe",
407: "4math4sqrtFdZd",
408: "4math4sqrtFeZe",
409: "4math4sqrtFfZf",
410: "4math4yl2xFeeZe",
411: "4math5ldexpFeiZe",
412: "4math6rndtolFeZl",
413: "4math6yl2xp1FeeZe",
414:
415: "9intrinsic2btFPmmZi",
416: "9intrinsic3bsfFkZi",
417: "9intrinsic3bsrFkZi",
418: "9intrinsic3btcFPmmZi",
419: "9intrinsic3btrFPmmZi",
420: "9intrinsic3btsFPmmZi",
421: "9intrinsic3inpFkZh",
422: "9intrinsic4inplFkZk",
423: "9intrinsic4inpwFkZt",
424: "9intrinsic4outpFkhZh",
425: "9intrinsic5bswapFkZk",
426: "9intrinsic5outplFkkZk",
427: "9intrinsic5outpwFktZt",
428: #elif DMDV2
429: /* The names are mangled differently because of the pure and
430: * nothrow attributes.
431: */
432: "4math3cosFNaNbNfeZe",
433: "4math3sinFNaNbNfeZe",
434: "4math4fabsFNaNbNfeZe",
435: "4math4rintFNaNbNfeZe",
436: "4math4sqrtFNaNbNfdZd",
437: "4math4sqrtFNaNbNfeZe",
438: "4math4sqrtFNaNbNffZf",
439: "4math4yl2xFNaNbNfeeZe",
440: "4math5ldexpFNaNbNfeiZe",
441: "4math6rndtolFNaNbNfeZl",
442: "4math6yl2xp1FNaNbNfeeZe",
443:
444: "9intrinsic2btFNaNbxPmmZi",
445: "9intrinsic3bsfFNaNbmZi",
446: "9intrinsic3bsrFNaNbmZi",
447: "9intrinsic3btcFNbPmmZi",
448: "9intrinsic3btrFNbPmmZi",
449: "9intrinsic3btsFNbPmmZi",
450: "9intrinsic3inpFNbkZh",
451: "9intrinsic4inplFNbkZk",
452: "9intrinsic4inpwFNbkZt",
453: "9intrinsic4outpFNbkhZh",
454: "9intrinsic5bswapFNaNbkZk",
455: "9intrinsic5outplFNbkkZk",
456: "9intrinsic5outpwFNbktZt",
457: #endif
458: };
459: static unsigned char std_ioptab[] =
460: {
461: OPcos,
462: OPsin,
463: OPabs,
464: OPrint,
465: OPsqrt,
466: OPsqrt,
467: OPsqrt,
468: OPyl2x,
469: OPscale,
470: OPrndtol,
471: OPyl2xp1,
472:
473: OPbt,
474: OPbsf,
475: OPbsr,
476: OPbtc,
477: OPbtr,
478: OPbts,
479: OPinp,
480: OPinp,
481: OPinp,
482: OPoutp,
483: OPbswap,
484: OPoutp,
485: OPoutp,
486: };
487:
488: #ifdef DMDV2
489: static const char *core_namearray[] =
490: {
491: "4math3cosFNaNbNfeZe",
492: "4math3sinFNaNbNfeZe",
493: "4math4fabsFNaNbNfeZe",
494: "4math4rintFNaNbNfeZe",
495: "4math4sqrtFNaNbNfdZd",
496: "4math4sqrtFNaNbNfeZe",
497: "4math4sqrtFNaNbNffZf",
498: "4math4yl2xFNaNbNfeeZe",
499: "4math5ldexpFNaNbNfeiZe",
500: "4math6rndtolFNaNbNfeZl",
501: "4math6yl2xp1FNaNbNfeeZe",
502:
503: "5bitop2btFNaNbxPkkZi",
504: "5bitop3bsfFNaNbkZi",
505: "5bitop3bsrFNaNbkZi",
506: "5bitop3btcFNbPkkZi",
507: "5bitop3btrFNbPkkZi",
508: "5bitop3btsFNbPkkZi",
509: "5bitop3inpFNbkZh",
510: "5bitop4inplFNbkZk",
511: "5bitop4inpwFNbkZt",
512: "5bitop4outpFNbkhZh",
513: "5bitop5bswapFNaNbkZk",
514: "5bitop5outplFNbkkZk",
515: "5bitop5outpwFNbktZt",
516: };
517: static const char *core_namearray64[] =
518: {
519: "4math3cosFNaNbNfeZe",
520: "4math3sinFNaNbNfeZe",
521: "4math4fabsFNaNbNfeZe",
522: "4math4rintFNaNbNfeZe",
523: "4math4sqrtFNaNbNfdZd",
524: "4math4sqrtFNaNbNfeZe",
525: "4math4sqrtFNaNbNffZf",
526: "4math4yl2xFNaNbNfeeZe",
527: "4math5ldexpFNaNbNfeiZe",
528: "4math6rndtolFNaNbNfeZl",
529: "4math6yl2xp1FNaNbNfeeZe",
530:
531: "5bitop2btFNaNbxPmmZi",
532: "5bitop3bsfFNaNbmZi",
533: "5bitop3bsrFNaNbmZi",
534: "5bitop3btcFNbPmmZi",
535: "5bitop3btrFNbPmmZi",
536: "5bitop3btsFNbPmmZi",
537: "5bitop3inpFNbkZh",
538: "5bitop4inplFNbkZk",
539: "5bitop4inpwFNbkZt",
540: "5bitop4outpFNbkhZh",
541: "5bitop5bswapFNaNbkZk",
542: "5bitop5outplFNbkkZk",
543: "5bitop5outpwFNbktZt",
544: };
545: static unsigned char core_ioptab[] =
546: {
547: OPcos,
548: OPsin,
549: OPabs,
550: OPrint,
551: OPsqrt,
552: OPsqrt,
553: OPsqrt,
554: OPyl2x,
555: OPscale,
556: OPrndtol,
557: OPyl2xp1,
558:
559: OPbt,
560: OPbsf,
561: OPbsr,
562: OPbtc,
563: OPbtr,
564: OPbts,
565: OPinp,
566: OPinp,
567: OPinp,
568: OPoutp,
569: OPbswap,
570: OPoutp,
571: OPoutp,
572: };
573: #endif
574:
575: #ifdef DEBUG
576: assert(sizeof(std_namearray) == sizeof(std_namearray64));
577: assert(sizeof(std_namearray) / sizeof(char *) == sizeof(std_ioptab));
578: for (int i = 0; i < sizeof(std_namearray) / sizeof(char *) - 1; i++)
579: {
580: if (strcmp(std_namearray[i], std_namearray[i + 1]) >= 0)
581: {
582: printf("std_namearray[%d] = '%s'\n", i, std_namearray[i]);
583: assert(0);
584: }
585: }
586: assert(sizeof(std_namearray64) / sizeof(char *) == sizeof(std_ioptab));
587: for (int i = 0; i < sizeof(std_namearray64) / sizeof(char *) - 1; i++)
588: {
589: if (strcmp(std_namearray64[i], std_namearray64[i + 1]) >= 0)
590: {
591: printf("std_namearray64[%d] = '%s'\n", i, std_namearray64[i]);
592: assert(0);
593: }
594: }
595: #ifdef DMDV2
596: assert(sizeof(core_namearray) == sizeof(core_namearray64));
597: assert(sizeof(core_namearray) / sizeof(char *) == sizeof(core_ioptab));
598: for (int i = 0; i < sizeof(core_namearray) / sizeof(char *) - 1; i++)
599: {
600: if (strcmp(core_namearray[i], core_namearray[i + 1]) >= 0)
601: {
602: printf("core_namearray[%d] = '%s'\n", i, core_namearray[i]);
603: assert(0);
604: }
605: }
606: assert(sizeof(core_namearray64) / sizeof(char *) == sizeof(core_ioptab));
607: for (int i = 0; i < sizeof(core_namearray64) / sizeof(char *) - 1; i++)
608: {
609: if (strcmp(core_namearray64[i], core_namearray64[i + 1]) >= 0)
610: {
611: printf("core_namearray64[%d] = '%s'\n", i, core_namearray64[i]);
612: assert(0);
613: }
614: }
615: #endif
616: #endif
617: size_t length = strlen(name);
618:
619: if (length > 10 &&
620: (name[7] == 'm' || name[7] == 'i') &&
621: !memcmp(name, "_D3std", 6))
622: {
623: int i = binary(name + 6, I64 ? std_namearray64 : std_namearray, sizeof(std_namearray) / sizeof(char *));
624: return (i == -1) ? i : std_ioptab[i];
625: }
626: #ifdef DMDV2
627: if (length > 12 &&
628: (name[8] == 'm' || name[8] == 'b') &&
629: !memcmp(name, "_D4core", 7))
630: {
631: int i = binary(name + 7, I64 ? core_namearray64 : core_namearray, sizeof(core_namearray) / sizeof(char *));
632: return (i == -1) ? i : core_ioptab[i];
633: }
634: #endif
635: return -1;
636: }
637:
638:
639: /**************************************
640: * Given an expression e that is an array,
641: * determine and set the 'length' variable.
642: * Input:
643: * lengthVar Symbol of 'length' variable
644: * &e expression that is the array
645: * t1 Type of the array
646: * Output:
647: * e is rewritten to avoid side effects
648: * Returns:
649: * expression that initializes 'length'
650: */
651:
652: elem *resolveLengthVar(VarDeclaration *lengthVar, elem **pe, Type *t1)
653: {
654: //printf("resolveLengthVar()\n");
655: elem *einit = NULL;
656:
657: if (lengthVar && !(lengthVar->storage_class & STCconst))
658: { elem *elength;
659: Symbol *slength;
660:
661: if (t1->ty == Tsarray)
662: { TypeSArray *tsa = (TypeSArray *)t1;
663: dinteger_t length = tsa->dim->toInteger();
664:
665: elength = el_long(TYsize_t, length);
666: goto L3;
667: }
668: else if (t1->ty == Tarray)
669: {
670: elength = *pe;
671: *pe = el_same(&elength);
672: elength = el_una(I64 ? OP128_64 : OP64_32, TYsize_t, elength);
673:
674: L3:
675: slength = lengthVar->toSymbol();
676: //symbol_add(slength);
677:
678: einit = el_bin(OPeq, TYsize_t, el_var(slength), elength);
679: }
680: }
681: return einit;
682: }
683:
684: /*************************************
685: * Closures are implemented by taking the local variables that
686: * need to survive the scope of the function, and copying them
687: * into a gc allocated chuck of memory. That chunk, called the
688: * closure here, is inserted into the linked list of stack
689: * frames instead of the usual stack frame.
690: *
691: * buildClosure() inserts code just after the function prolog
692: * is complete. It allocates memory for the closure, allocates
693: * a local variable (sclosure) to point to it, inserts into it
694: * the link to the enclosing frame, and copies into it the parameters
695: * that are referred to in nested functions.
696: * In VarExp::toElem and SymOffExp::toElem, when referring to a
697: * variable that is in a closure, takes the offset from sclosure rather
698: * than from the frame pointer.
699: *
700: * getEthis() and NewExp::toElem need to use sclosure, if set, rather
701: * than the current frame pointer.
702: */
703:
704: #if DMDV2
705:
706: void FuncDeclaration::buildClosure(IRState *irs)
707: {
708: if (needsClosure())
709: { // Generate closure on the heap
710: // BUG: doesn't capture variadic arguments passed to this function
711:
712: #if DMDV2
713: /* BUG: doesn't handle destructors for the local variables.
714: * The way to do it is to make the closure variables the fields
715: * of a class object:
716: * class Closure
717: * { vtbl[]
718: * monitor
719: * ptr to destructor
720: * sthis
721: * ... closure variables ...
722: * ~this() { call destructor }
723: * }
724: */
725: #endif
726: //printf("FuncDeclaration::buildClosure()\n");
727: Symbol *sclosure;
728: sclosure = symbol_name("__closptr",SCauto,Type::tvoidptr->toCtype());
729: sclosure->Sflags |= SFLtrue | SFLfree;
730: symbol_add(sclosure);
731: irs->sclosure = sclosure;
732:
733: unsigned offset = PTRSIZE; // leave room for previous sthis
734: for (int i = 0; i < closureVars.dim; i++)
warning C4018: '<' : signed/unsigned mismatch
735: { VarDeclaration *v = closureVars.tdata()[i];
736: assert(v->isVarDeclaration());
737:
738: #if DMDV2
739: if (v->needsAutoDtor())
740: /* Because the value needs to survive the end of the scope!
741: */
742: v->error("has scoped destruction, cannot build closure");
743: if (v->isargptr)
744: /* See Bugzilla 2479
745: * This is actually a bug, but better to produce a nice
746: * message at compile time rather than memory corruption at runtime
747: */
748: v->error("cannot reference variadic arguments from closure");
749: #endif
750: /* Align and allocate space for v in the closure
751: * just like AggregateDeclaration::addField() does.
752: */
753: unsigned memsize;
754: unsigned memalignsize;
755: unsigned xalign;
756: #if DMDV2
757: if (v->storage_class & STClazy)
758: {
759: /* Lazy variables are really delegates,
760: * so give same answers that TypeDelegate would
761: */
762: memsize = PTRSIZE * 2;
763: memalignsize = memsize;
764: xalign = global.structalign;
765: }
766: else if (v->isRef() || v->isOut())
767: { // reference parameters are just pointers
768: memsize = PTRSIZE;
769: memalignsize = memsize;
770: xalign = global.structalign;
771: }
772: else
773: #endif
774: {
775: memsize = v->type->size();
warning C4244: '=' : conversion from 'd_uns64' to 'unsigned int', possible loss of data
776: memalignsize = v->type->alignsize();
777: xalign = v->type->memalign(global.structalign);
778: }
779: AggregateDeclaration::alignmember(xalign, memalignsize, &offset);
780: v->offset = offset;
781: offset += memsize;
782:
783: /* Can't do nrvo if the variable is put in a closure, since
784: * what the shidden points to may no longer exist.
785: */
786: if (nrvo_can && nrvo_var == v)
787: {
788: nrvo_can = 0;
789: }
790: }
791: // offset is now the size of the closure
792:
793: // Allocate memory for the closure
794: elem *e;
795: e = el_long(TYsize_t, offset);
796: e = el_bin(OPcall, TYnptr, el_var(rtlsym[RTLSYM_ALLOCMEMORY]), e);
797:
798: // Assign block of memory to sclosure
799: // sclosure = allocmemory(sz);
800: e = el_bin(OPeq, TYvoid, el_var(sclosure), e);
801:
802: // Set the first element to sthis
803: // *(sclosure + 0) = sthis;
804: elem *ethis;
805: if (irs->sthis)
806: ethis = el_var(irs->sthis);
807: else
808: ethis = el_long(TYnptr, 0);
809: elem *ex = el_una(OPind, TYnptr, el_var(sclosure));
810: ex = el_bin(OPeq, TYnptr, ex, ethis);
811: e = el_combine(e, ex);
812:
813: // Copy function parameters into closure
814: for (int i = 0; i < closureVars.dim; i++)
warning C4018: '<' : signed/unsigned mismatch
815: { VarDeclaration *v = closureVars.tdata()[i];
816:
817: if (!v->isParameter())
818: continue;
819: tym_t tym = v->type->totym();
820: if (
821: #if !SARRAYVALUE
822: v->type->toBasetype()->ty == Tsarray ||
823: #endif
824: v->isOut() || v->isRef())
825: tym = TYnptr; // reference parameters are just pointers
826: #if DMDV2
827: else if (v->storage_class & STClazy)
828: tym = TYdelegate;
829: #endif
830: ex = el_bin(OPadd, TYnptr, el_var(sclosure), el_long(TYsize_t, v->offset));
831: ex = el_una(OPind, tym, ex);
832: if (tybasic(ex->Ety) == TYstruct || tybasic(ex->Ety) == TYarray)
833: {
834: ::type *t = v->type->toCtype();
835: ex->ET = t;
836: ex = el_bin(OPstreq, tym, ex, el_var(v->toSymbol()));
837: ex->ET = t;
838: }
839: else
840: ex = el_bin(OPeq, tym, ex, el_var(v->toSymbol()));
841:
842: e = el_combine(e, ex);
843: }
844:
845: block_appendexp(irs->blx->curblock, e);
846: }
847: }
848:
849: #endif
850:
851: /***************************
852: * Determine return style of function - whether in registers or
853: * through a hidden pointer to the caller's stack.
854: */
855:
856: enum RET TypeFunction::retStyle()
857: {
858: //printf("TypeFunction::retStyle() %s\n", toChars());
859: #if DMDV2
860: if (isref)
861: return RETregs; // returns a pointer
862: #endif
863:
864: Type *tn = next->toBasetype();
865: Type *tns = tn;
866: d_uns64 sz = tn->size();
867:
868: #if SARRAYVALUE
869: if (tn->ty == Tsarray)
870: {
871: do
872: {
873: tns = tns->nextOf()->toBasetype();
874: } while (tns->ty == Tsarray);
875: if (tns->ty != Tstruct)
876: {
877: if (global.params.isLinux && linkage != LINKd)
878: ;
879: else
880: {
881: switch (sz)
882: { case 1:
883: case 2:
884: case 4:
885: case 8:
886: return RETregs; // return small structs in regs
887: // (not 3 byte structs!)
888: default:
889: break;
890: }
891: }
892: return RETstack;
893: }
894: }
895: #endif
896:
897: if (tns->ty == Tstruct)
898: { StructDeclaration *sd = ((TypeStruct *)tn)->sym;
899: if (global.params.isLinux && linkage != LINKd)
900: ;
901: #if DMDV2
902: else if (sd->dtor || sd->cpctor)
903: ;
904: #endif
905: else
906: {
907: switch (sz)
908: { case 1:
909: case 2:
910: case 4:
911: case 8:
912: return RETregs; // return small structs in regs
913: // (not 3 byte structs!)
914: default:
915: break;
916: }
917: }
918: return RETstack;
919: }
920: else if ((global.params.isLinux || global.params.isOSX || global.params.isFreeBSD || global.params.isSolaris) &&
921: linkage == LINKc &&
922: tn->iscomplex())
923: {
924: if (tn->ty == Tcomplex32)
925: return RETregs; // in EDX:EAX, not ST1:ST0
926: else
927: return RETstack;
928: }
929: else
930: return RETregs;
931: }
932:
933:
934: