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: