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