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