root/trunk/src/inline.c

Revision 651, 37.4 kB (checked in by walter, 2 years ago)

fail_compilation/fail345.d asserts in expression.c

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