1:
2: // Copyright (c) 1999-2011 by Digital Mars
3: // All Rights Reserved
4: // written by Walter Bright
5: // http://www.digitalmars.com
6: // License for redistribution is by either the Artistic License
7: // in artistic.txt, or the GNU General Public License in gnu.txt.
8: // See the included readme.txt for details.
9:
10: // Routines to perform function inlining
11:
12: #define LOG 0
13:
14: #include <stdio.h>
15: #include <stdlib.h>
16: static char __file__[] = __FILE__; /* for tassert.h */
17: #include "tassert.h"
18:
19: #include "id.h"
20: #include "init.h"
21: #include "declaration.h"
22: #include "aggregate.h"
23: #include "expression.h"
24: #include "statement.h"
25: #include "mtype.h"
26: #include "scope.h"
27:
28: /* ========== Compute cost of inlining =============== */
29:
30: /* Walk trees to determine if inlining can be done, and if so,
31: * if it is too complex to be worth inlining or not.
32: */
33:
34: struct InlineCostState
35: {
36: int nested;
37: int hasthis;
38: int hdrscan; // !=0 if inline scan for 'header' content
39: FuncDeclaration *fd;
40: };
41:
42: const int COST_MAX = 250;
43:
44: int Statement::inlineCost(InlineCostState *ics)
45: {
46: return COST_MAX; // default is we can't inline it
47: }
48:
49: int ExpStatement::inlineCost(InlineCostState *ics)
50: {
51: return exp ? exp->inlineCost(ics) : 0;
52: }
53:
54: int CompoundStatement::inlineCost(InlineCostState *ics)
55: { int cost = 0;
56:
57: for (size_t i = 0; i < statements->dim; i++)
58: { Statement *s = statements->tdata()[i];
59: if (s)
60: {
61: cost += s->inlineCost(ics);
62: if (cost >= COST_MAX)
63: break;
64: }
65: }
66: return cost;
67: }
68:
69: int UnrolledLoopStatement::inlineCost(InlineCostState *ics)
70: { int cost = 0;
71:
72: for (size_t i = 0; i < statements->dim; i++)
73: { Statement *s = statements->tdata()[i];
74: if (s)
75: {
76: cost += s->inlineCost(ics);
77: if (cost >= COST_MAX)
78: break;
79: }
80: }
81: return cost;
82: }
83:
84: int IfStatement::inlineCost(InlineCostState *ics)
85: {
86: int cost;
87:
88: /* Can't declare variables inside ?: expressions, so
89: * we cannot inline if a variable is declared.
90: */
91: if (arg)
92: return COST_MAX;
93:
94: cost = condition->inlineCost(ics);
95:
96: /* Specifically allow:
97: * if (condition)
98: * return exp1;
99: * else
100: * return exp2;
101: * Otherwise, we can't handle return statements nested in if's.
102: */
103:
104: if (elsebody && ifbody &&
105: ifbody->isReturnStatement() &&
106: elsebody->isReturnStatement())
107: {
108: cost += ifbody->inlineCost(ics);
109: cost += elsebody->inlineCost(ics);
110: //printf("cost = %d\n", cost);
111: }
112: else
113: {
114: ics->nested += 1;
115: if (ifbody)
116: cost += ifbody->inlineCost(ics);
117: if (elsebody)
118: cost += elsebody->inlineCost(ics);
119: ics->nested -= 1;
120: }
121: return cost;
122: }
123:
124: int ReturnStatement::inlineCost(InlineCostState *ics)
125: {
126: // Can't handle return statements nested in if's
127: if (ics->nested)
128: return COST_MAX;
129: return exp ? exp->inlineCost(ics) : 0;
130: }
131:
132: int ImportStatement::inlineCost(InlineCostState *ics)
133: {
134: return 0;
135: }
136:
137: /* -------------------------- */
138:
139: int arrayInlineCost(InlineCostState *ics, Expressions *arguments)
140: { int cost = 0;
141:
142: if (arguments)
143: {
144: for (int i = 0; i < arguments->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
145: { Expression *e = arguments->tdata()[i];
146:
147: if (e)
148: cost += e->inlineCost(ics);
149: }
150: }
151: return cost;
152: }
153:
154: int Expression::inlineCost(InlineCostState *ics)
155: {
156: return 1;
157: }
158:
159: int VarExp::inlineCost(InlineCostState *ics)
160: {
161: //printf("VarExp::inlineCost() %s\n", toChars());
162: return 1;
163: }
164:
165: int ThisExp::inlineCost(InlineCostState *ics)
166: {
167: //printf("ThisExp::inlineCost() %s\n", toChars());
168: FuncDeclaration *fd = ics->fd;
169: if (!fd)
170: return COST_MAX;
171: if (!ics->hdrscan)
172: if (fd->isNested() || !ics->hasthis)
173: return COST_MAX;
174: return 1;
175: }
176:
177: int SuperExp::inlineCost(InlineCostState *ics)
178: {
179: FuncDeclaration *fd = ics->fd;
180: if (!fd)
181: return COST_MAX;
182: if (!ics->hdrscan)
183: if (fd->isNested() || !ics->hasthis)
184: return COST_MAX;
185: return 1;
186: }
187:
188: int TupleExp::inlineCost(InlineCostState *ics)
189: {
190: return 1 + arrayInlineCost(ics, exps);
191: }
192:
193: int ArrayLiteralExp::inlineCost(InlineCostState *ics)
194: {
195: return 1 + arrayInlineCost(ics, elements);
196: }
197:
198: int AssocArrayLiteralExp::inlineCost(InlineCostState *ics)
199: {
200: return 1 + arrayInlineCost(ics, keys) + arrayInlineCost(ics, values);
201: }
202:
203: int StructLiteralExp::inlineCost(InlineCostState *ics)
204: {
205: return 1 + arrayInlineCost(ics, elements);
206: }
207:
208: int FuncExp::inlineCost(InlineCostState *ics)
209: {
210: //printf("FuncExp::inlineCost()\n");
211: // Right now, this makes the function be output to the .obj file twice.
212: return COST_MAX;
213: }
214:
215: int DelegateExp::inlineCost(InlineCostState *ics)
216: {
217: return COST_MAX;
218: }
219:
220: int DeclarationExp::inlineCost(InlineCostState *ics)
221: { int cost = 0;
222: VarDeclaration *vd;
223:
224: //printf("DeclarationExp::inlineCost()\n");
225: vd = declaration->isVarDeclaration();
226: if (vd)
227: {
228: TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
229: if (td)
230: {
231: #if 1
232: return COST_MAX; // finish DeclarationExp::doInline
233: #else
234: for (size_t i = 0; i < td->objects->dim; i++)
235: { Object *o = td->objects->tdata()[i];
236: if (o->dyncast() != DYNCAST_EXPRESSION)
237: return COST_MAX;
238: Expression *eo = (Expression *)o;
239: if (eo->op != TOKdsymbol)
240: return COST_MAX;
241: }
242: return td->objects->dim;
243: #endif
244: }
245: if (!ics->hdrscan && vd->isDataseg())
246: return COST_MAX;
247: cost += 1;
248:
249: if (vd->edtor) // if destructor required
250: return COST_MAX; // needs work to make this work
251:
252: // Scan initializer (vd->init)
253: if (vd->init)
254: {
255: ExpInitializer *ie = vd->init->isExpInitializer();
256:
257: if (ie)
258: {
259: cost += ie->exp->inlineCost(ics);
260: }
261: }
262: }
263:
264: // These can contain functions, which when copied, get output twice.
265: if (declaration->isStructDeclaration() ||
266: declaration->isClassDeclaration() ||
267: declaration->isFuncDeclaration() ||
268: declaration->isTypedefDeclaration() ||
269: declaration->isAttribDeclaration() ||
270: declaration->isTemplateMixin())
271: return COST_MAX;
272:
273: //printf("DeclarationExp::inlineCost('%s')\n", toChars());
274: return cost;
275: }
276:
277: int UnaExp::inlineCost(InlineCostState *ics)
278: {
279: return 1 + e1->inlineCost(ics);
280: }
281:
282: int AssertExp::inlineCost(InlineCostState *ics)
283: {
284: return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0);
285: }
286:
287: int BinExp::inlineCost(InlineCostState *ics)
288: {
289: return 1 + e1->inlineCost(ics) + e2->inlineCost(ics);
290: }
291:
292: int CallExp::inlineCost(InlineCostState *ics)
293: {
294: // Bugzilla 3500: super.func() calls must be devirtualized, and the inliner
295: // can't handle that at present.
296: if (e1->op == TOKdotvar && ((DotVarExp *)e1)->e1->op == TOKsuper)
297: return COST_MAX;
298:
299: return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments);
300: }
301:
302: int SliceExp::inlineCost(InlineCostState *ics)
303: { int cost;
304:
305: cost = 1 + e1->inlineCost(ics);
306: if (lwr)
307: cost += lwr->inlineCost(ics);
308: if (upr)
309: cost += upr->inlineCost(ics);
310: return cost;
311: }
312:
313: int ArrayExp::inlineCost(InlineCostState *ics)
314: {
315: return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments);
316: }
317:
318:
319: int CondExp::inlineCost(InlineCostState *ics)
320: {
321: return 1 +
322: e1->inlineCost(ics) +
323: e2->inlineCost(ics) +
324: econd->inlineCost(ics);
325: }
326:
327:
328: /* ======================== Perform the inlining ============================== */
329:
330: /* Inlining is done by:
331: * o Converting to an Expression
332: * o Copying the trees of the function to be inlined
333: * o Renaming the variables
334: */
335:
336: struct InlineDoState
337: {
338: VarDeclaration *vthis;
339: Dsymbols from; // old Dsymbols
340: Dsymbols to; // parallel array of new Dsymbols
341: Dsymbol *parent; // new parent
342: };
343:
344: Expression *Statement::doInline(InlineDoState *ids)
345: {
346: assert(0);
347: return NULL; // default is we can't inline it
348: }
349:
350: Expression *ExpStatement::doInline(InlineDoState *ids)
351: {
352: #if LOG
353: if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars());
354: #endif
355: return exp ? exp->doInline(ids) : NULL;
356: }
357:
358: Expression *CompoundStatement::doInline(InlineDoState *ids)
359: {
360: Expression *e = NULL;
361:
362: //printf("CompoundStatement::doInline() %d\n", statements->dim);
363: for (size_t i = 0; i < statements->dim; i++)
364: { Statement *s = statements->tdata()[i];
365: if (s)
366: {
367: Expression *e2 = s->doInline(ids);
368: e = Expression::combine(e, e2);
369: if (s->isReturnStatement())
370: break;
371:
372: /* Check for:
373: * if (condition)
374: * return exp1;
375: * else
376: * return exp2;
377: */
378: IfStatement *ifs = s->isIfStatement();
379: if (ifs && ifs->elsebody && ifs->ifbody &&
380: ifs->ifbody->isReturnStatement() &&
381: ifs->elsebody->isReturnStatement()
382: )
383: break;
384:
385: }
386: }
387: return e;
388: }
389:
390: Expression *UnrolledLoopStatement::doInline(InlineDoState *ids)
391: {
392: Expression *e = NULL;
393:
394: //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim);
395: for (size_t i = 0; i < statements->dim; i++)
396: { Statement *s = statements->tdata()[i];
397: if (s)
398: {
399: Expression *e2 = s->doInline(ids);
400: e = Expression::combine(e, e2);
401: if (s->isReturnStatement())
402: break;
403: }
404: }
405: return e;
406: }
407:
408: Expression *IfStatement::doInline(InlineDoState *ids)
409: {
410: Expression *econd;
411: Expression *e1;
412: Expression *e2;
413: Expression *e;
414:
415: assert(!arg);
416: econd = condition->doInline(ids);
417: assert(econd);
418: if (ifbody)
419: e1 = ifbody->doInline(ids);
420: else
421: e1 = NULL;
422: if (elsebody)
423: e2 = elsebody->doInline(ids);
424: else
425: e2 = NULL;
426: if (e1 && e2)
427: {
428: e = new CondExp(econd->loc, econd, e1, e2);
429: e->type = e1->type;
430: }
431: else if (e1)
432: {
433: e = new AndAndExp(econd->loc, econd, e1);
434: e->type = Type::tvoid;
435: }
436: else if (e2)
437: {
438: e = new OrOrExp(econd->loc, econd, e2);
439: e->type = Type::tvoid;
440: }
441: else
442: {
443: e = econd;
444: }
445: return e;
446: }
447:
448: Expression *ReturnStatement::doInline(InlineDoState *ids)
449: {
450: //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : "");
451: return exp ? exp->doInline(ids) : 0;
452: }
453:
454: Expression *ImportStatement::doInline(InlineDoState *ids)
455: {
456: return NULL;
457: }
458:
459: /* --------------------------------------------------------------- */
460:
461: /******************************
462: * Perform doInline() on an array of Expressions.
463: */
464:
465: Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids)
466: { Expressions *newa = NULL;
467:
468: if (a)
469: {
470: newa = new Expressions();
471: newa->setDim(a->dim);
472:
473: for (int i = 0; i < a->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
474: { Expression *e = a->tdata()[i];
475:
476: if (e)
477: e = e->doInline(ids);
478: newa->tdata()[i] = e;
479: }
480: }
481: return newa;
482: }
483:
484: Expression *Expression::doInline(InlineDoState *ids)
485: {
486: //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars());
487: return copy();
488: }
489:
490: Expression *SymOffExp::doInline(InlineDoState *ids)
491: {
492: int i;
493:
494: //printf("SymOffExp::doInline(%s)\n", toChars());
495: for (i = 0; i < ids->from.dim; i++)
warning C4018: '<' : signed/unsigned mismatch
496: {
497: if (var == ids->from.tdata()[i])
498: {
499: SymOffExp *se = (SymOffExp *)copy();
500:
501: se->var = (Declaration *)ids->to.tdata()[i];
502: return se;
503: }
504: }
505: return this;
506: }
507:
508: Expression *VarExp::doInline(InlineDoState *ids)
509: {
510: int i;
511:
512: //printf("VarExp::doInline(%s)\n", toChars());
513: for (i = 0; i < ids->from.dim; i++)
warning C4018: '<' : signed/unsigned mismatch
514: {
515: if (var == ids->from.tdata()[i])
516: {
517: VarExp *ve = (VarExp *)copy();
518:
519: ve->var = (Declaration *)ids->to.tdata()[i];
520: return ve;
521: }
522: }
523: return this;
524: }
525:
526: Expression *ThisExp::doInline(InlineDoState *ids)
527: {
528: //if (!ids->vthis)
529: //error("no 'this' when inlining %s", ids->parent->toChars());
530: if (!ids->vthis)
531: {
532: return this;
533: }
534:
535: VarExp *ve = new VarExp(loc, ids->vthis);
536: ve->type = type;
537: return ve;
538: }
539:
540: Expression *SuperExp::doInline(InlineDoState *ids)
541: {
542: assert(ids->vthis);
543:
544: VarExp *ve = new VarExp(loc, ids->vthis);
545: ve->type = type;
546: return ve;
547: }
548:
549: Expression *DeclarationExp::doInline(InlineDoState *ids)
550: { DeclarationExp *de = (DeclarationExp *)copy();
551: VarDeclaration *vd;
552:
553: //printf("DeclarationExp::doInline(%s)\n", toChars());
554: vd = declaration->isVarDeclaration();
555: if (vd)
556: {
557: #if 0
558: // Need to figure this out before inlining can work for tuples
559: TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
560: if (td)
561: {
562: for (size_t i = 0; i < td->objects->dim; i++)
563: { DsymbolExp *se = td->objects->tdata()[i];
564: assert(se->op == TOKdsymbol);
565: se->s;
566: }
567: return st->objects->dim;
568: }
569: #endif
570: if (vd->isStatic())
571: ;
572: else
573: {
574: VarDeclaration *vto;
575:
576: vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init);
577: *vto = *vd;
578: vto->parent = ids->parent;
579: vto->csym = NULL;
580: vto->isym = NULL;
581:
582: ids->from.push(vd);
583: ids->to.push(vto);
584:
585: if (vd->init)
586: {
587: if (vd->init->isVoidInitializer())
588: {
589: vto->init = new VoidInitializer(vd->init->loc);
590: }
591: else
592: {
593: Expression *e = vd->init->toExpression();
594: assert(e);
595: vto->init = new ExpInitializer(e->loc, e->doInline(ids));
596: }
597: }
598: de->declaration = (Dsymbol *) (void *)vto;
599: }
600: }
601: /* This needs work, like DeclarationExp::toElem(), if we are
602: * to handle TemplateMixin's. For now, we just don't inline them.
603: */
604: return de;
605: }
606:
607: Expression *NewExp::doInline(InlineDoState *ids)
608: {
609: //printf("NewExp::doInline(): %s\n", toChars());
610: NewExp *ne = (NewExp *)copy();
611:
612: if (thisexp)
613: ne->thisexp = thisexp->doInline(ids);
614: ne->newargs = arrayExpressiondoInline(ne->newargs, ids);
615: ne->arguments = arrayExpressiondoInline(ne->arguments, ids);
616: return ne;
617: }
618:
619: Expression *UnaExp::doInline(InlineDoState *ids)
620: {
621: UnaExp *ue = (UnaExp *)copy();
622:
623: ue->e1 = e1->doInline(ids);
624: return ue;
625: }
626:
627: Expression *AssertExp::doInline(InlineDoState *ids)
628: {
629: AssertExp *ae = (AssertExp *)copy();
630:
631: ae->e1 = e1->doInline(ids);
632: if (msg)
633: ae->msg = msg->doInline(ids);
634: return ae;
635: }
636:
637: Expression *BinExp::doInline(InlineDoState *ids)
638: {
639: BinExp *be = (BinExp *)copy();
640:
641: be->e1 = e1->doInline(ids);
642: be->e2 = e2->doInline(ids);
643: return be;
644: }
645:
646: Expression *CallExp::doInline(InlineDoState *ids)
647: {
648: CallExp *ce;
649:
650: ce = (CallExp *)copy();
651: ce->e1 = e1->doInline(ids);
652: ce->arguments = arrayExpressiondoInline(arguments, ids);
653: return ce;
654: }
655:
656:
657: Expression *IndexExp::doInline(InlineDoState *ids)
658: {
659: IndexExp *are = (IndexExp *)copy();
660:
661: are->e1 = e1->doInline(ids);
662:
663: if (lengthVar)
664: { //printf("lengthVar\n");
665: VarDeclaration *vd = lengthVar;
666: ExpInitializer *ie;
667: ExpInitializer *ieto;
668: VarDeclaration *vto;
669:
670: vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init);
671: *vto = *vd;
672: vto->parent = ids->parent;
673: vto->csym = NULL;
674: vto->isym = NULL;
675:
676: ids->from.push(vd);
677: ids->to.push(vto);
678:
679: if (vd->init && !vd->init->isVoidInitializer())
680: {
681: ie = vd->init->isExpInitializer();
682: assert(ie);
683: ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids));
684: vto->init = ieto;
685: }
686:
687: are->lengthVar = (VarDeclaration *) (void *)vto;
688: }
689: are->e2 = e2->doInline(ids);
690: return are;
691: }
692:
693:
694: Expression *SliceExp::doInline(InlineDoState *ids)
695: {
696: SliceExp *are = (SliceExp *)copy();
697:
698: are->e1 = e1->doInline(ids);
699:
700: if (lengthVar)
701: { //printf("lengthVar\n");
702: VarDeclaration *vd = lengthVar;
703: ExpInitializer *ie;
704: ExpInitializer *ieto;
705: VarDeclaration *vto;
706:
707: vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init);
708: *vto = *vd;
709: vto->parent = ids->parent;
710: vto->csym = NULL;
711: vto->isym = NULL;
712:
713: ids->from.push(vd);
714: ids->to.push(vto);
715:
716: if (vd->init && !vd->init->isVoidInitializer())
717: {
718: ie = vd->init->isExpInitializer();
719: assert(ie);
720: ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids));
721: vto->init = ieto;
722: }
723:
724: are->lengthVar = (VarDeclaration *) (void *)vto;
725: }
726: if (lwr)
727: are->lwr = lwr->doInline(ids);
728: if (upr)
729: are->upr = upr->doInline(ids);
730: return are;
731: }
732:
733:
734: Expression *TupleExp::doInline(InlineDoState *ids)
735: {
736: TupleExp *ce;
737:
738: ce = (TupleExp *)copy();
739: ce->exps = arrayExpressiondoInline(exps, ids);
740: return ce;
741: }
742:
743:
744: Expression *ArrayLiteralExp::doInline(InlineDoState *ids)
745: {
746: ArrayLiteralExp *ce;
747:
748: ce = (ArrayLiteralExp *)copy();
749: ce->elements = arrayExpressiondoInline(elements, ids);
750: return ce;
751: }
752:
753:
754: Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids)
755: {
756: AssocArrayLiteralExp *ce;
757:
758: ce = (AssocArrayLiteralExp *)copy();
759: ce->keys = arrayExpressiondoInline(keys, ids);
760: ce->values = arrayExpressiondoInline(values, ids);
761: return ce;
762: }
763:
764:
765: Expression *StructLiteralExp::doInline(InlineDoState *ids)
766: {
767: StructLiteralExp *ce;
768:
769: ce = (StructLiteralExp *)copy();
770: ce->elements = arrayExpressiondoInline(elements, ids);
771: return ce;
772: }
773:
774:
775: Expression *ArrayExp::doInline(InlineDoState *ids)
776: {
777: ArrayExp *ce;
778:
779: ce = (ArrayExp *)copy();
780: ce->e1 = e1->doInline(ids);
781: ce->arguments = arrayExpressiondoInline(arguments, ids);
782: return ce;
783: }
784:
785:
786: Expression *CondExp::doInline(InlineDoState *ids)
787: {
788: CondExp *ce = (CondExp *)copy();
789:
790: ce->econd = econd->doInline(ids);
791: ce->e1 = e1->doInline(ids);
792: ce->e2 = e2->doInline(ids);
793: return ce;
794: }
795:
796:
797: /* ========== Walk the parse trees, and inline expand functions ============= */
798:
799: /* Walk the trees, looking for functions to inline.
800: * Inline any that can be.
801: */
802:
803: struct InlineScanState
804: {
805: FuncDeclaration *fd; // function being scanned
806: };
807:
808: Statement *Statement::inlineScan(InlineScanState *iss)
809: {
810: return this;
811: }
812:
813: Statement *ExpStatement::inlineScan(InlineScanState *iss)
814: {
815: #if LOG
816: printf("ExpStatement::inlineScan(%s)\n", toChars());
817: #endif
818: if (exp)
819: exp = exp->inlineScan(iss);
820: return this;
821: }
822:
823: Statement *CompoundStatement::inlineScan(InlineScanState *iss)
824: {
825: for (size_t i = 0; i < statements->dim; i++)
826: { Statement *s = statements->tdata()[i];
827: if (s)
828: statements->tdata()[i] = s->inlineScan(iss);
829: }
830: return this;
831: }
832:
833: Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss)
834: {
835: for (size_t i = 0; i < statements->dim; i++)
836: { Statement *s = statements->tdata()[i];
837: if (s)
838: statements->tdata()[i] = s->inlineScan(iss);
839: }
840: return this;
841: }
842:
843: Statement *ScopeStatement::inlineScan(InlineScanState *iss)
844: {
845: if (statement)
846: statement = statement->inlineScan(iss);
847: return this;
848: }
849:
850: Statement *WhileStatement::inlineScan(InlineScanState *iss)
851: {
852: condition = condition->inlineScan(iss);
853: body = body ? body->inlineScan(iss) : NULL;
854: return this;
855: }
856:
857:
858: Statement *DoStatement::inlineScan(InlineScanState *iss)
859: {
860: body = body ? body->inlineScan(iss) : NULL;
861: condition = condition->inlineScan(iss);
862: return this;
863: }
864:
865:
866: Statement *ForStatement::inlineScan(InlineScanState *iss)
867: {
868: if (init)
869: init = init->inlineScan(iss);
870: if (condition)
871: condition = condition->inlineScan(iss);
872: if (increment)
873: increment = increment->inlineScan(iss);
874: if (body)
875: body = body->inlineScan(iss);
876: return this;
877: }
878:
879:
880: Statement *ForeachStatement::inlineScan(InlineScanState *iss)
881: {
882: aggr = aggr->inlineScan(iss);
883: if (body)
884: body = body->inlineScan(iss);
885: return this;
886: }
887:
888:
889: #if DMDV2
890: Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss)
891: {
892: lwr = lwr->inlineScan(iss);
893: upr = upr->inlineScan(iss);
894: if (body)
895: body = body->inlineScan(iss);
896: return this;
897: }
898: #endif
899:
900:
901: Statement *IfStatement::inlineScan(InlineScanState *iss)
902: {
903: condition = condition->inlineScan(iss);
904: if (ifbody)
905: ifbody = ifbody->inlineScan(iss);
906: if (elsebody)
907: elsebody = elsebody->inlineScan(iss);
908: return this;
909: }
910:
911:
912: Statement *SwitchStatement::inlineScan(InlineScanState *iss)
913: {
914: //printf("SwitchStatement::inlineScan()\n");
915: condition = condition->inlineScan(iss);
916: body = body ? body->inlineScan(iss) : NULL;
917: if (sdefault)
918: sdefault = (DefaultStatement *)sdefault->inlineScan(iss);
919: if (cases)
920: {
921: for (int i = 0; i < cases->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
922: { CaseStatement *s;
923:
924: s = cases->tdata()[i];
925: cases->tdata()[i] = (CaseStatement *)s->inlineScan(iss);
926: }
927: }
928: return this;
929: }
930:
931:
932: Statement *CaseStatement::inlineScan(InlineScanState *iss)
933: {
934: //printf("CaseStatement::inlineScan()\n");
935: exp = exp->inlineScan(iss);
936: if (statement)
937: statement = statement->inlineScan(iss);
938: return this;
939: }
940:
941:
942: Statement *DefaultStatement::inlineScan(InlineScanState *iss)
943: {
944: if (statement)
945: statement = statement->inlineScan(iss);
946: return this;
947: }
948:
949:
950: Statement *ReturnStatement::inlineScan(InlineScanState *iss)
951: {
952: //printf("ReturnStatement::inlineScan()\n");
953: if (exp)
954: {
955: exp = exp->inlineScan(iss);
956: }
957: return this;
958: }
959:
960:
961: Statement *SynchronizedStatement::inlineScan(InlineScanState *iss)
962: {
963: if (exp)
964: exp = exp->inlineScan(iss);
965: if (body)
966: body = body->inlineScan(iss);
967: return this;
968: }
969:
970:
971: Statement *WithStatement::inlineScan(InlineScanState *iss)
972: {
973: if (exp)
974: exp = exp->inlineScan(iss);
975: if (body)
976: body = body->inlineScan(iss);
977: return this;
978: }
979:
980:
981: Statement *TryCatchStatement::inlineScan(InlineScanState *iss)
982: {
983: if (body)
984: body = body->inlineScan(iss);
985: if (catches)
986: {
987: for (int i = 0; i < catches->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
988: { Catch *c = catches->tdata()[i];
989:
990: if (c->handler)
991: c->handler = c->handler->inlineScan(iss);
992: }
993: }
994: return this;
995: }
996:
997:
998: Statement *TryFinallyStatement::inlineScan(InlineScanState *iss)
999: {
1000: if (body)
1001: body = body->inlineScan(iss);
1002: if (finalbody)
1003: finalbody = finalbody->inlineScan(iss);
1004: return this;
1005: }
1006:
1007:
1008: Statement *ThrowStatement::inlineScan(InlineScanState *iss)
1009: {
1010: if (exp)
1011: exp = exp->inlineScan(iss);
1012: return this;
1013: }
1014:
1015:
1016: Statement *VolatileStatement::inlineScan(InlineScanState *iss)
1017: {
1018: if (statement)
1019: statement = statement->inlineScan(iss);
1020: return this;
1021: }
1022:
1023:
1024: Statement *LabelStatement::inlineScan(InlineScanState *iss)
1025: {
1026: if (statement)
1027: statement = statement->inlineScan(iss);
1028: return this;
1029: }
1030:
1031: /* -------------------------- */
1032:
1033: void arrayInlineScan(InlineScanState *iss, Expressions *arguments)
1034: {
1035: if (arguments)
1036: {
1037: for (int i = 0; i < arguments->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
1038: { Expression *e = arguments->tdata()[i];
1039:
1040: if (e)
1041: {
1042: e = e->inlineScan(iss);
1043: arguments->tdata()[i] = e;
1044: }
1045: }
1046: }
1047: }
1048:
1049: Expression *Expression::inlineScan(InlineScanState *iss)
1050: {
1051: return this;
1052: }
1053:
1054: void scanVar(Dsymbol *s, InlineScanState *iss)
1055: {
1056: VarDeclaration *vd = s->isVarDeclaration();
1057: if (vd)
1058: {
1059: TupleDeclaration *td = vd->toAlias()->isTupleDeclaration();
1060: if (td)
1061: {
1062: for (size_t i = 0; i < td->objects->dim; i++)
1063: { DsymbolExp *se = (DsymbolExp *)td->objects->tdata()[i];
1064: assert(se->op == TOKdsymbol);
1065: scanVar(se->s, iss);
1066: }
1067: }
1068: else
1069: {
1070: // Scan initializer (vd->init)
1071: if (vd->init)
1072: {
1073: ExpInitializer *ie = vd->init->isExpInitializer();
1074:
1075: if (ie)
1076: {
1077: #if DMDV2
1078: if (vd->type)
1079: { Type *tb = vd->type->toBasetype();
1080: if (tb->ty == Tstruct)
1081: { StructDeclaration *sd = ((TypeStruct *)tb)->sym;
1082: if (sd->cpctor)
1083: { /* The problem here is that if the initializer is a
1084: * function call that returns a struct S with a cpctor:
1085: * S s = foo();
1086: * the postblit is done by the return statement in foo()
1087: * in s2ir.c, the intermediate code generator.
1088: * But, if foo() is inlined and now the code looks like:
1089: * S s = x;
1090: * the postblit is not there, because such assignments
1091: * are rewritten as s.cpctor(&x) by the front end.
1092: * So, the inlining won't get the postblit called.
1093: * Work around by not inlining these cases.
1094: * A proper fix would be to move all the postblit
1095: * additions to the front end.
1096: */
1097: return;
1098: }
1099: }
1100: }
1101: #endif
1102: ie->exp = ie->exp->inlineScan(iss);
1103: }
1104: }
1105: }
1106: }
1107: }
1108:
1109: Expression *DeclarationExp::inlineScan(InlineScanState *iss)
1110: {
1111: //printf("DeclarationExp::inlineScan()\n");
1112: scanVar(declaration, iss);
1113: return this;
1114: }
1115:
1116: Expression *UnaExp::inlineScan(InlineScanState *iss)
1117: {
1118: e1 = e1->inlineScan(iss);
1119: return this;
1120: }
1121:
1122: Expression *AssertExp::inlineScan(InlineScanState *iss)
1123: {
1124: e1 = e1->inlineScan(iss);
1125: if (msg)
1126: msg = msg->inlineScan(iss);
1127: return this;
1128: }
1129:
1130: Expression *BinExp::inlineScan(InlineScanState *iss)
1131: {
1132: e1 = e1->inlineScan(iss);
1133: e2 = e2->inlineScan(iss);
1134: return this;
1135: }
1136:
1137:
1138: Expression *CallExp::inlineScan(InlineScanState *iss)
1139: { Expression *e = this;
1140:
1141: //printf("CallExp::inlineScan()\n");
1142: e1 = e1->inlineScan(iss);
1143: arrayInlineScan(iss, arguments);
1144:
1145: if (e1->op == TOKvar)
1146: {
1147: VarExp *ve = (VarExp *)e1;
1148: FuncDeclaration *fd = ve->var->isFuncDeclaration();
1149:
1150: if (fd && fd != iss->fd && fd->canInline(0))
1151: {
1152: e = fd->doInline(iss, NULL, arguments);
1153: }
1154: }
1155: else if (e1->op == TOKdotvar)
1156: {
1157: DotVarExp *dve = (DotVarExp *)e1;
1158: FuncDeclaration *fd = dve->var->isFuncDeclaration();
1159:
1160: if (fd && fd != iss->fd && fd->canInline(1))
1161: {
1162: if (dve->e1->op == TOKcall &&
1163: dve->e1->type->toBasetype()->ty == Tstruct)
1164: {
1165: /* To create ethis, we'll need to take the address
1166: * of dve->e1, but this won't work if dve->e1 is
1167: * a function call.
1168: */
1169: ;
1170: }
1171: else
1172: e = fd->doInline(iss, dve->e1, arguments);
1173: }
1174: }
1175:
1176: return e;
1177: }
1178:
1179:
1180: Expression *SliceExp::inlineScan(InlineScanState *iss)
1181: {
1182: e1 = e1->inlineScan(iss);
1183: if (lwr)
1184: lwr = lwr->inlineScan(iss);
1185: if (upr)
1186: upr = upr->inlineScan(iss);
1187: return this;
1188: }
1189:
1190:
1191: Expression *TupleExp::inlineScan(InlineScanState *iss)
1192: { Expression *e = this;
1193:
1194: //printf("TupleExp::inlineScan()\n");
1195: arrayInlineScan(iss, exps);
1196:
1197: return e;
1198: }
1199:
1200:
1201: Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss)
1202: { Expression *e = this;
1203:
1204: //printf("ArrayLiteralExp::inlineScan()\n");
1205: arrayInlineScan(iss, elements);
1206:
1207: return e;
1208: }
1209:
1210:
1211: Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss)
1212: { Expression *e = this;
1213:
1214: //printf("AssocArrayLiteralExp::inlineScan()\n");
1215: arrayInlineScan(iss, keys);
1216: arrayInlineScan(iss, values);
1217:
1218: return e;
1219: }
1220:
1221:
1222: Expression *StructLiteralExp::inlineScan(InlineScanState *iss)
1223: { Expression *e = this;
1224:
1225: //printf("StructLiteralExp::inlineScan()\n");
1226: arrayInlineScan(iss, elements);
1227:
1228: return e;
1229: }
1230:
1231:
1232: Expression *ArrayExp::inlineScan(InlineScanState *iss)
1233: { Expression *e = this;
1234:
1235: //printf("ArrayExp::inlineScan()\n");
1236: e1 = e1->inlineScan(iss);
1237: arrayInlineScan(iss, arguments);
1238:
1239: return e;
1240: }
1241:
1242:
1243: Expression *CondExp::inlineScan(InlineScanState *iss)
1244: {
1245: econd = econd->inlineScan(iss);
1246: e1 = e1->inlineScan(iss);
1247: e2 = e2->inlineScan(iss);
1248: return this;
1249: }
1250:
1251:
1252: /* ========== =============== */
1253:
1254: void FuncDeclaration::inlineScan()
1255: {
1256: InlineScanState iss;
1257:
1258: #if LOG
1259: printf("FuncDeclaration::inlineScan('%s')\n", toChars());
1260: #endif
1261: memset(&iss, 0, sizeof(iss));
1262: iss.fd = this;
1263: if (fbody)
1264: {
1265: inlineNest++;
1266: fbody = fbody->inlineScan(&iss);
1267: inlineNest--;
1268: }
1269: }
1270:
1271: int FuncDeclaration::canInline(int hasthis, int hdrscan)
1272: {
1273: InlineCostState ics;
1274: int cost;
1275:
1276: #define CANINLINE_LOG 0
1277:
1278: #if CANINLINE_LOG
1279: printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars());
1280: #endif
1281:
1282: if (needThis() && !hasthis)
1283: return 0;
1284:
1285: if (inlineNest || (semanticRun < PASSsemantic3 && !hdrscan))
1286: {
1287: #if CANINLINE_LOG
1288: printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun);
1289: #endif
1290: return 0;
1291: }
1292:
1293: switch (inlineStatus)
1294: {
1295: case ILSyes:
1296: #if CANINLINE_LOG
1297: printf("\t1: yes %s\n", toChars());
1298: #endif
1299: return 1;
1300:
1301: case ILSno:
1302: #if CANINLINE_LOG
1303: printf("\t1: no %s\n", toChars());
1304: #endif
1305: return 0;
1306:
1307: case ILSuninitialized:
1308: break;
1309:
1310: default:
1311: assert(0);
1312: }
1313:
1314: if (type)
1315: { assert(type->ty == Tfunction);
1316: TypeFunction *tf = (TypeFunction *)(type);
1317: if (tf->varargs == 1) // no variadic parameter lists
1318: goto Lno;
1319:
1320: /* Don't inline a function that returns non-void, but has
1321: * no return expression.
1322: */
1323: if (tf->next && tf->next->ty != Tvoid &&
1324: !(hasReturnExp & 1) &&
1325: !hdrscan)
1326: goto Lno;
1327: }
1328:
1329: if (
1330: !fbody ||
1331: !hdrscan &&
1332: (
1333: #if 0
1334: isCtorDeclaration() || // cannot because need to convert:
1335: // return;
1336: // to:
1337: // return this;
1338: #endif
1339: isSynchronized() ||
1340: isImportedSymbol() ||
1341: #if DMDV2
1342: closureVars.dim || // no nested references to this frame
1343: #else
1344: nestedFrameRef || // no nested references to this frame
1345: #endif
1346: (isVirtual() && !isFinal())
1347: ))
1348: {
1349: goto Lno;
1350: }
1351:
1352: /* If any parameters are Tsarray's (which are passed by reference)
1353: * or out parameters (also passed by reference), don't do inlining.
1354: */
1355: #if 0
1356: if (parameters)
1357: {
1358: for (int i = 0; i < parameters->dim; i++)
1359: {
1360: VarDeclaration *v = parameters->tdata()[i];
1361: if (
1362: #if DMDV1
1363: v->isOut() || v->isRef() ||
1364: #endif
1365: v->type->toBasetype()->ty == Tsarray)
1366: goto Lno;
1367: }
1368: }
1369: #endif
1370:
1371: memset(&ics, 0, sizeof(ics));
1372: ics.hasthis = hasthis;
1373: ics.fd = this;
1374: ics.hdrscan = hdrscan;
1375: cost = fbody->inlineCost(&ics);
1376: #if CANINLINE_LOG
1377: printf("cost = %d\n", cost);
1378: #endif
1379: if (cost >= COST_MAX)
1380: goto Lno;
1381:
1382: if (!hdrscan) // Don't scan recursively for header content scan
1383: inlineScan();
1384:
1385: Lyes:
warning C4102: 'Lyes' : unreferenced label
1386: if (!hdrscan) // Don't modify inlineStatus for header content scan
1387: inlineStatus = ILSyes;
1388: #if CANINLINE_LOG
1389: printf("\t2: yes %s\n", toChars());
1390: #endif
1391: return 1;
1392:
1393: Lno:
1394: if (!hdrscan) // Don't modify inlineStatus for header content scan
1395: inlineStatus = ILSno;
1396: #if CANINLINE_LOG
1397: printf("\t2: no %s\n", toChars());
1398: #endif
1399: return 0;
1400: }
1401:
1402: Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, Expressions *arguments)
1403: {
1404: InlineDoState ids;
1405: DeclarationExp *de;
1406: Expression *e = NULL;
1407:
1408: #if LOG
1409: printf("FuncDeclaration::doInline('%s')\n", toChars());
1410: #endif
1411:
1412: memset(&ids, 0, sizeof(ids));
1413: ids.parent = iss->fd;
1414:
1415: // Set up vthis
1416: if (ethis)
1417: {
1418: VarDeclaration *vthis;
1419: ExpInitializer *ei;
1420: VarExp *ve;
1421:
1422: #if STRUCTTHISREF
1423: if (ethis->type->ty == Tpointer)
1424: { Type *t = ethis->type->nextOf();
1425: ethis = new PtrExp(ethis->loc, ethis);
1426: ethis->type = t;
1427: }
1428: ei = new ExpInitializer(ethis->loc, ethis);
1429:
1430: vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei);
1431: if (ethis->type->ty != Tclass)
1432: vthis->storage_class = STCref;
1433: else
1434: vthis->storage_class = STCin;
1435: #else
1436: if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer)
1437: {
1438: ethis = ethis->addressOf(NULL);
1439: }
1440:
1441: ei = new ExpInitializer(ethis->loc, ethis);
1442:
1443: vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei);
1444: vthis->storage_class = STCin;
1445: #endif
1446: vthis->linkage = LINKd;
1447: vthis->parent = iss->fd;
1448:
1449: ve = new VarExp(vthis->loc, vthis);
1450: ve->type = vthis->type;
1451:
1452: ei->exp = new AssignExp(vthis->loc, ve, ethis);
1453: ei->exp->type = ve->type;
1454: #if STRUCTTHISREF
1455: if (ethis->type->ty != Tclass)
1456: { /* This is a reference initialization, not a simple assignment.
1457: */
1458: ei->exp->op = TOKconstruct;
1459: }
1460: #endif
1461:
1462: ids.vthis = vthis;
1463: }
1464:
1465: // Set up parameters
1466: if (ethis)
1467: {
1468: e = new DeclarationExp(0, ids.vthis);
1469: e->type = Type::tvoid;
1470: }
1471:
1472: if (arguments && arguments->dim)
1473: {
1474: assert(parameters->dim == arguments->dim);
1475:
1476: for (int i = 0; i < arguments->dim; i++)
warning C4018: '<' : signed/unsigned mismatch
1477: {
1478: VarDeclaration *vfrom = parameters->tdata()[i];
1479: VarDeclaration *vto;
1480: Expression *arg = arguments->tdata()[i];
1481: ExpInitializer *ei;
1482: VarExp *ve;
1483:
1484: ei = new ExpInitializer(arg->loc, arg);
1485:
1486: vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei);
1487: vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref);
1488: vto->linkage = vfrom->linkage;
1489: vto->parent = iss->fd;
1490: //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class);
1491: //printf("vto->parent = '%s'\n", iss->fd->toChars());
1492:
1493: ve = new VarExp(vto->loc, vto);
1494: //ve->type = vto->type;
1495: ve->type = arg->type;
1496:
1497: ei->exp = new ConstructExp(vto->loc, ve, arg);
1498: ei->exp->type = ve->type;
1499: //ve->type->print();
1500: //arg->type->print();
1501: //ei->exp->print();
1502:
1503: ids.from.push(vfrom);
1504: ids.to.push(vto);
1505:
1506: de = new DeclarationExp(0, vto);
1507: de->type = Type::tvoid;
1508:
1509: e = Expression::combine(e, de);
1510: }
1511: }
1512:
1513: inlineNest++;
1514: Expression *eb = fbody->doInline(&ids);
1515: inlineNest--;
1516: //eb->type->print();
1517: //eb->print();
1518: //eb->dump(0);
1519:
1520: e = Expression::combine(e, eb);
1521:
1522: /* There's a problem if what the function returns is used subsequently as an
1523: * lvalue, as in a struct return that is then used as a 'this'.
1524: * If we take the address of the return value, we will be taking the address
1525: * of the original, not the copy. Fix this by assigning the return value to
1526: * a temporary, then returning the temporary. If the temporary is used as an
1527: * lvalue, it will work.
1528: * This only happens with struct returns.
1529: * See Bugzilla 2127 for an example.
1530: */
1531: TypeFunction *tf = (TypeFunction*)type;
1532: if (tf->next->ty == Tstruct)
1533: {
1534: /* Generate a new variable to hold the result and initialize it with the
1535: * inlined body of the function:
1536: * tret __inlineretval = e;
1537: */
1538: ExpInitializer* ei = new ExpInitializer(loc, e);
1539:
1540: Identifier* tmp = Identifier::generateId("__inlineretval");
1541: VarDeclaration* vd = new VarDeclaration(loc, tf->next, tmp, ei);
1542: vd->storage_class = tf->isref ? STCref : 0;
1543: vd->linkage = tf->linkage;
1544: vd->parent = iss->fd;
1545:
1546: VarExp *ve = new VarExp(loc, vd);
1547: ve->type = tf->next;
1548:
1549: ei->exp = new ConstructExp(loc, ve, e);
1550: ei->exp->type = ve->type;
1551:
1552: DeclarationExp* de = new DeclarationExp(0, vd);
warning C6246: Local declaration of 'de' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '1405' of 'c:\projects\extern\d\dmd\src\inline.c': Lines: 1405
1553: de->type = Type::tvoid;
1554:
1555: // Chain the two together:
1556: // ( typeof(return) __inlineretval = ( inlined body )) , __inlineretval
1557: e = Expression::combine(de, ve);
1558:
1559: //fprintf(stderr, "CallExp::inlineScan: e = "); e->print();
1560: }
1561:
1562: return e;
1563: }
1564:
1565:
1566: /****************************************************
1567: * Perform the "inline copying" of a default argument for a function parameter.
1568: */
1569:
1570: Expression *Expression::inlineCopy(Scope *sc)
1571: {
1572: #if 0
1573: /* See Bugzilla 2935 for explanation of why just a copy() is broken
1574: */
1575: return copy();
1576: #else
1577: InlineCostState ics;
1578:
1579: memset(&ics, 0, sizeof(ics));
1580: ics.hdrscan = 1; // so DeclarationExp:: will work on 'statics' which are not
1581: int cost = inlineCost(&ics);
1582: if (cost >= COST_MAX)
1583: { error("cannot inline default argument %s", toChars());
1584: return new ErrorExp();
1585: }
1586: InlineDoState ids;
1587: memset(&ids, 0, sizeof(ids));
1588: ids.parent = sc->parent;
1589: Expression *e = doInline(&ids);
1590: return e;
1591: #endif
1592: }
1593: