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