diff options
Diffstat (limited to 'gcc/d/dmd/optimize.c')
-rw-r--r-- | gcc/d/dmd/optimize.c | 1230 |
1 files changed, 0 insertions, 1230 deletions
diff --git a/gcc/d/dmd/optimize.c b/gcc/d/dmd/optimize.c deleted file mode 100644 index 44dedd8..0000000 --- a/gcc/d/dmd/optimize.c +++ /dev/null @@ -1,1230 +0,0 @@ - -/* Compiler implementation of the D programming language - * Copyright (C) 1999-2021 by The D Language Foundation, All Rights Reserved - * written by Walter Bright - * http://www.digitalmars.com - * Distributed under the Boost Software License, Version 1.0 - * http://www.boost.org/LICENSE_1_0.txt - * https://github.com/D-Programming-Language/dmd/blob/master/src/optimize.c - */ - -#include "root/dsystem.h" - -#include "root/checkedint.h" -#include "lexer.h" -#include "mtype.h" -#include "expression.h" -#include "declaration.h" -#include "aggregate.h" -#include "init.h" -#include "enum.h" -#include "ctfe.h" -#include "errors.h" - -/************************************* - * If variable has a const initializer, - * return that initializer. - */ - -Expression *expandVar(int result, VarDeclaration *v) -{ - //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null"); - - Expression *e = NULL; - if (!v) - return e; - if (!v->originalType && v->semanticRun < PASSsemanticdone) // semantic() not yet run - dsymbolSemantic(v, NULL); - - if (v->isConst() || v->isImmutable() || v->storage_class & STCmanifest) - { - if (!v->type) - { - return e; - } - Type *tb = v->type->toBasetype(); - if (v->storage_class & STCmanifest || - v->type->toBasetype()->isscalar() || - ((result & WANTexpand) && (tb->ty != Tsarray && tb->ty != Tstruct)) - ) - { - if (v->_init) - { - if (v->inuse) - { - if (v->storage_class & STCmanifest) - { - v->error("recursive initialization of constant"); - goto Lerror; - } - goto L1; - } - Expression *ei = v->getConstInitializer(); - if (!ei) - { - if (v->storage_class & STCmanifest) - { - v->error("enum cannot be initialized with %s", v->_init->toChars()); - goto Lerror; - } - goto L1; - } - if (ei->op == TOKconstruct || ei->op == TOKblit) - { - AssignExp *ae = (AssignExp *)ei; - ei = ae->e2; - if (ei->isConst() == 1) - { - } - else if (ei->op == TOKstring) - { - // Bugzilla 14459: We should not constfold the string literal - // if it's typed as a C string, because the value expansion - // will drop the pointer identity. - if (!(result & WANTexpand) && ei->type->toBasetype()->ty == Tpointer) - goto L1; - } - else - goto L1; - - if (ei->type == v->type) - { - // const variable initialized with const expression - } - else if (ei->implicitConvTo(v->type) >= MATCHconst) - { - // const var initialized with non-const expression - ei = ei->implicitCastTo(NULL, v->type); - ei = expressionSemantic(ei, NULL); - } - else - goto L1; - } - else if (!(v->storage_class & STCmanifest) && - ei->isConst() != 1 && ei->op != TOKstring && - ei->op != TOKaddress) - { - goto L1; - } - if (!ei->type) - { - goto L1; - } - else - { - // Should remove the copy() operation by - // making all mods to expressions copy-on-write - e = ei->copy(); - } - } - else - { - goto L1; - } - if (e->type != v->type) - { - e = e->castTo(NULL, v->type); - } - v->inuse++; - e = e->optimize(result); - v->inuse--; - } - } -L1: - //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars()); - return e; - -Lerror: - return new ErrorExp(); -} - - -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 it is a comma expression involving a declaration, we mustn't - // perform a copy -- we'd get two declarations of the same variable. - // See bugzilla 4465. - if (e->op == TOKcomma && ((CommaExp *)e)->e1->op == TOKdeclaration) - e = e1; - else - - if (e->type != e1->type && e1->type && e1->type->ty != Tident) - { - // Type 'paint' operation - e = e->copy(); - e->type = e1->type; - } - e->loc = e1->loc; - } - else - { - e = e1; - } - } - return e; -} - -Expression *Expression_optimize(Expression *e, int result, bool keepLvalue) -{ - class OptimizeVisitor : public Visitor - { - public: - int result; - bool keepLvalue; - Expression *ret; - - OptimizeVisitor(int result, bool keepLvalue) - : result(result), keepLvalue(keepLvalue) - { - } - - void error() - { - ret = new ErrorExp(); - } - - bool expOptimize(Expression *&e, int flags, bool keepLvalue = false) - { - if (!e) - return false; - Expression *ex = e->optimize(flags, keepLvalue); - if (ex->op == TOKerror) - { - ret = ex; // store error result - return true; - } - else - { - e = ex; // modify original - return false; - } - } - - bool unaOptimize(UnaExp *e, int flags) - { - return expOptimize(e->e1, flags); - } - - bool binOptimize(BinExp *e, int flags) - { - expOptimize(e->e1, flags); - expOptimize(e->e2, flags); - return ret->op == TOKerror; - } - - void visit(Expression *) - { - //printf("Expression::optimize(result = x%x) %s\n", result, e->toChars()); - } - - void visit(VarExp *e) - { - if (keepLvalue) - { - VarDeclaration *v = e->var->isVarDeclaration(); - if (v && !(v->storage_class & STCmanifest)) - return; - } - ret = fromConstInitializer(result, e); - } - - void visit(TupleExp *e) - { - expOptimize(e->e0, WANTvalue); - for (size_t i = 0; i < e->exps->length; i++) - { - expOptimize((*e->exps)[i], WANTvalue); - } - } - - void visit(ArrayLiteralExp *e) - { - if (e->elements) - { - expOptimize(e->basis, result & WANTexpand); - for (size_t i = 0; i < e->elements->length; i++) - { - expOptimize((*e->elements)[i], result & WANTexpand); - } - } - } - - void visit(AssocArrayLiteralExp *e) - { - assert(e->keys->length == e->values->length); - for (size_t i = 0; i < e->keys->length; i++) - { - expOptimize((*e->keys)[i], result & WANTexpand); - expOptimize((*e->values)[i], result & WANTexpand); - } - } - - void visit(StructLiteralExp *e) - { - if (e->stageflags & stageOptimize) return; - int old = e->stageflags; - e->stageflags |= stageOptimize; - if (e->elements) - { - for (size_t i = 0; i < e->elements->length; i++) - { - expOptimize((*e->elements)[i], result & WANTexpand); - } - } - e->stageflags = old; - } - - void visit(UnaExp *e) - { - //printf("UnaExp::optimize() %s\n", e->toChars()); - if (unaOptimize(e, result)) - return; - } - - void visit(NegExp *e) - { - if (unaOptimize(e, result)) - return; - - if (e->e1->isConst() == 1) - { - ret = Neg(e->type, e->e1).copy(); - } - } - - void visit(ComExp *e) - { - if (unaOptimize(e, result)) - return; - - if (e->e1->isConst() == 1) - { - ret = Com(e->type, e->e1).copy(); - } - } - - void visit(NotExp *e) - { - if (unaOptimize(e, result)) - return; - - if (e->e1->isConst() == 1) - { - ret = Not(e->type, e->e1).copy(); - } - } - - void visit(SymOffExp *e) - { - assert(e->var); - } - - void visit(AddrExp *e) - { - //printf("AddrExp::optimize(result = %d) %s\n", result, e->toChars()); - - /* Rewrite &(a,b) as (a,&b) - */ - if (e->e1->op == TOKcomma) - { - CommaExp *ce = (CommaExp *)e->e1; - AddrExp *ae = new AddrExp(e->loc, ce->e2, e->type); - ret = new CommaExp(ce->loc, ce->e1, ae); - ret->type = e->type; - return; - } - - // Keep lvalue-ness - if (expOptimize(e->e1, result, true)) - return; - - // Convert &*ex to ex - if (e->e1->op == TOKstar) - { - Expression *ex = ((PtrExp *)e->e1)->e1; - if (e->type->equals(ex->type)) - ret = ex; - else if (e->type->toBasetype()->equivalent(ex->type->toBasetype())) - { - ret = ex->copy(); - ret->type = e->type; - } - return; - } - if (e->e1->op == TOKvar) - { - VarExp *ve = (VarExp *)e->e1; - if (!ve->var->isOut() && !ve->var->isRef() && - !ve->var->isImportedSymbol()) - { - ret = new SymOffExp(e->loc, ve->var, 0, ve->hasOverloads); - ret->type = e->type; - return; - } - } - if (e->e1->op == TOKindex) - { - // Convert &array[n] to &array+n - IndexExp *ae = (IndexExp *)e->e1; - - if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar) - { - sinteger_t index = ae->e2->toInteger(); - VarExp *ve = (VarExp *)ae->e1; - if (ve->type->ty == Tsarray - && !ve->var->isImportedSymbol()) - { - TypeSArray *ts = (TypeSArray *)ve->type; - sinteger_t dim = ts->dim->toInteger(); - if (index < 0 || index >= dim) - { - e->error("array index %lld is out of bounds [0..%lld]", index, dim); - return error(); - } - - bool overflow = false; - const d_uns64 offset = mulu(index, ts->nextOf()->size(e->loc), overflow); - if (overflow) - { - e->error("array offset overflow"); - return error(); - } - - ret = new SymOffExp(e->loc, ve->var, offset); - ret->type = e->type; - return; - } - } - } - } - - void visit(PtrExp *e) - { - //printf("PtrExp::optimize(result = x%x) %s\n", result, e->toChars()); - if (expOptimize(e->e1, result)) - return; - // Convert *&ex to ex - // But only if there is no type punning involved - if (e->e1->op == TOKaddress) - { - Expression *ex = ((AddrExp *)e->e1)->e1; - if (e->type->equals(ex->type)) - ret = ex; - else if (e->type->toBasetype()->equivalent(ex->type->toBasetype())) - { - ret = ex->copy(); - ret->type = e->type; - } - } - if (keepLvalue) - return; - - // Constant fold *(&structliteral + offset) - if (e->e1->op == TOKadd) - { - Expression *ex = Ptr(e->type, e->e1).copy(); - if (!CTFEExp::isCantExp(ex)) - { - ret = ex; - return; - } - } - - if (e->e1->op == TOKsymoff) - { - SymOffExp *se = (SymOffExp *)e->e1; - VarDeclaration *v = se->var->isVarDeclaration(); - Expression *ex = expandVar(result, v); - if (ex && ex->op == TOKstructliteral) - { - StructLiteralExp *sle = (StructLiteralExp *)ex; - ex = sle->getField(e->type, (unsigned)se->offset); - if (ex && !CTFEExp::isCantExp(ex)) - { - ret = ex; - return; - } - } - } - } - - void visit(DotVarExp *e) - { - //printf("DotVarExp::optimize(result = x%x) %s\n", result, e->toChars()); - if (expOptimize(e->e1, result)) - return; - if (keepLvalue) - return; - - Expression *ex = e->e1; - - if (ex->op == TOKvar) - { - VarExp *ve = (VarExp *)ex; - VarDeclaration *v = ve->var->isVarDeclaration(); - ex = expandVar(result, v); - } - - if (ex && ex->op == TOKstructliteral) - { - StructLiteralExp *sle = (StructLiteralExp *)ex; - VarDeclaration *vf = e->var->isVarDeclaration(); - if (vf && !vf->overlapped) - { - /* Bugzilla 13021: Prevent optimization if vf has overlapped fields. - */ - ex = sle->getField(e->type, vf->offset); - if (ex && !CTFEExp::isCantExp(ex)) - { - ret = ex; - return; - } - } - } - } - - void visit(NewExp *e) - { - expOptimize(e->thisexp, WANTvalue); - - // Optimize parameters - if (e->newargs) - { - for (size_t i = 0; i < e->newargs->length; i++) - { - expOptimize((*e->newargs)[i], WANTvalue); - } - } - - if (e->arguments) - { - for (size_t i = 0; i < e->arguments->length; i++) - { - expOptimize((*e->arguments)[i], WANTvalue); - } - } - } - - void visit(CallExp *e) - { - //printf("CallExp::optimize(result = %d) %s\n", result, e->toChars()); - - // Optimize parameters with keeping lvalue-ness - if (expOptimize(e->e1, result)) - return; - if (e->arguments) - { - Type *t1 = e->e1->type->toBasetype(); - if (t1->ty == Tdelegate) t1 = t1->nextOf(); - assert(t1->ty == Tfunction); - TypeFunction *tf = (TypeFunction *)t1; - for (size_t i = 0; i < e->arguments->length; i++) - { - Parameter *p = tf->parameterList[i]; - bool keep = p && (p->storageClass & (STCref | STCout)) != 0; - expOptimize((*e->arguments)[i], WANTvalue, keep); - } - } - } - - void visit(CastExp *e) - { - //printf("CastExp::optimize(result = %d) %s\n", result, e->toChars()); - //printf("from %s to %s\n", e->type->toChars(), e->to->toChars()); - //printf("from %s\n", e->type->toChars()); - //printf("e1->type %s\n", e->e1->type->toChars()); - //printf("type = %p\n", e->type); - assert(e->type); - TOK op1 = e->e1->op; - - Expression *e1old = e->e1; - if (expOptimize(e->e1, result)) - return; - e->e1 = fromConstInitializer(result, e->e1); - - if (e->e1 == e1old && - e->e1->op == TOKarrayliteral && - e->type->toBasetype()->ty == Tpointer && - e->e1->type->toBasetype()->ty != Tsarray) - { - // Casting this will result in the same expression, and - // infinite loop because of Expression::implicitCastTo() - return; // no change - } - - if ((e->e1->op == TOKstring || e->e1->op == TOKarrayliteral) && - (e->type->ty == Tpointer || e->type->ty == Tarray)) - { - const d_uns64 esz = e->type->nextOf()->size(e->loc); - const d_uns64 e1sz = e->e1->type->toBasetype()->nextOf()->size(e->e1->loc); - if (esz == SIZE_INVALID || e1sz == SIZE_INVALID) - return error(); - - if (e1sz == esz) - { - // Bugzilla 12937: If target type is void array, trying to paint - // e->e1 with that type will cause infinite recursive optimization. - if (e->type->nextOf()->ty == Tvoid) - return; - - ret = e->e1->castTo(NULL, e->type); - //printf(" returning1 %s\n", ret->toChars()); - return; - } - } - - if (e->e1->op == TOKstructliteral && - e->e1->type->implicitConvTo(e->type) >= MATCHconst) - { - //printf(" returning2 %s\n", e->e1->toChars()); - L1: // Returning e1 with changing its type - ret = (e1old == e->e1 ? e->e1->copy() : e->e1); - ret->type = e->type; - return; - } - - /* The first test here is to prevent infinite loops - */ - if (op1 != TOKarrayliteral && e->e1->op == TOKarrayliteral) - { - ret = e->e1->castTo(NULL, e->to); - return; - } - if (e->e1->op == TOKnull && - (e->type->ty == Tpointer || e->type->ty == Tclass || e->type->ty == Tarray)) - { - //printf(" returning3 %s\n", e->e1->toChars()); - goto L1; - } - - if (e->type->ty == Tclass && e->e1->type->ty == Tclass) - { - // See if we can remove an unnecessary cast - ClassDeclaration *cdfrom = e->e1->type->isClassHandle(); - ClassDeclaration *cdto = e->type->isClassHandle(); - if (cdto == ClassDeclaration::object && !cdfrom->isInterfaceDeclaration()) - goto L1; // can always convert a class to Object - // Need to determine correct offset before optimizing away the cast. - // https://issues.dlang.org/show_bug.cgi?id=16980 - cdfrom->size(e->loc); - assert(cdfrom->sizeok == SIZEOKdone); - assert(cdto->sizeok == SIZEOKdone || !cdto->isBaseOf(cdfrom, NULL)); - int offset; - if (cdto->isBaseOf(cdfrom, &offset) && offset == 0) - { - //printf(" returning4 %s\n", e->e1->toChars()); - goto L1; - } - } - - // We can convert 'head const' to mutable - if (e->to->mutableOf()->constOf()->equals(e->e1->type->mutableOf()->constOf())) - { - //printf(" returning5 %s\n", e->e1->toChars()); - goto L1; - } - - if (e->e1->isConst()) - { - if (e->e1->op == TOKsymoff) - { - if (e->type->toBasetype()->ty != Tsarray) - { - const d_uns64 esz = e->type->size(e->loc); - const d_uns64 e1sz = e->e1->type->size(e->e1->loc); - if (esz == SIZE_INVALID || - e1sz == SIZE_INVALID) - return error(); - - if (esz == e1sz) - goto L1; - } - return; - } - if (e->to->toBasetype()->ty != Tvoid) - { - if (e->e1->type->equals(e->type) && e->type->equals(e->to)) - ret = e->e1; - else - ret = Cast(e->loc, e->type, e->to, e->e1).copy(); - } - } - //printf(" returning6 %s\n", ret->toChars()); - } - - void visit(BinExp *e) - { - //printf("BinExp::optimize(result = %d) %s\n", result, e->toChars()); - // don't replace const variable with its initializer in e1 - bool e2only = (e->op == TOKconstruct || e->op == TOKblit); - if (e2only ? expOptimize(e->e2, result) : binOptimize(e, result)) - return; - - if (e->op == TOKshlass || e->op == TOKshrass || e->op == TOKushrass) - { - if (e->e2->isConst() == 1) - { - sinteger_t i2 = e->e2->toInteger(); - d_uns64 sz = e->e1->type->size(e->e1->loc); - assert(sz != SIZE_INVALID); - sz *= 8; - if (i2 < 0 || (d_uns64)i2 >= sz) - { - e->error("shift assign by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1); - return error(); - } - } - } - } - - void visit(AddExp *e) - { - //printf("AddExp::optimize(%s)\n", e->toChars()); - - if (binOptimize(e, result)) - return; - - if (e->e1->isConst() && e->e2->isConst()) - { - if (e->e1->op == TOKsymoff && e->e2->op == TOKsymoff) - return; - ret = Add(e->loc, e->type, e->e1, e->e2).copy(); - } - } - - void visit(MinExp *e) - { - if (binOptimize(e, result)) - return; - - if (e->e1->isConst() && e->e2->isConst()) - { - if (e->e2->op == TOKsymoff) - return; - ret = Min(e->loc, e->type, e->e1, e->e2).copy(); - } - } - - void visit(MulExp *e) - { - //printf("MulExp::optimize(result = %d) %s\n", result, e->toChars()); - - if (binOptimize(e, result)) - return; - - if (e->e1->isConst() == 1 && e->e2->isConst() == 1) - { - ret = Mul(e->loc, e->type, e->e1, e->e2).copy(); - } - } - - void visit(DivExp *e) - { - //printf("DivExp::optimize(%s)\n", e->toChars()); - - if (binOptimize(e, result)) - return; - - if (e->e1->isConst() == 1 && e->e2->isConst() == 1) - { - ret = Div(e->loc, e->type, e->e1, e->e2).copy(); - } - } - - void visit(ModExp *e) - { - if (binOptimize(e, result)) - return; - - if (e->e1->isConst() == 1 && e->e2->isConst() == 1) - { - ret = Mod(e->loc, e->type, e->e1, e->e2).copy(); - } - } - - void shift_optimize(BinExp *e, UnionExp (*shift)(Loc, Type *, Expression *, Expression *)) - { - if (binOptimize(e, result)) - return; - - if (e->e2->isConst() == 1) - { - sinteger_t i2 = e->e2->toInteger(); - d_uns64 sz = e->e1->type->size(); - assert(sz != SIZE_INVALID); - sz *= 8; - if (i2 < 0 || (d_uns64)i2 >= sz) - { - e->error("shift by %lld is outside the range 0..%llu", i2, (ulonglong)sz - 1); - return error(); - } - if (e->e1->isConst() == 1) - ret = (*shift)(e->loc, e->type, e->e1, e->e2).copy(); - } - } - - void visit(ShlExp *e) - { - //printf("ShlExp::optimize(result = %d) %s\n", result, e->toChars()); - shift_optimize(e, &Shl); - } - - void visit(ShrExp *e) - { - //printf("ShrExp::optimize(result = %d) %s\n", result, e->toChars()); - shift_optimize(e, &Shr); - } - - void visit(UshrExp *e) - { - //printf("UshrExp::optimize(result = %d) %s\n", result, toChars()); - shift_optimize(e, &Ushr); - } - - void visit(AndExp *e) - { - if (binOptimize(e, result)) - return; - - if (e->e1->isConst() == 1 && e->e2->isConst() == 1) - ret = And(e->loc, e->type, e->e1, e->e2).copy(); - } - - void visit(OrExp *e) - { - if (binOptimize(e, result)) - return; - - if (e->e1->isConst() == 1 && e->e2->isConst() == 1) - ret = Or(e->loc, e->type, e->e1, e->e2).copy(); - } - - void visit(XorExp *e) - { - if (binOptimize(e, result)) - return; - - if (e->e1->isConst() == 1 && e->e2->isConst() == 1) - ret = Xor(e->loc, e->type, e->e1, e->e2).copy(); - } - - void visit(PowExp *e) - { - if (binOptimize(e, result)) - return; - - // Replace 1 ^^ x or 1.0^^x by (x, 1) - if ((e->e1->op == TOKint64 && e->e1->toInteger() == 1) || - (e->e1->op == TOKfloat64 && e->e1->toReal() == CTFloat::one)) - { - ret = new CommaExp(e->loc, e->e2, e->e1); - ret->type = e->type; - return; - } - - // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral - if (e->e2->type->isintegral() && e->e1->op == TOKint64 && (sinteger_t)e->e1->toInteger() == -1L) - { - ret = new AndExp(e->loc, e->e2, new IntegerExp(e->loc, 1, e->e2->type)); - ret->type = e->e2->type; - ret = new CondExp(e->loc, ret, new IntegerExp(e->loc, -1L, e->type), new IntegerExp(e->loc, 1L, e->type)); - ret->type = e->type; - return; - } - - // Replace x ^^ 0 or x^^0.0 by (x, 1) - if ((e->e2->op == TOKint64 && e->e2->toInteger() == 0) || - (e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::zero)) - { - if (e->e1->type->isintegral()) - ret = new IntegerExp(e->loc, 1, e->e1->type); - else - ret = new RealExp(e->loc, CTFloat::one, e->e1->type); - - ret = new CommaExp(e->loc, e->e1, ret); - ret->type = e->type; - return; - } - - // Replace x ^^ 1 or x^^1.0 by (x) - if ((e->e2->op == TOKint64 && e->e2->toInteger() == 1) || - (e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::one)) - { - ret = e->e1; - return; - } - - // Replace x ^^ -1.0 by (1.0 / x) - if ((e->e2->op == TOKfloat64 && e->e2->toReal() == CTFloat::minusone)) - { - ret = new DivExp(e->loc, new RealExp(e->loc, CTFloat::one, e->e2->type), e->e1); - ret->type = e->type; - return; - } - - // All other negative integral powers are illegal - if ((e->e1->type->isintegral()) && (e->e2->op == TOKint64) && (sinteger_t)e->e2->toInteger() < 0) - { - e->error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?", - e->e1->type->toBasetype()->toChars(), e->e1->toChars(), e->e2->toChars()); - return error(); - } - - // If e2 *could* have been an integer, make it one. - if (e->e2->op == TOKfloat64 && (e->e2->toReal() == ldouble((sinteger_t)e->e2->toReal()))) - e->e2 = new IntegerExp(e->loc, e->e2->toInteger(), Type::tint64); - - if (e->e1->isConst() == 1 && e->e2->isConst() == 1) - { - Expression *ex = Pow(e->loc, e->type, e->e1, e->e2).copy(); - if (!CTFEExp::isCantExp(ex)) - { - ret = ex; - return; - } - } - - // (2 ^^ n) ^^ p -> 1 << n * p - if (e->e1->op == TOKint64 && e->e1->toInteger() > 0 && - !((e->e1->toInteger() - 1) & e->e1->toInteger()) && - e->e2->type->isintegral() && e->e2->type->isunsigned()) - { - dinteger_t i = e->e1->toInteger(); - dinteger_t mul = 1; - while ((i >>= 1) > 1) - mul++; - Expression *shift = new MulExp(e->loc, e->e2, new IntegerExp(e->loc, mul, e->e2->type)); - shift->type = e->e2->type; - shift = shift->castTo(NULL, Type::tshiftcnt); - ret = new ShlExp(e->loc, new IntegerExp(e->loc, 1, e->e1->type), shift); - ret->type = e->type; - return; - } - } - - void visit(CommaExp *e) - { - //printf("CommaExp::optimize(result = %d) %s\n", result, e->toChars()); - // Comma needs special treatment, because it may - // contain compiler-generated declarations. We can interpret them, but - // otherwise we must NOT attempt to constant-fold them. - // In particular, if the comma returns a temporary variable, it needs - // to be an lvalue (this is particularly important for struct constructors) - - expOptimize(e->e1, WANTvalue); - expOptimize(e->e2, result, keepLvalue); - if (ret->op == TOKerror) - return; - - if (!e->e1 || e->e1->op == TOKint64 || e->e1->op == TOKfloat64 || !hasSideEffect(e->e1)) - { - ret = e->e2; - if (ret) - ret->type = e->type; - } - - //printf("-CommaExp::optimize(result = %d) %s\n", result, e->e->toChars()); - } - - void visit(ArrayLengthExp *e) - { - //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e->toChars()); - - if (unaOptimize(e, WANTexpand)) - return; - - // CTFE interpret static immutable arrays (to get better diagnostics) - if (e->e1->op == TOKvar) - { - VarDeclaration *v = ((VarExp *)e->e1)->var->isVarDeclaration(); - if (v && (v->storage_class & STCstatic) && (v->storage_class & STCimmutable) && v->_init) - { - if (Expression *ci = v->getConstInitializer()) - e->e1 = ci; - } - } - - if (e->e1->op == TOKstring || e->e1->op == TOKarrayliteral || e->e1->op == TOKassocarrayliteral || - e->e1->type->toBasetype()->ty == Tsarray) - { - ret = ArrayLength(e->type, e->e1).copy(); - } - } - - void visit(EqualExp *e) - { - //printf("EqualExp::optimize(result = %x) %s\n", result, e->toChars()); - if (binOptimize(e, WANTvalue)) - return; - - Expression *e1 = fromConstInitializer(result, e->e1); - Expression *e2 = fromConstInitializer(result, e->e2); - if (e1->op == TOKerror) - { - ret = e1; - return; - } - if (e2->op == TOKerror) - { - ret = e2; - return; - } - - ret = Equal(e->op, e->loc, e->type, e1, e2).copy(); - if (CTFEExp::isCantExp(ret)) - ret = e; - } - - void visit(IdentityExp *e) - { - //printf("IdentityExp::optimize(result = %d) %s\n", result, e->toChars()); - - if (binOptimize(e, WANTvalue)) - return; - - if ((e->e1->isConst() && e->e2->isConst()) || - (e->e1->op == TOKnull && e->e2->op == TOKnull) - ) - { - ret = Identity(e->op, e->loc, e->type, e->e1, e->e2).copy(); - if (CTFEExp::isCantExp(ret)) - ret = e; - } - } - - /* It is possible for constant folding to change an array expression of - * unknown length, into one where the length is known. - * If the expression 'arr' is a literal, set lengthVar to be its length. - */ - static void setLengthVarIfKnown(VarDeclaration *lengthVar, Expression *arr) - { - if (!lengthVar) - return; - if (lengthVar->_init && !lengthVar->_init->isVoidInitializer()) - return; // we have previously calculated the length - size_t len; - if (arr->op == TOKstring) - len = ((StringExp *)arr)->len; - else if (arr->op == TOKarrayliteral) - len = ((ArrayLiteralExp *)arr)->elements->length; - else - { - Type *t = arr->type->toBasetype(); - if (t->ty == Tsarray) - len = (size_t)((TypeSArray *)t)->dim->toInteger(); - else - return; // we don't know the length yet - } - - Expression *dollar = new IntegerExp(Loc(), len, Type::tsize_t); - lengthVar->_init = new ExpInitializer(Loc(), dollar); - lengthVar->storage_class |= STCstatic | STCconst; - } - - void visit(IndexExp *e) - { - //printf("IndexExp::optimize(result = %d) %s\n", result, e->toChars()); - if (expOptimize(e->e1, result & WANTexpand)) - return; - - Expression *ex = fromConstInitializer(result, e->e1); - - // We might know $ now - setLengthVarIfKnown(e->lengthVar, ex); - - if (expOptimize(e->e2, WANTvalue)) - return; - if (keepLvalue) - return; - ret = Index(e->type, ex, e->e2).copy(); - if (CTFEExp::isCantExp(ret)) - ret = e; - } - - void visit(SliceExp *e) - { - //printf("SliceExp::optimize(result = %d) %s\n", result, e->toChars()); - if (expOptimize(e->e1, result & WANTexpand)) - return; - if (!e->lwr) - { - if (e->e1->op == TOKstring) - { - // Convert slice of string literal into dynamic array - Type *t = e->e1->type->toBasetype(); - if (Type *tn = t->nextOf()) - ret = e->e1->castTo(NULL, tn->arrayOf()); - } - } - else - { - e->e1 = fromConstInitializer(result, e->e1); - // We might know $ now - setLengthVarIfKnown(e->lengthVar, e->e1); - expOptimize(e->lwr, WANTvalue); - expOptimize(e->upr, WANTvalue); - if (ret->op == TOKerror) - return; - ret = Slice(e->type, e->e1, e->lwr, e->upr).copy(); - if (CTFEExp::isCantExp(ret)) - ret = e; - } - - // Bugzilla 14649: We need to leave the slice form so it might be - // a part of array operation. - // Assume that the backend codegen will handle the form `e[]` - // as an equal to `e` itself. - if (ret->op == TOKstring) - { - e->e1 = ret; - e->lwr = NULL; - e->upr = NULL; - ret = e; - } - //printf("-SliceExp::optimize() %s\n", ret->toChars()); - } - - void visit(LogicalExp *e) - { - //printf("LogicalExp::optimize(%d) %s\n", result, e->toChars()); - if (expOptimize(e->e1, WANTvalue)) - return; - const bool oror = e->op == TOKoror; - if (e->e1->isBool(oror)) - { - // Replace with (e1, oror) - ret = new IntegerExp(e->loc, oror, Type::tbool); - ret = Expression::combine(e->e1, ret); - if (e->type->toBasetype()->ty == Tvoid) - { - ret = new CastExp(e->loc, ret, Type::tvoid); - ret->type = e->type; - } - ret = ret->optimize(result); - return; - } - - if (expOptimize(e->e2, WANTvalue)) - return; - - if (e->e1->isConst()) - { - if (e->e2->isConst()) - { - bool n1 = e->e1->isBool(true); - bool n2 = e->e2->isBool(true); - ret = new IntegerExp(e->loc, oror ? (n1 || n2) : (n1 && n2), e->type); - } - else if (e->e1->isBool(!oror)) - { - if (e->type->toBasetype()->ty == Tvoid) - ret = e->e2; - else - { - ret = new CastExp(e->loc, e->e2, e->type); - ret->type = e->type; - } - } - } - } - - void visit(CmpExp *e) - { - //printf("CmpExp::optimize() %s\n", e->toChars()); - if (binOptimize(e, WANTvalue)) - return; - - Expression *e1 = fromConstInitializer(result, e->e1); - Expression *e2 = fromConstInitializer(result, e->e2); - - ret = Cmp(e->op, e->loc, e->type, e1, e2).copy(); - if (CTFEExp::isCantExp(ret)) - ret = e; - } - - void visit(CatExp *e) - { - //printf("CatExp::optimize(%d) %s\n", result, e->toChars()); - - if (binOptimize(e, result)) - return; - - if (e->e1->op == TOKcat) - { - // Bugzilla 12798: optimize ((expr ~ str1) ~ str2) - CatExp *ce1 = (CatExp *)e->e1; - CatExp cex(e->loc, ce1->e2, e->e2); - cex.type = e->type; - Expression *ex = cex.optimize(result); - if (ex != &cex) - { - e->e1 = ce1->e1; - e->e2 = ex; - } - } - - // optimize "str"[] -> "str" - if (e->e1->op == TOKslice) - { - SliceExp *se1 = (SliceExp *)e->e1; - if (se1->e1->op == TOKstring && !se1->lwr) - e->e1 = se1->e1; - } - if (e->e2->op == TOKslice) - { - SliceExp *se2 = (SliceExp *)e->e2; - if (se2->e1->op == TOKstring && !se2->lwr) - e->e2 = se2->e1; - } - - ret = Cat(e->type, e->e1, e->e2).copy(); - if (CTFEExp::isCantExp(ret)) - ret = e; - } - - void visit(CondExp *e) - { - if (expOptimize(e->econd, WANTvalue)) - return; - if (e->econd->isBool(true)) - ret = e->e1->optimize(result, keepLvalue); - else if (e->econd->isBool(false)) - ret = e->e2->optimize(result, keepLvalue); - else - { - expOptimize(e->e1, result, keepLvalue); - expOptimize(e->e2, result, keepLvalue); - } - } - }; - - OptimizeVisitor v(result, keepLvalue); - Expression *ex = NULL; - v.ret = e; - - // Optimize the expression until it can no longer be simplified. - size_t b = 0; - while (1) - { - if (b++ == global.recursionLimit) - { - e->error("infinite loop while optimizing expression"); - fatal(); - } - ex = v.ret; - ex->accept(&v); - if (ex == v.ret) - break; - } - return ex; -} |