github.com/razvanm/vanadium-go-1.3@v0.0.0-20160721203343-4a65068e5915/src/cmd/5c/peep.c (about) 1 // Inferno utils/5c/peep.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/5c/peep.c 3 // 4 // Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. 5 // Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net) 6 // Portions Copyright © 1997-1999 Vita Nuova Limited 7 // Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com) 8 // Portions Copyright © 2004,2006 Bruce Ellis 9 // Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net) 10 // Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others 11 // Portions Copyright © 2009 The Go Authors. All rights reserved. 12 // 13 // Permission is hereby granted, free of charge, to any person obtaining a copy 14 // of this software and associated documentation files (the "Software"), to deal 15 // in the Software without restriction, including without limitation the rights 16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 17 // copies of the Software, and to permit persons to whom the Software is 18 // furnished to do so, subject to the following conditions: 19 // 20 // The above copyright notice and this permission notice shall be included in 21 // all copies or substantial portions of the Software. 22 // 23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 29 // THE SOFTWARE. 30 31 32 #include "gc.h" 33 34 int xtramodes(Reg*, Addr*); 35 36 void 37 peep(void) 38 { 39 Reg *r, *r1, *r2; 40 Prog *p, *p1; 41 int t; 42 /* 43 * complete R structure 44 */ 45 t = 0; 46 for(r=firstr; r!=R; r=r1) { 47 r1 = r->link; 48 if(r1 == R) 49 break; 50 p = r->prog->link; 51 while(p != r1->prog) 52 switch(p->as) { 53 default: 54 r2 = rega(); 55 r->link = r2; 56 r2->link = r1; 57 58 r2->prog = p; 59 r2->p1 = r; 60 r->s1 = r2; 61 r2->s1 = r1; 62 r1->p1 = r2; 63 64 r = r2; 65 t++; 66 67 case ADATA: 68 case AGLOBL: 69 case ANAME: 70 case ASIGNAME: 71 p = p->link; 72 } 73 } 74 75 loop1: 76 t = 0; 77 for(r=firstr; r!=R; r=r->link) { 78 p = r->prog; 79 if(p->as == ASLL || p->as == ASRL || p->as == ASRA) { 80 /* 81 * elide shift into D_SHIFT operand of subsequent instruction 82 */ 83 if(shiftprop(r)) { 84 excise(r); 85 t++; 86 } 87 } 88 if(p->as == AMOVW || p->as == AMOVF || p->as == AMOVD) 89 if(regtyp(&p->to)) { 90 if(p->from.type == D_CONST) 91 constprop(&p->from, &p->to, r->s1); 92 else if(regtyp(&p->from)) 93 if(p->from.type == p->to.type) { 94 if(copyprop(r)) { 95 excise(r); 96 t++; 97 } else 98 if(subprop(r) && copyprop(r)) { 99 excise(r); 100 t++; 101 } 102 } 103 } 104 } 105 if(t) 106 goto loop1; 107 /* 108 * look for MOVB x,R; MOVB R,R 109 */ 110 for(r=firstr; r!=R; r=r->link) { 111 p = r->prog; 112 switch(p->as) { 113 default: 114 continue; 115 case AEOR: 116 /* 117 * EOR -1,x,y => MVN x,y 118 */ 119 if(p->from.type == D_CONST && p->from.offset == -1) { 120 p->as = AMVN; 121 p->from.type = D_REG; 122 if(p->reg != NREG) 123 p->from.reg = p->reg; 124 else 125 p->from.reg = p->to.reg; 126 p->reg = NREG; 127 } 128 continue; 129 case AMOVH: 130 case AMOVHS: 131 case AMOVHU: 132 case AMOVB: 133 case AMOVBS: 134 case AMOVBU: 135 if(p->to.type != D_REG) 136 continue; 137 break; 138 } 139 r1 = r->link; 140 if(r1 == R) 141 continue; 142 p1 = r1->prog; 143 if(p1->as != p->as) 144 continue; 145 if(p1->from.type != D_REG || p1->from.reg != p->to.reg) 146 continue; 147 if(p1->to.type != D_REG || p1->to.reg != p->to.reg) 148 continue; 149 excise(r1); 150 } 151 152 for(r=firstr; r!=R; r=r->link) { 153 p = r->prog; 154 switch(p->as) { 155 case AMOVW: 156 case AMOVB: 157 case AMOVBS: 158 case AMOVBU: 159 if(p->from.type == D_OREG && p->from.offset == 0) 160 xtramodes(r, &p->from); 161 else if(p->to.type == D_OREG && p->to.offset == 0) 162 xtramodes(r, &p->to); 163 else 164 continue; 165 break; 166 case ACMP: 167 /* 168 * elide CMP $0,x if calculation of x can set condition codes 169 */ 170 if(p->from.type != D_CONST || p->from.offset != 0) 171 continue; 172 r2 = r->s1; 173 if(r2 == R) 174 continue; 175 t = r2->prog->as; 176 switch(t) { 177 default: 178 continue; 179 case ABEQ: 180 case ABNE: 181 case ABMI: 182 case ABPL: 183 break; 184 case ABGE: 185 t = ABPL; 186 break; 187 case ABLT: 188 t = ABMI; 189 break; 190 case ABHI: 191 t = ABNE; 192 break; 193 case ABLS: 194 t = ABEQ; 195 break; 196 } 197 r1 = r; 198 do 199 r1 = uniqp(r1); 200 while (r1 != R && r1->prog->as == ANOP); 201 if(r1 == R) 202 continue; 203 p1 = r1->prog; 204 if(p1->to.type != D_REG) 205 continue; 206 if(p1->to.reg != p->reg) 207 if(!(p1->as == AMOVW && p1->from.type == D_REG && p1->from.reg == p->reg)) 208 continue; 209 switch(p1->as) { 210 default: 211 continue; 212 case AMOVW: 213 if(p1->from.type != D_REG) 214 continue; 215 case AAND: 216 case AEOR: 217 case AORR: 218 case ABIC: 219 case AMVN: 220 case ASUB: 221 case ARSB: 222 case AADD: 223 case AADC: 224 case ASBC: 225 case ARSC: 226 break; 227 } 228 p1->scond |= C_SBIT; 229 r2->prog->as = t; 230 excise(r); 231 continue; 232 } 233 } 234 235 predicate(); 236 } 237 238 void 239 excise(Reg *r) 240 { 241 Prog *p; 242 243 p = r->prog; 244 p->as = ANOP; 245 p->scond = zprog.scond; 246 p->from = zprog.from; 247 p->to = zprog.to; 248 p->reg = zprog.reg; /**/ 249 } 250 251 Reg* 252 uniqp(Reg *r) 253 { 254 Reg *r1; 255 256 r1 = r->p1; 257 if(r1 == R) { 258 r1 = r->p2; 259 if(r1 == R || r1->p2link != R) 260 return R; 261 } else 262 if(r->p2 != R) 263 return R; 264 return r1; 265 } 266 267 Reg* 268 uniqs(Reg *r) 269 { 270 Reg *r1; 271 272 r1 = r->s1; 273 if(r1 == R) { 274 r1 = r->s2; 275 if(r1 == R) 276 return R; 277 } else 278 if(r->s2 != R) 279 return R; 280 return r1; 281 } 282 283 int 284 regtyp(Addr *a) 285 { 286 287 if(a->type == D_REG) 288 return 1; 289 if(a->type == D_FREG) 290 return 1; 291 return 0; 292 } 293 294 /* 295 * the idea is to substitute 296 * one register for another 297 * from one MOV to another 298 * MOV a, R0 299 * ADD b, R0 / no use of R1 300 * MOV R0, R1 301 * would be converted to 302 * MOV a, R1 303 * ADD b, R1 304 * MOV R1, R0 305 * hopefully, then the former or latter MOV 306 * will be eliminated by copy propagation. 307 */ 308 int 309 subprop(Reg *r0) 310 { 311 Prog *p; 312 Addr *v1, *v2; 313 Reg *r; 314 int t; 315 316 p = r0->prog; 317 v1 = &p->from; 318 if(!regtyp(v1)) 319 return 0; 320 v2 = &p->to; 321 if(!regtyp(v2)) 322 return 0; 323 for(r=uniqp(r0); r!=R; r=uniqp(r)) { 324 if(uniqs(r) == R) 325 break; 326 p = r->prog; 327 switch(p->as) { 328 case ABL: 329 return 0; 330 331 case ACMP: 332 case ACMN: 333 case AADD: 334 case ASUB: 335 case ARSB: 336 case ASLL: 337 case ASRL: 338 case ASRA: 339 case AORR: 340 case AAND: 341 case AEOR: 342 case AMUL: 343 case ADIV: 344 case ADIVU: 345 346 case ACMPF: 347 case ACMPD: 348 case AADDD: 349 case AADDF: 350 case ASUBD: 351 case ASUBF: 352 case AMULD: 353 case AMULF: 354 case ADIVD: 355 case ADIVF: 356 if(p->to.type == v1->type) 357 if(p->to.reg == v1->reg) { 358 if(p->reg == NREG) 359 p->reg = p->to.reg; 360 goto gotit; 361 } 362 break; 363 364 case AMOVF: 365 case AMOVD: 366 case AMOVW: 367 if(p->to.type == v1->type) 368 if(p->to.reg == v1->reg) 369 goto gotit; 370 break; 371 372 case AMOVM: 373 t = 1<<v2->reg; 374 if((p->from.type == D_CONST && (p->from.offset&t)) || 375 (p->to.type == D_CONST && (p->to.offset&t))) 376 return 0; 377 break; 378 } 379 if(copyau(&p->from, v2) || 380 copyau1(p, v2) || 381 copyau(&p->to, v2)) 382 break; 383 if(copysub(&p->from, v1, v2, 0) || 384 copysub1(p, v1, v2, 0) || 385 copysub(&p->to, v1, v2, 0)) 386 break; 387 } 388 return 0; 389 390 gotit: 391 copysub(&p->to, v1, v2, 1); 392 if(debug['P']) { 393 print("gotit: %D->%D\n%P", v1, v2, r->prog); 394 if(p->from.type == v2->type) 395 print(" excise"); 396 print("\n"); 397 } 398 for(r=uniqs(r); r!=r0; r=uniqs(r)) { 399 p = r->prog; 400 copysub(&p->from, v1, v2, 1); 401 copysub1(p, v1, v2, 1); 402 copysub(&p->to, v1, v2, 1); 403 if(debug['P']) 404 print("%P\n", r->prog); 405 } 406 t = v1->reg; 407 v1->reg = v2->reg; 408 v2->reg = t; 409 if(debug['P']) 410 print("%P last\n", r->prog); 411 return 1; 412 } 413 414 /* 415 * The idea is to remove redundant copies. 416 * v1->v2 F=0 417 * (use v2 s/v2/v1/)* 418 * set v1 F=1 419 * use v2 return fail 420 * ----------------- 421 * v1->v2 F=0 422 * (use v2 s/v2/v1/)* 423 * set v1 F=1 424 * set v2 return success 425 */ 426 int 427 copyprop(Reg *r0) 428 { 429 Prog *p; 430 Addr *v1, *v2; 431 Reg *r; 432 433 p = r0->prog; 434 v1 = &p->from; 435 v2 = &p->to; 436 if(copyas(v1, v2)) 437 return 1; 438 for(r=firstr; r!=R; r=r->link) 439 r->active = 0; 440 return copy1(v1, v2, r0->s1, 0); 441 } 442 443 int 444 copy1(Addr *v1, Addr *v2, Reg *r, int f) 445 { 446 int t; 447 Prog *p; 448 449 if(r->active) { 450 if(debug['P']) 451 print("act set; return 1\n"); 452 return 1; 453 } 454 r->active = 1; 455 if(debug['P']) 456 print("copy %D->%D f=%d\n", v1, v2, f); 457 for(; r != R; r = r->s1) { 458 p = r->prog; 459 if(debug['P']) 460 print("%P", p); 461 if(!f && uniqp(r) == R) { 462 f = 1; 463 if(debug['P']) 464 print("; merge; f=%d", f); 465 } 466 t = copyu(p, v2, A); 467 switch(t) { 468 case 2: /* rar, can't split */ 469 if(debug['P']) 470 print("; %Drar; return 0\n", v2); 471 return 0; 472 473 case 3: /* set */ 474 if(debug['P']) 475 print("; %Dset; return 1\n", v2); 476 return 1; 477 478 case 1: /* used, substitute */ 479 case 4: /* use and set */ 480 if(f) { 481 if(!debug['P']) 482 return 0; 483 if(t == 4) 484 print("; %Dused+set and f=%d; return 0\n", v2, f); 485 else 486 print("; %Dused and f=%d; return 0\n", v2, f); 487 return 0; 488 } 489 if(copyu(p, v2, v1)) { 490 if(debug['P']) 491 print("; sub fail; return 0\n"); 492 return 0; 493 } 494 if(debug['P']) 495 print("; sub%D/%D", v2, v1); 496 if(t == 4) { 497 if(debug['P']) 498 print("; %Dused+set; return 1\n", v2); 499 return 1; 500 } 501 break; 502 } 503 if(!f) { 504 t = copyu(p, v1, A); 505 if(!f && (t == 2 || t == 3 || t == 4)) { 506 f = 1; 507 if(debug['P']) 508 print("; %Dset and !f; f=%d", v1, f); 509 } 510 } 511 if(debug['P']) 512 print("\n"); 513 if(r->s2) 514 if(!copy1(v1, v2, r->s2, f)) 515 return 0; 516 } 517 return 1; 518 } 519 520 /* 521 * The idea is to remove redundant constants. 522 * $c1->v1 523 * ($c1->v2 s/$c1/v1)* 524 * set v1 return 525 * The v1->v2 should be eliminated by copy propagation. 526 */ 527 void 528 constprop(Addr *c1, Addr *v1, Reg *r) 529 { 530 Prog *p; 531 532 if(debug['C']) 533 print("constprop %D->%D\n", c1, v1); 534 for(; r != R; r = r->s1) { 535 p = r->prog; 536 if(debug['C']) 537 print("%P", p); 538 if(uniqp(r) == R) { 539 if(debug['C']) 540 print("; merge; return\n"); 541 return; 542 } 543 if(p->as == AMOVW && copyas(&p->from, c1)) { 544 if(debug['C']) 545 print("; sub%D/%D", &p->from, v1); 546 p->from = *v1; 547 } else if(copyu(p, v1, A) > 1) { 548 if(debug['C']) 549 print("; %Dset; return\n", v1); 550 return; 551 } 552 if(debug['C']) 553 print("\n"); 554 if(r->s2) 555 constprop(c1, v1, r->s2); 556 } 557 } 558 559 /* 560 * ASLL x,y,w 561 * .. (not use w, not set x y w) 562 * AXXX w,a,b (a != w) 563 * .. (not use w) 564 * (set w) 565 * ----------- changed to 566 * .. 567 * AXXX (x<<y),a,b 568 * .. 569 */ 570 #define FAIL(msg) { if(debug['H']) print("\t%s; FAILURE\n", msg); return 0; } 571 int 572 shiftprop(Reg *r) 573 { 574 Reg *r1; 575 Prog *p, *p1, *p2; 576 int n, o; 577 Addr a; 578 579 p = r->prog; 580 if(p->to.type != D_REG) 581 FAIL("BOTCH: result not reg"); 582 n = p->to.reg; 583 a = zprog.from; 584 if(p->reg != NREG && p->reg != p->to.reg) { 585 a.type = D_REG; 586 a.reg = p->reg; 587 } 588 if(debug['H']) 589 print("shiftprop\n%P", p); 590 r1 = r; 591 for(;;) { 592 /* find first use of shift result; abort if shift operands or result are changed */ 593 r1 = uniqs(r1); 594 if(r1 == R) 595 FAIL("branch"); 596 if(uniqp(r1) == R) 597 FAIL("merge"); 598 p1 = r1->prog; 599 if(debug['H']) 600 print("\n%P", p1); 601 switch(copyu(p1, &p->to, A)) { 602 case 0: /* not used or set */ 603 if((p->from.type == D_REG && copyu(p1, &p->from, A) > 1) || 604 (a.type == D_REG && copyu(p1, &a, A) > 1)) 605 FAIL("args modified"); 606 continue; 607 case 3: /* set, not used */ 608 FAIL("BOTCH: noref"); 609 } 610 break; 611 } 612 /* check whether substitution can be done */ 613 switch(p1->as) { 614 default: 615 FAIL("non-dpi"); 616 case AAND: 617 case AEOR: 618 case AADD: 619 case AADC: 620 case AORR: 621 case ASUB: 622 case ARSB: 623 case ASBC: 624 case ARSC: 625 if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) { 626 if(p1->from.type != D_REG) 627 FAIL("can't swap"); 628 p1->reg = p1->from.reg; 629 p1->from.reg = n; 630 switch(p1->as) { 631 case ASUB: 632 p1->as = ARSB; 633 break; 634 case ARSB: 635 p1->as = ASUB; 636 break; 637 case ASBC: 638 p1->as = ARSC; 639 break; 640 case ARSC: 641 p1->as = ASBC; 642 break; 643 } 644 if(debug['H']) 645 print("\t=>%P", p1); 646 } 647 case ABIC: 648 case ACMP: 649 case ACMN: 650 if(p1->reg == n) 651 FAIL("can't swap"); 652 if(p1->reg == NREG && p1->to.reg == n) 653 FAIL("shift result used twice"); 654 case AMVN: 655 if(p1->from.type == D_SHIFT) 656 FAIL("shift result used in shift"); 657 if(p1->from.type != D_REG || p1->from.reg != n) 658 FAIL("BOTCH: where is it used?"); 659 break; 660 } 661 /* check whether shift result is used subsequently */ 662 p2 = p1; 663 if(p1->to.reg != n) 664 for (;;) { 665 r1 = uniqs(r1); 666 if(r1 == R) 667 FAIL("inconclusive"); 668 p1 = r1->prog; 669 if(debug['H']) 670 print("\n%P", p1); 671 switch(copyu(p1, &p->to, A)) { 672 case 0: /* not used or set */ 673 continue; 674 case 3: /* set, not used */ 675 break; 676 default:/* used */ 677 FAIL("reused"); 678 } 679 break; 680 } 681 /* make the substitution */ 682 p2->from.type = D_SHIFT; 683 p2->from.reg = NREG; 684 o = p->reg; 685 if(o == NREG) 686 o = p->to.reg; 687 switch(p->from.type){ 688 case D_CONST: 689 o |= (p->from.offset&0x1f)<<7; 690 break; 691 case D_REG: 692 o |= (1<<4) | (p->from.reg<<8); 693 break; 694 } 695 switch(p->as){ 696 case ASLL: 697 o |= 0<<5; 698 break; 699 case ASRL: 700 o |= 1<<5; 701 break; 702 case ASRA: 703 o |= 2<<5; 704 break; 705 } 706 p2->from.offset = o; 707 if(debug['H']) 708 print("\t=>%P\tSUCCEED\n", p2); 709 return 1; 710 } 711 712 Reg* 713 findpre(Reg *r, Addr *v) 714 { 715 Reg *r1; 716 717 for(r1=uniqp(r); r1!=R; r=r1,r1=uniqp(r)) { 718 if(uniqs(r1) != r) 719 return R; 720 switch(copyu(r1->prog, v, A)) { 721 case 1: /* used */ 722 case 2: /* read-alter-rewrite */ 723 return R; 724 case 3: /* set */ 725 case 4: /* set and used */ 726 return r1; 727 } 728 } 729 return R; 730 } 731 732 Reg* 733 findinc(Reg *r, Reg *r2, Addr *v) 734 { 735 Reg *r1; 736 Prog *p; 737 738 739 for(r1=uniqs(r); r1!=R && r1!=r2; r=r1,r1=uniqs(r)) { 740 if(uniqp(r1) != r) 741 return R; 742 switch(copyu(r1->prog, v, A)) { 743 case 0: /* not touched */ 744 continue; 745 case 4: /* set and used */ 746 p = r1->prog; 747 if(p->as == AADD) 748 if(p->from.type == D_CONST) 749 if(p->from.offset > -4096 && p->from.offset < 4096) 750 return r1; 751 default: 752 return R; 753 } 754 } 755 return R; 756 } 757 758 int 759 nochange(Reg *r, Reg *r2, Prog *p) 760 { 761 Addr a[3]; 762 int i, n; 763 764 if(r == r2) 765 return 1; 766 n = 0; 767 if(p->reg != NREG && p->reg != p->to.reg) { 768 a[n].type = D_REG; 769 a[n++].reg = p->reg; 770 } 771 switch(p->from.type) { 772 case D_SHIFT: 773 a[n].type = D_REG; 774 a[n++].reg = p->from.offset&0xf; 775 case D_REG: 776 a[n].type = D_REG; 777 a[n++].reg = p->from.reg; 778 } 779 if(n == 0) 780 return 1; 781 for(; r!=R && r!=r2; r=uniqs(r)) { 782 p = r->prog; 783 for(i=0; i<n; i++) 784 if(copyu(p, &a[i], A) > 1) 785 return 0; 786 } 787 return 1; 788 } 789 790 int 791 findu1(Reg *r, Addr *v) 792 { 793 for(; r != R; r = r->s1) { 794 if(r->active) 795 return 0; 796 r->active = 1; 797 switch(copyu(r->prog, v, A)) { 798 case 1: /* used */ 799 case 2: /* read-alter-rewrite */ 800 case 4: /* set and used */ 801 return 1; 802 case 3: /* set */ 803 return 0; 804 } 805 if(r->s2) 806 if (findu1(r->s2, v)) 807 return 1; 808 } 809 return 0; 810 } 811 812 int 813 finduse(Reg *r, Addr *v) 814 { 815 Reg *r1; 816 817 for(r1=firstr; r1!=R; r1=r1->link) 818 r1->active = 0; 819 return findu1(r, v); 820 } 821 822 int 823 xtramodes(Reg *r, Addr *a) 824 { 825 Reg *r1, *r2, *r3; 826 Prog *p, *p1; 827 Addr v; 828 829 p = r->prog; 830 if((p->as == AMOVB || p->as == AMOVBS) && p->from.type == D_OREG) /* byte load */ 831 return 0; 832 v = *a; 833 v.type = D_REG; 834 r1 = findpre(r, &v); 835 if(r1 != R) { 836 p1 = r1->prog; 837 if(p1->to.type == D_REG && p1->to.reg == v.reg) 838 switch(p1->as) { 839 case AADD: 840 if(p1->from.type == D_REG || 841 (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 && 842 ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) || 843 (p1->from.type == D_CONST && 844 p1->from.offset > -4096 && p1->from.offset < 4096)) 845 if(nochange(uniqs(r1), r, p1)) { 846 if(a != &p->from || v.reg != p->to.reg) 847 if (finduse(r->s1, &v)) { 848 if(p1->reg == NREG || p1->reg == v.reg) 849 /* pre-indexing */ 850 p->scond |= C_WBIT; 851 else return 0; 852 } 853 switch (p1->from.type) { 854 case D_REG: 855 /* register offset */ 856 if(nacl) 857 return 0; 858 a->type = D_SHIFT; 859 a->offset = p1->from.reg; 860 break; 861 case D_SHIFT: 862 /* scaled register offset */ 863 if(nacl) 864 return 0; 865 a->type = D_SHIFT; 866 case D_CONST: 867 /* immediate offset */ 868 a->offset = p1->from.offset; 869 break; 870 } 871 if(p1->reg != NREG) 872 a->reg = p1->reg; 873 excise(r1); 874 return 1; 875 } 876 break; 877 case AMOVW: 878 if(p1->from.type == D_REG) 879 if((r2 = findinc(r1, r, &p1->from)) != R) { 880 for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3)) 881 ; 882 if(r3 == r) { 883 /* post-indexing */ 884 p1 = r2->prog; 885 a->reg = p1->to.reg; 886 a->offset = p1->from.offset; 887 p->scond |= C_PBIT; 888 if(!finduse(r, &r1->prog->to)) 889 excise(r1); 890 excise(r2); 891 return 1; 892 } 893 } 894 break; 895 } 896 } 897 if(a != &p->from || a->reg != p->to.reg) 898 if((r1 = findinc(r, R, &v)) != R) { 899 /* post-indexing */ 900 p1 = r1->prog; 901 a->offset = p1->from.offset; 902 p->scond |= C_PBIT; 903 excise(r1); 904 return 1; 905 } 906 return 0; 907 } 908 909 /* 910 * return 911 * 1 if v only used (and substitute), 912 * 2 if read-alter-rewrite 913 * 3 if set 914 * 4 if set and used 915 * 0 otherwise (not touched) 916 */ 917 int 918 copyu(Prog *p, Addr *v, Addr *s) 919 { 920 921 switch(p->as) { 922 923 default: 924 if(debug['P']) 925 print(" (?)"); 926 return 2; 927 928 case AMOVM: 929 if(v->type != D_REG) 930 return 0; 931 if(p->from.type == D_CONST) { /* read reglist, read/rar */ 932 if(s != A) { 933 if(p->from.offset&(1<<v->reg)) 934 return 1; 935 if(copysub(&p->to, v, s, 1)) 936 return 1; 937 return 0; 938 } 939 if(copyau(&p->to, v)) { 940 if(p->scond&C_WBIT) 941 return 2; 942 return 1; 943 } 944 if(p->from.offset&(1<<v->reg)) 945 return 1; 946 } else { /* read/rar, write reglist */ 947 if(s != A) { 948 if(p->to.offset&(1<<v->reg)) 949 return 1; 950 if(copysub(&p->from, v, s, 1)) 951 return 1; 952 return 0; 953 } 954 if(copyau(&p->from, v)) { 955 if(p->scond&C_WBIT) 956 return 2; 957 if(p->to.offset&(1<<v->reg)) 958 return 4; 959 return 1; 960 } 961 if(p->to.offset&(1<<v->reg)) 962 return 3; 963 } 964 return 0; 965 966 case ANOP: /* read, write */ 967 case AMOVW: 968 case AMOVF: 969 case AMOVD: 970 case AMOVH: 971 case AMOVHS: 972 case AMOVHU: 973 case AMOVB: 974 case AMOVBS: 975 case AMOVBU: 976 case AMOVDW: 977 case AMOVWD: 978 case AMOVFD: 979 case AMOVDF: 980 if(p->scond&(C_WBIT|C_PBIT)) 981 if(v->type == D_REG) { 982 if(p->from.type == D_OREG || p->from.type == D_SHIFT) { 983 if(p->from.reg == v->reg) 984 return 2; 985 } else { 986 if(p->to.reg == v->reg) 987 return 2; 988 } 989 } 990 if(s != A) { 991 if(copysub(&p->from, v, s, 1)) 992 return 1; 993 if(!copyas(&p->to, v)) 994 if(copysub(&p->to, v, s, 1)) 995 return 1; 996 return 0; 997 } 998 if(copyas(&p->to, v)) { 999 if(copyau(&p->from, v)) 1000 return 4; 1001 return 3; 1002 } 1003 if(copyau(&p->from, v)) 1004 return 1; 1005 if(copyau(&p->to, v)) 1006 return 1; 1007 return 0; 1008 1009 1010 case AADD: /* read, read, write */ 1011 case ASUB: 1012 case ARSB: 1013 case ASLL: 1014 case ASRL: 1015 case ASRA: 1016 case AORR: 1017 case AAND: 1018 case AEOR: 1019 case AMUL: 1020 case ADIV: 1021 case ADIVU: 1022 case AADDF: 1023 case AADDD: 1024 case ASUBF: 1025 case ASUBD: 1026 case AMULF: 1027 case AMULD: 1028 case ADIVF: 1029 case ADIVD: 1030 1031 case ACMPF: 1032 case ACMPD: 1033 case ACMP: 1034 case ACMN: 1035 case ACASE: 1036 if(s != A) { 1037 if(copysub(&p->from, v, s, 1)) 1038 return 1; 1039 if(copysub1(p, v, s, 1)) 1040 return 1; 1041 if(!copyas(&p->to, v)) 1042 if(copysub(&p->to, v, s, 1)) 1043 return 1; 1044 return 0; 1045 } 1046 if(copyas(&p->to, v)) { 1047 if(p->reg == NREG) 1048 p->reg = p->to.reg; 1049 if(copyau(&p->from, v)) 1050 return 4; 1051 if(copyau1(p, v)) 1052 return 4; 1053 return 3; 1054 } 1055 if(copyau(&p->from, v)) 1056 return 1; 1057 if(copyau1(p, v)) 1058 return 1; 1059 if(copyau(&p->to, v)) 1060 return 1; 1061 return 0; 1062 1063 case ABEQ: /* read, read */ 1064 case ABNE: 1065 case ABCS: 1066 case ABHS: 1067 case ABCC: 1068 case ABLO: 1069 case ABMI: 1070 case ABPL: 1071 case ABVS: 1072 case ABVC: 1073 case ABHI: 1074 case ABLS: 1075 case ABGE: 1076 case ABLT: 1077 case ABGT: 1078 case ABLE: 1079 case APLD: 1080 if(s != A) { 1081 if(copysub(&p->from, v, s, 1)) 1082 return 1; 1083 return copysub1(p, v, s, 1); 1084 } 1085 if(copyau(&p->from, v)) 1086 return 1; 1087 if(copyau1(p, v)) 1088 return 1; 1089 return 0; 1090 1091 case AB: /* funny */ 1092 if(s != A) { 1093 if(copysub(&p->to, v, s, 1)) 1094 return 1; 1095 return 0; 1096 } 1097 if(copyau(&p->to, v)) 1098 return 1; 1099 return 0; 1100 1101 case ARET: /* funny */ 1102 if(v->type == D_REG) 1103 if(v->reg == REGRET) 1104 return 2; 1105 if(v->type == D_FREG) 1106 if(v->reg == FREGRET) 1107 return 2; 1108 1109 case ABL: /* funny */ 1110 if(v->type == D_REG) { 1111 if(v->reg <= REGEXT && v->reg > exregoffset) 1112 return 2; 1113 if(v->reg == REGARG) 1114 return 2; 1115 } 1116 if(v->type == D_FREG) 1117 if(v->reg <= FREGEXT && v->reg > exfregoffset) 1118 return 2; 1119 1120 if(s != A) { 1121 if(copysub(&p->to, v, s, 1)) 1122 return 1; 1123 return 0; 1124 } 1125 if(copyau(&p->to, v)) 1126 return 4; 1127 return 3; 1128 1129 case ATEXT: /* funny */ 1130 if(v->type == D_REG) 1131 if(v->reg == REGARG) 1132 return 3; 1133 return 0; 1134 } 1135 } 1136 1137 int 1138 a2type(Prog *p) 1139 { 1140 1141 switch(p->as) { 1142 1143 case ACMP: 1144 case ACMN: 1145 1146 case AADD: 1147 case ASUB: 1148 case ARSB: 1149 case ASLL: 1150 case ASRL: 1151 case ASRA: 1152 case AORR: 1153 case AAND: 1154 case AEOR: 1155 case AMUL: 1156 case ADIV: 1157 case ADIVU: 1158 return D_REG; 1159 1160 case ACMPF: 1161 case ACMPD: 1162 1163 case AADDF: 1164 case AADDD: 1165 case ASUBF: 1166 case ASUBD: 1167 case AMULF: 1168 case AMULD: 1169 case ADIVF: 1170 case ADIVD: 1171 return D_FREG; 1172 } 1173 return D_NONE; 1174 } 1175 1176 /* 1177 * direct reference, 1178 * could be set/use depending on 1179 * semantics 1180 */ 1181 int 1182 copyas(Addr *a, Addr *v) 1183 { 1184 1185 if(regtyp(v)) { 1186 if(a->type == v->type) 1187 if(a->reg == v->reg) 1188 return 1; 1189 } else if(v->type == D_CONST) { /* for constprop */ 1190 if(a->type == v->type) 1191 if(a->name == v->name) 1192 if(a->sym == v->sym) 1193 if(a->reg == v->reg) 1194 if(a->offset == v->offset) 1195 return 1; 1196 } 1197 return 0; 1198 } 1199 1200 /* 1201 * either direct or indirect 1202 */ 1203 int 1204 copyau(Addr *a, Addr *v) 1205 { 1206 1207 if(copyas(a, v)) 1208 return 1; 1209 if(v->type == D_REG) { 1210 if(a->type == D_OREG) { 1211 if(v->reg == a->reg) 1212 return 1; 1213 } else if(a->type == D_SHIFT) { 1214 if((a->offset&0xf) == v->reg) 1215 return 1; 1216 if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) 1217 return 1; 1218 } 1219 } 1220 return 0; 1221 } 1222 1223 int 1224 copyau1(Prog *p, Addr *v) 1225 { 1226 1227 if(regtyp(v)) { 1228 if(a2type(p) == v->type) 1229 if(p->reg == v->reg) { 1230 if(a2type(p) != v->type) 1231 print("botch a2type %P\n", p); 1232 return 1; 1233 } 1234 } 1235 return 0; 1236 } 1237 1238 /* 1239 * substitute s for v in a 1240 * return failure to substitute 1241 */ 1242 int 1243 copysub(Addr *a, Addr *v, Addr *s, int f) 1244 { 1245 1246 if(f) 1247 if(copyau(a, v)) { 1248 if(a->type == D_SHIFT) { 1249 if((a->offset&0xf) == v->reg) 1250 a->offset = (a->offset&~0xf)|s->reg; 1251 if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) 1252 a->offset = (a->offset&~(0xf<<8))|(s->reg<<8); 1253 } else 1254 a->reg = s->reg; 1255 } 1256 return 0; 1257 } 1258 1259 int 1260 copysub1(Prog *p1, Addr *v, Addr *s, int f) 1261 { 1262 1263 if(f) 1264 if(copyau1(p1, v)) 1265 p1->reg = s->reg; 1266 return 0; 1267 } 1268 1269 struct { 1270 int opcode; 1271 int notopcode; 1272 int scond; 1273 int notscond; 1274 } predinfo[] = { 1275 { ABEQ, ABNE, 0x0, 0x1, }, 1276 { ABNE, ABEQ, 0x1, 0x0, }, 1277 { ABCS, ABCC, 0x2, 0x3, }, 1278 { ABHS, ABLO, 0x2, 0x3, }, 1279 { ABCC, ABCS, 0x3, 0x2, }, 1280 { ABLO, ABHS, 0x3, 0x2, }, 1281 { ABMI, ABPL, 0x4, 0x5, }, 1282 { ABPL, ABMI, 0x5, 0x4, }, 1283 { ABVS, ABVC, 0x6, 0x7, }, 1284 { ABVC, ABVS, 0x7, 0x6, }, 1285 { ABHI, ABLS, 0x8, 0x9, }, 1286 { ABLS, ABHI, 0x9, 0x8, }, 1287 { ABGE, ABLT, 0xA, 0xB, }, 1288 { ABLT, ABGE, 0xB, 0xA, }, 1289 { ABGT, ABLE, 0xC, 0xD, }, 1290 { ABLE, ABGT, 0xD, 0xC, }, 1291 }; 1292 1293 typedef struct { 1294 Reg *start; 1295 Reg *last; 1296 Reg *end; 1297 int len; 1298 } Joininfo; 1299 1300 enum { 1301 Join, 1302 Split, 1303 End, 1304 Branch, 1305 Setcond, 1306 Toolong 1307 }; 1308 1309 enum { 1310 Falsecond, 1311 Truecond, 1312 Delbranch, 1313 Keepbranch 1314 }; 1315 1316 int 1317 isbranch(Prog *p) 1318 { 1319 return (ABEQ <= p->as) && (p->as <= ABLE); 1320 } 1321 1322 int 1323 predicable(Prog *p) 1324 { 1325 if (isbranch(p) 1326 || p->as == ANOP 1327 || p->as == AXXX 1328 || p->as == ADATA 1329 || p->as == AGLOBL 1330 || p->as == AGOK 1331 || p->as == AHISTORY 1332 || p->as == ANAME 1333 || p->as == ASIGNAME 1334 || p->as == ATEXT 1335 || p->as == AWORD 1336 || p->as == ABCASE 1337 || p->as == ACASE) 1338 return 0; 1339 return 1; 1340 } 1341 1342 /* 1343 * Depends on an analysis of the encodings performed by 5l. 1344 * These seem to be all of the opcodes that lead to the "S" bit 1345 * being set in the instruction encodings. 1346 * 1347 * C_SBIT may also have been set explicitly in p->scond. 1348 */ 1349 int 1350 modifiescpsr(Prog *p) 1351 { 1352 return (p->scond&C_SBIT) 1353 || p->as == ATST 1354 || p->as == ATEQ 1355 || p->as == ACMN 1356 || p->as == ACMP 1357 || p->as == AMULU 1358 || p->as == ADIVU 1359 || p->as == AMUL 1360 || p->as == ADIV 1361 || p->as == AMOD 1362 || p->as == AMODU 1363 || p->as == ABL; 1364 } 1365 1366 /* 1367 * Find the maximal chain of instructions starting with r which could 1368 * be executed conditionally 1369 */ 1370 int 1371 joinsplit(Reg *r, Joininfo *j) 1372 { 1373 j->start = r; 1374 j->last = r; 1375 j->len = 0; 1376 do { 1377 if (r->p2 && (r->p1 || r->p2->p2link)) { 1378 j->end = r; 1379 return Join; 1380 } 1381 if (r->s1 && r->s2) { 1382 j->end = r; 1383 return Split; 1384 } 1385 j->last = r; 1386 if (r->prog->as != ANOP) 1387 j->len++; 1388 if (!r->s1 && !r->s2) { 1389 j->end = r->link; 1390 return End; 1391 } 1392 if (r->s2) { 1393 j->end = r->s2; 1394 return Branch; 1395 } 1396 if (modifiescpsr(r->prog)) { 1397 j->end = r->s1; 1398 return Setcond; 1399 } 1400 r = r->s1; 1401 } while (j->len < 4); 1402 j->end = r; 1403 return Toolong; 1404 } 1405 1406 Reg * 1407 successor(Reg *r) 1408 { 1409 if (r->s1) 1410 return r->s1; 1411 else 1412 return r->s2; 1413 } 1414 1415 void 1416 applypred(Reg *rstart, Joininfo *j, int cond, int branch) 1417 { 1418 int pred; 1419 Reg *r; 1420 1421 if(j->len == 0) 1422 return; 1423 if (cond == Truecond) 1424 pred = predinfo[rstart->prog->as - ABEQ].scond; 1425 else 1426 pred = predinfo[rstart->prog->as - ABEQ].notscond; 1427 1428 for (r = j->start; ; r = successor(r)) { 1429 if (r->prog->as == AB) { 1430 if (r != j->last || branch == Delbranch) 1431 excise(r); 1432 else { 1433 if (cond == Truecond) 1434 r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode; 1435 else 1436 r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode; 1437 } 1438 } 1439 else if (predicable(r->prog)) 1440 r->prog->scond = (r->prog->scond&~C_SCOND)|pred; 1441 if (r->s1 != r->link) { 1442 r->s1 = r->link; 1443 r->link->p1 = r; 1444 } 1445 if (r == j->last) 1446 break; 1447 } 1448 } 1449 1450 void 1451 predicate(void) 1452 { 1453 Reg *r; 1454 int t1, t2; 1455 Joininfo j1, j2; 1456 1457 for(r=firstr; r!=R; r=r->link) { 1458 if (isbranch(r->prog)) { 1459 t1 = joinsplit(r->s1, &j1); 1460 t2 = joinsplit(r->s2, &j2); 1461 if(j1.last->link != j2.start) 1462 continue; 1463 if(j1.end == j2.end) 1464 if((t1 == Branch && (t2 == Join || t2 == Setcond)) || 1465 (t2 == Join && (t1 == Join || t1 == Setcond))) { 1466 applypred(r, &j1, Falsecond, Delbranch); 1467 applypred(r, &j2, Truecond, Delbranch); 1468 excise(r); 1469 continue; 1470 } 1471 if(t1 == End || t1 == Branch) { 1472 applypred(r, &j1, Falsecond, Keepbranch); 1473 excise(r); 1474 continue; 1475 } 1476 } 1477 } 1478 }