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