github.com/ader1990/go@v0.0.0-20140630135419-8c24447fa791/src/cmd/8g/peep.c (about) 1 // Derived from Inferno utils/6c/peep.c 2 // http://code.google.com/p/inferno-os/source/browse/utils/6c/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 #include <u.h> 32 #include <libc.h> 33 #include "gg.h" 34 #include "opt.h" 35 36 #define REGEXT 0 37 38 static void conprop(Flow *r); 39 static void elimshortmov(Graph*); 40 static int subprop(Flow*); 41 static int copyprop(Graph*, Flow*); 42 static int copy1(Adr*, Adr*, Flow*, int); 43 static int copyas(Adr*, Adr*); 44 static int copyau(Adr*, Adr*); 45 static int copysub(Adr*, Adr*, Adr*, int); 46 47 static uint32 gactive; 48 49 // do we need the carry bit 50 static int 51 needc(Prog *p) 52 { 53 ProgInfo info; 54 55 while(p != P) { 56 proginfo(&info, p); 57 if(info.flags & UseCarry) 58 return 1; 59 if(info.flags & (SetCarry|KillCarry)) 60 return 0; 61 p = p->link; 62 } 63 return 0; 64 } 65 66 static Flow* 67 rnops(Flow *r) 68 { 69 Prog *p; 70 Flow *r1; 71 72 if(r != nil) 73 for(;;) { 74 p = r->prog; 75 if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE) 76 break; 77 r1 = uniqs(r); 78 if(r1 == nil) 79 break; 80 r = r1; 81 } 82 return r; 83 } 84 85 void 86 peep(Prog *firstp) 87 { 88 Flow *r, *r1; 89 Graph *g; 90 Prog *p, *p1; 91 int t; 92 93 g = flowstart(firstp, sizeof(Flow)); 94 if(g == nil) 95 return; 96 gactive = 0; 97 98 // byte, word arithmetic elimination. 99 elimshortmov(g); 100 101 // constant propagation 102 // find MOV $con,R followed by 103 // another MOV $con,R without 104 // setting R in the interim 105 for(r=g->start; r!=nil; r=r->link) { 106 p = r->prog; 107 switch(p->as) { 108 case ALEAL: 109 if(regtyp(&p->to)) 110 if(p->from.sym != nil) 111 if(p->from.index == D_NONE || p->from.index == D_CONST) 112 conprop(r); 113 break; 114 115 case AMOVB: 116 case AMOVW: 117 case AMOVL: 118 case AMOVSS: 119 case AMOVSD: 120 if(regtyp(&p->to)) 121 if(p->from.type == D_CONST) 122 conprop(r); 123 break; 124 } 125 } 126 127 loop1: 128 if(debug['P'] && debug['v']) 129 dumpit("loop1", g->start, 0); 130 131 t = 0; 132 for(r=g->start; r!=nil; r=r->link) { 133 p = r->prog; 134 switch(p->as) { 135 case AMOVL: 136 case AMOVSS: 137 case AMOVSD: 138 if(regtyp(&p->to)) 139 if(regtyp(&p->from)) { 140 if(copyprop(g, r)) { 141 excise(r); 142 t++; 143 } else 144 if(subprop(r) && copyprop(g, r)) { 145 excise(r); 146 t++; 147 } 148 } 149 break; 150 151 case AMOVBLZX: 152 case AMOVWLZX: 153 case AMOVBLSX: 154 case AMOVWLSX: 155 if(regtyp(&p->to)) { 156 r1 = rnops(uniqs(r)); 157 if(r1 != nil) { 158 p1 = r1->prog; 159 if(p->as == p1->as && p->to.type == p1->from.type){ 160 p1->as = AMOVL; 161 t++; 162 } 163 } 164 } 165 break; 166 167 case AADDL: 168 case AADDW: 169 if(p->from.type != D_CONST || needc(p->link)) 170 break; 171 if(p->from.offset == -1){ 172 if(p->as == AADDL) 173 p->as = ADECL; 174 else 175 p->as = ADECW; 176 p->from = zprog.from; 177 break; 178 } 179 if(p->from.offset == 1){ 180 if(p->as == AADDL) 181 p->as = AINCL; 182 else 183 p->as = AINCW; 184 p->from = zprog.from; 185 break; 186 } 187 break; 188 189 case ASUBL: 190 case ASUBW: 191 if(p->from.type != D_CONST || needc(p->link)) 192 break; 193 if(p->from.offset == -1) { 194 if(p->as == ASUBL) 195 p->as = AINCL; 196 else 197 p->as = AINCW; 198 p->from = zprog.from; 199 break; 200 } 201 if(p->from.offset == 1){ 202 if(p->as == ASUBL) 203 p->as = ADECL; 204 else 205 p->as = ADECW; 206 p->from = zprog.from; 207 break; 208 } 209 break; 210 } 211 } 212 if(t) 213 goto loop1; 214 215 // MOVSD removal. 216 // We never use packed registers, so a MOVSD between registers 217 // can be replaced by MOVAPD, which moves the pair of float64s 218 // instead of just the lower one. We only use the lower one, but 219 // the processor can do better if we do moves using both. 220 for(r=g->start; r!=nil; r=r->link) { 221 p = r->prog; 222 if(p->as == AMOVSD) 223 if(regtyp(&p->from)) 224 if(regtyp(&p->to)) 225 p->as = AMOVAPD; 226 } 227 228 flowend(g); 229 } 230 231 void 232 excise(Flow *r) 233 { 234 Prog *p; 235 236 p = r->prog; 237 if(debug['P'] && debug['v']) 238 print("%P ===delete===\n", p); 239 240 p->as = ANOP; 241 p->from = zprog.from; 242 p->to = zprog.to; 243 244 ostats.ndelmov++; 245 } 246 247 int 248 regtyp(Adr *a) 249 { 250 int t; 251 252 t = a->type; 253 if(t >= D_AX && t <= D_DI) 254 return 1; 255 if(t >= D_X0 && t <= D_X7) 256 return 1; 257 return 0; 258 } 259 260 // movb elimination. 261 // movb is simulated by the linker 262 // when a register other than ax, bx, cx, dx 263 // is used, so rewrite to other instructions 264 // when possible. a movb into a register 265 // can smash the entire 64-bit register without 266 // causing any trouble. 267 static void 268 elimshortmov(Graph *g) 269 { 270 Prog *p; 271 Flow *r; 272 273 for(r=g->start; r!=nil; r=r->link) { 274 p = r->prog; 275 if(regtyp(&p->to)) { 276 switch(p->as) { 277 case AINCB: 278 case AINCW: 279 p->as = AINCL; 280 break; 281 case ADECB: 282 case ADECW: 283 p->as = ADECL; 284 break; 285 case ANEGB: 286 case ANEGW: 287 p->as = ANEGL; 288 break; 289 case ANOTB: 290 case ANOTW: 291 p->as = ANOTL; 292 break; 293 } 294 if(regtyp(&p->from) || p->from.type == D_CONST) { 295 // move or artihmetic into partial register. 296 // from another register or constant can be movl. 297 // we don't switch to 32-bit arithmetic if it can 298 // change how the carry bit is set (and the carry bit is needed). 299 switch(p->as) { 300 case AMOVB: 301 case AMOVW: 302 p->as = AMOVL; 303 break; 304 case AADDB: 305 case AADDW: 306 if(!needc(p->link)) 307 p->as = AADDL; 308 break; 309 case ASUBB: 310 case ASUBW: 311 if(!needc(p->link)) 312 p->as = ASUBL; 313 break; 314 case AMULB: 315 case AMULW: 316 p->as = AMULL; 317 break; 318 case AIMULB: 319 case AIMULW: 320 p->as = AIMULL; 321 break; 322 case AANDB: 323 case AANDW: 324 p->as = AANDL; 325 break; 326 case AORB: 327 case AORW: 328 p->as = AORL; 329 break; 330 case AXORB: 331 case AXORW: 332 p->as = AXORL; 333 break; 334 case ASHLB: 335 case ASHLW: 336 p->as = ASHLL; 337 break; 338 } 339 } else { 340 // explicit zero extension 341 switch(p->as) { 342 case AMOVB: 343 p->as = AMOVBLZX; 344 break; 345 case AMOVW: 346 p->as = AMOVWLZX; 347 break; 348 } 349 } 350 } 351 } 352 } 353 354 /* 355 * the idea is to substitute 356 * one register for another 357 * from one MOV to another 358 * MOV a, R0 359 * ADD b, R0 / no use of R1 360 * MOV R0, R1 361 * would be converted to 362 * MOV a, R1 363 * ADD b, R1 364 * MOV R1, R0 365 * hopefully, then the former or latter MOV 366 * will be eliminated by copy propagation. 367 */ 368 static int 369 subprop(Flow *r0) 370 { 371 Prog *p; 372 Adr *v1, *v2; 373 Flow *r; 374 int t; 375 ProgInfo info; 376 377 p = r0->prog; 378 v1 = &p->from; 379 if(!regtyp(v1)) 380 return 0; 381 v2 = &p->to; 382 if(!regtyp(v2)) 383 return 0; 384 for(r=uniqp(r0); r!=nil; r=uniqp(r)) { 385 if(debug['P'] && debug['v']) 386 print("\t? %P\n", r->prog); 387 if(uniqs(r) == nil) 388 break; 389 p = r->prog; 390 if(p->as == AVARDEF || p->as == AVARKILL) 391 continue; 392 proginfo(&info, p); 393 if(info.flags & Call) 394 return 0; 395 396 if(info.reguse | info.regset) 397 return 0; 398 399 if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type) 400 goto gotit; 401 402 if(copyau(&p->from, v2) || copyau(&p->to, v2)) 403 break; 404 if(copysub(&p->from, v1, v2, 0) || copysub(&p->to, v1, v2, 0)) 405 break; 406 } 407 return 0; 408 409 gotit: 410 copysub(&p->to, v1, v2, 1); 411 if(debug['P']) { 412 print("gotit: %D->%D\n%P", v1, v2, r->prog); 413 if(p->from.type == v2->type) 414 print(" excise"); 415 print("\n"); 416 } 417 for(r=uniqs(r); r!=r0; r=uniqs(r)) { 418 p = r->prog; 419 copysub(&p->from, v1, v2, 1); 420 copysub(&p->to, v1, v2, 1); 421 if(debug['P']) 422 print("%P\n", r->prog); 423 } 424 t = v1->type; 425 v1->type = v2->type; 426 v2->type = t; 427 if(debug['P']) 428 print("%P last\n", r->prog); 429 return 1; 430 } 431 432 /* 433 * The idea is to remove redundant copies. 434 * v1->v2 F=0 435 * (use v2 s/v2/v1/)* 436 * set v1 F=1 437 * use v2 return fail 438 * ----------------- 439 * v1->v2 F=0 440 * (use v2 s/v2/v1/)* 441 * set v1 F=1 442 * set v2 return success 443 */ 444 static int 445 copyprop(Graph *g, Flow *r0) 446 { 447 Prog *p; 448 Adr *v1, *v2; 449 450 USED(g); 451 p = r0->prog; 452 v1 = &p->from; 453 v2 = &p->to; 454 if(copyas(v1, v2)) 455 return 1; 456 gactive++; 457 return copy1(v1, v2, r0->s1, 0); 458 } 459 460 static int 461 copy1(Adr *v1, Adr *v2, Flow *r, int f) 462 { 463 int t; 464 Prog *p; 465 466 if(r->active == gactive) { 467 if(debug['P']) 468 print("act set; return 1\n"); 469 return 1; 470 } 471 r->active = gactive; 472 if(debug['P']) 473 print("copy %D->%D f=%d\n", v1, v2, f); 474 for(; r != nil; r = r->s1) { 475 p = r->prog; 476 if(debug['P']) 477 print("%P", p); 478 if(!f && uniqp(r) == nil) { 479 f = 1; 480 if(debug['P']) 481 print("; merge; f=%d", f); 482 } 483 t = copyu(p, v2, nil); 484 switch(t) { 485 case 2: /* rar, can't split */ 486 if(debug['P']) 487 print("; %D rar; return 0\n", v2); 488 return 0; 489 490 case 3: /* set */ 491 if(debug['P']) 492 print("; %D set; return 1\n", v2); 493 return 1; 494 495 case 1: /* used, substitute */ 496 case 4: /* use and set */ 497 if(f) { 498 if(!debug['P']) 499 return 0; 500 if(t == 4) 501 print("; %D used+set and f=%d; return 0\n", v2, f); 502 else 503 print("; %D used and f=%d; return 0\n", v2, f); 504 return 0; 505 } 506 if(copyu(p, v2, v1)) { 507 if(debug['P']) 508 print("; sub fail; return 0\n"); 509 return 0; 510 } 511 if(debug['P']) 512 print("; sub %D/%D", v2, v1); 513 if(t == 4) { 514 if(debug['P']) 515 print("; %D used+set; return 1\n", v2); 516 return 1; 517 } 518 break; 519 } 520 if(!f) { 521 t = copyu(p, v1, nil); 522 if(!f && (t == 2 || t == 3 || t == 4)) { 523 f = 1; 524 if(debug['P']) 525 print("; %D set and !f; f=%d", v1, f); 526 } 527 } 528 if(debug['P']) 529 print("\n"); 530 if(r->s2) 531 if(!copy1(v1, v2, r->s2, f)) 532 return 0; 533 } 534 return 1; 535 } 536 537 /* 538 * return 539 * 1 if v only used (and substitute), 540 * 2 if read-alter-rewrite 541 * 3 if set 542 * 4 if set and used 543 * 0 otherwise (not touched) 544 */ 545 int 546 copyu(Prog *p, Adr *v, Adr *s) 547 { 548 ProgInfo info; 549 550 switch(p->as) { 551 case AJMP: 552 if(s != nil) { 553 if(copysub(&p->to, v, s, 1)) 554 return 1; 555 return 0; 556 } 557 if(copyau(&p->to, v)) 558 return 1; 559 return 0; 560 561 case ARET: 562 if(s != nil) 563 return 1; 564 return 3; 565 566 case ACALL: 567 if(REGEXT && v->type <= REGEXT && v->type > exregoffset) 568 return 2; 569 if(REGARG >= 0 && v->type == (uchar)REGARG) 570 return 2; 571 if(v->type == p->from.type) 572 return 2; 573 574 if(s != nil) { 575 if(copysub(&p->to, v, s, 1)) 576 return 1; 577 return 0; 578 } 579 if(copyau(&p->to, v)) 580 return 4; 581 return 3; 582 583 case ATEXT: 584 if(REGARG >= 0 && v->type == (uchar)REGARG) 585 return 3; 586 return 0; 587 } 588 589 if(p->as == AVARDEF || p->as == AVARKILL) 590 return 0; 591 proginfo(&info, p); 592 593 if((info.reguse|info.regset) & RtoB(v->type)) 594 return 2; 595 596 if(info.flags & LeftAddr) 597 if(copyas(&p->from, v)) 598 return 2; 599 600 if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite)) 601 if(copyas(&p->to, v)) 602 return 2; 603 604 if(info.flags & RightWrite) { 605 if(copyas(&p->to, v)) { 606 if(s != nil) 607 return copysub(&p->from, v, s, 1); 608 if(copyau(&p->from, v)) 609 return 4; 610 return 3; 611 } 612 } 613 614 if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) { 615 if(s != nil) { 616 if(copysub(&p->from, v, s, 1)) 617 return 1; 618 return copysub(&p->to, v, s, 1); 619 } 620 if(copyau(&p->from, v)) 621 return 1; 622 if(copyau(&p->to, v)) 623 return 1; 624 } 625 626 return 0; 627 } 628 629 /* 630 * direct reference, 631 * could be set/use depending on 632 * semantics 633 */ 634 static int 635 copyas(Adr *a, Adr *v) 636 { 637 if(a->type != v->type) 638 return 0; 639 if(regtyp(v)) 640 return 1; 641 if(v->type == D_AUTO || v->type == D_PARAM) 642 if(v->offset == a->offset) 643 return 1; 644 return 0; 645 } 646 647 int 648 sameaddr(Addr *a, Addr *v) 649 { 650 if(a->type != v->type) 651 return 0; 652 if(regtyp(v)) 653 return 1; 654 if(v->type == D_AUTO || v->type == D_PARAM) 655 if(v->offset == a->offset) 656 return 1; 657 return 0; 658 } 659 660 /* 661 * either direct or indirect 662 */ 663 static int 664 copyau(Adr *a, Adr *v) 665 { 666 667 if(copyas(a, v)) 668 return 1; 669 if(regtyp(v)) { 670 if(a->type-D_INDIR == v->type) 671 return 1; 672 if(a->index == v->type) 673 return 1; 674 } 675 return 0; 676 } 677 678 /* 679 * substitute s for v in a 680 * return failure to substitute 681 */ 682 static int 683 copysub(Adr *a, Adr *v, Adr *s, int f) 684 { 685 int t; 686 687 if(copyas(a, v)) { 688 t = s->type; 689 if(t >= D_AX && t <= D_DI || t >= D_X0 && t <= D_X7) { 690 if(f) 691 a->type = t; 692 } 693 return 0; 694 } 695 if(regtyp(v)) { 696 t = v->type; 697 if(a->type == t+D_INDIR) { 698 if((s->type == D_BP) && a->index != D_NONE) 699 return 1; /* can't use BP-base with index */ 700 if(f) 701 a->type = s->type+D_INDIR; 702 // return 0; 703 } 704 if(a->index == t) { 705 if(f) 706 a->index = s->type; 707 return 0; 708 } 709 return 0; 710 } 711 return 0; 712 } 713 714 static void 715 conprop(Flow *r0) 716 { 717 Flow *r; 718 Prog *p, *p0; 719 int t; 720 Adr *v0; 721 722 p0 = r0->prog; 723 v0 = &p0->to; 724 r = r0; 725 726 loop: 727 r = uniqs(r); 728 if(r == nil || r == r0) 729 return; 730 if(uniqp(r) == nil) 731 return; 732 733 p = r->prog; 734 t = copyu(p, v0, nil); 735 switch(t) { 736 case 0: // miss 737 case 1: // use 738 goto loop; 739 740 case 2: // rar 741 case 4: // use and set 742 break; 743 744 case 3: // set 745 if(p->as == p0->as) 746 if(p->from.type == p0->from.type) 747 if(p->from.node == p0->from.node) 748 if(p->from.offset == p0->from.offset) 749 if(p->from.scale == p0->from.scale) 750 if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval) 751 if(p->from.index == p0->from.index) { 752 excise(r); 753 goto loop; 754 } 755 break; 756 } 757 } 758 759 int 760 smallindir(Addr *a, Addr *reg) 761 { 762 return regtyp(reg) && 763 a->type == D_INDIR + reg->type && 764 a->index == D_NONE && 765 0 <= a->offset && a->offset < 4096; 766 } 767 768 int 769 stackaddr(Addr *a) 770 { 771 return regtyp(a) && a->type == D_SP; 772 }