github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 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(Adr *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 Adr *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 Adr *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(Adr *v1, Adr *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(Adr *c1, Adr *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 Adr 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, Adr *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, Adr *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 Adr 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, Adr *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, Adr *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, Adr *a) 824 { 825 Reg *r1, *r2, *r3; 826 Prog *p, *p1; 827 Adr 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 a->type = D_SHIFT; 857 a->offset = p1->from.reg; 858 break; 859 case D_SHIFT: 860 /* scaled register offset */ 861 a->type = D_SHIFT; 862 case D_CONST: 863 /* immediate offset */ 864 a->offset = p1->from.offset; 865 break; 866 } 867 if(p1->reg != NREG) 868 a->reg = p1->reg; 869 excise(r1); 870 return 1; 871 } 872 break; 873 case AMOVW: 874 if(p1->from.type == D_REG) 875 if((r2 = findinc(r1, r, &p1->from)) != R) { 876 for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3)) 877 ; 878 if(r3 == r) { 879 /* post-indexing */ 880 p1 = r2->prog; 881 a->reg = p1->to.reg; 882 a->offset = p1->from.offset; 883 p->scond |= C_PBIT; 884 if(!finduse(r, &r1->prog->to)) 885 excise(r1); 886 excise(r2); 887 return 1; 888 } 889 } 890 break; 891 } 892 } 893 if(a != &p->from || a->reg != p->to.reg) 894 if((r1 = findinc(r, R, &v)) != R) { 895 /* post-indexing */ 896 p1 = r1->prog; 897 a->offset = p1->from.offset; 898 p->scond |= C_PBIT; 899 excise(r1); 900 return 1; 901 } 902 return 0; 903 } 904 905 /* 906 * return 907 * 1 if v only used (and substitute), 908 * 2 if read-alter-rewrite 909 * 3 if set 910 * 4 if set and used 911 * 0 otherwise (not touched) 912 */ 913 int 914 copyu(Prog *p, Adr *v, Adr *s) 915 { 916 917 switch(p->as) { 918 919 default: 920 if(debug['P']) 921 print(" (?)"); 922 return 2; 923 924 case AMOVM: 925 if(v->type != D_REG) 926 return 0; 927 if(p->from.type == D_CONST) { /* read reglist, read/rar */ 928 if(s != A) { 929 if(p->from.offset&(1<<v->reg)) 930 return 1; 931 if(copysub(&p->to, v, s, 1)) 932 return 1; 933 return 0; 934 } 935 if(copyau(&p->to, v)) { 936 if(p->scond&C_WBIT) 937 return 2; 938 return 1; 939 } 940 if(p->from.offset&(1<<v->reg)) 941 return 1; 942 } else { /* read/rar, write reglist */ 943 if(s != A) { 944 if(p->to.offset&(1<<v->reg)) 945 return 1; 946 if(copysub(&p->from, v, s, 1)) 947 return 1; 948 return 0; 949 } 950 if(copyau(&p->from, v)) { 951 if(p->scond&C_WBIT) 952 return 2; 953 if(p->to.offset&(1<<v->reg)) 954 return 4; 955 return 1; 956 } 957 if(p->to.offset&(1<<v->reg)) 958 return 3; 959 } 960 return 0; 961 962 case ANOP: /* read, write */ 963 case AMOVW: 964 case AMOVF: 965 case AMOVD: 966 case AMOVH: 967 case AMOVHS: 968 case AMOVHU: 969 case AMOVB: 970 case AMOVBS: 971 case AMOVBU: 972 case AMOVDW: 973 case AMOVWD: 974 case AMOVFD: 975 case AMOVDF: 976 if(p->scond&(C_WBIT|C_PBIT)) 977 if(v->type == D_REG) { 978 if(p->from.type == D_OREG || p->from.type == D_SHIFT) { 979 if(p->from.reg == v->reg) 980 return 2; 981 } else { 982 if(p->to.reg == v->reg) 983 return 2; 984 } 985 } 986 if(s != A) { 987 if(copysub(&p->from, v, s, 1)) 988 return 1; 989 if(!copyas(&p->to, v)) 990 if(copysub(&p->to, v, s, 1)) 991 return 1; 992 return 0; 993 } 994 if(copyas(&p->to, v)) { 995 if(copyau(&p->from, v)) 996 return 4; 997 return 3; 998 } 999 if(copyau(&p->from, v)) 1000 return 1; 1001 if(copyau(&p->to, v)) 1002 return 1; 1003 return 0; 1004 1005 1006 case AADD: /* read, read, write */ 1007 case ASUB: 1008 case ARSB: 1009 case ASLL: 1010 case ASRL: 1011 case ASRA: 1012 case AORR: 1013 case AAND: 1014 case AEOR: 1015 case AMUL: 1016 case ADIV: 1017 case ADIVU: 1018 case AADDF: 1019 case AADDD: 1020 case ASUBF: 1021 case ASUBD: 1022 case AMULF: 1023 case AMULD: 1024 case ADIVF: 1025 case ADIVD: 1026 1027 case ACMPF: 1028 case ACMPD: 1029 case ACMP: 1030 case ACMN: 1031 case ACASE: 1032 if(s != A) { 1033 if(copysub(&p->from, v, s, 1)) 1034 return 1; 1035 if(copysub1(p, v, s, 1)) 1036 return 1; 1037 if(!copyas(&p->to, v)) 1038 if(copysub(&p->to, v, s, 1)) 1039 return 1; 1040 return 0; 1041 } 1042 if(copyas(&p->to, v)) { 1043 if(p->reg == NREG) 1044 p->reg = p->to.reg; 1045 if(copyau(&p->from, v)) 1046 return 4; 1047 if(copyau1(p, v)) 1048 return 4; 1049 return 3; 1050 } 1051 if(copyau(&p->from, v)) 1052 return 1; 1053 if(copyau1(p, v)) 1054 return 1; 1055 if(copyau(&p->to, v)) 1056 return 1; 1057 return 0; 1058 1059 case ABEQ: /* read, read */ 1060 case ABNE: 1061 case ABCS: 1062 case ABHS: 1063 case ABCC: 1064 case ABLO: 1065 case ABMI: 1066 case ABPL: 1067 case ABVS: 1068 case ABVC: 1069 case ABHI: 1070 case ABLS: 1071 case ABGE: 1072 case ABLT: 1073 case ABGT: 1074 case ABLE: 1075 case APLD: 1076 if(s != A) { 1077 if(copysub(&p->from, v, s, 1)) 1078 return 1; 1079 return copysub1(p, v, s, 1); 1080 } 1081 if(copyau(&p->from, v)) 1082 return 1; 1083 if(copyau1(p, v)) 1084 return 1; 1085 return 0; 1086 1087 case AB: /* funny */ 1088 if(s != A) { 1089 if(copysub(&p->to, v, s, 1)) 1090 return 1; 1091 return 0; 1092 } 1093 if(copyau(&p->to, v)) 1094 return 1; 1095 return 0; 1096 1097 case ARET: /* funny */ 1098 if(v->type == D_REG) 1099 if(v->reg == REGRET) 1100 return 2; 1101 if(v->type == D_FREG) 1102 if(v->reg == FREGRET) 1103 return 2; 1104 1105 case ABL: /* funny */ 1106 if(v->type == D_REG) { 1107 if(v->reg <= REGEXT && v->reg > exregoffset) 1108 return 2; 1109 if(v->reg == (uchar)REGARG) 1110 return 2; 1111 } 1112 if(v->type == D_FREG) 1113 if(v->reg <= FREGEXT && v->reg > exfregoffset) 1114 return 2; 1115 1116 if(s != A) { 1117 if(copysub(&p->to, v, s, 1)) 1118 return 1; 1119 return 0; 1120 } 1121 if(copyau(&p->to, v)) 1122 return 4; 1123 return 3; 1124 1125 case ATEXT: /* funny */ 1126 if(v->type == D_REG) 1127 if(v->reg == (uchar)REGARG) 1128 return 3; 1129 return 0; 1130 } 1131 } 1132 1133 int 1134 a2type(Prog *p) 1135 { 1136 1137 switch(p->as) { 1138 1139 case ACMP: 1140 case ACMN: 1141 1142 case AADD: 1143 case ASUB: 1144 case ARSB: 1145 case ASLL: 1146 case ASRL: 1147 case ASRA: 1148 case AORR: 1149 case AAND: 1150 case AEOR: 1151 case AMUL: 1152 case ADIV: 1153 case ADIVU: 1154 return D_REG; 1155 1156 case ACMPF: 1157 case ACMPD: 1158 1159 case AADDF: 1160 case AADDD: 1161 case ASUBF: 1162 case ASUBD: 1163 case AMULF: 1164 case AMULD: 1165 case ADIVF: 1166 case ADIVD: 1167 return D_FREG; 1168 } 1169 return D_NONE; 1170 } 1171 1172 /* 1173 * direct reference, 1174 * could be set/use depending on 1175 * semantics 1176 */ 1177 int 1178 copyas(Adr *a, Adr *v) 1179 { 1180 1181 if(regtyp(v)) { 1182 if(a->type == v->type) 1183 if(a->reg == v->reg) 1184 return 1; 1185 } else if(v->type == D_CONST) { /* for constprop */ 1186 if(a->type == v->type) 1187 if(a->name == v->name) 1188 if(a->sym == v->sym) 1189 if(a->reg == v->reg) 1190 if(a->offset == v->offset) 1191 return 1; 1192 } 1193 return 0; 1194 } 1195 1196 /* 1197 * either direct or indirect 1198 */ 1199 int 1200 copyau(Adr *a, Adr *v) 1201 { 1202 1203 if(copyas(a, v)) 1204 return 1; 1205 if(v->type == D_REG) { 1206 if(a->type == D_OREG) { 1207 if(v->reg == a->reg) 1208 return 1; 1209 } else if(a->type == D_SHIFT) { 1210 if((a->offset&0xf) == v->reg) 1211 return 1; 1212 if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) 1213 return 1; 1214 } 1215 } 1216 return 0; 1217 } 1218 1219 int 1220 copyau1(Prog *p, Adr *v) 1221 { 1222 1223 if(regtyp(v)) { 1224 if(a2type(p) == v->type) 1225 if(p->reg == v->reg) { 1226 if(a2type(p) != v->type) 1227 print("botch a2type %P\n", p); 1228 return 1; 1229 } 1230 } 1231 return 0; 1232 } 1233 1234 /* 1235 * substitute s for v in a 1236 * return failure to substitute 1237 */ 1238 int 1239 copysub(Adr *a, Adr *v, Adr *s, int f) 1240 { 1241 1242 if(f) 1243 if(copyau(a, v)) { 1244 if(a->type == D_SHIFT) { 1245 if((a->offset&0xf) == v->reg) 1246 a->offset = (a->offset&~0xf)|s->reg; 1247 if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) 1248 a->offset = (a->offset&~(0xf<<8))|(s->reg<<8); 1249 } else 1250 a->reg = s->reg; 1251 } 1252 return 0; 1253 } 1254 1255 int 1256 copysub1(Prog *p1, Adr *v, Adr *s, int f) 1257 { 1258 1259 if(f) 1260 if(copyau1(p1, v)) 1261 p1->reg = s->reg; 1262 return 0; 1263 } 1264 1265 struct { 1266 int opcode; 1267 int notopcode; 1268 int scond; 1269 int notscond; 1270 } predinfo[] = { 1271 { ABEQ, ABNE, 0x0, 0x1, }, 1272 { ABNE, ABEQ, 0x1, 0x0, }, 1273 { ABCS, ABCC, 0x2, 0x3, }, 1274 { ABHS, ABLO, 0x2, 0x3, }, 1275 { ABCC, ABCS, 0x3, 0x2, }, 1276 { ABLO, ABHS, 0x3, 0x2, }, 1277 { ABMI, ABPL, 0x4, 0x5, }, 1278 { ABPL, ABMI, 0x5, 0x4, }, 1279 { ABVS, ABVC, 0x6, 0x7, }, 1280 { ABVC, ABVS, 0x7, 0x6, }, 1281 { ABHI, ABLS, 0x8, 0x9, }, 1282 { ABLS, ABHI, 0x9, 0x8, }, 1283 { ABGE, ABLT, 0xA, 0xB, }, 1284 { ABLT, ABGE, 0xB, 0xA, }, 1285 { ABGT, ABLE, 0xC, 0xD, }, 1286 { ABLE, ABGT, 0xD, 0xC, }, 1287 }; 1288 1289 typedef struct { 1290 Reg *start; 1291 Reg *last; 1292 Reg *end; 1293 int len; 1294 } Joininfo; 1295 1296 enum { 1297 Join, 1298 Split, 1299 End, 1300 Branch, 1301 Setcond, 1302 Toolong 1303 }; 1304 1305 enum { 1306 Falsecond, 1307 Truecond, 1308 Delbranch, 1309 Keepbranch 1310 }; 1311 1312 int 1313 isbranch(Prog *p) 1314 { 1315 return (ABEQ <= p->as) && (p->as <= ABLE); 1316 } 1317 1318 int 1319 predicable(Prog *p) 1320 { 1321 if (isbranch(p) 1322 || p->as == ANOP 1323 || p->as == AXXX 1324 || p->as == ADATA 1325 || p->as == AGLOBL 1326 || p->as == AGOK 1327 || p->as == AHISTORY 1328 || p->as == ANAME 1329 || p->as == ASIGNAME 1330 || p->as == ATEXT 1331 || p->as == AWORD 1332 || p->as == ABCASE 1333 || p->as == ACASE) 1334 return 0; 1335 return 1; 1336 } 1337 1338 /* 1339 * Depends on an analysis of the encodings performed by 5l. 1340 * These seem to be all of the opcodes that lead to the "S" bit 1341 * being set in the instruction encodings. 1342 * 1343 * C_SBIT may also have been set explicitly in p->scond. 1344 */ 1345 int 1346 modifiescpsr(Prog *p) 1347 { 1348 return (p->scond&C_SBIT) 1349 || p->as == ATST 1350 || p->as == ATEQ 1351 || p->as == ACMN 1352 || p->as == ACMP 1353 || p->as == AMULU 1354 || p->as == ADIVU 1355 || p->as == AMUL 1356 || p->as == ADIV 1357 || p->as == AMOD 1358 || p->as == AMODU 1359 || p->as == ABL; 1360 } 1361 1362 /* 1363 * Find the maximal chain of instructions starting with r which could 1364 * be executed conditionally 1365 */ 1366 int 1367 joinsplit(Reg *r, Joininfo *j) 1368 { 1369 j->start = r; 1370 j->last = r; 1371 j->len = 0; 1372 do { 1373 if (r->p2 && (r->p1 || r->p2->p2link)) { 1374 j->end = r; 1375 return Join; 1376 } 1377 if (r->s1 && r->s2) { 1378 j->end = r; 1379 return Split; 1380 } 1381 j->last = r; 1382 if (r->prog->as != ANOP) 1383 j->len++; 1384 if (!r->s1 && !r->s2) { 1385 j->end = r->link; 1386 return End; 1387 } 1388 if (r->s2) { 1389 j->end = r->s2; 1390 return Branch; 1391 } 1392 if (modifiescpsr(r->prog)) { 1393 j->end = r->s1; 1394 return Setcond; 1395 } 1396 r = r->s1; 1397 } while (j->len < 4); 1398 j->end = r; 1399 return Toolong; 1400 } 1401 1402 Reg * 1403 successor(Reg *r) 1404 { 1405 if (r->s1) 1406 return r->s1; 1407 else 1408 return r->s2; 1409 } 1410 1411 void 1412 applypred(Reg *rstart, Joininfo *j, int cond, int branch) 1413 { 1414 int pred; 1415 Reg *r; 1416 1417 if(j->len == 0) 1418 return; 1419 if (cond == Truecond) 1420 pred = predinfo[rstart->prog->as - ABEQ].scond; 1421 else 1422 pred = predinfo[rstart->prog->as - ABEQ].notscond; 1423 1424 for (r = j->start; ; r = successor(r)) { 1425 if (r->prog->as == AB) { 1426 if (r != j->last || branch == Delbranch) 1427 excise(r); 1428 else { 1429 if (cond == Truecond) 1430 r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode; 1431 else 1432 r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode; 1433 } 1434 } 1435 else if (predicable(r->prog)) 1436 r->prog->scond = (r->prog->scond&~C_SCOND)|pred; 1437 if (r->s1 != r->link) { 1438 r->s1 = r->link; 1439 r->link->p1 = r; 1440 } 1441 if (r == j->last) 1442 break; 1443 } 1444 } 1445 1446 void 1447 predicate(void) 1448 { 1449 Reg *r; 1450 int t1, t2; 1451 Joininfo j1, j2; 1452 1453 for(r=firstr; r!=R; r=r->link) { 1454 if (isbranch(r->prog)) { 1455 t1 = joinsplit(r->s1, &j1); 1456 t2 = joinsplit(r->s2, &j2); 1457 if(j1.last->link != j2.start) 1458 continue; 1459 if(j1.end == j2.end) 1460 if((t1 == Branch && (t2 == Join || t2 == Setcond)) || 1461 (t2 == Join && (t1 == Join || t1 == Setcond))) { 1462 applypred(r, &j1, Falsecond, Delbranch); 1463 applypred(r, &j2, Truecond, Delbranch); 1464 excise(r); 1465 continue; 1466 } 1467 if(t1 == End || t1 == Branch) { 1468 applypred(r, &j1, Falsecond, Keepbranch); 1469 excise(r); 1470 continue; 1471 } 1472 } 1473 } 1474 }