github.com/bgentry/go@v0.0.0-20150121062915-6cf5a733d54d/src/cmd/6g/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 static void conprop(Flow *r); 37 static void elimshortmov(Graph *g); 38 static int prevl(Flow *r, int reg); 39 static void pushback(Flow *r); 40 static int regconsttyp(Adr*); 41 static int subprop(Flow*); 42 static int copyprop(Graph*, Flow*); 43 static int copy1(Adr*, Adr*, Flow*, int); 44 static int copyas(Adr*, Adr*); 45 static int copyau(Adr*, Adr*); 46 static int copysub(Adr*, Adr*, Adr*, int); 47 48 static uint32 gactive; 49 50 // do we need the carry bit 51 static int 52 needc(Prog *p) 53 { 54 ProgInfo info; 55 56 while(p != P) { 57 proginfo(&info, p); 58 if(info.flags & UseCarry) 59 return 1; 60 if(info.flags & (SetCarry|KillCarry)) 61 return 0; 62 p = p->link; 63 } 64 return 0; 65 } 66 67 static Flow* 68 rnops(Flow *r) 69 { 70 Prog *p; 71 Flow *r1; 72 73 if(r != nil) 74 for(;;) { 75 p = r->prog; 76 if(p->as != ANOP || p->from.type != D_NONE || p->to.type != D_NONE) 77 break; 78 r1 = uniqs(r); 79 if(r1 == nil) 80 break; 81 r = r1; 82 } 83 return r; 84 } 85 86 void 87 peep(Prog *firstp) 88 { 89 Flow *r, *r1; 90 Graph *g; 91 Prog *p, *p1; 92 int t; 93 94 g = flowstart(firstp, sizeof(Flow)); 95 if(g == nil) 96 return; 97 gactive = 0; 98 99 // byte, word arithmetic elimination. 100 elimshortmov(g); 101 102 // constant propagation 103 // find MOV $con,R followed by 104 // another MOV $con,R without 105 // setting R in the interim 106 for(r=g->start; r!=nil; r=r->link) { 107 p = r->prog; 108 switch(p->as) { 109 case ALEAL: 110 case ALEAQ: 111 if(regtyp(&p->to)) 112 if(p->from.sym != nil) 113 if(p->from.index == D_NONE || p->from.index == D_CONST) 114 conprop(r); 115 break; 116 117 case AMOVB: 118 case AMOVW: 119 case AMOVL: 120 case AMOVQ: 121 case AMOVSS: 122 case AMOVSD: 123 if(regtyp(&p->to)) 124 if(p->from.type == D_CONST || p->from.type == D_FCONST) 125 conprop(r); 126 break; 127 } 128 } 129 130 loop1: 131 if(debug['P'] && debug['v']) 132 dumpit("loop1", g->start, 0); 133 134 t = 0; 135 for(r=g->start; r!=nil; r=r->link) { 136 p = r->prog; 137 switch(p->as) { 138 case AMOVL: 139 case AMOVQ: 140 case AMOVSS: 141 case AMOVSD: 142 if(regtyp(&p->to)) 143 if(regtyp(&p->from)) { 144 if(copyprop(g, r)) { 145 excise(r); 146 t++; 147 } else 148 if(subprop(r) && copyprop(g, r)) { 149 excise(r); 150 t++; 151 } 152 } 153 break; 154 155 case AMOVBLZX: 156 case AMOVWLZX: 157 case AMOVBLSX: 158 case AMOVWLSX: 159 if(regtyp(&p->to)) { 160 r1 = rnops(uniqs(r)); 161 if(r1 != nil) { 162 p1 = r1->prog; 163 if(p->as == p1->as && p->to.type == p1->from.type){ 164 p1->as = AMOVL; 165 t++; 166 } 167 } 168 } 169 break; 170 171 case AMOVBQSX: 172 case AMOVBQZX: 173 case AMOVWQSX: 174 case AMOVWQZX: 175 case AMOVLQSX: 176 case AMOVLQZX: 177 case AMOVQL: 178 if(regtyp(&p->to)) { 179 r1 = rnops(uniqs(r)); 180 if(r1 != nil) { 181 p1 = r1->prog; 182 if(p->as == p1->as && p->to.type == p1->from.type){ 183 p1->as = AMOVQ; 184 t++; 185 } 186 } 187 } 188 break; 189 190 case AADDL: 191 case AADDQ: 192 case AADDW: 193 if(p->from.type != D_CONST || needc(p->link)) 194 break; 195 if(p->from.offset == -1){ 196 if(p->as == AADDQ) 197 p->as = ADECQ; 198 else 199 if(p->as == AADDL) 200 p->as = ADECL; 201 else 202 p->as = ADECW; 203 p->from = zprog.from; 204 break; 205 } 206 if(p->from.offset == 1){ 207 if(p->as == AADDQ) 208 p->as = AINCQ; 209 else if(p->as == AADDL) 210 p->as = AINCL; 211 else 212 p->as = AINCW; 213 p->from = zprog.from; 214 break; 215 } 216 break; 217 218 case ASUBL: 219 case ASUBQ: 220 case ASUBW: 221 if(p->from.type != D_CONST || needc(p->link)) 222 break; 223 if(p->from.offset == -1) { 224 if(p->as == ASUBQ) 225 p->as = AINCQ; 226 else 227 if(p->as == ASUBL) 228 p->as = AINCL; 229 else 230 p->as = AINCW; 231 p->from = zprog.from; 232 break; 233 } 234 if(p->from.offset == 1){ 235 if(p->as == ASUBQ) 236 p->as = ADECQ; 237 else 238 if(p->as == ASUBL) 239 p->as = ADECL; 240 else 241 p->as = ADECW; 242 p->from = zprog.from; 243 break; 244 } 245 break; 246 } 247 } 248 if(t) 249 goto loop1; 250 251 // MOVLQZX removal. 252 // The MOVLQZX exists to avoid being confused for a 253 // MOVL that is just copying 32-bit data around during 254 // copyprop. Now that copyprop is done, remov MOVLQZX R1, R2 255 // if it is dominated by an earlier ADDL/MOVL/etc into R1 that 256 // will have already cleared the high bits. 257 // 258 // MOVSD removal. 259 // We never use packed registers, so a MOVSD between registers 260 // can be replaced by MOVAPD, which moves the pair of float64s 261 // instead of just the lower one. We only use the lower one, but 262 // the processor can do better if we do moves using both. 263 for(r=g->start; r!=nil; r=r->link) { 264 p = r->prog; 265 if(p->as == AMOVLQZX) 266 if(regtyp(&p->from)) 267 if(p->from.type == p->to.type) 268 if(prevl(r, p->from.type)) 269 excise(r); 270 271 if(p->as == AMOVSD) 272 if(regtyp(&p->from)) 273 if(regtyp(&p->to)) 274 p->as = AMOVAPD; 275 } 276 277 // load pipelining 278 // push any load from memory as early as possible 279 // to give it time to complete before use. 280 for(r=g->start; r!=nil; r=r->link) { 281 p = r->prog; 282 switch(p->as) { 283 case AMOVB: 284 case AMOVW: 285 case AMOVL: 286 case AMOVQ: 287 case AMOVLQZX: 288 if(regtyp(&p->to) && !regconsttyp(&p->from)) 289 pushback(r); 290 } 291 } 292 293 flowend(g); 294 } 295 296 static void 297 pushback(Flow *r0) 298 { 299 Flow *r, *b; 300 Prog *p0, *p, t; 301 302 b = nil; 303 p0 = r0->prog; 304 for(r=uniqp(r0); r!=nil && uniqs(r)!=nil; r=uniqp(r)) { 305 p = r->prog; 306 if(p->as != ANOP) { 307 if(!regconsttyp(&p->from) || !regtyp(&p->to)) 308 break; 309 if(copyu(p, &p0->to, nil) || copyu(p0, &p->to, nil)) 310 break; 311 } 312 if(p->as == ACALL) 313 break; 314 b = r; 315 } 316 317 if(b == nil) { 318 if(debug['v']) { 319 print("no pushback: %P\n", r0->prog); 320 if(r) 321 print("\t%P [%d]\n", r->prog, uniqs(r)!=nil); 322 } 323 return; 324 } 325 326 if(debug['v']) { 327 print("pushback\n"); 328 for(r=b;; r=r->link) { 329 print("\t%P\n", r->prog); 330 if(r == r0) 331 break; 332 } 333 } 334 335 t = *r0->prog; 336 for(r=uniqp(r0);; r=uniqp(r)) { 337 p0 = r->link->prog; 338 p = r->prog; 339 p0->as = p->as; 340 p0->lineno = p->lineno; 341 p0->from = p->from; 342 p0->to = p->to; 343 344 if(r == b) 345 break; 346 } 347 p0 = r->prog; 348 p0->as = t.as; 349 p0->lineno = t.lineno; 350 p0->from = t.from; 351 p0->to = t.to; 352 353 if(debug['v']) { 354 print("\tafter\n"); 355 for(r=b;; r=r->link) { 356 print("\t%P\n", r->prog); 357 if(r == r0) 358 break; 359 } 360 } 361 } 362 363 void 364 excise(Flow *r) 365 { 366 Prog *p; 367 368 p = r->prog; 369 if(debug['P'] && debug['v']) 370 print("%P ===delete===\n", p); 371 372 p->as = ANOP; 373 p->from = zprog.from; 374 p->to = zprog.to; 375 376 ostats.ndelmov++; 377 } 378 379 int 380 regtyp(Adr *a) 381 { 382 int t; 383 384 t = a->type; 385 if(t >= D_AX && t <= D_R15) 386 return 1; 387 if(t >= D_X0 && t <= D_X15) 388 return 1; 389 return 0; 390 } 391 392 // movb elimination. 393 // movb is simulated by the linker 394 // when a register other than ax, bx, cx, dx 395 // is used, so rewrite to other instructions 396 // when possible. a movb into a register 397 // can smash the entire 32-bit register without 398 // causing any trouble. 399 // 400 // TODO: Using the Q forms here instead of the L forms 401 // seems unnecessary, and it makes the instructions longer. 402 static void 403 elimshortmov(Graph *g) 404 { 405 Prog *p; 406 Flow *r; 407 408 for(r=g->start; r!=nil; r=r->link) { 409 p = r->prog; 410 if(regtyp(&p->to)) { 411 switch(p->as) { 412 case AINCB: 413 case AINCW: 414 p->as = AINCQ; 415 break; 416 case ADECB: 417 case ADECW: 418 p->as = ADECQ; 419 break; 420 case ANEGB: 421 case ANEGW: 422 p->as = ANEGQ; 423 break; 424 case ANOTB: 425 case ANOTW: 426 p->as = ANOTQ; 427 break; 428 } 429 if(regtyp(&p->from) || p->from.type == D_CONST) { 430 // move or artihmetic into partial register. 431 // from another register or constant can be movl. 432 // we don't switch to 64-bit arithmetic if it can 433 // change how the carry bit is set (and the carry bit is needed). 434 switch(p->as) { 435 case AMOVB: 436 case AMOVW: 437 p->as = AMOVQ; 438 break; 439 case AADDB: 440 case AADDW: 441 if(!needc(p->link)) 442 p->as = AADDQ; 443 break; 444 case ASUBB: 445 case ASUBW: 446 if(!needc(p->link)) 447 p->as = ASUBQ; 448 break; 449 case AMULB: 450 case AMULW: 451 p->as = AMULQ; 452 break; 453 case AIMULB: 454 case AIMULW: 455 p->as = AIMULQ; 456 break; 457 case AANDB: 458 case AANDW: 459 p->as = AANDQ; 460 break; 461 case AORB: 462 case AORW: 463 p->as = AORQ; 464 break; 465 case AXORB: 466 case AXORW: 467 p->as = AXORQ; 468 break; 469 case ASHLB: 470 case ASHLW: 471 p->as = ASHLQ; 472 break; 473 } 474 } else if(p->from.type >= D_NONE) { 475 // explicit zero extension, but don't 476 // do that if source is a byte register 477 // (only AH can occur and it's forbidden). 478 switch(p->as) { 479 case AMOVB: 480 p->as = AMOVBQZX; 481 break; 482 case AMOVW: 483 p->as = AMOVWQZX; 484 break; 485 } 486 } 487 } 488 } 489 } 490 491 // is 'a' a register or constant? 492 static int 493 regconsttyp(Adr *a) 494 { 495 if(regtyp(a)) 496 return 1; 497 switch(a->type) { 498 case D_CONST: 499 case D_FCONST: 500 case D_SCONST: 501 case D_ADDR: 502 return 1; 503 } 504 return 0; 505 } 506 507 // is reg guaranteed to be truncated by a previous L instruction? 508 static int 509 prevl(Flow *r0, int reg) 510 { 511 Prog *p; 512 Flow *r; 513 ProgInfo info; 514 515 for(r=uniqp(r0); r!=nil; r=uniqp(r)) { 516 p = r->prog; 517 if(p->to.type == reg) { 518 proginfo(&info, p); 519 if(info.flags & RightWrite) { 520 if(info.flags & SizeL) 521 return 1; 522 return 0; 523 } 524 } 525 } 526 return 0; 527 } 528 529 /* 530 * the idea is to substitute 531 * one register for another 532 * from one MOV to another 533 * MOV a, R0 534 * ADD b, R0 / no use of R1 535 * MOV R0, R1 536 * would be converted to 537 * MOV a, R1 538 * ADD b, R1 539 * MOV R1, R0 540 * hopefully, then the former or latter MOV 541 * will be eliminated by copy propagation. 542 */ 543 static int 544 subprop(Flow *r0) 545 { 546 Prog *p; 547 ProgInfo info; 548 Adr *v1, *v2; 549 Flow *r; 550 int t; 551 552 if(debug['P'] && debug['v']) 553 print("subprop %P\n", r0->prog); 554 p = r0->prog; 555 v1 = &p->from; 556 if(!regtyp(v1)) { 557 if(debug['P'] && debug['v']) 558 print("\tnot regtype %D; return 0\n", v1); 559 return 0; 560 } 561 v2 = &p->to; 562 if(!regtyp(v2)) { 563 if(debug['P'] && debug['v']) 564 print("\tnot regtype %D; return 0\n", v2); 565 return 0; 566 } 567 for(r=uniqp(r0); r!=nil; r=uniqp(r)) { 568 if(debug['P'] && debug['v']) 569 print("\t? %P\n", r->prog); 570 if(uniqs(r) == nil) { 571 if(debug['P'] && debug['v']) 572 print("\tno unique successor\n"); 573 break; 574 } 575 p = r->prog; 576 if(p->as == AVARDEF || p->as == AVARKILL) 577 continue; 578 proginfo(&info, p); 579 if(info.flags & Call) { 580 if(debug['P'] && debug['v']) 581 print("\tfound %P; return 0\n", p); 582 return 0; 583 } 584 585 if(info.reguse | info.regset) { 586 if(debug['P'] && debug['v']) 587 print("\tfound %P; return 0\n", p); 588 return 0; 589 } 590 591 if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type) 592 goto gotit; 593 594 if(copyau(&p->from, v2) || 595 copyau(&p->to, v2)) { 596 if(debug['P'] && debug['v']) 597 print("\tcopyau %D failed\n", v2); 598 break; 599 } 600 if(copysub(&p->from, v1, v2, 0) || 601 copysub(&p->to, v1, v2, 0)) { 602 if(debug['P'] && debug['v']) 603 print("\tcopysub failed\n"); 604 break; 605 } 606 } 607 if(debug['P'] && debug['v']) 608 print("\tran off end; return 0\n"); 609 return 0; 610 611 gotit: 612 copysub(&p->to, v1, v2, 1); 613 if(debug['P']) { 614 print("gotit: %D->%D\n%P", v1, v2, r->prog); 615 if(p->from.type == v2->type) 616 print(" excise"); 617 print("\n"); 618 } 619 for(r=uniqs(r); r!=r0; r=uniqs(r)) { 620 p = r->prog; 621 copysub(&p->from, v1, v2, 1); 622 copysub(&p->to, v1, v2, 1); 623 if(debug['P']) 624 print("%P\n", r->prog); 625 } 626 t = v1->type; 627 v1->type = v2->type; 628 v2->type = t; 629 if(debug['P']) 630 print("%P last\n", r->prog); 631 return 1; 632 } 633 634 /* 635 * The idea is to remove redundant copies. 636 * v1->v2 F=0 637 * (use v2 s/v2/v1/)* 638 * set v1 F=1 639 * use v2 return fail 640 * ----------------- 641 * v1->v2 F=0 642 * (use v2 s/v2/v1/)* 643 * set v1 F=1 644 * set v2 return success 645 */ 646 static int 647 copyprop(Graph *g, Flow *r0) 648 { 649 Prog *p; 650 Adr *v1, *v2; 651 652 USED(g); 653 if(debug['P'] && debug['v']) 654 print("copyprop %P\n", r0->prog); 655 p = r0->prog; 656 v1 = &p->from; 657 v2 = &p->to; 658 if(copyas(v1, v2)) 659 return 1; 660 gactive++; 661 return copy1(v1, v2, r0->s1, 0); 662 } 663 664 static int 665 copy1(Adr *v1, Adr *v2, Flow *r, int f) 666 { 667 int t; 668 Prog *p; 669 670 if(r->active == gactive) { 671 if(debug['P']) 672 print("act set; return 1\n"); 673 return 1; 674 } 675 r->active = gactive; 676 if(debug['P']) 677 print("copy %D->%D f=%d\n", v1, v2, f); 678 for(; r != nil; r = r->s1) { 679 p = r->prog; 680 if(debug['P']) 681 print("%P", p); 682 if(!f && uniqp(r) == nil) { 683 f = 1; 684 if(debug['P']) 685 print("; merge; f=%d", f); 686 } 687 t = copyu(p, v2, nil); 688 switch(t) { 689 case 2: /* rar, can't split */ 690 if(debug['P']) 691 print("; %D rar; return 0\n", v2); 692 return 0; 693 694 case 3: /* set */ 695 if(debug['P']) 696 print("; %D set; return 1\n", v2); 697 return 1; 698 699 case 1: /* used, substitute */ 700 case 4: /* use and set */ 701 if(f) { 702 if(!debug['P']) 703 return 0; 704 if(t == 4) 705 print("; %D used+set and f=%d; return 0\n", v2, f); 706 else 707 print("; %D used and f=%d; return 0\n", v2, f); 708 return 0; 709 } 710 if(copyu(p, v2, v1)) { 711 if(debug['P']) 712 print("; sub fail; return 0\n"); 713 return 0; 714 } 715 if(debug['P']) 716 print("; sub %D/%D", v2, v1); 717 if(t == 4) { 718 if(debug['P']) 719 print("; %D used+set; return 1\n", v2); 720 return 1; 721 } 722 break; 723 } 724 if(!f) { 725 t = copyu(p, v1, nil); 726 if(!f && (t == 2 || t == 3 || t == 4)) { 727 f = 1; 728 if(debug['P']) 729 print("; %D set and !f; f=%d", v1, f); 730 } 731 } 732 if(debug['P']) 733 print("\n"); 734 if(r->s2) 735 if(!copy1(v1, v2, r->s2, f)) 736 return 0; 737 } 738 return 1; 739 } 740 741 /* 742 * return 743 * 1 if v only used (and substitute), 744 * 2 if read-alter-rewrite 745 * 3 if set 746 * 4 if set and used 747 * 0 otherwise (not touched) 748 */ 749 int 750 copyu(Prog *p, Adr *v, Adr *s) 751 { 752 ProgInfo info; 753 754 switch(p->as) { 755 case AJMP: 756 if(s != nil) { 757 if(copysub(&p->to, v, s, 1)) 758 return 1; 759 return 0; 760 } 761 if(copyau(&p->to, v)) 762 return 1; 763 return 0; 764 765 case ARET: 766 if(s != nil) 767 return 1; 768 return 3; 769 770 case ACALL: 771 if(REGEXT && v->type <= REGEXT && v->type > exregoffset) 772 return 2; 773 if(REGARG >= 0 && v->type == (uchar)REGARG) 774 return 2; 775 if(v->type == p->from.type) 776 return 2; 777 778 if(s != nil) { 779 if(copysub(&p->to, v, s, 1)) 780 return 1; 781 return 0; 782 } 783 if(copyau(&p->to, v)) 784 return 4; 785 return 3; 786 787 case ATEXT: 788 if(REGARG >= 0 && v->type == (uchar)REGARG) 789 return 3; 790 return 0; 791 } 792 793 if(p->as == AVARDEF || p->as == AVARKILL) 794 return 0; 795 proginfo(&info, p); 796 797 if((info.reguse|info.regset) & RtoB(v->type)) 798 return 2; 799 800 if(info.flags & LeftAddr) 801 if(copyas(&p->from, v)) 802 return 2; 803 804 if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite)) 805 if(copyas(&p->to, v)) 806 return 2; 807 808 if(info.flags & RightWrite) { 809 if(copyas(&p->to, v)) { 810 if(s != nil) 811 return copysub(&p->from, v, s, 1); 812 if(copyau(&p->from, v)) 813 return 4; 814 return 3; 815 } 816 } 817 818 if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) { 819 if(s != nil) { 820 if(copysub(&p->from, v, s, 1)) 821 return 1; 822 return copysub(&p->to, v, s, 1); 823 } 824 if(copyau(&p->from, v)) 825 return 1; 826 if(copyau(&p->to, v)) 827 return 1; 828 } 829 830 return 0; 831 } 832 833 /* 834 * direct reference, 835 * could be set/use depending on 836 * semantics 837 */ 838 static int 839 copyas(Adr *a, Adr *v) 840 { 841 if(D_AL <= a->type && a->type <= D_R15B) 842 fatal("use of byte register"); 843 if(D_AL <= v->type && v->type <= D_R15B) 844 fatal("use of byte register"); 845 846 if(a->type != v->type) 847 return 0; 848 if(regtyp(v)) 849 return 1; 850 if(v->type == D_AUTO || v->type == D_PARAM) 851 if(v->offset == a->offset) 852 return 1; 853 return 0; 854 } 855 856 int 857 sameaddr(Addr *a, Addr *v) 858 { 859 if(a->type != v->type) 860 return 0; 861 if(regtyp(v)) 862 return 1; 863 if(v->type == D_AUTO || v->type == D_PARAM) 864 if(v->offset == a->offset) 865 return 1; 866 return 0; 867 } 868 869 /* 870 * either direct or indirect 871 */ 872 static int 873 copyau(Adr *a, Adr *v) 874 { 875 876 if(copyas(a, v)) { 877 if(debug['P'] && debug['v']) 878 print("\tcopyau: copyas returned 1\n"); 879 return 1; 880 } 881 if(regtyp(v)) { 882 if(a->type-D_INDIR == v->type) { 883 if(debug['P'] && debug['v']) 884 print("\tcopyau: found indir use - return 1\n"); 885 return 1; 886 } 887 if(a->index == v->type) { 888 if(debug['P'] && debug['v']) 889 print("\tcopyau: found index use - return 1\n"); 890 return 1; 891 } 892 } 893 return 0; 894 } 895 896 /* 897 * substitute s for v in a 898 * return failure to substitute 899 */ 900 static int 901 copysub(Adr *a, Adr *v, Adr *s, int f) 902 { 903 int t; 904 905 if(copyas(a, v)) { 906 t = s->type; 907 if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) { 908 if(f) 909 a->type = t; 910 } 911 return 0; 912 } 913 if(regtyp(v)) { 914 t = v->type; 915 if(a->type == t+D_INDIR) { 916 if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE) 917 return 1; /* can't use BP-base with index */ 918 if(f) 919 a->type = s->type+D_INDIR; 920 // return 0; 921 } 922 if(a->index == t) { 923 if(f) 924 a->index = s->type; 925 return 0; 926 } 927 return 0; 928 } 929 return 0; 930 } 931 932 static void 933 conprop(Flow *r0) 934 { 935 Flow *r; 936 Prog *p, *p0; 937 int t; 938 Adr *v0; 939 940 p0 = r0->prog; 941 v0 = &p0->to; 942 r = r0; 943 944 loop: 945 r = uniqs(r); 946 if(r == nil || r == r0) 947 return; 948 if(uniqp(r) == nil) 949 return; 950 951 p = r->prog; 952 t = copyu(p, v0, nil); 953 switch(t) { 954 case 0: // miss 955 case 1: // use 956 goto loop; 957 958 case 2: // rar 959 case 4: // use and set 960 break; 961 962 case 3: // set 963 if(p->as == p0->as) 964 if(p->from.type == p0->from.type) 965 if(p->from.node == p0->from.node) 966 if(p->from.offset == p0->from.offset) 967 if(p->from.scale == p0->from.scale) 968 if(p->from.type == D_FCONST && p->from.u.dval == p0->from.u.dval) 969 if(p->from.index == p0->from.index) { 970 excise(r); 971 goto loop; 972 } 973 break; 974 } 975 } 976 977 int 978 smallindir(Addr *a, Addr *reg) 979 { 980 return regtyp(reg) && 981 a->type == D_INDIR + reg->type && 982 a->index == D_NONE && 983 0 <= a->offset && a->offset < 4096; 984 } 985 986 int 987 stackaddr(Addr *a) 988 { 989 return regtyp(a) && a->type == D_SP; 990 }