aboutsummaryrefslogtreecommitdiff
path: root/gcc/d/dmd/optimize.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/d/dmd/optimize.c')
-rw-r--r--gcc/d/dmd/optimize.c1230
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;
-}