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  }