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