Mercurial > projects > ldc
diff dmd2/inline.c @ 758:f04dde6e882c
Added initial D2 support, D2 frontend and changes to codegen to make things compile.
author | Tomas Lindquist Olsen <tomas.l.olsen@gmail.com> |
---|---|
date | Tue, 11 Nov 2008 01:38:48 +0100 |
parents | |
children | 356e65836fb5 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dmd2/inline.c Tue Nov 11 01:38:48 2008 +0100 @@ -0,0 +1,1447 @@ + +// Copyright (c) 1999-2007 by Digital Mars +// All Rights Reserved +// written by Walter Bright +// http://www.digitalmars.com +// License for redistribution is by either the Artistic License +// in artistic.txt, or the GNU General Public License in gnu.txt. +// See the included readme.txt for details. + +// Routines to perform function inlining + +#define LOG 0 + +#include <stdio.h> +#include <stdlib.h> +#include <assert.h> + +#include "id.h" +#include "init.h" +#include "declaration.h" +#include "aggregate.h" +#include "expression.h" +#include "statement.h" +#include "mtype.h" + +/* ========== Compute cost of inlining =============== */ + +/* Walk trees to determine if inlining can be done, and if so, + * if it is too complex to be worth inlining or not. + */ + +struct InlineCostState +{ + int nested; + int hasthis; + int hdrscan; // !=0 if inline scan for 'header' content + FuncDeclaration *fd; +}; + +const int COST_MAX = 250; + +int Statement::inlineCost(InlineCostState *ics) +{ + return COST_MAX; // default is we can't inline it +} + +int ExpStatement::inlineCost(InlineCostState *ics) +{ + return exp ? exp->inlineCost(ics) : 0; +} + +int CompoundStatement::inlineCost(InlineCostState *ics) +{ int cost = 0; + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + cost += s->inlineCost(ics); + if (cost >= COST_MAX) + break; + } + } + return cost; +} + +int UnrolledLoopStatement::inlineCost(InlineCostState *ics) +{ int cost = 0; + + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + cost += s->inlineCost(ics); + if (cost >= COST_MAX) + break; + } + } + return cost; +} + +int IfStatement::inlineCost(InlineCostState *ics) +{ + int cost; + + /* Can't declare variables inside ?: expressions, so + * we cannot inline if a variable is declared. + */ + if (arg) + return COST_MAX; + + cost = condition->inlineCost(ics); + + /* Specifically allow: + * if (condition) + * return exp1; + * else + * return exp2; + * Otherwise, we can't handle return statements nested in if's. + */ + + if (elsebody && ifbody && + ifbody->isReturnStatement() && + elsebody->isReturnStatement()) + { + cost += ifbody->inlineCost(ics); + cost += elsebody->inlineCost(ics); + //printf("cost = %d\n", cost); + } + else + { + ics->nested += 1; + if (ifbody) + cost += ifbody->inlineCost(ics); + if (elsebody) + cost += elsebody->inlineCost(ics); + ics->nested -= 1; + } + return cost; +} + +int ReturnStatement::inlineCost(InlineCostState *ics) +{ + // Can't handle return statements nested in if's + if (ics->nested) + return COST_MAX; + return exp ? exp->inlineCost(ics) : 0; +} + +/* -------------------------- */ + +int arrayInlineCost(InlineCostState *ics, Array *arguments) +{ int cost = 0; + + if (arguments) + { + for (int i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e) + cost += e->inlineCost(ics); + } + } + return cost; +} + +int Expression::inlineCost(InlineCostState *ics) +{ + return 1; +} + +int VarExp::inlineCost(InlineCostState *ics) +{ + //printf("VarExp::inlineCost() %s\n", toChars()); + return 1; +} + +int ThisExp::inlineCost(InlineCostState *ics) +{ + FuncDeclaration *fd = ics->fd; + if (!ics->hdrscan) + if (fd->isNested() || !ics->hasthis) + return COST_MAX; + return 1; +} + +int SuperExp::inlineCost(InlineCostState *ics) +{ + FuncDeclaration *fd = ics->fd; + if (!ics->hdrscan) + if (fd->isNested() || !ics->hasthis) + return COST_MAX; + return 1; +} + +int TupleExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, exps); +} + +int ArrayLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, elements); +} + +int AssocArrayLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, keys) + arrayInlineCost(ics, values); +} + +int StructLiteralExp::inlineCost(InlineCostState *ics) +{ + return 1 + arrayInlineCost(ics, elements); +} + +int FuncExp::inlineCost(InlineCostState *ics) +{ + // Right now, this makes the function be output to the .obj file twice. + return COST_MAX; +} + +int DelegateExp::inlineCost(InlineCostState *ics) +{ + return COST_MAX; +} + +int DeclarationExp::inlineCost(InlineCostState *ics) +{ int cost = 0; + VarDeclaration *vd; + + //printf("DeclarationExp::inlineCost()\n"); + vd = declaration->isVarDeclaration(); + if (vd) + { + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { +#if 1 + return COST_MAX; // finish DeclarationExp::doInline +#else + for (size_t i = 0; i < td->objects->dim; i++) + { Object *o = (Object *)td->objects->data[i]; + if (o->dyncast() != DYNCAST_EXPRESSION) + return COST_MAX; + Expression *eo = (Expression *)o; + if (eo->op != TOKdsymbol) + return COST_MAX; + } + return td->objects->dim; +#endif + } + if (!ics->hdrscan && vd->isDataseg()) + return COST_MAX; + cost += 1; + + // Scan initializer (vd->init) + if (vd->init) + { + ExpInitializer *ie = vd->init->isExpInitializer(); + + if (ie) + { + cost += ie->exp->inlineCost(ics); + } + } + } + + // These can contain functions, which when copied, get output twice. + if (declaration->isStructDeclaration() || + declaration->isClassDeclaration() || + declaration->isFuncDeclaration() || + declaration->isTypedefDeclaration() || + declaration->isTemplateMixin()) + return COST_MAX; + + //printf("DeclarationExp::inlineCost('%s')\n", toChars()); + return cost; +} + +int UnaExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics); +} + +int AssertExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + (msg ? msg->inlineCost(ics) : 0); +} + +int BinExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + e2->inlineCost(ics); +} + +int CallExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); +} + +int SliceExp::inlineCost(InlineCostState *ics) +{ int cost; + + cost = 1 + e1->inlineCost(ics); + if (lwr) + cost += lwr->inlineCost(ics); + if (upr) + cost += upr->inlineCost(ics); + return cost; +} + +int ArrayExp::inlineCost(InlineCostState *ics) +{ + return 1 + e1->inlineCost(ics) + arrayInlineCost(ics, arguments); +} + + +int CondExp::inlineCost(InlineCostState *ics) +{ + return 1 + + e1->inlineCost(ics) + + e2->inlineCost(ics) + + econd->inlineCost(ics); +} + + +/* ======================== Perform the inlining ============================== */ + +/* Inlining is done by: + * o Converting to an Expression + * o Copying the trees of the function to be inlined + * o Renaming the variables + */ + +struct InlineDoState +{ + VarDeclaration *vthis; + Array from; // old Dsymbols + Array to; // parallel array of new Dsymbols + Dsymbol *parent; // new parent +}; + +Expression *Statement::doInline(InlineDoState *ids) +{ + assert(0); + return NULL; // default is we can't inline it +} + +Expression *ExpStatement::doInline(InlineDoState *ids) +{ +#if LOG + if (exp) printf("ExpStatement::doInline() '%s'\n", exp->toChars()); +#endif + return exp ? exp->doInline(ids) : NULL; +} + +Expression *CompoundStatement::doInline(InlineDoState *ids) +{ + Expression *e = NULL; + + //printf("CompoundStatement::doInline() %d\n", statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + Expression *e2 = s->doInline(ids); + e = Expression::combine(e, e2); + if (s->isReturnStatement()) + break; + + /* Check for: + * if (condition) + * return exp1; + * else + * return exp2; + */ + IfStatement *ifs = s->isIfStatement(); + if (ifs && ifs->elsebody && ifs->ifbody && + ifs->ifbody->isReturnStatement() && + ifs->elsebody->isReturnStatement() + ) + break; + + } + } + return e; +} + +Expression *UnrolledLoopStatement::doInline(InlineDoState *ids) +{ + Expression *e = NULL; + + //printf("UnrolledLoopStatement::doInline() %d\n", statements->dim); + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + { + Expression *e2 = s->doInline(ids); + e = Expression::combine(e, e2); + if (s->isReturnStatement()) + break; + } + } + return e; +} + +Expression *IfStatement::doInline(InlineDoState *ids) +{ + Expression *econd; + Expression *e1; + Expression *e2; + Expression *e; + + assert(!arg); + econd = condition->doInline(ids); + assert(econd); + if (ifbody) + e1 = ifbody->doInline(ids); + else + e1 = NULL; + if (elsebody) + e2 = elsebody->doInline(ids); + else + e2 = NULL; + if (e1 && e2) + { + e = new CondExp(econd->loc, econd, e1, e2); + e->type = e1->type; + } + else if (e1) + { + e = new AndAndExp(econd->loc, econd, e1); + e->type = Type::tvoid; + } + else if (e2) + { + e = new OrOrExp(econd->loc, econd, e2); + e->type = Type::tvoid; + } + else + { + e = econd; + } + return e; +} + +Expression *ReturnStatement::doInline(InlineDoState *ids) +{ + //printf("ReturnStatement::doInline() '%s'\n", exp ? exp->toChars() : ""); + return exp ? exp->doInline(ids) : 0; +} + +/* --------------------------------------------------------------- */ + +/****************************** + * Perform doInline() on an array of Expressions. + */ + +Expressions *arrayExpressiondoInline(Expressions *a, InlineDoState *ids) +{ Expressions *newa = NULL; + + if (a) + { + newa = new Expressions(); + newa->setDim(a->dim); + + for (int i = 0; i < a->dim; i++) + { Expression *e = (Expression *)a->data[i]; + + if (e) + { + e = e->doInline(ids); + newa->data[i] = (void *)e; + } + } + } + return newa; +} + +Expression *Expression::doInline(InlineDoState *ids) +{ + //printf("Expression::doInline(%s): %s\n", Token::toChars(op), toChars()); + return copy(); +} + +Expression *SymOffExp::doInline(InlineDoState *ids) +{ + int i; + + //printf("SymOffExp::doInline(%s)\n", toChars()); + for (i = 0; i < ids->from.dim; i++) + { + if (var == (Declaration *)ids->from.data[i]) + { + SymOffExp *se = (SymOffExp *)copy(); + + se->var = (Declaration *)ids->to.data[i]; + return se; + } + } + return this; +} + +Expression *VarExp::doInline(InlineDoState *ids) +{ + int i; + + //printf("VarExp::doInline(%s)\n", toChars()); + for (i = 0; i < ids->from.dim; i++) + { + if (var == (Declaration *)ids->from.data[i]) + { + VarExp *ve = (VarExp *)copy(); + + ve->var = (Declaration *)ids->to.data[i]; + return ve; + } + } + return this; +} + +Expression *ThisExp::doInline(InlineDoState *ids) +{ + //if (!ids->vthis) + //error("no 'this' when inlining %s", ids->parent->toChars()); + if (!ids->vthis) + { + return this; + } + + VarExp *ve = new VarExp(loc, ids->vthis); + ve->type = type; + return ve; +} + +Expression *SuperExp::doInline(InlineDoState *ids) +{ + assert(ids->vthis); + + VarExp *ve = new VarExp(loc, ids->vthis); + ve->type = type; + return ve; +} + +Expression *DeclarationExp::doInline(InlineDoState *ids) +{ DeclarationExp *de = (DeclarationExp *)copy(); + VarDeclaration *vd; + + //printf("DeclarationExp::doInline(%s)\n", toChars()); + vd = declaration->isVarDeclaration(); + if (vd) + { +#if 0 + // Need to figure this out before inlining can work for tuples + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { + for (size_t i = 0; i < td->objects->dim; i++) + { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; + assert(se->op == TOKdsymbol); + se->s; + } + return st->objects->dim; + } +#endif + if (vd->isStatic()) + ; + else + { + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; + vto->csym = NULL; + vto->isym = NULL; + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + if (vd->init->isVoidInitializer()) + { + vto->init = new VoidInitializer(vd->init->loc); + } + else + { + ExpInitializer *ie = vd->init->isExpInitializer(); + assert(ie); + vto->init = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); + } + } + de->declaration = (Dsymbol *) (void *)vto; + } + } + /* This needs work, like DeclarationExp::toElem(), if we are + * to handle TemplateMixin's. For now, we just don't inline them. + */ + return de; +} + +Expression *NewExp::doInline(InlineDoState *ids) +{ + //printf("NewExp::doInline(): %s\n", toChars()); + NewExp *ne = (NewExp *)copy(); + + if (thisexp) + ne->thisexp = thisexp->doInline(ids); + ne->newargs = arrayExpressiondoInline(ne->newargs, ids); + ne->arguments = arrayExpressiondoInline(ne->arguments, ids); + return ne; +} + +Expression *UnaExp::doInline(InlineDoState *ids) +{ + UnaExp *ue = (UnaExp *)copy(); + + ue->e1 = e1->doInline(ids); + return ue; +} + +Expression *AssertExp::doInline(InlineDoState *ids) +{ + AssertExp *ae = (AssertExp *)copy(); + + ae->e1 = e1->doInline(ids); + if (msg) + ae->msg = msg->doInline(ids); + return ae; +} + +Expression *BinExp::doInline(InlineDoState *ids) +{ + BinExp *be = (BinExp *)copy(); + + be->e1 = e1->doInline(ids); + be->e2 = e2->doInline(ids); + return be; +} + +Expression *CallExp::doInline(InlineDoState *ids) +{ + CallExp *ce; + + ce = (CallExp *)copy(); + ce->e1 = e1->doInline(ids); + ce->arguments = arrayExpressiondoInline(arguments, ids); + return ce; +} + + +Expression *IndexExp::doInline(InlineDoState *ids) +{ + IndexExp *are = (IndexExp *)copy(); + + are->e1 = e1->doInline(ids); + + if (lengthVar) + { //printf("lengthVar\n"); + VarDeclaration *vd = lengthVar; + ExpInitializer *ie; + ExpInitializer *ieto; + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; + vto->csym = NULL; + vto->isym = NULL; + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + ie = vd->init->isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); + vto->init = ieto; + } + + are->lengthVar = (VarDeclaration *) (void *)vto; + } + are->e2 = e2->doInline(ids); + return are; +} + + +Expression *SliceExp::doInline(InlineDoState *ids) +{ + SliceExp *are = (SliceExp *)copy(); + + are->e1 = e1->doInline(ids); + + if (lengthVar) + { //printf("lengthVar\n"); + VarDeclaration *vd = lengthVar; + ExpInitializer *ie; + ExpInitializer *ieto; + VarDeclaration *vto; + + vto = new VarDeclaration(vd->loc, vd->type, vd->ident, vd->init); + *vto = *vd; + vto->parent = ids->parent; + vto->csym = NULL; + vto->isym = NULL; + + ids->from.push(vd); + ids->to.push(vto); + + if (vd->init) + { + ie = vd->init->isExpInitializer(); + assert(ie); + ieto = new ExpInitializer(ie->loc, ie->exp->doInline(ids)); + vto->init = ieto; + } + + are->lengthVar = (VarDeclaration *) (void *)vto; + } + if (lwr) + are->lwr = lwr->doInline(ids); + if (upr) + are->upr = upr->doInline(ids); + return are; +} + + +Expression *TupleExp::doInline(InlineDoState *ids) +{ + TupleExp *ce; + + ce = (TupleExp *)copy(); + ce->exps = arrayExpressiondoInline(exps, ids); + return ce; +} + + +Expression *ArrayLiteralExp::doInline(InlineDoState *ids) +{ + ArrayLiteralExp *ce; + + ce = (ArrayLiteralExp *)copy(); + ce->elements = arrayExpressiondoInline(elements, ids); + return ce; +} + + +Expression *AssocArrayLiteralExp::doInline(InlineDoState *ids) +{ + AssocArrayLiteralExp *ce; + + ce = (AssocArrayLiteralExp *)copy(); + ce->keys = arrayExpressiondoInline(keys, ids); + ce->values = arrayExpressiondoInline(values, ids); + return ce; +} + + +Expression *StructLiteralExp::doInline(InlineDoState *ids) +{ + StructLiteralExp *ce; + + ce = (StructLiteralExp *)copy(); + ce->elements = arrayExpressiondoInline(elements, ids); + return ce; +} + + +Expression *ArrayExp::doInline(InlineDoState *ids) +{ + ArrayExp *ce; + + ce = (ArrayExp *)copy(); + ce->e1 = e1->doInline(ids); + ce->arguments = arrayExpressiondoInline(arguments, ids); + return ce; +} + + +Expression *CondExp::doInline(InlineDoState *ids) +{ + CondExp *ce = (CondExp *)copy(); + + ce->econd = econd->doInline(ids); + ce->e1 = e1->doInline(ids); + ce->e2 = e2->doInline(ids); + return ce; +} + + +/* ========== Walk the parse trees, and inline expand functions ============= */ + +/* Walk the trees, looking for functions to inline. + * Inline any that can be. + */ + +struct InlineScanState +{ + FuncDeclaration *fd; // function being scanned +}; + +Statement *Statement::inlineScan(InlineScanState *iss) +{ + return this; +} + +Statement *ExpStatement::inlineScan(InlineScanState *iss) +{ +#if LOG + printf("ExpStatement::inlineScan(%s)\n", toChars()); +#endif + if (exp) + exp = exp->inlineScan(iss); + return this; +} + +Statement *CompoundStatement::inlineScan(InlineScanState *iss) +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + statements->data[i] = (void *)s->inlineScan(iss); + } + return this; +} + +Statement *UnrolledLoopStatement::inlineScan(InlineScanState *iss) +{ + for (size_t i = 0; i < statements->dim; i++) + { Statement *s = (Statement *) statements->data[i]; + if (s) + statements->data[i] = (void *)s->inlineScan(iss); + } + return this; +} + +Statement *ScopeStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + +Statement *WhileStatement::inlineScan(InlineScanState *iss) +{ + condition = condition->inlineScan(iss); + body = body ? body->inlineScan(iss) : NULL; + return this; +} + + +Statement *DoStatement::inlineScan(InlineScanState *iss) +{ + body = body ? body->inlineScan(iss) : NULL; + condition = condition->inlineScan(iss); + return this; +} + + +Statement *ForStatement::inlineScan(InlineScanState *iss) +{ + if (init) + init = init->inlineScan(iss); + if (condition) + condition = condition->inlineScan(iss); + if (increment) + increment = increment->inlineScan(iss); + body = body->inlineScan(iss); + return this; +} + + +Statement *ForeachStatement::inlineScan(InlineScanState *iss) +{ + aggr = aggr->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +#if DMDV2 +Statement *ForeachRangeStatement::inlineScan(InlineScanState *iss) +{ + lwr = lwr->inlineScan(iss); + upr = upr->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} +#endif + + +Statement *IfStatement::inlineScan(InlineScanState *iss) +{ + condition = condition->inlineScan(iss); + if (ifbody) + ifbody = ifbody->inlineScan(iss); + if (elsebody) + elsebody = elsebody->inlineScan(iss); + return this; +} + + +Statement *SwitchStatement::inlineScan(InlineScanState *iss) +{ + //printf("SwitchStatement::inlineScan()\n"); + condition = condition->inlineScan(iss); + body = body ? body->inlineScan(iss) : NULL; + if (sdefault) + sdefault = (DefaultStatement *)sdefault->inlineScan(iss); + if (cases) + { + for (int i = 0; i < cases->dim; i++) + { Statement *s; + + s = (Statement *) cases->data[i]; + cases->data[i] = (void *)s->inlineScan(iss); + } + } + return this; +} + + +Statement *CaseStatement::inlineScan(InlineScanState *iss) +{ + //printf("CaseStatement::inlineScan()\n"); + exp = exp->inlineScan(iss); + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *DefaultStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *ReturnStatement::inlineScan(InlineScanState *iss) +{ + //printf("ReturnStatement::inlineScan()\n"); + if (exp) + { + exp = exp->inlineScan(iss); + } + return this; +} + + +Statement *SynchronizedStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +Statement *WithStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + if (body) + body = body->inlineScan(iss); + return this; +} + + +Statement *TryCatchStatement::inlineScan(InlineScanState *iss) +{ + if (body) + body = body->inlineScan(iss); + if (catches) + { + for (int i = 0; i < catches->dim; i++) + { Catch *c = (Catch *)catches->data[i]; + + if (c->handler) + c->handler = c->handler->inlineScan(iss); + } + } + return this; +} + + +Statement *TryFinallyStatement::inlineScan(InlineScanState *iss) +{ + if (body) + body = body->inlineScan(iss); + if (finalbody) + finalbody = finalbody->inlineScan(iss); + return this; +} + + +Statement *ThrowStatement::inlineScan(InlineScanState *iss) +{ + if (exp) + exp = exp->inlineScan(iss); + return this; +} + + +Statement *VolatileStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + + +Statement *LabelStatement::inlineScan(InlineScanState *iss) +{ + if (statement) + statement = statement->inlineScan(iss); + return this; +} + +/* -------------------------- */ + +void arrayInlineScan(InlineScanState *iss, Array *arguments) +{ + if (arguments) + { + for (int i = 0; i < arguments->dim; i++) + { Expression *e = (Expression *)arguments->data[i]; + + if (e) + { + e = e->inlineScan(iss); + arguments->data[i] = (void *)e; + } + } + } +} + +Expression *Expression::inlineScan(InlineScanState *iss) +{ + return this; +} + +void scanVar(Dsymbol *s, InlineScanState *iss) +{ + VarDeclaration *vd = s->isVarDeclaration(); + if (vd) + { + TupleDeclaration *td = vd->toAlias()->isTupleDeclaration(); + if (td) + { + for (size_t i = 0; i < td->objects->dim; i++) + { DsymbolExp *se = (DsymbolExp *)td->objects->data[i]; + assert(se->op == TOKdsymbol); + scanVar(se->s, iss); + } + } + else + { + // Scan initializer (vd->init) + if (vd->init) + { + ExpInitializer *ie = vd->init->isExpInitializer(); + + if (ie) + { + ie->exp = ie->exp->inlineScan(iss); + } + } + } + } +} + +Expression *DeclarationExp::inlineScan(InlineScanState *iss) +{ + //printf("DeclarationExp::inlineScan()\n"); + scanVar(declaration, iss); + return this; +} + +Expression *UnaExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + return this; +} + +Expression *AssertExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + if (msg) + msg = msg->inlineScan(iss); + return this; +} + +Expression *BinExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + e2 = e2->inlineScan(iss); + return this; +} + + +Expression *CallExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("CallExp::inlineScan()\n"); + e1 = e1->inlineScan(iss); + arrayInlineScan(iss, arguments); + + if (e1->op == TOKvar) + { + VarExp *ve = (VarExp *)e1; + FuncDeclaration *fd = ve->var->isFuncDeclaration(); + + if (fd && fd != iss->fd && fd->canInline(0)) + { + e = fd->doInline(iss, NULL, arguments); + } + } + else if (e1->op == TOKdotvar) + { + DotVarExp *dve = (DotVarExp *)e1; + FuncDeclaration *fd = dve->var->isFuncDeclaration(); + + if (fd && fd != iss->fd && fd->canInline(1)) + { + if (dve->e1->op == TOKcall && + dve->e1->type->toBasetype()->ty == Tstruct) + { + /* To create ethis, we'll need to take the address + * of dve->e1, but this won't work if dve->e1 is + * a function call. + */ + ; + } + else + e = fd->doInline(iss, dve->e1, arguments); + } + } + + return e; +} + + +Expression *SliceExp::inlineScan(InlineScanState *iss) +{ + e1 = e1->inlineScan(iss); + if (lwr) + lwr = lwr->inlineScan(iss); + if (upr) + upr = upr->inlineScan(iss); + return this; +} + + +Expression *TupleExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("TupleExp::inlineScan()\n"); + arrayInlineScan(iss, exps); + + return e; +} + + +Expression *ArrayLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("ArrayLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, elements); + + return e; +} + + +Expression *AssocArrayLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("AssocArrayLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, keys); + arrayInlineScan(iss, values); + + return e; +} + + +Expression *StructLiteralExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("StructLiteralExp::inlineScan()\n"); + arrayInlineScan(iss, elements); + + return e; +} + + +Expression *ArrayExp::inlineScan(InlineScanState *iss) +{ Expression *e = this; + + //printf("ArrayExp::inlineScan()\n"); + e1 = e1->inlineScan(iss); + arrayInlineScan(iss, arguments); + + return e; +} + + +Expression *CondExp::inlineScan(InlineScanState *iss) +{ + econd = econd->inlineScan(iss); + e1 = e1->inlineScan(iss); + e2 = e2->inlineScan(iss); + return this; +} + + +/* ========== =============== */ + +void FuncDeclaration::inlineScan() +{ + InlineScanState iss; + +#if LOG + printf("FuncDeclaration::inlineScan('%s')\n", toChars()); +#endif + memset(&iss, 0, sizeof(iss)); + iss.fd = this; + if (fbody) + { + inlineNest++; + fbody = fbody->inlineScan(&iss); + inlineNest--; + } +} + +int FuncDeclaration::canInline(int hasthis, int hdrscan) +{ + InlineCostState ics; + int cost; + +#define CANINLINE_LOG 0 + +#if CANINLINE_LOG + printf("FuncDeclaration::canInline(hasthis = %d, '%s')\n", hasthis, toChars()); +#endif + + if (needThis() && !hasthis) + return 0; + + if (inlineNest || (!semanticRun && !hdrscan)) + { +#if CANINLINE_LOG + printf("\t1: no, inlineNest = %d, semanticRun = %d\n", inlineNest, semanticRun); +#endif + return 0; + } + + switch (inlineStatus) + { + case ILSyes: +#if CANINLINE_LOG + printf("\t1: yes %s\n", toChars()); +#endif + return 1; + + case ILSno: +#if CANINLINE_LOG + printf("\t1: no %s\n", toChars()); +#endif + return 0; + + case ILSuninitialized: + break; + + default: + assert(0); + } + + if (type) + { assert(type->ty == Tfunction); + TypeFunction *tf = (TypeFunction *)(type); + if (tf->varargs == 1) // no variadic parameter lists + goto Lno; + + /* Don't inline a function that returns non-void, but has + * no return expression. + */ + if (tf->next && tf->next->ty != Tvoid && + !(hasReturnExp & 1) && + !hdrscan) + goto Lno; + } + else + { CtorDeclaration *ctor = isCtorDeclaration(); + + if (ctor && ctor->varargs == 1) + goto Lno; + } + + if ( + !fbody || + !hdrscan && + ( +#if 0 + isCtorDeclaration() || // cannot because need to convert: + // return; + // to: + // return this; +#endif + isSynchronized() || + isImportedSymbol() || +#if DMDV2 + closureVars.dim || // no nested references to this frame +#else + nestedFrameRef || // no nested references to this frame +#endif + (isVirtual() && !isFinal()) + )) + { + goto Lno; + } + + /* If any parameters are Tsarray's (which are passed by reference) + * or out parameters (also passed by reference), don't do inlining. + */ + if (parameters) + { + for (int i = 0; i < parameters->dim; i++) + { + VarDeclaration *v = (VarDeclaration *)parameters->data[i]; + if (v->isOut() || v->isRef() || v->type->toBasetype()->ty == Tsarray) + goto Lno; + } + } + + memset(&ics, 0, sizeof(ics)); + ics.hasthis = hasthis; + ics.fd = this; + ics.hdrscan = hdrscan; + cost = fbody->inlineCost(&ics); +#if CANINLINE_LOG + printf("cost = %d\n", cost); +#endif + if (cost >= COST_MAX) + goto Lno; + + if (!hdrscan) // Don't scan recursively for header content scan + inlineScan(); + +Lyes: + if (!hdrscan) // Don't modify inlineStatus for header content scan + inlineStatus = ILSyes; +#if CANINLINE_LOG + printf("\t2: yes %s\n", toChars()); +#endif + return 1; + +Lno: + if (!hdrscan) // Don't modify inlineStatus for header content scan + inlineStatus = ILSno; +#if CANINLINE_LOG + printf("\t2: no %s\n", toChars()); +#endif + return 0; +} + +Expression *FuncDeclaration::doInline(InlineScanState *iss, Expression *ethis, Array *arguments) +{ + InlineDoState ids; + DeclarationExp *de; + Expression *e = NULL; + +#if LOG + printf("FuncDeclaration::doInline('%s')\n", toChars()); +#endif + + memset(&ids, 0, sizeof(ids)); + ids.parent = iss->fd; + + // Set up vthis + if (ethis) + { + VarDeclaration *vthis; + ExpInitializer *ei; + VarExp *ve; + + if (ethis->type->ty != Tclass && ethis->type->ty != Tpointer) + { + ethis = ethis->addressOf(NULL); + } + + ei = new ExpInitializer(ethis->loc, ethis); + + vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei); + vthis->storage_class = STCin; + vthis->linkage = LINKd; + vthis->parent = iss->fd; + + ve = new VarExp(vthis->loc, vthis); + ve->type = vthis->type; + + ei->exp = new AssignExp(vthis->loc, ve, ethis); + ei->exp->type = ve->type; + + ids.vthis = vthis; + } + + // Set up parameters + if (ethis) + { + e = new DeclarationExp(0, ids.vthis); + e->type = Type::tvoid; + } + + if (arguments && arguments->dim) + { + assert(parameters->dim == arguments->dim); + + for (int i = 0; i < arguments->dim; i++) + { + VarDeclaration *vfrom = (VarDeclaration *)parameters->data[i]; + VarDeclaration *vto; + Expression *arg = (Expression *)arguments->data[i]; + ExpInitializer *ei; + VarExp *ve; + + ei = new ExpInitializer(arg->loc, arg); + + vto = new VarDeclaration(vfrom->loc, vfrom->type, vfrom->ident, ei); + vto->storage_class |= vfrom->storage_class & (STCin | STCout | STClazy | STCref); + vto->linkage = vfrom->linkage; + vto->parent = iss->fd; + //printf("vto = '%s', vto->storage_class = x%x\n", vto->toChars(), vto->storage_class); + //printf("vto->parent = '%s'\n", iss->fd->toChars()); + + ve = new VarExp(vto->loc, vto); + //ve->type = vto->type; + ve->type = arg->type; + + ei->exp = new AssignExp(vto->loc, ve, arg); + ei->exp->type = ve->type; +//ve->type->print(); +//arg->type->print(); +//ei->exp->print(); + + ids.from.push(vfrom); + ids.to.push(vto); + + de = new DeclarationExp(0, vto); + de->type = Type::tvoid; + + e = Expression::combine(e, de); + } + } + + inlineNest++; + Expression *eb = fbody->doInline(&ids); + inlineNest--; + return Expression::combine(e, eb); +} + + +