1 /**
2  * Compiler implementation of the
3  * $(LINK2 http://www.dlang.org, D programming language).
4  *
5  * Copyright:   Copyright (c) 1999-2016 by Digital Mars, All Rights Reserved
6  * Authors:     $(LINK2 http://www.digitalmars.com, Walter Bright)
7  * License:     $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0)
8  * Source:      $(DMDSRC _constfold.d)
9  */
10 
11 module ddmd.constfold;
12 
13 import core.stdc..string;
14 import core.stdc.stdio;
15 import ddmd.arraytypes;
16 import ddmd.complex;
17 import ddmd.ctfeexpr;
18 import ddmd.declaration;
19 import ddmd.dstruct;
20 import ddmd.errors;
21 import ddmd.expression;
22 import ddmd.globals;
23 import ddmd.mtype;
24 import ddmd.root.ctfloat;
25 import ddmd.root.port;
26 import ddmd.root.rmem;
27 import ddmd.sideeffect;
28 import ddmd.target;
29 import ddmd.tokens;
30 import ddmd.utf;
31 
32 private enum LOG = false;
33 
34 extern (C++) Expression expType(Type type, Expression e)
35 {
36     if (type != e.type)
37     {
38         e = e.copy();
39         e.type = type;
40     }
41     return e;
42 }
43 
44 /* ================================== isConst() ============================== */
45 extern (C++) int isConst(Expression e)
46 {
47     //printf("Expression::isConst(): %s\n", e->toChars());
48     switch (e.op)
49     {
50     case TOKint64:
51     case TOKfloat64:
52     case TOKcomplex80:
53         return 1;
54     case TOKnull:
55         return 0;
56     case TOKsymoff:
57         return 2;
58     default:
59         return 0;
60     }
61     assert(0);
62 }
63 
64 /* =============================== constFold() ============================== */
65 /* The constFold() functions were redundant with the optimize() ones,
66  * and so have been folded in with them.
67  */
68 /* ========================================================================== */
69 extern (C++) UnionExp Neg(Type type, Expression e1)
70 {
71     UnionExp ue;
72     Loc loc = e1.loc;
73     if (e1.type.isreal())
74     {
75         emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type);
76     }
77     else if (e1.type.isimaginary())
78     {
79         emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type);
80     }
81     else if (e1.type.iscomplex())
82     {
83         emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type);
84     }
85     else
86     {
87         emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type);
88     }
89     return ue;
90 }
91 
92 extern (C++) UnionExp Com(Type type, Expression e1)
93 {
94     UnionExp ue;
95     Loc loc = e1.loc;
96     emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type);
97     return ue;
98 }
99 
100 extern (C++) UnionExp Not(Type type, Expression e1)
101 {
102     UnionExp ue;
103     Loc loc = e1.loc;
104     emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(false) ? 1 : 0, type);
105     return ue;
106 }
107 
108 extern (C++) UnionExp Bool(Type type, Expression e1)
109 {
110     UnionExp ue;
111     Loc loc = e1.loc;
112     emplaceExp!(IntegerExp)(&ue, loc, e1.isBool(true) ? 1 : 0, type);
113     return ue;
114 }
115 
116 extern (C++) UnionExp Add(Loc loc, Type type, Expression e1, Expression e2)
117 {
118     UnionExp ue;
119     static if (LOG)
120     {
121         printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
122     }
123     if (type.isreal())
124     {
125         emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type);
126     }
127     else if (type.isimaginary())
128     {
129         emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type);
130     }
131     else if (type.iscomplex())
132     {
133         // This rigamarole is necessary so that -0.0 doesn't get
134         // converted to +0.0 by doing an extraneous add with +0.0
135         auto c1 = complex_t(CTFloat.zero);
136         real_t r1 = 0;
137         real_t i1 = 0;
138         auto c2 = complex_t(CTFloat.zero);
139         real_t r2 = 0;
140         real_t i2 = 0;
141         auto v = complex_t(CTFloat.zero);
142         int x;
143         if (e1.type.isreal())
144         {
145             r1 = e1.toReal();
146             x = 0;
147         }
148         else if (e1.type.isimaginary())
149         {
150             i1 = e1.toImaginary();
151             x = 3;
152         }
153         else
154         {
155             c1 = e1.toComplex();
156             x = 6;
157         }
158         if (e2.type.isreal())
159         {
160             r2 = e2.toReal();
161         }
162         else if (e2.type.isimaginary())
163         {
164             i2 = e2.toImaginary();
165             x += 1;
166         }
167         else
168         {
169             c2 = e2.toComplex();
170             x += 2;
171         }
172         switch (x)
173         {
174         case 0 + 0:
175             v = complex_t(r1 + r2);
176             break;
177         case 0 + 1:
178             v = complex_t(r1, i2);
179             break;
180         case 0 + 2:
181             v = complex_t(r1 + creall(c2), cimagl(c2));
182             break;
183         case 3 + 0:
184             v = complex_t(r2, i1);
185             break;
186         case 3 + 1:
187             v = complex_t(CTFloat.zero, i1 + i2);
188             break;
189         case 3 + 2:
190             v = complex_t(creall(c2), i1 + cimagl(c2));
191             break;
192         case 6 + 0:
193             v = complex_t(creall(c1) + r2, cimagl(c2));
194             break;
195         case 6 + 1:
196             v = complex_t(creall(c1), cimagl(c1) + i2);
197             break;
198         case 6 + 2:
199             v = c1 + c2;
200             break;
201         default:
202             assert(0);
203         }
204         emplaceExp!(ComplexExp)(&ue, loc, v, type);
205     }
206     else if (e1.op == TOKsymoff)
207     {
208         SymOffExp soe = cast(SymOffExp)e1;
209         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
210         ue.exp().type = type;
211     }
212     else if (e2.op == TOKsymoff)
213     {
214         SymOffExp soe = cast(SymOffExp)e2;
215         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
216         ue.exp().type = type;
217     }
218     else
219         emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type);
220     return ue;
221 }
222 
223 extern (C++) UnionExp Min(Loc loc, Type type, Expression e1, Expression e2)
224 {
225     UnionExp ue;
226     if (type.isreal())
227     {
228         emplaceExp!(RealExp)(&ue, loc, e1.toReal() - e2.toReal(), type);
229     }
230     else if (type.isimaginary())
231     {
232         emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() - e2.toImaginary(), type);
233     }
234     else if (type.iscomplex())
235     {
236         // This rigamarole is necessary so that -0.0 doesn't get
237         // converted to +0.0 by doing an extraneous add with +0.0
238         auto c1 = complex_t(CTFloat.zero);
239         real_t r1 = 0;
240         real_t i1 = 0;
241         auto c2 = complex_t(CTFloat.zero);
242         real_t r2 = 0;
243         real_t i2 = 0;
244         auto v = complex_t(CTFloat.zero);
245         int x;
246         if (e1.type.isreal())
247         {
248             r1 = e1.toReal();
249             x = 0;
250         }
251         else if (e1.type.isimaginary())
252         {
253             i1 = e1.toImaginary();
254             x = 3;
255         }
256         else
257         {
258             c1 = e1.toComplex();
259             x = 6;
260         }
261         if (e2.type.isreal())
262         {
263             r2 = e2.toReal();
264         }
265         else if (e2.type.isimaginary())
266         {
267             i2 = e2.toImaginary();
268             x += 1;
269         }
270         else
271         {
272             c2 = e2.toComplex();
273             x += 2;
274         }
275         switch (x)
276         {
277         case 0 + 0:
278             v = complex_t(r1 - r2);
279             break;
280         case 0 + 1:
281             v = complex_t(r1, -i2);
282             break;
283         case 0 + 2:
284             v = complex_t(r1 - creall(c2), -cimagl(c2));
285             break;
286         case 3 + 0:
287             v = complex_t(-r2, i1);
288             break;
289         case 3 + 1:
290             v = complex_t(CTFloat.zero, i1 - i2);
291             break;
292         case 3 + 2:
293             v = complex_t(-creall(c2), i1 - cimagl(c2));
294             break;
295         case 6 + 0:
296             v = complex_t(creall(c1) - r2, cimagl(c1));
297             break;
298         case 6 + 1:
299             v = complex_t(creall(c1), cimagl(c1) - i2);
300             break;
301         case 6 + 2:
302             v = c1 - c2;
303             break;
304         default:
305             assert(0);
306         }
307         emplaceExp!(ComplexExp)(&ue, loc, v, type);
308     }
309     else if (e1.op == TOKsymoff)
310     {
311         SymOffExp soe = cast(SymOffExp)e1;
312         emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset - e2.toInteger());
313         ue.exp().type = type;
314     }
315     else
316     {
317         emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() - e2.toInteger(), type);
318     }
319     return ue;
320 }
321 
322 extern (C++) UnionExp Mul(Loc loc, Type type, Expression e1, Expression e2)
323 {
324     UnionExp ue;
325     if (type.isfloating())
326     {
327         auto c = complex_t(CTFloat.zero);
328         real_t r = 0;
329         if (e1.type.isreal())
330         {
331             r = e1.toReal();
332             c = e2.toComplex();
333             c = complex_t(r * creall(c), r * cimagl(c));
334         }
335         else if (e1.type.isimaginary())
336         {
337             r = e1.toImaginary();
338             c = e2.toComplex();
339             c = complex_t(-r * cimagl(c), r * creall(c));
340         }
341         else if (e2.type.isreal())
342         {
343             r = e2.toReal();
344             c = e1.toComplex();
345             c = complex_t(r * creall(c), r * cimagl(c));
346         }
347         else if (e2.type.isimaginary())
348         {
349             r = e2.toImaginary();
350             c = e1.toComplex();
351             c = complex_t(-r * cimagl(c), r * creall(c));
352         }
353         else
354             c = e1.toComplex() * e2.toComplex();
355         if (type.isreal())
356             emplaceExp!(RealExp)(&ue, loc, creall(c), type);
357         else if (type.isimaginary())
358             emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
359         else if (type.iscomplex())
360             emplaceExp!(ComplexExp)(&ue, loc, c, type);
361         else
362             assert(0);
363     }
364     else
365     {
366         emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type);
367     }
368     return ue;
369 }
370 
371 extern (C++) UnionExp Div(Loc loc, Type type, Expression e1, Expression e2)
372 {
373     UnionExp ue;
374     if (type.isfloating())
375     {
376         auto c = complex_t(CTFloat.zero);
377         //e1->type->print();
378         //e2->type->print();
379         if (e2.type.isreal())
380         {
381             if (e1.type.isreal())
382             {
383                 version (all)
384                 {
385                     // Work around redundant REX.W prefix breaking Valgrind
386                     // when built with affected versions of DMD.
387                     // https://issues.dlang.org/show_bug.cgi?id=14952
388                     // This can be removed once compiling with DMD 2.068 or
389                     // older is no longer supported.
390                     const r1 = e1.toReal();
391                     const r2 = e2.toReal();
392                     emplaceExp!(RealExp)(&ue, loc, r1 / r2, type);
393                 }
394                 else
395                 {
396                     emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type);
397                 }
398                 return ue;
399             }
400             const r = e2.toReal();
401             c = e1.toComplex();
402             c = complex_t(creall(c) / r, cimagl(c) / r);
403         }
404         else if (e2.type.isimaginary())
405         {
406             const r = e2.toImaginary();
407             c = e1.toComplex();
408             c = complex_t(cimagl(c) / r, -creall(c) / r);
409         }
410         else
411         {
412             c = e1.toComplex() / e2.toComplex();
413         }
414 
415         if (type.isreal())
416             emplaceExp!(RealExp)(&ue, loc, creall(c), type);
417         else if (type.isimaginary())
418             emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
419         else if (type.iscomplex())
420             emplaceExp!(ComplexExp)(&ue, loc, c, type);
421         else
422             assert(0);
423     }
424     else
425     {
426         sinteger_t n1;
427         sinteger_t n2;
428         sinteger_t n;
429         n1 = e1.toInteger();
430         n2 = e2.toInteger();
431         if (n2 == 0)
432         {
433             e2.error("divide by 0");
434             n2 = 1;
435         }
436         if (e1.type.isunsigned() || e2.type.isunsigned())
437             n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2);
438         else
439             n = n1 / n2;
440         emplaceExp!(IntegerExp)(&ue, loc, n, type);
441     }
442     return ue;
443 }
444 
445 extern (C++) UnionExp Mod(Loc loc, Type type, Expression e1, Expression e2)
446 {
447     UnionExp ue;
448     if (type.isfloating())
449     {
450         auto c = complex_t(CTFloat.zero);
451         if (e2.type.isreal())
452         {
453             const r2 = e2.toReal();
454             c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
455         }
456         else if (e2.type.isimaginary())
457         {
458             const i2 = e2.toImaginary();
459             c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
460         }
461         else
462             assert(0);
463         if (type.isreal())
464             emplaceExp!(RealExp)(&ue, loc, creall(c), type);
465         else if (type.isimaginary())
466             emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
467         else if (type.iscomplex())
468             emplaceExp!(ComplexExp)(&ue, loc, c, type);
469         else
470             assert(0);
471     }
472     else
473     {
474         sinteger_t n1;
475         sinteger_t n2;
476         sinteger_t n;
477         n1 = e1.toInteger();
478         n2 = e2.toInteger();
479         if (n2 == 0)
480         {
481             e2.error("divide by 0");
482             n2 = 1;
483         }
484         if (n2 == -1 && !type.isunsigned())
485         {
486             // Check for int.min % -1
487             if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
488             {
489                 e2.error("integer overflow: int.min % -1");
490                 n2 = 1;
491             }
492             else if (n1 == 0x8000000000000000L) // long.min % -1
493             {
494                 e2.error("integer overflow: long.min % -1");
495                 n2 = 1;
496             }
497         }
498         if (e1.type.isunsigned() || e2.type.isunsigned())
499             n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2);
500         else
501             n = n1 % n2;
502         emplaceExp!(IntegerExp)(&ue, loc, n, type);
503     }
504     return ue;
505 }
506 
507 extern (C++) UnionExp Pow(Loc loc, Type type, Expression e1, Expression e2)
508 {
509     UnionExp ue;
510     // Handle integer power operations.
511     if (e2.type.isintegral())
512     {
513         dinteger_t n = e2.toInteger();
514         bool neg;
515         if (!e2.type.isunsigned() && cast(sinteger_t)n < 0)
516         {
517             if (e1.type.isintegral())
518             {
519                 emplaceExp!(CTFEExp)(&ue, TOKcantexp);
520                 return ue;
521             }
522             // Don't worry about overflow, from now on n is unsigned.
523             neg = true;
524             n = -n;
525         }
526         else
527             neg = false;
528         UnionExp ur, uv;
529         if (e1.type.iscomplex())
530         {
531             emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
532             emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type);
533         }
534         else if (e1.type.isfloating())
535         {
536             emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
537             emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type);
538         }
539         else
540         {
541             emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type);
542             emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type);
543         }
544         Expression r = ur.exp();
545         Expression v = uv.exp();
546         while (n != 0)
547         {
548             if (n & 1)
549             {
550                 // v = v * r;
551                 uv = Mul(loc, v.type, v, r);
552             }
553             n >>= 1;
554             // r = r * r
555             ur = Mul(loc, r.type, r, r);
556         }
557         if (neg)
558         {
559             // ue = 1.0 / v
560             UnionExp one;
561             emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type);
562             uv = Div(loc, v.type, one.exp(), v);
563         }
564         if (type.iscomplex())
565             emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type);
566         else if (type.isintegral())
567             emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type);
568         else
569             emplaceExp!(RealExp)(&ue, loc, v.toReal(), type);
570     }
571     else if (e2.type.isfloating())
572     {
573         // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
574         if (e1.toReal() < CTFloat.zero)
575         {
576             emplaceExp!(RealExp)(&ue, loc, Target.RealProperties.nan, type);
577         }
578         else
579             emplaceExp!(CTFEExp)(&ue, TOKcantexp);
580     }
581     else
582         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
583     return ue;
584 }
585 
586 extern (C++) UnionExp Shl(Loc loc, Type type, Expression e1, Expression e2)
587 {
588     UnionExp ue;
589     emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type);
590     return ue;
591 }
592 
593 extern (C++) UnionExp Shr(Loc loc, Type type, Expression e1, Expression e2)
594 {
595     UnionExp ue;
596     dinteger_t value = e1.toInteger();
597     dinteger_t dcount = e2.toInteger();
598     assert(dcount <= 0xFFFFFFFF);
599     uint count = cast(uint)dcount;
600     switch (e1.type.toBasetype().ty)
601     {
602     case Tint8:
603         value = cast(d_int8)value >> count;
604         break;
605     case Tuns8:
606     case Tchar:
607         value = cast(d_uns8)value >> count;
608         break;
609     case Tint16:
610         value = cast(d_int16)value >> count;
611         break;
612     case Tuns16:
613     case Twchar:
614         value = cast(d_uns16)value >> count;
615         break;
616     case Tint32:
617         value = cast(d_int32)value >> count;
618         break;
619     case Tuns32:
620     case Tdchar:
621         value = cast(d_uns32)value >> count;
622         break;
623     case Tint64:
624         value = cast(d_int64)value >> count;
625         break;
626     case Tuns64:
627         value = cast(d_uns64)value >> count;
628         break;
629     case Terror:
630         emplaceExp!(ErrorExp)(&ue);
631         return ue;
632     default:
633         assert(0);
634     }
635     emplaceExp!(IntegerExp)(&ue, loc, value, type);
636     return ue;
637 }
638 
639 extern (C++) UnionExp Ushr(Loc loc, Type type, Expression e1, Expression e2)
640 {
641     UnionExp ue;
642     dinteger_t value = e1.toInteger();
643     dinteger_t dcount = e2.toInteger();
644     assert(dcount <= 0xFFFFFFFF);
645     uint count = cast(uint)dcount;
646     switch (e1.type.toBasetype().ty)
647     {
648     case Tint8:
649     case Tuns8:
650     case Tchar:
651         // Possible only with >>>=. >>> always gets promoted to int.
652         value = (value & 0xFF) >> count;
653         break;
654     case Tint16:
655     case Tuns16:
656     case Twchar:
657         // Possible only with >>>=. >>> always gets promoted to int.
658         value = (value & 0xFFFF) >> count;
659         break;
660     case Tint32:
661     case Tuns32:
662     case Tdchar:
663         value = (value & 0xFFFFFFFF) >> count;
664         break;
665     case Tint64:
666     case Tuns64:
667         value = cast(d_uns64)value >> count;
668         break;
669     case Terror:
670         emplaceExp!(ErrorExp)(&ue);
671         return ue;
672     default:
673         assert(0);
674     }
675     emplaceExp!(IntegerExp)(&ue, loc, value, type);
676     return ue;
677 }
678 
679 extern (C++) UnionExp And(Loc loc, Type type, Expression e1, Expression e2)
680 {
681     UnionExp ue;
682     emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type);
683     return ue;
684 }
685 
686 extern (C++) UnionExp Or(Loc loc, Type type, Expression e1, Expression e2)
687 {
688     UnionExp ue;
689     emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type);
690     return ue;
691 }
692 
693 extern (C++) UnionExp Xor(Loc loc, Type type, Expression e1, Expression e2)
694 {
695     //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
696     UnionExp ue;
697     emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type);
698     return ue;
699 }
700 
701 /* Also returns TOKcantexp if cannot be computed.
702  */
703 extern (C++) UnionExp Equal(TOK op, Loc loc, Type type, Expression e1, Expression e2)
704 {
705     UnionExp ue;
706     int cmp = 0;
707     real_t r1 = 0;
708     real_t r2 = 0;
709     //printf("Equal(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
710     assert(op == TOKequal || op == TOKnotequal);
711     if (e1.op == TOKnull)
712     {
713         if (e2.op == TOKnull)
714             cmp = 1;
715         else if (e2.op == TOKstring)
716         {
717             StringExp es2 = cast(StringExp)e2;
718             cmp = (0 == es2.len);
719         }
720         else if (e2.op == TOKarrayliteral)
721         {
722             ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
723             cmp = !es2.elements || (0 == es2.elements.dim);
724         }
725         else
726         {
727             emplaceExp!(CTFEExp)(&ue, TOKcantexp);
728             return ue;
729         }
730     }
731     else if (e2.op == TOKnull)
732     {
733         if (e1.op == TOKstring)
734         {
735             StringExp es1 = cast(StringExp)e1;
736             cmp = (0 == es1.len);
737         }
738         else if (e1.op == TOKarrayliteral)
739         {
740             ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
741             cmp = !es1.elements || (0 == es1.elements.dim);
742         }
743         else
744         {
745             emplaceExp!(CTFEExp)(&ue, TOKcantexp);
746             return ue;
747         }
748     }
749     else if (e1.op == TOKstring && e2.op == TOKstring)
750     {
751         StringExp es1 = cast(StringExp)e1;
752         StringExp es2 = cast(StringExp)e2;
753         if (es1.sz != es2.sz)
754         {
755             assert(global.errors);
756             emplaceExp!(CTFEExp)(&ue, TOKcantexp);
757             return ue;
758         }
759         if (es1.len == es2.len && memcmp(es1..string, es2..string, es1.sz * es1.len) == 0)
760             cmp = 1;
761         else
762             cmp = 0;
763     }
764     else if (e1.op == TOKarrayliteral && e2.op == TOKarrayliteral)
765     {
766         ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
767         ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
768         if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
769             cmp = 1; // both arrays are empty
770         else if (!es1.elements || !es2.elements)
771             cmp = 0;
772         else if (es1.elements.dim != es2.elements.dim)
773             cmp = 0;
774         else
775         {
776             for (size_t i = 0; i < es1.elements.dim; i++)
777             {
778                 auto ee1 = es1.getElement(i);
779                 auto ee2 = es2.getElement(i);
780                 ue = Equal(TOKequal, loc, Type.tint32, ee1, ee2);
781                 if (CTFEExp.isCantExp(ue.exp()))
782                     return ue;
783                 cmp = cast(int)ue.exp().toInteger();
784                 if (cmp == 0)
785                     break;
786             }
787         }
788     }
789     else if (e1.op == TOKarrayliteral && e2.op == TOKstring)
790     {
791         // Swap operands and use common code
792         Expression etmp = e1;
793         e1 = e2;
794         e2 = etmp;
795         goto Lsa;
796     }
797     else if (e1.op == TOKstring && e2.op == TOKarrayliteral)
798     {
799     Lsa:
800         StringExp es1 = cast(StringExp)e1;
801         ArrayLiteralExp es2 = cast(ArrayLiteralExp)e2;
802         size_t dim1 = es1.len;
803         size_t dim2 = es2.elements ? es2.elements.dim : 0;
804         if (dim1 != dim2)
805             cmp = 0;
806         else
807         {
808             cmp = 1; // if dim1 winds up being 0
809             for (size_t i = 0; i < dim1; i++)
810             {
811                 uinteger_t c = es1.charAt(i);
812                 auto ee2 = es2.getElement(i);
813                 if (ee2.isConst() != 1)
814                 {
815                     emplaceExp!(CTFEExp)(&ue, TOKcantexp);
816                     return ue;
817                 }
818                 cmp = (c == ee2.toInteger());
819                 if (cmp == 0)
820                     break;
821             }
822         }
823     }
824     else if (e1.op == TOKstructliteral && e2.op == TOKstructliteral)
825     {
826         StructLiteralExp es1 = cast(StructLiteralExp)e1;
827         StructLiteralExp es2 = cast(StructLiteralExp)e2;
828         if (es1.sd != es2.sd)
829             cmp = 0;
830         else if ((!es1.elements || !es1.elements.dim) && (!es2.elements || !es2.elements.dim))
831             cmp = 1; // both arrays are empty
832         else if (!es1.elements || !es2.elements)
833             cmp = 0;
834         else if (es1.elements.dim != es2.elements.dim)
835             cmp = 0;
836         else
837         {
838             cmp = 1;
839             for (size_t i = 0; i < es1.elements.dim; i++)
840             {
841                 Expression ee1 = (*es1.elements)[i];
842                 Expression ee2 = (*es2.elements)[i];
843                 if (ee1 == ee2)
844                     continue;
845                 if (!ee1 || !ee2)
846                 {
847                     cmp = 0;
848                     break;
849                 }
850                 ue = Equal(TOKequal, loc, Type.tint32, ee1, ee2);
851                 if (ue.exp().op == TOKcantexp)
852                     return ue;
853                 cmp = cast(int)ue.exp().toInteger();
854                 if (cmp == 0)
855                     break;
856             }
857         }
858     }
859     else if (e1.isConst() != 1 || e2.isConst() != 1)
860     {
861         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
862         return ue;
863     }
864     else if (e1.type.isreal())
865     {
866         r1 = e1.toReal();
867         r2 = e2.toReal();
868         goto L1;
869     }
870     else if (e1.type.isimaginary())
871     {
872         r1 = e1.toImaginary();
873         r2 = e2.toImaginary();
874     L1:
875         if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
876         {
877             cmp = 0;
878         }
879         else
880         {
881             cmp = (r1 == r2);
882         }
883     }
884     else if (e1.type.iscomplex())
885     {
886         cmp = e1.toComplex() == e2.toComplex();
887     }
888     else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer)
889     {
890         cmp = (e1.toInteger() == e2.toInteger());
891     }
892     else
893     {
894         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
895         return ue;
896     }
897     if (op == TOKnotequal)
898         cmp ^= 1;
899     emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
900     return ue;
901 }
902 
903 extern (C++) UnionExp Identity(TOK op, Loc loc, Type type, Expression e1, Expression e2)
904 {
905     UnionExp ue;
906     int cmp;
907     if (e1.op == TOKnull)
908     {
909         cmp = (e2.op == TOKnull);
910     }
911     else if (e2.op == TOKnull)
912     {
913         cmp = 0;
914     }
915     else if (e1.op == TOKsymoff && e2.op == TOKsymoff)
916     {
917         SymOffExp es1 = cast(SymOffExp)e1;
918         SymOffExp es2 = cast(SymOffExp)e2;
919         cmp = (es1.var == es2.var && es1.offset == es2.offset);
920     }
921     else
922     {
923         if (e1.type.isreal())
924         {
925             cmp = RealEquals(e1.toReal(), e2.toReal());
926         }
927         else if (e1.type.isimaginary())
928         {
929             cmp = RealEquals(e1.toImaginary(), e2.toImaginary());
930         }
931         else if (e1.type.iscomplex())
932         {
933             complex_t v1 = e1.toComplex();
934             complex_t v2 = e2.toComplex();
935             cmp = RealEquals(creall(v1), creall(v2)) && RealEquals(cimagl(v1), cimagl(v1));
936         }
937         else
938         {
939             ue = Equal((op == TOKidentity) ? TOKequal : TOKnotequal, loc, type, e1, e2);
940             return ue;
941         }
942     }
943     if (op == TOKnotidentity)
944         cmp ^= 1;
945     emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
946     return ue;
947 }
948 
949 extern (C++) UnionExp Cmp(TOK op, Loc loc, Type type, Expression e1, Expression e2)
950 {
951     UnionExp ue;
952     dinteger_t n;
953     real_t r1 = 0;
954     real_t r2 = 0;
955     //printf("Cmp(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
956     if (e1.op == TOKstring && e2.op == TOKstring)
957     {
958         StringExp es1 = cast(StringExp)e1;
959         StringExp es2 = cast(StringExp)e2;
960         size_t sz = es1.sz;
961         assert(sz == es2.sz);
962         size_t len = es1.len;
963         if (es2.len < len)
964             len = es2.len;
965         int rawCmp = memcmp(es1..string, es2..string, sz * len);
966         if (rawCmp == 0)
967             rawCmp = cast(int)(es1.len - es2.len);
968         n = specificCmp(op, rawCmp);
969     }
970     else if (e1.isConst() != 1 || e2.isConst() != 1)
971     {
972         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
973         return ue;
974     }
975     else if (e1.type.isreal())
976     {
977         r1 = e1.toReal();
978         r2 = e2.toReal();
979         goto L1;
980     }
981     else if (e1.type.isimaginary())
982     {
983         r1 = e1.toImaginary();
984         r2 = e2.toImaginary();
985     L1:
986         n = realCmp(op, r1, r2);
987     }
988     else if (e1.type.iscomplex())
989     {
990         assert(0);
991     }
992     else
993     {
994         sinteger_t n1;
995         sinteger_t n2;
996         n1 = e1.toInteger();
997         n2 = e2.toInteger();
998         if (e1.type.isunsigned() || e2.type.isunsigned())
999             n = intUnsignedCmp(op, n1, n2);
1000         else
1001             n = intSignedCmp(op, n1, n2);
1002     }
1003     emplaceExp!(IntegerExp)(&ue, loc, n, type);
1004     return ue;
1005 }
1006 
1007 /* Also returns TOKcantexp if cannot be computed.
1008  *  to: type to cast to
1009  *  type: type to paint the result
1010  */
1011 extern (C++) UnionExp Cast(Loc loc, Type type, Type to, Expression e1)
1012 {
1013     UnionExp ue;
1014     Type tb = to.toBasetype();
1015     Type typeb = type.toBasetype();
1016     //printf("Cast(type = %s, to = %s, e1 = %s)\n", type->toChars(), to->toChars(), e1->toChars());
1017     //printf("\te1->type = %s\n", e1->type->toChars());
1018     if (e1.type.equals(type) && type.equals(to))
1019     {
1020         emplaceExp!(UnionExp)(&ue, e1);
1021         return ue;
1022     }
1023     if (e1.op == TOKvector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
1024     {
1025         Expression ex = (cast(VectorExp)e1).e1;
1026         emplaceExp!(UnionExp)(&ue, ex);
1027         return ue;
1028     }
1029     if (e1.type.implicitConvTo(to) >= MATCHconst || to.implicitConvTo(e1.type) >= MATCHconst)
1030     {
1031         goto L1;
1032     }
1033     // Allow covariant converions of delegates
1034     // (Perhaps implicit conversion from pure to impure should be a MATCHconst,
1035     // then we wouldn't need this extra check.)
1036     if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCHconvert)
1037     {
1038         goto L1;
1039     }
1040     /* Allow casting from one string type to another
1041      */
1042     if (e1.op == TOKstring)
1043     {
1044         if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
1045         {
1046             goto L1;
1047         }
1048     }
1049     if (e1.op == TOKarrayliteral && typeb == tb)
1050     {
1051     L1:
1052         Expression ex = expType(to, e1);
1053         emplaceExp!(UnionExp)(&ue, ex);
1054         return ue;
1055     }
1056     if (e1.isConst() != 1)
1057     {
1058         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1059     }
1060     else if (tb.ty == Tbool)
1061     {
1062         emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() != 0, type);
1063     }
1064     else if (type.isintegral())
1065     {
1066         if (e1.type.isfloating())
1067         {
1068             dinteger_t result;
1069             real_t r = e1.toReal();
1070             switch (typeb.ty)
1071             {
1072             case Tint8:
1073                 result = cast(d_int8)cast(sinteger_t)r;
1074                 break;
1075             case Tchar:
1076             case Tuns8:
1077                 result = cast(d_uns8)cast(dinteger_t)r;
1078                 break;
1079             case Tint16:
1080                 result = cast(d_int16)cast(sinteger_t)r;
1081                 break;
1082             case Twchar:
1083             case Tuns16:
1084                 result = cast(d_uns16)cast(dinteger_t)r;
1085                 break;
1086             case Tint32:
1087                 result = cast(d_int32)r;
1088                 break;
1089             case Tdchar:
1090             case Tuns32:
1091                 result = cast(d_uns32)r;
1092                 break;
1093             case Tint64:
1094                 result = cast(d_int64)r;
1095                 break;
1096             case Tuns64:
1097                 result = cast(d_uns64)r;
1098                 break;
1099             default:
1100                 assert(0);
1101             }
1102             emplaceExp!(IntegerExp)(&ue, loc, result, type);
1103         }
1104         else if (type.isunsigned())
1105             emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type);
1106         else
1107             emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1108     }
1109     else if (tb.isreal())
1110     {
1111         real_t value = e1.toReal();
1112         emplaceExp!(RealExp)(&ue, loc, value, type);
1113     }
1114     else if (tb.isimaginary())
1115     {
1116         real_t value = e1.toImaginary();
1117         emplaceExp!(RealExp)(&ue, loc, value, type);
1118     }
1119     else if (tb.iscomplex())
1120     {
1121         complex_t value = e1.toComplex();
1122         emplaceExp!(ComplexExp)(&ue, loc, value, type);
1123     }
1124     else if (tb.isscalar())
1125     {
1126         emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1127     }
1128     else if (tb.ty == Tvoid)
1129     {
1130         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1131     }
1132     else if (tb.ty == Tstruct && e1.op == TOKint64)
1133     {
1134         // Struct = 0;
1135         StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
1136         assert(sd);
1137         auto elements = new Expressions();
1138         for (size_t i = 0; i < sd.fields.dim; i++)
1139         {
1140             VarDeclaration v = sd.fields[i];
1141             UnionExp zero;
1142             emplaceExp!(IntegerExp)(&zero, 0);
1143             ue = Cast(loc, v.type, v.type, zero.exp());
1144             if (ue.exp().op == TOKcantexp)
1145                 return ue;
1146             elements.push(ue.exp().copy());
1147         }
1148         emplaceExp!(StructLiteralExp)(&ue, loc, sd, elements);
1149         ue.exp().type = type;
1150     }
1151     else
1152     {
1153         if (type != Type.terror)
1154         {
1155             // have to change to Internal Compiler Error
1156             // all invalid casts should be handled already in Expression::castTo().
1157             error(loc, "cannot cast %s to %s", e1.type.toChars(), type.toChars());
1158         }
1159         emplaceExp!(ErrorExp)(&ue);
1160     }
1161     return ue;
1162 }
1163 
1164 extern (C++) UnionExp ArrayLength(Type type, Expression e1)
1165 {
1166     UnionExp ue;
1167     Loc loc = e1.loc;
1168     if (e1.op == TOKstring)
1169     {
1170         StringExp es1 = cast(StringExp)e1;
1171         emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
1172     }
1173     else if (e1.op == TOKarrayliteral)
1174     {
1175         ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
1176         size_t dim = ale.elements ? ale.elements.dim : 0;
1177         emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1178     }
1179     else if (e1.op == TOKassocarrayliteral)
1180     {
1181         AssocArrayLiteralExp ale = cast(AssocArrayLiteralExp)e1;
1182         size_t dim = ale.keys.dim;
1183         emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1184     }
1185     else if (e1.type.toBasetype().ty == Tsarray)
1186     {
1187         Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim;
1188         emplaceExp!(UnionExp)(&ue, e);
1189     }
1190     else
1191         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1192     return ue;
1193 }
1194 
1195 /* Also return TOKcantexp if this fails
1196  */
1197 extern (C++) UnionExp Index(Type type, Expression e1, Expression e2)
1198 {
1199     UnionExp ue;
1200     Loc loc = e1.loc;
1201     //printf("Index(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
1202     assert(e1.type);
1203     if (e1.op == TOKstring && e2.op == TOKint64)
1204     {
1205         StringExp es1 = cast(StringExp)e1;
1206         uinteger_t i = e2.toInteger();
1207         if (i >= es1.len)
1208         {
1209             e1.error("string index %llu is out of bounds [0 .. %llu]", i, cast(ulong)es1.len);
1210             emplaceExp!(ErrorExp)(&ue);
1211         }
1212         else
1213         {
1214             emplaceExp!(IntegerExp)(&ue, loc, es1.charAt(i), type);
1215         }
1216     }
1217     else if (e1.type.toBasetype().ty == Tsarray && e2.op == TOKint64)
1218     {
1219         TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
1220         uinteger_t length = tsa.dim.toInteger();
1221         uinteger_t i = e2.toInteger();
1222         if (i >= length)
1223         {
1224             e1.error("array index %llu is out of bounds %s[0 .. %llu]", i, e1.toChars(), length);
1225             emplaceExp!(ErrorExp)(&ue);
1226         }
1227         else if (e1.op == TOKarrayliteral)
1228         {
1229             ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
1230             auto e = ale.getElement(cast(size_t)i);
1231             e.type = type;
1232             e.loc = loc;
1233             if (hasSideEffect(e))
1234                 emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1235             else
1236                 emplaceExp!(UnionExp)(&ue, e);
1237         }
1238         else
1239             emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1240     }
1241     else if (e1.type.toBasetype().ty == Tarray && e2.op == TOKint64)
1242     {
1243         uinteger_t i = e2.toInteger();
1244         if (e1.op == TOKarrayliteral)
1245         {
1246             ArrayLiteralExp ale = cast(ArrayLiteralExp)e1;
1247             if (i >= ale.elements.dim)
1248             {
1249                 e1.error("array index %llu is out of bounds %s[0 .. %u]", i, e1.toChars(), ale.elements.dim);
1250                 emplaceExp!(ErrorExp)(&ue);
1251             }
1252             else
1253             {
1254                 auto e = ale.getElement(cast(size_t)i);
1255                 e.type = type;
1256                 e.loc = loc;
1257                 if (hasSideEffect(e))
1258                     emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1259                 else
1260                     emplaceExp!(UnionExp)(&ue, e);
1261             }
1262         }
1263         else
1264             emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1265     }
1266     else if (e1.op == TOKassocarrayliteral)
1267     {
1268         AssocArrayLiteralExp ae = cast(AssocArrayLiteralExp)e1;
1269         /* Search the keys backwards, in case there are duplicate keys
1270          */
1271         for (size_t i = ae.keys.dim; i;)
1272         {
1273             i--;
1274             Expression ekey = (*ae.keys)[i];
1275             ue = Equal(TOKequal, loc, Type.tbool, ekey, e2);
1276             if (CTFEExp.isCantExp(ue.exp()))
1277                 return ue;
1278             if (ue.exp().isBool(true))
1279             {
1280                 Expression e = (*ae.values)[i];
1281                 e.type = type;
1282                 e.loc = loc;
1283                 if (hasSideEffect(e))
1284                     emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1285                 else
1286                     emplaceExp!(UnionExp)(&ue, e);
1287                 return ue;
1288             }
1289         }
1290         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1291     }
1292     else
1293         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1294     return ue;
1295 }
1296 
1297 /* Also return TOKcantexp if this fails
1298  */
1299 extern (C++) UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
1300 {
1301     UnionExp ue;
1302     Loc loc = e1.loc;
1303     static if (LOG)
1304     {
1305         printf("Slice()\n");
1306         if (lwr)
1307         {
1308             printf("\te1 = %s\n", e1.toChars());
1309             printf("\tlwr = %s\n", lwr.toChars());
1310             printf("\tupr = %s\n", upr.toChars());
1311         }
1312     }
1313     if (e1.op == TOKstring && lwr.op == TOKint64 && upr.op == TOKint64)
1314     {
1315         StringExp es1 = cast(StringExp)e1;
1316         uinteger_t ilwr = lwr.toInteger();
1317         uinteger_t iupr = upr.toInteger();
1318         if (iupr > es1.len || ilwr > iupr)
1319         {
1320             e1.error("string slice [%llu .. %llu] is out of bounds", ilwr, iupr);
1321             emplaceExp!(ErrorExp)(&ue);
1322         }
1323         else
1324         {
1325             size_t len = cast(size_t)(iupr - ilwr);
1326             ubyte sz = es1.sz;
1327             void* s = mem.xmalloc(len * sz);
1328             memcpy(cast(char*)s, es1..string + ilwr * sz, len * sz);
1329             emplaceExp!(StringExp)(&ue, loc, s, len, es1.postfix);
1330             StringExp es = cast(StringExp)ue.exp();
1331             es.sz = sz;
1332             es.committed = es1.committed;
1333             es.type = type;
1334         }
1335     }
1336     else if (e1.op == TOKarrayliteral && lwr.op == TOKint64 && upr.op == TOKint64 && !hasSideEffect(e1))
1337     {
1338         ArrayLiteralExp es1 = cast(ArrayLiteralExp)e1;
1339         uinteger_t ilwr = lwr.toInteger();
1340         uinteger_t iupr = upr.toInteger();
1341         if (iupr > es1.elements.dim || ilwr > iupr)
1342         {
1343             e1.error("array slice [%llu .. %llu] is out of bounds", ilwr, iupr);
1344             emplaceExp!(ErrorExp)(&ue);
1345         }
1346         else
1347         {
1348             auto elements = new Expressions();
1349             elements.setDim(cast(size_t)(iupr - ilwr));
1350             memcpy(elements.tdata(), es1.elements.tdata() + ilwr, cast(size_t)(iupr - ilwr) * ((*es1.elements)[0]).sizeof);
1351             emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elements);
1352             ue.exp().type = type;
1353         }
1354     }
1355     else
1356         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1357     assert(ue.exp().type);
1358     return ue;
1359 }
1360 
1361 /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
1362  * existingAE[firstIndex..firstIndex+newval.length] = newval.
1363  */
1364 extern (C++) void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex)
1365 {
1366     const len = newval.len;
1367     Type elemType = existingAE.type.nextOf();
1368     foreach (j; 0 .. len)
1369     {
1370         const val = newval.getCodeUnit(j);
1371         (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType);
1372     }
1373 }
1374 
1375 /* Set a slice of string 'existingSE' from a char array literal 'newae'.
1376  *   existingSE[firstIndex..firstIndex+newae.length] = newae.
1377  */
1378 extern (C++) void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex)
1379 {
1380     assert(existingSE.ownedByCtfe != OWNEDcode);
1381     foreach (j; 0 .. newae.elements.dim)
1382     {
1383         existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae.getElement(j).toInteger());
1384     }
1385 }
1386 
1387 /* Set a slice of string 'existingSE' from a string 'newstr'.
1388  *   existingSE[firstIndex..firstIndex+newstr.length] = newstr.
1389  */
1390 extern (C++) void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex)
1391 {
1392     assert(existingSE.ownedByCtfe != OWNEDcode);
1393     size_t sz = existingSE.sz;
1394     assert(sz == newstr.sz);
1395     memcpy(existingSE..string + firstIndex * sz, newstr..string, sz * newstr.len);
1396 }
1397 
1398 /* Compare a string slice with another string slice.
1399  * Conceptually equivalent to memcmp( se1[lo1..lo1+len],  se2[lo2..lo2+len])
1400  */
1401 extern (C++) int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len)
1402 {
1403     size_t sz = se1.sz;
1404     assert(sz == se2.sz);
1405     return memcmp(se1..string + sz * lo1, se2..string + sz * lo2, sz * len);
1406 }
1407 
1408 /* Compare a string slice with an array literal slice
1409  * Conceptually equivalent to memcmp( se1[lo1..lo1+len],  ae2[lo2..lo2+len])
1410  */
1411 extern (C++) int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len)
1412 {
1413     foreach (j; 0 .. len)
1414     {
1415         const val2 = cast(dchar)ae2.getElement(j + lo2).toInteger();
1416         const val1 = se1.getCodeUnit(j + lo1);
1417         const int c = val1 - val2;
1418         if (c)
1419             return c;
1420     }
1421     return 0;
1422 }
1423 
1424 /* Also return TOKcantexp if this fails
1425  */
1426 extern (C++) UnionExp Cat(Type type, Expression e1, Expression e2)
1427 {
1428     UnionExp ue;
1429     Expression e = CTFEExp.cantexp;
1430     Loc loc = e1.loc;
1431     Type t;
1432     Type t1 = e1.type.toBasetype();
1433     Type t2 = e2.type.toBasetype();
1434     //printf("Cat(e1 = %s, e2 = %s)\n", e1->toChars(), e2->toChars());
1435     //printf("\tt1 = %s, t2 = %s, type = %s\n", t1->toChars(), t2->toChars(), type->toChars());
1436     if (e1.op == TOKnull && (e2.op == TOKint64 || e2.op == TOKstructliteral))
1437     {
1438         e = e2;
1439         t = t1;
1440         goto L2;
1441     }
1442     else if ((e1.op == TOKint64 || e1.op == TOKstructliteral) && e2.op == TOKnull)
1443     {
1444         e = e1;
1445         t = t2;
1446     L2:
1447         Type tn = e.type.toBasetype();
1448         if (tn.ty == Tchar || tn.ty == Twchar || tn.ty == Tdchar)
1449         {
1450             // Create a StringExp
1451             if (t.nextOf())
1452                 t = t.nextOf().toBasetype();
1453             ubyte sz = cast(ubyte)t.size();
1454             dinteger_t v = e.toInteger();
1455             size_t len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v);
1456             void* s = mem.xmalloc(len * sz);
1457             if (t.ty == tn.ty)
1458                 Port.valcpy(s, v, sz);
1459             else
1460                 utf_encode(sz, s, cast(dchar)v);
1461             emplaceExp!(StringExp)(&ue, loc, s, len);
1462             StringExp es = cast(StringExp)ue.exp();
1463             es.sz = sz;
1464             es.committed = 1;
1465         }
1466         else
1467         {
1468             // Create an ArrayLiteralExp
1469             auto elements = new Expressions();
1470             elements.push(e);
1471             emplaceExp!(ArrayLiteralExp)(&ue, e.loc, elements);
1472         }
1473         ue.exp().type = type;
1474         assert(ue.exp().type);
1475         return ue;
1476     }
1477     else if (e1.op == TOKnull && e2.op == TOKnull)
1478     {
1479         if (type == e1.type)
1480         {
1481             // Handle null ~= null
1482             if (t1.ty == Tarray && t2 == t1.nextOf())
1483             {
1484                 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, e2);
1485                 ue.exp().type = type;
1486                 assert(ue.exp().type);
1487                 return ue;
1488             }
1489             else
1490             {
1491                 emplaceExp!(UnionExp)(&ue, e1);
1492                 assert(ue.exp().type);
1493                 return ue;
1494             }
1495         }
1496         if (type == e2.type)
1497         {
1498             emplaceExp!(UnionExp)(&ue, e2);
1499             assert(ue.exp().type);
1500             return ue;
1501         }
1502         emplaceExp!(NullExp)(&ue, e1.loc, type);
1503         assert(ue.exp().type);
1504         return ue;
1505     }
1506     else if (e1.op == TOKstring && e2.op == TOKstring)
1507     {
1508         // Concatenate the strings
1509         StringExp es1 = cast(StringExp)e1;
1510         StringExp es2 = cast(StringExp)e2;
1511         size_t len = es1.len + es2.len;
1512         ubyte sz = es1.sz;
1513         if (sz != es2.sz)
1514         {
1515             /* Can happen with:
1516              *   auto s = "foo"d ~ "bar"c;
1517              */
1518             assert(global.errors);
1519             emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1520             assert(ue.exp().type);
1521             return ue;
1522         }
1523         void* s = mem.xmalloc(len * sz);
1524         memcpy(cast(char*)s, es1..string, es1.len * sz);
1525         memcpy(cast(char*)s + es1.len * sz, es2..string, es2.len * sz);
1526         emplaceExp!(StringExp)(&ue, loc, s, len);
1527         StringExp es = cast(StringExp)ue.exp();
1528         es.sz = sz;
1529         es.committed = es1.committed | es2.committed;
1530         es.type = type;
1531         assert(ue.exp().type);
1532         return ue;
1533     }
1534     else if (e2.op == TOKstring && e1.op == TOKarrayliteral && t1.nextOf().isintegral())
1535     {
1536         // [chars] ~ string --> [chars]
1537         StringExp es = cast(StringExp)e2;
1538         ArrayLiteralExp ea = cast(ArrayLiteralExp)e1;
1539         size_t len = es.len + ea.elements.dim;
1540         auto elems = new Expressions();
1541         elems.setDim(len);
1542         for (size_t i = 0; i < ea.elements.dim; ++i)
1543         {
1544             (*elems)[i] = ea.getElement(i);
1545         }
1546         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elems);
1547         ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
1548         dest.type = type;
1549         sliceAssignArrayLiteralFromString(dest, es, ea.elements.dim);
1550         assert(ue.exp().type);
1551         return ue;
1552     }
1553     else if (e1.op == TOKstring && e2.op == TOKarrayliteral && t2.nextOf().isintegral())
1554     {
1555         // string ~ [chars] --> [chars]
1556         StringExp es = cast(StringExp)e1;
1557         ArrayLiteralExp ea = cast(ArrayLiteralExp)e2;
1558         size_t len = es.len + ea.elements.dim;
1559         auto elems = new Expressions();
1560         elems.setDim(len);
1561         for (size_t i = 0; i < ea.elements.dim; ++i)
1562         {
1563             (*elems)[es.len + i] = ea.getElement(i);
1564         }
1565         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elems);
1566         ArrayLiteralExp dest = cast(ArrayLiteralExp)ue.exp();
1567         dest.type = type;
1568         sliceAssignArrayLiteralFromString(dest, es, 0);
1569         assert(ue.exp().type);
1570         return ue;
1571     }
1572     else if (e1.op == TOKstring && e2.op == TOKint64)
1573     {
1574         // string ~ char --> string
1575         StringExp es1 = cast(StringExp)e1;
1576         StringExp es;
1577         ubyte sz = es1.sz;
1578         dinteger_t v = e2.toInteger();
1579         // Is it a concatentation of homogenous types?
1580         // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
1581         bool homoConcat = (sz == t2.size());
1582         size_t len = es1.len;
1583         len += homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v);
1584         void* s = mem.xmalloc(len * sz);
1585         memcpy(s, es1..string, es1.len * sz);
1586         if (homoConcat)
1587             Port.valcpy(cast(char*)s + (sz * es1.len), v, sz);
1588         else
1589             utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
1590         emplaceExp!(StringExp)(&ue, loc, s, len);
1591         es = cast(StringExp)ue.exp();
1592         es.sz = sz;
1593         es.committed = es1.committed;
1594         es.type = type;
1595         assert(ue.exp().type);
1596         return ue;
1597     }
1598     else if (e1.op == TOKint64 && e2.op == TOKstring)
1599     {
1600         // Concatenate the strings
1601         StringExp es2 = cast(StringExp)e2;
1602         size_t len = 1 + es2.len;
1603         ubyte sz = es2.sz;
1604         dinteger_t v = e1.toInteger();
1605         void* s = mem.xmalloc(len * sz);
1606         memcpy(cast(char*)s, &v, sz);
1607         memcpy(cast(char*)s + sz, es2..string, es2.len * sz);
1608         emplaceExp!(StringExp)(&ue, loc, s, len);
1609         StringExp es = cast(StringExp)ue.exp();
1610         es.sz = sz;
1611         es.committed = es2.committed;
1612         es.type = type;
1613         assert(ue.exp().type);
1614         return ue;
1615     }
1616     else if (e1.op == TOKarrayliteral && e2.op == TOKarrayliteral && t1.nextOf().equals(t2.nextOf()))
1617     {
1618         // Concatenate the arrays
1619         auto elems = ArrayLiteralExp.copyElements(e1, e2);
1620 
1621         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elems);
1622 
1623         e = ue.exp();
1624         if (type.toBasetype().ty == Tsarray)
1625         {
1626             e.type = t1.nextOf().sarrayOf(elems.dim);
1627         }
1628         else
1629             e.type = type;
1630         assert(ue.exp().type);
1631         return ue;
1632     }
1633     else if (e1.op == TOKarrayliteral && e2.op == TOKnull && t1.nextOf().equals(t2.nextOf()))
1634     {
1635         e = e1;
1636         goto L3;
1637     }
1638     else if (e1.op == TOKnull && e2.op == TOKarrayliteral && t1.nextOf().equals(t2.nextOf()))
1639     {
1640         e = e2;
1641     L3:
1642         // Concatenate the array with null
1643         auto elems = ArrayLiteralExp.copyElements(e);
1644 
1645         emplaceExp!(ArrayLiteralExp)(&ue, e.loc, elems);
1646 
1647         e = ue.exp();
1648         if (type.toBasetype().ty == Tsarray)
1649         {
1650             e.type = t1.nextOf().sarrayOf(elems.dim);
1651         }
1652         else
1653             e.type = type;
1654         assert(ue.exp().type);
1655         return ue;
1656     }
1657     else if ((e1.op == TOKarrayliteral || e1.op == TOKnull) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
1658     {
1659         auto elems = (e1.op == TOKarrayliteral)
1660                 ? ArrayLiteralExp.copyElements(e1) : new Expressions();
1661         elems.push(e2);
1662 
1663         emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, elems);
1664 
1665         e = ue.exp();
1666         if (type.toBasetype().ty == Tsarray)
1667         {
1668             e.type = e2.type.sarrayOf(elems.dim);
1669         }
1670         else
1671             e.type = type;
1672         assert(ue.exp().type);
1673         return ue;
1674     }
1675     else if (e2.op == TOKarrayliteral && e2.type.toBasetype().nextOf().equals(e1.type))
1676     {
1677         auto elems = ArrayLiteralExp.copyElements(e1, e2);
1678 
1679         emplaceExp!(ArrayLiteralExp)(&ue, e2.loc, elems);
1680 
1681         e = ue.exp();
1682         if (type.toBasetype().ty == Tsarray)
1683         {
1684             e.type = e1.type.sarrayOf(elems.dim);
1685         }
1686         else
1687             e.type = type;
1688         assert(ue.exp().type);
1689         return ue;
1690     }
1691     else if (e1.op == TOKnull && e2.op == TOKstring)
1692     {
1693         t = e1.type;
1694         e = e2;
1695         goto L1;
1696     }
1697     else if (e1.op == TOKstring && e2.op == TOKnull)
1698     {
1699         e = e1;
1700         t = e2.type;
1701     L1:
1702         Type tb = t.toBasetype();
1703         if (tb.ty == Tarray && tb.nextOf().equivalent(e.type))
1704         {
1705             auto expressions = new Expressions();
1706             expressions.push(e);
1707             emplaceExp!(ArrayLiteralExp)(&ue, loc, expressions);
1708             e = ue.exp();
1709             e.type = t;
1710         }
1711         else
1712         {
1713             emplaceExp!(UnionExp)(&ue, e);
1714             e = ue.exp();
1715         }
1716         if (!e.type.equals(type))
1717         {
1718             StringExp se = cast(StringExp)e.copy();
1719             e = se.castTo(null, type);
1720             emplaceExp!(UnionExp)(&ue, e);
1721             e = ue.exp();
1722         }
1723     }
1724     else
1725         emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1726     assert(ue.exp().type);
1727     return ue;
1728 }
1729 
1730 extern (C++) UnionExp Ptr(Type type, Expression e1)
1731 {
1732     //printf("Ptr(e1 = %s)\n", e1->toChars());
1733     UnionExp ue;
1734     if (e1.op == TOKadd)
1735     {
1736         AddExp ae = cast(AddExp)e1;
1737         if (ae.e1.op == TOKaddress && ae.e2.op == TOKint64)
1738         {
1739             AddrExp ade = cast(AddrExp)ae.e1;
1740             if (ade.e1.op == TOKstructliteral)
1741             {
1742                 StructLiteralExp se = cast(StructLiteralExp)ade.e1;
1743                 uint offset = cast(uint)ae.e2.toInteger();
1744                 Expression e = se.getField(type, offset);
1745                 if (e)
1746                 {
1747                     emplaceExp!(UnionExp)(&ue, e);
1748                     return ue;
1749                 }
1750             }
1751         }
1752     }
1753     emplaceExp!(CTFEExp)(&ue, TOKcantexp);
1754     return ue;
1755 }