1 /** 2 * Local optimizations of elem trees 3 * 4 * Compiler implementation of the 5 * $(LINK2 https://www.dlang.org, D programming language). 6 * 7 * Does strength reduction optimizations on the elem trees, 8 * i.e. rewriting trees to less expensive trees. 9 * 10 * Copyright: Copyright (C) 1985-1998 by Symantec 11 * Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved 12 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 13 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 14 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/cgelem.d, backend/cgelem.d) 15 * Documentation: https://dlang.org/phobos/dmd_backend_cgelem.html 16 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/cgelem.d 17 * Add coverage tests to https://github.com/dlang/dmd/blob/master/test/runnable/testcgelem.d 18 */ 19 20 module dmd.backend.cgelem; 21 22 import core.stdc.stdio; 23 import core.stdc.stdlib; 24 import core.stdc.string; 25 26 import dmd.backend.cc; 27 import dmd.backend.code; 28 import dmd.backend.cdef; 29 import dmd.backend.code_x86; 30 import dmd.backend.oper; 31 import dmd.backend.global; 32 import dmd.backend.goh; 33 import dmd.backend.el; 34 import dmd.backend.rtlsym; 35 import dmd.backend.symtab; 36 import dmd.backend.ty; 37 import dmd.backend.type; 38 39 import dmd.backend.dlist; 40 import dmd.backend.dvec; 41 42 43 nothrow: 44 @safe: 45 46 import dmd.backend.evalu8 : evalu8; 47 48 /* Masks so we can easily check size */ 49 enum CHARMASK = 0xFF; 50 enum SHORTMASK = 0xFFFF; 51 enum INTMASK = SHORTMASK; 52 enum LONGMASK = 0xFFFFFFFF; 53 54 /* Common constants often checked for */ 55 enum LLONGMASK = 0xFFFFFFFFFFFFFFFFL; 56 enum ZEROLL = 0L; 57 58 private __gshared 59 { 60 bool again; 61 bool topair; 62 tym_t global_tyf; 63 } 64 65 private bool cnst(const elem* e) { return e.Eoper == OPconst; } 66 67 /***************************** 68 */ 69 70 @trusted 71 private elem * cgel_lvalue(elem *e) 72 { 73 //printf("cgel_lvalue()\n"); elem_print(e); 74 elem *e1 = e.EV.E1; 75 if (e1.Eoper == OPbit) 76 { 77 elem *e11 = e1.EV.E1; 78 79 if (e11.Eoper == OPcomma) 80 { 81 // Replace (((e,v) bit x) op e2) with (e,((v bit x) op e2)) 82 e1.EV.E1 = e11.EV.E2; 83 e11.EV.E2 = e; 84 e11.Ety = e.Ety; 85 e11.ET = e.ET; 86 e = e11; 87 goto L1; 88 } 89 else if (OTassign(e11.Eoper)) 90 { 91 // Replace (((e op= v) bit x) op e2) with ((e op= v) , ((e bit x) op e2)) 92 e1.EV.E1 = el_copytree(e11.EV.E1); 93 e = el_bin(OPcomma,e.Ety,e11,e); 94 goto L1; 95 } 96 } 97 else if (e1.Eoper == OPcomma) 98 { 99 // Replace ((e,v) op e2) with (e,(v op e2)) 100 const op = e.Eoper; 101 e.Eoper = OPcomma; 102 e1.Eoper = op; 103 e1.Ety = e.Ety; 104 e1.ET = e.ET; 105 e.EV.E1 = e1.EV.E1; 106 e1.EV.E1 = e1.EV.E2; 107 e1.EV.E2 = e.EV.E2; 108 e.EV.E2 = e1; 109 goto L1; 110 } 111 else if (OTassign(e1.Eoper)) 112 { 113 // Replace ((e op= v) op e2) with ((e op= v) , (e op e2)) 114 e.EV.E1 = el_copytree(e1.EV.E1); 115 e = el_bin(OPcomma,e.Ety,e1,e); 116 L1: 117 e = optelem(e,GOALvalue); 118 } 119 return e; 120 } 121 122 123 /****************************** 124 * Scan down commas. 125 */ 126 127 @trusted 128 private elem * elscancommas(elem *e) 129 { 130 while (e.Eoper == OPcomma 131 || e.Eoper == OPinfo 132 ) 133 e = e.EV.E2; 134 return e; 135 } 136 137 /************************* 138 * Returns: 139 * true if elem is the constant 1. 140 */ 141 142 int elemisone(elem *e) 143 { 144 if (e.Eoper == OPconst) 145 { 146 switch (tybasic(e.Ety)) 147 { 148 case TYchar: 149 case TYuchar: 150 case TYschar: 151 case TYchar16: 152 case TYshort: 153 case TYushort: 154 case TYint: 155 case TYuint: 156 case TYlong: 157 case TYulong: 158 case TYllong: 159 case TYullong: 160 case TYnullptr: 161 case TYsptr: 162 case TYcptr: 163 case TYhptr: 164 case TYfptr: 165 case TYvptr: 166 case TYnptr: 167 case TYimmutPtr: 168 case TYsharePtr: 169 case TYrestrictPtr: 170 case TYfgPtr: 171 case TYbool: 172 case TYwchar_t: 173 case TYdchar: 174 if (el_tolong(e) != 1) 175 goto nomatch; 176 break; 177 case TYldouble: 178 case TYildouble: 179 if (e.EV.Vldouble != 1) 180 goto nomatch; 181 break; 182 case TYdouble: 183 case TYidouble: 184 case TYdouble_alias: 185 if (e.EV.Vdouble != 1) 186 goto nomatch; 187 break; 188 case TYfloat: 189 case TYifloat: 190 if (e.EV.Vfloat != 1) 191 goto nomatch; 192 break; 193 default: 194 goto nomatch; 195 } 196 return true; 197 } 198 199 nomatch: 200 return false; 201 } 202 203 /************************* 204 * Returns: true if elem is the constant -1. 205 */ 206 207 int elemisnegone(elem *e) 208 { 209 if (e.Eoper == OPconst) 210 { 211 switch (tybasic(e.Ety)) 212 { 213 case TYchar: 214 case TYuchar: 215 case TYschar: 216 case TYchar16: 217 case TYshort: 218 case TYushort: 219 case TYint: 220 case TYuint: 221 case TYlong: 222 case TYulong: 223 case TYllong: 224 case TYullong: 225 case TYnullptr: 226 case TYnptr: 227 case TYsptr: 228 case TYcptr: 229 case TYhptr: 230 case TYfptr: 231 case TYvptr: 232 case TYimmutPtr: 233 case TYsharePtr: 234 case TYrestrictPtr: 235 case TYfgPtr: 236 case TYbool: 237 case TYwchar_t: 238 case TYdchar: 239 if (el_tolong(e) != -1) 240 goto nomatch; 241 break; 242 case TYldouble: 243 //case TYildouble: 244 if (e.EV.Vldouble != -1) 245 goto nomatch; 246 break; 247 case TYdouble: 248 //case TYidouble: 249 case TYdouble_alias: 250 if (e.EV.Vdouble != -1) 251 goto nomatch; 252 break; 253 case TYfloat: 254 //case TYifloat: 255 if (e.EV.Vfloat != -1) 256 goto nomatch; 257 break; 258 default: 259 goto nomatch; 260 } 261 return true; 262 } 263 264 nomatch: 265 return false; 266 } 267 268 /********************************** 269 * Swap relational operators (like if we swapped the leaves). 270 */ 271 272 OPER swaprel(OPER op) 273 { 274 assert(op < OPMAX); 275 if (OTrel(op)) 276 op = rel_swap(op); 277 return op; 278 } 279 280 /************************** 281 * Replace e1 by t=e1, replace e2 by t. 282 */ 283 284 private void fixside(elem **pe1,elem **pe2) 285 { 286 const tym = (*pe1).Ety; 287 elem *tmp = el_alloctmp(tym); 288 *pe1 = el_bin(OPeq,tym,tmp,*pe1); 289 elem *e2 = el_copytree(tmp); 290 el_free(*pe2); 291 *pe2 = e2; 292 } 293 294 295 296 /**************************** 297 * Compute the 'cost' of evaluating a elem. Could be done 298 * as Sethi-Ullman numbers, but that ain't worth the bother. 299 * We'll fake it. 300 */ 301 302 private int cost(const elem* n) { return opcost[n.Eoper]; } 303 304 /******************************* 305 * For floating point expressions, the cost would be the number 306 * of registers in the FPU stack needed. 307 */ 308 309 @trusted 310 private int fcost(const elem *e) 311 { 312 int cost; 313 314 //printf("fcost()\n"); 315 switch (e.Eoper) 316 { 317 case OPadd: 318 case OPmin: 319 case OPmul: 320 case OPdiv: 321 { 322 const int cost1 = fcost(e.EV.E1); 323 const int cost2 = fcost(e.EV.E2); 324 cost = cost2 + 1; 325 if (cost1 > cost) 326 cost = cost1; 327 break; 328 } 329 330 case OPcall: 331 case OPucall: 332 cost = 8; 333 break; 334 335 case OPneg: 336 case OPabs: 337 case OPtoprec: 338 return fcost(e.EV.E1); 339 340 case OPvar: 341 case OPconst: 342 case OPind: 343 default: 344 return 1; 345 } 346 if (cost > 8) 347 cost = 8; 348 return cost; 349 } 350 351 /******************************* 352 * The lvalue of an op= is a conversion operator. Since the code 353 * generator cannot handle this, we will have to fix it here. The 354 * general strategy is: 355 * (conv) e1 op= e2 => e1 = (conv) e1 op e2 356 * Since e1 can only be evaluated once, if it is an expression we 357 * must use a temporary. 358 */ 359 360 @trusted 361 private elem *fixconvop(elem *e) 362 { 363 static immutable ubyte[CNVOPMAX - CNVOPMIN + 1] invconvtab = 364 [ 365 OPbool, // OPb_8 366 OPs32_d, // OPd_s32 367 OPd_s32, // OPs32_d 368 OPs16_d, /* OPd_s16 */ 369 OPd_s16, /* OPs16_d */ 370 OPu16_d, // OPd_u16 371 OPd_u16, // OPu16_d 372 OPu32_d, /* OPd_u32 */ 373 OPd_u32, /* OPu32_d */ 374 OPs64_d, // OPd_s64 375 OPd_s64, // OPs64_d 376 OPu64_d, // OPd_u64 377 OPd_u64, // OPu64_d 378 OPf_d, // OPd_f 379 OPd_f, // OPf_d 380 OP32_16, // OPs16_32 381 OP32_16, // OPu16_32 382 OPs16_32, // OP32_16 383 OP16_8, // OPu8_16 384 OP16_8, // OPs8_16 385 OPs8_16, // OP16_8 386 OP64_32, // OPu32_64 387 OP64_32, // OPs32_64 388 OPs32_64, // OP64_32 389 OP128_64, // OPu64_128 390 OP128_64, // OPs64_128 391 OPs64_128, // OP128_64 392 393 0, /* OPvp_fp */ 394 0, /* OPcvp_fp */ 395 OPnp_fp, /* OPoffset */ 396 OPoffset, /* OPnp_fp */ 397 OPf16p_np, /* OPnp_f16p */ 398 OPnp_f16p, /* OPf16p_np */ 399 400 OPd_ld, // OPld_d 401 OPld_d, // OPd_ld 402 OPu64_d, // OPld_u64 403 ]; 404 405 //printf("fixconvop before\n"); 406 //elem_print(e); 407 assert(invconvtab.length == CNVOPMAX - CNVOPMIN + 1); 408 assert(e); 409 tym_t tyme = e.Ety; 410 const cop = e.EV.E1.Eoper; /* the conversion operator */ 411 assert(cop <= CNVOPMAX); 412 413 elem *econv = e.EV.E1; 414 while (OTconv(econv.Eoper)) 415 { 416 if (econv.EV.E1.Eoper != OPcomma) 417 { 418 econv = econv.EV.E1; 419 continue; 420 } 421 /* conv(a,b) op= e2 or conv(conv(a,b)) op= e2 422 * => many: => 423 * a, (conv(b) op= e2) a, (conv(conv(b)) op= e2) 424 */ 425 elem *ecomma = econv.EV.E1; 426 econv.EV.E1 = ecomma.EV.E2; 427 econv.EV.E1.Ety = ecomma.Ety; 428 ecomma.EV.E2 = e; 429 ecomma.Ety = e.Ety; 430 //printf("fixconvop comma\n"); 431 //elem_print(ecomma); 432 return optelem(ecomma, GOALvalue); 433 } 434 435 if (e.EV.E1.Eoper == OPd_f && OTconv(e.EV.E1.EV.E1.Eoper) && tyintegral(tyme)) 436 { 437 elem *e1 = e.EV.E1; 438 e.EV.E1 = e1.EV.E1; 439 e.EV.E2 = el_una(OPf_d, e.EV.E1.Ety, e.EV.E2); 440 e1.EV.E1 = null; 441 el_free(e1); 442 return fixconvop(e); 443 } 444 445 tym_t tycop = e.EV.E1.Ety; 446 tym_t tym = e.EV.E1.EV.E1.Ety; 447 e.EV.E1 = el_selecte1(e.EV.E1); /* dump it for now */ 448 elem *e1 = e.EV.E1; 449 e1.Ety = tym; 450 elem *e2 = e.EV.E2; 451 assert(e1 && e2); 452 /* select inverse conversion operator */ 453 const icop = invconvtab[convidx(cop)]; 454 455 /* First, let's see if we can just throw it away. */ 456 /* (unslng or shtlng) e op= e2 => e op= (lngsht) e2 */ 457 if (OTwid(e.Eoper) && 458 (cop == OPs16_32 || cop == OPu16_32 || 459 cop == OPu8_16 || cop == OPs8_16)) 460 { if (e.Eoper != OPshlass && e.Eoper != OPshrass && e.Eoper != OPashrass) 461 e.EV.E2 = el_una(icop,tym,e2); 462 463 // https://issues.dlang.org/show_bug.cgi?id=23618 464 if ((cop == OPu16_32 || cop == OPu8_16) && e.Eoper == OPashrass) 465 e.Eoper = OPshrass; // always unsigned right shift for MARS 466 467 return e; 468 } 469 470 /* Oh well, just split up the op and the =. */ 471 const op = opeqtoop(e.Eoper); // convert op= to op 472 e.Eoper = OPeq; // just plain = 473 elem *ed = el_copytree(e1); // duplicate e1 474 // make: e1 = (icop) ((cop) ed op e2) 475 e.EV.E2 = el_una(icop,e1.Ety, 476 el_bin(op,tycop,el_una(cop,tycop,ed), 477 e2)); 478 479 //printf("after1\n"); 480 //elem_print(e); 481 482 if (op == OPdiv && 483 tybasic(e2.Ety) == TYcdouble) 484 { 485 if (tycop == TYdouble) 486 { 487 e.EV.E2.EV.E1.Ety = tybasic(e2.Ety); 488 e.EV.E2.EV.E1 = el_una(OPc_r, tycop, e.EV.E2.EV.E1); 489 } 490 else if (tycop == TYidouble) 491 { 492 e.EV.E2.EV.E1.Ety = tybasic(e2.Ety); 493 e.EV.E2.EV.E1 = el_una(OPc_i, tycop, e.EV.E2.EV.E1); 494 } 495 } 496 497 if (op == OPdiv && 498 tybasic(e2.Ety) == TYcfloat) 499 { 500 if (tycop == TYfloat) 501 { 502 e.EV.E2.EV.E1.Ety = tybasic(e2.Ety); 503 e.EV.E2.EV.E1 = el_una(OPc_r, tycop, e.EV.E2.EV.E1); 504 } 505 else if (tycop == TYifloat) 506 { 507 e.EV.E2.EV.E1.Ety = tybasic(e2.Ety); 508 e.EV.E2.EV.E1 = el_una(OPc_i, tycop, e.EV.E2.EV.E1); 509 } 510 } 511 512 // Handle case of multiple conversion operators on lvalue 513 // (such as (intdbl 8int char += double)) 514 elem *ex = e; 515 elem **pe = &e; 516 while (OTconv(ed.Eoper)) 517 { 518 const uint copx = ed.Eoper; 519 const uint icopx = invconvtab[convidx(copx)]; 520 tym_t tymx = ex.EV.E1.EV.E1.Ety; 521 ex.EV.E1 = el_selecte1(ex.EV.E1); // dump it for now 522 e1 = ex.EV.E1; 523 e1.Ety = tymx; 524 ex.EV.E2 = el_una(icopx,e1.Ety,ex.EV.E2); 525 ex.Ety = tymx; 526 tym = tymx; 527 528 if (ex.Ety != tyme) 529 { *pe = el_una(copx, ed.Ety, ex); 530 pe = &(*pe).EV.E1; 531 } 532 533 ed = ed.EV.E1; 534 } 535 //printf("after2\n"); 536 //elem_print(e); 537 538 e.Ety = tym; 539 if (tym != tyme && 540 !(tyintegral(tym) && tyintegral(tyme) && tysize(tym) == tysize(tyme))) 541 e = el_una(cop, tyme, e); 542 543 if (ed.Eoper == OPbit) // special handling 544 { 545 ed = ed.EV.E1; 546 e1 = e1.EV.E1; // go down one 547 } 548 549 /* If we have a *, must assign a temporary to the expression 550 * underneath it (even if it's a var, as e2 may modify the var) 551 */ 552 if (ed.Eoper == OPind) 553 { 554 elem *T = el_alloctmp(ed.EV.E1.Ety); // make temporary 555 ed.EV.E1 = el_bin(OPeq,T.Ety,T,ed.EV.E1); // ed: *(T=e) 556 el_free(e1.EV.E1); 557 e1.EV.E1 = el_copytree(T); 558 } 559 //printf("after3\n"); 560 //elem_print(e); 561 return e; 562 } 563 564 private elem * elerr(elem *e, goal_t goal) 565 { 566 debug elem_print(e); 567 assert(0); 568 } 569 570 /* For ops with no optimizations */ 571 572 private elem * elzot(elem *e, goal_t goal) 573 { 574 return e; 575 } 576 577 /**************************** 578 */ 579 580 private elem * elstring(elem *e, goal_t goal) 581 { 582 return e; 583 } 584 585 /************************ 586 */ 587 588 /************************ 589 * Convert far pointer to pointer. 590 */ 591 592 @trusted 593 private void eltonear(elem **pe) 594 { 595 elem *e = *pe; 596 const tym_t ty = e.EV.E1.Ety; 597 e = el_selecte1(e); 598 e.Ety = ty; 599 *pe = optelem(e,GOALvalue); 600 } 601 602 /************************ 603 */ 604 605 @trusted 606 private elem * elstrcpy(elem *e, goal_t goal) 607 { 608 elem_debug(e); 609 switch (e.EV.E2.Eoper) 610 { 611 case OPnp_fp: 612 if (OPTIMIZER) 613 { 614 eltonear(&e.EV.E2); 615 e = optelem(e,GOALvalue); 616 } 617 break; 618 619 case OPstring: 620 /* Replace strcpy(e1,"string") with memcpy(e1,"string",sizeof("string")) */ 621 // As streq 622 e.Eoper = OPstreq; 623 type *t = type_allocn(TYarray, tstypes[TYchar]); 624 t.Tdim = strlen(e.EV.E2.EV.Vstring) + 1; 625 e.ET = t; 626 t.Tcount++; 627 e.EV.E1 = el_una(OPind,TYstruct,e.EV.E1); 628 e.EV.E2 = el_una(OPind,TYstruct,e.EV.E2); 629 630 e = el_bin(OPcomma,e.Ety,e,el_copytree(e.EV.E1.EV.E1)); 631 if (el_sideeffect(e.EV.E2)) 632 fixside(&e.EV.E1.EV.E1.EV.E1,&e.EV.E2); 633 e = optelem(e,GOALvalue); 634 break; 635 636 default: 637 break; 638 } 639 return e; 640 } 641 642 /************************ 643 */ 644 645 @trusted 646 private elem * elstrcmp(elem *e, goal_t goal) 647 { 648 elem_debug(e); 649 if (OPTIMIZER) 650 { 651 if (e.EV.E1.Eoper == OPnp_fp) 652 eltonear(&e.EV.E1); 653 switch (e.EV.E2.Eoper) 654 { 655 case OPnp_fp: 656 eltonear(&e.EV.E2); 657 break; 658 659 case OPstring: 660 // Replace strcmp(e1,"string") with memcmp(e1,"string",sizeof("string")) 661 e.Eoper = OPparam; 662 e = el_bin(OPmemcmp,e.Ety,e,el_long(TYint,strlen(e.EV.E2.EV.Vstring) + 1)); 663 e = optelem(e,GOALvalue); 664 break; 665 666 default: 667 break; 668 } 669 } 670 return e; 671 } 672 673 /**************************** 674 * For OPmemcmp 675 * memcmp(a, b, nbytes) => ((a param b) OPmemcmp nbytes) 676 */ 677 @trusted 678 679 private elem * elmemcmp(elem *e, goal_t goal) 680 { 681 elem_debug(e); 682 if (!OPTIMIZER) 683 return e; 684 685 /* Hoist comma operators in `a` out of OPmemcmp 686 */ 687 { 688 elem* ec = e.EV.E1.EV.E1; 689 if (ec.Eoper == OPcomma) 690 { 691 /* Rewrite: (((a,b) param c) OPmemcmp nbytes) 692 * As: a,((b param c) OPmemcmp nbytes) 693 */ 694 e.EV.E1.EV.E1 = ec.EV.E2; 695 e.EV.E1.EV.E1.Ety = ec.Ety; 696 e.EV.E1.EV.E1.ET = ec.ET; 697 ec.EV.E2 = e; 698 ec.Ety = e.Ety; 699 return optelem(ec, goal); 700 } 701 } 702 703 /* Hoist comma operators in `b` out of OPmemcmp 704 */ 705 { 706 elem* ec = e.EV.E1.EV.E2; 707 if (ec.Eoper == OPcomma) 708 { 709 /* Have: ((a param (b,c)) OPmemcmp nbytes) 710 */ 711 elem* a = e.EV.E1.EV.E1; 712 elem* b = ec.EV.E1; 713 if (a.canHappenAfter(b)) 714 { 715 /* Rewrite: ((a param (b,c)) OPmemcmp nbytes) 716 * As: b,((a param c) OPmemcmp nbytes) 717 */ 718 e.EV.E1.EV.E2 = ec.EV.E2; 719 e.EV.E1.EV.E2.Ety = ec.Ety; 720 e.EV.E1.EV.E2.ET = ec.ET; 721 ec.EV.E2 = e; 722 ec.Ety = e.Ety; 723 return optelem(ec, goal); 724 } 725 } 726 } 727 728 elem *ex = e.EV.E1; 729 if (ex.EV.E1.Eoper == OPnp_fp) 730 eltonear(&ex.EV.E1); 731 if (ex.EV.E2.Eoper == OPnp_fp) 732 eltonear(&ex.EV.E2); 733 734 return e; 735 } 736 737 /**************************** 738 * For OPmemset 739 */ 740 741 @trusted 742 private elem * elmemset(elem *e, goal_t goal) 743 { 744 //printf("elmemset()\n"); 745 elem_debug(e); 746 747 elem *ex = e.EV.E1; 748 if (ex.Eoper == OPnp_fp) 749 { 750 eltonear(&ex); 751 return e; 752 } 753 754 // lvalue OPmemset (nelems param value) 755 elem *enelems = e.EV.E2.EV.E1; 756 elem *evalue = e.EV.E2.EV.E2; 757 758 if (!(enelems.Eoper == OPconst && evalue.Eoper == OPconst && REGSIZE >= 4)) 759 return e; 760 761 elem *e1 = e.EV.E1; 762 763 if (e1.Eoper == OPcomma || OTassign(e1.Eoper)) 764 return cgel_lvalue(e); // replace ((e,v) memset e2) with (e,(v memset e2)) 765 766 /* Attempt to replace OPmemset with a sequence of ordinary assignments, 767 * so cdmemset() will have fewer cases to deal with 768 */ 769 770 const sz = tysize(evalue.Ety); 771 int nelems = cast(int)el_tolong(enelems); 772 ulong value = el_tolong(evalue); 773 774 if (sz * nelems > REGSIZE * 4) 775 return e; 776 777 switch (sz) 778 { 779 case 1: value = 0x0101_0101_0101_0101 * (value & 0xFF); break; 780 case 2: value = 0x0001_0001_0001_0001 * (value & 0xFFFF); break; 781 case 4: value = 0x0000_0001_0000_0001 * (value & 0xFFFFFFFF); break; 782 case 8: break; 783 default: 784 return e; 785 } 786 787 ulong valuexor = 0; 788 if (sz == 8 && REGSIZE == 4) 789 valuexor = (value ^ (value >> 32)) & 0xFFFF_FFFF; 790 791 elem* ey = null; 792 if (e1.Eoper != OPrelconst) 793 { 794 ey = e1; 795 e1 = el_same(&ey); 796 } 797 e.EV.E1 = null; // so we can free e later 798 799 for (int offset = 0; offset < sz * nelems; ) 800 { 801 int left = sz * nelems - offset; 802 if (left > REGSIZE) 803 left = REGSIZE; 804 tym_t tyv; 805 switch (left) 806 { 807 case 0: assert(0); 808 case 1: tyv = TYchar; left = 1; break; 809 case 2: 810 case 3: tyv = TYshort; left = 2; break; 811 case 4: 812 case 5: 813 case 6: 814 case 7: tyv = TYlong; left = 4; break; 815 default: 816 case 8: tyv = TYllong; left = 8; break; 817 } 818 auto e1a = el_copytree(e1); 819 assert(tybasic(e1a.Ety) != TYstruct); 820 e1a = el_bin(OPadd, TYnptr, e1a, el_long(TYsize_t, offset)); 821 e1a = el_una(OPind, tyv, e1a); 822 auto ea = el_bin(OPeq, tyv, e1a, el_long(tyv, value)); 823 if (sz * nelems - offset >= REGSIZE) 824 value ^= valuexor; // flip between low and high 32 bits of 8 byte value 825 offset += left; 826 ey = el_combine(ey, ea); 827 } 828 ey = el_combine(ey, e1); 829 el_free(e); 830 e = optelem(ey,GOALvalue); 831 return e; 832 } 833 834 835 /**************************** 836 * For OPmemcpy 837 * OPmemcpy 838 * / \ 839 * s1 OPparam 840 * / \ 841 * s2 n 842 */ 843 844 @trusted 845 private elem * elmemcpy(elem *e, goal_t goal) 846 { 847 elem_debug(e); 848 if (OPTIMIZER) 849 { 850 elem *ex = e.EV.E1; 851 if (ex.Eoper == OPnp_fp) 852 eltonear(&e.EV.E1); 853 ex = e.EV.E2; 854 if (ex.EV.E1.Eoper == OPnp_fp) 855 eltonear(&ex.EV.E1); 856 if (ex.EV.E2.Eoper == OPconst) 857 { 858 if (!boolres(ex.EV.E2)) 859 { // Copying 0 bytes, so remove memcpy 860 e.EV.E2 = e.EV.E1; 861 e.EV.E1 = ex.EV.E1; 862 ex.EV.E1 = null; 863 e.Eoper = OPcomma; 864 el_free(ex); 865 return optelem(e, GOALvalue); 866 } 867 // Convert OPmemcpy to OPstreq 868 e.Eoper = OPstreq; 869 type *t = type_allocn(TYarray, tstypes[TYchar]); 870 t.Tdim = cast(uint)el_tolong(ex.EV.E2); 871 e.ET = t; 872 t.Tcount++; 873 e.EV.E1 = el_una(OPind,TYstruct,e.EV.E1); 874 e.EV.E2 = el_una(OPind,TYstruct,ex.EV.E1); 875 ex.EV.E1 = null; 876 el_free(ex); 877 ex = el_copytree(e.EV.E1.EV.E1); 878 if (tysize(e.Ety) > tysize(ex.Ety)) 879 ex = el_una(OPnp_fp,e.Ety,ex); 880 e = el_bin(OPcomma,e.Ety,e,ex); 881 if (el_sideeffect(e.EV.E2)) 882 fixside(&e.EV.E1.EV.E1.EV.E1,&e.EV.E2); 883 return optelem(e,GOALvalue); 884 } 885 886 /+ The following fails the autotester for Linux32 and FreeBSD32 887 + for unknown reasons I cannot reproduce 888 // Convert to memcpy(s1, s2, n) 889 elem* ep = el_params(e.EV.E2.EV.E2, e.EV.E2.EV.E1, e.EV.E1, null); 890 const ty = e.Ety; 891 e.EV.E1 = null; 892 e.EV.E2.EV.E1 = null; 893 e.EV.E2.EV.E2 = null; 894 el_free(e); 895 e = el_bin(OPcall, ty, el_var(getRtlsym(RTLSYM.MEMCPY)), ep); 896 +/ 897 } 898 return e; 899 } 900 901 902 /*********************** 903 * + # (combine offsets with addresses) 904 * / \ => | 905 * # c v,c 906 * | 907 * v 908 */ 909 910 @trusted 911 private elem * eladd(elem *e, goal_t goal) 912 { 913 //printf("eladd(%p)\n",e); 914 targ_size_t ptrmask = ~cast(targ_size_t)0; 915 if (_tysize[TYnptr] <= 4) 916 ptrmask = 0xFFFFFFFF; 917 L1: 918 elem *e1 = e.EV.E1; 919 elem *e2 = e.EV.E2; 920 if (e2.Eoper == OPconst) 921 { 922 if (e1.Eoper == OPrelconst && e1.EV.Vsym.Sfl == FLgot) 923 return e; 924 if (e1.Eoper == OPrelconst || // if (&v) + c 925 e1.Eoper == OPstring) 926 { 927 e1.EV.Voffset += e2.EV.Vpointer; 928 e1.EV.Voffset &= ptrmask; 929 e = el_selecte1(e); 930 return e; 931 } 932 } 933 else if (e1.Eoper == OPconst) 934 { 935 if (e2.Eoper == OPrelconst && e2.EV.Vsym.Sfl == FLgot) 936 return e; 937 if (e2.Eoper == OPrelconst || // if c + (&v) 938 e2.Eoper == OPstring) 939 { 940 e2.EV.Voffset += e1.EV.Vpointer; 941 e2.EV.Voffset &= ptrmask; 942 e = el_selecte2(e); 943 return e; 944 } 945 } 946 947 if (!OPTIMIZER) 948 return e; 949 950 // Replace ((e + &v) + c) with (e + (&v+c)) 951 if (e2.Eoper == OPconst && e1.Eoper == OPadd && 952 (e1.EV.E2.Eoper == OPrelconst || e1.EV.E2.Eoper == OPstring)) 953 { 954 e1.EV.E2.EV.Voffset += e2.EV.Vpointer; 955 e1.EV.E2.EV.Voffset &= ptrmask; 956 e = el_selecte1(e); 957 goto L1; 958 } 959 // Replace ((e + c) + &v) with (e + (&v+c)) 960 else if ((e2.Eoper == OPrelconst || e2.Eoper == OPstring) && 961 e1.Eoper == OPadd && cnst(e1.EV.E2)) 962 { 963 e2.EV.Voffset += e1.EV.E2.EV.Vpointer; 964 e2.EV.Voffset &= ptrmask; 965 e.EV.E1 = el_selecte1(e1); 966 goto L1; /* try and find some more */ 967 } 968 // Replace (e1 + -e) with (e1 - e) 969 else if (e2.Eoper == OPneg) 970 { 971 e.EV.E2 = el_selecte1(e2); 972 e.Eoper = OPmin; 973 again = 1; 974 return e; 975 } 976 // Replace (-v + e) with (e + -v) 977 else if (e1.Eoper == OPneg && OTleaf(e1.EV.E1.Eoper)) 978 { 979 e.EV.E1 = e2; 980 e.EV.E2 = e1; /* swap leaves */ 981 goto L1; 982 } 983 /* Replace ((e - e2) + e2) with (e) 984 * The optimizer sometimes generates this case 985 */ 986 else if (!tyfloating(e.Ety) && /* no floating bugs */ 987 e1.Eoper == OPmin && 988 el_match(e1.EV.E2,e2) && 989 !el_sideeffect(e2)) 990 { 991 tym_t tym = e.Ety; 992 e = el_selecte1(el_selecte1(e)); 993 e.Ety = tym; /* retain original type */ 994 return e; 995 } 996 // Replace ((e - #v+c1) + #v+c2) with ((e - c1) + c2) 997 else if (e2.Eoper == OPrelconst && 998 e1.Eoper == OPmin && 999 e1.EV.E2.Eoper == OPrelconst && 1000 e1.EV.E2.EV.Vsym == e2.EV.Vsym) 1001 { 1002 e2.Eoper = OPconst; 1003 e2.Ety = TYint; 1004 e1.Ety = e1.EV.E1.Ety; 1005 e1.EV.E2.Eoper = OPconst; 1006 e1.EV.E2.Ety = TYint; 1007 { 1008 /* Watch out for pointer types changing, requiring a conversion */ 1009 tym_t ety = tybasic(e.Ety); 1010 tym_t e11ty = tybasic(e1.EV.E1.Ety); 1011 if (typtr(ety) && typtr(e11ty) && 1012 _tysize[ety] != _tysize[e11ty]) 1013 { 1014 e = el_una((_tysize[ety] > _tysize[e11ty]) ? OPnp_fp : OPoffset, 1015 e.Ety,e); 1016 e.EV.E1.Ety = e1.Ety; 1017 } 1018 } 1019 again = 1; 1020 return e; 1021 } 1022 // Replace (e + e) with (e * 2) 1023 else if (el_match(e1,e2) && !el_sideeffect(e1) && !tyfloating(e1.Ety) && 1024 !tyvector(e1.Ety)) // not all CPUs support XMM multiply 1025 { 1026 e.Eoper = OPmul; 1027 el_free(e2); 1028 e.EV.E2 = el_long(e1.Ety,2); 1029 again = 1; 1030 return e; 1031 } 1032 1033 // Replace ((e11 + c) + e2) with ((e11 + e2) + c) 1034 if (e1.Eoper == OPadd && e1.EV.E2.Eoper == OPconst && 1035 (e2.Eoper == OPvar || !OTleaf(e2.Eoper)) && 1036 tysize(e1.Ety) == tysize(e2.Ety) && 1037 tysize(e1.EV.E2.Ety) == tysize(e2.Ety)) 1038 { 1039 e.EV.E2 = e1.EV.E2; 1040 e1.EV.E2 = e2; 1041 e1.Ety = e.Ety; 1042 return e; 1043 } 1044 1045 // Replace (~e1 + 1) with (-e1) 1046 if (e1.Eoper == OPcom && e2.Eoper == OPconst && el_tolong(e2) == 1) 1047 { 1048 e = el_selecte1(e); 1049 e.Eoper = OPneg; 1050 e = optelem(e, goal); 1051 return e; 1052 } 1053 1054 // Replace ((e11 - e12) + e2) with ((e11 + e2) - e12) 1055 // (this should increase the number of LEA possibilities) 1056 int sz = tysize(e.Ety); 1057 if (e1.Eoper == OPmin && 1058 tysize(e1.Ety) == sz && 1059 tysize(e2.Ety) == sz && 1060 tysize(e1.EV.E1.Ety) == sz && 1061 tysize(e1.EV.E2.Ety) == sz && 1062 !tyfloating(e.Ety) 1063 ) 1064 { 1065 e.Eoper = OPmin; 1066 e.EV.E2 = e1.EV.E2; 1067 e1.EV.E2 = e2; 1068 e1.Eoper = OPadd; 1069 } 1070 1071 return e; 1072 } 1073 1074 1075 /************************ 1076 * Multiply (for OPmul && OPmulass) 1077 * e * (c**2) => e << c ;replace multiply by power of 2 with shift 1078 */ 1079 1080 @trusted 1081 private elem * elmul(elem *e, goal_t goal) 1082 { 1083 tym_t tym = e.Ety; 1084 1085 if (OPTIMIZER) 1086 { 1087 // Replace -a*-b with a*b. 1088 // This is valid for all floating point types as well as integers. 1089 if (tyarithmetic(tym) && e.EV.E2.Eoper == OPneg && e.EV.E1.Eoper == OPneg) 1090 { 1091 e.EV.E1 = el_selecte1(e.EV.E1); 1092 e.EV.E2 = el_selecte1(e.EV.E2); 1093 } 1094 } 1095 1096 elem *e2 = e.EV.E2; 1097 if (e2.Eoper == OPconst) // try to replace multiplies with shifts 1098 { 1099 if (OPTIMIZER) 1100 { 1101 elem *e1 = e.EV.E1; 1102 uint op1 = e1.Eoper; 1103 1104 if (tyintegral(tym) && // skip floating types 1105 OTbinary(op1) && 1106 e1.EV.E2.Eoper == OPconst 1107 ) 1108 { 1109 /* Attempt to replace ((e + c1) * c2) with (e * c2 + (c1 * c2)) 1110 * because the + can be frequently folded out (merged into an 1111 * array offset, for example. 1112 */ 1113 if (op1 == OPadd) 1114 { 1115 e.Eoper = OPadd; 1116 e1.Eoper = OPmul; 1117 e.EV.E2 = el_bin(OPmul,tym,e1.EV.E2,e2); 1118 e1.EV.E2 = el_copytree(e2); 1119 again = 1; 1120 return e; 1121 } 1122 1123 // ((e << c1) * c2) => e * ((1 << c1) * c2) 1124 if (op1 == OPshl) 1125 { 1126 e2.EV.Vullong *= cast(targ_ullong)1 << el_tolong(e1.EV.E2); 1127 e1.EV.E2.EV.Vullong = 0; 1128 again = 1; 1129 return e; 1130 } 1131 } 1132 1133 if (elemisnegone(e2)) 1134 { 1135 e.Eoper = (e.Eoper == OPmul) ? OPneg : OPnegass; 1136 e.EV.E2 = null; 1137 el_free(e2); 1138 return e; 1139 } 1140 } 1141 1142 if (tyintegral(tym) && !tyvector(tym)) 1143 { 1144 int i = ispow2(el_tolong(e2)); // check for power of 2 1145 if (i != -1) // if it is a power of 2 1146 { e2.EV.Vint = i; 1147 e2.Ety = TYint; 1148 e.Eoper = (e.Eoper == OPmul) /* convert to shift left */ 1149 ? OPshl : OPshlass; 1150 again = 1; 1151 return e; 1152 } 1153 else if (el_allbits(e2,-1)) 1154 goto Lneg; 1155 } 1156 else if (elemisnegone(e2) && !tycomplex(e.EV.E1.Ety)) 1157 { 1158 goto Lneg; 1159 } 1160 } 1161 return e; 1162 1163 Lneg: 1164 e.Eoper = (e.Eoper == OPmul) /* convert to negate */ 1165 ? OPneg : OPnegass; 1166 el_free(e.EV.E2); 1167 e.EV.E2 = null; 1168 again = 1; 1169 return e; 1170 } 1171 1172 /************************ 1173 * Subtract 1174 * - + 1175 * / \ => / \ (propagate minuses) 1176 * e c e -c 1177 */ 1178 1179 @trusted 1180 private elem * elmin(elem *e, goal_t goal) 1181 { 1182 elem *e2 = e.EV.E2; 1183 1184 if (OPTIMIZER) 1185 { 1186 tym_t tym = e.Ety; 1187 elem *e1 = e.EV.E1; 1188 if (e2.Eoper == OPrelconst) 1189 { 1190 if (e1.Eoper == OPrelconst && e1.EV.Vsym == e2.EV.Vsym) 1191 { 1192 e.Eoper = OPconst; 1193 e.EV.Vllong = e1.EV.Voffset - e2.EV.Voffset; 1194 el_free(e1); 1195 el_free(e2); 1196 return e; 1197 } 1198 } 1199 1200 // Convert subtraction of long pointers to subtraction of integers 1201 if (tyfv(e2.Ety) && tyfv(e1.Ety)) 1202 { 1203 e.EV.E1 = el_una(OP32_16,tym,e1); 1204 e.EV.E2 = el_una(OP32_16,tym,e2); 1205 return optelem(e,GOALvalue); 1206 } 1207 1208 // Replace (0 - e2) with (-e2) 1209 if (cnst(e1) && !boolres(e1) && 1210 !(tycomplex(tym) && !tycomplex(e1.Ety) && !tycomplex(e2.Ety)) && 1211 !tyvector(e1.Ety) 1212 ) 1213 { 1214 e.EV.E1 = e2; 1215 e.EV.E2 = null; 1216 e.Eoper = OPneg; 1217 el_free(e1); 1218 return optelem(e,GOALvalue); 1219 } 1220 1221 // Replace (e - e) with (0) 1222 if (el_match(e1,e2) && !el_sideeffect(e1)) 1223 { 1224 el_free(e); 1225 e = el_calloc(); 1226 e.Eoper = OPconst; 1227 e.Ety = tym; 1228 return e; 1229 } 1230 1231 // Replace ((e1 + c) - e2) with ((e1 - e2) + c), but not 1232 // for floating or far or huge pointers! 1233 if (e1.Eoper == OPadd && 1234 cnst(e1.EV.E2) && 1235 (tyintegral(tym) || 1236 tybasic(tym) == TYnptr || 1237 tybasic(tym) == TYsptr || 1238 tybasic(tym) == TYfgPtr || 1239 tybasic(tym) == TYimmutPtr || 1240 tybasic(tym) == TYrestrictPtr || 1241 tybasic(tym) == TYsharePtr) 1242 ) 1243 { 1244 e.Eoper = OPadd; 1245 e1.Eoper = OPmin; 1246 elem* c = e1.EV.E2; 1247 e1.EV.E2 = e2; 1248 e.EV.E2 = c; 1249 return optelem(e,GOALvalue); 1250 } 1251 1252 // Replace (e1 + c1) - (e2 + c2) with (e1 - e2) + (c1 - c2), but not 1253 // for floating or far or huge pointers! 1254 if (e1.Eoper == OPadd && e2.Eoper == OPadd && 1255 cnst(e1.EV.E2) && cnst(e2.EV.E2) && 1256 (tyintegral(tym) || 1257 tybasic(tym) == TYnptr || 1258 tybasic(tym) == TYsptr || 1259 tybasic(tym) == TYfgPtr || 1260 tybasic(tym) == TYimmutPtr || 1261 tybasic(tym) == TYrestrictPtr || 1262 tybasic(tym) == TYsharePtr) 1263 ) 1264 { 1265 e.Eoper = OPadd; 1266 e1.Eoper = OPmin; 1267 e2.Eoper = OPmin; 1268 elem *tmp = e1.EV.E2; 1269 e1.EV.E2 = e2.EV.E1; 1270 e2.EV.E1 = tmp; 1271 return optelem(e,GOALvalue); 1272 } 1273 1274 // Replace (-e1 - 1) with (~e1) 1275 if (e1.Eoper == OPneg && e2.Eoper == OPconst && tyintegral(tym) && el_tolong(e2) == 1) 1276 { 1277 e = el_selecte1(e); 1278 e.Eoper = OPcom; 1279 e = optelem(e, goal); 1280 return e; 1281 } 1282 1283 // Replace (-1 - e2) with (~e2) 1284 if (e1.Eoper == OPconst && tyintegral(tym) && !tyvector(tym) && el_tolong(e1) == -1) 1285 { 1286 el_free(e1); 1287 e.EV.E1 = e.EV.E2; 1288 e.EV.E2 = null; 1289 e.Eoper = OPcom; 1290 e = optelem(e, goal); 1291 return e; 1292 } 1293 1294 /* Replace e1 - (v * c) with e1 + (v * -c) 1295 */ 1296 if (e2.Eoper == OPmul && 1297 e2.EV.E2.Eoper == OPconst) 1298 { 1299 e.Eoper = OPadd; 1300 e2.EV.E2 = el_una(OPneg, e2.EV.E2.Ety, e2.EV.E2); 1301 return optelem(e, goal); 1302 } 1303 } 1304 1305 if (I16 && tybasic(e2.Ety) == TYhptr && tybasic(e.EV.E1.Ety) == TYhptr) 1306 { // Convert to _aNahdiff(e1,e2) 1307 __gshared Symbol *hdiff; 1308 if (!hdiff) 1309 { 1310 Symbol *s = symbol_calloc(LARGECODE ? "_aFahdiff" : "_aNahdiff"); 1311 s.Stype = tsclib; 1312 s.Sclass = SC.extern_; 1313 s.Sfl = FLfunc; 1314 s.Ssymnum = 0; 1315 s.Sregsaved = mBX|mCX|mSI|mDI|mBP|mES; 1316 hdiff = s; 1317 } 1318 e.Eoper = OPcall; 1319 e.EV.E2 = el_bin(OPparam,TYint,e2,e.EV.E1); 1320 e.EV.E1 = el_var(hdiff); 1321 return e; 1322 } 1323 1324 /* Disallow the optimization on doubles. The - operator is not 1325 * rearrangable by K+R, and can cause floating point problems if 1326 * converted to an add ((a + 1.0) - 1.0 shouldn't be folded). 1327 */ 1328 if (cnst(e2) && !tyfloating(e2.Ety) && 1329 !tyvector(e2.Ety)) // don't do vectors until we get constant folding for them 1330 { 1331 e.EV.E2 = el_una(OPneg,e2.Ety,e2); 1332 e.Eoper = OPadd; 1333 return optelem(e,GOALvalue); 1334 } 1335 return e; 1336 } 1337 1338 /***************************** 1339 * OPand,OPor,OPxor 1340 * This should be expanded to include long type stuff. 1341 */ 1342 1343 @trusted 1344 private elem * elbitwise(elem *e, goal_t goal) 1345 { 1346 //printf("elbitwise(e = %p, goal = x%x)\n", e, goal); 1347 1348 elem *e2 = e.EV.E2; 1349 elem *e1 = e.EV.E1; 1350 const op = e1.Eoper; 1351 uint sz = tysize(e2.Ety); 1352 1353 if (e2.Eoper == OPconst) 1354 { 1355 switch (sz) 1356 { 1357 case CHARSIZE: 1358 /* Replace (c & 0xFF) with (c) */ 1359 if (OPTIMIZER && e2.EV.Vuchar == CHARMASK) 1360 { 1361 L1: 1362 switch (e.Eoper) 1363 { case OPand: /* (c & 0xFF) => (c) */ 1364 return el_selecte1(e); 1365 case OPor: /* (c | 0xFF) => (0xFF) */ 1366 return el_selecte2(e); 1367 case OPxor: /* (c ^ 0xFF) => (~c) */ 1368 return el_una(OPcom,e.Ety,el_selecte1(e)); 1369 default: 1370 assert(0); 1371 } 1372 } 1373 break; 1374 1375 case LONGSIZE: 1376 { 1377 if (!OPTIMIZER) 1378 break; 1379 targ_ulong ul = e2.EV.Vulong; 1380 1381 if (ul == 0xFFFFFFFF) /* if e1 & 0xFFFFFFFF */ 1382 goto L1; 1383 /* (x >> 16) & 0xFFFF => (cast(uint)x >> 16) */ 1384 if (ul == 0xFFFF && e.Eoper == OPand && (op == OPshr || op == OPashr) && 1385 e1.EV.E2.Eoper == OPconst && el_tolong(e1.EV.E2) == 16) 1386 { 1387 elem *e11 = e1.EV.E1; 1388 e11.Ety = touns(e11.Ety) | (e11.Ety & ~mTYbasic); 1389 goto L1; 1390 } 1391 1392 /* Replace (L & 0x0000XXXX) with (unslng)((lngsht) & 0xXXXX) */ 1393 if (_tysize[TYint] < LONGSIZE && 1394 e.Eoper == OPand && 1395 ul <= SHORTMASK) 1396 { 1397 tym_t tym = e.Ety; 1398 e.EV.E1 = el_una(OP32_16,TYushort,e.EV.E1); 1399 e.EV.E2 = el_una(OP32_16,TYushort,e.EV.E2); 1400 e.Ety = TYushort; 1401 e = el_una(OPu16_32,tym,e); 1402 goto Lopt; 1403 } 1404 1405 // Replace ((s8sht)L & 0xFF) with (u8sht)L 1406 if (ul == 0xFF && _tysize[TYint] == LONGSIZE && e.Eoper == OPand && 1407 (op == OPs8_16 || op == OPu8_16) 1408 ) 1409 { 1410 e1.Eoper = OPu8_16; 1411 e = el_selecte1(e); 1412 goto Lopt; 1413 } 1414 break; 1415 } 1416 1417 case SHORTSIZE: 1418 { 1419 targ_short i = e2.EV.Vshort; 1420 if (i == cast(targ_short)SHORTMASK) // e2 & 0xFFFF 1421 goto L1; 1422 1423 /* (x >> 8) & 0xFF => ((uint short)x >> 8) */ 1424 if (OPTIMIZER && i == 0xFF && e.Eoper == OPand && 1425 (op == OPshr || op == OPashr) && e1.EV.E2.Eoper == OPconst && e1.EV.E2.EV.Vint == 8) 1426 { 1427 elem *e11 = e1.EV.E1; 1428 e11.Ety = touns(e11.Ety) | (e11.Ety & ~mTYbasic); 1429 goto L1; 1430 } 1431 1432 // (s8_16(e) & 0xFF) => u8_16(e) 1433 if (OPTIMIZER && op == OPs8_16 && e.Eoper == OPand && 1434 i == 0xFF) 1435 { 1436 e1.Eoper = OPu8_16; 1437 e = el_selecte1(e); 1438 goto Lopt; 1439 } 1440 1441 if ( 1442 /* OK for uint if AND or high bits of i are 0 */ 1443 op == OPu8_16 && (e.Eoper == OPand || !(i & ~0xFF)) || 1444 /* OK for signed if i is 'sign-extended' */ 1445 op == OPs8_16 && cast(targ_short)cast(targ_schar)i == i 1446 ) 1447 { 1448 /* Convert ((u8int) e) & i) to (u8int)(e & (int8) i) */ 1449 /* or similar for s8int */ 1450 e = el_una(e1.Eoper,e.Ety,e); 1451 e.EV.E1.Ety = e1.Ety = e1.EV.E1.Ety; 1452 e.EV.E1.EV.E1 = el_selecte1(e1); 1453 e.EV.E1.EV.E2 = el_una(OP16_8,e.EV.E1.Ety,e.EV.E1.EV.E2); 1454 goto Lopt; 1455 } 1456 break; 1457 } 1458 1459 case LLONGSIZE: 1460 if (OPTIMIZER) 1461 { 1462 if (e2.EV.Vullong == LLONGMASK) 1463 goto L1; 1464 } 1465 break; 1466 1467 default: 1468 break; 1469 } 1470 if (OPTIMIZER && sz < 16) 1471 { 1472 targ_ullong ul = el_tolong(e2); 1473 1474 if (e.Eoper == OPor && op == OPand && e1.EV.E2.Eoper == OPconst) 1475 { 1476 // ((x & c1) | c2) => (x | c2) 1477 targ_ullong c3; 1478 1479 c3 = ul | e1.EV.E2.EV.Vullong; 1480 switch (sz) 1481 { 1482 case CHARSIZE: 1483 if ((c3 & CHARMASK) == CHARMASK) 1484 goto L2; 1485 break; 1486 1487 case SHORTSIZE: 1488 if ((c3 & SHORTMASK) == SHORTMASK) 1489 goto L2; 1490 break; 1491 1492 case LONGSIZE: 1493 if ((c3 & LONGMASK) == LONGMASK) 1494 { 1495 L2: 1496 e1.EV.E2.EV.Vullong = c3; 1497 e.EV.E1 = elbitwise(e1, GOALvalue); 1498 goto Lopt; 1499 } 1500 break; 1501 1502 case LLONGSIZE: 1503 if ((c3 & LLONGMASK) == LLONGMASK) 1504 goto L2; 1505 break; 1506 1507 default: 1508 assert(0); 1509 } 1510 } 1511 1512 if (op == OPs16_32 && (ul & 0xFFFFFFFFFFFF8000L) == 0 || 1513 op == OPu16_32 && (ul & 0xFFFFFFFFFFFF0000L) == 0 || 1514 op == OPs8_16 && (ul & 0xFFFFFFFFFFFFFF80L) == 0 || 1515 op == OPu8_16 && (ul & 0xFFFFFFFFFFFFFF00L) == 0 || 1516 op == OPs32_64 && (ul & 0xFFFFFFFF80000000L) == 0 || 1517 op == OPu32_64 && (ul & 0xFFFFFFFF00000000L) == 0 1518 ) 1519 { 1520 if (e.Eoper == OPand) 1521 { 1522 if (op == OPs16_32 && (ul & 0x8000) == 0) 1523 e1.Eoper = OPu16_32; 1524 else if (op == OPs8_16 && (ul & 0x80) == 0) 1525 e1.Eoper = OPu8_16; 1526 else if (op == OPs32_64 && (ul & 0x80000000) == 0) 1527 e1.Eoper = OPu32_64; 1528 } 1529 1530 // ((shtlng)s & c) => ((shtlng)(s & c) 1531 e1.Ety = e.Ety; 1532 e.Ety = e2.Ety = e1.EV.E1.Ety; 1533 e.EV.E1 = e1.EV.E1; 1534 e1.EV.E1 = e; 1535 e = e1; 1536 goto Lopt; 1537 } 1538 1539 // Replace (((a & b) ^ c) & d) with ((a ^ c) & e), where 1540 // e is (b&d). 1541 if (e.Eoper == OPand && op == OPxor && e1.EV.E1.Eoper == OPand && 1542 e1.EV.E1.EV.E2.Eoper == OPconst) 1543 { 1544 e2.EV.Vullong &= e1.EV.E1.EV.E2.EV.Vullong; 1545 e1.EV.E1 = el_selecte1(e1.EV.E1); 1546 goto Lopt; 1547 } 1548 1549 // Replace ((a >> b) & 1) with (a btst b) 1550 if ((I32 || I64) && 1551 e.Eoper == OPand && 1552 ul == 1 && 1553 (e.EV.E1.Eoper == OPshr || e.EV.E1.Eoper == OPashr) && 1554 sz <= REGSIZE && 1555 tysize(e1.Ety) >= 2 // BT doesn't work on byte operands 1556 ) 1557 { 1558 e.EV.E1.Eoper = OPbtst; 1559 e = el_selecte1(e); 1560 goto Lopt; 1561 } 1562 } 1563 } 1564 1565 if (OPTIMIZER && goal & GOALflags && (I32 || I64) && e.Eoper == OPand && 1566 (sz == 4 || sz == 8)) 1567 { 1568 /* These should all compile to a BT instruction when -O, for -m32 and -m64 1569 * int bt32(uint *p, uint b) { return ((p[b >> 5] & (1 << (b & 0x1F)))) != 0; } 1570 * int bt64a(ulong *p, uint b) { return ((p[b >> 6] & (1L << (b & 63)))) != 0; } 1571 * int bt64b(ulong *p, size_t b) { return ((p[b >> 6] & (1L << (b & 63)))) != 0; } 1572 */ 1573 1574 static bool ELCONST(elem* e, long c) { return e.Eoper == OPconst && el_tolong(e) == c; } 1575 int pow2sz = ispow2(sz); 1576 1577 if (e1.Eoper == OPind) 1578 { // Swap e1 and e2 so that e1 is the mask and e2 is the memory location 1579 e2 = e1; 1580 e1 = e.EV.E2; 1581 } 1582 1583 /* Replace: 1584 * ((1 << (b & 31)) & *(((b >>> 5) << 2) + p) 1585 * with: 1586 * p bt b 1587 */ 1588 elem *e12; // the (b & 31), which may be preceded by (64_32) 1589 elem *e2111; // the (b >>> 5), which may be preceded by (u32_64) 1590 if (e1.Eoper == OPshl && 1591 ELCONST(e1.EV.E1,1) && 1592 (((e12 = e1.EV.E2).Eoper == OP64_32 ? (e12 = e12.EV.E1) : e12).Eoper == OPand) && 1593 ELCONST(e12.EV.E2,sz * 8 - 1) && 1594 tysize(e12.Ety) <= sz && 1595 1596 e2.Eoper == OPind && 1597 e2.EV.E1.Eoper == OPadd && 1598 e2.EV.E1.EV.E1.Eoper == OPshl && 1599 ELCONST(e2.EV.E1.EV.E1.EV.E2,pow2sz) && 1600 (((e2111 = e2.EV.E1.EV.E1.EV.E1).Eoper == OPu32_64 ? (e2111 = e2111.EV.E1) : e2111).Eoper == OPshr) && 1601 ELCONST(e2111.EV.E2,pow2sz + 3) 1602 ) 1603 { 1604 elem **pb1 = &e12.EV.E1; 1605 elem **pb2 = &e2111.EV.E1; 1606 elem **pp = &e2.EV.E1.EV.E2; 1607 1608 if (el_match(*pb1, *pb2) && 1609 !el_sideeffect(*pb1)) 1610 { 1611 e.Eoper = OPbt; 1612 e.EV.E1 = *pp; // p 1613 *pp = null; 1614 e.EV.E2 = *pb1; // b 1615 *pb1 = null; 1616 *pb2 = null; 1617 el_free(e1); 1618 el_free(e2); 1619 return optelem(e,goal); 1620 } 1621 } 1622 1623 /* Replace: 1624 * (1 << a) & b 1625 * with: 1626 * b btst a 1627 */ 1628 if (e1.Eoper == OPshl && 1629 ELCONST(e1.EV.E1,1) && 1630 tysize(e.EV.E1.Ety) <= REGSIZE) 1631 { 1632 const int sz1 = tysize(e.EV.E1.Ety); 1633 e.Eoper = OPbtst; 1634 e.Ety = TYbool; 1635 e.EV.E1 = e2; 1636 e.EV.E2 = e1.EV.E2; 1637 //e.EV.E2.Ety = e.EV.E1.Ety; // leave type as int 1638 e1.EV.E2 = null; 1639 el_free(e1); 1640 1641 if (sz1 >= 2) 1642 e = el_una(OPu8_16, TYushort, e); 1643 if (sz1 >= 4) 1644 e = el_una(OPu16_32, TYulong, e); 1645 if (sz1 >= 8) 1646 e = el_una(OPu32_64, TYullong, e); 1647 1648 return optelem(e, goal); 1649 } 1650 } 1651 1652 return e; 1653 1654 Lopt: 1655 debug 1656 { 1657 __gshared int nest; 1658 nest++; 1659 if (nest > 100) 1660 { elem_print(e); 1661 assert(0); 1662 } 1663 e = optelem(e,GOALvalue); 1664 nest--; 1665 return e; 1666 } 1667 else 1668 return optelem(e,GOALvalue); 1669 } 1670 1671 /*************************************** 1672 * Fill in ops[] with operands of repeated operator oper. 1673 * Returns: 1674 * true didn't fail 1675 * false more than ops.length operands 1676 */ 1677 1678 @trusted 1679 private 1680 bool fillinops(elem*[] ops, ref size_t opsi, OPER oper, elem* e) 1681 { 1682 if (e.Eoper == oper) 1683 { 1684 if (!fillinops(ops, opsi, oper, e.EV.E1) || 1685 !fillinops(ops, opsi, oper, e.EV.E2)) 1686 return false; 1687 } 1688 else 1689 { 1690 if (opsi >= ops.length) 1691 return false; // error, too many 1692 ops[opsi] = e; 1693 opsi += 1; 1694 } 1695 return true; 1696 } 1697 1698 1699 /************************************* 1700 * Replace shift|shift with rotate. 1701 */ 1702 1703 @trusted 1704 private elem *elor(elem *e, goal_t goal) 1705 { 1706 //printf("elor()\n"); 1707 /* ROL: (a << shift) | (a >> (sizeof(a) * 8 - shift)) 1708 * ROR: (a >> shift) | (a << (sizeof(a) * 8 - shift)) 1709 */ 1710 elem *e1 = e.EV.E1; 1711 elem *e2 = e.EV.E2; 1712 uint sz = tysize(e.Ety); 1713 if (sz <= REGSIZE) 1714 { 1715 if (e1.Eoper == OPshl && e2.Eoper == OPshr && 1716 tyuns(e2.EV.E1.Ety) && e2.EV.E2.Eoper == OPmin && 1717 e2.EV.E2.EV.E1.Eoper == OPconst && 1718 el_tolong(e2.EV.E2.EV.E1) == sz * 8 && 1719 el_match5(e1.EV.E1, e2.EV.E1) && 1720 el_match5(e1.EV.E2, e2.EV.E2.EV.E2) && 1721 !el_sideeffect(e) 1722 ) 1723 { 1724 e1.Eoper = OProl; 1725 return el_selecte1(e); 1726 } 1727 if (e1.Eoper == OPshr && e2.Eoper == OPshl && 1728 tyuns(e1.EV.E1.Ety) && e2.EV.E2.Eoper == OPmin && 1729 e2.EV.E2.EV.E1.Eoper == OPconst && 1730 el_tolong(e2.EV.E2.EV.E1) == sz * 8 && 1731 el_match5(e1.EV.E1, e2.EV.E1) && 1732 el_match5(e1.EV.E2, e2.EV.E2.EV.E2) && 1733 !el_sideeffect(e) 1734 ) 1735 { 1736 e1.Eoper = OPror; 1737 return el_selecte1(e); 1738 } 1739 // rotate left by a constant 1740 if (e1.Eoper == OPshl && e2.Eoper == OPshr && 1741 tyuns(e2.EV.E1.Ety) && 1742 e1.EV.E2.Eoper == OPconst && 1743 e2.EV.E2.Eoper == OPconst && 1744 el_tolong(e2.EV.E2) == sz * 8 - el_tolong(e1.EV.E2) && 1745 el_match5(e1.EV.E1, e2.EV.E1) && 1746 !el_sideeffect(e) 1747 ) 1748 { 1749 e1.Eoper = OProl; 1750 return el_selecte1(e); 1751 } 1752 // rotate right by a constant 1753 if (e1.Eoper == OPshr && e2.Eoper == OPshl && 1754 tyuns(e2.EV.E1.Ety) && 1755 e1.EV.E2.Eoper == OPconst && 1756 e2.EV.E2.Eoper == OPconst && 1757 el_tolong(e2.EV.E2) == sz * 8 - el_tolong(e1.EV.E2) && 1758 el_match5(e1.EV.E1, e2.EV.E1) && 1759 !el_sideeffect(e) 1760 ) 1761 { 1762 e1.Eoper = OPror; 1763 return el_selecte1(e); 1764 } 1765 } 1766 1767 /* Recognize the following function and replace it with OPbswap: 1768 ushort byteswap(ushort x) { return cast(ushort)(((x >> 8) & 0xFF) | ((x << 8) & 0xFF00)); } 1769 1770 | TYunsigned short 1771 & TYshort 1772 32_16 TYshort 1773 >> TYint 1774 u16_32 TYint 1775 var TYunsigned short x 1776 const TYint 8L 1777 const TYshort 255 1778 & TYshort 1779 << TYshort 1780 var TYshort x 1781 const TYshort 8 1782 const TYshort 0xFF00 1783 */ 1784 if (sz == 2 && OPTIMIZER) 1785 { 1786 if (e.Eoper == OPor && 1787 e1.Eoper == OPand && 1788 e2.Eoper == OPand) 1789 { 1790 elem* evar; 1791 elem* evar2; 1792 auto e11 = e1.EV.E1; 1793 auto e12 = e1.EV.E2; 1794 if (e11.Eoper == OP32_16 && 1795 e12.Eoper == OPconst && el_tolong(e12) == 0xFF) 1796 { 1797 auto e111 = e11.EV.E1; 1798 if (e111.Eoper == OPshr || e111.Eoper == OPashr) 1799 { 1800 auto e1111 = e111.EV.E1; 1801 auto e1112 = e111.EV.E2; 1802 if (e1112.Eoper == OPconst && el_tolong(e1112) == 8 && 1803 e1111.Eoper == OPu16_32) 1804 evar = e1111.EV.E1; 1805 } 1806 } 1807 1808 if (evar) 1809 { 1810 auto e22 = e2.EV.E2; 1811 if (e22.Eoper == OPconst && el_tolong(e22) == 0xFF00) 1812 { 1813 auto e21 = e2.EV.E1; 1814 if (e21.Eoper == OPshl) 1815 { 1816 auto e211 = e21.EV.E1; 1817 auto e212 = e21.EV.E2; 1818 if (e212.Eoper == OPconst && el_tolong(e212) == 8) 1819 { 1820 if (el_match5(evar, e211) && !el_sideeffect(e211)) 1821 { 1822 evar2 = e211; 1823 e21.EV.E1 = null; 1824 } 1825 } 1826 } 1827 } 1828 } 1829 1830 if (evar2) 1831 { 1832 el_free(e1); 1833 el_free(e2); 1834 e.Eoper = OPbswap; 1835 e.EV.E1 = evar2; 1836 e.EV.E2 = null; 1837 //printf("Matched byteswap(ushort)\n"); 1838 return e; 1839 } 1840 } 1841 } 1842 1843 /* BSWAP: (data[0]<< 24) | (data[1]<< 16) | (data[2]<< 8) | (data[3]<< 0) 1844 */ 1845 if (sz == 4 && OPTIMIZER) 1846 { 1847 elem*[4] ops = void; 1848 size_t opsi = 0; 1849 if (fillinops(ops, opsi, OPor, e) && opsi == ops.length) 1850 { 1851 elem *ex = null; 1852 uint bmask = 0; 1853 foreach (eo; ops) 1854 { 1855 elem *eo2; 1856 int shift; 1857 elem *eo111; 1858 if (eo.Eoper == OPu8_16 && 1859 eo.EV.E1.Eoper == OPind) 1860 { 1861 eo111 = eo.EV.E1.EV.E1; 1862 shift = 0; 1863 } 1864 else if (eo.Eoper == OPshl && 1865 eo.EV.E1.Eoper == OPu8_16 && 1866 (eo2 = eo.EV.E2).Eoper == OPconst && 1867 eo.EV.E1.EV.E1.Eoper == OPind) 1868 { 1869 shift = cast(int)el_tolong(eo2); 1870 switch (shift) 1871 { 1872 case 8: 1873 case 16: 1874 case 24: 1875 break; 1876 1877 default: 1878 goto L1; 1879 } 1880 eo111 = eo.EV.E1.EV.E1.EV.E1; 1881 } 1882 else 1883 goto L1; 1884 1885 uint off; 1886 elem *ed; 1887 if (eo111.Eoper == OPadd) 1888 { 1889 ed = eo111.EV.E1; 1890 if (eo111.EV.E2.Eoper != OPconst) 1891 goto L1; 1892 off = cast(uint)el_tolong(eo111.EV.E2); 1893 if (off < 1 || off > 3) 1894 goto L1; 1895 } 1896 else 1897 { 1898 ed = eo111; 1899 off = 0; 1900 } 1901 switch ((off << 5) | shift) 1902 { 1903 // BSWAP 1904 case (0 << 5) | 24: bmask |= 1; break; 1905 case (1 << 5) | 16: bmask |= 2; break; 1906 case (2 << 5) | 8: bmask |= 4; break; 1907 case (3 << 5) | 0: bmask |= 8; break; 1908 1909 // No swap 1910 case (0 << 5) | 0: bmask |= 0x10; break; 1911 case (1 << 5) | 8: bmask |= 0x20; break; 1912 case (2 << 5) | 16: bmask |= 0x40; break; 1913 case (3 << 5) | 24: bmask |= 0x80; break; 1914 1915 default: 1916 goto L1; 1917 } 1918 if (ex) 1919 { 1920 if (!el_match(ex, ed)) 1921 goto L1; 1922 } 1923 else 1924 { if (el_sideeffect(ed)) 1925 goto L1; 1926 ex = ed; 1927 } 1928 } 1929 /* Got a match, build: 1930 * BSWAP(*ex) 1931 */ 1932 if (bmask == 0x0F) 1933 e = el_una(OPbswap, e.Ety, el_una(OPind, e.Ety, ex)); 1934 else if (bmask == 0xF0) 1935 e = el_una(OPind, e.Ety, ex); 1936 else 1937 goto L1; 1938 return e; 1939 } 1940 } 1941 L1: 1942 1943 return elbitwise(e, goal); 1944 } 1945 1946 /************************************* 1947 */ 1948 1949 @trusted 1950 private elem *elxor(elem *e, goal_t goal) 1951 { 1952 if (OPTIMIZER) 1953 { 1954 elem *e1 = e.EV.E1; 1955 elem *e2 = e.EV.E2; 1956 1957 /* Recognize: 1958 * (a & c) ^ (b & c) => (a ^ b) & c 1959 */ 1960 if (e1.Eoper == OPand && e2.Eoper == OPand && 1961 el_match5(e1.EV.E2, e2.EV.E2) && 1962 (e2.EV.E2.Eoper == OPconst || (!el_sideeffect(e2.EV.E1) && !el_sideeffect(e2.EV.E2)))) 1963 { 1964 el_free(e1.EV.E2); 1965 e1.EV.E2 = e2.EV.E1; 1966 e1.Eoper = OPxor; 1967 e.Eoper = OPand; 1968 e.EV.E2 = e2.EV.E2; 1969 e2.EV.E1 = null; 1970 e2.EV.E2 = null; 1971 el_free(e2); 1972 return optelem(e, GOALvalue); 1973 } 1974 } 1975 return elbitwise(e, goal); 1976 } 1977 1978 /************************** 1979 * Optimize nots. 1980 * ! ! e => bool e 1981 * ! bool e => ! e 1982 * ! OTrel => !OTrel (invert the condition) 1983 * ! OTconv => ! 1984 */ 1985 1986 @trusted 1987 private elem * elnot(elem *e, goal_t goal) 1988 { 1989 elem *e1 = e.EV.E1; 1990 const op = e1.Eoper; 1991 switch (op) 1992 { 1993 case OPnot: // ! ! e => bool e 1994 case OPbool: // ! bool e => ! e 1995 e1.Eoper = cast(ubyte)(op ^ (OPbool ^ OPnot)); 1996 /* That was a clever substitute for the following: */ 1997 /* e.Eoper = (op == OPnot) ? OPbool : OPnot; */ 1998 e = optelem(el_selecte1(e), goal); 1999 break; 2000 2001 default: 2002 if (OTrel(op)) /* ! OTrel => !OTrel */ 2003 { 2004 /* Find the logical negation of the operator */ 2005 auto op2 = rel_not(op); 2006 if (!tyfloating(e1.EV.E1.Ety)) 2007 { op2 = rel_integral(op2); 2008 assert(OTrel(op2)); 2009 } 2010 e1.Eoper = cast(ubyte)op2; 2011 e = optelem(el_selecte1(e), goal); 2012 } 2013 else if (tybasic(e1.Ety) == TYbool && tysize(e.Ety) == 1) 2014 { 2015 // !e1 => (e1 ^ 1) 2016 e.Eoper = OPxor; 2017 e.EV.E2 = el_long(e1.Ety,1); 2018 e = optelem(e, goal); 2019 } 2020 else 2021 { 2022 static if (0) 2023 { 2024 // Can't use this because what if OPd_s32? 2025 // Note: !(long)(.1) != !(.1) 2026 if (OTconv(op)) // don't use case because of differ target 2027 { // conversion operators 2028 e1.Eoper = e.Eoper; 2029 e = optelem(el_selecte1(e), goal); 2030 break; 2031 } 2032 } 2033 } 2034 break; 2035 2036 case OPs32_d: 2037 case OPs16_d: 2038 case OPu16_d: 2039 case OPu32_d: 2040 case OPf_d: 2041 case OPd_ld: 2042 case OPs16_32: 2043 case OPu16_32: 2044 case OPu8_16: 2045 case OPs8_16: 2046 case OPu32_64: 2047 case OPs32_64: 2048 case OPvp_fp: 2049 case OPcvp_fp: 2050 case OPnp_fp: 2051 e1.Eoper = e.Eoper; 2052 e = optelem(el_selecte1(e), goal); 2053 break; 2054 } 2055 return e; 2056 } 2057 2058 /************************* 2059 * Complement 2060 * ~ ~ e => e 2061 */ 2062 2063 @trusted 2064 private elem * elcom(elem *e, goal_t goal) 2065 { 2066 elem *e1 = e.EV.E1; 2067 if (e1.Eoper == OPcom) // ~ ~ e => e 2068 // Typing problem here 2069 e = el_selecte1(el_selecte1(e)); 2070 return e; 2071 } 2072 2073 /************************* 2074 * If it is a conditional of a constant 2075 * then we know which exp to evaluate. 2076 * BUG: 2077 * doesn't detect ("string" ? et : ef) 2078 */ 2079 2080 @trusted 2081 private elem * elcond(elem *e, goal_t goal) 2082 { 2083 //printf("elcond() goal = %d\n", goal); 2084 //elem_print(e); 2085 elem *e1 = e.EV.E1; 2086 switch (e1.Eoper) 2087 { 2088 case OPconst: 2089 if (boolres(e1)) 2090 L1: 2091 e = el_selecte1(el_selecte2(e)); 2092 else 2093 e = el_selecte2(el_selecte2(e)); 2094 break; 2095 2096 case OPrelconst: 2097 case OPstring: 2098 goto L1; 2099 2100 case OPcomma: 2101 // ((a,b) ? c) => (a,(b ? c)) 2102 e.Eoper = OPcomma; 2103 e.EV.E1 = e1.EV.E1; 2104 e1.EV.E1 = e1.EV.E2; 2105 e1.EV.E2 = e.EV.E2; 2106 e.EV.E2 = e1; 2107 e1.Eoper = OPcond; 2108 e1.Ety = e.Ety; 2109 return optelem(e,GOALvalue); 2110 2111 case OPnot: 2112 { 2113 // (!a ? b : c) => (a ? c : b) 2114 elem *ex = e.EV.E2.EV.E1; 2115 e.EV.E2.EV.E1 = e.EV.E2.EV.E2; 2116 e.EV.E2.EV.E2 = ex; 2117 goto L2; 2118 } 2119 2120 default: 2121 if (OTboolnop(e1.Eoper)) 2122 { 2123 L2: 2124 e.EV.E1 = e1.EV.E1; 2125 e1.EV.E1 = null; 2126 el_free(e1); 2127 return elcond(e,goal); 2128 } 2129 if (!OPTIMIZER) 2130 break; 2131 2132 { 2133 tym_t ty = e.Ety; 2134 elem *ec1 = e.EV.E2.EV.E1; 2135 elem *ec2 = e.EV.E2.EV.E2; 2136 2137 if (tyintegral(ty) && ec1.Eoper == OPconst && ec2.Eoper == OPconst) 2138 { 2139 targ_llong i1 = el_tolong(ec1); 2140 targ_llong i2 = el_tolong(ec2); 2141 tym_t ty1 = tybasic(e1.Ety); 2142 2143 if ((ty1 == TYbool && !OTlogical(e1.Eoper) || e1.Eoper == OPand && e1.EV.E2.Eoper == OPconst) && 2144 tysize(ty) == tysize(ec1.Ety)) 2145 { 2146 targ_llong b = ty1 == TYbool ? 1 : el_tolong(e1.EV.E2); 2147 2148 if (b == 1 && ispow2(i1 - i2) != -1) 2149 { 2150 // replace (e1 ? i1 : i2) with (i1 + (e1 ^ 1) * (i2 - i1)) 2151 // replace (e1 ? i2 : i1) with (i1 + e1 * (i2 - i1)) 2152 int sz = tysize(e1.Ety); 2153 while (sz < tysize(ec1.Ety)) 2154 { 2155 // Increase the size of e1 until it matches the size of ec1 2156 switch (sz) 2157 { 2158 case 1: 2159 e1 = el_una(OPu8_16, TYushort, e1); 2160 sz = 2; 2161 break; 2162 case 2: 2163 e1 = el_una(OPu16_32, TYulong, e1); 2164 sz = 4; 2165 break; 2166 case 4: 2167 e1 = el_una(OPu32_64, TYullong, e1); 2168 sz = 8; 2169 break; 2170 default: 2171 assert(0); 2172 } 2173 } 2174 if (i1 < i2) 2175 { 2176 ec2.EV.Vllong = i2 - i1; 2177 e1 = el_bin(OPxor,e1.Ety,e1,el_long(e1.Ety,1)); 2178 } 2179 else 2180 { 2181 ec1.EV.Vllong = i2; 2182 ec2.EV.Vllong = i1 - i2; 2183 } 2184 e.EV.E1 = ec1; 2185 e.EV.E2.Eoper = OPmul; 2186 e.EV.E2.Ety = ty; 2187 e.EV.E2.EV.E1 = e1; 2188 e.Eoper = OPadd; 2189 return optelem(e,GOALvalue); 2190 } 2191 2192 /* If b is an integer with only 1 bit set then 2193 * replace ((a & b) ? b : 0) with (a & b) 2194 * replace ((a & b) ? 0 : b) with ((a & b) ^ b) 2195 */ 2196 if (e1.Eoper == OPand && e1.EV.E2.Eoper == OPconst && ispow2(b) != -1) // if only 1 bit is set 2197 { 2198 if (b == i1 && i2 == 0) 2199 { e = el_selecte1(e); 2200 e.EV.E1.Ety = ty; 2201 e.EV.E2.Ety = ty; 2202 e.EV.E2.EV.Vllong = b; 2203 return optelem(e,GOALvalue); 2204 } 2205 else if (i1 == 0 && b == i2) 2206 { 2207 e1.Ety = ty; 2208 e1.EV.E1.Ety = ty; 2209 e1.EV.E2.Ety = ty; 2210 e1.EV.E2.EV.Vllong = b; 2211 e.EV.E1 = el_bin(OPxor,ty,e1,el_long(ty,b)); 2212 e = el_selecte1(e); 2213 return optelem(e,GOALvalue); 2214 } 2215 } 2216 } 2217 2218 /* Replace ((a relop b) ? 1 : 0) with (a relop b) */ 2219 else if (OTrel(e1.Eoper) && 2220 tysize(ty) <= tysize(TYint)) 2221 { 2222 if (i1 == 1 && i2 == 0) 2223 e = el_selecte1(e); 2224 else if (i1 == 0 && i2 == 1) 2225 { 2226 e.EV.E1 = el_una(OPnot,ty,e1); 2227 e = optelem(el_selecte1(e),GOALvalue); 2228 } 2229 } 2230 2231 // The next two optimizations attempt to replace with an 2232 // uint compare, which the code generator can generate 2233 // code for without using jumps. 2234 2235 // Try to replace (!e1) with (e1 < 1) 2236 else if (e1.Eoper == OPnot && !OTrel(e1.EV.E1.Eoper) && e1.EV.E1.Eoper != OPand) 2237 { 2238 e.EV.E1 = el_bin(OPlt,TYint,e1.EV.E1,el_long(touns(e1.EV.E1.Ety),1)); 2239 e1.EV.E1 = null; 2240 el_free(e1); 2241 } 2242 // Try to replace (e1) with (e1 >= 1) 2243 else if (!OTrel(e1.Eoper) && e1.Eoper != OPand) 2244 { 2245 if (tyfv(e1.Ety)) 2246 { 2247 if (tysize(e.Ety) == tysize(TYint)) 2248 { 2249 if (i1 == 1 && i2 == 0) 2250 { e.Eoper = OPbool; 2251 el_free(e.EV.E2); 2252 e.EV.E2 = null; 2253 } 2254 else if (i1 == 0 && i2 == 1) 2255 { e.Eoper = OPnot; 2256 el_free(e.EV.E2); 2257 e.EV.E2 = null; 2258 } 2259 } 2260 } 2261 else if(tyintegral(e1.Ety)) 2262 e.EV.E1 = el_bin(OPge,TYint,e1,el_long(touns(e1.Ety),1)); 2263 } 2264 } 2265 2266 // Try to detect absolute value expression 2267 // (a < 0) -a : a 2268 else if ((e1.Eoper == OPlt || e1.Eoper == OPle) && 2269 e1.EV.E2.Eoper == OPconst && 2270 !boolres(e1.EV.E2) && 2271 !tyuns(e1.EV.E1.Ety) && 2272 !tyuns(e1.EV.E2.Ety) && 2273 ec1.Eoper == OPneg && 2274 !el_sideeffect(ec2) && 2275 el_match(e.EV.E1.EV.E1,ec2) && 2276 el_match(ec1.EV.E1,ec2) && 2277 tysize(ty) >= _tysize[TYint] 2278 ) 2279 { e.EV.E2.EV.E2 = null; 2280 el_free(e); 2281 e = el_una(OPabs,ty,ec2); 2282 } 2283 // (a >= 0) a : -a 2284 else if ((e1.Eoper == OPge || e1.Eoper == OPgt) && 2285 e1.EV.E2.Eoper == OPconst && 2286 !boolres(e1.EV.E2) && 2287 !tyuns(e1.EV.E1.Ety) && 2288 !tyuns(e1.EV.E2.Ety) && 2289 ec2.Eoper == OPneg && 2290 !el_sideeffect(ec1) && 2291 el_match(e.EV.E1.EV.E1,ec1) && 2292 el_match(ec2.EV.E1,ec1) && 2293 tysize(ty) >= _tysize[TYint] 2294 ) 2295 { e.EV.E2.EV.E1 = null; 2296 el_free(e); 2297 e = el_una(OPabs,ty,ec1); 2298 } 2299 2300 /* Replace: 2301 * a ? noreturn : c 2302 * with: 2303 * (a && noreturn), c 2304 * because that means fewer noreturn cases for the data flow analysis to deal with 2305 */ 2306 else if (!el_returns(ec1)) 2307 { 2308 e.Eoper = OPcomma; 2309 e.EV.E1 = e.EV.E2; 2310 e.EV.E2 = ec2; 2311 e.EV.E1.Eoper = OPandand; 2312 e.EV.E1.Ety = TYvoid; 2313 e.EV.E1.EV.E2 = ec1; 2314 e.EV.E1.EV.E1 = e1; 2315 } 2316 2317 /* Replace: 2318 * a ? b : noreturn 2319 * with: 2320 * (a || noreturn), b 2321 */ 2322 else if (!el_returns(ec2)) 2323 { 2324 e.Eoper = OPcomma; 2325 e.EV.E1 = e.EV.E2; 2326 e.EV.E2 = ec1; 2327 e.EV.E1.Eoper = OPoror; 2328 e.EV.E1.Ety = TYvoid; 2329 e.EV.E1.EV.E2 = ec2; 2330 e.EV.E1.EV.E1 = e1; 2331 } 2332 2333 /* Replace: 2334 * *p op e ? p : false 2335 * with: 2336 * bool 2337 */ 2338 else if (goal == GOALflags && 2339 ec2.Eoper == OPconst && !boolres(ec2) && 2340 typtr(ec1.Ety) && 2341 ec1.Eoper == OPvar && 2342 OTbinary(e1.Eoper) && 2343 !OTsideff(e1.Eoper) && 2344 e1.EV.E1.Eoper == OPind && 2345 el_match(findPointer(e1.EV.E1.EV.E1), ec1) && 2346 !el_sideeffect(e)) 2347 { 2348 /* NOTE: should optimize other cases of this 2349 */ 2350 el_free(e.EV.E2); 2351 e.EV.E2 = null; 2352 e.Eoper = OPbool; 2353 e.Ety = TYint; 2354 } 2355 break; 2356 } 2357 } 2358 return e; 2359 } 2360 2361 /****************************** 2362 * Given an elem that is the operand to OPind, 2363 * find the expression representing the pointer. 2364 * Params: 2365 * e = operand to OPind 2366 * Returns: 2367 * expression that represents the pointer 2368 */ 2369 @trusted 2370 private elem* findPointer(elem* e) 2371 { 2372 if (e.Eoper == OPvar) 2373 return e; 2374 if (OTleaf(e.Eoper) || !(e.Eoper == OPadd || e.Eoper == OPmin)) 2375 return null; 2376 2377 if (typtr(e.EV.E1.Ety)) 2378 return findPointer(e.EV.E1); 2379 if (OTbinary(e.Eoper)) 2380 { 2381 if (typtr(e.EV.E2.Ety)) 2382 return findPointer(e.EV.E2); 2383 } 2384 return null; 2385 } 2386 2387 2388 /**************************** 2389 * Comma operator. 2390 * , e 2391 * / \ => expression with no effect 2392 * c e 2393 * , , 2394 * / \ => / \ operators with no effect 2395 * + e , e 2396 * / \ / \ 2397 * e e e e 2398 */ 2399 2400 @trusted 2401 private elem * elcomma(elem *e, goal_t goal) 2402 { 2403 int changes = -1; 2404 L1: 2405 changes++; 2406 L2: 2407 //printf("elcomma()\n"); 2408 elem *e2 = e.EV.E2; 2409 elem **pe1 = &(e.EV.E1); 2410 elem *e1 = *pe1; 2411 int e1op = e1.Eoper; 2412 2413 // c,e => e 2414 if (OTleaf(e1op) && !OTsideff(e1op) && !(e1.Ety & (mTYvolatile | mTYshared))) 2415 { 2416 e2.Ety = e.Ety; 2417 e = el_selecte2(e); 2418 goto Lret; 2419 } 2420 2421 // ((a op b),e2) => ((a,b),e2) if op has no side effects 2422 if (!el_sideeffect(e1) && e1op != OPcomma && e1op != OPandand && 2423 e1op != OPoror && e1op != OPcond) 2424 { 2425 if (OTunary(e1op)) 2426 *pe1 = el_selecte1(e1); /* get rid of e1 */ 2427 else 2428 { 2429 e1.Eoper = OPcomma; 2430 e1.Ety = e1.EV.E2.Ety; 2431 } 2432 goto L1; 2433 } 2434 2435 if (!OPTIMIZER) 2436 goto Lret; 2437 2438 /* Replace (a,b),e2 with a,(b,e2) */ 2439 if (e1op == OPcomma) 2440 { 2441 e1.Ety = e.Ety; 2442 e.EV.E1 = e1.EV.E1; 2443 e1.EV.E1 = e1.EV.E2; 2444 e1.EV.E2 = e2; 2445 e.EV.E2 = elcomma(e1, GOALvalue); 2446 goto L2; 2447 } 2448 2449 if ((OTopeq(e1op) || e1op == OPeq) && 2450 (e1.EV.E1.Eoper == OPvar || e1.EV.E1.Eoper == OPind) && 2451 !el_sideeffect(e1.EV.E1) 2452 ) 2453 { 2454 if (el_match(e1.EV.E1,e2)) 2455 // ((a = b),a) => (a = b) 2456 e = el_selecte1(e); 2457 else if (OTrel(e2.Eoper) && 2458 OTleaf(e2.EV.E2.Eoper) && 2459 el_match(e1.EV.E1,e2.EV.E1) 2460 ) 2461 { // ((a = b),(a < 0)) => ((a = b) < 0) 2462 e1.Ety = e2.EV.E1.Ety; 2463 e.EV.E1 = e2.EV.E1; 2464 e2.EV.E1 = e1; 2465 goto L1; 2466 } 2467 else if ((e2.Eoper == OPandand || 2468 e2.Eoper == OPoror || 2469 e2.Eoper == OPcond) && 2470 el_match(e1.EV.E1,e2.EV.E1) 2471 ) 2472 { 2473 /* ((a = b),(a || c)) => ((a = b) || c) */ 2474 e1.Ety = e2.EV.E1.Ety; 2475 e.EV.E1 = e2.EV.E1; 2476 e2.EV.E1 = e1; 2477 e = el_selecte2(e); 2478 changes++; 2479 goto Lret; 2480 } 2481 else if (e1op == OPeq) 2482 { 2483 /* Replace ((a = b),(c = a)) with a,(c = (a = b)) */ 2484 for (; e2.Eoper == OPcomma; e2 = e2.EV.E1) 2485 { } 2486 if ((OTopeq(e2.Eoper) || e2.Eoper == OPeq) && 2487 el_match(e1.EV.E1,e2.EV.E2) && 2488 //!(e1.EV.E1.Eoper == OPvar && el_appears(e2.EV.E1,e1.EV.E1.EV.Vsym)) && 2489 ERTOL(e2)) 2490 { 2491 e.EV.E1 = e2.EV.E2; 2492 e1.Ety = e2.EV.E2.Ety; 2493 e2.EV.E2 = e1; 2494 goto L1; 2495 } 2496 } 2497 else 2498 { 2499 static if (1) // This optimization is undone in eleq(). 2500 { 2501 // Replace ((a op= b),(a op= c)) with (0,a = (a op b) op c) 2502 for (; e2.Eoper == OPcomma; e2 = e2.EV.E1) 2503 { } 2504 if ((OTopeq(e2.Eoper)) && 2505 el_match(e1.EV.E1,e2.EV.E1)) 2506 { 2507 elem *ex; 2508 e.EV.E1 = el_long(TYint,0); 2509 e1.Eoper = cast(ubyte)opeqtoop(e1op); 2510 e2.EV.E2 = el_bin(opeqtoop(e2.Eoper),e2.Ety,e1,e2.EV.E2); 2511 e2.Eoper = OPeq; 2512 goto L1; 2513 } 2514 } 2515 } 2516 } 2517 Lret: 2518 again = changes != 0; 2519 return e; 2520 } 2521 2522 /******************************** 2523 */ 2524 2525 private elem * elremquo(elem *e, goal_t goal) 2526 { 2527 static if (0) 2528 if (cnst(e.EV.E2) && !boolres(e.EV.E2)) 2529 error(e.Esrcpos.Sfilename, e.Esrcpos.Slinnum, e.Esrcpos.Scharnum, "divide by zero\n"); 2530 2531 return e; 2532 } 2533 2534 /******************************** 2535 */ 2536 2537 @trusted 2538 private elem * elmod(elem *e, goal_t goal) 2539 { 2540 tym_t tym = e.EV.E1.Ety; 2541 if (!tyfloating(tym)) 2542 return eldiv(e, goal); 2543 return e; 2544 } 2545 2546 /***************************** 2547 * Convert divides to >> if power of 2. 2548 * Can handle OPdiv, OPdivass, OPmod. 2549 */ 2550 2551 @trusted 2552 private elem * eldiv(elem *e, goal_t goal) 2553 { 2554 //printf("eldiv()\n"); 2555 elem *e2 = e.EV.E2; 2556 tym_t tym = e.EV.E1.Ety; 2557 int uns = tyuns(tym) | tyuns(e2.Ety); 2558 if (cnst(e2)) 2559 { 2560 static if (0) 2561 if (!boolres(e2)) 2562 error(e.Esrcpos.Sfilename, e.Esrcpos.Slinnum, e.Esrcpos.Scharnum, "divide by zero\n"); 2563 2564 if (uns) 2565 { 2566 e2.Ety = touns(e2.Ety); 2567 int i = ispow2(el_tolong(e2)); 2568 if (i != -1) 2569 { 2570 OPER op; 2571 switch (e.Eoper) 2572 { case OPdiv: 2573 op = OPshr; 2574 goto L1; 2575 2576 case OPdivass: 2577 op = OPshrass; 2578 L1: 2579 e2.EV.Vint = i; 2580 e2.Ety = TYint; 2581 e.EV.E1.Ety = touns(tym); 2582 break; 2583 2584 case OPmod: 2585 op = OPand; 2586 goto L3; 2587 case OPmodass: 2588 op = OPandass; 2589 L3: 2590 e2.EV.Vullong = el_tolong(e2) - 1; 2591 break; 2592 2593 default: 2594 assert(0); 2595 } 2596 e.Eoper = cast(ubyte)op; 2597 return optelem(e,GOALvalue); 2598 } 2599 } 2600 } 2601 2602 if (OPTIMIZER) 2603 { 2604 const int SQRT_INT_MAX = 0xB504; 2605 const uint SQRT_UINT_MAX = 0x10000; 2606 elem *e1 = e.EV.E1; 2607 if (tyintegral(tym) && e.Eoper == OPdiv && e2.Eoper == OPconst && 2608 e1.Eoper == OPdiv && e1.EV.E2.Eoper == OPconst) 2609 { 2610 /* Replace: 2611 * (e / c1) / c2 2612 * With: 2613 * e / (c1 * c2) 2614 */ 2615 targ_llong c1 = el_tolong(e1.EV.E2); 2616 targ_llong c2 = el_tolong(e2); 2617 bool uns1 = tyuns(e1.EV.E1.Ety) || tyuns(e1.EV.E2.Ety); 2618 bool uns2 = tyuns(e1.Ety) || tyuns(e2.Ety); 2619 if (uns1 == uns2) // identity doesn't hold for mixed sign case 2620 { 2621 // The transformation will fail if c1*c2 overflows. This substitutes 2622 // for a proper overflow check. 2623 if (uns1 ? (c1 < SQRT_UINT_MAX && c2 < SQRT_UINT_MAX) 2624 : (-SQRT_INT_MAX < c1 && c1 < SQRT_INT_MAX && -SQRT_INT_MAX < c2 && c2 < SQRT_INT_MAX)) 2625 { 2626 e.EV.E1 = e1.EV.E1; 2627 e1.EV.E1 = e1.EV.E2; 2628 e1.EV.E2 = e2; 2629 e.EV.E2 = e1; 2630 e1.Eoper = OPmul; 2631 return optelem(e, GOALvalue); 2632 } 2633 } 2634 } 2635 2636 if (tyintegral(tym) && e.Eoper == OPdiv && e2.Eoper == OPconst && 2637 e1.Eoper == OP64_32 && 2638 e1.EV.E1.Eoper == OPremquo && e1.EV.E1.EV.E2.Eoper == OPconst) 2639 { 2640 /* Replace: 2641 * (64_32 (e /% c1)) / c2 2642 * With: 2643 * e / (c1 * c2) 2644 */ 2645 elem *erq = e1.EV.E1; 2646 targ_llong c1 = el_tolong(erq.EV.E2); 2647 targ_llong c2 = el_tolong(e2); 2648 bool uns1 = tyuns(erq.EV.E1.Ety) || tyuns(erq.EV.E2.Ety); 2649 bool uns2 = tyuns(e1.Ety) || tyuns(e2.Ety); 2650 if (uns1 == uns2) // identity doesn't hold for mixed sign case 2651 { 2652 // The transformation will fail if c1*c2 overflows. This substitutes 2653 // for a proper overflow check. 2654 if (uns1 ? (c1 < SQRT_UINT_MAX && c2 < SQRT_UINT_MAX) 2655 : (-SQRT_INT_MAX < c1 && c1 < SQRT_INT_MAX && -SQRT_INT_MAX < c2 && c2 < SQRT_INT_MAX)) 2656 { 2657 e.EV.E1 = erq.EV.E1; 2658 erq.EV.E1 = erq.EV.E2; 2659 erq.EV.E2 = e2; 2660 e.EV.E2 = erq; 2661 erq.Eoper = OPmul; 2662 erq.Ety = e1.Ety; 2663 e1.EV.E1 = null; 2664 el_free(e1); 2665 return optelem(e, GOALvalue); 2666 } 2667 } 2668 } 2669 2670 /* Convert if(e1/e2) to if(e1>=e2) iff uint division. 2671 */ 2672 if (goal == GOALflags && uns && e.Eoper == OPdiv) 2673 { 2674 e.Eoper = OPge; 2675 e.Ety = TYbool; 2676 return e; 2677 } 2678 2679 /* TODO: (i*c1)/c2 => i*(c1/c2) if (c1%c2)==0 2680 * TODO: i/(x?c1:c2) => i>>(x?log2(c1):log2(c2)) if c1 and c2 are powers of 2 2681 */ 2682 2683 if (tyintegral(tym) && (e.Eoper == OPdiv || e.Eoper == OPmod)) 2684 { 2685 int sz = tysize(tym); 2686 2687 // See if we can replace with OPremquo 2688 if (sz == REGSIZE 2689 // Currently don't allow this because OPmsw doesn't work for the case 2690 //|| (I64 && sz == 4) 2691 ) 2692 { 2693 // Don't do it if there are special code sequences in the 2694 // code generator (see cdmul()) 2695 int pow2; 2696 if (e2.Eoper == OPconst && 2697 !uns && 2698 (pow2 = ispow2(el_tolong(e2))) != -1 && 2699 !(config.target_cpu < TARGET_80286 && pow2 != 1 && e.Eoper == OPdiv) 2700 ) 2701 { } 2702 else 2703 { 2704 assert(sz == 2 || sz == 4 || sz == 8); 2705 OPER op = OPmsw; 2706 if (e.Eoper == OPdiv) 2707 { 2708 op = (sz == 2) ? OP32_16 : (sz == 4) ? OP64_32 : OP128_64; 2709 } 2710 e.Eoper = OPremquo; 2711 e = el_una(op, tym, e); 2712 e.EV.E1.Ety = (sz == 2) ? TYlong : (sz == 4) ? TYllong : TYcent; 2713 return e; 2714 } 2715 } 2716 } 2717 } 2718 2719 return e; 2720 } 2721 2722 /************************** 2723 * Convert (a op b) op c to a op (b op c). 2724 */ 2725 2726 @trusted 2727 private elem * swaplog(elem *e, goal_t goal) 2728 { 2729 elem *e1 = e.EV.E1; 2730 e.EV.E1 = e1.EV.E2; 2731 e1.EV.E2 = e; 2732 return optelem(e1,goal); 2733 } 2734 2735 @trusted 2736 private elem * eloror(elem *e, goal_t goal) 2737 { 2738 tym_t ty1,ty2; 2739 2740 elem *e1 = e.EV.E1; 2741 if (OTboolnop(e1.Eoper)) 2742 { 2743 e.EV.E1 = e1.EV.E1; 2744 e1.EV.E1 = null; 2745 el_free(e1); 2746 return eloror(e, goal); 2747 } 2748 2749 elem *e2 = e.EV.E2; 2750 if (OTboolnop(e2.Eoper)) 2751 { 2752 e.EV.E2 = e2.EV.E1; 2753 e2.EV.E1 = null; 2754 el_free(e2); 2755 return eloror(e, goal); 2756 } 2757 2758 if (OPTIMIZER) 2759 { 2760 if (e1.Eoper == OPbool) 2761 { ty1 = e1.EV.E1.Ety; 2762 e1 = e.EV.E1 = el_selecte1(e1); 2763 e1.Ety = ty1; 2764 } 2765 if (e1.Eoper == OPoror) 2766 { /* convert (a||b)||c to a||(b||c). This will find more CSEs. */ 2767 return swaplog(e, goal); 2768 } 2769 e2 = elscancommas(e2); 2770 e1 = elscancommas(e1); 2771 } 2772 2773 tym_t t = e.Ety; 2774 if (e2.Eoper == OPconst || e2.Eoper == OPrelconst || e2.Eoper == OPstring) 2775 { 2776 if (boolres(e2)) /* e1 || 1 => e1 , 1 */ 2777 { 2778 if (e.EV.E2 == e2) 2779 goto L2; 2780 } 2781 else /* e1 || 0 => bool e1 */ 2782 { 2783 if (e.EV.E2 == e2) 2784 { 2785 el_free(e.EV.E2); 2786 e.EV.E2 = null; 2787 e.Eoper = OPbool; 2788 goto L3; 2789 } 2790 } 2791 } 2792 2793 if (e1.Eoper == OPconst || e1.Eoper == OPrelconst || e1.Eoper == OPstring) 2794 { 2795 if (boolres(e1)) /* (x,1) || e2 => (x,1),1 */ 2796 { 2797 if (tybasic(e.EV.E2.Ety) == TYvoid) 2798 { 2799 assert(!goal); 2800 el_free(e); 2801 return null; 2802 } 2803 else 2804 { 2805 L2: 2806 e.Eoper = OPcomma; 2807 el_free(e.EV.E2); 2808 e.EV.E2 = el_long(t,1); 2809 } 2810 } 2811 else /* (x,0) || e2 => (x,0),(bool e2) */ 2812 { 2813 e.Eoper = OPcomma; 2814 if (tybasic(e.EV.E2.Ety) != TYvoid) 2815 e.EV.E2 = el_una(OPbool,t,e.EV.E2); 2816 } 2817 } 2818 else if (OPTIMIZER && 2819 e.EV.E2.Eoper == OPvar && 2820 !OTlogical(e1.Eoper) && 2821 tysize(ty2 = e2.Ety) == tysize(ty1 = e1.Ety) && 2822 tysize(ty1) <= _tysize[TYint] && 2823 !tyfloating(ty2) && 2824 !tyfloating(ty1) && 2825 !(ty2 & (mTYvolatile | mTYshared))) 2826 { /* Convert (e1 || e2) => (e1 | e2) */ 2827 e.Eoper = OPor; 2828 e.Ety = ty1; 2829 e = el_una(OPbool,t,e); 2830 } 2831 else if (OPTIMIZER && 2832 e1.Eoper == OPand && e2.Eoper == OPand && 2833 tysize(e1.Ety) == tysize(e2.Ety) && 2834 el_match(e1.EV.E1,e2.EV.E1) && !el_sideeffect(e1.EV.E1) && 2835 !el_sideeffect(e2.EV.E2) 2836 ) 2837 { // Convert ((a & b) || (a & c)) => bool(a & (b | c)) 2838 e.Eoper = OPbool; 2839 e.EV.E2 = null; 2840 e2.Eoper = OPor; 2841 el_free(e2.EV.E1); 2842 e2.EV.E1 = e1.EV.E2; 2843 e1.EV.E2 = e2; 2844 } 2845 else 2846 goto L1; 2847 L3: 2848 e = optelem(e,GOALvalue); 2849 L1: 2850 return e; 2851 } 2852 2853 /********************************************** 2854 * Try to rewrite sequence of || and && with faster operations, such as BT. 2855 * Returns: 2856 * false nothing changed 2857 * true *pe is rewritten 2858 */ 2859 2860 @trusted 2861 private bool optim_loglog(ref elem* pe) 2862 { 2863 if (I16) 2864 return false; 2865 elem *e = pe; 2866 const op = e.Eoper; 2867 assert(op == OPandand || op == OPoror); 2868 size_t n = el_opN(e, op); 2869 if (n <= 3) 2870 return false; 2871 uint ty = e.Ety; 2872 2873 import dmd.common.string : SmallBuffer; 2874 elem*[100] tmp = void; 2875 auto sb = SmallBuffer!(elem*)(n, tmp[]); 2876 elem*[] array = sb[]; 2877 2878 elem **p = array.ptr; 2879 el_opArray(&p, e, op); 2880 2881 bool any = false; 2882 size_t first, last; 2883 targ_ullong emin, emax; 2884 int cmpop = op == OPandand ? OPne : OPeqeq; 2885 for (size_t i = 0; i < n; ++i) 2886 { 2887 elem *eq = array[i]; 2888 if (eq.Eoper == cmpop && 2889 eq.EV.E2.Eoper == OPconst && 2890 tyintegral(eq.EV.E2.Ety) && 2891 !el_sideeffect(eq.EV.E1)) 2892 { 2893 targ_ullong m = el_tolong(eq.EV.E2); 2894 if (any) 2895 { 2896 if (el_match(array[first].EV.E1, eq.EV.E1)) 2897 { 2898 last = i; 2899 if (m < emin) 2900 emin = m; 2901 if (m > emax) 2902 emax = m; 2903 } 2904 else if (last - first > 2) 2905 break; 2906 else 2907 { 2908 first = last = i; 2909 emin = emax = m; 2910 } 2911 } 2912 else 2913 { 2914 any = true; 2915 first = last = i; 2916 emin = emax = m; 2917 } 2918 } 2919 else if (any && last - first > 2) 2920 break; 2921 else 2922 any = false; 2923 } 2924 2925 //printf("n = %d, count = %d, min = %d, max = %d\n", cast(int)n, last - first + 1, cast(int)emin, cast(int)emax); 2926 if (any && last - first > 2 && emax - emin < REGSIZE * 8) 2927 { 2928 /** 2929 * Transforms expressions of the form x==c1 || x==c2 || x==c3 || ... into a single 2930 * comparison by using a bitmapped representation of data, as follows. First, the 2931 * smallest constant of c1, c2, ... (call it min) is subtracted from all constants 2932 * and also from x (this step may be elided if all constants are small enough). Then, 2933 * the test is expressed as 2934 * (1 << (x-min)) | ((1 << (c1-min)) | (1 << (c2-min)) | ...) 2935 * The test is guarded for overflow (x must be no larger than the largest of c1, c2, ...). 2936 * Since each constant is encoded as a displacement in a bitmap, hitting any bit yields 2937 * true for the expression. 2938 * 2939 * I.e. replace: 2940 * e==c1 || e==c2 || e==c3 ... 2941 * with: 2942 * (e - emin) <= (emax - emin) && (1 << (int)(e - emin)) & bits 2943 * where bits is: 2944 * (1<<(c1-emin)) | (1<<(c2-emin)) | (1<<(c3-emin)) ... 2945 * 2946 * For the case of: 2947 * x!=c1 && x!=c2 && x!=c3 && ... 2948 * using De Morgan's theorem, rewrite as: 2949 * (e - emin) > (emax - emin) || ((1 << (int)(e - emin)) & ~bits) 2950 */ 2951 2952 // Delete all the || nodes that are no longer referenced 2953 el_opFree(e, op); 2954 2955 if (emax < 32) // if everything fits in a 32 bit register 2956 emin = 0; // no need for bias 2957 2958 // Compute bit mask 2959 targ_ullong bits = 0; 2960 for (size_t i = first; i <= last; ++i) 2961 { 2962 elem *eq = array[i]; 2963 if (0 && eq.EV.E2.Eoper != OPconst) 2964 { 2965 printf("eq = %p, eq.EV.E2 = %p\n", eq, eq.EV.E2); 2966 printf("first = %d, i = %d, last = %d, Eoper = %d\n", cast(int)first, cast(int)i, cast(int)last, eq.EV.E2.Eoper); 2967 printf("any = %d, n = %d, count = %d, min = %d, max = %d\n", any, cast(int)n, cast(int)(last - first + 1), cast(int)emin, cast(int)emax); 2968 } 2969 assert(eq.EV.E2.Eoper == OPconst); 2970 bits |= cast(targ_ullong)1 << (el_tolong(eq.EV.E2) - emin); 2971 } 2972 //printf("n = %d, count = %d, min = %d, max = %d\n", cast(int)n, last - first + 1, cast(int)emin, cast(int)emax); 2973 //printf("bits = x%llx\n", bits); 2974 2975 if (op == OPandand) 2976 bits = ~bits; 2977 2978 uint tyc = array[first].EV.E1.Ety; 2979 2980 elem *ex = el_bin(OPmin, tyc, array[first].EV.E1, el_long(tyc,emin)); 2981 ex = el_bin(op == OPandand ? OPgt : OPle, TYbool, ex, el_long(touns(tyc), emax - emin)); 2982 elem *ey = el_bin(OPmin, tyc, array[first + 1].EV.E1, el_long(tyc,emin)); 2983 2984 tym_t tybits = TYuint; 2985 if ((emax - emin) >= 32) 2986 { 2987 assert(I64); // need 64 bit BT 2988 tybits = TYullong; 2989 } 2990 2991 // Shift count must be an int 2992 switch (tysize(tyc)) 2993 { 2994 case 1: 2995 ey = el_una(OPu8_16,TYint,ey); 2996 goto case 2; 2997 2998 case 2: 2999 ey = el_una(OPu16_32,TYint,ey); 3000 break; 3001 3002 case 4: 3003 break; 3004 3005 case 8: 3006 ey = el_una(OP64_32,TYint,ey); 3007 break; 3008 3009 default: 3010 assert(0); 3011 } 3012 ey = el_bin(OPbtst,TYbool,el_long(tybits,bits),ey); 3013 ex = el_bin(op == OPandand ? OPoror : OPandand, ty, ex, ey); 3014 3015 /* Free unneeded nodes 3016 */ 3017 array[first].EV.E1 = null; 3018 el_free(array[first]); 3019 array[first + 1].EV.E1 = null; 3020 el_free(array[first + 1]); 3021 for (size_t i = first + 2; i <= last; ++i) 3022 el_free(array[i]); 3023 3024 array[first] = ex; 3025 3026 for (size_t i = first + 1; i + (last - first) < n; ++i) 3027 array[i] = array[i + (last - first)]; 3028 n -= last - first; 3029 pe = el_opCombine(array.ptr, n, op, ty); 3030 3031 return true; 3032 } 3033 3034 return false; 3035 } 3036 3037 @trusted 3038 private elem * elandand(elem *e, goal_t goal) 3039 { 3040 elem *e1 = e.EV.E1; 3041 if (OTboolnop(e1.Eoper)) 3042 { 3043 e.EV.E1 = e1.EV.E1; 3044 e1.EV.E1 = null; 3045 el_free(e1); 3046 return elandand(e, goal); 3047 } 3048 elem *e2 = e.EV.E2; 3049 if (OTboolnop(e2.Eoper)) 3050 { 3051 e.EV.E2 = e2.EV.E1; 3052 e2.EV.E1 = null; 3053 el_free(e2); 3054 return elandand(e, goal); 3055 } 3056 if (OPTIMIZER) 3057 { 3058 /* Recognize: (a >= c1 && a < c2) 3059 */ 3060 if ((e1.Eoper == OPge || e1.Eoper == OPgt) && 3061 (e2.Eoper == OPlt || e2.Eoper == OPle) && 3062 e1.EV.E2.Eoper == OPconst && e2.EV.E2.Eoper == OPconst && 3063 !el_sideeffect(e1.EV.E1) && el_match(e1.EV.E1, e2.EV.E1) && 3064 tyintegral(e1.EV.E1.Ety) && 3065 tybasic(e1.EV.E2.Ety) == tybasic(e2.EV.E2.Ety) && 3066 tysize(e1.EV.E1.Ety) == _tysize[TYnptr]) 3067 { 3068 /* Replace with: ((a - c1) < (c2 - c1)) 3069 */ 3070 targ_llong c1 = el_tolong(e1.EV.E2); 3071 if (e1.Eoper == OPgt) 3072 ++c1; 3073 targ_llong c2 = el_tolong(e2.EV.E2); 3074 if (0 <= c1 && c1 <= c2) 3075 { 3076 e1.Eoper = OPmin; 3077 e1.Ety = e1.EV.E1.Ety; 3078 e1.EV.E2.EV.Vllong = c1; 3079 e.EV.E2 = el_long(touns(e2.EV.E2.Ety), c2 - c1); 3080 e.Eoper = e2.Eoper; 3081 el_free(e2); 3082 return optelem(e, GOALvalue); 3083 } 3084 } 3085 3086 // Look for (!(e >>> c) && ...) 3087 if (e1.Eoper == OPnot && e1.EV.E1.Eoper == OPshr && 3088 e1.EV.E1.EV.E2.Eoper == OPconst) 3089 { 3090 // Replace (e >>> c) with (e & x) 3091 elem *e11 = e1.EV.E1; 3092 3093 targ_ullong shift = el_tolong(e11.EV.E2); 3094 if (shift < _tysize[TYint] * 8) 3095 { 3096 targ_ullong m; 3097 m = ~0L << cast(int)shift; 3098 e11.Eoper = OPand; 3099 e11.EV.E2.EV.Vullong = m; 3100 e11.EV.E2.Ety = e11.Ety; 3101 return optelem(e,GOALvalue); 3102 } 3103 } 3104 3105 if (e1.Eoper == OPbool) 3106 { 3107 tym_t t = e1.EV.E1.Ety; 3108 e1 = e.EV.E1 = el_selecte1(e1); 3109 e1.Ety = t; 3110 } 3111 if (e1.Eoper == OPandand) 3112 { // convert (a&&b)&&c to a&&(b&&c). This will find more CSEs. 3113 return swaplog(e, goal); 3114 } 3115 e2 = elscancommas(e2); 3116 3117 while (1) 3118 { 3119 e1 = elscancommas(e1); 3120 if (e1.Eoper == OPeq) 3121 e1 = e1.EV.E2; 3122 else 3123 break; 3124 } 3125 } 3126 3127 if (e2.Eoper == OPconst || e2.Eoper == OPrelconst || e2.Eoper == OPstring) 3128 { 3129 if (boolres(e2)) // e1 && (x,1) => e1 ? ((x,1),1) : 0 3130 { 3131 if (e2 == e.EV.E2) // if no x, replace e with (bool e1) 3132 { 3133 el_free(e2); 3134 e.EV.E2 = null; 3135 e.Eoper = OPbool; 3136 goto L3; 3137 } 3138 } 3139 else // e1 && (x,0) => e1 , (x,0) 3140 { 3141 if (e2 == e.EV.E2) 3142 { e.Eoper = OPcomma; 3143 goto L3; 3144 } 3145 } 3146 } 3147 3148 if (e1.Eoper == OPconst || e1.Eoper == OPrelconst || e1.Eoper == OPstring) 3149 { 3150 e.Eoper = OPcomma; 3151 if (boolres(e1)) // (x,1) && e2 => (x,1),bool e2 3152 { 3153 if (tybasic(e.EV.E2.Ety) != TYvoid) 3154 e.EV.E2 = el_una(OPbool,e.Ety,e.EV.E2); 3155 } 3156 else // (x,0) && e2 => (x,0),0 3157 { 3158 if (tybasic(e.EV.E2.Ety) == TYvoid) 3159 { 3160 assert(!goal); 3161 el_free(e); 3162 return null; 3163 } 3164 else 3165 { 3166 el_free(e.EV.E2); 3167 e.EV.E2 = el_long(e.Ety,0); 3168 } 3169 } 3170 } 3171 else 3172 goto L1; 3173 L3: 3174 e = optelem(e,GOALvalue); 3175 L1: 3176 return e; 3177 } 3178 3179 /************************** 3180 * Reference to bit field 3181 * bit 3182 * / \ => ((e << c) >> b) & m 3183 * e w,b 3184 * 3185 * Note that this routine can handle long bit fields, though this may 3186 * not be supported later on. 3187 */ 3188 3189 @trusted 3190 private elem * elbit(elem *e, goal_t goal) 3191 { 3192 tym_t tym1 = e.EV.E1.Ety; 3193 uint sz = tysize(tym1) * 8; 3194 elem *e2 = e.EV.E2; 3195 uint wb = e2.EV.Vuns; 3196 3197 uint w = (wb >> 8) & 0xFF; // width in bits of field 3198 targ_ullong m = (cast(targ_ullong)1 << w) - 1; // mask w bits wide 3199 uint b = wb & 0xFF; // bits to right of field 3200 uint c = 0; 3201 //printf("w %u + b %u <= sz %u\n", w, b, sz); 3202 assert(w + b <= sz); 3203 3204 if (tyuns(tym1)) // if uint bit field 3205 { 3206 // Should use a more general solution to this 3207 if (w == 8 && sz == 16 && b == 0) 3208 { 3209 e.EV.E1 = el_una(OP16_8,TYuchar,e.EV.E1); 3210 e.Eoper = OPu8_16; 3211 e.EV.E2 = null; 3212 el_free(e2); 3213 return optelem(e,GOALvalue); // optimize result 3214 } 3215 3216 if (w + b == sz) // if field is left-justified 3217 m = ~cast(targ_ullong)0; // no need to mask 3218 } 3219 else // signed bit field 3220 { 3221 if (w == 8 && sz == 16 && b == 0) 3222 { 3223 e.EV.E1 = el_una(OP16_8,TYschar,e.EV.E1); 3224 e.Eoper = OPs8_16; 3225 e.EV.E2 = null; 3226 el_free(e2); 3227 return optelem(e,GOALvalue); // optimize result 3228 } 3229 m = ~cast(targ_ullong)0; 3230 c = sz - (w + b); 3231 b = sz - w; 3232 } 3233 3234 e.Eoper = OPand; 3235 3236 e2.EV.Vullong = m; // mask w bits wide 3237 e2.Ety = e.Ety; 3238 3239 OPER shift = OPshr; 3240 if (!tyuns(tym1)) 3241 shift = OPashr; 3242 e.EV.E1 = el_bin(shift,tym1, 3243 el_bin(OPshl,tym1,e.EV.E1,el_long(TYint,c)), 3244 el_long(TYint,b)); 3245 return optelem(e,GOALvalue); // optimize result 3246 } 3247 3248 /***************** 3249 * Indirection 3250 * * & e => e 3251 */ 3252 3253 @trusted 3254 private elem * elind(elem *e, goal_t goal) 3255 { 3256 tym_t tym = e.Ety; 3257 elem *e1 = e.EV.E1; 3258 switch (e1.Eoper) 3259 { 3260 case OPrelconst: 3261 e.EV.E1.ET = e.ET; 3262 e = el_selecte1(e); 3263 e.Eoper = OPvar; 3264 e.Ety = tym; /* preserve original type */ 3265 break; 3266 3267 case OPadd: 3268 if (OPTIMIZER) 3269 { /* Try to convert far pointer to stack pointer */ 3270 elem *e12 = e1.EV.E2; 3271 3272 if (e12.Eoper == OPrelconst && 3273 tybasic(e12.Ety) == TYfptr && 3274 /* If symbol is located on the stack */ 3275 sytab[e12.EV.Vsym.Sclass] & SCSS) 3276 { e1.Ety = (e1.Ety & (mTYconst | mTYvolatile | mTYimmutable | mTYshared | mTYLINK)) | TYsptr; 3277 e12.Ety = (e12.Ety & (mTYconst | mTYvolatile | mTYimmutable | mTYshared | mTYLINK)) | TYsptr; 3278 } 3279 } 3280 break; 3281 3282 case OPcomma: 3283 // Replace (*(ea,eb)) with (ea,*eb) 3284 e.EV.E1.ET = e.ET; 3285 type *t = e.ET; 3286 e = el_selecte1(e); 3287 e.Ety = tym; 3288 e.EV.E2 = el_una(OPind,tym,e.EV.E2); 3289 e.EV.E2.ET = t; 3290 again = 1; 3291 return e; 3292 3293 default: 3294 break; 3295 } 3296 topair |= (config.fpxmmregs && tycomplex(tym)); 3297 return e; 3298 } 3299 3300 /***************** 3301 * Address of. 3302 * & v => &v 3303 * & * e => e 3304 * & (v1 = v2) => ((v1 = v2), &v1) 3305 */ 3306 3307 @trusted 3308 private elem * eladdr(elem *e, goal_t goal) 3309 { 3310 tym_t tym = e.Ety; 3311 elem *e1 = e.EV.E1; 3312 elem_debug(e1); 3313 switch (e1.Eoper) 3314 { 3315 case OPvar: 3316 e1.Eoper = OPrelconst; 3317 e1.EV.Vsym.Sflags &= ~(SFLunambig | GTregcand); 3318 e1.Ety = tym; 3319 e = optelem(el_selecte1(e),GOALvalue); 3320 break; 3321 3322 case OPind: 3323 { 3324 tym_t tym2 = e1.EV.E1.Ety; 3325 3326 // Watch out for conversions between near and far pointers 3327 int sz = tysize(tym) - tysize(tym2); 3328 if (sz != 0) 3329 { 3330 OPER op; 3331 if (sz > 0) // if &far * near 3332 op = OPnp_fp; 3333 else // else &near * far 3334 op = OPoffset; 3335 e.Ety = tym2; 3336 e = el_una(op,tym,e); 3337 goto L1; 3338 } 3339 3340 e = el_selecte1(el_selecte1(e)); 3341 e.Ety = tym; 3342 break; 3343 } 3344 3345 case OPcomma: 3346 // Replace (&(ea,eb)) with (ea,&eb) 3347 e = el_selecte1(e); 3348 e.Ety = tym; 3349 e.EV.E2 = el_una(OPaddr,tym,e.EV.E2); 3350 L1: 3351 e = optelem(e,GOALvalue); 3352 break; 3353 3354 case OPnegass: 3355 assert(0); 3356 3357 default: 3358 if (OTassign(e1.Eoper)) 3359 { 3360 case OPstreq: 3361 // & (v1 = e) => ((v1 = e), &v1) 3362 if (e1.EV.E1.Eoper == OPvar) 3363 { 3364 e.Eoper = OPcomma; 3365 e.EV.E2 = el_una(OPaddr,tym,el_copytree(e1.EV.E1)); 3366 goto L1; 3367 } 3368 // & (*p1 = e) => ((*(t = p1) = e), t) 3369 else if (e1.EV.E1.Eoper == OPind) 3370 { 3371 const tym_t tym111 = e1.EV.E1.EV.E1.Ety; 3372 elem *tmp = el_alloctmp(tym111); 3373 e1.EV.E1.EV.E1 = el_bin(OPeq,tym111,tmp,e1.EV.E1.EV.E1); 3374 e.Eoper = OPcomma; 3375 e.EV.E2 = el_copytree(tmp); 3376 goto L1; 3377 } 3378 } 3379 break; 3380 3381 case OPcond: 3382 { // Replace &(x ? y : z) with (x ? &y : &z) 3383 elem *ecolon = e1.EV.E2; 3384 ecolon.Ety = tym; 3385 ecolon.EV.E1 = el_una(OPaddr,tym,ecolon.EV.E1); 3386 ecolon.EV.E2 = el_una(OPaddr,tym,ecolon.EV.E2); 3387 e = el_selecte1(e); 3388 e = optelem(e,GOALvalue); 3389 break; 3390 } 3391 3392 case OPinfo: 3393 // Replace &(e1 info e2) with (e1 info &e2) 3394 e = el_selecte1(e); 3395 e.EV.E2 = el_una(OPaddr,tym,e.EV.E2); 3396 e = optelem(e,GOALvalue); 3397 break; 3398 } 3399 return e; 3400 } 3401 3402 /******************************************* 3403 */ 3404 3405 @trusted 3406 private elem * elneg(elem *e, goal_t goal) 3407 { 3408 if (e.EV.E1.Eoper == OPneg) 3409 { 3410 e = el_selecte1(e); 3411 e = el_selecte1(e); 3412 } 3413 /* Convert -(e1 + c) to (-e1 - c) 3414 */ 3415 else if (e.EV.E1.Eoper == OPadd && e.EV.E1.EV.E2.Eoper == OPconst) 3416 { 3417 e.Eoper = OPmin; 3418 e.EV.E2 = e.EV.E1.EV.E2; 3419 e.EV.E1.Eoper = OPneg; 3420 e.EV.E1.EV.E2 = null; 3421 e = optelem(e,goal); 3422 } 3423 else 3424 e = evalu8(e, goal); 3425 return e; 3426 } 3427 3428 @trusted 3429 private elem * elcall(elem *e, goal_t goal) 3430 { 3431 if (e.EV.E1.Eoper == OPcomma || OTassign(e.EV.E1.Eoper)) 3432 e = cgel_lvalue(e); 3433 return e; 3434 } 3435 3436 /*************************** 3437 * Walk tree, converting types to tym. 3438 */ 3439 3440 @trusted 3441 private void elstructwalk(elem *e,tym_t tym) 3442 { 3443 tym_t ety; 3444 3445 while ((ety = tybasic(e.Ety)) == TYstruct || 3446 ety == TYarray) 3447 { elem_debug(e); 3448 e.Ety = (e.Ety & ~mTYbasic) | tym; 3449 switch (e.Eoper) 3450 { 3451 case OPcomma: 3452 case OPcond: 3453 case OPinfo: 3454 break; 3455 3456 case OPeq: 3457 case OPcolon: 3458 case OPcolon2: 3459 elstructwalk(e.EV.E1,tym); 3460 break; 3461 3462 default: 3463 return; 3464 } 3465 e = e.EV.E2; 3466 } 3467 } 3468 3469 /******************************* 3470 * See if we can replace struct operations with simpler ones. 3471 * For OPstreq and OPstrpar. 3472 */ 3473 3474 @trusted 3475 elem * elstruct(elem *e, goal_t goal) 3476 { 3477 //printf("elstruct(%p)\n", e); 3478 //elem_print(e); 3479 if (e.Eoper == OPstreq && (e.EV.E1.Eoper == OPcomma || OTassign(e.EV.E1.Eoper))) 3480 return cgel_lvalue(e); 3481 3482 if (e.Eoper == OPstreq && e.EV.E2.Eoper == OPcomma) 3483 { 3484 /* Replace (e1 streq (e21, e22)) with (e21, (e1 streq e22)) 3485 */ 3486 e.EV.E2.Eoper = e.Eoper; 3487 e.EV.E2.Ety = e.Ety; 3488 e.EV.E2.ET = e.ET; 3489 e.Eoper = OPcomma; 3490 elem *etmp = e.EV.E1; 3491 e.EV.E1 = e.EV.E2.EV.E1; 3492 e.EV.E2.EV.E1 = etmp; 3493 return optelem(e, goal); 3494 } 3495 3496 if (!e.ET) 3497 return e; 3498 //printf("\tnumbytes = %d\n", cast(int)type_size(e.ET)); 3499 3500 type *t = e.ET; 3501 tym_t tym = ~0; 3502 tym_t ty = tybasic(t.Tty); 3503 3504 uint sz = (e.Eoper == OPstrpar && type_zeroSize(t, global_tyf)) ? 0 : cast(uint)type_size(t); 3505 //printf("\tsz = %d\n", cast(int)sz); 3506 3507 type *targ1 = null; 3508 type *targ2 = null; 3509 if (ty == TYstruct) 3510 { // If a struct is a wrapper for another type, prefer that other type 3511 targ1 = t.Ttag.Sstruct.Sarg1type; 3512 targ2 = t.Ttag.Sstruct.Sarg2type; 3513 } 3514 3515 if (ty == TYarray && sz && config.exe != EX_WIN64) 3516 { 3517 argtypes(t, targ1, targ2); 3518 if (!targ1) 3519 goto Ldefault; 3520 goto L1; 3521 } 3522 //if (targ1) { printf("targ1\n"); type_print(targ1); } 3523 //if (targ2) { printf("targ2\n"); type_print(targ2); } 3524 switch (cast(int)sz) 3525 { 3526 case 1: tym = TYchar; goto L1; 3527 case 2: tym = TYshort; goto L1; 3528 case 4: tym = TYlong; goto L1; 3529 case 8: if (_tysize[TYint] == 2) 3530 goto Ldefault; 3531 tym = TYllong; goto L1; 3532 3533 case 3: tym = TYlong; goto L2; 3534 case 5: 3535 case 6: 3536 case 7: tym = TYllong; 3537 L2: 3538 if (e.Eoper == OPstrpar && config.exe == EX_WIN64) 3539 { 3540 goto L1; 3541 } 3542 if (I64 && config.exe != EX_WIN64) 3543 { 3544 goto L1; 3545 } 3546 tym = ~0; 3547 goto Ldefault; 3548 3549 case 10: 3550 case 12: 3551 if (tysize(TYldouble) == sz && targ1 && !targ2 && tybasic(targ1.Tty) == TYldouble) 3552 { 3553 tym = TYldouble; 3554 goto L1; 3555 } 3556 goto case 9; 3557 3558 case 9: 3559 case 11: 3560 case 13: 3561 case 14: 3562 case 15: 3563 if (I64 && config.exe != EX_WIN64) 3564 { 3565 goto L1; 3566 } 3567 goto Ldefault; 3568 3569 case 16: 3570 if (I64 && (ty == TYstruct || (ty == TYarray && config.exe == EX_WIN64))) 3571 { 3572 tym = TYucent; 3573 goto L1; 3574 } 3575 if (config.exe == EX_WIN64) 3576 goto Ldefault; 3577 if (targ1 && !targ2) 3578 goto L1; 3579 goto Ldefault; 3580 3581 L1: 3582 if (ty == TYstruct || ty == TYarray) 3583 { 3584 // This needs to match what TypeFunction::retStyle() does 3585 if (config.exe == EX_WIN64) 3586 { 3587 //if (t.Ttag.Sstruct.Sflags & STRnotpod) 3588 //goto Ldefault; 3589 } 3590 // If a struct is a wrapper for another type, prefer that other type 3591 else if (targ1 && !targ2) 3592 tym = targ1.Tty; 3593 else if (I64 && !targ1 && !targ2) 3594 { 3595 if (t.Ttag.Sstruct.Sflags & STRnotpod) 3596 { 3597 // In-memory only 3598 goto Ldefault; 3599 } 3600 // if (type_size(t) == 16) 3601 goto Ldefault; 3602 } 3603 else if (I64 && targ1 && targ2) 3604 { 3605 if (tyfloating(tybasic(targ1.Tty))) 3606 tym = TYcdouble; 3607 else 3608 tym = TYucent; 3609 if ((0 == tyfloating(targ1.Tty)) ^ (0 == tyfloating(targ2.Tty))) 3610 { 3611 tym |= tyfloating(targ1.Tty) ? mTYxmmgpr : mTYgprxmm; 3612 } 3613 } 3614 else if (I32 && targ1 && targ2) 3615 { 3616 tym = TYllong; 3617 } 3618 assert(tym != TYstruct); 3619 } 3620 assert(tym != ~0); 3621 switch (e.Eoper) 3622 { 3623 case OPstreq: 3624 if (sz != tysize(tym)) 3625 { 3626 // we can't optimize OPstreq in this case, 3627 // there will be memory corruption in the assignment 3628 elem *e2 = e.EV.E2; 3629 if (e2.Eoper != OPvar && e2.Eoper != OPind) 3630 { 3631 // the source may come in registers. ex: returned from a function. 3632 assert(tyaggregate(e2.Ety)); 3633 e2 = optelem(e2, GOALvalue); 3634 e2 = elstruct(e2, GOALvalue); 3635 e2 = exp2_copytotemp(e2); // (tmp = e2, tmp) 3636 e2.EV.E2.EV.Vsym.Sfl = FLauto; 3637 e2.Ety = e2.EV.E2.Ety = e.Ety; 3638 e2.ET = e2.EV.E2.ET = e.ET; 3639 e.EV.E2 = e2; 3640 } 3641 break; 3642 } 3643 e.Eoper = OPeq; 3644 e.Ety = (e.Ety & ~mTYbasic) | tym; 3645 elstructwalk(e.EV.E1,tym); 3646 elstructwalk(e.EV.E2,tym); 3647 e = optelem(e,GOALvalue); 3648 break; 3649 3650 case OPstrpar: 3651 e = el_selecte1(e); 3652 goto default; 3653 3654 default: /* called by doptelem() */ 3655 elstructwalk(e,tym); 3656 break; 3657 } 3658 break; 3659 3660 case 0: 3661 if (e.Eoper == OPstreq) 3662 { 3663 e.Eoper = OPcomma; 3664 e = optelem(e,GOALvalue); 3665 again = 1; 3666 } 3667 else 3668 goto Ldefault; 3669 break; 3670 3671 default: 3672 Ldefault: 3673 { 3674 elem **pe2; 3675 if (e.Eoper == OPstreq) 3676 pe2 = &e.EV.E2; 3677 else if (e.Eoper == OPstrpar) 3678 pe2 = &e.EV.E1; 3679 else 3680 break; 3681 while ((*pe2).Eoper == OPcomma) 3682 pe2 = &(*pe2).EV.E2; 3683 elem *e2 = *pe2; 3684 3685 if (e2.Eoper == OPvar) 3686 e2.EV.Vsym.Sflags &= ~GTregcand; 3687 3688 // Convert (x streq (a?y:z)) to (x streq *(a ? &y : &z)) 3689 if (e2.Eoper == OPcond) 3690 { 3691 tym_t ty2 = e2.Ety; 3692 3693 /* We should do the analysis to see if we can use 3694 something simpler than TYfptr. 3695 */ 3696 tym_t typ = (_tysize[TYint] == LONGSIZE) ? TYnptr : TYfptr; 3697 e2 = el_una(OPaddr,typ,e2); 3698 e2 = optelem(e2,GOALvalue); /* distribute & to x and y leaves */ 3699 *pe2 = el_una(OPind,ty2,e2); 3700 break; 3701 } 3702 break; 3703 } 3704 } 3705 //printf("elstruct return\n"); 3706 //elem_print(e); 3707 return e; 3708 } 3709 3710 /************************** 3711 * Assignment. Replace bit field assignment with 3712 * equivalent tree. 3713 * = 3714 * / \ 3715 * / r 3716 * bit 3717 * / \ 3718 * l w,b 3719 * 3720 * becomes: 3721 * , 3722 * / \ 3723 * = (r&m) 3724 * / \ 3725 * l | 3726 * / \ 3727 * (r&m)<<b & 3728 * / \ 3729 * l ~(m<<b) 3730 * Note: 3731 * This depends on the expression (r&m)<<b before l. This is because 3732 * of expressions like (l.a = l.b = n). It is an artifact of the way 3733 * we do things that this works (cost() will rate the << as more 3734 * expensive than the &, and so it will wind up on the left). 3735 */ 3736 3737 @trusted 3738 private elem * eleq(elem *e, goal_t goal) 3739 { 3740 goal_t wantres = goal; 3741 elem *e1 = e.EV.E1; 3742 3743 if (e1.Eoper == OPcomma || OTassign(e1.Eoper)) 3744 return cgel_lvalue(e); 3745 3746 static if (0) // Doesn't work too well, removed 3747 { 3748 // Replace (*p++ = e2) with ((*p = e2),*p++) 3749 if (OPTIMIZER && e1.Eoper == OPind && 3750 (e1.EV.E1.Eoper == OPpostinc || e1.EV.E1.Eoper == OPpostdec) && 3751 !el_sideeffect(e1.EV.E1.EV.E1) 3752 ) 3753 { 3754 e = el_bin(OPcomma,e.Ety,e,e1); 3755 e.EV.E1.EV.E1 = el_una(OPind,e1.Ety,el_copytree(e1.EV.E1.EV.E1)); 3756 return optelem(e,GOALvalue); 3757 } 3758 } 3759 3760 if (OPTIMIZER) 3761 { 3762 elem *e2 = e.EV.E2; 3763 int op2 = e2.Eoper; 3764 3765 // Replace (e1 = *p++) with (e1 = *p, p++, e1) 3766 elem *ei = e2; 3767 if (e1.Eoper == OPvar && 3768 (op2 == OPind || (OTunary(op2) && (ei = e2.EV.E1).Eoper == OPind)) && 3769 (ei.EV.E1.Eoper == OPpostinc || ei.EV.E1.Eoper == OPpostdec) && 3770 !el_sideeffect(e1) && 3771 !el_sideeffect(ei.EV.E1.EV.E1) 3772 ) 3773 { 3774 e = el_bin(OPcomma,e.Ety, 3775 e, 3776 el_bin(OPcomma,e.Ety,ei.EV.E1,el_copytree(e1))); 3777 ei.EV.E1 = el_copytree(ei.EV.E1.EV.E1); // copy p 3778 return optelem(e,GOALvalue); 3779 } 3780 3781 /* Replace (e = e) with (e,e) */ 3782 if (el_match(e1,e2)) 3783 { 3784 e.Eoper = OPcomma; 3785 L1: 3786 return optelem(e,GOALvalue); 3787 } 3788 3789 // Replace (e1 = (e21 , e22)) with (e21 , (e1 = e22)) 3790 if (op2 == OPcomma) 3791 { 3792 e2.Ety = e.Ety; 3793 e.EV.E2 = e2.EV.E2; 3794 e2.EV.E2 = e; 3795 e = e2; 3796 goto L1; 3797 } 3798 3799 if (OTop(op2) && !el_sideeffect(e1) 3800 && op2 != OPdiv && op2 != OPmod 3801 ) 3802 { 3803 tym_t ty; 3804 3805 enum side = false; // don't allow side effects in e2.EV.E2 because of 3806 // D order-of-evaluation rules 3807 3808 // Replace (e1 = e1 op e) with (e1 op= e) 3809 if (el_match(e1,e2.EV.E1) && 3810 (side || !el_sideeffect(e2.EV.E2))) 3811 { 3812 ty = e2.EV.E2.Ety; 3813 e.EV.E2 = el_selecte2(e2); 3814 L2: 3815 e.EV.E2.Ety = ty; 3816 e.Eoper = cast(ubyte)optoopeq(op2); 3817 goto L1; 3818 } 3819 if (OTcommut(op2)) 3820 { 3821 /* Replace (e1 = e op e1) with (e1 op= e) */ 3822 if (el_match(e1,e2.EV.E2)) 3823 { ty = e2.EV.E1.Ety; 3824 e.EV.E2 = el_selecte1(e2); 3825 goto L2; 3826 } 3827 } 3828 3829 static if (0) 3830 { 3831 // Note that this optimization is undone in elcomma(), this results in an 3832 // infinite loop. This optimization is preferable if e1 winds up a register 3833 // variable, the inverse in elcomma() is preferable if e1 winds up in memory. 3834 // Replace (e1 = (e1 op3 ea) op2 eb) with (e1 op3= ea),(e1 op2= eb) 3835 int op3 = e2.EV.E1.Eoper; 3836 if (OTop(op3) && el_match(e1,e2.EV.E1.EV.E1) && !el_depends(e1,e2.EV.E2)) 3837 { 3838 e.Eoper = OPcomma; 3839 e.EV.E1 = e2.EV.E1; 3840 e.EV.E1.Eoper = optoopeq(op3); 3841 e2.EV.E1 = e1; 3842 e1.Ety = e.EV.E1.Ety; 3843 e2.Eoper = optoopeq(op2); 3844 e2.Ety = e.Ety; 3845 goto L1; 3846 } 3847 } 3848 } 3849 3850 if (op2 == OPneg && el_match(e1,e2.EV.E1) && !el_sideeffect(e1)) 3851 { 3852 // Replace (i = -i) with (negass i) 3853 e.Eoper = OPnegass; 3854 e.EV.E2 = null; 3855 el_free(e2); 3856 return optelem(e, GOALvalue); 3857 } 3858 3859 // Replace (x = (y ? z : x)) with ((y && (x = z)),x) 3860 if (op2 == OPcond && el_match(e1,e2.EV.E2.EV.E2)) 3861 { 3862 elem *e22 = e2.EV.E2; // e22 is the OPcond 3863 e.Eoper = OPcomma; 3864 e.EV.E2 = e1; 3865 e.EV.E1 = e2; 3866 e2.Eoper = OPandand; 3867 e2.Ety = TYint; 3868 e22.Eoper = OPeq; 3869 e22.Ety = e.Ety; 3870 e1 = e22.EV.E1; 3871 e22.EV.E1 = e22.EV.E2; 3872 e22.EV.E2 = e1; 3873 return optelem(e,GOALvalue); 3874 } 3875 3876 // Replace (x = (y ? x : z)) with ((y || (x = z)),x) 3877 if (op2 == OPcond && el_match(e1,e2.EV.E2.EV.E1)) 3878 { 3879 elem *e22 = e2.EV.E2; // e22 is the OPcond 3880 e.Eoper = OPcomma; 3881 e.EV.E2 = e1; 3882 e.EV.E1 = e2; 3883 e2.Eoper = OPoror; 3884 e2.Ety = TYint; 3885 e22.Eoper = OPeq; 3886 e22.Ety = e.Ety; 3887 return optelem(e,GOALvalue); 3888 } 3889 3890 // If floating point, replace (x = -y) with (x = y ^ signbit) 3891 if (op2 == OPneg && (tyreal(e2.Ety) || tyimaginary(e2.Ety)) && 3892 (e2.EV.E1.Eoper == OPvar || e2.EV.E1.Eoper == OPind) && 3893 /* Turned off for XMM registers because they don't play well with 3894 * int registers. 3895 */ 3896 !config.fpxmmregs) 3897 { 3898 tym_t ty; 3899 3900 elem *es = el_calloc(); 3901 es.Eoper = OPconst; 3902 switch (tysize(e2.Ety)) 3903 { 3904 case FLOATSIZE: 3905 ty = TYlong; 3906 es.EV.Vlong = 0x80000000; 3907 break; 3908 3909 case DOUBLESIZE: 3910 if (I32) 3911 { 3912 ty = TYllong; 3913 es.EV.Vllong = 0x8000000000000000L; 3914 break; 3915 } 3916 goto default; 3917 3918 default: 3919 el_free(es); 3920 goto L8; 3921 } 3922 es.Ety = ty; 3923 e1.Ety = ty; 3924 e2.Ety = ty; 3925 e2.EV.E1.Ety = ty; 3926 e2.EV.E2 = es; 3927 e2.Eoper = OPxor; 3928 return optelem(e,GOALvalue); 3929 3930 L8: 3931 } 3932 3933 // Replace (a=(r1 pair r2)) with (a1=r1), (a2=r2) 3934 if (tysize(e1.Ety) == 2 * REGSIZE && 3935 e1.Eoper == OPvar && 3936 (e2.Eoper == OPpair || e2.Eoper == OPrpair) && 3937 goal == GOALnone && 3938 !el_appears(e2, e1.EV.Vsym) && 3939 // this clause needs investigation because the code doesn't match the comment 3940 // Disable this rewrite if we're using x87 and `e1` is a FP-value 3941 // but `e2` is not, or vice versa 3942 // https://issues.dlang.org/show_bug.cgi?id=18197 3943 (config.fpxmmregs || 3944 (tyfloating(e2.EV.E1.Ety) != 0) == (tyfloating(e2.Ety) != 0)) 3945 ) 3946 { 3947 // printf("** before:\n"); elem_print(e); printf("\n"); 3948 tym_t ty = (REGSIZE == 8) ? TYllong : TYint; 3949 if (tyfloating(e1.Ety) && REGSIZE >= 4) 3950 ty = (REGSIZE == 8) ? TYdouble : TYfloat; 3951 ty |= e1.Ety & ~mTYbasic; 3952 e2.Ety = ty; 3953 e.Ety = ty; 3954 e1.Ety = ty; 3955 elem *eb = el_copytree(e1); 3956 eb.EV.Voffset += REGSIZE; 3957 3958 if (e2.Eoper == OPpair) 3959 { 3960 e.EV.E2 = e2.EV.E1; 3961 eb = el_bin(OPeq,ty,eb,e2.EV.E2); 3962 e2.EV.E1 = e; 3963 e2.EV.E2 = eb; 3964 } 3965 else 3966 { 3967 e.EV.E2 = e2.EV.E2; 3968 eb = el_bin(OPeq,ty,eb,e2.EV.E1); 3969 e2.EV.E1 = eb; 3970 e2.EV.E2 = e; 3971 } 3972 3973 e2.Eoper = OPcomma; 3974 // printf("** after:\n"); elem_print(e2); printf("\n"); 3975 return optelem(e2,goal); 3976 } 3977 3978 // Replace (a=b) with (a1=b1),(a2=b2) 3979 if (tysize(e1.Ety) == 2 * REGSIZE && 3980 e1.Eoper == OPvar && 3981 e2.Eoper == OPvar && 3982 goal == GOALnone && 3983 !tyfloating(e1.Ety) && !tyvector(e1.Ety) 3984 ) 3985 { 3986 tym_t ty = (REGSIZE == 8) ? TYllong : TYint; 3987 ty |= e1.Ety & ~mTYbasic; 3988 e2.Ety = ty; 3989 e.Ety = ty; 3990 e1.Ety = ty; 3991 3992 elem *eb = el_copytree(e); 3993 eb.EV.E1.EV.Voffset += REGSIZE; 3994 eb.EV.E2.EV.Voffset += REGSIZE; 3995 3996 e = el_bin(OPcomma,ty,e,eb); 3997 return optelem(e,goal); 3998 } 3999 } 4000 4001 if (e1.Eoper == OPcomma) 4002 return cgel_lvalue(e); 4003 if (e1.Eoper != OPbit) 4004 return e; 4005 if (e1.EV.E1.Eoper == OPcomma || OTassign(e1.EV.E1.Eoper)) 4006 return cgel_lvalue(e); 4007 4008 uint t = e.Ety; 4009 elem *l = e1.EV.E1; // lvalue 4010 elem *r = e.EV.E2; 4011 tym_t tyl = l.Ety; 4012 uint sz = tysize(tyl) * 8; 4013 uint w = (e1.EV.E2.EV.Vuns >> 8); // width in bits of field 4014 targ_ullong m = (cast(targ_ullong)1 << w) - 1; // mask w bits wide 4015 uint b = e1.EV.E2.EV.Vuns & 0xFF; // bits to shift 4016 4017 elem *l2; 4018 elem *r2; 4019 elem *eres = el_bin(OPeq,t, 4020 l, 4021 el_bin(OPor,t, 4022 el_bin(OPshl,t, 4023 (r2 = el_bin(OPand,t,r,el_long(t,m))), 4024 el_long(TYint,b) 4025 ), 4026 el_bin(OPand,t, 4027 (l2 = el_copytree(l)), 4028 el_long(t,~(m << b)) 4029 ) 4030 ) 4031 ); 4032 eres.Esrcpos = e.Esrcpos; // save line information 4033 if (OPTIMIZER && w + b == sz) 4034 r2.EV.E2.EV.Vllong = ~ZEROLL; // no need to mask if left justified 4035 if (wantres) 4036 { 4037 uint c; 4038 elem **pe; 4039 elem *e2; 4040 4041 r = el_copytree(r); 4042 if (tyuns(tyl)) /* uint bit field */ 4043 { 4044 e2 = el_bin(OPand,t,r,el_long(t,m)); 4045 pe = &e2.EV.E1; 4046 } 4047 else /* signed bit field */ 4048 { 4049 OPER shift = OPshr; 4050 shift = OPashr; 4051 c = sz - w; /* e2 = (r << c) >> c */ 4052 e2 = el_bin(shift,t,el_bin(OPshl,tyl,r,el_long(TYint,c)),el_long(TYint,c)); 4053 pe = &e2.EV.E1.EV.E1; 4054 } 4055 eres = el_bin(OPcomma,t,eres,e2); 4056 if (!OTleaf(r.Eoper)) 4057 fixside(&(r2.EV.E1),pe); 4058 } 4059 4060 if (!OTleaf(l.Eoper) && !OTleaf(l.EV.E1.Eoper)) 4061 fixside(&(l2.EV.E1),&(l.EV.E1)); 4062 e1.EV.E1 = e.EV.E2 = null; 4063 el_free(e); 4064 return optelem(eres,GOALvalue); 4065 } 4066 4067 /********************************** 4068 */ 4069 4070 private elem * elnegass(elem *e, goal_t goal) 4071 { 4072 e = cgel_lvalue(e); 4073 return e; 4074 } 4075 4076 /************************** 4077 * Add assignment. Replace bit field assignment with 4078 * equivalent tree. 4079 * += 4080 * / \ 4081 * / r 4082 * bit 4083 * / \ 4084 * l w,b 4085 * 4086 * becomes: 4087 * = 4088 * / \ 4089 * l | 4090 * / \ 4091 * << \ 4092 * / \ \ 4093 * & b & 4094 * / \ / \ 4095 * op m l ~(m<<b) 4096 * / \ 4097 * & r 4098 * / \ 4099 * >> m 4100 * / \ 4101 * l b 4102 */ 4103 4104 @trusted 4105 private elem * elopass(elem *e, goal_t goal) 4106 { 4107 elem *e1 = e.EV.E1; 4108 if (OTconv(e1.Eoper)) 4109 { e = fixconvop(e); 4110 return optelem(e,GOALvalue); 4111 } 4112 4113 goal_t wantres = goal; 4114 if (e1.Eoper == OPbit) 4115 { 4116 const op = opeqtoop(e.Eoper); 4117 4118 // Make sure t is uint 4119 // so >> doesn't have to be masked 4120 tym_t t = touns(e.Ety); 4121 4122 assert(tyintegral(t)); 4123 elem *l = e1.EV.E1; // lvalue 4124 tym_t tyl = l.Ety; 4125 elem *r = e.EV.E2; 4126 uint w = (e1.EV.E2.EV.Vuns >> 8) & 0xFF; // width in bits of field 4127 targ_llong m = (cast(targ_llong)1 << w) - 1; // mask w bits wide 4128 uint b = e1.EV.E2.EV.Vuns & 0xFF; // bits to shift 4129 4130 elem* l2,l3,op2,eres; 4131 4132 if (tyuns(tyl)) 4133 { 4134 eres = el_bin(OPeq,t, 4135 l, 4136 el_bin(OPor,t, 4137 (op2=el_bin(OPshl,t, 4138 el_bin(OPand,t, 4139 el_bin(op,t, 4140 el_bin(OPand,t, 4141 el_bin(OPshr,t, 4142 (l2=el_copytree(l)), 4143 el_long(TYint,b) 4144 ), 4145 el_long(t,m) 4146 ), 4147 r 4148 ), 4149 el_long(t,m) 4150 ), 4151 el_long(TYint,b) 4152 )), 4153 el_bin(OPand,t, 4154 l3=el_copytree(l), 4155 el_long(t,~(m << b)) 4156 ) 4157 ) 4158 ); 4159 4160 if (wantres) 4161 { 4162 eres = el_bin(OPcomma,t,eres,el_copytree(op2.EV.E1)); 4163 fixside(&(op2.EV.E1),&(eres.EV.E2)); 4164 } 4165 } 4166 else 4167 { /* signed bit field 4168 rewrite to: (l bit w,b) = ((l bit w,b) op r) 4169 */ 4170 e.Eoper = OPeq; 4171 e.EV.E2 = el_bin(op,t,el_copytree(e1),r); 4172 if (l.Eoper == OPind) 4173 fixside(&e.EV.E2.EV.E1.EV.E1.EV.E1,&l.EV.E1); 4174 eres = e; 4175 goto ret; 4176 } 4177 4178 if (!OTleaf(l.Eoper) && !OTleaf(l.EV.E1.Eoper)) 4179 { 4180 fixside(&(l2.EV.E1),&(l.EV.E1)); 4181 el_free(l3.EV.E1); 4182 l3.EV.E1 = el_copytree(l.EV.E1); 4183 } 4184 4185 e1.EV.E1 = e.EV.E2 = null; 4186 el_free(e); 4187 ret: 4188 e = optelem(eres,GOALvalue); 4189 return e; 4190 } 4191 4192 { 4193 if (e1.Eoper == OPcomma || OTassign(e1.Eoper)) 4194 e = cgel_lvalue(e); // replace (e,v)op=e2 with e,(v op= e2) 4195 else 4196 { 4197 switch (e.Eoper) 4198 { 4199 case OPmulass: 4200 e = elmul(e,GOALvalue); 4201 break; 4202 4203 case OPdivass: 4204 // Replace r/=c with r=r/c 4205 if (tycomplex(e.EV.E2.Ety) && !tycomplex(e1.Ety)) 4206 { 4207 elem *ed; 4208 e.Eoper = OPeq; 4209 if (e1.Eoper == OPind) 4210 { // ed: *(tmp=e1.EV.E1) 4211 // e1: *tmp 4212 elem *tmp = el_alloctmp(e1.EV.E1.Ety); 4213 ed = el_bin(OPeq, tmp.Ety, tmp, e1.EV.E1); 4214 e1.EV.E1 = el_copytree(tmp); 4215 ed = el_una(OPind, e1.Ety, ed); 4216 } 4217 else 4218 ed = el_copytree(e1); 4219 // e: e1=ed/e2 4220 e.EV.E2 = el_bin(OPdiv, e.EV.E2.Ety, ed, e.EV.E2); 4221 if (tyreal(e1.Ety)) 4222 e.EV.E2 = el_una(OPc_r, e1.Ety, e.EV.E2); 4223 else 4224 e.EV.E2 = el_una(OPc_i, e1.Ety, e.EV.E2); 4225 return optelem(e, GOALvalue); 4226 } 4227 // Replace x/=y with x=x/y 4228 if (OPTIMIZER && 4229 tyintegral(e.EV.E1.Ety) && 4230 e.EV.E1.Eoper == OPvar && 4231 !el_sideeffect(e.EV.E1)) 4232 { 4233 e.Eoper = OPeq; 4234 e.EV.E2 = el_bin(OPdiv, e.EV.E2.Ety, el_copytree(e.EV.E1), e.EV.E2); 4235 return optelem(e, GOALvalue); 4236 } 4237 e = eldiv(e, GOALvalue); 4238 break; 4239 4240 case OPmodass: 4241 // Replace x%=y with x=x%y 4242 if (OPTIMIZER && 4243 tyintegral(e.EV.E1.Ety) && 4244 e.EV.E1.Eoper == OPvar && 4245 !el_sideeffect(e.EV.E1)) 4246 { 4247 e.Eoper = OPeq; 4248 e.EV.E2 = el_bin(OPmod, e.EV.E2.Ety, el_copytree(e.EV.E1), e.EV.E2); 4249 return optelem(e, GOALvalue); 4250 } 4251 break; 4252 4253 default: 4254 break; 4255 } 4256 } 4257 } 4258 return e; 4259 } 4260 4261 /************************** 4262 * Add assignment. Replace bit field post assignment with 4263 * equivalent tree. 4264 * (l bit w,b) ++ r 4265 * becomes: 4266 * (((l bit w,b) += r) - r) & m 4267 */ 4268 4269 @trusted 4270 private elem * elpost(elem *e, goal_t goal) 4271 { 4272 elem *e1 = e.EV.E1; 4273 if (e1.Eoper != OPbit) 4274 { 4275 if (e1.Eoper == OPcomma || OTassign(e1.Eoper)) 4276 return cgel_lvalue(e); // replace (e,v)op=e2 with e,(v op= e2) 4277 return e; 4278 } 4279 4280 assert(e.EV.E2.Eoper == OPconst); 4281 targ_llong r = el_tolong(e.EV.E2); 4282 4283 uint w = (e1.EV.E2.EV.Vuns >> 8) & 0xFF; // width in bits of field 4284 targ_llong m = (cast(targ_llong)1 << w) - 1; // mask w bits wide 4285 4286 tym_t ty = e.Ety; 4287 if (e.Eoper != OPpostinc) 4288 r = -r; 4289 e.Eoper = (e.Eoper == OPpostinc) ? OPaddass : OPminass; 4290 e = el_bin(OPmin,ty,e,el_long(ty,r)); 4291 if (tyuns(e1.EV.E1.Ety)) /* if uint bit field */ 4292 e = el_bin(OPand,ty,e,el_long(ty,m)); 4293 return optelem(e,GOALvalue); 4294 } 4295 4296 /*************************** 4297 * Take care of compares. 4298 * (e == 0) => (!e) 4299 * (e != 0) => (bool e) 4300 */ 4301 4302 @trusted 4303 private elem * elcmp(elem *e, goal_t goal) 4304 { 4305 elem *e2 = e.EV.E2; 4306 elem *e1 = e.EV.E1; 4307 4308 //printf("elcmp(%p)\n",e); elem_print(e); 4309 4310 if (tyvector(e1.Ety)) // vectors don't give boolean result 4311 return e; 4312 4313 if (OPTIMIZER) 4314 { 4315 auto op = e.Eoper; 4316 4317 // Convert comparison of OPrelconsts of the same symbol to comparisons 4318 // of their offsets. 4319 if (e1.Eoper == OPrelconst && e2.Eoper == OPrelconst && 4320 e1.EV.Vsym == e2.EV.Vsym) 4321 { 4322 e1.Eoper = OPconst; 4323 e1.Ety = TYptrdiff; 4324 e2.Eoper = OPconst; 4325 e2.Ety = TYptrdiff; 4326 return optelem(e,GOALvalue); 4327 } 4328 4329 // Convert comparison of long pointers to comparison of integers 4330 if ((op == OPlt || op == OPle || op == OPgt || op == OPge) && 4331 tyfv(e2.Ety) && tyfv(e1.Ety)) 4332 { 4333 e.EV.E1 = el_una(OP32_16,e.Ety,e1); 4334 e.EV.E2 = el_una(OP32_16,e.Ety,e2); 4335 return optelem(e,GOALvalue); 4336 } 4337 4338 // Convert ((e & 1) == 1) => (e & 1) 4339 if (op == OPeqeq && e2.Eoper == OPconst && e1.Eoper == OPand) 4340 { 4341 elem *e12 = e1.EV.E2; 4342 4343 if (e12.Eoper == OPconst && el_tolong(e2) == 1 && el_tolong(e12) == 1) 4344 { 4345 tym_t ty = e.Ety; 4346 tym_t ty1 = e1.Ety; 4347 e = el_selecte1(e); 4348 e.Ety = ty1; 4349 int sz = tysize(ty); 4350 for (int sz1 = tysize(ty1); sz1 != sz; sz1 = tysize(e.Ety)) 4351 { 4352 switch (sz1) 4353 { 4354 case 1: 4355 e = el_una(OPu8_16,TYshort,e); 4356 break; 4357 case 2: 4358 if (sz > 2) 4359 e = el_una(OPu16_32,TYlong,e); 4360 else 4361 e = el_una(OP16_8,TYuchar,e); 4362 break; 4363 case 4: 4364 if (sz > 2) 4365 e = el_una(OPu32_64,TYshort,e); 4366 else 4367 e = el_una(OP32_16,TYshort,e); 4368 break; 4369 case 8: 4370 e = el_una(OP64_32,TYlong,e); 4371 break; 4372 default: 4373 assert(0); 4374 } 4375 } 4376 e.Ety = ty; 4377 return optelem(e,GOALvalue); 4378 } 4379 } 4380 } 4381 4382 int uns = tyuns(e1.Ety) | tyuns(e2.Ety); 4383 if (cnst(e2)) 4384 { 4385 tym_t tym; 4386 int sz = tysize(e2.Ety); 4387 4388 if (e1.Eoper == OPu16_32 && e2.EV.Vulong <= cast(targ_ulong) SHORTMASK || 4389 e1.Eoper == OPs16_32 && 4390 e2.EV.Vlong == cast(targ_short) e2.EV.Vlong) 4391 { 4392 tym = (uns || e1.Eoper == OPu16_32) ? TYushort : TYshort; 4393 e.EV.E2 = el_una(OP32_16,tym,e2); 4394 goto L2; 4395 } 4396 4397 /* Try to convert to byte/word comparison for ((x & c)==d) 4398 when mask c essentially casts x to a smaller type 4399 */ 4400 if (OPTIMIZER && 4401 e1.Eoper == OPand && 4402 e1.EV.E2.Eoper == OPconst && 4403 sz > CHARSIZE) 4404 { 4405 OPER op; 4406 assert(tyintegral(e2.Ety) || typtr(e2.Ety)); 4407 /* ending up with byte ops in A regs */ 4408 if (!(el_tolong(e2) & ~CHARMASK) && 4409 !(el_tolong(e1.EV.E2) & ~CHARMASK) 4410 ) 4411 { 4412 if (sz == LLONGSIZE) 4413 { 4414 e1.EV.E1 = el_una(OP64_32,TYulong,e1.EV.E1); 4415 e1.EV.E1 = el_una(OP32_16,TYushort,e1.EV.E1); 4416 } 4417 else if (sz == LONGSIZE) 4418 e1.EV.E1 = el_una(OP32_16,TYushort,e1.EV.E1); 4419 tym = TYuchar; 4420 op = OP16_8; 4421 goto L4; 4422 } 4423 if (_tysize[TYint] == SHORTSIZE && /* not a win when regs are long */ 4424 sz == LONGSIZE && 4425 !(e2.EV.Vulong & ~SHORTMASK) && 4426 !(e1.EV.E2.EV.Vulong & ~SHORTMASK) 4427 ) 4428 { 4429 tym = TYushort; 4430 op = OP32_16; 4431 L4: 4432 e2.Ety = tym; 4433 e1.Ety = tym; 4434 e1.EV.E2.Ety = tym; 4435 e1.EV.E1 = el_una(op,tym,e1.EV.E1); 4436 e = optelem(e,GOALvalue); 4437 goto ret; 4438 } 4439 } 4440 4441 if (e1.Eoper == OPf_d && tysize(e1.Ety) == 8 && cast(targ_float)e2.EV.Vdouble == e2.EV.Vdouble) 4442 { 4443 /* Remove unnecessary OPf_d operator 4444 */ 4445 e.EV.E1 = e1.EV.E1; 4446 e1.EV.E1 = null; 4447 el_free(e1); 4448 e2.Ety = e.EV.E1.Ety; 4449 e2.EV.Vfloat = cast(targ_float)e2.EV.Vdouble; 4450 return optelem(e,GOALvalue); 4451 } 4452 4453 if (e1.Eoper == OPd_ld && tysize(e1.Ety) == tysize(TYldouble) && cast(targ_double)e2.EV.Vldouble == e2.EV.Vldouble) 4454 { 4455 /* Remove unnecessary OPd_ld operator 4456 */ 4457 e.EV.E1 = e1.EV.E1; 4458 e1.EV.E1 = null; 4459 el_free(e1); 4460 e2.Ety = e.EV.E1.Ety; 4461 e2.EV.Vdouble = cast(targ_double)e2.EV.Vldouble; 4462 return optelem(e,GOALvalue); 4463 } 4464 4465 /* Convert (ulong > uint.max) to (msw(ulong) != 0) 4466 */ 4467 if (OPTIMIZER && I32 && e.Eoper == OPgt && sz == LLONGSIZE && e2.EV.Vullong == 0xFFFFFFFF) 4468 { 4469 e.Eoper = OPne; 4470 e2.Ety = TYulong; 4471 e2.EV.Vulong = 0; 4472 e.EV.E1 = el_una(OPmsw,TYulong,e1); 4473 e = optelem(e,GOALvalue); 4474 goto ret; 4475 } 4476 4477 if (e1.Eoper == OPu8_16 && e2.EV.Vuns < 256 || 4478 e1.Eoper == OPs8_16 && 4479 e2.EV.Vint == cast(targ_schar) e2.EV.Vint) 4480 { 4481 tym = (uns || e1.Eoper == OPu8_16) ? TYuchar : TYschar; 4482 e.EV.E2 = el_una(OP16_8,tym,e2); 4483 L2: 4484 tym |= e1.Ety & ~mTYbasic; 4485 e.EV.E1 = el_selecte1(e1); 4486 e.EV.E1.Ety = tym; 4487 e = optelem(e,GOALvalue); 4488 } 4489 else if (!boolres(e2)) 4490 { 4491 targ_int i; 4492 switch (e.Eoper) 4493 { 4494 case OPle: // (u <= 0) becomes (u == 0) 4495 if (!uns) 4496 break; 4497 goto case OPeqeq; 4498 4499 case OPeqeq: 4500 e.Eoper = OPnot; 4501 goto L5; 4502 4503 case OPgt: // (u > 0) becomes (u != 0) 4504 if (!uns) 4505 break; 4506 goto case OPne; 4507 4508 case OPne: 4509 e.Eoper = OPbool; 4510 L5: el_free(e2); 4511 e.EV.E2 = null; 4512 e = optelem(e,GOALvalue); 4513 break; 4514 4515 case OPge: 4516 i = 1; // (u >= 0) becomes (u,1) 4517 goto L3; 4518 4519 case OPlt: // (u < 0) becomes (u,0) 4520 i = 0; 4521 L3: 4522 if (uns) 4523 { 4524 e2.EV.Vint = i; 4525 e2.Ety = TYint; 4526 e.Eoper = OPcomma; 4527 e = optelem(e,GOALvalue); 4528 } 4529 else 4530 { 4531 if (tyintegral(e1.Ety) && sz == 2 * REGSIZE) 4532 { 4533 // Only need to examine MSW 4534 tym_t ty = sz == 4 ? TYint : 4535 sz == 8 ? TYint : 4536 TYlong; // for TYcent's 4537 e.EV.E1 = el_una(OPmsw, ty, e1); 4538 e2.Ety = ty; 4539 return optelem(e, GOALvalue); 4540 } 4541 } 4542 break; 4543 4544 default: 4545 break; 4546 } 4547 } 4548 else if (OPTIMIZER && uns && tysize(e2.Ety) == 2 && 4549 cast(ushort)e2.EV.Vuns == 0x8000 && 4550 (e.Eoper == OPlt || e.Eoper == OPge) 4551 ) 4552 { 4553 // Convert to signed comparison against 0 4554 tym_t ty = tybasic(e2.Ety); 4555 switch (_tysize[ty]) 4556 { 4557 case 1: ty = TYschar; break; 4558 case 2: ty = TYshort; break; 4559 default: assert(0); 4560 } 4561 e.Eoper ^= (OPlt ^ OPge); // switch between them 4562 e2.EV.Vuns = 0; 4563 e2.Ety = ty | (e2.Ety & ~mTYbasic); 4564 e1.Ety = ty | (e1.Ety & ~mTYbasic); 4565 } 4566 else if (OPTIMIZER && e1.Eoper == OPeq && 4567 e1.EV.E2.Eoper == OPconst) 4568 { // Convert ((x = c1) rel c2) to ((x = c1),(c1 rel c2) 4569 elem *ec = el_copytree(e1.EV.E2); 4570 ec.Ety = e1.Ety; 4571 e.EV.E1 = ec; 4572 e = el_bin(OPcomma,e.Ety,e1,e); 4573 e = optelem(e,GOALvalue); 4574 } 4575 } 4576 else if (( 4577 (e1.Eoper == OPu8_16 || 4578 e1.Eoper == OPs8_16)|| 4579 (e1.Eoper == OPu16_32 || 4580 e1.Eoper == OPs16_32) 4581 ) && 4582 e1.Eoper == e2.Eoper) 4583 { 4584 if (uns) 4585 { 4586 e1.EV.E1.Ety = touns(e1.EV.E1.Ety); 4587 e2.EV.E1.Ety = touns(e2.EV.E1.Ety); 4588 } 4589 e1.Ety = e1.EV.E1.Ety; 4590 e2.Ety = e2.EV.E1.Ety; 4591 e.EV.E1 = el_selecte1(e1); 4592 e.EV.E2 = el_selecte1(e2); 4593 e = optelem(e,GOALvalue); 4594 } 4595 ret: 4596 return e; 4597 } 4598 4599 /***************************** 4600 * Boolean operator. 4601 * OPbool 4602 */ 4603 4604 @trusted 4605 private elem * elbool(elem *e, goal_t goal) 4606 { 4607 //printf("elbool()\n"); 4608 elem* e1 = e.EV.E1; 4609 const op = e1.Eoper; 4610 4611 if (OTlogical(op) || 4612 // bool bool => bool 4613 (tybasic(e1.Ety) == TYbool && tysize(e.Ety) == 1) 4614 ) 4615 return el_selecte1(e); 4616 4617 switch (op) 4618 { 4619 case OPs32_d: 4620 case OPs16_d: 4621 case OPu16_d: 4622 case OPu32_d: 4623 case OPf_d: 4624 case OPd_ld: 4625 case OPs16_32: 4626 case OPu16_32: 4627 case OPu8_16: 4628 case OPs8_16: 4629 case OPu32_64: 4630 case OPs32_64: 4631 case OPvp_fp: 4632 case OPcvp_fp: 4633 case OPnp_fp: 4634 e1.Eoper = e.Eoper; 4635 return optelem(el_selecte1(e), goal); 4636 4637 default: 4638 break; 4639 } 4640 4641 if (OPTIMIZER) 4642 { 4643 int shift; 4644 4645 // Replace bool(x,1) with (x,1),1 4646 e1 = elscancommas(e1); 4647 if (cnst(e1) || e1.Eoper == OPrelconst) 4648 { 4649 int i = boolres(e1) != 0; 4650 e.Eoper = OPcomma; 4651 e.EV.E2 = el_long(e.Ety,i); 4652 e = optelem(e,GOALvalue); 4653 return e; 4654 } 4655 4656 // Replace bool(e & 1) with (uint char)(e & 1) 4657 else if (e.EV.E1.Eoper == OPand && e.EV.E1.EV.E2.Eoper == OPconst && el_tolong(e.EV.E1.EV.E2) == 1) 4658 { 4659 L1: 4660 uint sz = tysize(e.EV.E1.Ety); 4661 tym_t ty = e.Ety; 4662 switch (sz) 4663 { 4664 case 1: 4665 e = el_selecte1(e); 4666 break; 4667 4668 case 2: 4669 e.Eoper = OP16_8; 4670 break; 4671 4672 case 4: 4673 e.Eoper = OP32_16; 4674 e.Ety = TYushort; 4675 e = el_una(OP16_8, ty, e); 4676 break; 4677 4678 case 8: 4679 e.Eoper = OP64_32; 4680 e.Ety = TYulong; 4681 e = el_una(OP32_16, TYushort, e); 4682 e = el_una(OP16_8, ty, e); 4683 break; 4684 4685 default: 4686 assert(0); 4687 } 4688 e = optelem(e,GOALvalue); 4689 } 4690 4691 // Replace bool(e % 2) with (uint char)(e & 1) 4692 else if (e.EV.E1.Eoper == OPmod && e.EV.E1.EV.E2.Eoper == OPconst && el_tolong(e.EV.E1.EV.E2) == 2 4693 && !tyfloating(e.EV.E1.Ety)) // dont optimize fmod() 4694 { 4695 uint sz = tysize(e.EV.E1.Ety); 4696 tym_t ty = e.Ety; 4697 e.EV.E1.Eoper = OPand; 4698 e.EV.E1.EV.E2.EV.Vullong = 1; 4699 switch (sz) 4700 { 4701 case 1: 4702 e = el_selecte1(e); 4703 break; 4704 4705 case 2: 4706 e.Eoper = OP16_8; 4707 break; 4708 4709 case 4: 4710 e.Eoper = OP32_16; 4711 e.Ety = TYushort; 4712 e = el_una(OP16_8, ty, e); 4713 break; 4714 4715 case 8: 4716 e.Eoper = OP64_32; 4717 e.Ety = TYulong; 4718 e = el_una(OP32_16, TYushort, e); 4719 e = el_una(OP16_8, ty, e); 4720 break; 4721 4722 default: 4723 assert(0); 4724 } 4725 e = optelem(e,GOALvalue); 4726 } 4727 4728 // Replace bool((1<<c)&b) with -(b btst c) 4729 else if ((I32 || I64) && 4730 e.EV.E1.Eoper == OPand && 4731 e.EV.E1.EV.E1.Eoper == OPshl && 4732 e.EV.E1.EV.E1.EV.E1.Eoper == OPconst && el_tolong(e.EV.E1.EV.E1.EV.E1) == 1 && 4733 tysize(e.EV.E1.Ety) <= REGSIZE 4734 ) 4735 { 4736 tym_t ty = e.Ety; 4737 elem *ex = e.EV.E1.EV.E1; 4738 ex.Eoper = OPbtst; 4739 e.EV.E1.EV.E1 = null; 4740 ex.EV.E1 = e.EV.E1.EV.E2; 4741 e.EV.E1.EV.E2 = null; 4742 ex.Ety = e.Ety; 4743 el_free(e); 4744 e = ex; 4745 return optelem(e,GOALvalue); 4746 } 4747 4748 // Replace bool(a & c) when c is a power of 2 with ((a >> shift) & 1) 4749 else if (e.EV.E1.Eoper == OPand && 4750 e.EV.E1.EV.E2.Eoper == OPconst && 4751 (shift = ispow2(el_tolong(e.EV.E1.EV.E2))) != -1 4752 ) 4753 { 4754 e.EV.E1.EV.E1 = el_bin(OPshr, e.EV.E1.EV.E1.Ety, e.EV.E1.EV.E1, el_long(TYint, shift)); 4755 e.EV.E1.EV.E2.EV.Vullong = 1; 4756 goto L1; 4757 } 4758 } 4759 return e; 4760 } 4761 4762 4763 /********************************* 4764 * Conversions of pointers to far pointers. 4765 */ 4766 4767 @trusted 4768 private elem * elptrlptr(elem *e, goal_t goal) 4769 { 4770 if (e.EV.E1.Eoper == OPrelconst || e.EV.E1.Eoper == OPstring) 4771 { 4772 e.EV.E1.Ety = e.Ety; 4773 e = el_selecte1(e); 4774 } 4775 return e; 4776 } 4777 4778 4779 /********************************* 4780 * Conversions of handle pointers to far pointers. 4781 */ 4782 @trusted 4783 private elem * elvptrfptr(elem *e, goal_t goal) 4784 { 4785 elem *e1 = e.EV.E1; 4786 if (e1.Eoper == OPadd || e1.Eoper == OPmin) 4787 { 4788 elem *e12 = e1.EV.E2; 4789 if (tybasic(e12.Ety) != TYvptr) 4790 { 4791 /* Rewrite (vtof(e11 + e12)) to (vtof(e11) + e12) */ 4792 const op = e.Eoper; 4793 e.Eoper = e1.Eoper; 4794 e.EV.E2 = e12; 4795 e1.Ety = e.Ety; 4796 e1.Eoper = cast(ubyte)op; 4797 e1.EV.E2 = null; 4798 e = optelem(e,GOALvalue); 4799 } 4800 } 4801 return e; 4802 } 4803 4804 4805 /************************ 4806 * Optimize conversions of longs to ints. 4807 * Also used for (OPoffset) (TYfptr|TYvptr). 4808 * Also used for conversions of ints to bytes. 4809 */ 4810 4811 @trusted 4812 private elem * ellngsht(elem *e, goal_t goal) 4813 { 4814 //printf("ellngsht()\n"); 4815 tym_t ty = e.Ety; 4816 elem *e1 = e.EV.E1; 4817 switch (e1.Eoper) 4818 { 4819 case OPs16_32: 4820 case OPu16_32: 4821 case OPu8_16: 4822 case OPs8_16: 4823 // This fix is not quite right. For example, it fails 4824 // if e.Ety != e.EV.E1.EV.E1.Ety. The difference is when 4825 // one is uint and the other isn't. 4826 if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety)) 4827 break; 4828 e = el_selecte1(el_selecte1(e)); 4829 e.Ety = ty; 4830 return e; 4831 4832 case OPvar: // simply paint type of variable 4833 // Do not paint type of ints into bytes, as this causes 4834 // many CSEs to be missed, resulting in bad code. 4835 // Loading a word anyway is just as fast as loading a byte. 4836 // for 68000 byte is swapped, load byte != load word 4837 if (e.Eoper == OP16_8) 4838 { 4839 // Mark symbol as being used sometimes as a byte to 4840 // 80X86 - preclude using SI or DI 4841 // 68000 - preclude using An 4842 e1.EV.Vsym.Sflags |= GTbyte; 4843 } 4844 else 4845 e1.Ety = ty; 4846 e = el_selecte1(e); 4847 break; 4848 4849 case OPind: 4850 e = el_selecte1(e); 4851 break; 4852 4853 case OPnp_fp: 4854 if (e.Eoper != OPoffset) 4855 goto case_default; 4856 // Replace (offset)(ptrlptr)e11 with e11 4857 e = el_selecte1(el_selecte1(e)); 4858 e.Ety = ty; // retain original type 4859 break; 4860 4861 case OPbtst: 4862 e = el_selecte1(e); 4863 break; 4864 4865 default: // operator 4866 case_default: 4867 // Attempt to replace (lngsht)(a op b) with 4868 // ((lngsht)a op (lngsht)b). 4869 // op is now an integer op, which is cheaper. 4870 if (OTwid(e1.Eoper) && !OTassign(e1.Eoper)) 4871 { 4872 tym_t ty1 = e1.EV.E1.Ety; 4873 switch (e.Eoper) 4874 { 4875 case OP16_8: 4876 // Make sure e1.EV.E1 is of the type we're converting from 4877 if (tysize(ty1) <= _tysize[TYint]) 4878 { 4879 ty1 = (tyuns(ty1) ? TYuchar : TYschar) | 4880 (ty1 & ~mTYbasic); 4881 e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1); 4882 } 4883 // Rvalue may be an int if it is a shift operator 4884 if (OTbinary(e1.Eoper)) 4885 { tym_t ty2 = e1.EV.E2.Ety; 4886 4887 if (tysize(ty2) <= _tysize[TYint]) 4888 { 4889 ty2 = (tyuns(ty2) ? TYuchar : TYschar) | 4890 (ty2 & ~mTYbasic); 4891 e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2); 4892 } 4893 } 4894 break; 4895 4896 case OPoffset: 4897 if (_tysize[TYint] == LONGSIZE) 4898 { 4899 // Make sure e1.EV.E1 is of the type we're converting from 4900 if (tysize(ty1) > LONGSIZE) 4901 { 4902 ty1 = (tyuns(ty1) ? TYuint : TYint) | (ty1 & ~mTYbasic); 4903 e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1); 4904 } 4905 // Rvalue may be an int if it is a shift operator 4906 if (OTbinary(e1.Eoper)) 4907 { tym_t ty2 = e1.EV.E2.Ety; 4908 4909 if (tysize(ty2) > LONGSIZE) 4910 { 4911 ty2 = (tyuns(ty2) ? TYuint : TYint) | 4912 (ty2 & ~mTYbasic); 4913 e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2); 4914 } 4915 } 4916 break; 4917 } 4918 goto case OP32_16; 4919 4920 case OP32_16: 4921 // Make sure e1.EV.E1 is of the type we're converting from 4922 if (tysize(ty1) == LONGSIZE) 4923 { 4924 ty1 = (tyuns(ty1) ? TYushort : TYshort) | (ty1 & ~mTYbasic); 4925 e1.EV.E1 = el_una(e.Eoper,ty1,e1.EV.E1); 4926 } 4927 // Rvalue may be an int if it is a shift operator 4928 if (OTbinary(e1.Eoper)) 4929 { tym_t ty2 = e1.EV.E2.Ety; 4930 4931 if (tysize(ty2) == LONGSIZE) 4932 { 4933 ty2 = (tyuns(ty2) ? TYushort : TYshort) | 4934 (ty2 & ~mTYbasic); 4935 e1.EV.E2 = el_una(e.Eoper,ty2,e1.EV.E2); 4936 } 4937 } 4938 break; 4939 4940 default: 4941 assert(0); 4942 } 4943 e1.Ety = ty; 4944 e = el_selecte1(e); 4945 again = 1; 4946 return e; 4947 } 4948 break; 4949 } 4950 return e; 4951 } 4952 4953 4954 /************************ 4955 * Optimize conversions of long longs to ints. 4956 * OP64_32, OP128_64 4957 */ 4958 4959 @trusted 4960 private elem * el64_32(elem *e, goal_t goal) 4961 { 4962 tym_t ty = e.Ety; 4963 elem *e1 = e.EV.E1; 4964 switch (e1.Eoper) 4965 { 4966 case OPs32_64: 4967 case OPu32_64: 4968 case OPs64_128: 4969 case OPu64_128: 4970 if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety)) 4971 break; 4972 e = el_selecte1(el_selecte1(e)); 4973 e.Ety = ty; 4974 break; 4975 4976 case OPpair: 4977 if (tysize(ty) != tysize(e.EV.E1.EV.E1.Ety)) 4978 break; 4979 if (el_sideeffect(e1.EV.E2)) 4980 { 4981 // Rewrite (OP64_32(a pair b)) as ((t=a),(b,t)) 4982 elem *a = e1.EV.E1; 4983 elem *b = e1.EV.E2; 4984 elem *t = el_alloctmp(a.Ety); 4985 4986 e.Eoper = OPcomma; 4987 e.EV.E1 = el_bin(OPeq,a.Ety,t,a); 4988 e.EV.E2 = e1; 4989 4990 e1.Eoper = OPcomma; 4991 e1.EV.E1 = b; 4992 e1.EV.E2 = el_copytree(t); 4993 e1.Ety = e.Ety; 4994 break; 4995 } 4996 e = el_selecte1(el_selecte1(e)); 4997 e.Ety = ty; 4998 break; 4999 5000 case OPrpair: 5001 if (tysize(ty) != tysize(e.EV.E1.EV.E2.Ety)) 5002 break; 5003 if (el_sideeffect(e1.EV.E1)) 5004 { 5005 // Rewrite (OP64_32(a rpair b)) as (a,b) 5006 e = el_selecte1(e); 5007 e.Eoper = OPcomma; 5008 e.Ety = ty; 5009 break; 5010 } 5011 e = el_selecte2(el_selecte1(e)); 5012 e.Ety = ty; 5013 break; 5014 5015 case OPvar: // simply paint type of variable 5016 case OPind: 5017 e = el_selecte1(e); 5018 break; 5019 5020 case OPshr: // OP64_32(x >> 32) => OPmsw(x) 5021 if (e1.EV.E2.Eoper == OPconst && 5022 (e.Eoper == OP64_32 && el_tolong(e1.EV.E2) == 32 && !I64 || 5023 e.Eoper == OP128_64 && el_tolong(e1.EV.E2) == 64 && I64) 5024 ) 5025 { 5026 e.Eoper = OPmsw; 5027 e.EV.E1 = el_selecte1(e.EV.E1); 5028 } 5029 break; 5030 5031 case OPmul: 5032 if (config.exe & (EX_OSX | EX_OSX64)) // https://issues.dlang.org/show_bug.cgi?id=21047 5033 break; 5034 else 5035 goto case; 5036 5037 case OPadd: 5038 case OPmin: 5039 case OPor: 5040 case OPand: 5041 case OPxor: 5042 // OP64_32(a op b) => (OP64_32(a) op OP64_32(b)) 5043 e1.EV.E1 = el_una(e.Eoper, ty, e1.EV.E1); 5044 e1.EV.E2 = el_una(e.Eoper, ty, e1.EV.E2); 5045 e = el_selecte1(e); 5046 break; 5047 5048 default: 5049 break; 5050 } 5051 return e; 5052 } 5053 5054 5055 /******************************* 5056 * Convert complex to real. 5057 */ 5058 5059 @trusted 5060 private elem *elc_r(elem *e, goal_t goal) 5061 { 5062 elem *e1 = e.EV.E1; 5063 5064 if (e1.Eoper == OPvar || e1.Eoper == OPind) 5065 { 5066 e1.Ety = e.Ety; 5067 e = el_selecte1(e); 5068 } 5069 return e; 5070 } 5071 5072 /******************************* 5073 * Convert complex to imaginary. 5074 */ 5075 5076 @trusted 5077 private elem *elc_i(elem *e, goal_t goal) 5078 { 5079 elem *e1 = e.EV.E1; 5080 5081 if (e1.Eoper == OPvar) 5082 { 5083 e1.Ety = e.Ety; 5084 e1.EV.Voffset += tysize(e.Ety); 5085 e = el_selecte1(e); 5086 } 5087 else if (e1.Eoper == OPind) 5088 { 5089 e1.Ety = e.Ety; 5090 e = el_selecte1(e); 5091 e.EV.E1 = el_bin(OPadd, e.EV.E1.Ety, e.EV.E1, el_long(TYint, tysize(e.Ety))); 5092 return optelem(e, GOALvalue); 5093 } 5094 5095 return e; 5096 } 5097 5098 /****************************** 5099 * Handle OPu8_16 and OPs8_16. 5100 */ 5101 5102 @trusted 5103 private elem * elbyteint(elem *e, goal_t goal) 5104 { 5105 if (OTlogical(e.EV.E1.Eoper) || e.EV.E1.Eoper == OPbtst) 5106 { 5107 e.EV.E1.Ety = e.Ety; 5108 e = el_selecte1(e); 5109 return e; 5110 } 5111 return evalu8(e, goal); 5112 } 5113 5114 /****************************** 5115 * OPs32_64 5116 * OPu32_64 5117 */ 5118 @trusted 5119 private elem * el32_64(elem *e, goal_t goal) 5120 { 5121 if (REGSIZE == 8 && e.EV.E1.Eoper == OPbtst) 5122 { 5123 e.EV.E1.Ety = e.Ety; 5124 e = el_selecte1(e); 5125 return e; 5126 } 5127 return evalu8(e, goal); 5128 } 5129 5130 /**************************** 5131 * Handle OPu64_d, 5132 * OPd_ld OPu64_d, 5133 * OPd_f OPu64_d 5134 */ 5135 5136 @trusted 5137 private elem *elu64_d(elem *e, goal_t goal) 5138 { 5139 tym_t ty; 5140 elem** pu; 5141 if (e.Eoper == OPu64_d) 5142 { 5143 pu = &e.EV.E1; 5144 ty = TYdouble; 5145 } 5146 else if (e.Eoper == OPd_ld && e.EV.E1.Eoper == OPu64_d) 5147 { 5148 pu = &e.EV.E1.EV.E1; 5149 *pu = optelem(*pu, GOALvalue); 5150 ty = TYldouble; 5151 } 5152 else if (e.Eoper == OPd_f && e.EV.E1.Eoper == OPu64_d) 5153 { 5154 pu = &e.EV.E1.EV.E1; 5155 *pu = optelem(*pu, GOALvalue); 5156 ty = TYfloat; 5157 } 5158 5159 if (!pu || (*pu).Eoper == OPconst) 5160 return evalu8(e, goal); 5161 5162 elem* u = *pu; 5163 if (config.fpxmmregs && I64 && (ty == TYfloat || ty == TYdouble)) 5164 { 5165 /* Rewrite for SIMD as: 5166 * u >= 0 ? OPs64_d(u) : OPs64_d((u >> 1) | (u & 1)) * 2 5167 */ 5168 u.Ety = TYllong; 5169 elem *u1 = el_copytree(u); 5170 if (!OTleaf(u.Eoper)) 5171 fixside(&u, &u1); 5172 elem *u2 = el_copytree(u1); 5173 5174 u = el_bin(OPge, TYint, u, el_long(TYllong, 0)); 5175 5176 u1 = el_una(OPs64_d, TYdouble, u1); 5177 if (ty == TYfloat) 5178 u1 = el_una(OPd_f, TYfloat, u1); 5179 5180 elem* u3 = el_copytree(u2); 5181 u2 = el_bin(OPshr, TYullong, u2, el_long(TYullong, 1)); 5182 u3 = el_bin(OPand, TYullong, u3, el_long(TYullong, 1)); 5183 u2 = el_bin(OPor, TYllong, u2, u3); 5184 5185 u2 = el_una(OPs64_d, TYdouble, u2); 5186 if (ty == TYfloat) 5187 u2 = el_una(OPd_f, TYfloat, u2); 5188 5189 u2 = el_bin(OPmul, ty, u2, el_long(ty, 2)); 5190 5191 elem* r = el_bin(OPcond, e.Ety, u, el_bin(OPcolon, e.Ety, u1, u2)); 5192 *pu = null; 5193 el_free(e); 5194 return optelem(r, GOALvalue); 5195 } 5196 if (config.inline8087) 5197 { 5198 /* Rewrite for x87 as: 5199 * u < 0 ? OPs64_d(u) : OPs64_d(u) + 0x1p+64 5200 */ 5201 u.Ety = TYllong; 5202 elem *u1 = el_copytree(u); 5203 if (!OTleaf(u.Eoper)) 5204 fixside(&u, &u1); 5205 5206 elem* eop1 = el_una(OPs64_d, TYdouble, u1); 5207 eop1 = el_una(OPd_ld, TYldouble, eop1); 5208 5209 elem* eoff = el_calloc(); 5210 eoff.Eoper = OPconst; 5211 eoff.Ety = TYldouble; 5212 eoff.EV.Vldouble = 0x1p+64; 5213 5214 elem* u2 = el_copytree(u1); 5215 u2 = el_una(OPs64_d, TYdouble, u2); 5216 u2 = el_una(OPd_ld, TYldouble, u2); 5217 5218 elem* eop2 = el_bin(OPadd, TYldouble, u2, eoff); 5219 5220 elem* r = el_bin(OPcond, TYldouble, 5221 el_bin(OPge, OPbool, u, el_long(TYllong, 0)), 5222 el_bin(OPcolon, TYldouble, eop1, eop2)); 5223 5224 if (ty != TYldouble) 5225 r = el_una(OPtoprec, e.Ety, r); 5226 5227 *pu = null; 5228 el_free(e); 5229 5230 return optelem(r, GOALvalue); 5231 } 5232 5233 return evalu8(e, goal); 5234 } 5235 5236 5237 /************************ 5238 * Handle <<, OProl and OPror 5239 */ 5240 5241 @trusted 5242 private elem *elshl(elem *e, goal_t goal) 5243 { 5244 tym_t ty = e.Ety; 5245 elem *e1 = e.EV.E1; 5246 elem *e2 = e.EV.E2; 5247 5248 if (e1.Eoper == OPconst && !boolres(e1)) // if e1 is 0 5249 { 5250 e1.Ety = ty; 5251 e = el_selecte1(e); // (0 << e2) => 0 5252 } 5253 else if (OPTIMIZER && 5254 e2.Eoper == OPconst && 5255 (e1.Eoper == OPshr || e1.Eoper == OPashr) && 5256 e1.EV.E2.Eoper == OPconst && 5257 el_tolong(e2) == el_tolong(e1.EV.E2)) 5258 { /* Rewrite: 5259 * (x >> c) << c) 5260 * with: 5261 * x & ~((1 << c) - 1); 5262 */ 5263 targ_ullong c = el_tolong(e.EV.E2); 5264 e = el_selecte1(e); 5265 e = el_selecte1(e); 5266 e = el_bin(OPand, e.Ety, e, el_long(e.Ety, ~((1UL << c) - 1))); 5267 return optelem(e, goal); 5268 } 5269 return e; 5270 } 5271 5272 /************************ 5273 * Handle >> 5274 * OPshr, OPashr 5275 */ 5276 5277 @trusted 5278 private elem * elshr(elem *e, goal_t goal) 5279 { 5280 tym_t ty = e.Ety; 5281 elem *e1 = e.EV.E1; 5282 elem *e2 = e.EV.E2; 5283 5284 // (x >> 16) replaced with ((shtlng) x+2) 5285 if (OPTIMIZER && 5286 e2.Eoper == OPconst && e2.EV.Vshort == SHORTSIZE * 8 && 5287 tysize(ty) == LONGSIZE) 5288 { 5289 if (e1.Eoper == OPvar) 5290 { 5291 Symbol *s = e1.EV.Vsym; 5292 5293 if (s.Sclass != SC.fastpar && s.Sclass != SC.shadowreg) 5294 { 5295 e1.EV.Voffset += SHORTSIZE; // address high word in long 5296 if (I32) 5297 // Cannot independently address high word of register 5298 s.Sflags &= ~GTregcand; 5299 goto L1; 5300 } 5301 } 5302 else if (e1.Eoper == OPind) 5303 { 5304 /* Replace (*p >> 16) with (shtlng)(*(&*p + 2)) */ 5305 e.EV.E1 = el_una(OPind,TYshort, 5306 el_bin(OPadd,e1.EV.E1.Ety, 5307 el_una(OPaddr,e1.EV.E1.Ety,e1), 5308 el_long(TYint,SHORTSIZE))); 5309 L1: 5310 e.Eoper = tyuns(e1.Ety) ? OPu16_32 : OPs16_32; 5311 el_free(e2); 5312 e.EV.E2 = null; 5313 e1.Ety = TYshort; 5314 e = optelem(e,GOALvalue); 5315 } 5316 } 5317 5318 // (x >> 32) replaced with ((lngllng) x+4) 5319 if (e2.Eoper == OPconst && e2.EV.Vlong == LONGSIZE * 8 && 5320 tysize(ty) == LLONGSIZE) 5321 { 5322 if (e1.Eoper == OPvar) 5323 { 5324 e1.EV.Voffset += LONGSIZE; // address high dword in longlong 5325 if (I64) 5326 // Cannot independently address high word of register 5327 e1.EV.Vsym.Sflags &= ~GTregcand; 5328 goto L2; 5329 } 5330 else if (e1.Eoper == OPind) 5331 { 5332 // Replace (*p >> 32) with (lngllng)(*(&*p + 4)) 5333 e.EV.E1 = el_una(OPind,TYlong, 5334 el_bin(OPadd,e1.EV.E1.Ety, 5335 el_una(OPaddr,e1.EV.E1.Ety,e1), 5336 el_long(TYint,LONGSIZE))); 5337 L2: 5338 e.Eoper = tyuns(e1.Ety) ? OPu32_64 : OPs32_64; 5339 el_free(e2); 5340 e.EV.E2 = null; 5341 e1.Ety = TYlong; 5342 e = optelem(e,GOALvalue); 5343 } 5344 } 5345 return e; 5346 } 5347 5348 /*********************************** 5349 * Handle OPmsw. 5350 */ 5351 5352 @trusted 5353 elem *elmsw(elem *e, goal_t goal) 5354 { 5355 tym_t ty = e.Ety; 5356 elem *e1 = e.EV.E1; 5357 5358 if (OPTIMIZER && 5359 tysize(e1.Ety) == LLONGSIZE && 5360 tysize(ty) == LONGSIZE) 5361 { 5362 // Replace (int)(msw (long)x) with (int)*(&x+4) 5363 if (e1.Eoper == OPvar) 5364 { 5365 e1.EV.Voffset += LONGSIZE; // address high dword in longlong 5366 if (I64) 5367 // Cannot independently address high word of register 5368 e1.EV.Vsym.Sflags &= ~GTregcand; 5369 e1.Ety = ty; 5370 e = optelem(e1,GOALvalue); 5371 } 5372 // Replace (int)(msw (long)*x) with (int)*(&*x+4) 5373 else if (e1.Eoper == OPind) 5374 { 5375 e1 = el_una(OPind,ty, 5376 el_bin(OPadd,e1.EV.E1.Ety, 5377 el_una(OPaddr,e1.EV.E1.Ety,e1), 5378 el_long(TYint,LONGSIZE))); 5379 e = optelem(e1,GOALvalue); 5380 } 5381 else 5382 { 5383 e = evalu8(e, goal); 5384 } 5385 } 5386 else if (OPTIMIZER && I64 && 5387 tysize(e1.Ety) == CENTSIZE && 5388 tysize(ty) == LLONGSIZE) 5389 { 5390 // Replace (long)(msw (cent)x) with (long)*(&x+8) 5391 if (e1.Eoper == OPvar) 5392 { 5393 e1.EV.Voffset += LLONGSIZE; // address high dword in longlong 5394 e1.Ety = ty; 5395 e = optelem(e1,GOALvalue); 5396 } 5397 // Replace (long)(msw (cent)*x) with (long)*(&*x+8) 5398 else if (e1.Eoper == OPind) 5399 { 5400 e1 = el_una(OPind,ty, 5401 el_bin(OPadd,e1.EV.E1.Ety, 5402 el_una(OPaddr,e1.EV.E1.Ety,e1), 5403 el_long(TYint,LLONGSIZE))); 5404 e = optelem(e1,GOALvalue); 5405 } 5406 else 5407 { 5408 e = evalu8(e, goal); 5409 } 5410 } 5411 else 5412 { 5413 e = evalu8(e, goal); 5414 } 5415 5416 return e; 5417 } 5418 5419 /*********************************** 5420 * Handle OPpair, OPrpair. 5421 */ 5422 5423 @trusted 5424 elem *elpair(elem *e, goal_t goal) 5425 { 5426 //printf("elpair()\n"); 5427 elem *e1 = e.EV.E1; 5428 if (e1.Eoper == OPconst) 5429 { 5430 e.EV.E1 = e.EV.E2; 5431 e.EV.E2 = e1; 5432 e.Eoper ^= OPpair ^ OPrpair; 5433 } 5434 return e; 5435 } 5436 5437 /******************************** 5438 * Handle OPddtor 5439 */ 5440 5441 elem *elddtor(elem *e, goal_t goal) 5442 { 5443 return e; 5444 } 5445 5446 /******************************** 5447 * Handle OPinfo, OPmark, OPctor, OPdtor 5448 */ 5449 5450 private elem * elinfo(elem *e, goal_t goal) 5451 { 5452 //printf("elinfo()\n"); 5453 return e; 5454 } 5455 5456 /******************************************** 5457 */ 5458 5459 private elem * elclassinit(elem *e, goal_t goal) 5460 { 5461 return e; 5462 } 5463 5464 /******************************************** 5465 */ 5466 5467 @trusted 5468 private elem * elvalist(elem *e, goal_t goal) 5469 { 5470 assert(e.Eoper == OPva_start); 5471 5472 if (funcsym_p.ty() & mTYnaked) 5473 { // do not generate prolog 5474 el_free(e); 5475 e = el_long(TYint, 0); 5476 return e; 5477 } 5478 5479 elem* ap = e.EV.E1; // pointer to va_list 5480 elem* parmn = e.EV.E2; // address of last named parameter 5481 5482 if (I32) 5483 { 5484 // (OPva_start &va) 5485 // (OPeq (OPind E1) (OPptr lastNamed+T.sizeof)) 5486 //elem_print(e); 5487 5488 // Find last named parameter 5489 Symbol *lastNamed = null; 5490 Symbol *arguments_typeinfo = null; 5491 for (SYMIDX si = 0; si < globsym.length; si++) 5492 { 5493 Symbol *s = globsym[si]; 5494 5495 if (s.Sclass == SC.parameter || s.Sclass == SC.regpar) 5496 lastNamed = s; 5497 if (s.Sident[0] == '_' && strcmp(s.Sident.ptr, "_arguments_typeinfo") == 0) 5498 arguments_typeinfo = s; 5499 } 5500 5501 if (!lastNamed) 5502 lastNamed = arguments_typeinfo; 5503 5504 e.Eoper = OPeq; 5505 e.EV.E1 = el_una(OPind, TYnptr, ap); 5506 if (lastNamed) 5507 { 5508 e.EV.E2 = el_ptr(lastNamed); 5509 e.EV.E2.EV.Voffset = (type_size(lastNamed.Stype) + 3) & ~3; 5510 } 5511 else 5512 e.EV.E2 = el_long(TYnptr, 0); 5513 // elem_print(e); 5514 5515 return e; 5516 } 5517 5518 if (config.exe & EX_windos) 5519 { 5520 assert(config.exe == EX_WIN64); // va_start is not an intrinsic on 32-bit 5521 5522 // (OPva_start &va) 5523 // (OPeq (OPind E1) (OPptr &lastNamed+8)) 5524 //elem_print(e); 5525 5526 // Find last named parameter 5527 Symbol *lastNamed = null; 5528 for (SYMIDX si = 0; si < globsym.length; si++) 5529 { 5530 Symbol *s = globsym[si]; 5531 5532 if (s.Sclass == SC.fastpar || s.Sclass == SC.shadowreg || s.Sclass == SC.parameter) 5533 lastNamed = s; 5534 } 5535 5536 e.Eoper = OPeq; 5537 e.EV.E1 = el_una(OPind, TYnptr, ap); 5538 if (lastNamed) 5539 { 5540 e.EV.E2 = el_ptr(lastNamed); 5541 e.EV.E2.EV.Voffset = 8; 5542 } 5543 else 5544 e.EV.E2 = el_long(TYnptr, 0); 5545 //elem_print(e); 5546 5547 } 5548 5549 if (config.exe & EX_posix) 5550 { 5551 assert(I64); // va_start is not an intrinsic on 32-bit 5552 // (OPva_start &va) 5553 // (OPeq (OPind E1) __va_argsave+offset) 5554 //elem_print(e); 5555 5556 // Find __va_argsave 5557 Symbol *va_argsave = null; 5558 for (SYMIDX si = 0; si < globsym.length; si++) 5559 { 5560 Symbol *s = globsym[si]; 5561 if (s.Sident[0] == '_' && strcmp(s.Sident.ptr, "__va_argsave") == 0) 5562 { 5563 va_argsave = s; 5564 break; 5565 } 5566 } 5567 5568 e.Eoper = OPeq; 5569 e.EV.E1 = el_una(OPind, TYnptr, ap); 5570 if (va_argsave) 5571 { 5572 e.EV.E2 = el_ptr(va_argsave); 5573 e.EV.E2.EV.Voffset = 6 * 8 + 8 * 16; // offset to struct __va_list_tag defined in sysv_x64.d 5574 return el_combine(prolog_genva_start(va_argsave, parmn.EV.Vsym), e); 5575 } 5576 else 5577 e.EV.E2 = el_long(TYnptr, 0); 5578 //elem_print(e); 5579 } 5580 5581 return e; 5582 } 5583 5584 /****************************************** 5585 * OPparam 5586 */ 5587 5588 @trusted 5589 private void elparamx(elem *e) 5590 { 5591 //printf("elparam()\n"); 5592 if (e.EV.E1.Eoper == OPrpair) 5593 { 5594 e.EV.E1.Eoper = OPparam; 5595 } 5596 else if (e.EV.E1.Eoper == OPpair && !el_sideeffect(e.EV.E1)) 5597 { 5598 e.EV.E1.Eoper = OPparam; 5599 elem *ex = e.EV.E1.EV.E2; 5600 e.EV.E1.EV.E2 = e.EV.E1.EV.E1; 5601 e.EV.E1.EV.E1 = ex; 5602 } 5603 else 5604 { 5605 static if (0) 5606 { 5607 // Unfortunately, these don't work because if the last parameter 5608 // is a pair, and it is a D function, the last parameter will get 5609 // passed in EAX. 5610 if (e.EV.E2.Eoper == OPrpair) 5611 { 5612 e.EV.E2.Eoper = OPparam; 5613 } 5614 else if (e.EV.E2.Eoper == OPpair) 5615 { 5616 e.EV.E2.Eoper = OPparam; 5617 elem *ex = e.EV.E2.EV.E2; 5618 e.EV.E2.EV.E2 = e.EV.E2.EV.E1; 5619 e.EV.E2.EV.E1 = ex; 5620 } 5621 } 5622 } 5623 } 5624 5625 @trusted 5626 private elem * elparam(elem *e, goal_t goal) 5627 { 5628 if (!OPTIMIZER) 5629 { 5630 if (!I64) 5631 elparamx(e); 5632 } 5633 return e; 5634 } 5635 5636 /******************************** 5637 * Optimize an element. This routine is recursive! 5638 * Be careful not to do this if VBEs have been done (else the VBE 5639 * work will be undone), or if DAGs have been built (will crash if 5640 * there is more than one parent for an elem). 5641 * If (goal) 5642 * we care about the result. 5643 */ 5644 5645 @trusted 5646 private elem * optelem(elem *e, goal_t goal) 5647 { 5648 beg: 5649 //__gshared uint count; 5650 //printf("count: %u\n", ++count); 5651 //{ printf("xoptelem: %p %s goal x%x\n",e, oper_str(e.Eoper), goal); } 5652 assert(e); 5653 elem_debug(e); 5654 assert(e.Ecount == 0); // no CSEs 5655 5656 if (OPTIMIZER) 5657 { 5658 if (goal) 5659 e.Nflags &= ~NFLnogoal; 5660 else 5661 e.Nflags |= NFLnogoal; 5662 } 5663 5664 auto op = e.Eoper; 5665 if (OTleaf(op)) // if not an operator node 5666 { 5667 if (goal || OTsideff(op) || e.Ety & (mTYvolatile | mTYshared)) 5668 { 5669 return e; 5670 } 5671 else 5672 { 5673 retnull: 5674 el_free(e); 5675 return null; 5676 } 5677 } 5678 else if (OTbinary(op)) // if binary operator 5679 { 5680 /* Determine goals for left and right subtrees */ 5681 goal_t leftgoal = GOALvalue; 5682 goal_t rightgoal = (goal || OTsideff(op)) ? GOALvalue : GOALnone; 5683 switch (op) 5684 { 5685 case OPcomma: 5686 { 5687 elem *e1 = e.EV.E1 = optelem(e.EV.E1,GOALnone); 5688 // if (e1 && !OTsideff(e1.Eoper)) 5689 // e1 = e.EV.E1 = optelem(e1, GOALnone); 5690 elem *e2 = e.EV.E2 = optelem(e.EV.E2,goal); 5691 if (!e1) 5692 { 5693 if (!e2) 5694 goto retnull; 5695 if (!goal) 5696 e.Ety = e.EV.E2.Ety; 5697 e = el_selecte2(e); 5698 return e; 5699 } 5700 if (!e2) 5701 { 5702 e.Ety = e.EV.E1.Ety; 5703 return el_selecte1(e); 5704 } 5705 if (!goal) 5706 e.Ety = e2.Ety; 5707 return e; 5708 } 5709 5710 case OPcond: 5711 if (!goal) 5712 { // Transform x?y:z into x&&y or x||z 5713 elem *e2 = e.EV.E2; 5714 if (!el_sideeffect(e2.EV.E1)) 5715 { 5716 e.Eoper = OPoror; 5717 e.EV.E2 = el_selecte2(e2); 5718 e.Ety = TYint; 5719 goto beg; 5720 } 5721 else if (!el_sideeffect(e2.EV.E2)) 5722 { 5723 e.Eoper = OPandand; 5724 e.EV.E2 = el_selecte1(e2); 5725 e.Ety = TYint; 5726 goto beg; 5727 } 5728 assert(e2.Eoper == OPcolon || e2.Eoper == OPcolon2); 5729 elem *e21 = e2.EV.E1 = optelem(e2.EV.E1, goal); 5730 elem *e22 = e2.EV.E2 = optelem(e2.EV.E2, goal); 5731 if (!e21) 5732 { 5733 if (!e22) 5734 { 5735 e = el_selecte1(e); 5736 goto beg; 5737 } 5738 // Rewrite (e1 ? null : e22) as (e1 || e22) 5739 e.Eoper = OPoror; 5740 e.EV.E2 = el_selecte2(e2); 5741 goto beg; 5742 } 5743 if (!e22) 5744 { 5745 // Rewrite (e1 ? e21 : null) as (e1 && e21) 5746 e.Eoper = OPandand; 5747 e.EV.E2 = el_selecte1(e2); 5748 goto beg; 5749 } 5750 if (!rightgoal) 5751 rightgoal = GOALvalue; 5752 } 5753 goto Llog; 5754 5755 case OPoror: 5756 if (rightgoal) 5757 rightgoal = GOALflags; 5758 if (OPTIMIZER && optim_loglog(e)) 5759 goto beg; 5760 goto Llog; 5761 5762 case OPandand: 5763 if (rightgoal) 5764 rightgoal = GOALflags; 5765 if (OPTIMIZER && optim_loglog(e)) 5766 goto beg; 5767 goto Llog; 5768 5769 Llog: // case (c log f()) with no goal 5770 if (goal || el_sideeffect(e.EV.E2)) 5771 leftgoal = GOALflags; 5772 break; 5773 5774 default: 5775 leftgoal = rightgoal; 5776 break; 5777 5778 case OPcolon: 5779 case OPcolon2: 5780 if (!goal && !el_sideeffect(e)) 5781 goto retnull; 5782 leftgoal = rightgoal; 5783 break; 5784 5785 case OPmemcmp: 5786 if (!goal) 5787 { // So OPmemcmp is removed cleanly 5788 assert(e.EV.E1.Eoper == OPparam); 5789 e.EV.E1.Eoper = OPcomma; 5790 } 5791 leftgoal = rightgoal; 5792 break; 5793 5794 case OPcall: 5795 case OPcallns: 5796 { 5797 const tyf = tybasic(e.EV.E1.Ety); 5798 leftgoal = rightgoal; 5799 elem *e1 = e.EV.E1 = optelem(e.EV.E1, leftgoal); 5800 5801 // Need argument to type_zeroSize() 5802 const tyf_save = global_tyf; 5803 global_tyf = tyf; 5804 elem *e2 = e.EV.E2 = optelem(e.EV.E2, rightgoal); 5805 global_tyf = tyf_save; 5806 5807 if (!e1) 5808 { 5809 if (!e2) 5810 goto retnull; 5811 return el_selecte2(e); 5812 } 5813 if (!e2) 5814 { 5815 if (!leftgoal) 5816 e.Ety = e1.Ety; 5817 return el_selecte1(e); 5818 } 5819 return (*elxxx[op])(e, goal); 5820 } 5821 } 5822 5823 elem *e1 = e.EV.E1; 5824 if (OTassign(op)) 5825 { 5826 elem *ex = e1; 5827 while (OTconv(ex.Eoper)) 5828 ex = ex.EV.E1; 5829 if (ex.Eoper == OPbit) 5830 ex.EV.E1 = optelem(ex.EV.E1, leftgoal); 5831 else if (e1.Eoper == OPu64_d) 5832 e1.EV.E1 = optelem(e1.EV.E1, leftgoal); 5833 else if ((e1.Eoper == OPd_ld || e1.Eoper == OPd_f) && e1.EV.E1.Eoper == OPu64_d) 5834 e1.EV.E1.EV.E1 = optelem(e1.EV.E1.EV.E1, leftgoal); 5835 else 5836 e1 = e.EV.E1 = optelem(e1,leftgoal); 5837 } 5838 else 5839 e1 = e.EV.E1 = optelem(e1,leftgoal); 5840 5841 if ((op == OPandand || op == OPoror || op == OPcond) && e1) // short circuit evaluations 5842 { 5843 switch (op) 5844 { 5845 case OPandand: 5846 if (iffalse(e1)) 5847 { 5848 // Do not evaluate E2 5849 el_free(e.EV.E2); 5850 e.EV.E2 = null; 5851 e.Eoper = OPbool; 5852 goto beg; 5853 } 5854 break; 5855 5856 case OPoror: 5857 if (iftrue(e1)) 5858 { 5859 // Do not evaluate E2 5860 el_free(e.EV.E2); 5861 e.EV.E2 = null; 5862 e.Eoper = OPbool; 5863 goto beg; 5864 } 5865 break; 5866 5867 case OPcond: 5868 if (iftrue(e1)) 5869 { 5870 e.EV.E2 = el_selecte1(e.EV.E2); 5871 e.EV.E2.Ety = e.Ety; 5872 e.EV.E2.ET = e.ET; 5873 e.Eoper = OPcomma; 5874 goto beg; 5875 } 5876 if (iffalse(e1)) 5877 { 5878 e.EV.E2 = el_selecte2(e.EV.E2); 5879 e.EV.E2.Ety = e.Ety; 5880 e.EV.E2.ET = e.ET; 5881 e.Eoper = OPcomma; 5882 goto beg; 5883 } 5884 break; 5885 5886 default: 5887 assert(0); 5888 } 5889 } 5890 5891 elem *e2 = e.EV.E2 = optelem(e.EV.E2,rightgoal); 5892 if (!e1) 5893 { 5894 if (!e2) 5895 goto retnull; 5896 return el_selecte2(e); 5897 } 5898 if (!e2) 5899 { 5900 if (!leftgoal) 5901 e.Ety = e1.Ety; 5902 return el_selecte1(e); 5903 } 5904 5905 if (op == OPparam && !goal) 5906 e.Eoper = OPcomma; // DMD bug 6733 5907 5908 if (cnst(e1) && cnst(e2)) 5909 { 5910 e = evalu8(e, GOALvalue); 5911 return e; 5912 } 5913 if (OPTIMIZER) 5914 { 5915 if (OTassoc(op)) 5916 { 5917 /* Replace (a op1 (b op2 c)) with ((a op2 b) op1 c) 5918 (this must come before the leaf swapping, or we could cause 5919 infinite loops) 5920 */ 5921 if (e2.Eoper == op && 5922 e2.EV.E2.Eoper == OPconst && 5923 tysize(e2.EV.E1.Ety) == tysize(e2.EV.E2.Ety) && 5924 (!tyfloating(e1.Ety) || e1.Ety == e2.Ety) 5925 ) 5926 { 5927 e.EV.E1 = e2; 5928 e.EV.E2 = e2.EV.E2; 5929 e2.EV.E2 = e2.EV.E1; 5930 e2.EV.E1 = e1; 5931 if (op == OPadd) /* fix types */ 5932 { 5933 e1 = e.EV.E1; 5934 if (typtr(e1.EV.E2.Ety)) 5935 e1.Ety = e1.EV.E2.Ety; 5936 else 5937 /* suppose a and b are ints, and c is a pointer */ 5938 /* then this will fix the type of op2 to be int */ 5939 e1.Ety = e1.EV.E1.Ety; 5940 } 5941 goto beg; 5942 } 5943 5944 // Replace ((a op c1) op c2) with (a op (c2 op c1)) 5945 if (e1.Eoper == op && 5946 e2.Eoper == OPconst && 5947 e1.EV.E2.Eoper == OPconst && 5948 e1.EV.E1.Eoper != OPconst && 5949 tysize(e2.Ety) == tysize(e1.EV.E2.Ety)) 5950 { 5951 e.EV.E1 = e1.EV.E1; 5952 e1.EV.E1 = e2; 5953 e1.Ety = e2.Ety; 5954 e.EV.E2 = e1; 5955 5956 if (tyfloating(e1.Ety)) 5957 { 5958 e1 = evalu8(e1, GOALvalue); 5959 if (!OTleaf(e1.Eoper)) // if failed to fold the constants 5960 { // Undo the changes so we don't infinite loop 5961 e.EV.E2 = e1.EV.E1; 5962 e1.EV.E1 = e.EV.E1; 5963 e.EV.E1 = e1; 5964 } 5965 else 5966 { e.EV.E2 = e1; 5967 goto beg; 5968 } 5969 } 5970 else 5971 goto beg; 5972 } 5973 } 5974 5975 if (!OTrtol(op) && op != OPparam && op != OPcolon && op != OPcolon2 && 5976 e1.Eoper == OPcomma) 5977 { // Convert ((a,b) op c) to (a,(b op c)) 5978 e1.EV.E2.Ety = e1.Ety; 5979 e1.EV.E2.ET = e1.ET; 5980 5981 e1.Ety = e.Ety; 5982 e1.ET = e.ET; 5983 5984 e.EV.E1 = e1.EV.E2; 5985 e1.EV.E2 = e; 5986 e = e1; 5987 goto beg; 5988 } 5989 } 5990 5991 if (OTcommut(op)) // if commutative 5992 { 5993 /* see if we should swap the leaves */ 5994 enum MARS = true; 5995 if ( 5996 MARS ? ( 5997 cost(e2) > cost(e1) && 5998 !(tyvector(e1.Ety) && op == OPgt) 5999 /* Swap only if order of evaluation can be proved 6000 * to not matter, as we must evaluate Left-to-Right 6001 */ 6002 && e1.canHappenAfter(e2) 6003 ) 6004 : cost(e2) > cost(e1) && !(tyvector(e1.Ety) && op == OPgt) 6005 ) 6006 { 6007 e.EV.E1 = e2; 6008 e2 = e.EV.E2 = e1; 6009 e1 = e.EV.E1; // reverse the leaves 6010 op = e.Eoper = cast(ubyte)swaprel(op); 6011 } 6012 if (OTassoc(op)) // if commutative and associative 6013 { 6014 if (!OTleaf(e1.Eoper) && 6015 op == e1.Eoper && 6016 e1.EV.E2.Eoper == OPconst && 6017 e.Ety == e1.Ety && 6018 tysize(e1.EV.E2.Ety) == tysize(e2.Ety) 6019 6020 // Reordering floating point can change the semantics 6021 && (!MARS || !tyfloating(e1.Ety)) 6022 ) 6023 { 6024 // look for ((e op c1) op c2), 6025 // replace with (e op (c1 op c2)) 6026 if (e2.Eoper == OPconst) 6027 { 6028 e.EV.E1 = e1.EV.E1; 6029 e.EV.E2 = e1; 6030 e1.EV.E1 = e1.EV.E2; 6031 e1.EV.E2 = e2; 6032 e1.Ety = e2.Ety; 6033 6034 e1 = e.EV.E1; 6035 e2 = e.EV.E2 = evalu8(e.EV.E2, GOALvalue); 6036 } 6037 else 6038 { // Replace ((e op c) op e2) with ((e op e2) op c) 6039 e.EV.E2 = e1.EV.E2; 6040 e1.EV.E2 = e2; 6041 e2 = e.EV.E2; 6042 } 6043 } 6044 } 6045 } 6046 6047 if (e2.Eoper == OPconst && // if right operand is a constant 6048 !(OTopeq(op) && OTconv(e1.Eoper)) 6049 ) 6050 { 6051 debug assert(!(OTeop0e(op) && (OTeop00(op)))); 6052 if (OTeop0e(op)) /* if e1 op 0 => e1 */ 6053 { 6054 if (!boolres(e2)) /* if e2 is 0 */ 6055 { 6056 // Don't do it for ANSI floating point 6057 if (tyfloating(e1.Ety) && !(config.flags4 & CFG4fastfloat)) 6058 { } 6059 // Don't do it if we're assembling a complex value 6060 else if ((tytab[e.EV.E1.Ety & 0xFF] ^ 6061 tytab[e.EV.E2.Ety & 0xFF]) == (TYFLreal | TYFLimaginary)) 6062 { } 6063 else 6064 return optelem(el_selecte1(e),goal); 6065 } 6066 } 6067 else if (OTeop00(op) && !boolres(e2) && !tyfloating(e.Ety)) 6068 { 6069 if (OTassign(op)) 6070 op = e.Eoper = OPeq; 6071 else 6072 op = e.Eoper = OPcomma; 6073 } 6074 6075 if (OTeop1e(op)) /* if e1 op 1 => e1 */ 6076 { 6077 if (elemisone(e2) && !tyimaginary(e2.Ety)) 6078 return optelem(el_selecte1(e),goal); 6079 } 6080 } 6081 6082 if (OTpost(op) && !goal) 6083 { 6084 op = e.Eoper = (op == OPpostinc) ? OPaddass : OPminass; 6085 } 6086 } 6087 else /* unary operator */ 6088 { 6089 elem* e1 = e.EV.E1; 6090 6091 /* op(a,b) => a,(op b) 6092 */ 6093 if (e1.Eoper == OPcomma && op != OPstrpar && op != OPddtor) 6094 { 6095 e.Eoper = e1.Eoper; 6096 e.EV.E1 = e1.EV.E1; 6097 e.EV.E2 = e1; 6098 e1.Eoper = op; 6099 e1.Ety = e.Ety; 6100 e1.ET = e.ET; 6101 e1.EV.E1 = e1.EV.E2; 6102 e1.EV.E2 = null; 6103 return optelem(e, goal); 6104 } 6105 6106 assert(!e.EV.E2 || op == OPinfo || op == OPddtor); 6107 if (!goal && !OTsideff(op) && !(e.Ety & (mTYvolatile | mTYshared))) 6108 { 6109 tym_t tym = e1.Ety; 6110 6111 e = el_selecte1(e); 6112 e.Ety = tym; 6113 return optelem(e,GOALnone); 6114 } 6115 6116 if ((op == OPd_f || op == OPd_ld) && e1.Eoper == OPu64_d) 6117 { 6118 return elu64_d(e, goal); 6119 } 6120 6121 e1 = e.EV.E1 = optelem(e1, (op == OPddtor) 6122 ? GOALnone 6123 : (op == OPbool || op == OPnot) ? GOALflags : GOALvalue); 6124 if (!e1) 6125 goto retnull; 6126 if (e1.Eoper == OPconst) 6127 { 6128 if (!(op == OPnp_fp && el_tolong(e1) != 0)) 6129 return evalu8(e, GOALvalue); 6130 } 6131 } 6132 6133 // if (debugb) 6134 // { print("optelem: %p %s\n",e, oper_str(op)); } 6135 6136 static if (0) 6137 { 6138 printf("xoptelem: %p %s\n", e, oper_str(e.Eoper)); 6139 elem_print(e); 6140 e = (*elxxx[op])(e, goal); 6141 printf("After:\n"); 6142 elem_print(e); 6143 return e; 6144 } 6145 else 6146 { 6147 return (*elxxx[op])(e, goal); 6148 } 6149 } 6150 6151 6152 /******************************** 6153 * Optimize and canonicalize an expression tree. 6154 * Fiddle with double operators so that the rvalue is a pointer 6155 * (this is needed by the 8086 code generator). 6156 * 6157 * op op 6158 * / \ / \ 6159 * e1 e2 e1 , 6160 * / \ 6161 * = & 6162 * / \ \ 6163 * fr e2 fr 6164 * 6165 * e1 op (*p) e1 op p 6166 * e1 op c e1 op &dc 6167 * e1 op v e1 op &v 6168 */ 6169 6170 @trusted 6171 elem *doptelem(elem *e, goal_t goal) 6172 { 6173 //printf("doptelem(e = %p, goal = x%x)\n", e, goal); 6174 assert(!PARSER); 6175 do 6176 { again = false; 6177 topair = false; 6178 e = optelem(e,goal & (GOALflags | GOALvalue | GOALnone)); 6179 } while (again && goal & GOALagain && e); 6180 6181 /* If entire expression is a struct, and we can replace it with */ 6182 /* something simpler, do so. */ 6183 if (goal & GOALstruct && e && (tybasic(e.Ety) == TYstruct || tybasic(e.Ety) == TYarray)) 6184 e = elstruct(e, goal); 6185 6186 if (topair && e) 6187 e = elToPair(e); 6188 6189 return e; 6190 } 6191 6192 /**************************************** 6193 * Do optimizations after bltailrecursion() and before common subexpressions. 6194 */ 6195 6196 @trusted 6197 void postoptelem(elem *e) 6198 { 6199 Srcpos pos = {0}; 6200 6201 elem_debug(e); 6202 while (1) 6203 { 6204 if (OTunary(e.Eoper)) 6205 { 6206 /* This is necessary as the optimizer tends to lose this information 6207 */ 6208 if (e.Esrcpos.Slinnum > pos.Slinnum) 6209 pos = e.Esrcpos; 6210 6211 if (e.Eoper == OPind) 6212 { 6213 if (e.EV.E1.Eoper == OPconst && 6214 /* Allow TYfgptr to reference GS:[0000] etc. 6215 */ 6216 tybasic(e.EV.E1.Ety) == TYnptr) 6217 { 6218 /* Disallow anything in the range [0..4096] 6219 * Let volatile pointers dereference null 6220 */ 6221 const targ_ullong v = el_tolong(e.EV.E1); 6222 if (v < 4096 && !(e.Ety & mTYvolatile)) 6223 { 6224 error(pos.Sfilename, pos.Slinnum, pos.Scharnum, "null dereference in function %s", funcsym_p.Sident.ptr); 6225 e.EV.E1.EV.Vlong = 4096; // suppress redundant messages 6226 } 6227 } 6228 } 6229 e = e.EV.E1; 6230 } 6231 else if (OTbinary(e.Eoper)) 6232 { 6233 /* This is necessary as the optimizer tends to lose this information 6234 */ 6235 if (e.Esrcpos.Slinnum > pos.Slinnum) 6236 pos = e.Esrcpos; 6237 6238 if (e.Eoper == OPparam) 6239 { 6240 if (!I64) 6241 elparamx(e); 6242 } 6243 postoptelem(e.EV.E2); 6244 e = e.EV.E1; 6245 } 6246 else 6247 break; 6248 } 6249 } 6250 6251 /*********************************** 6252 * Rewrite rvalues of complex numbers to pairs of floating point numbers. 6253 */ 6254 @trusted 6255 private elem *elToPair(elem *e) 6256 { 6257 switch (e.Eoper) 6258 { 6259 case OPvar: 6260 { 6261 /* Rewrite complex number loads as a pair of loads 6262 * e => (e.0 pair e.offset) 6263 */ 6264 tym_t ty0; 6265 tym_t ty = e.Ety; 6266 if (ty & (mTYxmmgpr | mTYgprxmm)) 6267 break; // register allocation doesn't support it yet. 6268 switch (tybasic(ty)) 6269 { 6270 case TYcfloat: ty0 = TYfloat | (ty & ~mTYbasic); goto L1; 6271 case TYcdouble: ty0 = TYdouble | (ty & ~mTYbasic); goto L1; 6272 L1: 6273 if (_tysize[tybasic(ty0)] < REGSIZE) 6274 break; // func parameters, for example, can't handle this 6275 e.Ety = ty0; 6276 elem *e2 = el_copytree(e); 6277 e2.EV.Voffset += _tysize[tybasic(ty0)]; 6278 return el_bin(OPpair, ty, e, e2); 6279 6280 default: 6281 break; 6282 } 6283 break; 6284 } 6285 6286 case OPind: 6287 { 6288 e.EV.E1 = elToPair(e.EV.E1); 6289 /* Rewrite complex number loads as a pair of loads 6290 * *e1 => (*e1 pair *(e1 + offset)) 6291 */ 6292 tym_t ty0; 6293 tym_t ty = e.Ety; 6294 if (ty & (mTYxmmgpr | mTYgprxmm)) 6295 break; // register allocation doesn't support it yet. 6296 switch (tybasic(ty)) 6297 { 6298 case TYcfloat: ty0 = TYfloat | (ty & ~mTYbasic); goto L2; 6299 case TYcdouble: ty0 = TYdouble | (ty & ~mTYbasic); goto L2; 6300 L2: 6301 if (_tysize[tybasic(ty0)] < REGSIZE) 6302 break; // func parameters, for example, can't handle this 6303 e.Ety = ty0; 6304 elem *e2 = el_copytree(e.EV.E1); 6305 if (el_sideeffect(e2)) 6306 fixside(&e.EV.E1, &e2); 6307 e2 = el_bin(OPadd,e2.Ety,e2,el_long(TYsize, _tysize[tybasic(ty0)])); 6308 e2 = el_una(OPind, ty0, e2); 6309 return el_bin(OPpair, ty, e, e2); 6310 6311 default: 6312 break; 6313 } 6314 break; 6315 } 6316 6317 default: 6318 if (OTassign(e.Eoper)) 6319 { 6320 // Skip over OPvar and OPind lvalues 6321 if (OTbinary(e.Eoper)) 6322 e.EV.E2 = elToPair(e.EV.E2); 6323 if (e.EV.E1.Eoper == OPvar) 6324 { 6325 } 6326 else if (e.EV.E1.Eoper == OPind) 6327 e.EV.E1.EV.E1 = elToPair(e.EV.E1.EV.E1); 6328 else 6329 e.EV.E1 = elToPair(e.EV.E1); 6330 } 6331 else if (OTunary(e.Eoper)) 6332 { 6333 e.EV.E1 = elToPair(e.EV.E1); 6334 } 6335 else if (OTbinary(e.Eoper)) 6336 { 6337 e.EV.E2 = elToPair(e.EV.E2); 6338 e.EV.E1 = elToPair(e.EV.E1); 6339 } 6340 break; 6341 } 6342 return e; 6343 } 6344 6345 /****************************************** 6346 * Determine if `b` can be moved before `a` without disturbing 6347 * order-of-evaluation semantics. 6348 */ 6349 6350 @trusted 6351 private bool canHappenAfter(elem* a, elem* b) 6352 { 6353 return a.Eoper == OPconst || 6354 a.Eoper == OPrelconst || 6355 6356 /* a is a variable that is not aliased 6357 * and is not assigned to in b 6358 */ 6359 (a.Eoper == OPvar && a.EV.Vsym.Sflags & SFLunambig && !el_appears(b, a.EV.Vsym)) || 6360 6361 !(el_sideeffect(a) || el_sideeffect(b)); 6362 } 6363 6364 6365 /*************************************************** 6366 * Call table, index is OPER 6367 */ 6368 6369 private alias elfp_t = elem *function(elem *, goal_t) nothrow; 6370 6371 private immutable elfp_t[OPMAX] elxxx = 6372 [ 6373 OPunde: &elerr, 6374 OPadd: &eladd, 6375 OPmul: &elmul, 6376 OPand: &elbitwise, 6377 OPmin: &elmin, 6378 OPnot: &elnot, 6379 OPcom: &elcom, 6380 OPcond: &elcond, 6381 OPcomma: &elcomma, 6382 OPremquo: &elremquo, 6383 OPdiv: &eldiv, 6384 OPmod: &elmod, 6385 OPxor: &elxor, 6386 OPstring: &elstring, 6387 OPrelconst: &elzot, 6388 OPinp: &elzot, 6389 OPoutp: &elzot, 6390 OPasm: &elzot, 6391 OPinfo: &elinfo, 6392 OPdctor: &elzot, 6393 OPddtor: &elddtor, 6394 OPctor: &elinfo, 6395 OPdtor: &elinfo, 6396 OPmark: &elinfo, 6397 OPvoid: &elzot, 6398 OPhalt: &elzot, 6399 OPnullptr: &elerr, 6400 OPpair: &elpair, 6401 OPrpair: &elpair, 6402 6403 OPor: &elor, 6404 OPoror: &eloror, 6405 OPandand: &elandand, 6406 OProl: &elshl, 6407 OPror: &elshl, 6408 OPshl: &elshl, 6409 OPshr: &elshr, 6410 OPashr: &elshr, 6411 OPbit: &elbit, 6412 OPind: &elind, 6413 OPaddr: &eladdr, 6414 OPneg: &elneg, 6415 OPuadd: &elzot, 6416 OPabs: &evalu8, 6417 OPsqrt: &evalu8, 6418 OPsin: &evalu8, 6419 OPcos: &evalu8, 6420 OPscale: &elzot, 6421 OPyl2x: &elzot, 6422 OPyl2xp1: &elzot, 6423 OPcmpxchg: &elzot, 6424 OPtoprec: &elzot, 6425 OPrint: &evalu8, 6426 OPrndtol: &evalu8, 6427 OPstrlen: &elzot, 6428 OPstrcpy: &elstrcpy, 6429 OPmemcpy: &elmemcpy, 6430 OPmemset: &elmemset, 6431 OPstrcat: &elzot, 6432 OPstrcmp: &elstrcmp, 6433 OPmemcmp: &elmemcmp, 6434 OPsetjmp: &elzot, 6435 OPnegass: &elnegass, 6436 OPpreinc: &elzot, 6437 OPpredec: &elzot, 6438 OPstreq: &elstruct, 6439 OPpostinc: &elpost, 6440 OPpostdec: &elpost, 6441 OPeq: &eleq, 6442 OPaddass: &elopass, 6443 OPminass: &elopass, 6444 OPmulass: &elopass, 6445 OPdivass: &elopass, 6446 OPmodass: &elopass, 6447 OPshrass: &elopass, 6448 OPashrass: &elopass, 6449 OPshlass: &elopass, 6450 OPandass: &elopass, 6451 OPxorass: &elopass, 6452 OPorass: &elopass, 6453 6454 OPle: &elcmp, 6455 OPgt: &elcmp, 6456 OPlt: &elcmp, 6457 OPge: &elcmp, 6458 OPeqeq: &elcmp, 6459 OPne: &elcmp, 6460 6461 OPunord: &elcmp, 6462 OPlg: &elcmp, 6463 OPleg: &elcmp, 6464 OPule: &elcmp, 6465 OPul: &elcmp, 6466 OPuge: &elcmp, 6467 OPug: &elcmp, 6468 OPue: &elcmp, 6469 OPngt: &elcmp, 6470 OPnge: &elcmp, 6471 OPnlt: &elcmp, 6472 OPnle: &elcmp, 6473 OPord: &elcmp, 6474 OPnlg: &elcmp, 6475 OPnleg: &elcmp, 6476 OPnule: &elcmp, 6477 OPnul: &elcmp, 6478 OPnuge: &elcmp, 6479 OPnug: &elcmp, 6480 OPnue: &elcmp, 6481 6482 OPvp_fp: &elvptrfptr, 6483 OPcvp_fp: &elvptrfptr, 6484 OPoffset: &ellngsht, 6485 OPnp_fp: &elptrlptr, 6486 OPnp_f16p: &elzot, 6487 OPf16p_np: &elzot, 6488 6489 OPs16_32: &evalu8, 6490 OPu16_32: &evalu8, 6491 OPd_s32: &evalu8, 6492 OPb_8: &evalu8, 6493 OPs32_d: &evalu8, 6494 OPd_s16: &evalu8, 6495 OPs16_d: &evalu8, 6496 OPd_u16: &evalu8, 6497 OPu16_d: &evalu8, 6498 OPd_u32: &evalu8, 6499 OPu32_d: &evalu8, 6500 OP32_16: &ellngsht, 6501 OPd_f: &evalu8, 6502 OPf_d: &evalu8, 6503 OPd_ld: &evalu8, 6504 OPld_d: &evalu8, 6505 OPc_r: &elc_r, 6506 OPc_i: &elc_i, 6507 OPu8_16: &elbyteint, 6508 OPs8_16: &elbyteint, 6509 OP16_8: &ellngsht, 6510 OPu32_64: &el32_64, 6511 OPs32_64: &el32_64, 6512 OP64_32: &el64_32, 6513 OPu64_128: &evalu8, 6514 OPs64_128: &evalu8, 6515 OP128_64: &el64_32, 6516 OPmsw: &elmsw, 6517 6518 OPd_s64: &evalu8, 6519 OPs64_d: &evalu8, 6520 OPd_u64: &evalu8, 6521 OPu64_d: &elu64_d, 6522 OPld_u64: &evalu8, 6523 OPparam: &elparam, 6524 OPsizeof: &elzot, 6525 OParrow: &elzot, 6526 OParrowstar: &elzot, 6527 OPcolon: &elzot, 6528 OPcolon2: &elzot, 6529 OPbool: &elbool, 6530 OPcall: &elcall, 6531 OPucall: &elcall, 6532 OPcallns: &elcall, 6533 OPucallns: &elcall, 6534 OPstrpar: &elstruct, 6535 OPstrctor: &elzot, 6536 OPstrthis: &elzot, 6537 OPconst: &elerr, 6538 OPvar: &elerr, 6539 OPreg: &elerr, 6540 OPnew: &elerr, 6541 OPanew: &elerr, 6542 OPdelete: &elerr, 6543 OPadelete: &elerr, 6544 OPbrack: &elerr, 6545 OPframeptr: &elzot, 6546 OPgot: &elzot, 6547 6548 OPbsf: &elzot, 6549 OPbsr: &elzot, 6550 OPbtst: &elzot, 6551 OPbt: &elzot, 6552 OPbtc: &elzot, 6553 OPbtr: &elzot, 6554 OPbts: &elzot, 6555 6556 OPbswap: &evalu8, 6557 OPpopcnt: &evalu8, 6558 OPvector: &elzot, 6559 OPvecsto: &elzot, 6560 OPvecfill: &elzot, 6561 OPva_start: &elvalist, 6562 OPprefetch: &elzot, 6563 ];