d: Merge dmd. druntime e770945277, phobos 6d6e0b9b9
[official-gcc.git] / gcc / d / dmd / constfold.d
blob41fed9cae49678284496c00563b0c757f544f5e6
1 /**
2 * Perform constant folding of arithmetic expressions.
4 * The routines in this module are called from `optimize.d`.
6 * Specification: $(LINK2 https://dlang.org/spec/float.html#fp_const_folding, Floating Point Constant Folding)
8 * Copyright: Copyright (C) 1999-2024 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
16 module dmd.constfold;
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.dcast;
24 import dmd.declaration;
25 import dmd.dstruct;
26 import dmd.errors;
27 import dmd.expression;
28 import dmd.globals;
29 import dmd.location;
30 import dmd.mtype;
31 import dmd.root.complex;
32 import dmd.root.ctfloat;
33 import dmd.root.port;
34 import dmd.root.rmem;
35 import dmd.root.utf;
36 import dmd.sideeffect;
37 import dmd.target;
38 import dmd.tokens;
40 private enum LOG = false;
42 private Expression expType(Type type, Expression e)
44 if (type != e.type)
46 e = e.copy();
47 e.type = type;
49 return e;
52 /**********************************
53 * Initialize a EXP.cantExpression Expression.
54 * Params:
55 * ue = where to write it
57 void cantExp(out UnionExp ue)
59 emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
62 /* =============================== constFold() ============================== */
63 /* The constFold() functions were redundant with the optimize() ones,
64 * and so have been folded in with them.
66 /* ========================================================================== */
67 UnionExp Neg(Type type, Expression e1)
69 UnionExp ue = void;
70 Loc loc = e1.loc;
71 if (e1.type.isreal())
73 emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type);
75 else if (e1.type.isimaginary())
77 emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type);
79 else if (e1.type.iscomplex())
81 emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type);
83 else
85 emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type);
87 return ue;
90 UnionExp Com(Type type, Expression e1)
92 UnionExp ue = void;
93 Loc loc = e1.loc;
94 emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type);
95 return ue;
98 UnionExp Not(Type type, Expression e1)
100 UnionExp ue = void;
101 Loc loc = e1.loc;
102 // BUG: Should be replaced with e1.toBool().get(), but this is apparently
103 // executed for some expressions that cannot be const-folded
104 // To be fixed in another PR
105 emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(false) ? 1 : 0, type);
106 return ue;
109 UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
111 UnionExp ue = void;
112 static if (LOG)
114 printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
116 if (type.isreal())
118 emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type);
120 else if (type.isimaginary())
122 emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type);
124 else if (type.iscomplex())
126 // This rigamarole is necessary so that -0.0 doesn't get
127 // converted to +0.0 by doing an extraneous add with +0.0
128 auto c1 = complex_t(CTFloat.zero);
129 real_t r1 = CTFloat.zero;
130 real_t i1 = CTFloat.zero;
131 auto c2 = complex_t(CTFloat.zero);
132 real_t r2 = CTFloat.zero;
133 real_t i2 = CTFloat.zero;
134 auto v = complex_t(CTFloat.zero);
135 int x;
136 if (e1.type.isreal())
138 r1 = e1.toReal();
139 x = 0;
141 else if (e1.type.isimaginary())
143 i1 = e1.toImaginary();
144 x = 3;
146 else
148 c1 = e1.toComplex();
149 x = 6;
151 if (e2.type.isreal())
153 r2 = e2.toReal();
155 else if (e2.type.isimaginary())
157 i2 = e2.toImaginary();
158 x += 1;
160 else
162 c2 = e2.toComplex();
163 x += 2;
165 switch (x)
167 case 0 + 0:
168 v = complex_t(r1 + r2);
169 break;
170 case 0 + 1:
171 v = complex_t(r1, i2);
172 break;
173 case 0 + 2:
174 v = complex_t(r1 + creall(c2), cimagl(c2));
175 break;
176 case 3 + 0:
177 v = complex_t(r2, i1);
178 break;
179 case 3 + 1:
180 v = complex_t(CTFloat.zero, i1 + i2);
181 break;
182 case 3 + 2:
183 v = complex_t(creall(c2), i1 + cimagl(c2));
184 break;
185 case 6 + 0:
186 v = complex_t(creall(c1) + r2, cimagl(c2));
187 break;
188 case 6 + 1:
189 v = complex_t(creall(c1), cimagl(c1) + i2);
190 break;
191 case 6 + 2:
192 v = c1 + c2;
193 break;
194 default:
195 assert(0);
197 emplaceExp!(ComplexExp)(&ue, loc, v, type);
199 else if (SymOffExp soe = e1.isSymOffExp())
201 emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
202 ue.exp().type = type;
204 else if (SymOffExp soe = e2.isSymOffExp())
206 emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
207 ue.exp().type = type;
209 else
210 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type);
211 return ue;
214 UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
216 // Compute e1-e2 as e1+(-e2)
217 UnionExp neg = Neg(e2.type, e2);
218 UnionExp ue = Add(loc, type, e1, neg.exp());
219 return ue;
222 UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
224 UnionExp ue = void;
225 if (type.isfloating())
227 auto c = complex_t(CTFloat.zero);
228 real_t r = CTFloat.zero;
229 if (e1.type.isreal())
231 r = e1.toReal();
232 c = e2.toComplex();
233 c = complex_t(r * creall(c), r * cimagl(c));
235 else if (e1.type.isimaginary())
237 r = e1.toImaginary();
238 c = e2.toComplex();
239 c = complex_t(-r * cimagl(c), r * creall(c));
241 else if (e2.type.isreal())
243 r = e2.toReal();
244 c = e1.toComplex();
245 c = complex_t(r * creall(c), r * cimagl(c));
247 else if (e2.type.isimaginary())
249 r = e2.toImaginary();
250 c = e1.toComplex();
251 c = complex_t(-r * cimagl(c), r * creall(c));
253 else
254 c = e1.toComplex() * e2.toComplex();
255 if (type.isreal())
256 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
257 else if (type.isimaginary())
258 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
259 else if (type.iscomplex())
260 emplaceExp!(ComplexExp)(&ue, loc, c, type);
261 else
262 assert(0);
264 else
266 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type);
268 return ue;
271 UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
273 UnionExp ue = void;
274 if (type.isfloating())
276 auto c = complex_t(CTFloat.zero);
277 if (e2.type.isreal())
279 if (e1.type.isreal())
281 emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type);
282 return ue;
284 const r = e2.toReal();
285 c = e1.toComplex();
286 c = complex_t(creall(c) / r, cimagl(c) / r);
288 else if (e2.type.isimaginary())
290 const r = e2.toImaginary();
291 c = e1.toComplex();
292 c = complex_t(cimagl(c) / r, -creall(c) / r);
294 else
296 c = e1.toComplex() / e2.toComplex();
299 if (type.isreal())
300 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
301 else if (type.isimaginary())
302 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
303 else if (type.iscomplex())
304 emplaceExp!(ComplexExp)(&ue, loc, c, type);
305 else
306 assert(0);
308 else
310 sinteger_t n1;
311 sinteger_t n2;
312 sinteger_t n;
313 n1 = e1.toInteger();
314 n2 = e2.toInteger();
315 if (n2 == 0)
317 error(e2.loc, "divide by 0");
318 emplaceExp!(ErrorExp)(&ue);
319 return ue;
321 if (n2 == -1 && !type.isunsigned())
323 // Check for int.min / -1
324 if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
326 error(e2.loc, "integer overflow: `int.min / -1`");
327 emplaceExp!(ErrorExp)(&ue);
328 return ue;
330 else if (n1 == 0x8000000000000000L) // long.min / -1
332 error(e2.loc, "integer overflow: `long.min / -1L`");
333 emplaceExp!(ErrorExp)(&ue);
334 return ue;
337 if (e1.type.isunsigned() || e2.type.isunsigned())
338 n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2);
339 else
340 n = n1 / n2;
341 emplaceExp!(IntegerExp)(&ue, loc, n, type);
343 return ue;
346 UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
348 UnionExp ue = void;
349 if (type.isfloating())
351 auto c = complex_t(CTFloat.zero);
352 if (e2.type.isreal())
354 const r2 = e2.toReal();
355 c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
357 else if (e2.type.isimaginary())
359 const i2 = e2.toImaginary();
360 c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
362 else
363 assert(0);
364 if (type.isreal())
365 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
366 else if (type.isimaginary())
367 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
368 else if (type.iscomplex())
369 emplaceExp!(ComplexExp)(&ue, loc, c, type);
370 else
371 assert(0);
373 else
375 sinteger_t n1;
376 sinteger_t n2;
377 sinteger_t n;
378 n1 = e1.toInteger();
379 n2 = e2.toInteger();
380 if (n2 == 0)
382 error(e2.loc, "divide by 0");
383 emplaceExp!(ErrorExp)(&ue);
384 return ue;
386 if (n2 == -1 && !type.isunsigned())
388 // Check for int.min % -1
389 if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
391 error(e2.loc, "integer overflow: `int.min %% -1`");
392 emplaceExp!(ErrorExp)(&ue);
393 return ue;
395 else if (n1 == 0x8000000000000000L) // long.min % -1
397 error(e2.loc, "integer overflow: `long.min %% -1L`");
398 emplaceExp!(ErrorExp)(&ue);
399 return ue;
402 if (e1.type.isunsigned() || e2.type.isunsigned())
403 n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2);
404 else
405 n = n1 % n2;
406 emplaceExp!(IntegerExp)(&ue, loc, n, type);
408 return ue;
411 UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
413 //printf("Pow()\n");
414 UnionExp ue;
415 // Handle integer power operations.
416 if (e2.type.isintegral())
418 dinteger_t n = e2.toInteger();
419 bool neg;
420 if (!e2.type.isunsigned() && cast(sinteger_t)n < 0)
422 if (e1.type.isintegral())
424 cantExp(ue);
425 return ue;
427 // Don't worry about overflow, from now on n is unsigned.
428 neg = true;
429 n = -n;
431 else
432 neg = false;
433 UnionExp ur, uv;
434 if (e1.type.iscomplex())
436 emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
437 emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type);
439 else if (e1.type.isfloating())
441 emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
442 emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type);
444 else
446 emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type);
447 emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type);
449 Expression r = ur.exp();
450 Expression v = uv.exp();
451 while (n != 0)
453 if (n & 1)
455 // v = v * r;
456 uv = Mul(loc, v.type, v, r);
458 n >>= 1;
459 // r = r * r
460 ur = Mul(loc, r.type, r, r);
462 if (neg)
464 // ue = 1.0 / v
465 UnionExp one;
466 emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type);
467 uv = Div(loc, v.type, one.exp(), v);
469 if (type.iscomplex())
470 emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type);
471 else if (type.isintegral())
472 emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type);
473 else
474 emplaceExp!(RealExp)(&ue, loc, v.toReal(), type);
476 else if (e2.type.isfloating())
478 // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
479 if (e1.toReal() < CTFloat.zero)
481 emplaceExp!(RealExp)(&ue, loc, target.RealProperties.nan, type);
483 else
484 cantExp(ue);
486 else
487 cantExp(ue);
488 return ue;
491 UnionExp Shl(const ref Loc loc, Type type, Expression e1, Expression e2)
493 UnionExp ue = void;
494 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type);
495 return ue;
498 UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
500 UnionExp ue = void;
501 dinteger_t value = e1.toInteger();
502 dinteger_t dcount = e2.toInteger();
503 assert(dcount <= 0xFFFFFFFF);
504 uint count = cast(uint)dcount;
505 switch (e1.type.toBasetype().ty)
507 case Tint8:
508 value = cast(byte)value >> count;
509 break;
510 case Tuns8:
511 case Tchar:
512 value = cast(ubyte)value >> count;
513 break;
514 case Tint16:
515 value = cast(short)value >> count;
516 break;
517 case Tuns16:
518 case Twchar:
519 value = cast(ushort)value >> count;
520 break;
521 case Tint32:
522 value = cast(int)value >> count;
523 break;
524 case Tuns32:
525 case Tdchar:
526 value = cast(uint)value >> count;
527 break;
528 case Tint64:
529 value = cast(long)value >> count;
530 break;
531 case Tuns64:
532 value = cast(ulong)value >> count;
533 break;
534 case Terror:
535 emplaceExp!(ErrorExp)(&ue);
536 return ue;
537 default:
538 assert(0);
540 emplaceExp!(IntegerExp)(&ue, loc, value, type);
541 return ue;
544 UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2)
546 UnionExp ue = void;
547 dinteger_t value = e1.toInteger();
548 dinteger_t dcount = e2.toInteger();
549 assert(dcount <= 0xFFFFFFFF);
550 uint count = cast(uint)dcount;
551 switch (e1.type.toBasetype().ty)
553 case Tint8:
554 case Tuns8:
555 case Tchar:
556 // Possible only with >>>=. >>> always gets promoted to int.
557 value = (value & 0xFF) >>> count;
558 break;
559 case Tint16:
560 case Tuns16:
561 case Twchar:
562 // Possible only with >>>=. >>> always gets promoted to int.
563 value = (value & 0xFFFF) >>> count;
564 break;
565 case Tint32:
566 case Tuns32:
567 case Tdchar:
568 value = (value & 0xFFFFFFFF) >>> count;
569 break;
570 case Tint64:
571 case Tuns64:
572 value = value >>> count;
573 break;
574 case Terror:
575 emplaceExp!(ErrorExp)(&ue);
576 return ue;
577 default:
578 assert(0);
580 emplaceExp!(IntegerExp)(&ue, loc, value, type);
581 return ue;
584 UnionExp And(const ref Loc loc, Type type, Expression e1, Expression e2)
586 UnionExp ue = void;
587 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type);
588 return ue;
591 UnionExp Or(const ref Loc loc, Type type, Expression e1, Expression e2)
593 UnionExp ue = void;
594 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type);
595 return ue;
598 UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
600 //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
601 UnionExp ue = void;
602 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type);
603 return ue;
606 /* Also returns EXP.cantExpression if cannot be computed.
608 UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
610 UnionExp ue = void;
611 int cmp = 0;
612 real_t r1 = CTFloat.zero;
613 real_t r2 = CTFloat.zero;
614 //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
615 assert(op == EXP.equal || op == EXP.notEqual);
616 if (e1.op == EXP.null_)
618 if (e2.op == EXP.null_)
619 cmp = 1;
620 else if (StringExp es2 = e2.isStringExp())
622 cmp = (0 == es2.len);
624 else if (ArrayLiteralExp es2 = e2.isArrayLiteralExp())
626 cmp = !es2.elements || (0 == es2.elements.length);
628 else
630 cantExp(ue);
631 return ue;
634 else if (e2.op == EXP.null_)
636 if (StringExp es1 = e1.isStringExp())
638 cmp = (0 == es1.len);
640 else if (ArrayLiteralExp es1 = e1.isArrayLiteralExp())
642 cmp = !es1.elements || (0 == es1.elements.length);
644 else
646 cantExp(ue);
647 return ue;
650 else if (e1.op == EXP.string_ && e2.op == EXP.string_)
652 StringExp es1 = e1.isStringExp();
653 StringExp es2 = e2.isStringExp();
654 if (es1.sz != es2.sz)
656 assert(global.errors);
657 cantExp(ue);
658 return ue;
660 const data1 = es1.peekData();
661 const data2 = es2.peekData();
662 if (es1.len == es2.len && memcmp(data1.ptr, data2.ptr, es1.sz * es1.len) == 0)
663 cmp = 1;
664 else
665 cmp = 0;
667 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
669 ArrayLiteralExp es1 = e1.isArrayLiteralExp();
670 ArrayLiteralExp es2 = e2.isArrayLiteralExp();
671 if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
672 cmp = 1; // both arrays are empty
673 else if (!es1.elements || !es2.elements)
674 cmp = 0;
675 else if (es1.elements.length != es2.elements.length)
676 cmp = 0;
677 else
679 for (size_t i = 0; i < es1.elements.length; i++)
681 auto ee1 = es1[i];
682 auto ee2 = es2[i];
683 ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
684 if (CTFEExp.isCantExp(ue.exp()))
685 return ue;
686 cmp = cast(int)ue.exp().toInteger();
687 if (cmp == 0)
688 break;
692 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.string_)
694 // Swap operands and use common code
695 Expression etmp = e1;
696 e1 = e2;
697 e2 = etmp;
698 goto Lsa;
700 else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
702 Lsa:
703 StringExp es1 = e1.isStringExp();
704 ArrayLiteralExp es2 = e2.isArrayLiteralExp();
705 size_t dim1 = es1.len;
706 size_t dim2 = es2.elements ? es2.elements.length : 0;
707 if (dim1 != dim2)
708 cmp = 0;
709 else
711 cmp = 1; // if dim1 winds up being 0
712 foreach (i; 0 .. dim1)
714 uinteger_t c = es1.getIndex(i);
715 auto ee2 = es2[i];
716 if (ee2.isConst() != 1)
718 cantExp(ue);
719 return ue;
721 cmp = (c == ee2.toInteger());
722 if (cmp == 0)
723 break;
727 else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
729 StructLiteralExp es1 = e1.isStructLiteralExp();
730 StructLiteralExp es2 = e2.isStructLiteralExp();
731 if (es1.sd != es2.sd)
732 cmp = 0;
733 else if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
734 cmp = 1; // both arrays are empty
735 else if (!es1.elements || !es2.elements)
736 cmp = 0;
737 else if (es1.elements.length != es2.elements.length)
738 cmp = 0;
739 else
741 cmp = 1;
742 for (size_t i = 0; i < es1.elements.length; i++)
744 Expression ee1 = (*es1.elements)[i];
745 Expression ee2 = (*es2.elements)[i];
746 if (ee1 == ee2)
747 continue;
748 if (!ee1 || !ee2)
750 cmp = 0;
751 break;
753 ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
754 if (ue.exp().op == EXP.cantExpression)
755 return ue;
756 cmp = cast(int)ue.exp().toInteger();
757 if (cmp == 0)
758 break;
762 else if (e1.isConst() != 1 || e2.isConst() != 1)
764 cantExp(ue);
765 return ue;
767 else if (e1.type.isreal())
769 r1 = e1.toReal();
770 r2 = e2.toReal();
771 goto L1;
773 else if (e1.type.isimaginary())
775 r1 = e1.toImaginary();
776 r2 = e2.toImaginary();
778 if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
780 cmp = 0;
782 else
784 cmp = (r1 == r2);
787 else if (e1.type.iscomplex())
789 cmp = e1.toComplex() == e2.toComplex();
791 else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer)
793 cmp = (e1.toInteger() == e2.toInteger());
795 else
797 cantExp(ue);
798 return ue;
800 if (op == EXP.notEqual)
801 cmp ^= 1;
802 emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
803 return ue;
806 UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
808 UnionExp ue = void;
809 int cmp;
810 if (e1.op == EXP.null_)
812 cmp = (e2.op == EXP.null_);
814 else if (e2.op == EXP.null_)
816 cmp = 0;
818 else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
820 SymOffExp es1 = e1.isSymOffExp();
821 SymOffExp es2 = e2.isSymOffExp();
822 cmp = (es1.var == es2.var && es1.offset == es2.offset);
824 else
826 if (e1.type.isfloating())
827 cmp = e1.isIdentical(e2);
828 else
830 ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2);
831 return ue;
834 if (op == EXP.notIdentity)
835 cmp ^= 1;
836 emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
837 return ue;
840 UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
842 UnionExp ue = void;
843 dinteger_t n;
844 real_t r1 = CTFloat.zero;
845 real_t r2 = CTFloat.zero;
846 //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
847 if (e1.op == EXP.string_ && e2.op == EXP.string_)
849 StringExp es1 = e1.isStringExp();
850 StringExp es2 = e2.isStringExp();
851 size_t sz = es1.sz;
852 assert(sz == es2.sz);
853 size_t len = es1.len;
854 if (es2.len < len)
855 len = es2.len;
856 const data1 = es1.peekData();
857 const data2 = es1.peekData();
858 int rawCmp = memcmp(data1.ptr, data2.ptr, sz * len);
859 if (rawCmp == 0)
860 rawCmp = cast(int)(es1.len - es2.len);
861 n = specificCmp(op, rawCmp);
863 else if (e1.isConst() != 1 || e2.isConst() != 1)
865 cantExp(ue);
866 return ue;
868 else if (e1.type.isreal())
870 r1 = e1.toReal();
871 r2 = e2.toReal();
872 goto L1;
874 else if (e1.type.isimaginary())
876 r1 = e1.toImaginary();
877 r2 = e2.toImaginary();
879 n = realCmp(op, r1, r2);
881 else if (e1.type.iscomplex())
883 assert(0);
885 else
887 sinteger_t n1;
888 sinteger_t n2;
889 n1 = e1.toInteger();
890 n2 = e2.toInteger();
891 if (e1.type.isunsigned() || e2.type.isunsigned())
892 n = intUnsignedCmp(op, n1, n2);
893 else
894 n = intSignedCmp(op, n1, n2);
896 emplaceExp!(IntegerExp)(&ue, loc, n, type);
897 return ue;
900 /* Also returns EXP.cantExpression if cannot be computed.
901 * to: type to cast to
902 * type: type to paint the result
904 UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
906 UnionExp ue = void;
907 Type tb = to.toBasetype();
908 Type typeb = type.toBasetype();
909 //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars());
910 //printf("\te1.type = %s\n", e1.type.toChars());
911 if (e1.type.equals(type) && type.equals(to))
913 emplaceExp!(UnionExp)(&ue, e1);
914 return ue;
916 if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
918 Expression ex = e1.isVectorExp().e1;
919 emplaceExp!(UnionExp)(&ue, ex);
920 return ue;
922 if (e1.type.toBasetype.equals(type) && type.equals(to))
924 emplaceExp!(UnionExp)(&ue, e1);
925 ue.exp().type = type;
926 return ue;
928 if (e1.type.implicitConvTo(to) >= MATCH.constant || to.implicitConvTo(e1.type) >= MATCH.constant)
930 goto L1;
932 // Allow covariant converions of delegates
933 // (Perhaps implicit conversion from pure to impure should be a MATCH.constant,
934 // then we wouldn't need this extra check.)
935 if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCH.convert)
937 goto L1;
939 /* Allow casting from one string type to another
941 if (e1.op == EXP.string_)
943 if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
945 goto L1;
948 if (e1.op == EXP.arrayLiteral && typeb == tb)
951 Expression ex = expType(to, e1);
952 emplaceExp!(UnionExp)(&ue, ex);
953 return ue;
955 if (e1.isConst() != 1)
957 cantExp(ue);
959 else if (tb.ty == Tbool)
961 const opt = e1.toBool();
962 if (opt.isEmpty())
964 cantExp(ue);
965 return ue;
968 emplaceExp!(IntegerExp)(&ue, loc, opt.get(), type);
970 else if (type.isintegral())
972 if (e1.type.isfloating())
974 dinteger_t result;
975 real_t r = e1.toReal();
976 switch (typeb.ty)
978 case Tint8:
979 result = cast(byte)cast(sinteger_t)r;
980 break;
981 case Tchar:
982 case Tuns8:
983 result = cast(ubyte)cast(dinteger_t)r;
984 break;
985 case Tint16:
986 result = cast(short)cast(sinteger_t)r;
987 break;
988 case Twchar:
989 case Tuns16:
990 result = cast(ushort)cast(dinteger_t)r;
991 break;
992 case Tint32:
993 result = cast(int)r;
994 break;
995 case Tdchar:
996 case Tuns32:
997 result = cast(uint)r;
998 break;
999 case Tint64:
1000 result = cast(long)r;
1001 break;
1002 case Tuns64:
1003 result = cast(ulong)r;
1004 break;
1005 default:
1006 assert(0);
1008 emplaceExp!(IntegerExp)(&ue, loc, result, type);
1010 else if (type.isunsigned())
1011 emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type);
1012 else
1013 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1015 else if (tb.isreal())
1017 real_t value = e1.toReal();
1018 emplaceExp!(RealExp)(&ue, loc, value, type);
1020 else if (tb.isimaginary())
1022 real_t value = e1.toImaginary();
1023 emplaceExp!(RealExp)(&ue, loc, value, type);
1025 else if (tb.iscomplex())
1027 complex_t value = e1.toComplex();
1028 emplaceExp!(ComplexExp)(&ue, loc, value, type);
1030 else if (tb.isscalar())
1032 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1034 else if (tb.ty == Tvoid)
1036 cantExp(ue);
1038 else if (tb.ty == Tstruct && e1.op == EXP.int64)
1040 // Struct = 0;
1041 import dmd.typesem : toDsymbol;
1042 StructDeclaration sd = tb.toDsymbol(null).isStructDeclaration();
1043 assert(sd);
1044 auto elements = new Expressions();
1045 for (size_t i = 0; i < sd.fields.length; i++)
1047 VarDeclaration v = sd.fields[i];
1048 UnionExp zero;
1049 emplaceExp!(IntegerExp)(&zero, 0);
1050 ue = Cast(loc, v.type, v.type, zero.exp());
1051 if (ue.exp().op == EXP.cantExpression)
1052 return ue;
1053 elements.push(ue.exp().copy());
1055 emplaceExp!(StructLiteralExp)(&ue, loc, sd, elements);
1056 ue.exp().type = type;
1058 else
1060 if (type != Type.terror)
1062 // have to change to internal compiler error
1063 // all invalid casts should be handled already in Expression::castTo().
1064 error(loc, "cannot cast `%s` to `%s`", e1.type.toChars(), type.toChars());
1066 emplaceExp!(ErrorExp)(&ue);
1068 return ue;
1071 UnionExp ArrayLength(Type type, Expression e1)
1073 UnionExp ue = void;
1074 Loc loc = e1.loc;
1075 if (StringExp es1 = e1.isStringExp())
1077 emplaceExp!(IntegerExp)(&ue, loc, es1.len, type);
1079 else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1081 size_t dim = ale.elements ? ale.elements.length : 0;
1082 emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1084 else if (AssocArrayLiteralExp ale = e1.isAssocArrayLiteralExp)
1086 size_t dim = ale.keys.length;
1087 emplaceExp!(IntegerExp)(&ue, loc, dim, type);
1089 else if (e1.type.toBasetype().ty == Tsarray)
1091 Expression e = (cast(TypeSArray)e1.type.toBasetype()).dim;
1092 emplaceExp!(UnionExp)(&ue, e);
1094 else if (e1.isNullExp())
1096 emplaceExp!(IntegerExp)(&ue, loc, 0, type);
1098 else
1099 cantExp(ue);
1100 return ue;
1103 /* Also return EXP.cantExpression if this fails
1105 UnionExp Index(Type type, Expression e1, Expression e2, bool indexIsInBounds)
1107 UnionExp ue = void;
1108 Loc loc = e1.loc;
1109 //printf("Index(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1110 assert(e1.type);
1111 if (e1.op == EXP.string_ && e2.op == EXP.int64)
1113 StringExp es1 = e1.isStringExp();
1114 uinteger_t i = e2.toInteger();
1115 if (i >= es1.len)
1117 error(e1.loc, "string index %llu is out of bounds `[0 .. %llu]`", i, cast(ulong)es1.len);
1118 emplaceExp!(ErrorExp)(&ue);
1120 else
1122 emplaceExp!(IntegerExp)(&ue, loc, es1.getIndex(cast(size_t) i), type);
1125 else if (e1.type.toBasetype().ty == Tsarray && e2.op == EXP.int64)
1127 TypeSArray tsa = cast(TypeSArray)e1.type.toBasetype();
1128 uinteger_t length = tsa.dim.toInteger();
1129 uinteger_t i = e2.toInteger();
1130 if (i >= length && (e1.op == EXP.arrayLiteral || !indexIsInBounds))
1132 // C code only checks bounds if an ArrayLiteralExp
1133 error(e1.loc, "array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), length);
1134 emplaceExp!(ErrorExp)(&ue);
1136 else if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1138 auto e = ale[cast(size_t)i];
1139 e.type = type;
1140 e.loc = loc;
1141 if (hasSideEffect(e))
1142 cantExp(ue);
1143 else
1144 emplaceExp!(UnionExp)(&ue, e);
1146 else
1147 cantExp(ue);
1149 else if (e1.type.toBasetype().ty == Tarray && e2.op == EXP.int64)
1151 uinteger_t i = e2.toInteger();
1152 if (ArrayLiteralExp ale = e1.isArrayLiteralExp())
1154 if (i >= ale.elements.length)
1156 error(e1.loc, "array index %llu is out of bounds `%s[0 .. %llu]`", i, e1.toChars(), cast(ulong) ale.elements.length);
1157 emplaceExp!(ErrorExp)(&ue);
1159 else
1161 auto e = ale[cast(size_t)i];
1162 e.type = type;
1163 e.loc = loc;
1164 if (hasSideEffect(e))
1165 cantExp(ue);
1166 else
1167 emplaceExp!(UnionExp)(&ue, e);
1170 else
1171 cantExp(ue);
1173 else if (AssocArrayLiteralExp ae = e1.isAssocArrayLiteralExp())
1175 /* Search the keys backwards, in case there are duplicate keys
1177 for (size_t i = ae.keys.length; i;)
1179 i--;
1180 Expression ekey = (*ae.keys)[i];
1181 ue = Equal(EXP.equal, loc, Type.tbool, ekey, e2);
1182 if (CTFEExp.isCantExp(ue.exp()))
1183 return ue;
1184 if (ue.exp().toBool().hasValue(true))
1186 Expression e = (*ae.values)[i];
1187 e.type = type;
1188 e.loc = loc;
1189 if (hasSideEffect(e))
1190 cantExp(ue);
1191 else
1192 emplaceExp!(UnionExp)(&ue, e);
1193 return ue;
1196 cantExp(ue);
1198 else
1199 cantExp(ue);
1200 return ue;
1203 /* Also return EXP.cantExpression if this fails
1205 UnionExp Slice(Type type, Expression e1, Expression lwr, Expression upr)
1207 UnionExp ue = void;
1208 Loc loc = e1.loc;
1209 static if (LOG)
1211 printf("Slice()\n");
1212 if (lwr)
1214 printf("\te1 = %s\n", e1.toChars());
1215 printf("\tlwr = %s\n", lwr.toChars());
1216 printf("\tupr = %s\n", upr.toChars());
1220 if (!lwr)
1222 if (e1.op == EXP.string_)
1223 emplaceExp(&ue, e1);
1224 else
1225 cantExp(ue);
1227 else if (e1.op == EXP.string_ && lwr.op == EXP.int64 && upr.op == EXP.int64)
1229 StringExp es1 = e1.isStringExp();
1230 const uinteger_t ilwr = lwr.toInteger();
1231 const uinteger_t iupr = upr.toInteger();
1232 if (sliceBoundsCheck(0, es1.len, ilwr, iupr))
1233 cantExp(ue); // https://issues.dlang.org/show_bug.cgi?id=18115
1234 else
1236 const len = cast(size_t)(iupr - ilwr);
1237 const sz = es1.sz;
1238 void* s = mem.xmalloc(len * sz);
1239 const data1 = es1.peekData();
1240 memcpy(s, data1.ptr + ilwr * sz, len * sz);
1241 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz, es1.postfix);
1242 StringExp es = ue.exp().isStringExp();
1243 es.committed = es1.committed;
1244 es.type = type;
1247 else if (e1.op == EXP.arrayLiteral && lwr.op == EXP.int64 && upr.op == EXP.int64 && !hasSideEffect(e1))
1249 ArrayLiteralExp es1 = e1.isArrayLiteralExp();
1250 const uinteger_t ilwr = lwr.toInteger();
1251 const uinteger_t iupr = upr.toInteger();
1252 if (sliceBoundsCheck(0, es1.elements.length, ilwr, iupr))
1253 cantExp(ue);
1254 else
1256 auto elements = new Expressions(cast(size_t)(iupr - ilwr));
1257 memcpy(elements.tdata(), es1.elements.tdata() + ilwr, cast(size_t)(iupr - ilwr) * ((*es1.elements)[0]).sizeof);
1258 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elements);
1261 else
1262 cantExp(ue);
1263 return ue;
1266 /* Check whether slice `[newlwr .. newupr]` is in the range `[lwr .. upr]`
1268 bool sliceBoundsCheck(uinteger_t lwr, uinteger_t upr, uinteger_t newlwr, uinteger_t newupr) pure @safe
1270 assert(lwr <= upr);
1271 return !(newlwr <= newupr &&
1272 lwr <= newlwr &&
1273 newupr <= upr);
1276 /* Set a slice of char/integer array literal 'existingAE' from a string 'newval'.
1277 * existingAE[firstIndex..firstIndex+newval.length] = newval.
1279 void sliceAssignArrayLiteralFromString(ArrayLiteralExp existingAE, const StringExp newval, size_t firstIndex)
1281 const len = newval.len;
1282 Type elemType = existingAE.type.nextOf();
1283 foreach (j; 0 .. len)
1285 const val = newval.getIndex(j);
1286 (*existingAE.elements)[j + firstIndex] = new IntegerExp(newval.loc, val, elemType);
1290 /* Set a slice of string 'existingSE' from a char array literal 'newae'.
1291 * existingSE[firstIndex..firstIndex+newae.length] = newae.
1293 void sliceAssignStringFromArrayLiteral(StringExp existingSE, ArrayLiteralExp newae, size_t firstIndex)
1295 assert(existingSE.ownedByCtfe != OwnedBy.code);
1296 foreach (j; 0 .. newae.elements.length)
1298 existingSE.setCodeUnit(firstIndex + j, cast(dchar)newae[j].toInteger());
1302 /* Set a slice of string 'existingSE' from a string 'newstr'.
1303 * existingSE[firstIndex..firstIndex+newstr.length] = newstr.
1305 void sliceAssignStringFromString(StringExp existingSE, const StringExp newstr, size_t firstIndex)
1307 assert(existingSE.ownedByCtfe != OwnedBy.code);
1308 size_t sz = existingSE.sz;
1309 assert(sz == newstr.sz);
1310 auto data1 = existingSE.borrowData();
1311 const data2 = newstr.peekData();
1312 memcpy(data1.ptr + firstIndex * sz, data2.ptr, data2.length);
1315 /* Compare a string slice with another string slice.
1316 * Conceptually equivalent to memcmp( se1[lo1..lo1+len], se2[lo2..lo2+len])
1318 int sliceCmpStringWithString(const StringExp se1, const StringExp se2, size_t lo1, size_t lo2, size_t len)
1320 size_t sz = se1.sz;
1321 assert(sz == se2.sz);
1322 const data1 = se1.peekData();
1323 const data2 = se2.peekData();
1324 return memcmp(data1.ptr + sz * lo1, data2.ptr + sz * lo2, sz * len);
1327 /* Compare a string slice with an array literal slice
1328 * Conceptually equivalent to memcmp( se1[lo1..lo1+len], ae2[lo2..lo2+len])
1330 int sliceCmpStringWithArray(const StringExp se1, ArrayLiteralExp ae2, size_t lo1, size_t lo2, size_t len)
1332 foreach (j; 0 .. len)
1334 const val2 = cast(dchar)ae2[j + lo2].toInteger();
1335 const val1 = se1.getCodeUnit(j + lo1);
1336 const int c = val1 - val2;
1337 if (c)
1338 return c;
1340 return 0;
1343 /** Copy element `Expressions` in the parameters when they're `ArrayLiteralExp`s.
1344 * Params:
1345 * e1 = If it's ArrayLiteralExp, its `elements` will be copied.
1346 * Otherwise, `e1` itself will be pushed into the new `Expressions`.
1347 * e2 = If it's not `null`, it will be pushed/appended to the new
1348 * `Expressions` by the same way with `e1`.
1349 * Returns:
1350 * Newly allocated `Expressions`. Note that it points to the original
1351 * `Expression` values in e1 and e2.
1353 private Expressions* copyElements(Expression e1, Expression e2 = null)
1355 auto elems = new Expressions();
1357 void append(ArrayLiteralExp ale)
1359 if (!ale.elements)
1360 return;
1361 auto d = elems.length;
1362 elems.append(ale.elements);
1363 foreach (ref el; (*elems)[d .. elems.length])
1365 if (!el)
1366 el = ale.basis;
1370 if (auto ale = e1.isArrayLiteralExp())
1371 append(ale);
1372 else
1373 elems.push(e1);
1375 if (e2)
1377 if (auto ale = e2.isArrayLiteralExp())
1378 append(ale);
1379 else
1380 elems.push(e2);
1383 return elems;
1386 /* Also return EXP.cantExpression if this fails
1388 UnionExp Cat(const ref Loc loc, Type type, Expression e1, Expression e2)
1390 UnionExp ue = void;
1391 Expression e = CTFEExp.cantexp;
1392 Type t;
1393 Type t1 = e1.type.toBasetype();
1394 Type t2 = e2.type.toBasetype();
1395 //printf("Cat(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
1396 //printf("\tt1 = %s, t2 = %s, type = %s\n", t1.toChars(), t2.toChars(), type.toChars());
1398 /* e is the non-null operand, t is the type of the null operand
1400 UnionExp catNull(Expression e, Type t)
1402 Type tn = e.type.toBasetype();
1403 if (tn.ty.isSomeChar)
1405 // Create a StringExp
1406 if (t.nextOf())
1407 t = t.nextOf().toBasetype();
1408 const sz = cast(ubyte)t.size();
1409 dinteger_t v = e.toInteger();
1410 const len = (t.ty == tn.ty) ? 1 : utf_codeLength(sz, cast(dchar)v);
1411 void* s = mem.xmalloc(len * sz);
1412 if (t.ty == tn.ty)
1413 Port.valcpy(s, v, sz);
1414 else
1415 utf_encode(sz, s, cast(dchar)v);
1416 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1417 StringExp es = ue.exp().isStringExp();
1418 es.type = type;
1419 es.committed = true;
1421 else
1423 // Create an ArrayLiteralExp
1424 auto elements = new Expressions();
1425 elements.push(e);
1426 emplaceExp!(ArrayLiteralExp)(&ue, e.loc, type, elements);
1428 assert(ue.exp().type);
1429 return ue;
1432 if (e1.op == EXP.null_ && (e2.op == EXP.int64 || e2.op == EXP.structLiteral))
1434 return catNull(e2, t1);
1436 else if ((e1.op == EXP.int64 || e1.op == EXP.structLiteral) && e2.op == EXP.null_)
1438 return catNull(e1, t2);
1440 else if (e1.op == EXP.null_ && e2.op == EXP.null_)
1442 if (type == e1.type)
1444 // Handle null ~= null
1445 if (t1.ty == Tarray && t2 == t1.nextOf())
1447 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, e2);
1448 assert(ue.exp().type);
1449 return ue;
1451 else
1453 emplaceExp!(UnionExp)(&ue, e1);
1454 assert(ue.exp().type);
1455 return ue;
1458 if (type == e2.type)
1460 emplaceExp!(UnionExp)(&ue, e2);
1461 assert(ue.exp().type);
1462 return ue;
1464 emplaceExp!(NullExp)(&ue, e1.loc, type);
1465 assert(ue.exp().type);
1466 return ue;
1468 else if (e1.op == EXP.string_ && e2.op == EXP.string_)
1470 // Concatenate the strings
1471 StringExp es1 = e1.isStringExp();
1472 StringExp es2 = e2.isStringExp();
1473 size_t len = es1.len + es2.len;
1474 ubyte sz = es1.sz;
1475 if (sz != es2.sz)
1477 /* Can happen with:
1478 * auto s = "foo"d ~ "bar"c;
1480 assert(global.errors);
1481 cantExp(ue);
1482 assert(ue.exp().type);
1483 return ue;
1485 void* s = mem.xmalloc(len * sz);
1486 const data1 = es1.peekData();
1487 const data2 = es2.peekData();
1488 memcpy(cast(char*)s, data1.ptr, es1.len * sz);
1489 memcpy(cast(char*)s + es1.len * sz, data2.ptr, es2.len * sz);
1490 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1491 StringExp es = ue.exp().isStringExp();
1492 es.committed = es1.committed | es2.committed;
1493 es.type = type;
1494 assert(ue.exp().type);
1495 return ue;
1497 else if (e2.op == EXP.string_ && e1.op == EXP.arrayLiteral && t1.nextOf().isintegral())
1499 // [chars] ~ string --> [chars]
1500 StringExp es = e2.isStringExp();
1501 ArrayLiteralExp ea = e1.isArrayLiteralExp();
1502 size_t len = es.len + ea.elements.length;
1503 auto elems = new Expressions(len);
1504 for (size_t i = 0; i < ea.elements.length; ++i)
1506 (*elems)[i] = ea[i];
1508 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
1509 ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
1510 sliceAssignArrayLiteralFromString(dest, es, ea.elements.length);
1511 assert(ue.exp().type);
1512 return ue;
1514 else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral && t2.nextOf().isintegral())
1516 // string ~ [chars] --> [chars]
1517 StringExp es = e1.isStringExp();
1518 ArrayLiteralExp ea = e2.isArrayLiteralExp();
1519 size_t len = es.len + ea.elements.length;
1520 auto elems = new Expressions(len);
1521 for (size_t i = 0; i < ea.elements.length; ++i)
1523 (*elems)[es.len + i] = ea[i];
1525 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, type, elems);
1526 ArrayLiteralExp dest = ue.exp().isArrayLiteralExp();
1527 sliceAssignArrayLiteralFromString(dest, es, 0);
1528 assert(ue.exp().type);
1529 return ue;
1531 else if (e1.op == EXP.string_ && e2.op == EXP.int64)
1533 // string ~ char --> string
1534 StringExp es1 = e1.isStringExp();
1535 StringExp es;
1536 const sz = es1.sz;
1537 dinteger_t v = e2.toInteger();
1538 // Is it a concatenation of homogenous types?
1539 // (char[] ~ char, wchar[]~wchar, or dchar[]~dchar)
1540 bool homoConcat = (sz == t2.size());
1541 const len = es1.len + (homoConcat ? 1 : utf_codeLength(sz, cast(dchar)v));
1542 void* s = mem.xmalloc(len * sz);
1543 const data1 = es1.peekData();
1544 memcpy(s, data1.ptr, data1.length);
1545 if (homoConcat)
1546 Port.valcpy(cast(char*)s + (sz * es1.len), v, sz);
1547 else
1548 utf_encode(sz, cast(char*)s + (sz * es1.len), cast(dchar)v);
1549 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1550 es = ue.exp().isStringExp();
1551 es.committed = es1.committed;
1552 es.type = type;
1553 assert(ue.exp().type);
1554 return ue;
1556 else if (e1.op == EXP.int64 && e2.op == EXP.string_)
1558 // [w|d]?char ~ string --> string
1559 // We assume that we only ever prepend one char of the same type
1560 // (wchar,dchar) as the string's characters.
1561 StringExp es2 = e2.isStringExp();
1562 const len = 1 + es2.len;
1563 const sz = es2.sz;
1564 dinteger_t v = e1.toInteger();
1565 void* s = mem.xmalloc(len * sz);
1566 Port.valcpy(cast(char*)s, v, sz);
1567 const data2 = es2.peekData();
1568 memcpy(cast(char*)s + sz, data2.ptr, data2.length);
1569 emplaceExp!(StringExp)(&ue, loc, s[0 .. len * sz], len, sz);
1570 StringExp es = ue.exp().isStringExp();
1571 es.sz = sz;
1572 es.committed = es2.committed;
1573 es.type = type;
1574 assert(ue.exp().type);
1575 return ue;
1577 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1579 // Concatenate the arrays
1580 auto elems = copyElements(e1, e2);
1582 emplaceExp!(ArrayLiteralExp)(&ue, e1.loc, cast(Type)null, elems);
1584 e = ue.exp();
1585 if (type.toBasetype().ty == Tsarray)
1587 e.type = t1.nextOf().sarrayOf(elems.length);
1589 else
1590 e.type = type;
1591 assert(ue.exp().type);
1592 return ue;
1594 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.null_ && t1.nextOf().equals(t2.nextOf()))
1596 e = e1;
1597 goto L3;
1599 else if (e1.op == EXP.null_ && e2.op == EXP.arrayLiteral && t1.nextOf().equals(t2.nextOf()))
1601 e = e2;
1603 // Concatenate the array with null
1604 auto elems = copyElements(e);
1606 emplaceExp!(ArrayLiteralExp)(&ue, e.loc, cast(Type)null, elems);
1608 e = ue.exp();
1609 if (type.toBasetype().ty == Tsarray)
1611 e.type = t1.nextOf().sarrayOf(elems.length);
1613 else
1614 e.type = type;
1615 assert(ue.exp().type);
1616 return ue;
1618 else if ((e1.op == EXP.arrayLiteral || e1.op == EXP.null_) && e1.type.toBasetype().nextOf() && e1.type.toBasetype().nextOf().equals(e2.type))
1620 auto elems = (e1.op == EXP.arrayLiteral)
1621 ? copyElements(e1) : new Expressions();
1622 elems.push(e2);
1624 emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
1626 e = ue.exp();
1627 if (type.toBasetype().ty == Tsarray)
1629 e.type = e2.type.sarrayOf(elems.length);
1631 else
1632 e.type = type;
1633 assert(ue.exp().type);
1634 return ue;
1636 else if (e2.op == EXP.arrayLiteral && e2.type.toBasetype().nextOf().equals(e1.type))
1638 auto elems = copyElements(e1, e2);
1640 emplaceExp!(ArrayLiteralExp)(&ue, loc, cast(Type)null, elems);
1642 e = ue.exp();
1643 if (type.toBasetype().ty == Tsarray)
1645 e.type = e1.type.sarrayOf(elems.length);
1647 else
1648 e.type = type;
1649 assert(ue.exp().type);
1650 return ue;
1652 else if (e1.op == EXP.null_ && e2.op == EXP.string_)
1654 t = e1.type;
1655 e = e2;
1656 goto L1;
1658 else if (e1.op == EXP.string_ && e2.op == EXP.null_)
1660 e = e1;
1661 t = e2.type;
1663 Type tb = t.toBasetype();
1664 if (tb.ty == Tarray && tb.nextOf().equivalent(e.type))
1666 auto expressions = new Expressions();
1667 expressions.push(e);
1668 emplaceExp!(ArrayLiteralExp)(&ue, loc, t, expressions);
1669 e = ue.exp();
1671 else
1673 emplaceExp!(UnionExp)(&ue, e);
1674 e = ue.exp();
1676 if (!e.type.equals(type))
1678 StringExp se = e.copy().isStringExp();
1679 e = se.castTo(null, type);
1680 emplaceExp!(UnionExp)(&ue, e);
1681 e = ue.exp();
1684 else
1685 cantExp(ue);
1686 assert(ue.exp().type);
1687 return ue;
1690 UnionExp Ptr(Type type, Expression e1)
1692 //printf("Ptr(e1 = %s)\n", e1.toChars());
1693 UnionExp ue = void;
1694 if (AddExp ae = e1.isAddExp())
1696 if (AddrExp ade = ae.e1.isAddrExp())
1698 if (ae.e2.op == EXP.int64)
1699 if (StructLiteralExp se = ade.e1.isStructLiteralExp())
1701 uint offset = cast(uint)ae.e2.toInteger();
1702 Expression e = se.getField(type, offset);
1703 if (e)
1705 emplaceExp!(UnionExp)(&ue, e);
1706 return ue;
1711 cantExp(ue);
1712 return ue;