github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/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 /*c2go void FAIL(char*); */ 568 569 int 570 shiftprop(Flow *r) 571 { 572 Flow *r1; 573 Prog *p, *p1, *p2; 574 int n, o; 575 Adr a; 576 577 p = r->prog; 578 if(p->to.type != D_REG) 579 FAIL("BOTCH: result not reg"); 580 n = p->to.reg; 581 a = zprog.from; 582 if(p->reg != NREG && p->reg != p->to.reg) { 583 a.type = D_REG; 584 a.reg = p->reg; 585 } 586 if(debug['P']) 587 print("shiftprop\n%P", p); 588 r1 = r; 589 for(;;) { 590 /* find first use of shift result; abort if shift operands or result are changed */ 591 r1 = uniqs(r1); 592 if(r1 == nil) 593 FAIL("branch"); 594 if(uniqp(r1) == nil) 595 FAIL("merge"); 596 p1 = r1->prog; 597 if(debug['P']) 598 print("\n%P", p1); 599 switch(copyu(p1, &p->to, nil)) { 600 case 0: /* not used or set */ 601 if((p->from.type == D_REG && copyu(p1, &p->from, nil) > 1) || 602 (a.type == D_REG && copyu(p1, &a, nil) > 1)) 603 FAIL("args modified"); 604 continue; 605 case 3: /* set, not used */ 606 FAIL("BOTCH: noref"); 607 } 608 break; 609 } 610 /* check whether substitution can be done */ 611 switch(p1->as) { 612 default: 613 FAIL("non-dpi"); 614 case AAND: 615 case AEOR: 616 case AADD: 617 case AADC: 618 case AORR: 619 case ASUB: 620 case ASBC: 621 case ARSB: 622 case ARSC: 623 if(p1->reg == n || (p1->reg == NREG && p1->to.type == D_REG && p1->to.reg == n)) { 624 if(p1->from.type != D_REG) 625 FAIL("can't swap"); 626 p1->reg = p1->from.reg; 627 p1->from.reg = n; 628 switch(p1->as) { 629 case ASUB: 630 p1->as = ARSB; 631 break; 632 case ARSB: 633 p1->as = ASUB; 634 break; 635 case ASBC: 636 p1->as = ARSC; 637 break; 638 case ARSC: 639 p1->as = ASBC; 640 break; 641 } 642 if(debug['P']) 643 print("\t=>%P", p1); 644 } 645 case ABIC: 646 case ATST: 647 case ACMP: 648 case ACMN: 649 if(p1->reg == n) 650 FAIL("can't swap"); 651 if(p1->reg == NREG && p1->to.reg == n) 652 FAIL("shift result used twice"); 653 // case AMVN: 654 if(p1->from.type == D_SHIFT) 655 FAIL("shift result used in shift"); 656 if(p1->from.type != D_REG || p1->from.reg != n) 657 FAIL("BOTCH: where is it used?"); 658 break; 659 } 660 /* check whether shift result is used subsequently */ 661 p2 = p1; 662 if(p1->to.reg != n) 663 for (;;) { 664 r1 = uniqs(r1); 665 if(r1 == nil) 666 FAIL("inconclusive"); 667 p1 = r1->prog; 668 if(debug['P']) 669 print("\n%P", p1); 670 switch(copyu(p1, &p->to, nil)) { 671 case 0: /* not used or set */ 672 continue; 673 case 3: /* set, not used */ 674 break; 675 default:/* used */ 676 FAIL("reused"); 677 } 678 break; 679 } 680 681 /* make the substitution */ 682 p2->from.type = D_SHIFT; 683 p2->from.reg = NREG; 684 o = p->reg; 685 if(o == NREG) 686 o = p->to.reg; 687 688 switch(p->from.type){ 689 case D_CONST: 690 o |= (p->from.offset&0x1f)<<7; 691 break; 692 case D_REG: 693 o |= (1<<4) | (p->from.reg<<8); 694 break; 695 } 696 switch(p->as){ 697 case ASLL: 698 o |= 0<<5; 699 break; 700 case ASRL: 701 o |= 1<<5; 702 break; 703 case ASRA: 704 o |= 2<<5; 705 break; 706 } 707 p2->from.offset = o; 708 if(debug['P']) 709 print("\t=>%P\tSUCCEED\n", p2); 710 return 1; 711 } 712 713 /* 714 * findpre returns the last instruction mentioning v 715 * before r. It must be a set, and there must be 716 * a unique path from that instruction to r. 717 */ 718 static Flow* 719 findpre(Flow *r, Adr *v) 720 { 721 Flow *r1; 722 723 for(r1=uniqp(r); r1!=nil; r=r1,r1=uniqp(r)) { 724 if(uniqs(r1) != r) 725 return nil; 726 switch(copyu(r1->prog, v, nil)) { 727 case 1: /* used */ 728 case 2: /* read-alter-rewrite */ 729 return nil; 730 case 3: /* set */ 731 case 4: /* set and used */ 732 return r1; 733 } 734 } 735 return nil; 736 } 737 738 /* 739 * findinc finds ADD instructions with a constant 740 * argument which falls within the immed_12 range. 741 */ 742 static Flow* 743 findinc(Flow *r, Flow *r2, Adr *v) 744 { 745 Flow *r1; 746 Prog *p; 747 748 749 for(r1=uniqs(r); r1!=nil && r1!=r2; r=r1,r1=uniqs(r)) { 750 if(uniqp(r1) != r) 751 return nil; 752 switch(copyu(r1->prog, v, nil)) { 753 case 0: /* not touched */ 754 continue; 755 case 4: /* set and used */ 756 p = r1->prog; 757 if(p->as == AADD) 758 if(isdconst(&p->from)) 759 if(p->from.offset > -4096 && p->from.offset < 4096) 760 return r1; 761 default: 762 return nil; 763 } 764 } 765 return nil; 766 } 767 768 static int 769 nochange(Flow *r, Flow *r2, Prog *p) 770 { 771 Adr a[3]; 772 int i, n; 773 774 if(r == r2) 775 return 1; 776 n = 0; 777 if(p->reg != NREG && p->reg != p->to.reg) { 778 a[n].type = D_REG; 779 a[n++].reg = p->reg; 780 } 781 switch(p->from.type) { 782 case D_SHIFT: 783 a[n].type = D_REG; 784 a[n++].reg = p->from.offset&0xf; 785 case D_REG: 786 a[n].type = D_REG; 787 a[n++].reg = p->from.reg; 788 } 789 if(n == 0) 790 return 1; 791 for(; r!=nil && r!=r2; r=uniqs(r)) { 792 p = r->prog; 793 for(i=0; i<n; i++) 794 if(copyu(p, &a[i], nil) > 1) 795 return 0; 796 } 797 return 1; 798 } 799 800 static int 801 findu1(Flow *r, Adr *v) 802 { 803 for(; r != nil; r = r->s1) { 804 if(r->active) 805 return 0; 806 r->active = 1; 807 switch(copyu(r->prog, v, nil)) { 808 case 1: /* used */ 809 case 2: /* read-alter-rewrite */ 810 case 4: /* set and used */ 811 return 1; 812 case 3: /* set */ 813 return 0; 814 } 815 if(r->s2) 816 if (findu1(r->s2, v)) 817 return 1; 818 } 819 return 0; 820 } 821 822 static int 823 finduse(Graph *g, Flow *r, Adr *v) 824 { 825 Flow *r1; 826 827 for(r1=g->start; r1!=nil; r1=r1->link) 828 r1->active = 0; 829 return findu1(r, v); 830 } 831 832 /* 833 * xtramodes enables the ARM post increment and 834 * shift offset addressing modes to transform 835 * MOVW 0(R3),R1 836 * ADD $4,R3,R3 837 * into 838 * MOVW.P 4(R3),R1 839 * and 840 * ADD R0,R1 841 * MOVBU 0(R1),R0 842 * into 843 * MOVBU R0<<0(R1),R0 844 */ 845 static int 846 xtramodes(Graph *g, Flow *r, Adr *a) 847 { 848 Flow *r1, *r2, *r3; 849 Prog *p, *p1; 850 Adr v; 851 852 p = r->prog; 853 v = *a; 854 v.type = D_REG; 855 r1 = findpre(r, &v); 856 if(r1 != nil) { 857 p1 = r1->prog; 858 if(p1->to.type == D_REG && p1->to.reg == v.reg) 859 switch(p1->as) { 860 case AADD: 861 if(p1->scond & C_SBIT) 862 // avoid altering ADD.S/ADC sequences. 863 break; 864 if(p1->from.type == D_REG || 865 (p1->from.type == D_SHIFT && (p1->from.offset&(1<<4)) == 0 && 866 ((p->as != AMOVB && p->as != AMOVBS) || (a == &p->from && (p1->from.offset&~0xf) == 0))) || 867 (p1->from.type == D_CONST && 868 p1->from.offset > -4096 && p1->from.offset < 4096)) 869 if(nochange(uniqs(r1), r, p1)) { 870 if(a != &p->from || v.reg != p->to.reg) 871 if (finduse(g, r->s1, &v)) { 872 if(p1->reg == NREG || p1->reg == v.reg) 873 /* pre-indexing */ 874 p->scond |= C_WBIT; 875 else return 0; 876 } 877 switch (p1->from.type) { 878 case D_REG: 879 /* register offset */ 880 if(nacl) 881 return 0; 882 a->type = D_SHIFT; 883 a->offset = p1->from.reg; 884 break; 885 case D_SHIFT: 886 /* scaled register offset */ 887 if(nacl) 888 return 0; 889 a->type = D_SHIFT; 890 case D_CONST: 891 /* immediate offset */ 892 a->offset = p1->from.offset; 893 break; 894 } 895 if(p1->reg != NREG) 896 a->reg = p1->reg; 897 excise(r1); 898 return 1; 899 } 900 break; 901 case AMOVW: 902 if(p1->from.type == D_REG) 903 if((r2 = findinc(r1, r, &p1->from)) != nil) { 904 for(r3=uniqs(r2); r3->prog->as==ANOP; r3=uniqs(r3)) 905 ; 906 if(r3 == r) { 907 /* post-indexing */ 908 p1 = r2->prog; 909 a->reg = p1->to.reg; 910 a->offset = p1->from.offset; 911 p->scond |= C_PBIT; 912 if(!finduse(g, r, &r1->prog->to)) 913 excise(r1); 914 excise(r2); 915 return 1; 916 } 917 } 918 break; 919 } 920 } 921 if(a != &p->from || a->reg != p->to.reg) 922 if((r1 = findinc(r, nil, &v)) != nil) { 923 /* post-indexing */ 924 p1 = r1->prog; 925 a->offset = p1->from.offset; 926 p->scond |= C_PBIT; 927 excise(r1); 928 return 1; 929 } 930 return 0; 931 } 932 933 /* 934 * return 935 * 1 if v only used (and substitute), 936 * 2 if read-alter-rewrite 937 * 3 if set 938 * 4 if set and used 939 * 0 otherwise (not touched) 940 */ 941 int 942 copyu(Prog *p, Adr *v, Adr *s) 943 { 944 switch(p->as) { 945 946 default: 947 print("copyu: can't find %A\n", p->as); 948 return 2; 949 950 case AMOVM: 951 if(v->type != D_REG) 952 return 0; 953 if(p->from.type == D_CONST) { /* read reglist, read/rar */ 954 if(s != nil) { 955 if(p->from.offset&(1<<v->reg)) 956 return 1; 957 if(copysub(&p->to, v, s, 1)) 958 return 1; 959 return 0; 960 } 961 if(copyau(&p->to, v)) { 962 if(p->scond&C_WBIT) 963 return 2; 964 return 1; 965 } 966 if(p->from.offset&(1<<v->reg)) 967 return 1; 968 } else { /* read/rar, write reglist */ 969 if(s != nil) { 970 if(p->to.offset&(1<<v->reg)) 971 return 1; 972 if(copysub(&p->from, v, s, 1)) 973 return 1; 974 return 0; 975 } 976 if(copyau(&p->from, v)) { 977 if(p->scond&C_WBIT) 978 return 2; 979 if(p->to.offset&(1<<v->reg)) 980 return 4; 981 return 1; 982 } 983 if(p->to.offset&(1<<v->reg)) 984 return 3; 985 } 986 return 0; 987 988 case ANOP: /* read,, write */ 989 case AMOVW: 990 case AMOVF: 991 case AMOVD: 992 case AMOVH: 993 case AMOVHS: 994 case AMOVHU: 995 case AMOVB: 996 case AMOVBS: 997 case AMOVBU: 998 case AMOVFW: 999 case AMOVWF: 1000 case AMOVDW: 1001 case AMOVWD: 1002 case AMOVFD: 1003 case AMOVDF: 1004 if(p->scond&(C_WBIT|C_PBIT)) 1005 if(v->type == D_REG) { 1006 if(p->from.type == D_OREG || p->from.type == D_SHIFT) { 1007 if(p->from.reg == v->reg) 1008 return 2; 1009 } else { 1010 if(p->to.reg == v->reg) 1011 return 2; 1012 } 1013 } 1014 if(s != nil) { 1015 if(copysub(&p->from, v, s, 1)) 1016 return 1; 1017 if(!copyas(&p->to, v)) 1018 if(copysub(&p->to, v, s, 1)) 1019 return 1; 1020 return 0; 1021 } 1022 if(copyas(&p->to, v)) { 1023 if(p->scond != C_SCOND_NONE) 1024 return 2; 1025 if(copyau(&p->from, v)) 1026 return 4; 1027 return 3; 1028 } 1029 if(copyau(&p->from, v)) 1030 return 1; 1031 if(copyau(&p->to, v)) 1032 return 1; 1033 return 0; 1034 1035 case AMULLU: /* read, read, write, write */ 1036 case AMULL: 1037 case AMULA: 1038 case AMVN: 1039 return 2; 1040 1041 case AADD: /* read, read, write */ 1042 case AADC: 1043 case ASUB: 1044 case ASBC: 1045 case ARSB: 1046 case ASLL: 1047 case ASRL: 1048 case ASRA: 1049 case AORR: 1050 case AAND: 1051 case AEOR: 1052 case AMUL: 1053 case AMULU: 1054 case ADIV: 1055 case ADIVU: 1056 case AMOD: 1057 case AMODU: 1058 case AADDF: 1059 case AADDD: 1060 case ASUBF: 1061 case ASUBD: 1062 case AMULF: 1063 case AMULD: 1064 case ADIVF: 1065 case ADIVD: 1066 1067 case ACHECKNIL: /* read */ 1068 case ACMPF: /* read, read, */ 1069 case ACMPD: 1070 case ACMP: 1071 case ACMN: 1072 case ACASE: 1073 case ATST: /* read,, */ 1074 if(s != nil) { 1075 if(copysub(&p->from, v, s, 1)) 1076 return 1; 1077 if(copysub1(p, v, s, 1)) 1078 return 1; 1079 if(!copyas(&p->to, v)) 1080 if(copysub(&p->to, v, s, 1)) 1081 return 1; 1082 return 0; 1083 } 1084 if(copyas(&p->to, v)) { 1085 if(p->scond != C_SCOND_NONE) 1086 return 2; 1087 if(p->reg == NREG) 1088 p->reg = p->to.reg; 1089 if(copyau(&p->from, v)) 1090 return 4; 1091 if(copyau1(p, v)) 1092 return 4; 1093 return 3; 1094 } 1095 if(copyau(&p->from, v)) 1096 return 1; 1097 if(copyau1(p, v)) 1098 return 1; 1099 if(copyau(&p->to, v)) 1100 return 1; 1101 return 0; 1102 1103 case ABEQ: /* read, read */ 1104 case ABNE: 1105 case ABCS: 1106 case ABHS: 1107 case ABCC: 1108 case ABLO: 1109 case ABMI: 1110 case ABPL: 1111 case ABVS: 1112 case ABVC: 1113 case ABHI: 1114 case ABLS: 1115 case ABGE: 1116 case ABLT: 1117 case ABGT: 1118 case ABLE: 1119 if(s != nil) { 1120 if(copysub(&p->from, v, s, 1)) 1121 return 1; 1122 return copysub1(p, v, s, 1); 1123 } 1124 if(copyau(&p->from, v)) 1125 return 1; 1126 if(copyau1(p, v)) 1127 return 1; 1128 return 0; 1129 1130 case AB: /* funny */ 1131 if(s != nil) { 1132 if(copysub(&p->to, v, s, 1)) 1133 return 1; 1134 return 0; 1135 } 1136 if(copyau(&p->to, v)) 1137 return 1; 1138 return 0; 1139 1140 case ARET: /* funny */ 1141 if(s != nil) 1142 return 1; 1143 return 3; 1144 1145 case ABL: /* funny */ 1146 if(v->type == D_REG) { 1147 if(v->reg <= REGEXT && v->reg > exregoffset) 1148 return 2; 1149 if(v->reg == REGARG) 1150 return 2; 1151 } 1152 if(v->type == D_FREG) 1153 if(v->reg <= FREGEXT && v->reg > exfregoffset) 1154 return 2; 1155 if(p->from.type == D_REG && v->type == D_REG && p->from.reg == v->reg) 1156 return 2; 1157 1158 if(s != nil) { 1159 if(copysub(&p->to, v, s, 1)) 1160 return 1; 1161 return 0; 1162 } 1163 if(copyau(&p->to, v)) 1164 return 4; 1165 return 3; 1166 case ADUFFZERO: 1167 // R0 is zero, used by DUFFZERO, cannot be substituted. 1168 // R1 is ptr to memory, used and set, cannot be substituted. 1169 if(v->type == D_REG) { 1170 if(v->reg == REGALLOC_R0) 1171 return 1; 1172 if(v->reg == REGALLOC_R0+1) 1173 return 2; 1174 } 1175 return 0; 1176 case ADUFFCOPY: 1177 // R0 is scratch, set by DUFFCOPY, cannot be substituted. 1178 // R1, R2 areptr to src, dst, used and set, cannot be substituted. 1179 if(v->type == D_REG) { 1180 if(v->reg == REGALLOC_R0) 1181 return 3; 1182 if(v->reg == REGALLOC_R0+1 || v->reg == REGALLOC_R0+2) 1183 return 2; 1184 } 1185 return 0; 1186 1187 case ATEXT: /* funny */ 1188 if(v->type == D_REG) 1189 if(v->reg == REGARG) 1190 return 3; 1191 return 0; 1192 1193 case APCDATA: 1194 case AFUNCDATA: 1195 case AVARDEF: 1196 case AVARKILL: 1197 return 0; 1198 } 1199 } 1200 1201 /* 1202 * direct reference, 1203 * could be set/use depending on 1204 * semantics 1205 */ 1206 static int 1207 copyas(Adr *a, Adr *v) 1208 { 1209 1210 if(regtyp(v)) { 1211 if(a->type == v->type) 1212 if(a->reg == v->reg) 1213 return 1; 1214 } else 1215 if(v->type == D_CONST) { /* for constprop */ 1216 if(a->type == v->type) 1217 if(a->name == v->name) 1218 if(a->sym == v->sym) 1219 if(a->reg == v->reg) 1220 if(a->offset == v->offset) 1221 return 1; 1222 } 1223 return 0; 1224 } 1225 1226 int 1227 sameaddr(Adr *a, Adr *v) 1228 { 1229 if(a->type != v->type) 1230 return 0; 1231 if(regtyp(v) && a->reg == v->reg) 1232 return 1; 1233 if(v->type == D_AUTO || v->type == D_PARAM) { 1234 if(v->offset == a->offset) 1235 return 1; 1236 } 1237 return 0; 1238 } 1239 1240 /* 1241 * either direct or indirect 1242 */ 1243 static int 1244 copyau(Adr *a, Adr *v) 1245 { 1246 1247 if(copyas(a, v)) 1248 return 1; 1249 if(v->type == D_REG) { 1250 if(a->type == D_CONST && a->reg != NREG) { 1251 if(a->reg == v->reg) 1252 return 1; 1253 } else 1254 if(a->type == D_OREG) { 1255 if(a->reg == v->reg) 1256 return 1; 1257 } else 1258 if(a->type == D_REGREG || a->type == D_REGREG2) { 1259 if(a->reg == v->reg) 1260 return 1; 1261 if(a->offset == v->reg) 1262 return 1; 1263 } else 1264 if(a->type == D_SHIFT) { 1265 if((a->offset&0xf) == v->reg) 1266 return 1; 1267 if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) 1268 return 1; 1269 } 1270 } 1271 return 0; 1272 } 1273 1274 static int 1275 a2type(Prog *p) 1276 { 1277 if(p->reg == NREG) 1278 return D_NONE; 1279 1280 switch(p->as) { 1281 default: 1282 fatal("a2type: unhandled %P", p); 1283 1284 case AAND: 1285 case AEOR: 1286 case ASUB: 1287 case ARSB: 1288 case AADD: 1289 case AADC: 1290 case ASBC: 1291 case ARSC: 1292 case ATST: 1293 case ATEQ: 1294 case ACMP: 1295 case ACMN: 1296 case AORR: 1297 case ABIC: 1298 case AMVN: 1299 case ASRL: 1300 case ASRA: 1301 case ASLL: 1302 case AMULU: 1303 case ADIVU: 1304 case AMUL: 1305 case ADIV: 1306 case AMOD: 1307 case AMODU: 1308 case AMULA: 1309 case AMULL: 1310 case AMULAL: 1311 case AMULLU: 1312 case AMULALU: 1313 case AMULWT: 1314 case AMULWB: 1315 case AMULAWT: 1316 case AMULAWB: 1317 return D_REG; 1318 1319 case ACMPF: 1320 case ACMPD: 1321 case AADDF: 1322 case AADDD: 1323 case ASUBF: 1324 case ASUBD: 1325 case AMULF: 1326 case AMULD: 1327 case ADIVF: 1328 case ADIVD: 1329 case ASQRTF: 1330 case ASQRTD: 1331 case AABSF: 1332 case AABSD: 1333 return D_FREG; 1334 } 1335 } 1336 1337 /* 1338 * compare v to the center 1339 * register in p (p->reg) 1340 */ 1341 static int 1342 copyau1(Prog *p, Adr *v) 1343 { 1344 if(v->type == D_REG && v->reg == NREG) 1345 return 0; 1346 return p->reg == v->reg && a2type(p) == v->type; 1347 } 1348 1349 /* 1350 * substitute s for v in a 1351 * return failure to substitute 1352 */ 1353 static int 1354 copysub(Adr *a, Adr *v, Adr *s, int f) 1355 { 1356 1357 if(f) 1358 if(copyau(a, v)) { 1359 if(a->type == D_SHIFT) { 1360 if((a->offset&0xf) == v->reg) 1361 a->offset = (a->offset&~0xf)|s->reg; 1362 if((a->offset&(1<<4)) && (a->offset>>8) == v->reg) 1363 a->offset = (a->offset&~(0xf<<8))|(s->reg<<8); 1364 } else 1365 if(a->type == D_REGREG || a->type == D_REGREG2) { 1366 if(a->offset == v->reg) 1367 a->offset = s->reg; 1368 if(a->reg == v->reg) 1369 a->reg = s->reg; 1370 } else 1371 a->reg = s->reg; 1372 } 1373 return 0; 1374 } 1375 1376 static int 1377 copysub1(Prog *p1, Adr *v, Adr *s, int f) 1378 { 1379 1380 if(f) 1381 if(copyau1(p1, v)) 1382 p1->reg = s->reg; 1383 return 0; 1384 } 1385 1386 struct { 1387 int opcode; 1388 int notopcode; 1389 int scond; 1390 int notscond; 1391 } predinfo[] = { 1392 { ABEQ, ABNE, 0x0, 0x1, }, 1393 { ABNE, ABEQ, 0x1, 0x0, }, 1394 { ABCS, ABCC, 0x2, 0x3, }, 1395 { ABHS, ABLO, 0x2, 0x3, }, 1396 { ABCC, ABCS, 0x3, 0x2, }, 1397 { ABLO, ABHS, 0x3, 0x2, }, 1398 { ABMI, ABPL, 0x4, 0x5, }, 1399 { ABPL, ABMI, 0x5, 0x4, }, 1400 { ABVS, ABVC, 0x6, 0x7, }, 1401 { ABVC, ABVS, 0x7, 0x6, }, 1402 { ABHI, ABLS, 0x8, 0x9, }, 1403 { ABLS, ABHI, 0x9, 0x8, }, 1404 { ABGE, ABLT, 0xA, 0xB, }, 1405 { ABLT, ABGE, 0xB, 0xA, }, 1406 { ABGT, ABLE, 0xC, 0xD, }, 1407 { ABLE, ABGT, 0xD, 0xC, }, 1408 }; 1409 1410 typedef struct { 1411 Flow *start; 1412 Flow *last; 1413 Flow *end; 1414 int len; 1415 } Joininfo; 1416 1417 enum { 1418 Join, 1419 Split, 1420 End, 1421 Branch, 1422 Setcond, 1423 Toolong 1424 }; 1425 1426 enum { 1427 Falsecond, 1428 Truecond, 1429 Delbranch, 1430 Keepbranch 1431 }; 1432 1433 static int 1434 isbranch(Prog *p) 1435 { 1436 return (ABEQ <= p->as) && (p->as <= ABLE); 1437 } 1438 1439 static int 1440 predicable(Prog *p) 1441 { 1442 switch(p->as) { 1443 case ANOP: 1444 case AXXX: 1445 case ADATA: 1446 case AGLOBL: 1447 case AGOK: 1448 case AHISTORY: 1449 case ANAME: 1450 case ASIGNAME: 1451 case ATEXT: 1452 case AWORD: 1453 case ABCASE: 1454 case ACASE: 1455 return 0; 1456 } 1457 if(isbranch(p)) 1458 return 0; 1459 return 1; 1460 } 1461 1462 /* 1463 * Depends on an analysis of the encodings performed by 5l. 1464 * These seem to be all of the opcodes that lead to the "S" bit 1465 * being set in the instruction encodings. 1466 * 1467 * C_SBIT may also have been set explicitly in p->scond. 1468 */ 1469 static int 1470 modifiescpsr(Prog *p) 1471 { 1472 switch(p->as) { 1473 case AMULLU: 1474 case AMULA: 1475 case AMULU: 1476 case ADIVU: 1477 1478 case ATEQ: 1479 case ACMN: 1480 case ATST: 1481 case ACMP: 1482 case AMUL: 1483 case ADIV: 1484 case AMOD: 1485 case AMODU: 1486 case ABL: 1487 return 1; 1488 } 1489 if(p->scond & C_SBIT) 1490 return 1; 1491 return 0; 1492 } 1493 1494 /* 1495 * Find the maximal chain of instructions starting with r which could 1496 * be executed conditionally 1497 */ 1498 static int 1499 joinsplit(Flow *r, Joininfo *j) 1500 { 1501 j->start = r; 1502 j->last = r; 1503 j->len = 0; 1504 do { 1505 if (r->p2 && (r->p1 || r->p2->p2link)) { 1506 j->end = r; 1507 return Join; 1508 } 1509 if (r->s1 && r->s2) { 1510 j->end = r; 1511 return Split; 1512 } 1513 j->last = r; 1514 if (r->prog->as != ANOP) 1515 j->len++; 1516 if (!r->s1 && !r->s2) { 1517 j->end = r->link; 1518 return End; 1519 } 1520 if (r->s2) { 1521 j->end = r->s2; 1522 return Branch; 1523 } 1524 if (modifiescpsr(r->prog)) { 1525 j->end = r->s1; 1526 return Setcond; 1527 } 1528 r = r->s1; 1529 } while (j->len < 4); 1530 j->end = r; 1531 return Toolong; 1532 } 1533 1534 static Flow* 1535 successor(Flow *r) 1536 { 1537 if(r->s1) 1538 return r->s1; 1539 else 1540 return r->s2; 1541 } 1542 1543 static void 1544 applypred(Flow *rstart, Joininfo *j, int cond, int branch) 1545 { 1546 int pred; 1547 Flow *r; 1548 1549 if(j->len == 0) 1550 return; 1551 if(cond == Truecond) 1552 pred = predinfo[rstart->prog->as - ABEQ].scond; 1553 else 1554 pred = predinfo[rstart->prog->as - ABEQ].notscond; 1555 1556 for(r = j->start;; r = successor(r)) { 1557 if(r->prog->as == AB) { 1558 if(r != j->last || branch == Delbranch) 1559 excise(r); 1560 else { 1561 if(cond == Truecond) 1562 r->prog->as = predinfo[rstart->prog->as - ABEQ].opcode; 1563 else 1564 r->prog->as = predinfo[rstart->prog->as - ABEQ].notopcode; 1565 } 1566 } 1567 else 1568 if(predicable(r->prog)) 1569 r->prog->scond = (r->prog->scond&~C_SCOND)|pred; 1570 if(r->s1 != r->link) { 1571 r->s1 = r->link; 1572 r->link->p1 = r; 1573 } 1574 if(r == j->last) 1575 break; 1576 } 1577 } 1578 1579 void 1580 predicate(Graph *g) 1581 { 1582 Flow *r; 1583 int t1, t2; 1584 Joininfo j1, j2; 1585 1586 for(r=g->start; r!=nil; r=r->link) { 1587 if (isbranch(r->prog)) { 1588 t1 = joinsplit(r->s1, &j1); 1589 t2 = joinsplit(r->s2, &j2); 1590 if(j1.last->link != j2.start) 1591 continue; 1592 if(j1.end == j2.end) 1593 if((t1 == Branch && (t2 == Join || t2 == Setcond)) || 1594 (t2 == Join && (t1 == Join || t1 == Setcond))) { 1595 applypred(r, &j1, Falsecond, Delbranch); 1596 applypred(r, &j2, Truecond, Delbranch); 1597 excise(r); 1598 continue; 1599 } 1600 if(t1 == End || t1 == Branch) { 1601 applypred(r, &j1, Falsecond, Keepbranch); 1602 excise(r); 1603 continue; 1604 } 1605 } 1606 } 1607 } 1608 1609 static int 1610 isdconst(Addr *a) 1611 { 1612 if(a->type == D_CONST && a->reg == NREG) 1613 return 1; 1614 return 0; 1615 } 1616 1617 int 1618 stackaddr(Addr *a) 1619 { 1620 return regtyp(a) && a->reg == REGSP; 1621 } 1622 1623 int 1624 smallindir(Addr *a, Addr *reg) 1625 { 1626 return reg->type == D_REG && a->type == D_OREG && 1627 a->reg == reg->reg && 1628 0 <= a->offset && a->offset < 4096; 1629 }