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