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