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