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