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