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