github.com/rohankumardubey/syslog-redirector-golang@v0.0.0-20140320174030-4859f03d829a/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 != S) 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) 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, A) || copyu(p0, &p->to, A)) 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_X0+15) 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 proginfo(&info, p); 577 if(info.flags & Call) { 578 if(debug['P'] && debug['v']) 579 print("\tfound %P; return 0\n", p); 580 return 0; 581 } 582 583 if(info.reguse | info.regset) { 584 if(debug['P'] && debug['v']) 585 print("\tfound %P; return 0\n", p); 586 return 0; 587 } 588 589 if((info.flags & Move) && (info.flags & (SizeL|SizeQ|SizeF|SizeD)) && p->to.type == v1->type) 590 goto gotit; 591 592 if(copyau(&p->from, v2) || 593 copyau(&p->to, v2)) { 594 if(debug['P'] && debug['v']) 595 print("\tcopyau %D failed\n", v2); 596 break; 597 } 598 if(copysub(&p->from, v1, v2, 0) || 599 copysub(&p->to, v1, v2, 0)) { 600 if(debug['P'] && debug['v']) 601 print("\tcopysub failed\n"); 602 break; 603 } 604 } 605 if(debug['P'] && debug['v']) 606 print("\tran off end; return 0\n"); 607 return 0; 608 609 gotit: 610 copysub(&p->to, v1, v2, 1); 611 if(debug['P']) { 612 print("gotit: %D->%D\n%P", v1, v2, r->prog); 613 if(p->from.type == v2->type) 614 print(" excise"); 615 print("\n"); 616 } 617 for(r=uniqs(r); r!=r0; r=uniqs(r)) { 618 p = r->prog; 619 copysub(&p->from, v1, v2, 1); 620 copysub(&p->to, v1, v2, 1); 621 if(debug['P']) 622 print("%P\n", r->prog); 623 } 624 t = v1->type; 625 v1->type = v2->type; 626 v2->type = t; 627 if(debug['P']) 628 print("%P last\n", r->prog); 629 return 1; 630 } 631 632 /* 633 * The idea is to remove redundant copies. 634 * v1->v2 F=0 635 * (use v2 s/v2/v1/)* 636 * set v1 F=1 637 * use v2 return fail 638 * ----------------- 639 * v1->v2 F=0 640 * (use v2 s/v2/v1/)* 641 * set v1 F=1 642 * set v2 return success 643 */ 644 static int 645 copyprop(Graph *g, Flow *r0) 646 { 647 Prog *p; 648 Adr *v1, *v2; 649 650 USED(g); 651 if(debug['P'] && debug['v']) 652 print("copyprop %P\n", r0->prog); 653 p = r0->prog; 654 v1 = &p->from; 655 v2 = &p->to; 656 if(copyas(v1, v2)) 657 return 1; 658 gactive++; 659 return copy1(v1, v2, r0->s1, 0); 660 } 661 662 static int 663 copy1(Adr *v1, Adr *v2, Flow *r, int f) 664 { 665 int t; 666 Prog *p; 667 668 if(r->active == gactive) { 669 if(debug['P']) 670 print("act set; return 1\n"); 671 return 1; 672 } 673 r->active = gactive; 674 if(debug['P']) 675 print("copy %D->%D f=%d\n", v1, v2, f); 676 for(; r != nil; r = r->s1) { 677 p = r->prog; 678 if(debug['P']) 679 print("%P", p); 680 if(!f && uniqp(r) == nil) { 681 f = 1; 682 if(debug['P']) 683 print("; merge; f=%d", f); 684 } 685 t = copyu(p, v2, A); 686 switch(t) { 687 case 2: /* rar, can't split */ 688 if(debug['P']) 689 print("; %D rar; return 0\n", v2); 690 return 0; 691 692 case 3: /* set */ 693 if(debug['P']) 694 print("; %D set; return 1\n", v2); 695 return 1; 696 697 case 1: /* used, substitute */ 698 case 4: /* use and set */ 699 if(f) { 700 if(!debug['P']) 701 return 0; 702 if(t == 4) 703 print("; %D used+set and f=%d; return 0\n", v2, f); 704 else 705 print("; %D used and f=%d; return 0\n", v2, f); 706 return 0; 707 } 708 if(copyu(p, v2, v1)) { 709 if(debug['P']) 710 print("; sub fail; return 0\n"); 711 return 0; 712 } 713 if(debug['P']) 714 print("; sub %D/%D", v2, v1); 715 if(t == 4) { 716 if(debug['P']) 717 print("; %D used+set; return 1\n", v2); 718 return 1; 719 } 720 break; 721 } 722 if(!f) { 723 t = copyu(p, v1, A); 724 if(!f && (t == 2 || t == 3 || t == 4)) { 725 f = 1; 726 if(debug['P']) 727 print("; %D set and !f; f=%d", v1, f); 728 } 729 } 730 if(debug['P']) 731 print("\n"); 732 if(r->s2) 733 if(!copy1(v1, v2, r->s2, f)) 734 return 0; 735 } 736 return 1; 737 } 738 739 /* 740 * return 741 * 1 if v only used (and substitute), 742 * 2 if read-alter-rewrite 743 * 3 if set 744 * 4 if set and used 745 * 0 otherwise (not touched) 746 */ 747 int 748 copyu(Prog *p, Adr *v, Adr *s) 749 { 750 ProgInfo info; 751 752 switch(p->as) { 753 case AJMP: 754 if(s != A) { 755 if(copysub(&p->to, v, s, 1)) 756 return 1; 757 return 0; 758 } 759 if(copyau(&p->to, v)) 760 return 1; 761 return 0; 762 763 case ARET: 764 if(s != A) 765 return 1; 766 return 3; 767 768 case ACALL: 769 if(REGEXT && v->type <= REGEXT && v->type > exregoffset) 770 return 2; 771 if(REGARG >= 0 && v->type == (uchar)REGARG) 772 return 2; 773 if(v->type == p->from.type) 774 return 2; 775 776 if(s != A) { 777 if(copysub(&p->to, v, s, 1)) 778 return 1; 779 return 0; 780 } 781 if(copyau(&p->to, v)) 782 return 4; 783 return 3; 784 785 case ATEXT: 786 if(REGARG >= 0 && v->type == (uchar)REGARG) 787 return 3; 788 return 0; 789 } 790 791 proginfo(&info, p); 792 793 if((info.reguse|info.regset) & RtoB(v->type)) 794 return 2; 795 796 if(info.flags & LeftAddr) 797 if(copyas(&p->from, v)) 798 return 2; 799 800 if((info.flags & (RightRead|RightWrite)) == (RightRead|RightWrite)) 801 if(copyas(&p->to, v)) 802 return 2; 803 804 if(info.flags & RightWrite) { 805 if(copyas(&p->to, v)) { 806 if(s != A) 807 return copysub(&p->from, v, s, 1); 808 if(copyau(&p->from, v)) 809 return 4; 810 return 3; 811 } 812 } 813 814 if(info.flags & (LeftAddr|LeftRead|LeftWrite|RightAddr|RightRead|RightWrite)) { 815 if(s != A) { 816 if(copysub(&p->from, v, s, 1)) 817 return 1; 818 return copysub(&p->to, v, s, 1); 819 } 820 if(copyau(&p->from, v)) 821 return 1; 822 if(copyau(&p->to, v)) 823 return 1; 824 } 825 826 return 0; 827 } 828 829 /* 830 * direct reference, 831 * could be set/use depending on 832 * semantics 833 */ 834 static int 835 copyas(Adr *a, Adr *v) 836 { 837 if(a->type != v->type) 838 return 0; 839 if(regtyp(v)) 840 return 1; 841 if(v->type == D_AUTO || v->type == D_PARAM) 842 if(v->offset == a->offset) 843 return 1; 844 return 0; 845 } 846 847 int 848 sameaddr(Addr *a, Addr *v) 849 { 850 if(a->type != v->type) 851 return 0; 852 if(regtyp(v)) 853 return 1; 854 if(v->type == D_AUTO || v->type == D_PARAM) 855 if(v->offset == a->offset) 856 return 1; 857 return 0; 858 } 859 860 /* 861 * either direct or indirect 862 */ 863 static int 864 copyau(Adr *a, Adr *v) 865 { 866 867 if(copyas(a, v)) { 868 if(debug['P'] && debug['v']) 869 print("\tcopyau: copyas returned 1\n"); 870 return 1; 871 } 872 if(regtyp(v)) { 873 if(a->type-D_INDIR == v->type) { 874 if(debug['P'] && debug['v']) 875 print("\tcopyau: found indir use - return 1\n"); 876 return 1; 877 } 878 if(a->index == v->type) { 879 if(debug['P'] && debug['v']) 880 print("\tcopyau: found index use - return 1\n"); 881 return 1; 882 } 883 } 884 return 0; 885 } 886 887 /* 888 * substitute s for v in a 889 * return failure to substitute 890 */ 891 static int 892 copysub(Adr *a, Adr *v, Adr *s, int f) 893 { 894 int t; 895 896 if(copyas(a, v)) { 897 t = s->type; 898 if(t >= D_AX && t <= D_R15 || t >= D_X0 && t <= D_X0+15) { 899 if(f) 900 a->type = t; 901 } 902 return 0; 903 } 904 if(regtyp(v)) { 905 t = v->type; 906 if(a->type == t+D_INDIR) { 907 if((s->type == D_BP || s->type == D_R13) && a->index != D_NONE) 908 return 1; /* can't use BP-base with index */ 909 if(f) 910 a->type = s->type+D_INDIR; 911 // return 0; 912 } 913 if(a->index == t) { 914 if(f) 915 a->index = s->type; 916 return 0; 917 } 918 return 0; 919 } 920 return 0; 921 } 922 923 static void 924 conprop(Flow *r0) 925 { 926 Flow *r; 927 Prog *p, *p0; 928 int t; 929 Adr *v0; 930 931 p0 = r0->prog; 932 v0 = &p0->to; 933 r = r0; 934 935 loop: 936 r = uniqs(r); 937 if(r == nil || r == r0) 938 return; 939 if(uniqp(r) == nil) 940 return; 941 942 p = r->prog; 943 t = copyu(p, v0, A); 944 switch(t) { 945 case 0: // miss 946 case 1: // use 947 goto loop; 948 949 case 2: // rar 950 case 4: // use and set 951 break; 952 953 case 3: // set 954 if(p->as == p0->as) 955 if(p->from.type == p0->from.type) 956 if(p->from.node == p0->from.node) 957 if(p->from.offset == p0->from.offset) 958 if(p->from.scale == p0->from.scale) 959 if(p->from.u.vval == p0->from.u.vval) 960 if(p->from.index == p0->from.index) { 961 excise(r); 962 goto loop; 963 } 964 break; 965 } 966 } 967 968 int 969 smallindir(Addr *a, Addr *reg) 970 { 971 return regtyp(reg) && 972 a->type == D_INDIR + reg->type && 973 a->index == D_NONE && 974 0 <= a->offset && a->offset < 4096; 975 } 976 977 int 978 stackaddr(Addr *a) 979 { 980 return regtyp(a) && a->type == D_SP; 981 }