1 /** 2 * Directed acyclic graphs and global optimizer common subexpressions 3 * 4 * Compiler implementation of the 5 * $(LINK2 https://www.dlang.org, D programming language). 6 * 7 * Copyright: Copyright (C) 1986-1998 by Symantec 8 * Copyright (C) 2000-2023 by The D Language Foundation, All Rights Reserved 9 * Authors: $(LINK2 https://www.digitalmars.com, Walter Bright) 10 * License: $(LINK2 https://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 11 * Source: $(LINK2 https://github.com/dlang/dmd/blob/master/src/dmd/backend/gdag.d, backend/gdag.d) 12 * Coverage: https://codecov.io/gh/dlang/dmd/src/master/src/dmd/backend/gdag.d 13 */ 14 15 module dmd.backend.gdag; 16 17 version (SCPP) 18 version = COMPILE; 19 version (MARS) 20 version = COMPILE; 21 22 version (COMPILE) 23 { 24 25 import core.stdc.stdio; 26 import core.stdc.time; 27 28 import dmd.backend.cc; 29 import dmd.backend.cdef; 30 import dmd.backend.code_x86; 31 import dmd.backend.oper; 32 import dmd.backend.global; 33 import dmd.backend.goh; 34 import dmd.backend.el; 35 import dmd.backend.ty; 36 import dmd.backend.type; 37 38 import dmd.backend.dlist; 39 import dmd.backend.dvec; 40 41 extern (C++): 42 43 nothrow: 44 @safe: 45 46 enum Aetype { cse, arraybounds } 47 48 private __gshared Aetype aetype; 49 50 @trusted 51 bool Eunambig(elem* e) { return OTassign(e.Eoper) && e.EV.E1.Eoper == OPvar; } 52 53 /************************************* 54 * Determine if floating point should be cse'd. 55 * Returns: 56 * true if should be cse'd 57 */ 58 59 @trusted 60 private bool cse_float(elem *e) 61 { 62 // Don't CSE floating stuff if generating 63 // inline 8087 code, the code generator 64 // can't handle it yet 65 return !(tyfloating(e.Ety) && config.inline8087 && 66 e.Eoper != OPvar && e.Eoper != OPconst) || 67 (tyxmmreg(e.Ety) && config.fpxmmregs); 68 } 69 70 /************************************ 71 * Build DAGs (basically find all the common subexpressions). 72 * Must be done after all other optimizations, because most 73 * of them depend on the trees being trees, not DAGs. 74 * The general strategy is: 75 * Compute available expressions (AEs) 76 * For each block 77 * stick together nodes that match, keeping AEs up to date 78 * For each block 79 * unstick unprofitable common subexpressions 80 * (this is generally target-dependent) 81 */ 82 @trusted 83 void builddags() 84 { 85 vec_t aevec; 86 87 debug if (debugc) printf("builddags()\n"); 88 assert(dfo); 89 flowae(); /* compute available expressions */ 90 if (go.exptop <= 1) /* if no AEs */ 91 return; 92 aetype = Aetype.cse; 93 94 debug 95 foreach (i, e; go.expnod[]) 96 { 97 //printf("go.expnod[%d] = %p\n",i,e); 98 if (e) 99 elem_debug(e); 100 } 101 102 static if (0) 103 { 104 printf("defkill "); vec_println(go.defkill,go.exptop); 105 printf("starkill "); vec_println(go.starkill,go.exptop); 106 printf("vptrkill "); vec_println(go.vptrkill,go.exptop); 107 } 108 109 static if (0) 110 { 111 /* This is the 'correct' algorithm for CSEs. We can't use it */ 112 /* till we fix the code generator. */ 113 foreach (i, b; dfo[]) 114 { 115 if (b.Belem) 116 { 117 static if (0) 118 { 119 printf("dfo[%d] = %p\n",i,b); 120 printf("b.Bin "); vec_println(b.Bin,go.exptop); 121 printf("b.Bout "); vec_println(b.Bout,go.exptop); 122 aewalk(&(b.Belem),b.Bin); 123 printf("b.Bin "); vec_println(b.Bin,go.exptop); 124 printf("b.Bout "); vec_println(b.Bout,go.exptop); 125 } 126 else 127 { 128 aewalk(&(b.Belem),b.Bin); 129 } 130 /* Bin and Bout would be equal at this point */ 131 /* except that we deleted some elems from */ 132 /* go.expnod[] and so it's a subset of Bout */ 133 /* assert(veceq(b.Bin,b.Bout)); */ 134 } 135 } 136 } 137 else 138 { 139 /* Do CSEs across extended basic blocks only. This is because */ 140 /* the code generator can only track register contents */ 141 /* properly across extended basic blocks. */ 142 aevec = vec_calloc(go.exptop); 143 foreach (i, b; dfo[]) 144 { 145 /* if not first block and (there are more than one */ 146 /* predecessor or the only predecessor is not the */ 147 /* previous block), then zero out the available */ 148 /* expressions. */ 149 if ((i != 0 && 150 (list_block(b.Bpred) != dfo[i - 1] || 151 list_next(b.Bpred) != null)) 152 || b.BC == BCasm 153 || b.BC == BC_finally 154 || b.BC == BC_lpad 155 || b.BC == BCcatch 156 || b.BC == BCjcatch 157 ) 158 vec_clear(aevec); 159 if (b.Belem) /* if there is an expression */ 160 aewalk(&(b.Belem),aevec); 161 } 162 vec_free(aevec); 163 } 164 165 // Need 2 passes to converge on solution 166 foreach (j; 0 .. 2) 167 foreach (b; dfo[]) 168 { 169 if (b.Belem) 170 { 171 //printf("b = 0x%x\n",b); 172 removecses(&(b.Belem)); 173 } 174 } 175 } 176 177 178 /**************************** 179 * Walk tree, rewriting *pn into a DAG as we go. 180 * Params: 181 * pn = pointer to expression tree to convert to DAG 182 * ae = vector of available expressions 183 */ 184 @trusted 185 private void aewalk(elem **pn,vec_t ae) 186 { 187 elem* n = *pn; 188 assert(n && ae); 189 //printf("visiting %d: (",n.Eexp); WReqn(*pn); printf(")\n"); 190 //chkvecdim(go.exptop); 191 const op = n.Eoper; 192 if (n.Eexp) // if an AE 193 { // Try to find an equivalent AE, and point to it instead 194 assert(go.expnod[n.Eexp] == n); 195 if (aetype == Aetype.cse) 196 { 197 for (uint i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) 198 { elem *e = go.expnod[i]; 199 200 // Attempt to replace n with e 201 if (e == null) // if elem no longer exists 202 vec_clearbit(i,ae); // it's not available 203 else if (n != e && 204 el_match(n,e) && 205 e.Ecount < 0xFF-1 && // must fit in unsigned char 206 cse_float(n) 207 ) 208 { 209 *pn = e; // replace n with e 210 //printf("cse: %p (",n); WReqn(*pn); printf(")\n"); 211 e.Ecount++; 212 debug assert(e.Ecount != 0); 213 214 void aeclear(elem *n) 215 { 216 while (1) 217 { 218 const i = n.Eexp; 219 assert(i); 220 if (n.Ecount) 221 break; 222 223 go.expnod[i] = null; 224 vec_clearbit(i,ae); 225 if (OTunary(n.Eoper)) 226 { 227 n = n.EV.E1; 228 continue; 229 } 230 else if (OTbinary(n.Eoper)) 231 { 232 aeclear(n.EV.E1); 233 n = n.EV.E2; 234 continue; 235 } 236 break; 237 } 238 } 239 240 aeclear(n); 241 el_free(n); 242 return; 243 } 244 } 245 } 246 } 247 248 elem *t; 249 switch (op) 250 { 251 case OPcolon: 252 case OPcolon2: 253 { 254 // ae = ae & ael & aer 255 // AEs gened by ael and aer are mutually exclusive 256 vec_t aer = vec_clone(ae); 257 aewalk(&(n.EV.E1),ae); 258 aewalk(&(n.EV.E2),aer); 259 vec_andass(ae,aer); 260 vec_free(aer); 261 break; 262 } 263 264 case OPandand: 265 case OPoror: 266 { 267 aewalk(&(n.EV.E1),ae); 268 /* ae &= aer */ 269 vec_t aer = vec_clone(ae); 270 aewalk(&(n.EV.E2),aer); 271 if (el_returns(n.EV.E2)) 272 vec_andass(ae,aer); 273 vec_free(aer); 274 break; 275 } 276 277 case OPnegass: 278 t = n.EV.E1; 279 if (t.Eoper == OPind) 280 aewalk(&(t.EV.E1),ae); 281 break; 282 283 case OPctor: 284 case OPdtor: 285 case OPdctor: 286 break; 287 288 case OPasm: 289 case OPddtor: 290 vec_clear(ae); // kill everything 291 return; 292 293 default: 294 if (OTbinary(op)) 295 { 296 if (ERTOL(n)) 297 { 298 // Don't CSE constants that will turn into 299 // an INC or DEC anyway 300 if (n.EV.E2.Eoper == OPconst && 301 n.EV.E2.EV.Vint == 1 && 302 (op == OPaddass || op == OPminass || 303 op == OPpostinc || op == OPpostdec) 304 ) 305 { } 306 else 307 aewalk(&(n.EV.E2),ae); 308 } 309 if (OTassign(op)) 310 { 311 t = n.EV.E1; 312 if (t.Eoper == OPind) 313 aewalk(&(t.EV.E1),ae); 314 } 315 else 316 aewalk(&(n.EV.E1),ae); 317 if (!ERTOL(n)) 318 aewalk(&(n.EV.E2),ae); 319 } 320 else if (OTunary(op)) 321 { 322 assert(op != OPnegass); 323 aewalk(&(n.EV.E1),ae); 324 } 325 } 326 327 if (OTdef(op)) 328 { 329 assert(n.Eexp == 0); // should not be an AE 330 /* remove all AEs that could be affected by this def */ 331 if (Eunambig(n)) // if unambiguous definition 332 { 333 assert(t.Eoper == OPvar); 334 Symbol* s = t.EV.Vsym; 335 if (Symbol_isAffected(*s)) 336 vec_subass(ae,go.starkill); 337 for (uint i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) // for each ae elem 338 { 339 elem *e = go.expnod[i]; 340 341 if (!e) continue; 342 if (OTunary(e.Eoper)) 343 { 344 if (vec_testbit(e.EV.E1.Eexp,ae)) 345 continue; 346 } 347 else if (OTbinary(e.Eoper)) 348 { 349 if (vec_testbit(e.EV.E1.Eexp,ae) && 350 vec_testbit(e.EV.E2.Eexp,ae)) 351 continue; 352 } 353 else if (e.Eoper == OPvar) 354 { 355 if (e.EV.Vsym != s) 356 continue; 357 } 358 else 359 continue; 360 vec_clearbit(i,ae); 361 } 362 } 363 else /* else ambiguous definition */ 364 { 365 vec_subass(ae,go.defkill); 366 if (OTcalldef(op)) 367 vec_subass(ae,go.vptrkill); 368 } 369 370 // GEN the lvalue of an assignment operator 371 if (OTassign(op) && !OTpost(op) && t.Eexp) 372 vec_setbit(t.Eexp,ae); 373 } 374 if (n.Eexp) // if an AE 375 { 376 if (op == OPvp_fp || op == OPcvp_fp) 377 /* Invalidate all other OPvp_fps */ 378 vec_subass(ae,go.vptrkill); 379 380 /*printf("available: ("); WReqn(n); printf(")\n"); 381 elem_print(n);*/ 382 vec_setbit(n.Eexp,ae); /* mark this elem as available */ 383 } 384 } 385 386 387 /************************** 388 * Remove a CSE. 389 * Input: 390 * pe pointer to pointer to CSE 391 * Output: 392 * *pe new elem to replace the old 393 * Returns: 394 * *pe 395 */ 396 @trusted 397 private elem * delcse(elem **pe) 398 { 399 elem *e; 400 401 e = el_calloc(); 402 el_copy(e,*pe); 403 404 debug if (debugc) 405 { 406 printf("deleting unprofitable CSE %p (", *pe); 407 WReqn(e); 408 printf(")\n"); 409 } 410 411 assert(e.Ecount != 0); 412 if (!OTleaf(e.Eoper)) 413 { 414 if (e.EV.E1.Ecount == 0xFF-1) 415 { 416 elem *ereplace; 417 ereplace = el_calloc(); 418 el_copy(ereplace,e.EV.E1); 419 e.EV.E1 = ereplace; 420 ereplace.Ecount = 0; 421 } 422 else 423 { 424 e.EV.E1.Ecount++; 425 debug assert(e.EV.E1.Ecount != 0); 426 } 427 if (OTbinary(e.Eoper)) 428 { 429 if (e.EV.E2.Ecount == 0xFF-1) 430 { 431 elem *ereplace; 432 ereplace = el_calloc(); 433 el_copy(ereplace,e.EV.E2); 434 e.EV.E2 = ereplace; 435 ereplace.Ecount = 0; 436 } 437 else 438 { 439 e.EV.E2.Ecount++; 440 debug assert(e.EV.E2.Ecount != 0); 441 } 442 } 443 } 444 --(*pe).Ecount; 445 debug assert((*pe).Ecount != 0xFF); 446 (*pe).Nflags |= NFLdelcse; // not generating node 447 e.Ecount = 0; 448 *pe = e; 449 return *pe; 450 } 451 452 453 /****************************** 454 * 'Unstick' CSEs that would be unprofitable to do. These are usually 455 * things like addressing modes, and are usually target-dependent. 456 */ 457 458 @trusted 459 private void removecses(elem **pe) 460 { 461 L1: 462 elem* e = *pe; 463 //printf(" removecses(%p) ", e); WReqn(e); printf("\n"); 464 assert(e); 465 elem_debug(e); 466 if (e.Nflags & NFLdelcse && e.Ecount) 467 { 468 delcse(pe); 469 goto L1; 470 } 471 const op = e.Eoper; 472 if (OTunary(op)) 473 { 474 if (op == OPind) 475 { 476 bool scaledIndex = I32 || I64; // if scaled index addressing mode support 477 elem *e1 = e.EV.E1; 478 if (e1.Eoper == OPadd && 479 e1.Ecount 480 ) 481 { 482 if (scaledIndex) 483 { 484 e1 = delcse(&e.EV.E1); 485 if (e1.EV.E1.Ecount) // == 1) 486 delcse(&e1.EV.E1); 487 if (e1.EV.E2.Ecount && e1.EV.E2.Eoper != OPind) 488 delcse(&e1.EV.E2); 489 } 490 /* *(v +. c) 491 * *(*pc +. c) 492 * The + and the const shouldn't be CSEs. 493 */ 494 else if (e1.EV.E2.Eoper == OPconst && 495 (e1.EV.E1.Eoper == OPvar || (e1.EV.E1.Eoper == OPind && e1.EV.E1.Ety & (mTYconst | mTYimmutable))) 496 ) 497 { 498 e1 = delcse(&e.EV.E1); 499 } 500 } 501 502 /* *(((e <<. 3) + e) + e) 503 */ 504 if (scaledIndex && e1.Eoper == OPadd && 505 e1.EV.E1.Eoper == OPadd && 506 e1.EV.E1.EV.E1.Ecount && 507 e1.EV.E1.EV.E1.Eoper == OPshl && 508 e1.EV.E1.EV.E1.EV.E2.Eoper == OPconst && 509 e1.EV.E1.EV.E1.EV.E2.EV.Vuns <= 3 510 ) 511 { 512 delcse(&e1.EV.E1.EV.E1); // the <<. operator 513 } 514 515 /* *(((e << 3) +. e) + e) 516 */ 517 if (scaledIndex && e1.Eoper == OPadd && 518 e1.EV.E1.Eoper == OPadd && 519 e1.EV.E1.Ecount && 520 e1.EV.E1.EV.E1.Eoper == OPshl && 521 e1.EV.E1.EV.E1.EV.E2.Eoper == OPconst && 522 e1.EV.E1.EV.E1.EV.E2.EV.Vuns <= 3 523 ) 524 { 525 delcse(&e1.EV.E1); // the +. operator 526 } 527 528 /* *((e <<. 3) + e) 529 */ 530 else if (scaledIndex && e1.Eoper == OPadd && 531 e1.EV.E1.Ecount && 532 e1.EV.E1.Eoper == OPshl && 533 e1.EV.E1.EV.E2.Eoper == OPconst && 534 e1.EV.E1.EV.E2.EV.Vuns <= 3 535 ) 536 { 537 delcse(&e1.EV.E1); // the <<. operator 538 } 539 540 // Remove *e1 where it's a double 541 if (e.Ecount && tyfloating(e.Ety)) 542 e = delcse(pe); 543 } 544 // This CSE is too easy to regenerate 545 else if (op == OPu16_32 && I16 && e.Ecount) 546 e = delcse(pe); 547 548 else if (op == OPd_ld && e.EV.E1.Ecount > 0) 549 delcse(&e.EV.E1); 550 551 // OPremquo is only worthwhile if its result is used more than once 552 else if (e.EV.E1.Eoper == OPremquo && 553 (op == OP64_32 || op == OP128_64 || op == OPmsw) && 554 e.EV.E1.Ecount == 0) 555 { // Convert back to OPdiv or OPmod 556 elem *e1 = e.EV.E1; 557 e.Eoper = (op == OPmsw) ? OPmod : OPdiv; 558 e.EV.E1 = e1.EV.E1; 559 e.EV.E2 = e1.EV.E2; 560 e1.EV.E1 = null; 561 e1.EV.E2 = null; 562 el_free(e1); 563 564 removecses(&(e.EV.E1)); 565 pe = &(e.EV.E2); 566 goto L1; 567 } 568 } 569 else if (OTbinary(op)) 570 { 571 if (e.Ecount > 0 && OTrel(op) && e.Ecount < 4 572 /* Don't CSE floating stuff if generating */ 573 /* inline 8087 code, the code generator */ 574 /* can't handle it yet */ 575 && !(tyfloating(e.EV.E1.Ety) && config.inline8087) 576 ) 577 e = delcse(pe); 578 if (ERTOL(e)) 579 { 580 removecses(&(e.EV.E2)); 581 pe = &(e.EV.E1); 582 } 583 else 584 { 585 removecses(&(e.EV.E1)); 586 pe = &(e.EV.E2); 587 } 588 goto L1; 589 } 590 else /* leaf node */ 591 { 592 return; 593 } 594 pe = &(e.EV.E1); 595 goto L1; 596 } 597 598 /***************************************** 599 * Do optimizations based on if we know an expression is 600 * 0 or !=0, even though we don't know anything else. 601 */ 602 603 @trusted 604 void boolopt() 605 { 606 vec_t aevec; 607 vec_t aevecval; 608 609 debug if (debugc) printf("boolopt()\n"); 610 if (!dfo.length) 611 compdfo(dfo, startblock); 612 flowae(); /* compute available expressions */ 613 if (go.exptop <= 1) /* if no AEs */ 614 return; 615 static if (0) 616 { 617 for (uint i = 0; i < go.exptop; i++) 618 printf("go.expnod[%d] = 0x%x\n",i,go.expnod[i]); 619 printf("defkill "); vec_println(go.defkill,go.exptop); 620 printf("starkill "); vec_println(go.starkill,go.exptop); 621 printf("vptrkill "); vec_println(go.vptrkill,go.exptop); 622 } 623 624 /* Do CSEs across extended basic blocks only. This is because */ 625 /* the code generator can only track register contents */ 626 /* properly across extended basic blocks. */ 627 aevec = vec_calloc(go.exptop); 628 aevecval = vec_calloc(go.exptop); 629 630 // Mark each expression that we know starts off with a non-zero value 631 for (uint i = 0; i < go.exptop; i++) 632 { 633 elem *e = go.expnod[i]; 634 if (e) 635 { 636 elem_debug(e); 637 if (e.Eoper == OPvar && e.EV.Vsym.Sflags & SFLtrue) 638 { 639 vec_setbit(i,aevec); 640 vec_setbit(i,aevecval); 641 } 642 } 643 } 644 645 foreach (i, b; dfo[]) 646 { 647 /* if not first block and (there are more than one */ 648 /* predecessor or the only predecessor is not the */ 649 /* previous block), then zero out the available */ 650 /* expressions. */ 651 if ((i != 0 && 652 (list_block(b.Bpred) != dfo[i - 1] || 653 list_next(b.Bpred) != null)) 654 || b.BC == BCasm 655 || b.BC == BC_finally 656 || b.BC == BC_lpad 657 || b.BC == BCcatch 658 || b.BC == BCjcatch 659 ) 660 vec_clear(aevec); 661 if (b.Belem) /* if there is an expression */ 662 abewalk(b.Belem,aevec,aevecval); 663 } 664 vec_free(aevec); 665 vec_free(aevecval); 666 } 667 668 /**************************** 669 * Walk tree, replacing bool expressions that we know 670 * ae = vector of available boolean expressions 671 * aeval = parallel vector of values corresponding to whether bool 672 * value is 1 or 0 673 * n = elem tree to look at 674 */ 675 676 @trusted 677 private void abewalk(elem *n,vec_t ae,vec_t aeval) 678 { 679 elem *t; 680 681 assert(n && ae); 682 elem_debug(n); 683 /*printf("visiting: ("); WReqn(*pn); printf("), Eexp = %d\n",n.Eexp);*/ 684 /*chkvecdim(go.exptop);*/ 685 const op = n.Eoper; 686 switch (op) 687 { 688 case OPcond: 689 { 690 assert(n.EV.E2.Eoper == OPcolon || n.EV.E2.Eoper == OPcolon2); 691 abewalk(n.EV.E1,ae,aeval); 692 abeboolres(n.EV.E1,ae,aeval); 693 vec_t aer = vec_clone(ae); 694 vec_t aerval = vec_clone(aeval); 695 if (!el_returns(n.EV.E2.EV.E1)) 696 { 697 abeset(n.EV.E1,aer,aerval,true); 698 abewalk(n.EV.E2.EV.E1,aer,aerval); 699 abeset(n.EV.E1,ae,aeval,false); 700 abewalk(n.EV.E2.EV.E2,ae,aeval); 701 } 702 else if (!el_returns(n.EV.E2.EV.E2)) 703 { 704 abeset(n.EV.E1,ae,aeval,true); 705 abewalk(n.EV.E2.EV.E1,ae,aeval); 706 abeset(n.EV.E1,aer,aerval,false); 707 abewalk(n.EV.E2.EV.E2,aer,aerval); 708 } 709 else 710 { 711 /* ae = ae & ael & aer 712 * AEs gened by ael and aer are mutually exclusive 713 */ 714 abeset(n.EV.E1,aer,aerval,true); 715 abewalk(n.EV.E2.EV.E1,aer,aerval); 716 abeset(n.EV.E1,ae,aeval,false); 717 abewalk(n.EV.E2.EV.E2,ae,aeval); 718 719 vec_xorass(aerval,aeval); 720 vec_subass(aer,aerval); 721 vec_andass(ae,aer); 722 } 723 vec_free(aer); 724 vec_free(aerval); 725 break; 726 } 727 728 case OPcolon: 729 case OPcolon2: 730 assert(0); 731 732 case OPandand: 733 case OPoror: 734 { 735 //printf("test1 %p: ", n); WReqn(n); printf("\n"); 736 abewalk(n.EV.E1,ae,aeval); 737 abeboolres(n.EV.E1,ae,aeval); 738 vec_t aer = vec_clone(ae); 739 vec_t aerval = vec_clone(aeval); 740 if (!el_returns(n.EV.E2)) 741 { 742 abeset(n.EV.E1,aer,aerval,(op == OPandand)); 743 abewalk(n.EV.E2,aer,aerval); 744 abeset(n.EV.E1,ae,aeval,(op != OPandand)); 745 } 746 else 747 { 748 /* ae &= aer 749 */ 750 abeset(n.EV.E1,aer,aerval,(op == OPandand)); 751 abewalk(n.EV.E2,aer,aerval); 752 753 vec_xorass(aerval,aeval); 754 vec_subass(aer,aerval); 755 vec_andass(ae,aer); 756 } 757 758 vec_free(aer); 759 vec_free(aerval); 760 break; 761 } 762 763 case OPbool: 764 case OPnot: 765 abewalk(n.EV.E1,ae,aeval); 766 abeboolres(n.EV.E1,ae,aeval); 767 break; 768 769 case OPeqeq: 770 case OPne: 771 case OPlt: 772 case OPle: 773 case OPgt: 774 case OPge: 775 case OPunord: case OPlg: case OPleg: case OPule: 776 case OPul: case OPuge: case OPug: case OPue: 777 case OPngt: case OPnge: case OPnlt: case OPnle: 778 case OPord: case OPnlg: case OPnleg: case OPnule: 779 case OPnul: case OPnuge: case OPnug: case OPnue: 780 abewalk(n.EV.E1,ae,aeval); 781 abewalk(n.EV.E2,ae,aeval); 782 abeboolres(n,ae,aeval); 783 break; 784 785 case OPnegass: 786 t = n.EV.E1; 787 if (t.Eoper == OPind) 788 abewalk(t.EV.E1,ae,aeval); 789 break; 790 791 case OPasm: 792 vec_clear(ae); // kill everything 793 return; 794 795 default: 796 if (OTbinary(op)) 797 { if (ERTOL(n)) 798 abewalk(n.EV.E2,ae,aeval); 799 if (OTassign(op)) 800 { t = n.EV.E1; 801 if (t.Eoper == OPind) 802 abewalk(t.EV.E1,ae,aeval); 803 } 804 else 805 abewalk(n.EV.E1,ae,aeval); 806 if (!ERTOL(n)) 807 abewalk(n.EV.E2,ae,aeval); 808 } 809 else if (OTunary(op)) 810 abewalk(n.EV.E1,ae,aeval); 811 break; 812 } 813 814 if (OTdef(op)) 815 { 816 assert(n.Eexp == 0); // should not be an AE 817 /* remove all AEs that could be affected by this def */ 818 if (Eunambig(n)) /* if unambiguous definition */ 819 { 820 Symbol *s; 821 822 assert(t.Eoper == OPvar); 823 s = t.EV.Vsym; 824 if (Symbol_isAffected(*s)) 825 vec_subass(ae,go.starkill); 826 for (uint i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) // for each ae elem 827 { 828 elem *e = go.expnod[i]; 829 830 if (!e) continue; 831 if (el_appears(e,s)) 832 vec_clearbit(i,ae); 833 } 834 } 835 else /* else ambiguous definition */ 836 { 837 vec_subass(ae,go.defkill); 838 if (OTcalldef(op)) 839 vec_subass(ae,go.vptrkill); 840 } 841 /* GEN the lvalue of an assignment operator */ 842 uint i1, i2; 843 if (op == OPeq && (i1 = t.Eexp) != 0 && (i2 = n.EV.E2.Eexp) != 0) 844 { 845 if (vec_testbit(i2,ae)) 846 { 847 vec_setbit(i1,ae); 848 if (vec_testbit(i2,aeval)) 849 vec_setbit(i1,aeval); 850 else 851 vec_clearbit(i1,aeval); 852 } 853 } 854 } 855 else if (n.Eexp) /* if an AE */ 856 { 857 if (op == OPvp_fp || op == OPcvp_fp) 858 /* Invalidate all other OPvp_fps */ 859 vec_subass(ae,go.vptrkill); 860 861 /*printf("available: ("); WReqn(n); printf(")\n"); 862 elem_print(n);*/ 863 // vec_setbit(n.Eexp,ae); /* mark this elem as available */ 864 } 865 } 866 867 /************************************ 868 * Elem e is to be evaluated for a boolean result. 869 * See if we already know its value. 870 */ 871 872 @trusted 873 private void abeboolres(elem *n,vec_t ae,vec_t aeval) 874 { 875 //printf("abeboolres()[%d %p] ", n.Eexp, go.expnod[n.Eexp]); WReqn(n); printf("\n"); 876 elem_debug(n); 877 if (n.Eexp && go.expnod[n.Eexp]) 878 { /* Try to find an equivalent AE, and point to it instead */ 879 assert(go.expnod[n.Eexp] == n); 880 uint i; 881 for (i = 0; (i = cast(uint) vec_index(i, ae)) < go.exptop; ++i) // for each ae elem 882 { elem *e = go.expnod[i]; 883 884 // Attempt to replace n with the boolean result of e 885 //printf("Looking at go.expnod[%d] = %p\n",i,e); 886 assert(e); 887 elem_debug(e); 888 if (n != e && el_match(n,e)) 889 { 890 debug if (debugc) 891 { printf("Elem %p: ",n); 892 WReqn(n); 893 printf(" is replaced by %d\n",vec_testbit(i,aeval) != 0); 894 } 895 896 abefree(n,ae); 897 n.EV.Vlong = vec_testbit(i,aeval) != 0; 898 n.Eoper = OPconst; 899 n.Ety = TYint; 900 go.changes++; 901 break; 902 } 903 } 904 } 905 } 906 907 /**************************** 908 * Remove e from available expressions, and its children. 909 */ 910 911 @trusted 912 private void abefree(elem *e,vec_t ae) 913 { 914 //printf("abefree [%d %p]: ", e.Eexp, e); WReqn(e); printf("\n"); 915 assert(e.Eexp); 916 vec_clearbit(e.Eexp,ae); 917 go.expnod[e.Eexp] = null; 918 if (!OTleaf(e.Eoper)) 919 { 920 if (OTbinary(e.Eoper)) 921 { 922 abefree(e.EV.E2,ae); 923 el_free(e.EV.E2); 924 e.EV.E2 = null; 925 } 926 abefree(e.EV.E1,ae); 927 el_free(e.EV.E1); 928 e.EV.E1 = null; 929 } 930 } 931 932 /************************************ 933 * Elem e is to be evaluated for a boolean result. 934 * Set its result according to flag. 935 */ 936 937 @trusted 938 private void abeset(elem *e,vec_t ae,vec_t aeval,int flag) 939 { 940 while (1) 941 { 942 uint i = e.Eexp; 943 if (i && go.expnod[i]) 944 { 945 //printf("abeset for go.expnod[%d] = %p: ",i,e); WReqn(e); printf("\n"); 946 vec_setbit(i,ae); 947 if (flag) 948 vec_setbit(i,aeval); 949 else 950 vec_clearbit(i,aeval); 951 } 952 switch (e.Eoper) 953 { case OPnot: 954 flag ^= 1; 955 e = e.EV.E1; 956 continue; 957 958 case OPbool: 959 case OPeq: 960 e = e.EV.E1; 961 continue; 962 963 default: 964 break; 965 } 966 break; 967 } 968 } 969 970 }