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