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