Mercurial > projects > ldc
view dmd2/optimize.c @ 1415:bac3931b3de3
Fix a behavioral change accidentally introduced by the move to the LLVM
commandline system: `-output-(bc|ll|s)` used to disable generation of an object
file unless explicitly requested with `-output-o`. Now they do so again.
author | Frits van Bommel <fvbommel wxs.nl> |
---|---|
date | Sat, 23 May 2009 20:57:22 +0200 |
parents | f04dde6e882c |
children | 638d16625da2 |
line wrap: on
line source
// Compiler implementation of the D programming language // Copyright (c) 1999-2007 by Digital Mars // All Rights Reserved // written by Walter Bright // http://www.digitalmars.com // License for redistribution is by either the Artistic License // in artistic.txt, or the GNU General Public License in gnu.txt. // See the included readme.txt for details. #include <stdio.h> #include <ctype.h> #include <assert.h> #include <math.h> #if __DMC__ #include <complex.h> #endif #include "lexer.h" #include "mtype.h" #include "expression.h" #include "declaration.h" #include "aggregate.h" #include "init.h" #ifdef IN_GCC #include "d-gcc-real.h" /* %% fix? */ extern "C" bool real_isnan (const real_t *); #endif static real_t zero; // work around DMC bug for now /************************************* * If variable has a const initializer, * return that initializer. */ Expression *expandVar(int result, VarDeclaration *v) { //printf("expandVar(result = %d, v = %s)\n", result, v ? v->toChars() : "null"); Expression *e = NULL; if (v && (v->isConst() || v->isInvariant() || v->storage_class & STCmanifest)) { Type *tb = v->type->toBasetype(); if (result & WANTinterpret || v->storage_class & STCmanifest || (tb->ty != Tsarray && tb->ty != Tstruct) ) { if (v->init) { if (v->inuse) goto L1; Expression *ei = v->init->toExpression(); if (!ei) goto L1; if (ei->op == TOKconstruct || ei->op == TOKblit) { AssignExp *ae = (AssignExp *)ei; ei = ae->e2; if (ei->isConst() != 1 && ei->op != TOKstring) goto L1; if (ei->type != v->type) goto L1; } if (v->scope) { v->inuse++; e = ei->syntaxCopy(); e = e->semantic(v->scope); e = e->implicitCastTo(v->scope, v->type); v->scope = NULL; v->inuse--; } else if (!ei->type) { goto L1; } else // Should remove the copy() operation by // making all mods to expressions copy-on-write e = ei->copy(); } else { #if 1 goto L1; #else // BUG: what if const is initialized in constructor? e = v->type->defaultInit(); e->loc = e1->loc; #endif } if (e->type != v->type) { e = e->castTo(NULL, v->type); } e = e->optimize(result); } } L1: //if (e) printf("\te = %s, e->type = %s\n", e->toChars(), e->type->toChars()); return e; } Expression *fromConstInitializer(int result, Expression *e1) { //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars()); //static int xx; if (xx++ == 10) assert(0); Expression *e = e1; if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; VarDeclaration *v = ve->var->isVarDeclaration(); e = expandVar(result, v); if (e) { if (e->type != e1->type) { // Type 'paint' operation e = e->copy(); e->type = e1->type; } } else e = e1; } return e; } Expression *Expression::optimize(int result) { //printf("Expression::optimize(result = x%x) %s\n", result, toChars()); return this; } Expression *VarExp::optimize(int result) { return fromConstInitializer(result, this); } Expression *TupleExp::optimize(int result) { for (size_t i = 0; i < exps->dim; i++) { Expression *e = (Expression *)exps->data[i]; e = e->optimize(WANTvalue | (result & WANTinterpret)); exps->data[i] = (void *)e; } return this; } Expression *ArrayLiteralExp::optimize(int result) { if (elements) { for (size_t i = 0; i < elements->dim; i++) { Expression *e = (Expression *)elements->data[i]; e = e->optimize(WANTvalue | (result & WANTinterpret)); elements->data[i] = (void *)e; } } return this; } Expression *AssocArrayLiteralExp::optimize(int result) { assert(keys->dim == values->dim); for (size_t i = 0; i < keys->dim; i++) { Expression *e = (Expression *)keys->data[i]; e = e->optimize(WANTvalue | (result & WANTinterpret)); keys->data[i] = (void *)e; e = (Expression *)values->data[i]; e = e->optimize(WANTvalue | (result & WANTinterpret)); values->data[i] = (void *)e; } return this; } Expression *StructLiteralExp::optimize(int result) { if (elements) { for (size_t i = 0; i < elements->dim; i++) { Expression *e = (Expression *)elements->data[i]; if (!e) continue; e = e->optimize(WANTvalue | (result & WANTinterpret)); elements->data[i] = (void *)e; } } return this; } Expression *TypeExp::optimize(int result) { return this; } Expression *UnaExp::optimize(int result) { e1 = e1->optimize(result); return this; } Expression *NegExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); if (e1->isConst() == 1) { e = Neg(type, e1); } else e = this; return e; } Expression *ComExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); if (e1->isConst() == 1) { e = Com(type, e1); } else e = this; return e; } Expression *NotExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); if (e1->isConst() == 1) { e = Not(type, e1); } else e = this; return e; } Expression *BoolExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); if (e1->isConst() == 1) { e = Bool(type, e1); } else e = this; return e; } Expression *AddrExp::optimize(int result) { Expression *e; //printf("AddrExp::optimize(result = %d) %s\n", result, toChars()); /* Rewrite &(a,b) as (a,&b) */ if (e1->op == TOKcomma) { CommaExp *ce = (CommaExp *)e1; AddrExp *ae = new AddrExp(loc, ce->e2); ae->type = type; e = new CommaExp(ce->loc, ce->e1, ae); e->type = type; return e->optimize(result); } if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; if (ve->var->storage_class & STCmanifest) e1 = e1->optimize(result); } else e1 = e1->optimize(result); // Convert &*ex to ex if (e1->op == TOKstar) { Expression *ex; ex = ((PtrExp *)e1)->e1; if (type->equals(ex->type)) e = ex; else { e = ex->copy(); e->type = type; } return e; } #if !IN_LLVM if (e1->op == TOKvar) { VarExp *ve = (VarExp *)e1; if (!ve->var->isOut() && !ve->var->isRef() && !ve->var->isImportedSymbol()) { SymOffExp *se = new SymOffExp(loc, ve->var, 0, ve->hasOverloads); se->type = type; return se; } } if (e1->op == TOKindex) { // Convert &array[n] to &array+n IndexExp *ae = (IndexExp *)e1; if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) { integer_t index = ae->e2->toInteger(); VarExp *ve = (VarExp *)ae->e1; if (ve->type->ty == Tsarray && !ve->var->isImportedSymbol()) { TypeSArray *ts = (TypeSArray *)ve->type; integer_t dim = ts->dim->toInteger(); if (index < 0 || index >= dim) error("array index %lld is out of bounds [0..%lld]", index, dim); e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size()); e->type = type; return e; } } } #endif return this; } Expression *PtrExp::optimize(int result) { //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars()); e1 = e1->optimize(result); // Convert *&ex to ex if (e1->op == TOKaddress) { Expression *e; Expression *ex; ex = ((AddrExp *)e1)->e1; if (type->equals(ex->type)) e = ex; else { e = ex->copy(); e->type = type; } return e; } // Constant fold *(&structliteral + offset) if (e1->op == TOKadd) { Expression *e; e = Ptr(type, e1); if (e != EXP_CANT_INTERPRET) return e; } if (e1->op == TOKsymoff) { SymOffExp *se = (SymOffExp *)e1; VarDeclaration *v = se->var->isVarDeclaration(); Expression *e = expandVar(result, v); if (e && e->op == TOKstructliteral) { StructLiteralExp *sle = (StructLiteralExp *)e; e = sle->getField(type, se->offset); if (e != EXP_CANT_INTERPRET) return e; } } return this; } /////////////////////////////////////////// // LDC Expression *DotVarExp::optimize(int result) { e1 = e1->optimize(result); // Constant fold structliteral.member if (e1->op == TOKstructliteral) { StructLiteralExp *se = (StructLiteralExp *)e1; VarDeclaration* v; if (v = var->isVarDeclaration()) { Expression *e = se->getField(type, v->offset); if (!e) e = EXP_CANT_INTERPRET; return e; } } return this; } /////////////////////////////////////////// Expression *CallExp::optimize(int result) { //printf("CallExp::optimize(result = %d) %s\n", result, toChars()); Expression *e = this; e1 = e1->optimize(result); if (e1->op == TOKvar) { FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration(); if (fd) { enum BUILTIN b = fd->isBuiltin(); if (b) { e = eval_builtin(b, arguments); if (!e) // failed e = this; // evaluate at runtime } else if (result & WANTinterpret) { Expression *eresult = fd->interpret(NULL, arguments); if (eresult && eresult != EXP_VOID_INTERPRET) e = eresult; else error("cannot evaluate %s at compile time", toChars()); } } } return e; } Expression *CastExp::optimize(int result) { //printf("CastExp::optimize(result = %d) %s\n", result, toChars()); //printf("from %s to %s\n", type->toChars(), to->toChars()); //printf("from %s\n", type->toChars()); //printf("e1->type %s\n", e1->type->toChars()); //printf("type = %p\n", type); assert(type); enum TOK op1 = e1->op; #define X 0 e1 = e1->optimize(result); e1 = fromConstInitializer(result, e1); if ((e1->op == TOKstring || e1->op == TOKarrayliteral) && (type->ty == Tpointer || type->ty == Tarray) && e1->type->nextOf()->size() == type->nextOf()->size() ) { e1 = e1->castTo(NULL, type); if (X) printf(" returning1 %s\n", e1->toChars()); return e1; } if (e1->op == TOKstructliteral && e1->type->implicitConvTo(type) >= MATCHconst) { e1->type = type; if (X) printf(" returning2 %s\n", e1->toChars()); return e1; } /* The first test here is to prevent infinite loops */ if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral) return e1->castTo(NULL, to); if (e1->op == TOKnull && (type->ty == Tpointer || type->ty == Tclass || type->ty == Tarray)) { e1->type = type; if (X) printf(" returning3 %s\n", e1->toChars()); return e1; } if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass) { // See if we can remove an unnecessary cast ClassDeclaration *cdfrom; ClassDeclaration *cdto; int offset; cdfrom = e1->type->isClassHandle(); cdto = type->isClassHandle(); if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) { e1->type = type; if (X) printf(" returning4 %s\n", e1->toChars()); return e1; } } // We can convert 'head const' to mutable if (to->constOf()->equals(e1->type->constOf())) // if (to->constConv(e1->type) >= MATCHconst) { e1->type = type; if (X) printf(" returning5 %s\n", e1->toChars()); return e1; } Expression *e; if (e1->isConst()) { if (e1->op == TOKsymoff) { if (type->size() == e1->type->size() && type->toBasetype()->ty != Tsarray) { e1->type = type; return e1; } return this; } if (to->toBasetype()->ty == Tvoid) e = this; else e = Cast(type, to, e1); } else e = this; if (X) printf(" returning6 %s\n", e->toChars()); return e; #undef X } Expression *BinExp::optimize(int result) { //printf("BinExp::optimize(result = %d) %s\n", result, toChars()); if (op != TOKconstruct && op != TOKblit) // don't replace const variable with its initializer e1 = e1->optimize(result); e2 = e2->optimize(result); if (op == TOKshlass || op == TOKshrass || op == TOKushrass) { if (e2->isConst() == 1) { integer_t i2 = e2->toInteger(); d_uns64 sz = e1->type->size() * 8; if (i2 < 0 || i2 > sz) { error("shift assign by %lld is outside the range 0..%"PRIuSIZE, i2, sz); e2 = new IntegerExp(0); } } } return this; } Expression *AddExp::optimize(int result) { Expression *e; //printf("AddExp::optimize(%s)\n", toChars()); e1 = e1->optimize(result); e2 = e2->optimize(result); if (e1->isConst() && e2->isConst()) { if (e1->op == TOKsymoff && e2->op == TOKsymoff) return this; e = Add(type, e1, e2); } else e = this; return e; } Expression *MinExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); e2 = e2->optimize(result); if (e1->isConst() && e2->isConst()) { if (e2->op == TOKsymoff) return this; e = Min(type, e1, e2); } else e = this; return e; } Expression *MulExp::optimize(int result) { Expression *e; //printf("MulExp::optimize(result = %d) %s\n", result, toChars()); e1 = e1->optimize(result); e2 = e2->optimize(result); if (e1->isConst() == 1 && e2->isConst() == 1) { e = Mul(type, e1, e2); } else e = this; return e; } Expression *DivExp::optimize(int result) { Expression *e; //printf("DivExp::optimize(%s)\n", toChars()); e1 = e1->optimize(result); e2 = e2->optimize(result); if (e1->isConst() == 1 && e2->isConst() == 1) { e = Div(type, e1, e2); } else e = this; return e; } Expression *ModExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); e2 = e2->optimize(result); if (e1->isConst() == 1 && e2->isConst() == 1) { e = Mod(type, e1, e2); } else e = this; return e; } Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *)) { Expression *ex = e; e->e1 = e->e1->optimize(result); e->e2 = e->e2->optimize(result); if (e->e2->isConst() == 1) { integer_t i2 = e->e2->toInteger(); d_uns64 sz = e->e1->type->size() * 8; if (i2 < 0 || i2 > sz) { error("shift by %lld is outside the range 0..%"PRIuSIZE, i2, sz); e->e2 = new IntegerExp(0); } if (e->e1->isConst() == 1) ex = (*shift)(e->type, e->e1, e->e2); } return ex; } Expression *ShlExp::optimize(int result) { //printf("ShlExp::optimize(result = %d) %s\n", result, toChars()); return shift_optimize(result, this, Shl); } Expression *ShrExp::optimize(int result) { //printf("ShrExp::optimize(result = %d) %s\n", result, toChars()); return shift_optimize(result, this, Shr); } Expression *UshrExp::optimize(int result) { //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); return shift_optimize(result, this, Ushr); } Expression *AndExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); e2 = e2->optimize(result); if (e1->isConst() == 1 && e2->isConst() == 1) e = And(type, e1, e2); else e = this; return e; } Expression *OrExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); e2 = e2->optimize(result); if (e1->isConst() == 1 && e2->isConst() == 1) e = Or(type, e1, e2); else e = this; return e; } Expression *XorExp::optimize(int result) { Expression *e; e1 = e1->optimize(result); e2 = e2->optimize(result); if (e1->isConst() == 1 && e2->isConst() == 1) e = Xor(type, e1, e2); else e = this; return e; } Expression *CommaExp::optimize(int result) { Expression *e; //printf("CommaExp::optimize(result = %d) %s\n", result, toChars()); e1 = e1->optimize(result & WANTinterpret); e2 = e2->optimize(result); if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2)) { e = e2; if (e) e->type = type; } else e = this; //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars()); return e; } Expression *ArrayLengthExp::optimize(int result) { Expression *e; //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars()); e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); e = this; if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral) { e = ArrayLength(type, e1); } return e; } Expression *EqualExp::optimize(int result) { Expression *e; //printf("EqualExp::optimize(result = %x) %s\n", result, toChars()); e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); e = this; Expression *e1 = fromConstInitializer(result, this->e1); Expression *e2 = fromConstInitializer(result, this->e2); e = Equal(op, type, e1, e2); if (e == EXP_CANT_INTERPRET) e = this; return e; } Expression *IdentityExp::optimize(int result) { Expression *e; //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars()); e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); e = this; if (this->e1->isConst() && this->e2->isConst()) { e = Identity(op, type, this->e1, this->e2); } return e; } Expression *IndexExp::optimize(int result) { Expression *e; //printf("IndexExp::optimize(result = %d) %s\n", result, toChars()); Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret)); e1 = fromConstInitializer(result, e1); e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); e = Index(type, e1, e2); if (e == EXP_CANT_INTERPRET) e = this; return e; } Expression *SliceExp::optimize(int result) { Expression *e; //printf("SliceExp::optimize(result = %d) %s\n", result, toChars()); e = this; e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); if (!lwr) { if (e1->op == TOKstring) { // Convert slice of string literal into dynamic array Type *t = e1->type->toBasetype(); if (t->nextOf()) e = e1->castTo(NULL, t->nextOf()->arrayOf()); } return e; } e1 = fromConstInitializer(result, e1); lwr = lwr->optimize(WANTvalue | (result & WANTinterpret)); upr = upr->optimize(WANTvalue | (result & WANTinterpret)); e = Slice(type, e1, lwr, upr); if (e == EXP_CANT_INTERPRET) e = this; //printf("-SliceExp::optimize() %s\n", e->toChars()); return e; } Expression *AndAndExp::optimize(int result) { Expression *e; //printf("AndAndExp::optimize(%d) %s\n", result, toChars()); e1 = e1->optimize(WANTflags | (result & WANTinterpret)); e = this; if (e1->isBool(FALSE)) { e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type)); e->type = type; e = e->optimize(result); } else { e2 = e2->optimize(WANTflags | (result & WANTinterpret)); if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) error("void has no value"); if (e1->isConst()) { if (e2->isConst()) { int n1 = e1->isBool(1); int n2 = e2->isBool(1); e = new IntegerExp(loc, n1 && n2, type); } else if (e1->isBool(TRUE)) e = new BoolExp(loc, e2, type); } } return e; } Expression *OrOrExp::optimize(int result) { Expression *e; e1 = e1->optimize(WANTflags | (result & WANTinterpret)); e = this; if (e1->isBool(TRUE)) { // Replace with (e1, 1) e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type)); e->type = type; e = e->optimize(result); } else { e2 = e2->optimize(WANTflags | (result & WANTinterpret)); if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors) error("void has no value"); if (e1->isConst()) { if (e2->isConst()) { int n1 = e1->isBool(1); int n2 = e2->isBool(1); e = new IntegerExp(loc, n1 || n2, type); } else if (e1->isBool(FALSE)) e = new BoolExp(loc, e2, type); } } return e; } Expression *CmpExp::optimize(int result) { Expression *e; //printf("CmpExp::optimize() %s\n", toChars()); e1 = e1->optimize(WANTvalue | (result & WANTinterpret)); e2 = e2->optimize(WANTvalue | (result & WANTinterpret)); Expression *e1 = fromConstInitializer(result, this->e1); Expression *e2 = fromConstInitializer(result, this->e2); e = Cmp(op, type, e1, e2); if (e == EXP_CANT_INTERPRET) e = this; return e; } Expression *CatExp::optimize(int result) { Expression *e; //printf("CatExp::optimize(%d) %s\n", result, toChars()); e1 = e1->optimize(result); e2 = e2->optimize(result); e = Cat(type, e1, e2); if (e == EXP_CANT_INTERPRET) e = this; return e; } Expression *CondExp::optimize(int result) { Expression *e; econd = econd->optimize(WANTflags | (result & WANTinterpret)); if (econd->isBool(TRUE)) e = e1->optimize(result); else if (econd->isBool(FALSE)) e = e2->optimize(result); else { e1 = e1->optimize(result); e2 = e2->optimize(result); e = this; } return e; }