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