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