github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/ppc64/peep.go (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 package ppc64 32 33 import ( 34 "cmd/compile/internal/gc" 35 "cmd/internal/obj" 36 "cmd/internal/obj/ppc64" 37 "fmt" 38 ) 39 40 var gactive uint32 41 42 func peep(firstp *obj.Prog) { 43 g := (*gc.Graph)(gc.Flowstart(firstp, nil)) 44 if g == nil { 45 return 46 } 47 gactive = 0 48 49 var p *obj.Prog 50 var r *gc.Flow 51 var t int 52 loop1: 53 if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { 54 gc.Dumpit("loop1", g.Start, 0) 55 } 56 57 t = 0 58 for r = g.Start; r != nil; r = r.Link { 59 p = r.Prog 60 61 // TODO(austin) Handle smaller moves. arm and amd64 62 // distinguish between moves that moves that *must* 63 // sign/zero extend and moves that don't care so they 64 // can eliminate moves that don't care without 65 // breaking moves that do care. This might let us 66 // simplify or remove the next peep loop, too. 67 if p.As == ppc64.AMOVD || p.As == ppc64.AFMOVD { 68 if regtyp(&p.To) { 69 // Try to eliminate reg->reg moves 70 if regtyp(&p.From) { 71 if p.From.Type == p.To.Type { 72 if copyprop(r) { 73 excise(r) 74 t++ 75 } else if subprop(r) && copyprop(r) { 76 excise(r) 77 t++ 78 } 79 } 80 } 81 82 // Convert uses to $0 to uses of R0 and 83 // propagate R0 84 if regzer(&p.From) != 0 { 85 if p.To.Type == obj.TYPE_REG { 86 p.From.Type = obj.TYPE_REG 87 p.From.Reg = ppc64.REGZERO 88 if copyprop(r) { 89 excise(r) 90 t++ 91 } else if subprop(r) && copyprop(r) { 92 excise(r) 93 t++ 94 } 95 } 96 } 97 } 98 } 99 } 100 101 if t != 0 { 102 goto loop1 103 } 104 105 /* 106 * look for MOVB x,R; MOVB R,R (for small MOVs not handled above) 107 */ 108 var p1 *obj.Prog 109 var r1 *gc.Flow 110 for r := (*gc.Flow)(g.Start); r != nil; r = r.Link { 111 p = r.Prog 112 switch p.As { 113 default: 114 continue 115 116 case ppc64.AMOVH, 117 ppc64.AMOVHZ, 118 ppc64.AMOVB, 119 ppc64.AMOVBZ, 120 ppc64.AMOVW, 121 ppc64.AMOVWZ: 122 if p.To.Type != obj.TYPE_REG { 123 continue 124 } 125 } 126 127 r1 = r.Link 128 if r1 == nil { 129 continue 130 } 131 p1 = r1.Prog 132 if p1.As != p.As { 133 continue 134 } 135 if p1.From.Type != obj.TYPE_REG || p1.From.Reg != p.To.Reg { 136 continue 137 } 138 if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.To.Reg { 139 continue 140 } 141 excise(r1) 142 } 143 144 if gc.Debug['D'] > 1 { 145 goto ret /* allow following code improvement to be suppressed */ 146 } 147 148 /* 149 * look for OP x,y,R; CMP R, $0 -> OPCC x,y,R 150 * when OP can set condition codes correctly 151 */ 152 for r := (*gc.Flow)(g.Start); r != nil; r = r.Link { 153 p = r.Prog 154 switch p.As { 155 case ppc64.ACMP, 156 ppc64.ACMPW: /* always safe? */ 157 if regzer(&p.To) == 0 { 158 continue 159 } 160 r1 = r.S1 161 if r1 == nil { 162 continue 163 } 164 switch r1.Prog.As { 165 default: 166 continue 167 168 /* the conditions can be complex and these are currently little used */ 169 case ppc64.ABCL, 170 ppc64.ABC: 171 continue 172 173 case ppc64.ABEQ, 174 ppc64.ABGE, 175 ppc64.ABGT, 176 ppc64.ABLE, 177 ppc64.ABLT, 178 ppc64.ABNE, 179 ppc64.ABVC, 180 ppc64.ABVS: 181 break 182 } 183 184 r1 = r 185 for { 186 r1 = gc.Uniqp(r1) 187 if r1 == nil || r1.Prog.As != obj.ANOP { 188 break 189 } 190 } 191 192 if r1 == nil { 193 continue 194 } 195 p1 = r1.Prog 196 if p1.To.Type != obj.TYPE_REG || p1.To.Reg != p.From.Reg { 197 continue 198 } 199 switch p1.As { 200 /* irregular instructions */ 201 case ppc64.ASUB, 202 ppc64.AADD, 203 ppc64.AXOR, 204 ppc64.AOR: 205 if p1.From.Type == obj.TYPE_CONST || p1.From.Type == obj.TYPE_ADDR { 206 continue 207 } 208 } 209 210 switch p1.As { 211 default: 212 continue 213 214 case ppc64.AMOVW, 215 ppc64.AMOVD: 216 if p1.From.Type != obj.TYPE_REG { 217 continue 218 } 219 continue 220 221 case ppc64.AANDCC, 222 ppc64.AANDNCC, 223 ppc64.AORCC, 224 ppc64.AORNCC, 225 ppc64.AXORCC, 226 ppc64.ASUBCC, 227 ppc64.ASUBECC, 228 ppc64.ASUBMECC, 229 ppc64.ASUBZECC, 230 ppc64.AADDCC, 231 ppc64.AADDCCC, 232 ppc64.AADDECC, 233 ppc64.AADDMECC, 234 ppc64.AADDZECC, 235 ppc64.ARLWMICC, 236 ppc64.ARLWNMCC, 237 /* don't deal with floating point instructions for now */ 238 /* 239 case AFABS: 240 case AFADD: 241 case AFADDS: 242 case AFCTIW: 243 case AFCTIWZ: 244 case AFDIV: 245 case AFDIVS: 246 case AFMADD: 247 case AFMADDS: 248 case AFMOVD: 249 case AFMSUB: 250 case AFMSUBS: 251 case AFMUL: 252 case AFMULS: 253 case AFNABS: 254 case AFNEG: 255 case AFNMADD: 256 case AFNMADDS: 257 case AFNMSUB: 258 case AFNMSUBS: 259 case AFRSP: 260 case AFSUB: 261 case AFSUBS: 262 case ACNTLZW: 263 case AMTFSB0: 264 case AMTFSB1: 265 */ 266 ppc64.AADD, 267 ppc64.AADDV, 268 ppc64.AADDC, 269 ppc64.AADDCV, 270 ppc64.AADDME, 271 ppc64.AADDMEV, 272 ppc64.AADDE, 273 ppc64.AADDEV, 274 ppc64.AADDZE, 275 ppc64.AADDZEV, 276 ppc64.AAND, 277 ppc64.AANDN, 278 ppc64.ADIVW, 279 ppc64.ADIVWV, 280 ppc64.ADIVWU, 281 ppc64.ADIVWUV, 282 ppc64.ADIVD, 283 ppc64.ADIVDV, 284 ppc64.ADIVDU, 285 ppc64.ADIVDUV, 286 ppc64.AEQV, 287 ppc64.AEXTSB, 288 ppc64.AEXTSH, 289 ppc64.AEXTSW, 290 ppc64.AMULHW, 291 ppc64.AMULHWU, 292 ppc64.AMULLW, 293 ppc64.AMULLWV, 294 ppc64.AMULHD, 295 ppc64.AMULHDU, 296 ppc64.AMULLD, 297 ppc64.AMULLDV, 298 ppc64.ANAND, 299 ppc64.ANEG, 300 ppc64.ANEGV, 301 ppc64.ANOR, 302 ppc64.AOR, 303 ppc64.AORN, 304 ppc64.AREM, 305 ppc64.AREMV, 306 ppc64.AREMU, 307 ppc64.AREMUV, 308 ppc64.AREMD, 309 ppc64.AREMDV, 310 ppc64.AREMDU, 311 ppc64.AREMDUV, 312 ppc64.ARLWMI, 313 ppc64.ARLWNM, 314 ppc64.ASLW, 315 ppc64.ASRAW, 316 ppc64.ASRW, 317 ppc64.ASLD, 318 ppc64.ASRAD, 319 ppc64.ASRD, 320 ppc64.ASUB, 321 ppc64.ASUBV, 322 ppc64.ASUBC, 323 ppc64.ASUBCV, 324 ppc64.ASUBME, 325 ppc64.ASUBMEV, 326 ppc64.ASUBE, 327 ppc64.ASUBEV, 328 ppc64.ASUBZE, 329 ppc64.ASUBZEV, 330 ppc64.AXOR: 331 t = variant2as(int(p1.As), as2variant(int(p1.As))|V_CC) 332 } 333 334 if gc.Debug['D'] != 0 { 335 fmt.Printf("cmp %v; %v -> ", p1, p) 336 } 337 p1.As = int16(t) 338 if gc.Debug['D'] != 0 { 339 fmt.Printf("%v\n", p1) 340 } 341 excise(r) 342 continue 343 } 344 } 345 346 ret: 347 gc.Flowend(g) 348 } 349 350 func excise(r *gc.Flow) { 351 p := (*obj.Prog)(r.Prog) 352 if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 { 353 fmt.Printf("%v ===delete===\n", p) 354 } 355 obj.Nopout(p) 356 gc.Ostats.Ndelmov++ 357 } 358 359 /* 360 * regzer returns 1 if a's value is 0 (a is R0 or $0) 361 */ 362 func regzer(a *obj.Addr) int { 363 if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR { 364 if a.Sym == nil && a.Reg == 0 { 365 if a.Offset == 0 { 366 return 1 367 } 368 } 369 } 370 if a.Type == obj.TYPE_REG { 371 if a.Reg == ppc64.REGZERO { 372 return 1 373 } 374 } 375 return 0 376 } 377 378 func regtyp(a *obj.Addr) bool { 379 // TODO(rsc): Floating point register exclusions? 380 return a.Type == obj.TYPE_REG && ppc64.REG_R0 <= a.Reg && a.Reg <= ppc64.REG_F31 && a.Reg != ppc64.REGZERO 381 } 382 383 /* 384 * the idea is to substitute 385 * one register for another 386 * from one MOV to another 387 * MOV a, R1 388 * ADD b, R1 / no use of R2 389 * MOV R1, R2 390 * would be converted to 391 * MOV a, R2 392 * ADD b, R2 393 * MOV R2, R1 394 * hopefully, then the former or latter MOV 395 * will be eliminated by copy propagation. 396 * 397 * r0 (the argument, not the register) is the MOV at the end of the 398 * above sequences. This returns 1 if it modified any instructions. 399 */ 400 func subprop(r0 *gc.Flow) bool { 401 p := (*obj.Prog)(r0.Prog) 402 v1 := (*obj.Addr)(&p.From) 403 if !regtyp(v1) { 404 return false 405 } 406 v2 := (*obj.Addr)(&p.To) 407 if !regtyp(v2) { 408 return false 409 } 410 for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) { 411 if gc.Uniqs(r) == nil { 412 break 413 } 414 p = r.Prog 415 if p.As == obj.AVARDEF || p.As == obj.AVARKILL { 416 continue 417 } 418 if p.Info.Flags&gc.Call != 0 { 419 return false 420 } 421 422 if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite { 423 if p.To.Type == v1.Type { 424 if p.To.Reg == v1.Reg { 425 copysub(&p.To, v1, v2, 1) 426 if gc.Debug['P'] != 0 { 427 fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog) 428 if p.From.Type == v2.Type { 429 fmt.Printf(" excise") 430 } 431 fmt.Printf("\n") 432 } 433 434 for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) { 435 p = r.Prog 436 copysub(&p.From, v1, v2, 1) 437 copysub1(p, v1, v2, 1) 438 copysub(&p.To, v1, v2, 1) 439 if gc.Debug['P'] != 0 { 440 fmt.Printf("%v\n", r.Prog) 441 } 442 } 443 444 t := int(int(v1.Reg)) 445 v1.Reg = v2.Reg 446 v2.Reg = int16(t) 447 if gc.Debug['P'] != 0 { 448 fmt.Printf("%v last\n", r.Prog) 449 } 450 return true 451 } 452 } 453 } 454 455 if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) { 456 break 457 } 458 if copysub(&p.From, v1, v2, 0) != 0 || copysub1(p, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 { 459 break 460 } 461 } 462 463 return false 464 } 465 466 /* 467 * The idea is to remove redundant copies. 468 * v1->v2 F=0 469 * (use v2 s/v2/v1/)* 470 * set v1 F=1 471 * use v2 return fail (v1->v2 move must remain) 472 * ----------------- 473 * v1->v2 F=0 474 * (use v2 s/v2/v1/)* 475 * set v1 F=1 476 * set v2 return success (caller can remove v1->v2 move) 477 */ 478 func copyprop(r0 *gc.Flow) bool { 479 p := (*obj.Prog)(r0.Prog) 480 v1 := (*obj.Addr)(&p.From) 481 v2 := (*obj.Addr)(&p.To) 482 if copyas(v1, v2) { 483 if gc.Debug['P'] != 0 { 484 fmt.Printf("eliminating self-move: %v\n", r0.Prog) 485 } 486 return true 487 } 488 489 gactive++ 490 if gc.Debug['P'] != 0 { 491 fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog) 492 } 493 return copy1(v1, v2, r0.S1, 0) 494 } 495 496 // copy1 replaces uses of v2 with v1 starting at r and returns 1 if 497 // all uses were rewritten. 498 func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool { 499 if uint32(r.Active) == gactive { 500 if gc.Debug['P'] != 0 { 501 fmt.Printf("act set; return 1\n") 502 } 503 return true 504 } 505 506 r.Active = int32(gactive) 507 if gc.Debug['P'] != 0 { 508 fmt.Printf("copy1 replace %v with %v f=%d\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f) 509 } 510 var t int 511 var p *obj.Prog 512 for ; r != nil; r = r.S1 { 513 p = r.Prog 514 if gc.Debug['P'] != 0 { 515 fmt.Printf("%v", p) 516 } 517 if f == 0 && gc.Uniqp(r) == nil { 518 // Multiple predecessors; conservatively 519 // assume v1 was set on other path 520 f = 1 521 522 if gc.Debug['P'] != 0 { 523 fmt.Printf("; merge; f=%d", f) 524 } 525 } 526 527 t = copyu(p, v2, nil) 528 switch t { 529 case 2: /* rar, can't split */ 530 if gc.Debug['P'] != 0 { 531 fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2)) 532 } 533 return false 534 535 case 3: /* set */ 536 if gc.Debug['P'] != 0 { 537 fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2)) 538 } 539 return true 540 541 case 1, /* used, substitute */ 542 4: /* use and set */ 543 if f != 0 { 544 if gc.Debug['P'] == 0 { 545 return false 546 } 547 if t == 4 { 548 fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) 549 } else { 550 fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f) 551 } 552 return false 553 } 554 555 if copyu(p, v2, v1) != 0 { 556 if gc.Debug['P'] != 0 { 557 fmt.Printf("; sub fail; return 0\n") 558 } 559 return false 560 } 561 562 if gc.Debug['P'] != 0 { 563 fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p) 564 } 565 if t == 4 { 566 if gc.Debug['P'] != 0 { 567 fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2)) 568 } 569 return true 570 } 571 } 572 573 if f == 0 { 574 t = copyu(p, v1, nil) 575 if f == 0 && (t == 2 || t == 3 || t == 4) { 576 f = 1 577 if gc.Debug['P'] != 0 { 578 fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f) 579 } 580 } 581 } 582 583 if gc.Debug['P'] != 0 { 584 fmt.Printf("\n") 585 } 586 if r.S2 != nil { 587 if !copy1(v1, v2, r.S2, f) { 588 return false 589 } 590 } 591 } 592 593 return true 594 } 595 596 // If s==nil, copyu returns the set/use of v in p; otherwise, it 597 // modifies p to replace reads of v with reads of s and returns 0 for 598 // success or non-zero for failure. 599 // 600 // If s==nil, copy returns one of the following values: 601 // 1 if v only used 602 // 2 if v is set and used in one address (read-alter-rewrite; 603 // can't substitute) 604 // 3 if v is only set 605 // 4 if v is set in one address and used in another (so addresses 606 // can be rewritten independently) 607 // 0 otherwise (not touched) 608 func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int { 609 if p.From3Type() != obj.TYPE_NONE { 610 // 9g never generates a from3 611 fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3)) 612 } 613 614 switch p.As { 615 default: 616 fmt.Printf("copyu: can't find %v\n", obj.Aconv(int(p.As))) 617 return 2 618 619 case obj.ANOP, /* read p->from, write p->to */ 620 ppc64.AMOVH, 621 ppc64.AMOVHZ, 622 ppc64.AMOVB, 623 ppc64.AMOVBZ, 624 ppc64.AMOVW, 625 ppc64.AMOVWZ, 626 ppc64.AMOVD, 627 ppc64.ANEG, 628 ppc64.ANEGCC, 629 ppc64.AADDME, 630 ppc64.AADDMECC, 631 ppc64.AADDZE, 632 ppc64.AADDZECC, 633 ppc64.ASUBME, 634 ppc64.ASUBMECC, 635 ppc64.ASUBZE, 636 ppc64.ASUBZECC, 637 ppc64.AFCTIW, 638 ppc64.AFCTIWZ, 639 ppc64.AFCTID, 640 ppc64.AFCTIDZ, 641 ppc64.AFCFID, 642 ppc64.AFCFIDCC, 643 ppc64.AFMOVS, 644 ppc64.AFMOVD, 645 ppc64.AFRSP, 646 ppc64.AFNEG, 647 ppc64.AFNEGCC: 648 if s != nil { 649 if copysub(&p.From, v, s, 1) != 0 { 650 return 1 651 } 652 653 // Update only indirect uses of v in p->to 654 if !copyas(&p.To, v) { 655 if copysub(&p.To, v, s, 1) != 0 { 656 return 1 657 } 658 } 659 return 0 660 } 661 662 if copyas(&p.To, v) { 663 // Fix up implicit from 664 if p.From.Type == obj.TYPE_NONE { 665 p.From = p.To 666 } 667 if copyau(&p.From, v) { 668 return 4 669 } 670 return 3 671 } 672 673 if copyau(&p.From, v) { 674 return 1 675 } 676 if copyau(&p.To, v) { 677 // p->to only indirectly uses v 678 return 1 679 } 680 681 return 0 682 683 case ppc64.AMOVBU, /* rar p->from, write p->to or read p->from, rar p->to */ 684 ppc64.AMOVBZU, 685 ppc64.AMOVHU, 686 ppc64.AMOVHZU, 687 ppc64.AMOVWZU, 688 ppc64.AMOVDU: 689 if p.From.Type == obj.TYPE_MEM { 690 if copyas(&p.From, v) { 691 // No s!=nil check; need to fail 692 // anyway in that case 693 return 2 694 } 695 696 if s != nil { 697 if copysub(&p.To, v, s, 1) != 0 { 698 return 1 699 } 700 return 0 701 } 702 703 if copyas(&p.To, v) { 704 return 3 705 } 706 } else if p.To.Type == obj.TYPE_MEM { 707 if copyas(&p.To, v) { 708 return 2 709 } 710 if s != nil { 711 if copysub(&p.From, v, s, 1) != 0 { 712 return 1 713 } 714 return 0 715 } 716 717 if copyau(&p.From, v) { 718 return 1 719 } 720 } else { 721 fmt.Printf("copyu: bad %v\n", p) 722 } 723 724 return 0 725 726 case ppc64.ARLWMI, /* read p->from, read p->reg, rar p->to */ 727 ppc64.ARLWMICC: 728 if copyas(&p.To, v) { 729 return 2 730 } 731 fallthrough 732 733 /* fall through */ 734 case ppc64.AADD, 735 /* read p->from, read p->reg, write p->to */ 736 ppc64.AADDC, 737 ppc64.AADDE, 738 ppc64.ASUB, 739 ppc64.ASLW, 740 ppc64.ASRW, 741 ppc64.ASRAW, 742 ppc64.ASLD, 743 ppc64.ASRD, 744 ppc64.ASRAD, 745 ppc64.AOR, 746 ppc64.AORCC, 747 ppc64.AORN, 748 ppc64.AORNCC, 749 ppc64.AAND, 750 ppc64.AANDCC, 751 ppc64.AANDN, 752 ppc64.AANDNCC, 753 ppc64.ANAND, 754 ppc64.ANANDCC, 755 ppc64.ANOR, 756 ppc64.ANORCC, 757 ppc64.AXOR, 758 ppc64.AMULHW, 759 ppc64.AMULHWU, 760 ppc64.AMULLW, 761 ppc64.AMULLD, 762 ppc64.ADIVW, 763 ppc64.ADIVD, 764 ppc64.ADIVWU, 765 ppc64.ADIVDU, 766 ppc64.AREM, 767 ppc64.AREMU, 768 ppc64.AREMD, 769 ppc64.AREMDU, 770 ppc64.ARLWNM, 771 ppc64.ARLWNMCC, 772 ppc64.AFADDS, 773 ppc64.AFADD, 774 ppc64.AFSUBS, 775 ppc64.AFSUB, 776 ppc64.AFMULS, 777 ppc64.AFMUL, 778 ppc64.AFDIVS, 779 ppc64.AFDIV: 780 if s != nil { 781 if copysub(&p.From, v, s, 1) != 0 { 782 return 1 783 } 784 if copysub1(p, v, s, 1) != 0 { 785 return 1 786 } 787 788 // Update only indirect uses of v in p->to 789 if !copyas(&p.To, v) { 790 if copysub(&p.To, v, s, 1) != 0 { 791 return 1 792 } 793 } 794 return 0 795 } 796 797 if copyas(&p.To, v) { 798 if p.Reg == 0 { 799 // Fix up implicit reg (e.g., ADD 800 // R3,R4 -> ADD R3,R4,R4) so we can 801 // update reg and to separately. 802 p.Reg = p.To.Reg 803 } 804 805 if copyau(&p.From, v) { 806 return 4 807 } 808 if copyau1(p, v) { 809 return 4 810 } 811 return 3 812 } 813 814 if copyau(&p.From, v) { 815 return 1 816 } 817 if copyau1(p, v) { 818 return 1 819 } 820 if copyau(&p.To, v) { 821 return 1 822 } 823 return 0 824 825 case ppc64.ABEQ, 826 ppc64.ABGT, 827 ppc64.ABGE, 828 ppc64.ABLT, 829 ppc64.ABLE, 830 ppc64.ABNE, 831 ppc64.ABVC, 832 ppc64.ABVS: 833 return 0 834 835 case obj.ACHECKNIL, /* read p->from */ 836 ppc64.ACMP, /* read p->from, read p->to */ 837 ppc64.ACMPU, 838 ppc64.ACMPW, 839 ppc64.ACMPWU, 840 ppc64.AFCMPO, 841 ppc64.AFCMPU: 842 if s != nil { 843 if copysub(&p.From, v, s, 1) != 0 { 844 return 1 845 } 846 return copysub(&p.To, v, s, 1) 847 } 848 849 if copyau(&p.From, v) { 850 return 1 851 } 852 if copyau(&p.To, v) { 853 return 1 854 } 855 return 0 856 857 // 9g never generates a branch to a GPR (this isn't 858 // even a normal instruction; liblink turns it in to a 859 // mov and a branch). 860 case ppc64.ABR: /* read p->to */ 861 if s != nil { 862 if copysub(&p.To, v, s, 1) != 0 { 863 return 1 864 } 865 return 0 866 } 867 868 if copyau(&p.To, v) { 869 return 1 870 } 871 return 0 872 873 case obj.ARET: /* funny */ 874 if s != nil { 875 return 0 876 } 877 878 // All registers die at this point, so claim 879 // everything is set (and not used). 880 return 3 881 882 case ppc64.ABL: /* funny */ 883 if v.Type == obj.TYPE_REG { 884 // TODO(rsc): REG_R0 and REG_F0 used to be 885 // (when register numbers started at 0) exregoffset and exfregoffset, 886 // which are unset entirely. 887 // It's strange that this handles R0 and F0 differently from the other 888 // registers. Possible failure to optimize? 889 if ppc64.REG_R0 < v.Reg && v.Reg <= ppc64.REGEXT { 890 return 2 891 } 892 if v.Reg == ppc64.REGARG { 893 return 2 894 } 895 if ppc64.REG_F0 < v.Reg && v.Reg <= ppc64.FREGEXT { 896 return 2 897 } 898 } 899 900 if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg { 901 return 2 902 } 903 904 if s != nil { 905 if copysub(&p.To, v, s, 1) != 0 { 906 return 1 907 } 908 return 0 909 } 910 911 if copyau(&p.To, v) { 912 return 4 913 } 914 return 3 915 916 // R0 is zero, used by DUFFZERO, cannot be substituted. 917 // R3 is ptr to memory, used and set, cannot be substituted. 918 case obj.ADUFFZERO: 919 if v.Type == obj.TYPE_REG { 920 if v.Reg == 0 { 921 return 1 922 } 923 if v.Reg == 3 { 924 return 2 925 } 926 } 927 928 return 0 929 930 // R3, R4 are ptr to src, dst, used and set, cannot be substituted. 931 // R5 is scratch, set by DUFFCOPY, cannot be substituted. 932 case obj.ADUFFCOPY: 933 if v.Type == obj.TYPE_REG { 934 if v.Reg == 3 || v.Reg == 4 { 935 return 2 936 } 937 if v.Reg == 5 { 938 return 3 939 } 940 } 941 942 return 0 943 944 case obj.ATEXT: /* funny */ 945 if v.Type == obj.TYPE_REG { 946 if v.Reg == ppc64.REGARG { 947 return 3 948 } 949 } 950 return 0 951 952 case obj.APCDATA, 953 obj.AFUNCDATA, 954 obj.AVARDEF, 955 obj.AVARKILL: 956 return 0 957 } 958 } 959 960 // copyas returns 1 if a and v address the same register. 961 // 962 // If a is the from operand, this means this operation reads the 963 // register in v. If a is the to operand, this means this operation 964 // writes the register in v. 965 func copyas(a *obj.Addr, v *obj.Addr) bool { 966 if regtyp(v) { 967 if a.Type == v.Type { 968 if a.Reg == v.Reg { 969 return true 970 } 971 } 972 } 973 return false 974 } 975 976 // copyau returns 1 if a either directly or indirectly addresses the 977 // same register as v. 978 // 979 // If a is the from operand, this means this operation reads the 980 // register in v. If a is the to operand, this means the operation 981 // either reads or writes the register in v (if !copyas(a, v), then 982 // the operation reads the register in v). 983 func copyau(a *obj.Addr, v *obj.Addr) bool { 984 if copyas(a, v) { 985 return true 986 } 987 if v.Type == obj.TYPE_REG { 988 if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) { 989 if v.Reg == a.Reg { 990 return true 991 } 992 } 993 } 994 return false 995 } 996 997 // copyau1 returns 1 if p->reg references the same register as v and v 998 // is a direct reference. 999 func copyau1(p *obj.Prog, v *obj.Addr) bool { 1000 if regtyp(v) && v.Reg != 0 { 1001 if p.Reg == v.Reg { 1002 return true 1003 } 1004 } 1005 return false 1006 } 1007 1008 // copysub replaces v with s in a if f!=0 or indicates it if could if f==0. 1009 // Returns 1 on failure to substitute (it always succeeds on ppc64). 1010 func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int { 1011 if f != 0 { 1012 if copyau(a, v) { 1013 a.Reg = s.Reg 1014 } 1015 } 1016 return 0 1017 } 1018 1019 // copysub1 replaces v with s in p1->reg if f!=0 or indicates if it could if f==0. 1020 // Returns 1 on failure to substitute (it always succeeds on ppc64). 1021 func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f int) int { 1022 if f != 0 { 1023 if copyau1(p1, v) { 1024 p1.Reg = s.Reg 1025 } 1026 } 1027 return 0 1028 } 1029 1030 func sameaddr(a *obj.Addr, v *obj.Addr) bool { 1031 if a.Type != v.Type { 1032 return false 1033 } 1034 if regtyp(v) && a.Reg == v.Reg { 1035 return true 1036 } 1037 if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM { 1038 if v.Offset == a.Offset { 1039 return true 1040 } 1041 } 1042 return false 1043 } 1044 1045 func smallindir(a *obj.Addr, reg *obj.Addr) bool { 1046 return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096 1047 } 1048 1049 func stackaddr(a *obj.Addr) bool { 1050 return a.Type == obj.TYPE_REG && a.Reg == ppc64.REGSP 1051 }