e907229be4c40bb41aeb55d17d6baf00b4e2bd26
2 /* Compiler implementation of the D programming language
3 * Copyright (C) 1999-2020 by The D Language Foundation, All Rights Reserved
4 * written by Walter Bright
5 * http://www.digitalmars.com
6 * Distributed under the Boost Software License, Version 1.0
7 * http://www.boost.org/LICENSE_1_0.txt
8 * https://github.com/D-Programming-Language/dmd/blob/master/src/optimize.c
11 #include "root/dsystem.h"
13 #include "root/checkedint.h"
16 #include "expression.h"
17 #include "declaration.h"
18 #include "aggregate.h"
23 Expression
*semantic(Expression
*e
, Scope
*sc
);
25 /*************************************
26 * If variable has a const initializer,
27 * return that initializer.
30 Expression
*expandVar(int result
, VarDeclaration
*v
)
32 //printf("expandVar(result = %d, v = %p, %s)\n", result, v, v ? v->toChars() : "null");
37 if (!v
->originalType
&& v
->semanticRun
< PASSsemanticdone
) // semantic() not yet run
40 if (v
->isConst() || v
->isImmutable() || v
->storage_class
& STCmanifest
)
46 Type
*tb
= v
->type
->toBasetype();
47 if (v
->storage_class
& STCmanifest
||
48 v
->type
->toBasetype()->isscalar() ||
49 ((result
& WANTexpand
) && (tb
->ty
!= Tsarray
&& tb
->ty
!= Tstruct
))
56 if (v
->storage_class
& STCmanifest
)
58 v
->error("recursive initialization of constant");
63 Expression
*ei
= v
->getConstInitializer();
66 if (v
->storage_class
& STCmanifest
)
68 v
->error("enum cannot be initialized with %s", v
->_init
->toChars());
73 if (ei
->op
== TOKconstruct
|| ei
->op
== TOKblit
)
75 AssignExp
*ae
= (AssignExp
*)ei
;
77 if (ei
->isConst() == 1)
80 else if (ei
->op
== TOKstring
)
82 // Bugzilla 14459: We should not constfold the string literal
83 // if it's typed as a C string, because the value expansion
84 // will drop the pointer identity.
85 if (!(result
& WANTexpand
) && ei
->type
->toBasetype()->ty
== Tpointer
)
91 if (ei
->type
== v
->type
)
93 // const variable initialized with const expression
95 else if (ei
->implicitConvTo(v
->type
) >= MATCHconst
)
97 // const var initialized with non-const expression
98 ei
= ei
->implicitCastTo(NULL
, v
->type
);
99 ei
= semantic(ei
, NULL
);
104 else if (!(v
->storage_class
& STCmanifest
) &&
105 ei
->isConst() != 1 && ei
->op
!= TOKstring
&&
106 ei
->op
!= TOKaddress
)
116 // Should remove the copy() operation by
117 // making all mods to expressions copy-on-write
125 if (e
->type
!= v
->type
)
127 e
= e
->castTo(NULL
, v
->type
);
130 e
= e
->optimize(result
);
135 //if (e) printf("\te = %p, %s, e->type = %d, %s\n", e, e->toChars(), e->type->ty, e->type->toChars());
139 return new ErrorExp();
143 Expression
*fromConstInitializer(int result
, Expression
*e1
)
145 //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars());
146 //static int xx; if (xx++ == 10) assert(0);
148 if (e1
->op
== TOKvar
)
150 VarExp
*ve
= (VarExp
*)e1
;
151 VarDeclaration
*v
= ve
->var
->isVarDeclaration();
152 e
= expandVar(result
, v
);
155 // If it is a comma expression involving a declaration, we mustn't
156 // perform a copy -- we'd get two declarations of the same variable.
157 // See bugzilla 4465.
158 if (e
->op
== TOKcomma
&& ((CommaExp
*)e
)->e1
->op
== TOKdeclaration
)
162 if (e
->type
!= e1
->type
&& e1
->type
&& e1
->type
->ty
!= Tident
)
164 // Type 'paint' operation
178 Expression
*Expression_optimize(Expression
*e
, int result
, bool keepLvalue
)
180 class OptimizeVisitor
: public Visitor
187 OptimizeVisitor(int result
, bool keepLvalue
)
188 : result(result
), keepLvalue(keepLvalue
)
194 ret
= new ErrorExp();
197 bool expOptimize(Expression
*&e
, int flags
, bool keepLvalue
= false)
201 Expression
*ex
= e
->optimize(flags
, keepLvalue
);
202 if (ex
->op
== TOKerror
)
204 ret
= ex
; // store error result
209 e
= ex
; // modify original
214 bool unaOptimize(UnaExp
*e
, int flags
)
216 return expOptimize(e
->e1
, flags
);
219 bool binOptimize(BinExp
*e
, int flags
)
221 expOptimize(e
->e1
, flags
);
222 expOptimize(e
->e2
, flags
);
223 return ret
->op
== TOKerror
;
226 void visit(Expression
*)
228 //printf("Expression::optimize(result = x%x) %s\n", result, e->toChars());
231 void visit(VarExp
*e
)
235 VarDeclaration
*v
= e
->var
->isVarDeclaration();
236 if (v
&& !(v
->storage_class
& STCmanifest
))
239 ret
= fromConstInitializer(result
, e
);
242 void visit(TupleExp
*e
)
244 expOptimize(e
->e0
, WANTvalue
);
245 for (size_t i
= 0; i
< e
->exps
->length
; i
++)
247 expOptimize((*e
->exps
)[i
], WANTvalue
);
251 void visit(ArrayLiteralExp
*e
)
255 expOptimize(e
->basis
, result
& WANTexpand
);
256 for (size_t i
= 0; i
< e
->elements
->length
; i
++)
258 expOptimize((*e
->elements
)[i
], result
& WANTexpand
);
263 void visit(AssocArrayLiteralExp
*e
)
265 assert(e
->keys
->length
== e
->values
->length
);
266 for (size_t i
= 0; i
< e
->keys
->length
; i
++)
268 expOptimize((*e
->keys
)[i
], result
& WANTexpand
);
269 expOptimize((*e
->values
)[i
], result
& WANTexpand
);
273 void visit(StructLiteralExp
*e
)
275 if (e
->stageflags
& stageOptimize
) return;
276 int old
= e
->stageflags
;
277 e
->stageflags
|= stageOptimize
;
280 for (size_t i
= 0; i
< e
->elements
->length
; i
++)
282 expOptimize((*e
->elements
)[i
], result
& WANTexpand
);
288 void visit(UnaExp
*e
)
290 //printf("UnaExp::optimize() %s\n", e->toChars());
291 if (unaOptimize(e
, result
))
295 void visit(NegExp
*e
)
297 if (unaOptimize(e
, result
))
300 if (e
->e1
->isConst() == 1)
302 ret
= Neg(e
->type
, e
->e1
).copy();
306 void visit(ComExp
*e
)
308 if (unaOptimize(e
, result
))
311 if (e
->e1
->isConst() == 1)
313 ret
= Com(e
->type
, e
->e1
).copy();
317 void visit(NotExp
*e
)
319 if (unaOptimize(e
, result
))
322 if (e
->e1
->isConst() == 1)
324 ret
= Not(e
->type
, e
->e1
).copy();
328 void visit(SymOffExp
*e
)
333 void visit(AddrExp
*e
)
335 //printf("AddrExp::optimize(result = %d) %s\n", result, e->toChars());
337 /* Rewrite &(a,b) as (a,&b)
339 if (e
->e1
->op
== TOKcomma
)
341 CommaExp
*ce
= (CommaExp
*)e
->e1
;
342 AddrExp
*ae
= new AddrExp(e
->loc
, ce
->e2
, e
->type
);
343 ret
= new CommaExp(ce
->loc
, ce
->e1
, ae
);
349 if (expOptimize(e
->e1
, result
, true))
352 // Convert &*ex to ex
353 if (e
->e1
->op
== TOKstar
)
355 Expression
*ex
= ((PtrExp
*)e
->e1
)->e1
;
356 if (e
->type
->equals(ex
->type
))
358 else if (e
->type
->toBasetype()->equivalent(ex
->type
->toBasetype()))
365 if (e
->e1
->op
== TOKvar
)
367 VarExp
*ve
= (VarExp
*)e
->e1
;
368 if (!ve
->var
->isOut() && !ve
->var
->isRef() &&
369 !ve
->var
->isImportedSymbol())
371 ret
= new SymOffExp(e
->loc
, ve
->var
, 0, ve
->hasOverloads
);
376 if (e
->e1
->op
== TOKindex
)
378 // Convert &array[n] to &array+n
379 IndexExp
*ae
= (IndexExp
*)e
->e1
;
381 if (ae
->e2
->op
== TOKint64
&& ae
->e1
->op
== TOKvar
)
383 sinteger_t index
= ae
->e2
->toInteger();
384 VarExp
*ve
= (VarExp
*)ae
->e1
;
385 if (ve
->type
->ty
== Tsarray
386 && !ve
->var
->isImportedSymbol())
388 TypeSArray
*ts
= (TypeSArray
*)ve
->type
;
389 sinteger_t dim
= ts
->dim
->toInteger();
390 if (index
< 0 || index
>= dim
)
392 e
->error("array index %lld is out of bounds [0..%lld]", index
, dim
);
396 bool overflow
= false;
397 const d_uns64 offset
= mulu(index
, ts
->nextOf()->size(e
->loc
), overflow
);
400 e
->error("array offset overflow");
404 ret
= new SymOffExp(e
->loc
, ve
->var
, offset
);
412 void visit(PtrExp
*e
)
414 //printf("PtrExp::optimize(result = x%x) %s\n", result, e->toChars());
415 if (expOptimize(e
->e1
, result
))
417 // Convert *&ex to ex
418 // But only if there is no type punning involved
419 if (e
->e1
->op
== TOKaddress
)
421 Expression
*ex
= ((AddrExp
*)e
->e1
)->e1
;
422 if (e
->type
->equals(ex
->type
))
424 else if (e
->type
->toBasetype()->equivalent(ex
->type
->toBasetype()))
433 // Constant fold *(&structliteral + offset)
434 if (e
->e1
->op
== TOKadd
)
436 Expression
*ex
= Ptr(e
->type
, e
->e1
).copy();
437 if (!CTFEExp::isCantExp(ex
))
444 if (e
->e1
->op
== TOKsymoff
)
446 SymOffExp
*se
= (SymOffExp
*)e
->e1
;
447 VarDeclaration
*v
= se
->var
->isVarDeclaration();
448 Expression
*ex
= expandVar(result
, v
);
449 if (ex
&& ex
->op
== TOKstructliteral
)
451 StructLiteralExp
*sle
= (StructLiteralExp
*)ex
;
452 ex
= sle
->getField(e
->type
, (unsigned)se
->offset
);
453 if (ex
&& !CTFEExp::isCantExp(ex
))
462 void visit(DotVarExp
*e
)
464 //printf("DotVarExp::optimize(result = x%x) %s\n", result, e->toChars());
465 if (expOptimize(e
->e1
, result
))
470 Expression
*ex
= e
->e1
;
472 if (ex
->op
== TOKvar
)
474 VarExp
*ve
= (VarExp
*)ex
;
475 VarDeclaration
*v
= ve
->var
->isVarDeclaration();
476 ex
= expandVar(result
, v
);
479 if (ex
&& ex
->op
== TOKstructliteral
)
481 StructLiteralExp
*sle
= (StructLiteralExp
*)ex
;
482 VarDeclaration
*vf
= e
->var
->isVarDeclaration();
483 if (vf
&& !vf
->overlapped
)
485 /* Bugzilla 13021: Prevent optimization if vf has overlapped fields.
487 ex
= sle
->getField(e
->type
, vf
->offset
);
488 if (ex
&& !CTFEExp::isCantExp(ex
))
497 void visit(NewExp
*e
)
499 expOptimize(e
->thisexp
, WANTvalue
);
501 // Optimize parameters
504 for (size_t i
= 0; i
< e
->newargs
->length
; i
++)
506 expOptimize((*e
->newargs
)[i
], WANTvalue
);
512 for (size_t i
= 0; i
< e
->arguments
->length
; i
++)
514 expOptimize((*e
->arguments
)[i
], WANTvalue
);
519 void visit(CallExp
*e
)
521 //printf("CallExp::optimize(result = %d) %s\n", result, e->toChars());
523 // Optimize parameters with keeping lvalue-ness
524 if (expOptimize(e
->e1
, result
))
528 Type
*t1
= e
->e1
->type
->toBasetype();
529 if (t1
->ty
== Tdelegate
) t1
= t1
->nextOf();
530 assert(t1
->ty
== Tfunction
);
531 TypeFunction
*tf
= (TypeFunction
*)t1
;
532 for (size_t i
= 0; i
< e
->arguments
->length
; i
++)
534 Parameter
*p
= tf
->parameterList
[i
];
535 bool keep
= p
&& (p
->storageClass
& (STCref
| STCout
)) != 0;
536 expOptimize((*e
->arguments
)[i
], WANTvalue
, keep
);
541 void visit(CastExp
*e
)
543 //printf("CastExp::optimize(result = %d) %s\n", result, e->toChars());
544 //printf("from %s to %s\n", e->type->toChars(), e->to->toChars());
545 //printf("from %s\n", e->type->toChars());
546 //printf("e1->type %s\n", e->e1->type->toChars());
547 //printf("type = %p\n", e->type);
551 Expression
*e1old
= e
->e1
;
552 if (expOptimize(e
->e1
, result
))
554 e
->e1
= fromConstInitializer(result
, e
->e1
);
556 if (e
->e1
== e1old
&&
557 e
->e1
->op
== TOKarrayliteral
&&
558 e
->type
->toBasetype()->ty
== Tpointer
&&
559 e
->e1
->type
->toBasetype()->ty
!= Tsarray
)
561 // Casting this will result in the same expression, and
562 // infinite loop because of Expression::implicitCastTo()
566 if ((e
->e1
->op
== TOKstring
|| e
->e1
->op
== TOKarrayliteral
) &&
567 (e
->type
->ty
== Tpointer
|| e
->type
->ty
== Tarray
))
569 const d_uns64 esz
= e
->type
->nextOf()->size(e
->loc
);
570 const d_uns64 e1sz
= e
->e1
->type
->toBasetype()->nextOf()->size(e
->e1
->loc
);
571 if (esz
== SIZE_INVALID
|| e1sz
== SIZE_INVALID
)
576 // Bugzilla 12937: If target type is void array, trying to paint
577 // e->e1 with that type will cause infinite recursive optimization.
578 if (e
->type
->nextOf()->ty
== Tvoid
)
581 ret
= e
->e1
->castTo(NULL
, e
->type
);
582 //printf(" returning1 %s\n", ret->toChars());
587 if (e
->e1
->op
== TOKstructliteral
&&
588 e
->e1
->type
->implicitConvTo(e
->type
) >= MATCHconst
)
590 //printf(" returning2 %s\n", e->e1->toChars());
591 L1
: // Returning e1 with changing its type
592 ret
= (e1old
== e
->e1
? e
->e1
->copy() : e
->e1
);
597 /* The first test here is to prevent infinite loops
599 if (op1
!= TOKarrayliteral
&& e
->e1
->op
== TOKarrayliteral
)
601 ret
= e
->e1
->castTo(NULL
, e
->to
);
604 if (e
->e1
->op
== TOKnull
&&
605 (e
->type
->ty
== Tpointer
|| e
->type
->ty
== Tclass
|| e
->type
->ty
== Tarray
))
607 //printf(" returning3 %s\n", e->e1->toChars());
611 if (e
->type
->ty
== Tclass
&& e
->e1
->type
->ty
== Tclass
)
613 // See if we can remove an unnecessary cast
614 ClassDeclaration
*cdfrom
= e
->e1
->type
->isClassHandle();
615 ClassDeclaration
*cdto
= e
->type
->isClassHandle();
616 if (cdto
== ClassDeclaration::object
&& !cdfrom
->isInterfaceDeclaration())
617 goto L1
; // can always convert a class to Object
618 // Need to determine correct offset before optimizing away the cast.
619 // https://issues.dlang.org/show_bug.cgi?id=16980
620 cdfrom
->size(e
->loc
);
621 assert(cdfrom
->sizeok
== SIZEOKdone
);
622 assert(cdto
->sizeok
== SIZEOKdone
|| !cdto
->isBaseOf(cdfrom
, NULL
));
624 if (cdto
->isBaseOf(cdfrom
, &offset
) && offset
== 0)
626 //printf(" returning4 %s\n", e->e1->toChars());
631 // We can convert 'head const' to mutable
632 if (e
->to
->mutableOf()->constOf()->equals(e
->e1
->type
->mutableOf()->constOf()))
634 //printf(" returning5 %s\n", e->e1->toChars());
638 if (e
->e1
->isConst())
640 if (e
->e1
->op
== TOKsymoff
)
642 if (e
->type
->toBasetype()->ty
!= Tsarray
)
644 const d_uns64 esz
= e
->type
->size(e
->loc
);
645 const d_uns64 e1sz
= e
->e1
->type
->size(e
->e1
->loc
);
646 if (esz
== SIZE_INVALID
||
647 e1sz
== SIZE_INVALID
)
655 if (e
->to
->toBasetype()->ty
!= Tvoid
)
657 if (e
->e1
->type
->equals(e
->type
) && e
->type
->equals(e
->to
))
660 ret
= Cast(e
->loc
, e
->type
, e
->to
, e
->e1
).copy();
663 //printf(" returning6 %s\n", ret->toChars());
666 void visit(BinExp
*e
)
668 //printf("BinExp::optimize(result = %d) %s\n", result, e->toChars());
669 // don't replace const variable with its initializer in e1
670 bool e2only
= (e
->op
== TOKconstruct
|| e
->op
== TOKblit
);
671 if (e2only
? expOptimize(e
->e2
, result
) : binOptimize(e
, result
))
674 if (e
->op
== TOKshlass
|| e
->op
== TOKshrass
|| e
->op
== TOKushrass
)
676 if (e
->e2
->isConst() == 1)
678 sinteger_t i2
= e
->e2
->toInteger();
679 d_uns64 sz
= e
->e1
->type
->size(e
->e1
->loc
);
680 assert(sz
!= SIZE_INVALID
);
682 if (i2
< 0 || (d_uns64
)i2
>= sz
)
684 e
->error("shift assign by %lld is outside the range 0..%llu", i2
, (ulonglong
)sz
- 1);
691 void visit(AddExp
*e
)
693 //printf("AddExp::optimize(%s)\n", e->toChars());
695 if (binOptimize(e
, result
))
698 if (e
->e1
->isConst() && e
->e2
->isConst())
700 if (e
->e1
->op
== TOKsymoff
&& e
->e2
->op
== TOKsymoff
)
702 ret
= Add(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
706 void visit(MinExp
*e
)
708 if (binOptimize(e
, result
))
711 if (e
->e1
->isConst() && e
->e2
->isConst())
713 if (e
->e2
->op
== TOKsymoff
)
715 ret
= Min(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
719 void visit(MulExp
*e
)
721 //printf("MulExp::optimize(result = %d) %s\n", result, e->toChars());
723 if (binOptimize(e
, result
))
726 if (e
->e1
->isConst() == 1 && e
->e2
->isConst() == 1)
728 ret
= Mul(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
732 void visit(DivExp
*e
)
734 //printf("DivExp::optimize(%s)\n", e->toChars());
736 if (binOptimize(e
, result
))
739 if (e
->e1
->isConst() == 1 && e
->e2
->isConst() == 1)
741 ret
= Div(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
745 void visit(ModExp
*e
)
747 if (binOptimize(e
, result
))
750 if (e
->e1
->isConst() == 1 && e
->e2
->isConst() == 1)
752 ret
= Mod(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
756 void shift_optimize(BinExp
*e
, UnionExp (*shift
)(Loc
, Type
*, Expression
*, Expression
*))
758 if (binOptimize(e
, result
))
761 if (e
->e2
->isConst() == 1)
763 sinteger_t i2
= e
->e2
->toInteger();
764 d_uns64 sz
= e
->e1
->type
->size();
765 assert(sz
!= SIZE_INVALID
);
767 if (i2
< 0 || (d_uns64
)i2
>= sz
)
769 e
->error("shift by %lld is outside the range 0..%llu", i2
, (ulonglong
)sz
- 1);
772 if (e
->e1
->isConst() == 1)
773 ret
= (*shift
)(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
777 void visit(ShlExp
*e
)
779 //printf("ShlExp::optimize(result = %d) %s\n", result, e->toChars());
780 shift_optimize(e
, &Shl
);
783 void visit(ShrExp
*e
)
785 //printf("ShrExp::optimize(result = %d) %s\n", result, e->toChars());
786 shift_optimize(e
, &Shr
);
789 void visit(UshrExp
*e
)
791 //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
792 shift_optimize(e
, &Ushr
);
795 void visit(AndExp
*e
)
797 if (binOptimize(e
, result
))
800 if (e
->e1
->isConst() == 1 && e
->e2
->isConst() == 1)
801 ret
= And(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
806 if (binOptimize(e
, result
))
809 if (e
->e1
->isConst() == 1 && e
->e2
->isConst() == 1)
810 ret
= Or(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
813 void visit(XorExp
*e
)
815 if (binOptimize(e
, result
))
818 if (e
->e1
->isConst() == 1 && e
->e2
->isConst() == 1)
819 ret
= Xor(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
822 void visit(PowExp
*e
)
824 if (binOptimize(e
, result
))
827 // Replace 1 ^^ x or 1.0^^x by (x, 1)
828 if ((e
->e1
->op
== TOKint64
&& e
->e1
->toInteger() == 1) ||
829 (e
->e1
->op
== TOKfloat64
&& e
->e1
->toReal() == CTFloat::one
))
831 ret
= new CommaExp(e
->loc
, e
->e2
, e
->e1
);
836 // Replace -1 ^^ x by (x&1) ? -1 : 1, where x is integral
837 if (e
->e2
->type
->isintegral() && e
->e1
->op
== TOKint64
&& (sinteger_t
)e
->e1
->toInteger() == -1L)
839 ret
= new AndExp(e
->loc
, e
->e2
, new IntegerExp(e
->loc
, 1, e
->e2
->type
));
840 ret
->type
= e
->e2
->type
;
841 ret
= new CondExp(e
->loc
, ret
, new IntegerExp(e
->loc
, -1L, e
->type
), new IntegerExp(e
->loc
, 1L, e
->type
));
846 // Replace x ^^ 0 or x^^0.0 by (x, 1)
847 if ((e
->e2
->op
== TOKint64
&& e
->e2
->toInteger() == 0) ||
848 (e
->e2
->op
== TOKfloat64
&& e
->e2
->toReal() == CTFloat::zero
))
850 if (e
->e1
->type
->isintegral())
851 ret
= new IntegerExp(e
->loc
, 1, e
->e1
->type
);
853 ret
= new RealExp(e
->loc
, CTFloat::one
, e
->e1
->type
);
855 ret
= new CommaExp(e
->loc
, e
->e1
, ret
);
860 // Replace x ^^ 1 or x^^1.0 by (x)
861 if ((e
->e2
->op
== TOKint64
&& e
->e2
->toInteger() == 1) ||
862 (e
->e2
->op
== TOKfloat64
&& e
->e2
->toReal() == CTFloat::one
))
868 // Replace x ^^ -1.0 by (1.0 / x)
869 if ((e
->e2
->op
== TOKfloat64
&& e
->e2
->toReal() == CTFloat::minusone
))
871 ret
= new DivExp(e
->loc
, new RealExp(e
->loc
, CTFloat::one
, e
->e2
->type
), e
->e1
);
876 // All other negative integral powers are illegal
877 if ((e
->e1
->type
->isintegral()) && (e
->e2
->op
== TOKint64
) && (sinteger_t
)e
->e2
->toInteger() < 0)
879 e
->error("cannot raise %s to a negative integer power. Did you mean (cast(real)%s)^^%s ?",
880 e
->e1
->type
->toBasetype()->toChars(), e
->e1
->toChars(), e
->e2
->toChars());
884 // If e2 *could* have been an integer, make it one.
885 if (e
->e2
->op
== TOKfloat64
&& (e
->e2
->toReal() == ldouble((sinteger_t
)e
->e2
->toReal())))
886 e
->e2
= new IntegerExp(e
->loc
, e
->e2
->toInteger(), Type::tint64
);
888 if (e
->e1
->isConst() == 1 && e
->e2
->isConst() == 1)
890 Expression
*ex
= Pow(e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
891 if (!CTFEExp::isCantExp(ex
))
898 // (2 ^^ n) ^^ p -> 1 << n * p
899 if (e
->e1
->op
== TOKint64
&& e
->e1
->toInteger() > 0 &&
900 !((e
->e1
->toInteger() - 1) & e
->e1
->toInteger()) &&
901 e
->e2
->type
->isintegral() && e
->e2
->type
->isunsigned())
903 dinteger_t i
= e
->e1
->toInteger();
905 while ((i
>>= 1) > 1)
907 Expression
*shift
= new MulExp(e
->loc
, e
->e2
, new IntegerExp(e
->loc
, mul
, e
->e2
->type
));
908 shift
->type
= e
->e2
->type
;
909 shift
= shift
->castTo(NULL
, Type::tshiftcnt
);
910 ret
= new ShlExp(e
->loc
, new IntegerExp(e
->loc
, 1, e
->e1
->type
), shift
);
916 void visit(CommaExp
*e
)
918 //printf("CommaExp::optimize(result = %d) %s\n", result, e->toChars());
919 // Comma needs special treatment, because it may
920 // contain compiler-generated declarations. We can interpret them, but
921 // otherwise we must NOT attempt to constant-fold them.
922 // In particular, if the comma returns a temporary variable, it needs
923 // to be an lvalue (this is particularly important for struct constructors)
925 expOptimize(e
->e1
, WANTvalue
);
926 expOptimize(e
->e2
, result
, keepLvalue
);
927 if (ret
->op
== TOKerror
)
930 if (!e
->e1
|| e
->e1
->op
== TOKint64
|| e
->e1
->op
== TOKfloat64
|| !hasSideEffect(e
->e1
))
937 //printf("-CommaExp::optimize(result = %d) %s\n", result, e->e->toChars());
940 void visit(ArrayLengthExp
*e
)
942 //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, e->toChars());
944 if (unaOptimize(e
, WANTexpand
))
947 // CTFE interpret static immutable arrays (to get better diagnostics)
948 if (e
->e1
->op
== TOKvar
)
950 VarDeclaration
*v
= ((VarExp
*)e
->e1
)->var
->isVarDeclaration();
951 if (v
&& (v
->storage_class
& STCstatic
) && (v
->storage_class
& STCimmutable
) && v
->_init
)
953 if (Expression
*ci
= v
->getConstInitializer())
958 if (e
->e1
->op
== TOKstring
|| e
->e1
->op
== TOKarrayliteral
|| e
->e1
->op
== TOKassocarrayliteral
||
959 e
->e1
->type
->toBasetype()->ty
== Tsarray
)
961 ret
= ArrayLength(e
->type
, e
->e1
).copy();
965 void visit(EqualExp
*e
)
967 //printf("EqualExp::optimize(result = %x) %s\n", result, e->toChars());
968 if (binOptimize(e
, WANTvalue
))
971 Expression
*e1
= fromConstInitializer(result
, e
->e1
);
972 Expression
*e2
= fromConstInitializer(result
, e
->e2
);
973 if (e1
->op
== TOKerror
)
978 if (e2
->op
== TOKerror
)
984 ret
= Equal(e
->op
, e
->loc
, e
->type
, e1
, e2
).copy();
985 if (CTFEExp::isCantExp(ret
))
989 void visit(IdentityExp
*e
)
991 //printf("IdentityExp::optimize(result = %d) %s\n", result, e->toChars());
993 if (binOptimize(e
, WANTvalue
))
996 if ((e
->e1
->isConst() && e
->e2
->isConst()) ||
997 (e
->e1
->op
== TOKnull
&& e
->e2
->op
== TOKnull
)
1000 ret
= Identity(e
->op
, e
->loc
, e
->type
, e
->e1
, e
->e2
).copy();
1001 if (CTFEExp::isCantExp(ret
))
1006 /* It is possible for constant folding to change an array expression of
1007 * unknown length, into one where the length is known.
1008 * If the expression 'arr' is a literal, set lengthVar to be its length.
1010 static void setLengthVarIfKnown(VarDeclaration
*lengthVar
, Expression
*arr
)
1014 if (lengthVar
->_init
&& !lengthVar
->_init
->isVoidInitializer())
1015 return; // we have previously calculated the length
1017 if (arr
->op
== TOKstring
)
1018 len
= ((StringExp
*)arr
)->len
;
1019 else if (arr
->op
== TOKarrayliteral
)
1020 len
= ((ArrayLiteralExp
*)arr
)->elements
->length
;
1023 Type
*t
= arr
->type
->toBasetype();
1024 if (t
->ty
== Tsarray
)
1025 len
= (size_t)((TypeSArray
*)t
)->dim
->toInteger();
1027 return; // we don't know the length yet
1030 Expression
*dollar
= new IntegerExp(Loc(), len
, Type::tsize_t
);
1031 lengthVar
->_init
= new ExpInitializer(Loc(), dollar
);
1032 lengthVar
->storage_class
|= STCstatic
| STCconst
;
1035 void visit(IndexExp
*e
)
1037 //printf("IndexExp::optimize(result = %d) %s\n", result, e->toChars());
1038 if (expOptimize(e
->e1
, result
& WANTexpand
))
1041 Expression
*ex
= fromConstInitializer(result
, e
->e1
);
1043 // We might know $ now
1044 setLengthVarIfKnown(e
->lengthVar
, ex
);
1046 if (expOptimize(e
->e2
, WANTvalue
))
1050 ret
= Index(e
->type
, ex
, e
->e2
).copy();
1051 if (CTFEExp::isCantExp(ret
))
1055 void visit(SliceExp
*e
)
1057 //printf("SliceExp::optimize(result = %d) %s\n", result, e->toChars());
1058 if (expOptimize(e
->e1
, result
& WANTexpand
))
1062 if (e
->e1
->op
== TOKstring
)
1064 // Convert slice of string literal into dynamic array
1065 Type
*t
= e
->e1
->type
->toBasetype();
1066 if (Type
*tn
= t
->nextOf())
1067 ret
= e
->e1
->castTo(NULL
, tn
->arrayOf());
1072 e
->e1
= fromConstInitializer(result
, e
->e1
);
1073 // We might know $ now
1074 setLengthVarIfKnown(e
->lengthVar
, e
->e1
);
1075 expOptimize(e
->lwr
, WANTvalue
);
1076 expOptimize(e
->upr
, WANTvalue
);
1077 if (ret
->op
== TOKerror
)
1079 ret
= Slice(e
->type
, e
->e1
, e
->lwr
, e
->upr
).copy();
1080 if (CTFEExp::isCantExp(ret
))
1084 // Bugzilla 14649: We need to leave the slice form so it might be
1085 // a part of array operation.
1086 // Assume that the backend codegen will handle the form `e[]`
1087 // as an equal to `e` itself.
1088 if (ret
->op
== TOKstring
)
1095 //printf("-SliceExp::optimize() %s\n", ret->toChars());
1098 void visit(LogicalExp
*e
)
1100 //printf("LogicalExp::optimize(%d) %s\n", result, e->toChars());
1101 if (expOptimize(e
->e1
, WANTvalue
))
1103 const bool oror
= e
->op
== TOKoror
;
1104 if (e
->e1
->isBool(oror
))
1106 // Replace with (e1, oror)
1107 ret
= new IntegerExp(e
->loc
, oror
, Type::tbool
);
1108 ret
= Expression::combine(e
->e1
, ret
);
1109 if (e
->type
->toBasetype()->ty
== Tvoid
)
1111 ret
= new CastExp(e
->loc
, ret
, Type::tvoid
);
1112 ret
->type
= e
->type
;
1114 ret
= ret
->optimize(result
);
1118 if (expOptimize(e
->e2
, WANTvalue
))
1121 if (e
->e1
->isConst())
1123 if (e
->e2
->isConst())
1125 bool n1
= e
->e1
->isBool(true);
1126 bool n2
= e
->e2
->isBool(true);
1127 ret
= new IntegerExp(e
->loc
, oror
? (n1
|| n2
) : (n1
&& n2
), e
->type
);
1129 else if (e
->e1
->isBool(!oror
))
1131 if (e
->type
->toBasetype()->ty
== Tvoid
)
1135 ret
= new CastExp(e
->loc
, e
->e2
, e
->type
);
1136 ret
->type
= e
->type
;
1142 void visit(CmpExp
*e
)
1144 //printf("CmpExp::optimize() %s\n", e->toChars());
1145 if (binOptimize(e
, WANTvalue
))
1148 Expression
*e1
= fromConstInitializer(result
, e
->e1
);
1149 Expression
*e2
= fromConstInitializer(result
, e
->e2
);
1151 ret
= Cmp(e
->op
, e
->loc
, e
->type
, e1
, e2
).copy();
1152 if (CTFEExp::isCantExp(ret
))
1156 void visit(CatExp
*e
)
1158 //printf("CatExp::optimize(%d) %s\n", result, e->toChars());
1160 if (binOptimize(e
, result
))
1163 if (e
->e1
->op
== TOKcat
)
1165 // Bugzilla 12798: optimize ((expr ~ str1) ~ str2)
1166 CatExp
*ce1
= (CatExp
*)e
->e1
;
1167 CatExp
cex(e
->loc
, ce1
->e2
, e
->e2
);
1169 Expression
*ex
= cex
.optimize(result
);
1177 // optimize "str"[] -> "str"
1178 if (e
->e1
->op
== TOKslice
)
1180 SliceExp
*se1
= (SliceExp
*)e
->e1
;
1181 if (se1
->e1
->op
== TOKstring
&& !se1
->lwr
)
1184 if (e
->e2
->op
== TOKslice
)
1186 SliceExp
*se2
= (SliceExp
*)e
->e2
;
1187 if (se2
->e1
->op
== TOKstring
&& !se2
->lwr
)
1191 ret
= Cat(e
->type
, e
->e1
, e
->e2
).copy();
1192 if (CTFEExp::isCantExp(ret
))
1196 void visit(CondExp
*e
)
1198 if (expOptimize(e
->econd
, WANTvalue
))
1200 if (e
->econd
->isBool(true))
1201 ret
= e
->e1
->optimize(result
, keepLvalue
);
1202 else if (e
->econd
->isBool(false))
1203 ret
= e
->e2
->optimize(result
, keepLvalue
);
1206 expOptimize(e
->e1
, result
, keepLvalue
);
1207 expOptimize(e
->e2
, result
, keepLvalue
);
1212 OptimizeVisitor
v(result
, keepLvalue
);
1213 Expression
*ex
= NULL
;
1216 // Optimize the expression until it can no longer be simplified.