Home | History | Annotate | Download | only in ppc64
      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 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 }
   1052