tree-optimization/115629 - missed tail merging
[official-gcc.git] / gcc / d / dmd / constfold.d
blob6ec31d5f9bb446a091da61ab9f4105c42f9f258d
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;
39 import dmd.typesem : toDsymbol, equivalent, sarrayOf;
41 private enum LOG = false;
43 private Expression expType(Type type, Expression e)
45 if (type != e.type)
47 e = e.copy();
48 e.type = type;
50 return e;
53 /**********************************
54 * Initialize a EXP.cantExpression Expression.
55 * Params:
56 * ue = where to write it
58 void cantExp(out UnionExp ue)
60 emplaceExp!(CTFEExp)(&ue, EXP.cantExpression);
63 /* =============================== constFold() ============================== */
64 /* The constFold() functions were redundant with the optimize() ones,
65 * and so have been folded in with them.
67 /* ========================================================================== */
68 UnionExp Neg(Type type, Expression e1)
70 UnionExp ue = void;
71 Loc loc = e1.loc;
72 if (e1.type.isreal())
74 emplaceExp!(RealExp)(&ue, loc, -e1.toReal(), type);
76 else if (e1.type.isimaginary())
78 emplaceExp!(RealExp)(&ue, loc, -e1.toImaginary(), type);
80 else if (e1.type.iscomplex())
82 emplaceExp!(ComplexExp)(&ue, loc, -e1.toComplex(), type);
84 else
86 emplaceExp!(IntegerExp)(&ue, loc, -e1.toInteger(), type);
88 return ue;
91 UnionExp Com(Type type, Expression e1)
93 UnionExp ue = void;
94 Loc loc = e1.loc;
95 emplaceExp!(IntegerExp)(&ue, loc, ~e1.toInteger(), type);
96 return ue;
99 UnionExp Not(Type type, Expression e1)
101 UnionExp ue = void;
102 Loc loc = e1.loc;
103 // BUG: Should be replaced with e1.toBool().get(), but this is apparently
104 // executed for some expressions that cannot be const-folded
105 // To be fixed in another PR
106 emplaceExp!(IntegerExp)(&ue, loc, e1.toBool().hasValue(false) ? 1 : 0, type);
107 return ue;
110 UnionExp Add(const ref Loc loc, Type type, Expression e1, Expression e2)
112 UnionExp ue = void;
113 static if (LOG)
115 printf("Add(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
117 if (type.isreal())
119 emplaceExp!(RealExp)(&ue, loc, e1.toReal() + e2.toReal(), type);
121 else if (type.isimaginary())
123 emplaceExp!(RealExp)(&ue, loc, e1.toImaginary() + e2.toImaginary(), type);
125 else if (type.iscomplex())
127 // This rigamarole is necessary so that -0.0 doesn't get
128 // converted to +0.0 by doing an extraneous add with +0.0
129 auto c1 = complex_t(CTFloat.zero);
130 real_t r1 = CTFloat.zero;
131 real_t i1 = CTFloat.zero;
132 auto c2 = complex_t(CTFloat.zero);
133 real_t r2 = CTFloat.zero;
134 real_t i2 = CTFloat.zero;
135 auto v = complex_t(CTFloat.zero);
136 int x;
137 if (e1.type.isreal())
139 r1 = e1.toReal();
140 x = 0;
142 else if (e1.type.isimaginary())
144 i1 = e1.toImaginary();
145 x = 3;
147 else
149 c1 = e1.toComplex();
150 x = 6;
152 if (e2.type.isreal())
154 r2 = e2.toReal();
156 else if (e2.type.isimaginary())
158 i2 = e2.toImaginary();
159 x += 1;
161 else
163 c2 = e2.toComplex();
164 x += 2;
166 switch (x)
168 case 0 + 0:
169 v = complex_t(r1 + r2);
170 break;
171 case 0 + 1:
172 v = complex_t(r1, i2);
173 break;
174 case 0 + 2:
175 v = complex_t(r1 + creall(c2), cimagl(c2));
176 break;
177 case 3 + 0:
178 v = complex_t(r2, i1);
179 break;
180 case 3 + 1:
181 v = complex_t(CTFloat.zero, i1 + i2);
182 break;
183 case 3 + 2:
184 v = complex_t(creall(c2), i1 + cimagl(c2));
185 break;
186 case 6 + 0:
187 v = complex_t(creall(c1) + r2, cimagl(c2));
188 break;
189 case 6 + 1:
190 v = complex_t(creall(c1), cimagl(c1) + i2);
191 break;
192 case 6 + 2:
193 v = c1 + c2;
194 break;
195 default:
196 assert(0);
198 emplaceExp!(ComplexExp)(&ue, loc, v, type);
200 else if (SymOffExp soe = e1.isSymOffExp())
202 emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e2.toInteger());
203 ue.exp().type = type;
205 else if (SymOffExp soe = e2.isSymOffExp())
207 emplaceExp!(SymOffExp)(&ue, loc, soe.var, soe.offset + e1.toInteger());
208 ue.exp().type = type;
210 else
211 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() + e2.toInteger(), type);
212 return ue;
215 UnionExp Min(const ref Loc loc, Type type, Expression e1, Expression e2)
217 // Compute e1-e2 as e1+(-e2)
218 UnionExp neg = Neg(e2.type, e2);
219 UnionExp ue = Add(loc, type, e1, neg.exp());
220 return ue;
223 UnionExp Mul(const ref Loc loc, Type type, Expression e1, Expression e2)
225 UnionExp ue = void;
226 if (type.isfloating())
228 auto c = complex_t(CTFloat.zero);
229 real_t r = CTFloat.zero;
230 if (e1.type.isreal())
232 r = e1.toReal();
233 c = e2.toComplex();
234 c = complex_t(r * creall(c), r * cimagl(c));
236 else if (e1.type.isimaginary())
238 r = e1.toImaginary();
239 c = e2.toComplex();
240 c = complex_t(-r * cimagl(c), r * creall(c));
242 else if (e2.type.isreal())
244 r = e2.toReal();
245 c = e1.toComplex();
246 c = complex_t(r * creall(c), r * cimagl(c));
248 else if (e2.type.isimaginary())
250 r = e2.toImaginary();
251 c = e1.toComplex();
252 c = complex_t(-r * cimagl(c), r * creall(c));
254 else
255 c = e1.toComplex() * e2.toComplex();
256 if (type.isreal())
257 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
258 else if (type.isimaginary())
259 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
260 else if (type.iscomplex())
261 emplaceExp!(ComplexExp)(&ue, loc, c, type);
262 else
263 assert(0);
265 else
267 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() * e2.toInteger(), type);
269 return ue;
272 UnionExp Div(const ref Loc loc, Type type, Expression e1, Expression e2)
274 UnionExp ue = void;
275 if (type.isfloating())
277 auto c = complex_t(CTFloat.zero);
278 if (e2.type.isreal())
280 if (e1.type.isreal())
282 emplaceExp!(RealExp)(&ue, loc, e1.toReal() / e2.toReal(), type);
283 return ue;
285 const r = e2.toReal();
286 c = e1.toComplex();
287 c = complex_t(creall(c) / r, cimagl(c) / r);
289 else if (e2.type.isimaginary())
291 const r = e2.toImaginary();
292 c = e1.toComplex();
293 c = complex_t(cimagl(c) / r, -creall(c) / r);
295 else
297 c = e1.toComplex() / e2.toComplex();
300 if (type.isreal())
301 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
302 else if (type.isimaginary())
303 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
304 else if (type.iscomplex())
305 emplaceExp!(ComplexExp)(&ue, loc, c, type);
306 else
307 assert(0);
309 else
311 sinteger_t n1;
312 sinteger_t n2;
313 sinteger_t n;
314 n1 = e1.toInteger();
315 n2 = e2.toInteger();
316 if (n2 == 0)
318 error(e2.loc, "divide by 0");
319 emplaceExp!(ErrorExp)(&ue);
320 return ue;
322 if (n2 == -1 && !type.isunsigned())
324 // Check for int.min / -1
325 if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
327 error(e2.loc, "integer overflow: `int.min / -1`");
328 emplaceExp!(ErrorExp)(&ue);
329 return ue;
331 else if (n1 == 0x8000000000000000L) // long.min / -1
333 error(e2.loc, "integer overflow: `long.min / -1L`");
334 emplaceExp!(ErrorExp)(&ue);
335 return ue;
338 if (e1.type.isunsigned() || e2.type.isunsigned())
339 n = (cast(dinteger_t)n1) / (cast(dinteger_t)n2);
340 else
341 n = n1 / n2;
342 emplaceExp!(IntegerExp)(&ue, loc, n, type);
344 return ue;
347 UnionExp Mod(const ref Loc loc, Type type, Expression e1, Expression e2)
349 UnionExp ue = void;
350 if (type.isfloating())
352 auto c = complex_t(CTFloat.zero);
353 if (e2.type.isreal())
355 const r2 = e2.toReal();
356 c = complex_t(e1.toReal() % r2, e1.toImaginary() % r2);
358 else if (e2.type.isimaginary())
360 const i2 = e2.toImaginary();
361 c = complex_t(e1.toReal() % i2, e1.toImaginary() % i2);
363 else
364 assert(0);
365 if (type.isreal())
366 emplaceExp!(RealExp)(&ue, loc, creall(c), type);
367 else if (type.isimaginary())
368 emplaceExp!(RealExp)(&ue, loc, cimagl(c), type);
369 else if (type.iscomplex())
370 emplaceExp!(ComplexExp)(&ue, loc, c, type);
371 else
372 assert(0);
374 else
376 sinteger_t n1;
377 sinteger_t n2;
378 sinteger_t n;
379 n1 = e1.toInteger();
380 n2 = e2.toInteger();
381 if (n2 == 0)
383 error(e2.loc, "divide by 0");
384 emplaceExp!(ErrorExp)(&ue);
385 return ue;
387 if (n2 == -1 && !type.isunsigned())
389 // Check for int.min % -1
390 if (n1 == 0xFFFFFFFF80000000UL && type.toBasetype().ty != Tint64)
392 error(e2.loc, "integer overflow: `int.min %% -1`");
393 emplaceExp!(ErrorExp)(&ue);
394 return ue;
396 else if (n1 == 0x8000000000000000L) // long.min % -1
398 error(e2.loc, "integer overflow: `long.min %% -1L`");
399 emplaceExp!(ErrorExp)(&ue);
400 return ue;
403 if (e1.type.isunsigned() || e2.type.isunsigned())
404 n = (cast(dinteger_t)n1) % (cast(dinteger_t)n2);
405 else
406 n = n1 % n2;
407 emplaceExp!(IntegerExp)(&ue, loc, n, type);
409 return ue;
412 UnionExp Pow(const ref Loc loc, Type type, Expression e1, Expression e2)
414 //printf("Pow()\n");
415 UnionExp ue;
416 // Handle integer power operations.
417 if (e2.type.isintegral())
419 dinteger_t n = e2.toInteger();
420 bool neg;
421 if (!e2.type.isunsigned() && cast(sinteger_t)n < 0)
423 if (e1.type.isintegral())
425 cantExp(ue);
426 return ue;
428 // Don't worry about overflow, from now on n is unsigned.
429 neg = true;
430 n = -n;
432 else
433 neg = false;
434 UnionExp ur, uv;
435 if (e1.type.iscomplex())
437 emplaceExp!(ComplexExp)(&ur, loc, e1.toComplex(), e1.type);
438 emplaceExp!(ComplexExp)(&uv, loc, complex_t(CTFloat.one), e1.type);
440 else if (e1.type.isfloating())
442 emplaceExp!(RealExp)(&ur, loc, e1.toReal(), e1.type);
443 emplaceExp!(RealExp)(&uv, loc, CTFloat.one, e1.type);
445 else
447 emplaceExp!(IntegerExp)(&ur, loc, e1.toInteger(), e1.type);
448 emplaceExp!(IntegerExp)(&uv, loc, 1, e1.type);
450 Expression r = ur.exp();
451 Expression v = uv.exp();
452 while (n != 0)
454 if (n & 1)
456 // v = v * r;
457 uv = Mul(loc, v.type, v, r);
459 n >>= 1;
460 // r = r * r
461 ur = Mul(loc, r.type, r, r);
463 if (neg)
465 // ue = 1.0 / v
466 UnionExp one;
467 emplaceExp!(RealExp)(&one, loc, CTFloat.one, v.type);
468 uv = Div(loc, v.type, one.exp(), v);
470 if (type.iscomplex())
471 emplaceExp!(ComplexExp)(&ue, loc, v.toComplex(), type);
472 else if (type.isintegral())
473 emplaceExp!(IntegerExp)(&ue, loc, v.toInteger(), type);
474 else
475 emplaceExp!(RealExp)(&ue, loc, v.toReal(), type);
477 else if (e2.type.isfloating())
479 // x ^^ y for x < 0 and y not an integer is not defined; so set result as NaN
480 if (e1.toReal() < CTFloat.zero)
482 emplaceExp!(RealExp)(&ue, loc, target.RealProperties.nan, type);
484 else
485 cantExp(ue);
487 else
488 cantExp(ue);
489 return ue;
492 UnionExp Shl(const ref Loc loc, Type type, Expression e1, Expression e2)
494 UnionExp ue = void;
495 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() << e2.toInteger(), type);
496 return ue;
499 UnionExp Shr(const ref Loc loc, Type type, Expression e1, Expression e2)
501 UnionExp ue = void;
502 dinteger_t value = e1.toInteger();
503 dinteger_t dcount = e2.toInteger();
504 assert(dcount <= 0xFFFFFFFF);
505 uint count = cast(uint)dcount;
506 switch (e1.type.toBasetype().ty)
508 case Tint8:
509 value = cast(byte)value >> count;
510 break;
511 case Tuns8:
512 case Tchar:
513 value = cast(ubyte)value >> count;
514 break;
515 case Tint16:
516 value = cast(short)value >> count;
517 break;
518 case Tuns16:
519 case Twchar:
520 value = cast(ushort)value >> count;
521 break;
522 case Tint32:
523 value = cast(int)value >> count;
524 break;
525 case Tuns32:
526 case Tdchar:
527 value = cast(uint)value >> count;
528 break;
529 case Tint64:
530 value = cast(long)value >> count;
531 break;
532 case Tuns64:
533 value = cast(ulong)value >> count;
534 break;
535 case Terror:
536 emplaceExp!(ErrorExp)(&ue);
537 return ue;
538 default:
539 assert(0);
541 emplaceExp!(IntegerExp)(&ue, loc, value, type);
542 return ue;
545 UnionExp Ushr(const ref Loc loc, Type type, Expression e1, Expression e2)
547 UnionExp ue = void;
548 dinteger_t value = e1.toInteger();
549 dinteger_t dcount = e2.toInteger();
550 assert(dcount <= 0xFFFFFFFF);
551 uint count = cast(uint)dcount;
552 switch (e1.type.toBasetype().ty)
554 case Tint8:
555 case Tuns8:
556 case Tchar:
557 // Possible only with >>>=. >>> always gets promoted to int.
558 value = (value & 0xFF) >>> count;
559 break;
560 case Tint16:
561 case Tuns16:
562 case Twchar:
563 // Possible only with >>>=. >>> always gets promoted to int.
564 value = (value & 0xFFFF) >>> count;
565 break;
566 case Tint32:
567 case Tuns32:
568 case Tdchar:
569 value = (value & 0xFFFFFFFF) >>> count;
570 break;
571 case Tint64:
572 case Tuns64:
573 value = value >>> count;
574 break;
575 case Terror:
576 emplaceExp!(ErrorExp)(&ue);
577 return ue;
578 default:
579 assert(0);
581 emplaceExp!(IntegerExp)(&ue, loc, value, type);
582 return ue;
585 UnionExp And(const ref Loc loc, Type type, Expression e1, Expression e2)
587 UnionExp ue = void;
588 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() & e2.toInteger(), type);
589 return ue;
592 UnionExp Or(const ref Loc loc, Type type, Expression e1, Expression e2)
594 UnionExp ue = void;
595 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() | e2.toInteger(), type);
596 return ue;
599 UnionExp Xor(const ref Loc loc, Type type, Expression e1, Expression e2)
601 //printf("Xor(linnum = %d, e1 = %s, e2 = %s)\n", loc.linnum, e1.toChars(), e2.toChars());
602 UnionExp ue = void;
603 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger() ^ e2.toInteger(), type);
604 return ue;
607 /* Also returns EXP.cantExpression if cannot be computed.
609 UnionExp Equal(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
611 UnionExp ue = void;
612 int cmp = 0;
613 real_t r1 = CTFloat.zero;
614 real_t r2 = CTFloat.zero;
615 //printf("Equal(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
616 assert(op == EXP.equal || op == EXP.notEqual);
617 if (e1.op == EXP.null_)
619 if (e2.op == EXP.null_)
620 cmp = 1;
621 else if (StringExp es2 = e2.isStringExp())
623 cmp = (0 == es2.len);
625 else if (ArrayLiteralExp es2 = e2.isArrayLiteralExp())
627 cmp = !es2.elements || (0 == es2.elements.length);
629 else
631 cantExp(ue);
632 return ue;
635 else if (e2.op == EXP.null_)
637 if (StringExp es1 = e1.isStringExp())
639 cmp = (0 == es1.len);
641 else if (ArrayLiteralExp es1 = e1.isArrayLiteralExp())
643 cmp = !es1.elements || (0 == es1.elements.length);
645 else
647 cantExp(ue);
648 return ue;
651 else if (e1.op == EXP.string_ && e2.op == EXP.string_)
653 StringExp es1 = e1.isStringExp();
654 StringExp es2 = e2.isStringExp();
655 if (es1.sz != es2.sz)
657 assert(global.errors);
658 cantExp(ue);
659 return ue;
661 const data1 = es1.peekData();
662 const data2 = es2.peekData();
663 if (es1.len == es2.len && memcmp(data1.ptr, data2.ptr, es1.sz * es1.len) == 0)
664 cmp = 1;
665 else
666 cmp = 0;
668 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.arrayLiteral)
670 ArrayLiteralExp es1 = e1.isArrayLiteralExp();
671 ArrayLiteralExp es2 = e2.isArrayLiteralExp();
672 if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
673 cmp = 1; // both arrays are empty
674 else if (!es1.elements || !es2.elements)
675 cmp = 0;
676 else if (es1.elements.length != es2.elements.length)
677 cmp = 0;
678 else
680 for (size_t i = 0; i < es1.elements.length; i++)
682 auto ee1 = es1[i];
683 auto ee2 = es2[i];
684 ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
685 if (CTFEExp.isCantExp(ue.exp()))
686 return ue;
687 cmp = cast(int)ue.exp().toInteger();
688 if (cmp == 0)
689 break;
693 else if (e1.op == EXP.arrayLiteral && e2.op == EXP.string_)
695 // Swap operands and use common code
696 Expression etmp = e1;
697 e1 = e2;
698 e2 = etmp;
699 goto Lsa;
701 else if (e1.op == EXP.string_ && e2.op == EXP.arrayLiteral)
703 Lsa:
704 StringExp es1 = e1.isStringExp();
705 ArrayLiteralExp es2 = e2.isArrayLiteralExp();
706 size_t dim1 = es1.len;
707 size_t dim2 = es2.elements ? es2.elements.length : 0;
708 if (dim1 != dim2)
709 cmp = 0;
710 else
712 cmp = 1; // if dim1 winds up being 0
713 foreach (i; 0 .. dim1)
715 uinteger_t c = es1.getIndex(i);
716 auto ee2 = es2[i];
717 if (ee2.isConst() != 1)
719 cantExp(ue);
720 return ue;
722 cmp = (c == ee2.toInteger());
723 if (cmp == 0)
724 break;
728 else if (e1.op == EXP.structLiteral && e2.op == EXP.structLiteral)
730 StructLiteralExp es1 = e1.isStructLiteralExp();
731 StructLiteralExp es2 = e2.isStructLiteralExp();
732 if (es1.sd != es2.sd)
733 cmp = 0;
734 else if ((!es1.elements || !es1.elements.length) && (!es2.elements || !es2.elements.length))
735 cmp = 1; // both arrays are empty
736 else if (!es1.elements || !es2.elements)
737 cmp = 0;
738 else if (es1.elements.length != es2.elements.length)
739 cmp = 0;
740 else
742 cmp = 1;
743 for (size_t i = 0; i < es1.elements.length; i++)
745 Expression ee1 = (*es1.elements)[i];
746 Expression ee2 = (*es2.elements)[i];
747 if (ee1 == ee2)
748 continue;
749 if (!ee1 || !ee2)
751 cmp = 0;
752 break;
754 ue = Equal(EXP.equal, loc, Type.tint32, ee1, ee2);
755 if (ue.exp().op == EXP.cantExpression)
756 return ue;
757 cmp = cast(int)ue.exp().toInteger();
758 if (cmp == 0)
759 break;
763 else if (e1.isConst() != 1 || e2.isConst() != 1)
765 cantExp(ue);
766 return ue;
768 else if (e1.type.isreal())
770 r1 = e1.toReal();
771 r2 = e2.toReal();
772 goto L1;
774 else if (e1.type.isimaginary())
776 r1 = e1.toImaginary();
777 r2 = e2.toImaginary();
779 if (CTFloat.isNaN(r1) || CTFloat.isNaN(r2)) // if unordered
781 cmp = 0;
783 else
785 cmp = (r1 == r2);
788 else if (e1.type.iscomplex())
790 cmp = e1.toComplex() == e2.toComplex();
792 else if (e1.type.isintegral() || e1.type.toBasetype().ty == Tpointer)
794 cmp = (e1.toInteger() == e2.toInteger());
796 else
798 cantExp(ue);
799 return ue;
801 if (op == EXP.notEqual)
802 cmp ^= 1;
803 emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
804 return ue;
807 UnionExp Identity(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
809 UnionExp ue = void;
810 int cmp;
811 if (e1.op == EXP.null_)
813 cmp = (e2.op == EXP.null_);
815 else if (e2.op == EXP.null_)
817 cmp = 0;
819 else if (e1.op == EXP.symbolOffset && e2.op == EXP.symbolOffset)
821 SymOffExp es1 = e1.isSymOffExp();
822 SymOffExp es2 = e2.isSymOffExp();
823 cmp = (es1.var == es2.var && es1.offset == es2.offset);
825 else
827 if (e1.type.isfloating())
828 cmp = e1.isIdentical(e2);
829 else
831 ue = Equal((op == EXP.identity) ? EXP.equal : EXP.notEqual, loc, type, e1, e2);
832 return ue;
835 if (op == EXP.notIdentity)
836 cmp ^= 1;
837 emplaceExp!(IntegerExp)(&ue, loc, cmp, type);
838 return ue;
841 UnionExp Cmp(EXP op, const ref Loc loc, Type type, Expression e1, Expression e2)
843 UnionExp ue = void;
844 dinteger_t n;
845 real_t r1 = CTFloat.zero;
846 real_t r2 = CTFloat.zero;
847 //printf("Cmp(e1 = %s, e2 = %s)\n", e1.toChars(), e2.toChars());
848 if (e1.op == EXP.string_ && e2.op == EXP.string_)
850 StringExp es1 = e1.isStringExp();
851 StringExp es2 = e2.isStringExp();
852 size_t sz = es1.sz;
853 assert(sz == es2.sz);
854 size_t len = es1.len;
855 if (es2.len < len)
856 len = es2.len;
857 const data1 = es1.peekData();
858 const data2 = es1.peekData();
859 int rawCmp = memcmp(data1.ptr, data2.ptr, sz * len);
860 if (rawCmp == 0)
861 rawCmp = cast(int)(es1.len - es2.len);
862 n = specificCmp(op, rawCmp);
864 else if (e1.isConst() != 1 || e2.isConst() != 1)
866 cantExp(ue);
867 return ue;
869 else if (e1.type.isreal())
871 r1 = e1.toReal();
872 r2 = e2.toReal();
873 goto L1;
875 else if (e1.type.isimaginary())
877 r1 = e1.toImaginary();
878 r2 = e2.toImaginary();
880 n = realCmp(op, r1, r2);
882 else if (e1.type.iscomplex())
884 assert(0);
886 else
888 sinteger_t n1;
889 sinteger_t n2;
890 n1 = e1.toInteger();
891 n2 = e2.toInteger();
892 if (e1.type.isunsigned() || e2.type.isunsigned())
893 n = intUnsignedCmp(op, n1, n2);
894 else
895 n = intSignedCmp(op, n1, n2);
897 emplaceExp!(IntegerExp)(&ue, loc, n, type);
898 return ue;
901 /* Also returns EXP.cantExpression if cannot be computed.
902 * to: type to cast to
903 * type: type to paint the result
905 UnionExp Cast(const ref Loc loc, Type type, Type to, Expression e1)
907 UnionExp ue = void;
908 Type tb = to.toBasetype();
909 Type typeb = type.toBasetype();
910 //printf("Cast(type = %s, to = %s, e1 = %s)\n", type.toChars(), to.toChars(), e1.toChars());
911 //printf("\te1.type = %s\n", e1.type.toChars());
912 if (e1.type.equals(type) && type.equals(to))
914 emplaceExp!(UnionExp)(&ue, e1);
915 return ue;
917 if (e1.op == EXP.vector && (cast(TypeVector)e1.type).basetype.equals(type) && type.equals(to))
919 Expression ex = e1.isVectorExp().e1;
920 emplaceExp!(UnionExp)(&ue, ex);
921 return ue;
923 if (e1.type.toBasetype.equals(type) && type.equals(to))
925 emplaceExp!(UnionExp)(&ue, e1);
926 ue.exp().type = type;
927 return ue;
929 if (e1.type.implicitConvTo(to) >= MATCH.constant || to.implicitConvTo(e1.type) >= MATCH.constant)
931 goto L1;
933 // Allow covariant converions of delegates
934 // (Perhaps implicit conversion from pure to impure should be a MATCH.constant,
935 // then we wouldn't need this extra check.)
936 if (e1.type.toBasetype().ty == Tdelegate && e1.type.implicitConvTo(to) == MATCH.convert)
938 goto L1;
940 /* Allow casting from one string type to another
942 if (e1.op == EXP.string_)
944 if (tb.ty == Tarray && typeb.ty == Tarray && tb.nextOf().size() == typeb.nextOf().size())
946 goto L1;
949 if (e1.op == EXP.arrayLiteral && typeb == tb)
952 Expression ex = expType(to, e1);
953 emplaceExp!(UnionExp)(&ue, ex);
954 return ue;
956 if (e1.isConst() != 1)
958 cantExp(ue);
960 else if (tb.ty == Tbool)
962 const opt = e1.toBool();
963 if (opt.isEmpty())
965 cantExp(ue);
966 return ue;
969 emplaceExp!(IntegerExp)(&ue, loc, opt.get(), type);
971 else if (type.isintegral())
973 if (e1.type.isfloating())
975 dinteger_t result;
976 real_t r = e1.toReal();
977 switch (typeb.ty)
979 case Tint8:
980 result = cast(byte)cast(sinteger_t)r;
981 break;
982 case Tchar:
983 case Tuns8:
984 result = cast(ubyte)cast(dinteger_t)r;
985 break;
986 case Tint16:
987 result = cast(short)cast(sinteger_t)r;
988 break;
989 case Twchar:
990 case Tuns16:
991 result = cast(ushort)cast(dinteger_t)r;
992 break;
993 case Tint32:
994 result = cast(int)r;
995 break;
996 case Tdchar:
997 case Tuns32:
998 result = cast(uint)r;
999 break;
1000 case Tint64:
1001 result = cast(long)r;
1002 break;
1003 case Tuns64:
1004 result = cast(ulong)r;
1005 break;
1006 default:
1007 assert(0);
1009 emplaceExp!(IntegerExp)(&ue, loc, result, type);
1011 else if (type.isunsigned())
1012 emplaceExp!(IntegerExp)(&ue, loc, e1.toUInteger(), type);
1013 else
1014 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1016 else if (tb.isreal())
1018 real_t value = e1.toReal();
1019 emplaceExp!(RealExp)(&ue, loc, value, type);
1021 else if (tb.isimaginary())
1023 real_t value = e1.toImaginary();
1024 emplaceExp!(RealExp)(&ue, loc, value, type);
1026 else if (tb.iscomplex())
1028 complex_t value = e1.toComplex();
1029 emplaceExp!(ComplexExp)(&ue, loc, value, type);
1031 else if (tb.isscalar())
1033 emplaceExp!(IntegerExp)(&ue, loc, e1.toInteger(), type);
1035 else if (tb.ty == Tvoid)
1037 cantExp(ue);
1039 else if (tb.ty == Tstruct && e1.op == EXP.int64)
1041 // Struct = 0;
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 = ae2[j + lo2].toInteger();
1335 const val1 = se1.getIndex(j + lo1);
1336 const int c = (val1 > val2) - (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;