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