Logo Search packages:      
Sourcecode: ldc version File versions

inline.c

// Copyright (c) 1999-2009 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;

#if !IN_LLVM
    /* Can't declare variables inside ?: expressions, so
     * we cannot inline if a variable is declared.
     */
    if (arg)
      return COST_MAX;
#endif

    cost = condition->inlineCost(ics);

#if !IN_LLVM
    /* 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
#endif
    {
      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)
{
#if !IN_LLVM
    // Can't handle return statements nested in if's
    if (ics->nested)
      return COST_MAX;
#endif
    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)
{
#if !IN_LLVM
    FuncDeclaration *fd = ics->fd;
    if (!ics->hdrscan)
      if (fd->isNested() || !ics->hasthis)
          return COST_MAX;
#endif
    return 1;
}

int SuperExp::inlineCost(InlineCostState *ics)
{
#if !IN_LLVM
    FuncDeclaration *fd = ics->fd;
    if (!ics->hdrscan)
      if (fd->isNested() || !ics->hasthis)
          return COST_MAX;
#endif
    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)
{
    // This breaks on LDC too, since nested functions have internal linkage
    // and thus can't be referenced from other objects.
    // Right now, this makes the function be output to the .obj file twice.
    return COST_MAX;
}

int DelegateExp::inlineCost(InlineCostState *ics)
{
    // This breaks on LDC too, since nested functions have internal linkage
    // and thus can't be referenced from other objects.
    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
      }
        // This breaks on LDC too, since nested static variables have internal
        // linkage and thus can't be referenced from other objects.
      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.
    // These break on LDC too, since nested static variables and functions have
    // internal linkage and thus can't be referenced from other objects.
    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;
#if IN_DMD
          vto->csym = NULL;
          vto->isym = NULL;
#endif

          ids->from.push(vd);
          ids->to.push(vto);

          if (vd->init)
          {
            if (vd->init->isVoidInitializer())
            {
                vto->init = new VoidInitializer(vd->init->loc);
            }
            else
            {
                Expression *e = vd->init->toExpression();
                assert(e);
                vto->init = new ExpInitializer(e->loc, e->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;
#if IN_DMD
      vto->csym = NULL;
      vto->isym = NULL;
#endif

      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;
#if IN_DMD
      vto->csym = NULL;
      vto->isym = NULL;
#endif

      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);
    if (body)
      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)
            {
#if DMDV2
                if (vd->type)
                { Type *tb = vd->type->toBasetype();
                  if (tb->ty == Tstruct)
                  {   StructDeclaration *sd = ((TypeStruct *)tb)->sym;
                      if (sd->cpctor)
                      {   /* The problem here is that if the initializer is a
                         * function call that returns a struct S with a cpctor:
                         *   S s = foo();
                         * the postblit is done by the return statement in foo()
                         * in s2ir.c, the intermediate code generator.
                         * But, if foo() is inlined and now the code looks like:
                         *   S s = x;
                         * the postblit is not there, because such assignments
                         * are rewritten as s.cpctor(&x) by the front end.
                         * So, the inlining won't get the postblit called.
                         * Work around by not inlining these cases.
                         * A proper fix would be to move all the postblit
                         * additions to the front end.
                         */
                        return;
                      }
                  }
                }
#endif
                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 < 3 && !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 IN_LLVM
        // LDC: Only extern(C) varargs count.
        if (tf->linkage != LINKd)
#endif
      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;
    }
#if !IN_LLVM
    // LDC: Only extern(C) varargs count, and ctors use extern(D).
    else
    { CtorDeclaration *ctor = isCtorDeclaration();

      if (ctor && ctor->varargs == 1)
          goto Lno;
    }
#endif

    if (
      !fbody ||
      !hdrscan &&
      (
#if 0
      isCtorDeclaration() ||  // cannot because need to convert:
                        //    return;
                        // to:
                        //    return this;
#endif
      isSynchronized() ||
      isImportedSymbol() ||
#if !IN_LLVM
#if DMDV2
      closureVars.dim ||      // no nested references to this frame
#else
      nestedFrameRef || // no nested references to this frame
#endif
#endif // !IN_LLVM
      (isVirtual() && !isFinal())
       ))
    {
      goto Lno;
    }

#if !IN_LLVM
    /* 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;
      }
    }
#endif

    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 !IN_LLVM
    if (!hdrscan)    // Don't scan recursively for header content scan
      inlineScan();
#endif

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 STRUCTTHISREF
      if (ethis->type->ty == Tpointer)
      {   Type *t = ethis->type->nextOf();
          ethis = new PtrExp(ethis->loc, ethis);
          ethis->type = t;
      }
      ei = new ExpInitializer(ethis->loc, ethis);

      vthis = new VarDeclaration(ethis->loc, ethis->type, Id::This, ei);
      if (ethis->type->ty != Tclass)
          vthis->storage_class = STCref;
      else
          vthis->storage_class = STCin;
#else
      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;
#endif
      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;
#if STRUCTTHISREF
      if (ethis->type->ty != Tclass)
      {   /* This is a reference initialization, not a simple assignment.
           */
          ei->exp->op = TOKconstruct;
      }
#endif

      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--;
//eb->type->print();
//eb->print();
//eb->dump(0);
    return Expression::combine(e, eb);
}




Generated by  Doxygen 1.6.0   Back to index