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