Disallow x[y] if x has a maybe type
[delight/core.git] / dmd2 / optimize.c
blobdbe737f4baea842738d3e8d5eadbacde50ca5392
2 // Compiler implementation of the D programming language
3 // Copyright (c) 1999-2007 by Digital Mars
4 // All Rights Reserved
5 // written by Walter Bright
6 // http://www.digitalmars.com
7 // License for redistribution is by either the Artistic License
8 // in artistic.txt, or the GNU General Public License in gnu.txt.
9 // See the included readme.txt for details.
11 /* NOTE: This file has been patched from the original DMD distribution to
12 work with the GDC compiler.
14 Modified by David Friedman, December 2006
17 #include <stdio.h>
18 #include <ctype.h>
19 #include <assert.h>
20 #include <math.h>
22 #if __DMC__
23 #include <complex.h>
24 #endif
26 #include "lexer.h"
27 #include "mtype.h"
28 #include "expression.h"
29 #include "declaration.h"
30 #include "aggregate.h"
31 #include "init.h"
34 #ifdef IN_GCC
35 #include "d-gcc-real.h"
37 /* %% fix? */
38 extern "C" bool real_isnan (const real_t *);
39 #endif
41 static real_t zero; // work around DMC bug for now
44 /*************************************
45 * If variable has a const initializer,
46 * return that initializer.
49 Expression *expandVar(int result, VarDeclaration *v)
51 //printf("expandVar(result = %d, v = %s)\n", result, v ? v->toChars() : "null");
52 Expression *e = NULL;
53 if (v && (v->isConst() || v->isInvariant() || v->storage_class & STCmanifest))
55 Type *tb = v->type->toBasetype();
56 if (result & WANTinterpret ||
57 v->storage_class & STCmanifest ||
58 (tb->ty != Tsarray && tb->ty != Tstruct)
61 if (v->init)
63 if (v->inuse)
64 goto L1;
65 Expression *ei = v->init->toExpression();
66 if (!ei)
67 goto L1;
68 if (ei->op == TOKconstruct || ei->op == TOKblit)
69 { AssignExp *ae = (AssignExp *)ei;
70 ei = ae->e2;
71 if (ei->isConst() != 1 && ei->op != TOKstring)
72 goto L1;
73 if (ei->type != v->type)
74 goto L1;
76 if (v->scope)
78 v->inuse++;
79 e = ei->syntaxCopy();
80 e = e->semantic(v->scope);
81 e = e->implicitCastTo(v->scope, v->type);
82 v->scope = NULL;
83 v->inuse--;
85 else if (!ei->type)
87 goto L1;
89 else
90 // Should remove the copy() operation by
91 // making all mods to expressions copy-on-write
92 e = ei->copy();
94 else
96 #if 1
97 goto L1;
98 #else
99 // BUG: what if const is initialized in constructor?
100 e = v->type->defaultInit();
101 e->loc = e1->loc;
102 #endif
104 if (e->type != v->type)
106 e = e->castTo(NULL, v->type);
108 e = e->optimize(result);
112 //if (e) printf("\te = %s, e->type = %s\n", e->toChars(), e->type->toChars());
113 return e;
117 Expression *fromConstInitializer(int result, Expression *e1)
119 //printf("fromConstInitializer(result = %x, %s)\n", result, e1->toChars());
120 //static int xx; if (xx++ == 10) assert(0);
121 Expression *e = e1;
122 if (e1->op == TOKvar)
123 { VarExp *ve = (VarExp *)e1;
124 VarDeclaration *v = ve->var->isVarDeclaration();
125 e = expandVar(result, v);
126 if (e)
127 { if (e->type != e1->type)
128 { // Type 'paint' operation
129 e = e->copy();
130 e->type = e1->type;
133 else
134 e = e1;
136 return e;
140 Expression *Expression::optimize(int result)
142 //printf("Expression::optimize(result = x%x) %s\n", result, toChars());
143 return this;
146 Expression *VarExp::optimize(int result)
148 return fromConstInitializer(result, this);
151 Expression *TupleExp::optimize(int result)
153 for (size_t i = 0; i < exps->dim; i++)
154 { Expression *e = (Expression *)exps->data[i];
156 e = e->optimize(WANTvalue | (result & WANTinterpret));
157 exps->data[i] = (void *)e;
159 return this;
162 Expression *ArrayLiteralExp::optimize(int result)
164 if (elements)
166 for (size_t i = 0; i < elements->dim; i++)
167 { Expression *e = (Expression *)elements->data[i];
169 e = e->optimize(WANTvalue | (result & WANTinterpret));
170 elements->data[i] = (void *)e;
173 return this;
176 Expression *AssocArrayLiteralExp::optimize(int result)
178 assert(keys->dim == values->dim);
179 for (size_t i = 0; i < keys->dim; i++)
180 { Expression *e = (Expression *)keys->data[i];
182 e = e->optimize(WANTvalue | (result & WANTinterpret));
183 keys->data[i] = (void *)e;
185 e = (Expression *)values->data[i];
186 e = e->optimize(WANTvalue | (result & WANTinterpret));
187 values->data[i] = (void *)e;
189 return this;
192 Expression *StructLiteralExp::optimize(int result)
194 if (elements)
196 for (size_t i = 0; i < elements->dim; i++)
197 { Expression *e = (Expression *)elements->data[i];
198 if (!e)
199 continue;
200 e = e->optimize(WANTvalue | (result & WANTinterpret));
201 elements->data[i] = (void *)e;
204 return this;
207 Expression *TypeExp::optimize(int result)
209 return this;
212 Expression *UnaExp::optimize(int result)
214 e1 = e1->optimize(result);
215 return this;
218 Expression *NegExp::optimize(int result)
219 { Expression *e;
221 e1 = e1->optimize(result);
222 if (e1->isConst() == 1)
224 e = Neg(type, e1);
226 else
227 e = this;
228 return e;
231 Expression *ComExp::optimize(int result)
232 { Expression *e;
234 e1 = e1->optimize(result);
235 if (e1->isConst() == 1)
237 e = Com(type, e1);
239 else
240 e = this;
241 return e;
244 Expression *NotExp::optimize(int result)
245 { Expression *e;
247 e1 = e1->optimize(result);
248 if (e1->isConst() == 1)
250 e = Not(type, e1);
252 else
253 e = this;
254 return e;
257 Expression *BoolExp::optimize(int result)
258 { Expression *e;
260 e1 = e1->optimize(result);
261 if (e1->isConst() == 1)
263 e = Bool(type, e1);
265 else
266 e = this;
267 return e;
270 Expression *AddrExp::optimize(int result)
271 { Expression *e;
273 //printf("AddrExp::optimize(result = %d) %s\n", result, toChars());
275 /* Rewrite &(a,b) as (a,&b)
277 if (e1->op == TOKcomma)
278 { CommaExp *ce = (CommaExp *)e1;
279 AddrExp *ae = new AddrExp(loc, ce->e2);
280 ae->type = type;
281 e = new CommaExp(ce->loc, ce->e1, ae);
282 e->type = type;
283 return e->optimize(result);
286 if (e1->op == TOKvar)
287 { VarExp *ve = (VarExp *)e1;
288 if (ve->var->storage_class & STCmanifest)
289 e1 = e1->optimize(result);
291 else
292 e1 = e1->optimize(result);
294 // Convert &*ex to ex
295 if (e1->op == TOKstar)
296 { Expression *ex;
298 ex = ((PtrExp *)e1)->e1;
299 if (type->equals(ex->type))
300 e = ex;
301 else
303 #ifndef IN_GCC
304 e = ex->copy();
305 e->type = type;
306 #else
307 // Stuffing types does not always work in GCC
308 return this;
309 #endif
311 return e;
313 if (e1->op == TOKvar)
314 { VarExp *ve = (VarExp *)e1;
315 if (!ve->var->isOut() && !ve->var->isRef() &&
316 !ve->var->isImportedSymbol())
318 SymOffExp *se = new SymOffExp(loc, ve->var, 0, ve->hasOverloads);
319 se->type = type;
320 return se;
323 if (e1->op == TOKindex)
324 { // Convert &array[n] to &array+n
325 IndexExp *ae = (IndexExp *)e1;
327 if (ae->e2->op == TOKint64 && ae->e1->op == TOKvar)
329 integer_t index = ae->e2->toInteger();
330 VarExp *ve = (VarExp *)ae->e1;
331 if (ve->type->ty == Tsarray
332 && !ve->var->isImportedSymbol())
334 TypeSArray *ts = (TypeSArray *)ve->type;
335 integer_t dim = ts->dim->toInteger();
336 if (index < 0 || index >= dim)
337 error("array index %"PRIdMAX" is out of bounds [0..%"PRIdMAX"]", index, dim);
338 e = new SymOffExp(loc, ve->var, index * ts->nextOf()->size());
339 e->type = type;
340 return e;
344 return this;
347 Expression *PtrExp::optimize(int result)
349 //printf("PtrExp::optimize(result = x%x) %s\n", result, toChars());
350 e1 = e1->optimize(result);
351 // Convert *&ex to ex
352 if (e1->op == TOKaddress)
353 { Expression *e;
354 Expression *ex;
356 ex = ((AddrExp *)e1)->e1;
357 if (type->equals(ex->type))
358 e = ex;
359 else
361 #ifndef IN_GCC
362 e = ex->copy();
363 e->type = type;
364 #else
365 // Stuffing types does not always work in GCC
366 return this;
367 #endif
369 return e;
371 // Constant fold *(&structliteral + offset)
372 if (e1->op == TOKadd)
374 Expression *e;
375 e = Ptr(type, e1);
376 if (e != EXP_CANT_INTERPRET)
377 return e;
380 if (e1->op == TOKsymoff)
381 { SymOffExp *se = (SymOffExp *)e1;
382 VarDeclaration *v = se->var->isVarDeclaration();
383 Expression *e = expandVar(result, v);
384 if (e && e->op == TOKstructliteral)
385 { StructLiteralExp *sle = (StructLiteralExp *)e;
386 e = sle->getField(type, se->offset);
387 if (e != EXP_CANT_INTERPRET)
388 return e;
391 return this;
394 Expression *CallExp::optimize(int result)
396 //printf("CallExp::optimize(result = %d) %s\n", result, toChars());
397 Expression *e = this;
399 e1 = e1->optimize(result);
400 if (e1->op == TOKvar)
402 FuncDeclaration *fd = ((VarExp *)e1)->var->isFuncDeclaration();
403 if (fd)
405 enum BUILTIN b = fd->isBuiltin();
406 if (b)
408 e = eval_builtin(b, arguments);
409 if (!e) // failed
410 e = this; // evaluate at runtime
412 else if (result & WANTinterpret)
414 Expression *eresult = fd->interpret(NULL, arguments);
415 if (eresult && eresult != EXP_VOID_INTERPRET)
416 e = eresult;
417 else
418 error("cannot evaluate %s at compile time", toChars());
422 return e;
426 Expression *CastExp::optimize(int result)
428 //printf("CastExp::optimize(result = %d) %s\n", result, toChars());
429 //printf("from %s to %s\n", type->toChars(), to->toChars());
430 //printf("from %s\n", type->toChars());
431 //printf("e1->type %s\n", e1->type->toChars());
432 //printf("type = %p\n", type);
433 assert(type);
434 enum TOK op1 = e1->op;
435 #define X 0
437 e1 = e1->optimize(result);
438 e1 = fromConstInitializer(result, e1);
440 if ((e1->op == TOKstring || e1->op == TOKarrayliteral) &&
441 (type->ty == Tpointer || type->ty == Tarray) &&
442 e1->type->nextOf()->size() == type->nextOf()->size()
445 e1 = e1->castTo(NULL, type);
446 if (X) printf(" returning1 %s\n", e1->toChars());
447 return e1;
450 if (e1->op == TOKstructliteral &&
451 e1->type->implicitConvTo(type) >= MATCHconst)
453 e1->type = type;
454 if (X) printf(" returning2 %s\n", e1->toChars());
455 return e1;
458 /* The first test here is to prevent infinite loops
460 if (op1 != TOKarrayliteral && e1->op == TOKarrayliteral)
461 return e1->castTo(NULL, to);
462 if (e1->op == TOKnull &&
463 (type->ty == Tpointer || type->ty == Tclass || type->ty == Tarray))
465 e1->type = type;
466 if (X) printf(" returning3 %s\n", e1->toChars());
467 return e1;
470 if (result & WANTflags && type->ty == Tclass && e1->type->ty == Tclass)
472 // See if we can remove an unnecessary cast
473 ClassDeclaration *cdfrom;
474 ClassDeclaration *cdto;
475 target_ptrdiff_t offset;
477 cdfrom = e1->type->isClassHandle();
478 cdto = type->isClassHandle();
479 if (cdto->isBaseOf(cdfrom, &offset) && offset == 0)
481 e1->type = type;
482 if (X) printf(" returning4 %s\n", e1->toChars());
483 return e1;
487 // We can convert 'head const' to mutable
488 if (to->constOf()->equals(e1->type->constOf()))
489 // if (to->constConv(e1->type) >= MATCHconst)
491 e1->type = type;
492 if (X) printf(" returning5 %s\n", e1->toChars());
493 return e1;
496 Expression *e;
498 if (e1->isConst())
500 if (e1->op == TOKsymoff)
502 if (type->size() == e1->type->size() &&
503 type->toBasetype()->ty != Tsarray)
505 e1->type = type;
506 return e1;
508 return this;
510 if (to->toBasetype()->ty == Tvoid)
511 e = this;
512 else
513 e = Cast(type, to, e1);
515 else
516 e = this;
517 if (X) printf(" returning6 %s\n", e->toChars());
518 return e;
519 #undef X
522 Expression *BinExp::optimize(int result)
524 //printf("BinExp::optimize(result = %d) %s\n", result, toChars());
525 if (op != TOKconstruct && op != TOKblit) // don't replace const variable with its initializer
526 e1 = e1->optimize(result);
527 e2 = e2->optimize(result);
528 if (op == TOKshlass || op == TOKshrass || op == TOKushrass)
530 if (e2->isConst() == 1)
532 integer_t i2 = e2->toInteger();
533 d_uns64 sz = e1->type->size() * 8;
534 if (i2 < 0 || i2 > sz)
535 { error("shift assign by %jd is outside the range 0..%zu", i2, sz);
536 e2 = new IntegerExp(0);
540 return this;
543 Expression *AddExp::optimize(int result)
544 { Expression *e;
546 //printf("AddExp::optimize(%s)\n", toChars());
547 e1 = e1->optimize(result);
548 e2 = e2->optimize(result);
549 if (e1->isConst() && e2->isConst())
551 if (e1->op == TOKsymoff && e2->op == TOKsymoff)
552 return this;
553 e = Add(type, e1, e2);
555 else
556 e = this;
557 return e;
560 Expression *MinExp::optimize(int result)
561 { Expression *e;
563 e1 = e1->optimize(result);
564 e2 = e2->optimize(result);
565 if (e1->isConst() && e2->isConst())
567 if (e2->op == TOKsymoff)
568 return this;
569 e = Min(type, e1, e2);
571 else
572 e = this;
573 return e;
576 Expression *MulExp::optimize(int result)
577 { Expression *e;
579 //printf("MulExp::optimize(result = %d) %s\n", result, toChars());
580 e1 = e1->optimize(result);
581 e2 = e2->optimize(result);
582 if (e1->isConst() == 1 && e2->isConst() == 1)
584 e = Mul(type, e1, e2);
586 else
587 e = this;
588 return e;
591 Expression *DivExp::optimize(int result)
592 { Expression *e;
594 //printf("DivExp::optimize(%s)\n", toChars());
595 e1 = e1->optimize(result);
596 e2 = e2->optimize(result);
597 if (e1->isConst() == 1 && e2->isConst() == 1)
599 e = Div(type, e1, e2);
601 else
602 e = this;
603 return e;
606 Expression *ModExp::optimize(int result)
607 { Expression *e;
609 e1 = e1->optimize(result);
610 e2 = e2->optimize(result);
611 if (e1->isConst() == 1 && e2->isConst() == 1)
613 e = Mod(type, e1, e2);
615 else
616 e = this;
617 return e;
620 Expression *shift_optimize(int result, BinExp *e, Expression *(*shift)(Type *, Expression *, Expression *))
621 { Expression *ex = e;
623 e->e1 = e->e1->optimize(result);
624 e->e2 = e->e2->optimize(result);
625 if (e->e2->isConst() == 1)
627 integer_t i2 = e->e2->toInteger();
628 target_size_t sz = e->e1->type->size() * 8;
629 if (i2 < 0 || i2 > sz)
630 { error("shift left by %"PRIdMAX" exceeds %"PRIuTSIZE, i2, sz);
631 e->e2 = new IntegerExp(0);
633 if (e->e1->isConst() == 1)
634 ex = (*shift)(e->type, e->e1, e->e2);
636 return ex;
639 Expression *ShlExp::optimize(int result)
641 //printf("ShlExp::optimize(result = %d) %s\n", result, toChars());
642 return shift_optimize(result, this, Shl);
645 Expression *ShrExp::optimize(int result)
647 //printf("ShrExp::optimize(result = %d) %s\n", result, toChars());
648 return shift_optimize(result, this, Shr);
651 Expression *UshrExp::optimize(int result)
653 //printf("UshrExp::optimize(result = %d) %s\n", result, toChars());
654 return shift_optimize(result, this, Ushr);
657 Expression *AndExp::optimize(int result)
658 { Expression *e;
660 e1 = e1->optimize(result);
661 e2 = e2->optimize(result);
662 if (e1->isConst() == 1 && e2->isConst() == 1)
663 e = And(type, e1, e2);
664 else
665 e = this;
666 return e;
669 Expression *OrExp::optimize(int result)
670 { Expression *e;
672 e1 = e1->optimize(result);
673 e2 = e2->optimize(result);
674 if (e1->isConst() == 1 && e2->isConst() == 1)
675 e = Or(type, e1, e2);
676 else
677 e = this;
678 return e;
681 Expression *XorExp::optimize(int result)
682 { Expression *e;
684 e1 = e1->optimize(result);
685 e2 = e2->optimize(result);
686 if (e1->isConst() == 1 && e2->isConst() == 1)
687 e = Xor(type, e1, e2);
688 else
689 e = this;
690 return e;
693 Expression *CommaExp::optimize(int result)
694 { Expression *e;
696 //printf("CommaExp::optimize(result = %d) %s\n", result, toChars());
697 e1 = e1->optimize(result & WANTinterpret);
698 e2 = e2->optimize(result);
699 if (!e1 || e1->op == TOKint64 || e1->op == TOKfloat64 || !e1->checkSideEffect(2))
701 e = e2;
702 if (e)
703 e->type = type;
705 else
706 e = this;
707 //printf("-CommaExp::optimize(result = %d) %s\n", result, e->toChars());
708 return e;
711 Expression *ArrayLengthExp::optimize(int result)
712 { Expression *e;
714 //printf("ArrayLengthExp::optimize(result = %d) %s\n", result, toChars());
715 e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
716 e = this;
717 if (e1->op == TOKstring || e1->op == TOKarrayliteral || e1->op == TOKassocarrayliteral)
719 e = ArrayLength(type, e1);
721 return e;
724 Expression *EqualExp::optimize(int result)
725 { Expression *e;
727 //printf("EqualExp::optimize(result = %x) %s\n", result, toChars());
728 e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
729 e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
730 e = this;
732 Expression *e1 = fromConstInitializer(result, this->e1);
733 Expression *e2 = fromConstInitializer(result, this->e2);
735 e = Equal(op, type, e1, e2);
736 if (e == EXP_CANT_INTERPRET)
737 e = this;
738 return e;
741 Expression *IdentityExp::optimize(int result)
742 { Expression *e;
744 //printf("IdentityExp::optimize(result = %d) %s\n", result, toChars());
745 e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
746 e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
747 e = this;
748 if (this->e1->isConst() && this->e2->isConst())
750 e = Identity(op, type, this->e1, this->e2);
752 return e;
755 Expression *IndexExp::optimize(int result)
756 { Expression *e;
758 //printf("IndexExp::optimize(result = %d) %s\n", result, toChars());
759 Expression *e1 = this->e1->optimize(WANTvalue | (result & WANTinterpret));
760 e1 = fromConstInitializer(result, e1);
761 e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
762 e = Index(type, e1, e2);
763 if (e == EXP_CANT_INTERPRET)
764 e = this;
765 return e;
768 Expression *SliceExp::optimize(int result)
769 { Expression *e;
771 //printf("SliceExp::optimize(result = %d) %s\n", result, toChars());
772 e = this;
773 e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
774 if (!lwr)
775 { if (e1->op == TOKstring)
776 { // Convert slice of string literal into dynamic array
777 Type *t = e1->type->toBasetype();
778 if (t->nextOf())
779 e = e1->castTo(NULL, t->nextOf()->arrayOf());
781 return e;
783 e1 = fromConstInitializer(result, e1);
784 lwr = lwr->optimize(WANTvalue | (result & WANTinterpret));
785 upr = upr->optimize(WANTvalue | (result & WANTinterpret));
786 e = Slice(type, e1, lwr, upr);
787 if (e == EXP_CANT_INTERPRET)
788 e = this;
789 //printf("-SliceExp::optimize() %s\n", e->toChars());
790 return e;
793 Expression *AndAndExp::optimize(int result)
794 { Expression *e;
796 //printf("AndAndExp::optimize(%d) %s\n", result, toChars());
797 e1 = e1->optimize(WANTflags | (result & WANTinterpret));
798 e = this;
799 if (e1->isBool(FALSE))
801 e = new CommaExp(loc, e1, new IntegerExp(loc, 0, type));
802 e->type = type;
803 e = e->optimize(result);
805 else
807 e2 = e2->optimize(WANTflags | (result & WANTinterpret));
808 if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors)
809 error("void has no value");
810 if (e1->isConst())
812 if (e2->isConst())
813 { int n1 = e1->isBool(1);
814 int n2 = e2->isBool(1);
816 e = new IntegerExp(loc, n1 && n2, type);
818 else if (e1->isBool(TRUE))
819 e = new BoolExp(loc, e2, type);
822 return e;
825 Expression *OrOrExp::optimize(int result)
826 { Expression *e;
828 e1 = e1->optimize(WANTflags | (result & WANTinterpret));
829 e = this;
830 if (e1->isBool(TRUE))
831 { // Replace with (e1, 1)
832 e = new CommaExp(loc, e1, new IntegerExp(loc, 1, type));
833 e->type = type;
834 e = e->optimize(result);
836 else
838 e2 = e2->optimize(WANTflags | (result & WANTinterpret));
839 if (result && e2->type->toBasetype()->ty == Tvoid && !global.errors)
840 error("void has no value");
841 if (e1->isConst())
843 if (e2->isConst())
844 { int n1 = e1->isBool(1);
845 int n2 = e2->isBool(1);
847 e = new IntegerExp(loc, n1 || n2, type);
849 else if (e1->isBool(FALSE))
850 e = new BoolExp(loc, e2, type);
853 return e;
856 Expression *CmpExp::optimize(int result)
857 { Expression *e;
859 //printf("CmpExp::optimize() %s\n", toChars());
860 e1 = e1->optimize(WANTvalue | (result & WANTinterpret));
861 e2 = e2->optimize(WANTvalue | (result & WANTinterpret));
863 Expression *e1 = fromConstInitializer(result, this->e1);
864 Expression *e2 = fromConstInitializer(result, this->e2);
866 e = Cmp(op, type, e1, e2);
867 if (e == EXP_CANT_INTERPRET)
868 e = this;
869 return e;
872 Expression *CatExp::optimize(int result)
873 { Expression *e;
875 //printf("CatExp::optimize(%d) %s\n", result, toChars());
876 e1 = e1->optimize(result);
877 e2 = e2->optimize(result);
878 e = Cat(type, e1, e2);
879 if (e == EXP_CANT_INTERPRET)
880 e = this;
881 return e;
885 Expression *CondExp::optimize(int result)
886 { Expression *e;
888 econd = econd->optimize(WANTflags | (result & WANTinterpret));
889 if (econd->isBool(TRUE))
890 e = e1->optimize(result);
891 else if (econd->isBool(FALSE))
892 e = e2->optimize(result);
893 else
894 { e1 = e1->optimize(result);
895 e2 = e2->optimize(result);
896 e = this;
898 return e;