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