1: 2: // Compiler implementation of the D programming language 3: // Copyright (c) 1999-2011 by Digital Mars 4: // All Rights Reserved 5: // written by Walter Bright 6: // http://www.digitalmars.com 7: // License for redistribution is by either the Artistic License 8: // in artistic.txt, or the GNU General Public License in gnu.txt. 9: // See the included readme.txt for details. 10: 11: #include <stdio.h> 12: #include <ctype.h> 13: static char __file__[] = __FILE__; /* for tassert.h */ 14: #include "tassert.h" 15: #include <math.h> 16: 17: #if __DMC__ 18: #include <complex.h> 19: #endif 20: 21: #include "cdef.h" 22: #include "lexer.h" 23: #include "mtype.h" 24: #include "expression.h" 25: #include "declaration.h" 26: #include "aggregate.h" 27: #include "init.h" 28: 29: 30: #ifdef IN_GCC 31: #include "d-gcc-real.h" 32: 33: /* %% fix? */ 34: extern "C" bool real_isnan (const real_t *); 35: #endif 36: 37: static real_t zero; // work around DMC bug for now 38: 39: 40: /************************************* 41: * If variable has a const initializer, 42: * return that initializer. 43: */ 44: 45: Expression *expandVar(int result, VarDeclaration *v) 46: { 47: //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null"); 48: 49: Expression *e = NULL; 50: if (!v) 51: return e; 52: if (!v->originalType && v->scope) // semantic() not yet run 53: v->semantic (v->scope); 54: 55: if (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) 56: { 57: if (!v->type) 58: { 59: //error("ICE"); 60: return e; 61: } 62: Type *tb = v->type->toBasetype(); 63: if (result & WANTinterpret || 64: v->storage_class & STCmanifest || 65: v->type->toBasetype()->isscalar() || 66: ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct)) 67: ) 68: { 69: if (v->init) 70: { 71: if (v->inuse) 72: { if (v->storage_class & STCmanifest) 73: v->error("recursive initialization of constant"); 74: goto L1; 75: } 76: Expression *ei = v->init->toExpression(); 77: if (!ei) 78: { if (v->storage_class & STCmanifest) 79: v->error("enum cannot be initialized with %s", v->init->toChars()); 80: goto L1; 81: } 82: if (ei->op == TOKconstruct || ei->op == TOKblit) 83: { AssignExp *ae = (AssignExp *)ei; 84: ei = ae->e2; 85: if (result & WANTinterpret) 86: { 87: v->inuse++; 88: ei = ei->optimize(result); 89: v->inuse--; 90: } 91: else if (ei->isConst() != 1 && ei->op != TOKstring) 92: goto L1; 93: 94: if (ei->type == v->type) 95: { // const variable initialized with const expression 96: } 97: else if (ei->implicitConvTo(v->type) >= MATCHconst) 98: { // const var initialized with non-const expression 99: ei = ei->implicitCastTo(0, v->type); 100: ei = ei->semantic(0); 101: } 102: else 103: goto L1; 104: } 105: if (v->scope) 106: { 107: v->inuse++; 108: e = ei->syntaxCopy(); 109: e = e->semantic(v->scope); 110: e = e->implicitCastTo(v->scope, v->type); 111: // enabling this line causes test22 in test suite to fail 112: //ei->type = e->type; 113: v->scope = NULL; 114: v->inuse--; 115: } 116: else if (!ei->type) 117: { 118: goto L1; 119: } 120: else 121: // Should remove the copy() operation by 122: // making all mods to expressions copy-on-write 123: e = ei->copy(); 124: } 125: else 126: { 127: #if 1 128: goto L1; 129: #else 130: // BUG: what if const is initialized in constructor? 131: e = v->type->defaultInit(); 132: e->loc = e1->loc; 133: #endif 134: } 135: if (e->type != v->type) 136: { 137: e = e->castTo(NULL, v->type); 138: } 139: v->inuse++; 140: e = e->optimize(result); 141: v->inuse--; 142: } 143: } 144: L1: 145: //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars()); 146: return e; 147: } 148: 149: 150: Expression *fromConstInitializer(int result, Expression *e1) 151: { 152: //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars()); 153: //static int xx; if (xx++ == 10) assert(0); 154: Expression *e = e1; 155: if (e1->op == TOKvar) 156: { VarExp *ve = (VarExp *)e1; 157: VarDeclaration *v = ve->var->isVarDeclaration(); 158: int fwdref = (v && !v->originalType && v->scope); 159: e = expandVar(result, v); 160: if (e) 161: { 162: // If it is a comma expression involving a declaration, we mustn't 163: // perform a copy -- we'd get two declarations of the same variable. 164: // See bugzilla 4465. 165: if (e->op == TOKcomma && ((CommaExp *)e)->e1->op == TOKdeclaration) 166: e = e1; 167: else 168: 169: if (e->type != e1->type && e1->type && e1->type->ty != Tident) 170: { // Type 'paint' operation 171: e = e->copy(); 172: e->type = e1->type; 173: } 174: e->loc = e1->loc; 175: } 176: else 177: { 178: e = e1; 179: /* If we needed to interpret, generate an error. 180: * Don't give an error if it's a template parameter 181: */ 182: if (v && (result & WANTinterpret) && 183: !(v->storage_class & STCtemplateparameter)) 184: { 185: e1->error("variable %s cannot be read at compile time", v->toChars()); 186: } 187: } 188: } 189: return e; 190: } 191: 192: 193: Expression *Expression::optimize(int result) 194: { 195: //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); 196: return this; 197: } 198: 199: Expression *VarExp::optimize(int result) 200: { 201: return fromConstInitializer(result, this); 202: } 203: 204: Expression *TupleExp::optimize(int result) 205: { 206: for (size_t i = 0; i < exps->dim; i++) 207: { Expression *e = exps->tdata()[i]; 208: 209: e = e->optimize(WANTvalue | (result & WANTinterpret)); 210: exps->tdata()[i] = e; 211: } 212: return this; 213: } 214: 215: Expression *ArrayLiteralExp::optimize(int result) 216: { 217: if (elements) 218: { 219: for (size_t i = 0; i < elements->dim; i++) 220: { Expression *e = elements->tdata()[i]; 221: 222: e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); 223: elements->tdata()[i] = e; 224: } 225: } 226: return this; 227: } 228: 229: Expression *AssocArrayLiteralExp::optimize(int result) 230: { 231: assert(keys->dim == values->dim); 232: for (size_t i = 0; i < keys->dim; i++) 233: { Expression *e = keys->tdata()[i]; 234: 235: e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); 236: keys->tdata()[i] = e; 237: 238: e = values->tdata()[i]; 239: e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); 240: values->tdata()[i] = e; 241: } 242: return this; 243: } 244: 245: Expression *StructLiteralExp::optimize(int result) 246: { 247: if (elements) 248: { 249: for (size_t i = 0; i < elements->dim; i++) 250: { Expression *e = elements->tdata()[i]; 251: if (!e) 252: continue; 253: e = e->optimize(WANTvalue | (result & (WANTinterpret | WANTexpand))); 254: elements->tdata()[i] = e; 255: } 256: } 257: return this; 258: } 259: 260: Expression *TypeExp::optimize(int result) 261: { 262: return this; 263: } 264: 265: Expression *UnaExp::optimize(int result) 266: { 267: e1 = e1->optimize(result); 268: return this; 269: } 270: 271: Expression *NegExp::optimize(int result) 272: { Expression *e; 273: 274: e1 = e1->optimize(result); 275: if (e1->isConst() == 1) 276: { 277: e = Neg(type, e1); 278: } 279: else 280: e = this; 281: return e; 282: } 283: 284: Expression *ComExp::optimize(int result) 285: { Expression *e; 286: 287: e1 = e1->optimize(result); 288: if (e1->isConst() == 1) 289: { 290: e = Com(type, e1); 291: } 292: else 293: e = this; 294: return e; 295: } 296: 297: Expression *NotExp::optimize(int result) 298: { Expression *e; 299: 300: e1 = e1->optimize(result); 301: if (e1->isConst() == 1) 302: { 303: e = Not(type, e1); 304: } 305: else 306: e = this; 307: return e; 308: } 309: 310: Expression *BoolExp::optimize(int result) 311: { Expression *e; 312: 313: e1 = e1->optimize(result); 314: if (e1->isConst() == 1) 315: { 316: e = Bool(type, e1); 317: } 318: else 319: e = this; 320: return e; 321: } 322: 323: Expression *AddrExp::optimize(int result) 324: { Expression *e; 325: 326: //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); 327: 328: /* Rewrite &(a,b) as (a,&b) 329: */ 330: if (e1->op == TOKcomma) 331: { CommaExp *ce = (CommaExp *)e1; 332: AddrExp *ae = new AddrExp(loc, ce->e2); 333: ae->type = type; 334: e = new CommaExp(ce->loc, ce->e1, ae); 335: e->type = type; 336: return e->optimize(result); 337: } 338: 339: if (e1->op == TOKvar) 340: { VarExp *ve = (VarExp *)e1; 341: if (ve->var->storage_class & STCmanifest) 342: e1 = e1->optimize(result); 343: } 344: else 345: e1 = e1->optimize(result); 346: 347: // Convert &*ex to ex 348: if (e1->op == TOKstar) 349: { Expression *ex; 350: 351: ex = ((PtrExp *)e1)->e1; 352: if (type->equals(ex->type)) 353: e = ex; 354: else 355: { 356: e = ex->copy(); 357: e->type = type; 358: } 359: return e; 360: } 361: if (e1->op == TOKvar) 362: { VarExp *ve = (VarExp *)e1; 363: if (!ve->var->isOut() && !ve->var->isRef() && 364: !ve->var->isImportedSymbol()) 365: { 366: SymOffExp *se = new SymOffExp(loc, ve->var, 0, ve->hasOverloads); 367: se->type = type; 368: return se; 369: } 370: } 371: if (e1->op == TOKindex) 372: { // Convert &array[n] to &array+n 373: IndexExp *ae = (IndexExp *)e1; 374: 375: if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) 376: { 377: dinteger_t index = ae->e2->toInteger(); 378: VarExp *ve = (VarExp *)ae->e1; 379: if (ve->type->ty == Tsarray 380: && !ve->var->isImportedSymbol()) 381: { 382: TypeSArray *ts = (TypeSArray *)ve->type; 383: dinteger_t dim = ts->dim->toInteger(); 384: if (index < 0 || index >= dim) 385: error("array index %jd is out of bounds [0..%jd]", index, dim); 386: e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size());warning C4244: 'argument' : conversion from 'dinteger_t' to 'unsigned int', possible loss of data387: e->type = type; 388: return e; 389: } 390: } 391: } 392: return this; 393: } 394: 395: Expression *PtrExp::optimize(int result) 396: { 397: //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); 398: e1 = e1->optimize(result); 399: // Convert *&ex to ex 400: if (e1->op == TOKaddress) 401: { Expression *e; 402: Expression *ex; 403: 404: ex = ((AddrExp *)e1)->e1; 405: if (type->equals(ex->type)) 406: e = ex; 407: else 408: { 409: e = ex->copy(); 410: e->type = type; 411: } 412: return e; 413: } 414: // Constant fold *(&structliteral + offset) 415: if (e1->op == TOKadd) 416: { 417: Expression *e; 418: e = Ptr(type, e1); 419: if (e != EXP_CANT_INTERPRET) 420: return e; 421: } 422: 423: if (e1->op == TOKsymoff) 424: { SymOffExp *se = (SymOffExp *)e1; 425: VarDeclaration *v = se->var->isVarDeclaration(); 426: Expression *e = expandVar(result, v); 427: if (e && e->op == TOKstructliteral) 428: { StructLiteralExp *sle = (StructLiteralExp *)e; 429: e = sle->getField(type, se->offset); 430: if (e && e != EXP_CANT_INTERPRET) 431: return e; 432: } 433: } 434: return this; 435: } 436: 437: Expression *DotVarExp::optimize(int result) 438: { 439: //printf("DotVarExp::optimize(result = x%x) %s\n", result, toChars()); 440: e1 = e1->optimize(result); 441: 442: Expression *e = e1; 443: 444: if (e1->op == TOKvar) 445: { VarExp *ve = (VarExp *)e1; 446: VarDeclaration *v = ve->var->isVarDeclaration(); 447: e = expandVar(result, v); 448: } 449: 450: if (e && e->op == TOKstructliteral) 451: { StructLiteralExp *sle = (StructLiteralExp *)e; 452: VarDeclaration *vf = var->isVarDeclaration(); 453: if (vf) 454: { 455: Expression *e = sle->getField(type, vf->offset);warning C6246: Local declaration of 'e' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '442' of 'c:\projects\extern\d\dmd\src\optimize.c': Lines: 442456: if (e && e != EXP_CANT_INTERPRET) 457: return e; 458: } 459: } 460: 461: return this; 462: } 463: 464: Expression *NewExp::optimize(int result) 465: { 466: if (thisexp) 467: thisexp = thisexp->optimize(WANTvalue); 468: 469: // Optimize parameters 470: if (newargs) 471: { 472: for (size_t i = 0; i < newargs->dim; i++) 473: { Expression *e = newargs->tdata()[i]; 474: 475: e = e->optimize(WANTvalue); 476: newargs->tdata()[i] = e; 477: } 478: } 479: 480: if (arguments) 481: { 482: for (size_t i = 0; i < arguments->dim; i++) 483: { Expression *e = arguments->tdata()[i]; 484: 485: e = e->optimize(WANTvalue); 486: arguments->tdata()[i] = e; 487: } 488: } 489: if (result & WANTinterpret) 490: { 491: error("cannot evaluate %s at compile time", toChars()); 492: } 493: return this; 494: } 495: 496: Expression *CallExp::optimize(int result) 497: { 498: //printf("CallExp::optimize(result = %d) %s\n", result, toChars()); 499: Expression *e = this; 500: 501: // Optimize parameters 502: if (arguments) 503: { 504: for (size_t i = 0; i < arguments->dim; i++) 505: { Expression *e = arguments->tdata()[i];warning C6246: Local declaration of 'e' hides declaration of the same name in outer scope. For additional information, see previous declaration at line '499' of 'c:\projects\extern\d\dmd\src\optimize.c': Lines: 499506: 507: e = e->optimize(WANTvalue); 508: arguments->tdata()[i] = e; 509: } 510: } 511: 512: e1 = e1->optimize(result); 513: #if 1 514: if (result & WANTinterpret) 515: { 516: Expression *eresult = interpret(NULL); 517: if (eresult == EXP_CANT_INTERPRET) 518: return e; 519: if (eresult && eresult != EXP_VOID_INTERPRET) 520: e = eresult; 521: else 522: error("cannot evaluate %s at compile time", toChars()); 523: } 524: #else 525: if (e1->op == TOKvar) 526: { 527: FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); 528: if (fd) 529: { 530: enum BUILTIN b = fd->isBuiltin(); 531: if (b) 532: { 533: e = eval_builtin(b, arguments); 534: if (!e) // failed 535: e = this; // evaluate at runtime 536: } 537: else if (result & WANTinterpret) 538: { 539: Expression *eresult = fd->interpret(NULL, arguments); 540: if (eresult && eresult != EXP_VOID_INTERPRET) 541: e = eresult; 542: else 543: error("cannot evaluate %s at compile time", toChars()); 544: } 545: } 546: } 547: else if (e1->op == TOKdotvar && result & WANTinterpret) 548: { DotVarExp *dve = (DotVarExp *)e1; 549: FuncDeclaration *fd = dve->var->isFuncDeclaration(); 550: if (fd) 551: { 552: Expression *eresult = fd->interpret(NULL, arguments, dve->e1); 553: if (eresult && eresult != EXP_VOID_INTERPRET) 554: e = eresult; 555: else 556: error("cannot evaluate %s at compile time", toChars()); 557: } 558: } 559: #endif 560: return e; 561: } 562: 563: 564: Expression *CastExp::optimize(int result) 565: { 566: //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); 567: //printf("from %s to %s\n", type->toChars(), to->toChars()); 568: //printf("from %s\n", type->toChars()); 569: //printf("e1->type %s\n", e1->type->toChars()); 570: //printf("type = %p\n", type); 571: assert(type); 572: enum TOK op1 = e1->op; 573: #define X 0 574: 575: Expression *e1old = e1; 576: e1 = e1->optimize(result); 577: e1 = fromConstInitializer(result, e1); 578: 579: if (e1 == e1old && 580: e1->op == TOKarrayliteral && 581: type->toBasetype()->ty == Tpointer && 582: e1->type->toBasetype()->ty != Tsarray) 583: { 584: // Casting this will result in the same expression, and 585: // infinite loop because of Expression::implicitCastTo() 586: return this; // no change 587: } 588: 589: if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && 590: (type->ty == Tpointer || type->ty == Tarray) && 591: e1->type->nextOf()->size() == type->nextOf()->size() 592: ) 593: { 594: Expression *e = e1->castTo(NULL, type); 595: if (X) printf(" returning1 %s\n", e->toChars()); 596: return e; 597: } 598: 599: if (e1->op == TOKstructliteral && 600: e1->type->implicitConvTo(type) >= MATCHconst) 601: { 602: e1->type = type; 603: if (X) printf(" returning2 %s\n", e1->toChars()); 604: return e1; 605: } 606: 607: /* The first test here is to prevent infinite loops 608: */ 609: if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) 610: return e1->castTo(NULL, to); 611: if (e1->op == TOKnull && 612: (type->ty == Tpointer || type->ty == Tclass || type->ty == Tarray)) 613: { 614: e1->type = type; 615: if (X) printf(" returning3 %s\n", e1->toChars()); 616: return e1; 617: } 618: 619: if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) 620: { 621: // See if we can remove an unnecessary cast 622: ClassDeclaration *cdfrom; 623: ClassDeclaration *cdto; 624: int offset; 625: 626: cdfrom = e1->type->isClassHandle(); 627: cdto = type->isClassHandle(); 628: if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) 629: { 630: e1->type = type; 631: if (X) printf(" returning4 %s\n", e1->toChars()); 632: return e1; 633: } 634: } 635: 636: // We can convert 'head const' to mutable 637: if (to->constOf()->equals(e1->type->constOf())) 638: // if (to->constConv(e1->type) >= MATCHconst) 639: { 640: e1->type = type; 641: if (X) printf(" returning5 %s\n", e1->toChars()); 642: return e1; 643: } 644: 645: Expression *e; 646: 647: if (e1->isConst()) 648: { 649: if (e1->op == TOKsymoff) 650: { 651: if (type->size() == e1->type->size() && 652: type->toBasetype()->ty != Tsarray) 653: { 654: e1->type = type; 655: return e1; 656: } 657: return this; 658: } 659: if (to->toBasetype()->ty == Tvoid) 660: e = this; 661: else 662: e = Cast(type, to, e1); 663: } 664: else 665: e = this; 666: if (X) printf(" returning6 %s\n", e->toChars()); 667: return e; 668: #undef X 669: } 670: 671: Expression *BinExp::optimize(int result) 672: { 673: //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); 674: if (op != TOKconstruct && op != TOKblit) // don't replace const variable with its initializer 675: e1 = e1->optimize(result); 676: e2 = e2->optimize(result); 677: if (op == TOKshlass || op == TOKshrass || op == TOKushrass) 678: { 679: if (e2->isConst() == 1) 680: { 681: dinteger_t i2 = e2->toInteger(); 682: d_uns64 sz = e1->type->size() * 8; 683: if (i2 < 0 || i2 > sz) 684: { error("shift assign by %jd is outside the range 0..%"SIZE_T_FORMAT"u", i2, sz); 685: e2 = new IntegerExp(0); 686: } 687: } 688: } 689: return this; 690: } 691: 692: Expression *AddExp::optimize(int result) 693: { Expression *e; 694: 695: //printf("AddExp::optimize(%s)\n", toChars()); 696: e1 = e1->optimize(result); 697: e2 = e2->optimize(result); 698: if (e1->isConst() && e2->isConst()) 699: { 700: if (e1->op == TOKsymoff && e2->op == TOKsymoff) 701: return this; 702: e = Add(type, e1, e2); 703: } 704: else 705: e = this; 706: return e; 707: } 708: 709: Expression *MinExp::optimize(int result) 710: { Expression *e; 711: 712: e1 = e1->optimize(result); 713: e2 = e2->optimize(result); 714: if (e1->isConst() && e2->isConst()) 715: { 716: if (e2->op == TOKsymoff) 717: return this; 718: e = Min(type, e1, e2); 719: } 720: else 721: e = this; 722: return e; 723: } 724: 725: Expression *MulExp::optimize(int result) 726: { Expression *e; 727: 728: //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); 729: e1 = e1->optimize(result); 730: e2 = e2->optimize(result); 731: if (e1->isConst() == 1 && e2->isConst() == 1) 732: { 733: e = Mul(type, e1, e2); 734: } 735: else 736: e = this; 737: return e; 738: } 739: 740: Expression *DivExp::optimize(int result) 741: { Expression *e; 742: 743: //printf("DivExp::optimize(%s)\n", toChars()); 744: e1 = e1->optimize(result); 745: e2 = e2->optimize(result); 746: if (e1->isConst() == 1 && e2->isConst() == 1) 747: { 748: e = Div(type, e1, e2); 749: } 750: else 751: e = this; 752: return e; 753: } 754: 755: Expression *ModExp::optimize(int result) 756: { Expression *e; 757: 758: e1 = e1->optimize(result); 759: e2 = e2->optimize(result); 760: if (e1->isConst() == 1 && e2->isConst() == 1) 761: { 762: e = Mod(type, e1, e2); 763: } 764: else 765: e = this; 766: return e; 767: } 768: 769: Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *)) 770: { Expression *ex = e; 771: 772: e->e1 = e->e1->optimize(result); 773: e->e2 = e->e2->optimize(result); 774: if (e->e2->isConst() == 1) 775: { 776: dinteger_t i2 = e->e2->toInteger(); 777: d_uns64 sz = e->e1->type->size() * 8; 778: if (i2 < 0 || i2 > sz) 779: { e->error("shift by %jd is outside the range 0..%"SIZE_T_FORMAT"u", i2, sz); 780: e->e2 = new IntegerExp(0); 781: } 782: if (e->e1->isConst() == 1) 783: ex = (*shift)(e->type, e->e1, e->e2); 784: } 785: return ex; 786: } 787: 788: Expression *ShlExp::optimize(int result) 789: { 790: //printf("ShlExp::optimize(result = %d) %s\n", result, toChars()); 791: return shift_optimize(result, this, Shl); 792: } 793: 794: Expression *ShrExp::optimize(int result) 795: { 796: //printf("ShrExp::optimize(result = %d) %s\n", result, toChars()); 797: return shift_optimize(result, this, Shr); 798: } 799: 800: Expression *UshrExp::optimize(int result) 801: { 802: //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); 803: return shift_optimize(result, this, Ushr); 804: } 805: 806: Expression *AndExp::optimize(int result) 807: { Expression *e; 808: 809: e1 = e1->optimize(result); 810: e2 = e2->optimize(result); 811: if (e1->isConst() == 1 && e2->isConst() == 1) 812: e = And(type, e1, e2); 813: else 814: e = this; 815: return e; 816: } 817: 818: Expression *OrExp::optimize(int result) 819: { Expression *e; 820: 821: e1 = e1->optimize(result); 822: e2 = e2->optimize(result); 823: if (e1->isConst() == 1 && e2->isConst() == 1) 824: e = Or(type, e1, e2); 825: else 826: e = this; 827: return e; 828: } 829: 830: Expression *XorExp::optimize(int result) 831: { Expression *e; 832: 833: e1 = e1->optimize(result); 834: e2 = e2->optimize(result); 835: if (e1->isConst() == 1 && e2->isConst() == 1) 836: e = Xor(type, e1, e2); 837: else 838: e = this; 839: return e; 840: } 841: 842: Expression *CommaExp::optimize(int result) 843: { Expression *e; 844: 845: //printf("CommaExp::optimize(result = %d) %s\n", result, toChars()); 846: // Comma needs special treatment, because it may 847: // contain compiler-generated declarations. We can interpret them, but 848: // otherwise we must NOT attempt to constant-fold them. 849: // In particular, if the comma returns a temporary variable, it needs 850: // to be an lvalue (this is particularly important for struct constructors) 851: 852: if (result & WANTinterpret) 853: { // Interpreting comma needs special treatment, because it may 854: // contain compiler-generated declarations. 855: e = interpret(NULL); 856: return (e == EXP_CANT_INTERPRET) ? this : e; 857: } 858: // Don't constant fold if it is a compiler-generated temporary. 859: if (e1->op == TOKdeclaration) 860: return this; 861: 862: e1 = e1->optimize(result & WANTinterpret); 863: e2 = e2->optimize(result); 864: if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2)) 865: { 866: e = e2; 867: if (e) 868: e->type = type; 869: } 870: else 871: e = this; 872: //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars()); 873: return e; 874: } 875: 876: Expression *ArrayLengthExp::optimize(int result) 877: { Expression *e; 878: 879: //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); 880: e1 = e1->optimize(WANTvalue | WANTexpand | (result & WANTinterpret)); 881: e = this; 882: if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) 883: { 884: e = ArrayLength(type, e1); 885: } 886: return e; 887: } 888: 889: Expression *EqualExp::optimize(int result) 890: { Expression *e; 891: 892: //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); 893: e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); 894: e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); 895: e = this; 896: 897: Expression *e1 = fromConstInitializer(result, this->e1); 898: Expression *e2 = fromConstInitializer(result, this->e2); 899: 900: e = Equal(op, type, e1, e2); 901: if (e == EXP_CANT_INTERPRET) 902: e = this; 903: return e; 904: } 905: 906: Expression *IdentityExp::optimize(int result) 907: { 908: //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); 909: e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); 910: e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); 911: Expression *e = this; 912: 913: if ((this->e1->isConst() && this->e2->isConst()) || 914: (this->e1->op == TOKnull && this->e2->op == TOKnull)) 915: { 916: e = Identity(op, type, this->e1, this->e2); 917: if (e == EXP_CANT_INTERPRET) 918: e = this; 919: } 920: return e; 921: } 922: 923: /* It is possible for constant folding to change an array expression of 924: * unknown length, into one where the length is known. 925: * If the expression 'arr' is a literal, set lengthVar to be its length. 926: */ 927: void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr) 928: { 929: if (!lengthVar) 930: return; 931: if (lengthVar->init && !lengthVar->init->isVoidInitializer()) 932: return; // we have previously calculated the length 933: size_t len; 934: if (arr->op == TOKstring) 935: len = ((StringExp *)arr)->len; 936: else if (arr->op == TOKarrayliteral) 937: len = ((ArrayLiteralExp *)arr)->elements->dim; 938: else 939: return; // we don't know the length yet 940: 941: Expression *dollar = new IntegerExp(0, len, Type::tsize_t); 942: lengthVar->init = new ExpInitializer(0, dollar); 943: lengthVar->storage_class |= STCstatic | STCconst; 944: } 945: 946: 947: Expression *IndexExp::optimize(int result) 948: { Expression *e; 949: 950: //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); 951: Expression *e1 = this->e1->optimize( 952: WANTvalue | (result & (WANTinterpret| WANTexpand))); 953: e1 = fromConstInitializer(result, e1); 954: if (this->e1->op == TOKvar) 955: { VarExp *ve = (VarExp *)this->e1; 956: if (ve->var->storage_class & STCmanifest) 957: { /* We generally don't want to have more than one copy of an 958: * array literal, but if it's an enum we have to because the 959: * enum isn't stored elsewhere. See Bugzilla 2559 960: */ 961: this->e1 = e1; 962: } 963: } 964: // We might know $ now 965: setLengthVarIfKnown(lengthVar, e1); 966: e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); 967: e = Index(type, e1, e2); 968: if (e == EXP_CANT_INTERPRET) 969: e = this; 970: return e; 971: } 972: 973: 974: Expression *SliceExp::optimize(int result) 975: { Expression *e; 976: 977: //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); 978: e = this; 979: e1 = e1->optimize(WANTvalue | (result & (WANTinterpret|WANTexpand))); 980: if (!lwr) 981: { if (e1->op == TOKstring) 982: { // Convert slice of string literal into dynamic array 983: Type *t = e1->type->toBasetype(); 984: if (t->nextOf()) 985: e = e1->castTo(NULL, t->nextOf()->arrayOf()); 986: } 987: return e; 988: } 989: e1 = fromConstInitializer(result, e1); 990: // We might know $ now 991: setLengthVarIfKnown(lengthVar, e1); 992: lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); 993: upr = upr->optimize(WANTvalue | (result & WANTinterpret)); 994: e = Slice(type, e1, lwr, upr); 995: if (e == EXP_CANT_INTERPRET) 996: e = this; 997: //printf("-SliceExp::optimize() %s\n", e->toChars()); 998: return e; 999: } 1000: 1001: Expression *AndAndExp::optimize(int result) 1002: { Expression *e; 1003: 1004: //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); 1005: e1 = e1->optimize(WANTflags | (result & WANTinterpret)); 1006: e = this; 1007: if (e1->isBool(FALSE)) 1008: { 1009: e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); 1010: e->type = type; 1011: e = e->optimize(result); 1012: } 1013: else 1014: { 1015: e2 = e2->optimize(WANTflags | (result & WANTinterpret)); 1016: if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) 1017: error("void has no value"); 1018: if (e1->isConst()) 1019: { 1020: if (e2->isConst()) 1021: { int n1 = e1->isBool(1); 1022: int n2 = e2->isBool(1); 1023: 1024: e = new IntegerExp(loc, n1 && n2, type); 1025: } 1026: else if (e1->isBool(TRUE)) 1027: e = new BoolExp(loc, e2, type); 1028: } 1029: } 1030: return e; 1031: } 1032: 1033: Expression *OrOrExp::optimize(int result) 1034: { Expression *e; 1035: 1036: e1 = e1->optimize(WANTflags | (result & WANTinterpret)); 1037: e = this; 1038: if (e1->isBool(TRUE)) 1039: { // Replace with (e1, 1) 1040: e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type)); 1041: e->type = type; 1042: e = e->optimize(result); 1043: } 1044: else 1045: { 1046: e2 = e2->optimize(WANTflags | (result & WANTinterpret)); 1047: if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) 1048: error("void has no value"); 1049: if (e1->isConst()) 1050: { 1051: if (e2->isConst()) 1052: { int n1 = e1->isBool(1); 1053: int n2 = e2->isBool(1); 1054: 1055: e = new IntegerExp(loc, n1 || n2, type); 1056: } 1057: else if (e1->isBool(FALSE)) 1058: e = new BoolExp(loc, e2, type); 1059: } 1060: } 1061: return e; 1062: } 1063: 1064: Expression *CmpExp::optimize(int result) 1065: { Expression *e; 1066: 1067: //printf("CmpExp::optimize() %s\n", toChars()); 1068: e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); 1069: e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); 1070: 1071: Expression *e1 = fromConstInitializer(result, this->e1); 1072: Expression *e2 = fromConstInitializer(result, this->e2); 1073: 1074: e = Cmp(op, type, e1, e2); 1075: if (e == EXP_CANT_INTERPRET) 1076: e = this; 1077: return e; 1078: } 1079: 1080: Expression *CatExp::optimize(int result) 1081: { Expression *e; 1082: 1083: //printf("CatExp::optimize(%d) %s\n", result, toChars()); 1084: e1 = e1->optimize(result); 1085: e2 = e2->optimize(result); 1086: e = Cat(type, e1, e2); 1087: if (e == EXP_CANT_INTERPRET) 1088: e = this; 1089: return e; 1090: } 1091: 1092: 1093: Expression *CondExp::optimize(int result) 1094: { Expression *e; 1095: 1096: econd = econd->optimize(WANTflags | (result & WANTinterpret)); 1097: if (econd->isBool(TRUE)) 1098: e = e1->optimize(result); 1099: else if (econd->isBool(FALSE)) 1100: e = e2->optimize(result); 1101: else 1102: { e1 = e1->optimize(result); 1103: e2 = e2->optimize(result); 1104: e = this; 1105: } 1106: return e; 1107: } 1108: 1109: 1110: