github.com/euank/go@v0.0.0-20160829210321-495514729181/src/cmd/compile/internal/ppc64/peep.go (about)

     1  // Derived from Inferno utils/6c/peep.c
     2  // https://bitbucket.org/inferno-os/inferno-os/src/default/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.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 obj.As
    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) {
    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 := 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 := 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) {
   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(p1.As, as2variant(p1.As)|V_CC)
   332  			}
   333  
   334  			if gc.Debug['D'] != 0 {
   335  				fmt.Printf("cmp %v; %v -> ", p1, p)
   336  			}
   337  			p1.As = 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 := 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  // regzer returns true if a's value is 0 (a is R0 or $0)
   360  func regzer(a *obj.Addr) bool {
   361  	if a.Type == obj.TYPE_CONST || a.Type == obj.TYPE_ADDR {
   362  		if a.Sym == nil && a.Reg == 0 {
   363  			if a.Offset == 0 {
   364  				return true
   365  			}
   366  		}
   367  	}
   368  	return a.Type == obj.TYPE_REG && a.Reg == ppc64.REGZERO
   369  }
   370  
   371  func regtyp(a *obj.Addr) bool {
   372  	// TODO(rsc): Floating point register exclusions?
   373  	return a.Type == obj.TYPE_REG && ppc64.REG_R0 <= a.Reg && a.Reg <= ppc64.REG_F31 && a.Reg != ppc64.REGZERO
   374  }
   375  
   376  /*
   377   * the idea is to substitute
   378   * one register for another
   379   * from one MOV to another
   380   *	MOV	a, R1
   381   *	ADD	b, R1	/ no use of R2
   382   *	MOV	R1, R2
   383   * would be converted to
   384   *	MOV	a, R2
   385   *	ADD	b, R2
   386   *	MOV	R2, R1
   387   * hopefully, then the former or latter MOV
   388   * will be eliminated by copy propagation.
   389   *
   390   * r0 (the argument, not the register) is the MOV at the end of the
   391   * above sequences.  This returns 1 if it modified any instructions.
   392   */
   393  func subprop(r0 *gc.Flow) bool {
   394  	p := r0.Prog
   395  	v1 := &p.From
   396  	if !regtyp(v1) {
   397  		return false
   398  	}
   399  	v2 := &p.To
   400  	if !regtyp(v2) {
   401  		return false
   402  	}
   403  	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
   404  		if gc.Uniqs(r) == nil {
   405  			break
   406  		}
   407  		p = r.Prog
   408  		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
   409  			continue
   410  		}
   411  		if p.Info.Flags&gc.Call != 0 {
   412  			return false
   413  		}
   414  
   415  		if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightWrite {
   416  			if p.To.Type == v1.Type {
   417  				if p.To.Reg == v1.Reg {
   418  					copysub(&p.To, v1, v2, true)
   419  					if gc.Debug['P'] != 0 {
   420  						fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
   421  						if p.From.Type == v2.Type {
   422  							fmt.Printf(" excise")
   423  						}
   424  						fmt.Printf("\n")
   425  					}
   426  
   427  					for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
   428  						p = r.Prog
   429  						copysub(&p.From, v1, v2, true)
   430  						copysub1(p, v1, v2, true)
   431  						copysub(&p.To, v1, v2, true)
   432  						if gc.Debug['P'] != 0 {
   433  							fmt.Printf("%v\n", r.Prog)
   434  						}
   435  					}
   436  
   437  					v1.Reg, v2.Reg = v2.Reg, v1.Reg
   438  					if gc.Debug['P'] != 0 {
   439  						fmt.Printf("%v last\n", r.Prog)
   440  					}
   441  					return true
   442  				}
   443  			}
   444  		}
   445  
   446  		if copyau(&p.From, v2) || copyau1(p, v2) || copyau(&p.To, v2) {
   447  			break
   448  		}
   449  		if copysub(&p.From, v1, v2, false) || copysub1(p, v1, v2, false) || copysub(&p.To, v1, v2, false) {
   450  			break
   451  		}
   452  	}
   453  
   454  	return false
   455  }
   456  
   457  /*
   458   * The idea is to remove redundant copies.
   459   *	v1->v2	F=0
   460   *	(use v2	s/v2/v1/)*
   461   *	set v1	F=1
   462   *	use v2	return fail (v1->v2 move must remain)
   463   *	-----------------
   464   *	v1->v2	F=0
   465   *	(use v2	s/v2/v1/)*
   466   *	set v1	F=1
   467   *	set v2	return success (caller can remove v1->v2 move)
   468   */
   469  func copyprop(r0 *gc.Flow) bool {
   470  	p := r0.Prog
   471  	v1 := &p.From
   472  	v2 := &p.To
   473  	if copyas(v1, v2) {
   474  		if gc.Debug['P'] != 0 {
   475  			fmt.Printf("eliminating self-move: %v\n", r0.Prog)
   476  		}
   477  		return true
   478  	}
   479  
   480  	gactive++
   481  	if gc.Debug['P'] != 0 {
   482  		fmt.Printf("trying to eliminate %v->%v move from:\n%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r0.Prog)
   483  	}
   484  	return copy1(v1, v2, r0.S1, false)
   485  }
   486  
   487  // copy1 replaces uses of v2 with v1 starting at r and returns 1 if
   488  // all uses were rewritten.
   489  func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
   490  	if uint32(r.Active) == gactive {
   491  		if gc.Debug['P'] != 0 {
   492  			fmt.Printf("act set; return 1\n")
   493  		}
   494  		return true
   495  	}
   496  
   497  	r.Active = int32(gactive)
   498  	if gc.Debug['P'] != 0 {
   499  		fmt.Printf("copy1 replace %v with %v f=%v\n", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), f)
   500  	}
   501  	for ; r != nil; r = r.S1 {
   502  		p := r.Prog
   503  		if gc.Debug['P'] != 0 {
   504  			fmt.Printf("%v", p)
   505  		}
   506  		if !f && gc.Uniqp(r) == nil {
   507  			// Multiple predecessors; conservatively
   508  			// assume v1 was set on other path
   509  			f = true
   510  
   511  			if gc.Debug['P'] != 0 {
   512  				fmt.Printf("; merge; f=%v", f)
   513  			}
   514  		}
   515  
   516  		switch t := copyu(p, v2, nil); t {
   517  		case 2: /* rar, can't split */
   518  			if gc.Debug['P'] != 0 {
   519  				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
   520  			}
   521  			return false
   522  
   523  		case 3: /* set */
   524  			if gc.Debug['P'] != 0 {
   525  				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
   526  			}
   527  			return true
   528  
   529  		case 1, /* used, substitute */
   530  			4: /* use and set */
   531  			if f {
   532  				if gc.Debug['P'] == 0 {
   533  					return false
   534  				}
   535  				if t == 4 {
   536  					fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
   537  				} else {
   538  					fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
   539  				}
   540  				return false
   541  			}
   542  
   543  			if copyu(p, v2, v1) != 0 {
   544  				if gc.Debug['P'] != 0 {
   545  					fmt.Printf("; sub fail; return 0\n")
   546  				}
   547  				return false
   548  			}
   549  
   550  			if gc.Debug['P'] != 0 {
   551  				fmt.Printf("; sub %v->%v\n => %v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1), p)
   552  			}
   553  			if t == 4 {
   554  				if gc.Debug['P'] != 0 {
   555  					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
   556  				}
   557  				return true
   558  			}
   559  		}
   560  
   561  		if !f {
   562  			t := copyu(p, v1, nil)
   563  			if t == 2 || t == 3 || t == 4 {
   564  				f = true
   565  				if gc.Debug['P'] != 0 {
   566  					fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
   567  				}
   568  			}
   569  		}
   570  
   571  		if gc.Debug['P'] != 0 {
   572  			fmt.Printf("\n")
   573  		}
   574  		if r.S2 != nil {
   575  			if !copy1(v1, v2, r.S2, f) {
   576  				return false
   577  			}
   578  		}
   579  	}
   580  
   581  	return true
   582  }
   583  
   584  // If s==nil, copyu returns the set/use of v in p; otherwise, it
   585  // modifies p to replace reads of v with reads of s and returns 0 for
   586  // success or non-zero for failure.
   587  //
   588  // If s==nil, copy returns one of the following values:
   589  // 	1 if v only used
   590  //	2 if v is set and used in one address (read-alter-rewrite;
   591  // 	  can't substitute)
   592  //	3 if v is only set
   593  //	4 if v is set in one address and used in another (so addresses
   594  // 	  can be rewritten independently)
   595  //	0 otherwise (not touched)
   596  func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
   597  	if p.From3Type() != obj.TYPE_NONE {
   598  		// 9g never generates a from3
   599  		fmt.Printf("copyu: from3 (%v) not implemented\n", gc.Ctxt.Dconv(p.From3))
   600  	}
   601  
   602  	switch p.As {
   603  	default:
   604  		fmt.Printf("copyu: can't find %v\n", p.As)
   605  		return 2
   606  
   607  	case obj.ANOP, /* read p->from, write p->to */
   608  		ppc64.AMOVH,
   609  		ppc64.AMOVHZ,
   610  		ppc64.AMOVB,
   611  		ppc64.AMOVBZ,
   612  		ppc64.AMOVW,
   613  		ppc64.AMOVWZ,
   614  		ppc64.AMOVD,
   615  		ppc64.ANEG,
   616  		ppc64.ANEGCC,
   617  		ppc64.AADDME,
   618  		ppc64.AADDMECC,
   619  		ppc64.AADDZE,
   620  		ppc64.AADDZECC,
   621  		ppc64.ASUBME,
   622  		ppc64.ASUBMECC,
   623  		ppc64.ASUBZE,
   624  		ppc64.ASUBZECC,
   625  		ppc64.AFCTIW,
   626  		ppc64.AFCTIWZ,
   627  		ppc64.AFCTID,
   628  		ppc64.AFCTIDZ,
   629  		ppc64.AFCFID,
   630  		ppc64.AFCFIDCC,
   631  		ppc64.AFCFIDU,
   632  		ppc64.AFCFIDUCC,
   633  		ppc64.AFMOVS,
   634  		ppc64.AFMOVD,
   635  		ppc64.AFRSP,
   636  		ppc64.AFNEG,
   637  		ppc64.AFNEGCC,
   638  		ppc64.AFSQRT:
   639  		if s != nil {
   640  			if copysub(&p.From, v, s, true) {
   641  				return 1
   642  			}
   643  
   644  			// Update only indirect uses of v in p->to
   645  			if !copyas(&p.To, v) {
   646  				if copysub(&p.To, v, s, true) {
   647  					return 1
   648  				}
   649  			}
   650  			return 0
   651  		}
   652  
   653  		if copyas(&p.To, v) {
   654  			// Fix up implicit from
   655  			if p.From.Type == obj.TYPE_NONE {
   656  				p.From = p.To
   657  			}
   658  			if copyau(&p.From, v) {
   659  				return 4
   660  			}
   661  			return 3
   662  		}
   663  
   664  		if copyau(&p.From, v) {
   665  			return 1
   666  		}
   667  		if copyau(&p.To, v) {
   668  			// p->to only indirectly uses v
   669  			return 1
   670  		}
   671  
   672  		return 0
   673  
   674  	case ppc64.AMOVBU, /* rar p->from, write p->to or read p->from, rar p->to */
   675  		ppc64.AMOVBZU,
   676  		ppc64.AMOVHU,
   677  		ppc64.AMOVHZU,
   678  		ppc64.AMOVWZU,
   679  		ppc64.AMOVDU:
   680  		if p.From.Type == obj.TYPE_MEM {
   681  			if copyas(&p.From, v) {
   682  				// No s!=nil check; need to fail
   683  				// anyway in that case
   684  				return 2
   685  			}
   686  
   687  			if s != nil {
   688  				if copysub(&p.To, v, s, true) {
   689  					return 1
   690  				}
   691  				return 0
   692  			}
   693  
   694  			if copyas(&p.To, v) {
   695  				return 3
   696  			}
   697  		} else if p.To.Type == obj.TYPE_MEM {
   698  			if copyas(&p.To, v) {
   699  				return 2
   700  			}
   701  			if s != nil {
   702  				if copysub(&p.From, v, s, true) {
   703  					return 1
   704  				}
   705  				return 0
   706  			}
   707  
   708  			if copyau(&p.From, v) {
   709  				return 1
   710  			}
   711  		} else {
   712  			fmt.Printf("copyu: bad %v\n", p)
   713  		}
   714  
   715  		return 0
   716  
   717  	case ppc64.ARLWMI, /* read p->from, read p->reg, rar p->to */
   718  		ppc64.ARLWMICC:
   719  		if copyas(&p.To, v) {
   720  			return 2
   721  		}
   722  		fallthrough
   723  
   724  		/* fall through */
   725  	case ppc64.AADD,
   726  		/* read p->from, read p->reg, write p->to */
   727  		ppc64.AADDC,
   728  		ppc64.AADDE,
   729  		ppc64.ASUB,
   730  		ppc64.ASLW,
   731  		ppc64.ASRW,
   732  		ppc64.ASRAW,
   733  		ppc64.ASLD,
   734  		ppc64.ASRD,
   735  		ppc64.ASRAD,
   736  		ppc64.AOR,
   737  		ppc64.AORCC,
   738  		ppc64.AORN,
   739  		ppc64.AORNCC,
   740  		ppc64.AAND,
   741  		ppc64.AANDCC,
   742  		ppc64.AANDN,
   743  		ppc64.AANDNCC,
   744  		ppc64.ANAND,
   745  		ppc64.ANANDCC,
   746  		ppc64.ANOR,
   747  		ppc64.ANORCC,
   748  		ppc64.AXOR,
   749  		ppc64.AMULHW,
   750  		ppc64.AMULHWU,
   751  		ppc64.AMULLW,
   752  		ppc64.AMULLD,
   753  		ppc64.ADIVW,
   754  		ppc64.ADIVD,
   755  		ppc64.ADIVWU,
   756  		ppc64.ADIVDU,
   757  		ppc64.AREM,
   758  		ppc64.AREMU,
   759  		ppc64.AREMD,
   760  		ppc64.AREMDU,
   761  		ppc64.ARLWNM,
   762  		ppc64.ARLWNMCC,
   763  		ppc64.AFADDS,
   764  		ppc64.AFADD,
   765  		ppc64.AFSUBS,
   766  		ppc64.AFSUB,
   767  		ppc64.AFMULS,
   768  		ppc64.AFMUL,
   769  		ppc64.AFDIVS,
   770  		ppc64.AFDIV:
   771  		if s != nil {
   772  			if copysub(&p.From, v, s, true) {
   773  				return 1
   774  			}
   775  			if copysub1(p, v, s, true) {
   776  				return 1
   777  			}
   778  
   779  			// Update only indirect uses of v in p->to
   780  			if !copyas(&p.To, v) {
   781  				if copysub(&p.To, v, s, true) {
   782  					return 1
   783  				}
   784  			}
   785  			return 0
   786  		}
   787  
   788  		if copyas(&p.To, v) {
   789  			if p.Reg == 0 {
   790  				// Fix up implicit reg (e.g., ADD
   791  				// R3,R4 -> ADD R3,R4,R4) so we can
   792  				// update reg and to separately.
   793  				p.Reg = p.To.Reg
   794  			}
   795  
   796  			if copyau(&p.From, v) {
   797  				return 4
   798  			}
   799  			if copyau1(p, v) {
   800  				return 4
   801  			}
   802  			return 3
   803  		}
   804  
   805  		if copyau(&p.From, v) {
   806  			return 1
   807  		}
   808  		if copyau1(p, v) {
   809  			return 1
   810  		}
   811  		if copyau(&p.To, v) {
   812  			return 1
   813  		}
   814  		return 0
   815  
   816  	case ppc64.ABEQ,
   817  		ppc64.ABGT,
   818  		ppc64.ABGE,
   819  		ppc64.ABLT,
   820  		ppc64.ABLE,
   821  		ppc64.ABNE,
   822  		ppc64.ABVC,
   823  		ppc64.ABVS:
   824  		return 0
   825  
   826  	case obj.ACHECKNIL, /* read p->from */
   827  		ppc64.ACMP, /* read p->from, read p->to */
   828  		ppc64.ACMPU,
   829  		ppc64.ACMPW,
   830  		ppc64.ACMPWU,
   831  		ppc64.AFCMPO,
   832  		ppc64.AFCMPU:
   833  		if s != nil {
   834  			if copysub(&p.From, v, s, true) {
   835  				return 1
   836  			}
   837  			if copysub(&p.To, v, s, true) {
   838  				return 1
   839  			}
   840  			return 0
   841  		}
   842  
   843  		if copyau(&p.From, v) {
   844  			return 1
   845  		}
   846  		if copyau(&p.To, v) {
   847  			return 1
   848  		}
   849  		return 0
   850  
   851  		// 9g never generates a branch to a GPR (this isn't
   852  	// even a normal instruction; liblink turns it in to a
   853  	// mov and a branch).
   854  	case ppc64.ABR: /* read p->to */
   855  		if s != nil {
   856  			if copysub(&p.To, v, s, true) {
   857  				return 1
   858  			}
   859  			return 0
   860  		}
   861  
   862  		if copyau(&p.To, v) {
   863  			return 1
   864  		}
   865  		return 0
   866  
   867  	case obj.ARET: /* funny */
   868  		if s != nil {
   869  			return 0
   870  		}
   871  
   872  		// All registers die at this point, so claim
   873  		// everything is set (and not used).
   874  		return 3
   875  
   876  	case ppc64.ABL: /* funny */
   877  		if v.Type == obj.TYPE_REG {
   878  			// TODO(rsc): REG_R0 and REG_F0 used to be
   879  			// (when register numbers started at 0) exregoffset and exfregoffset,
   880  			// which are unset entirely.
   881  			// It's strange that this handles R0 and F0 differently from the other
   882  			// registers. Possible failure to optimize?
   883  			if ppc64.REG_R0 < v.Reg && v.Reg <= ppc64.REGEXT {
   884  				return 2
   885  			}
   886  			if v.Reg == ppc64.REGARG {
   887  				return 2
   888  			}
   889  			if ppc64.REG_F0 < v.Reg && v.Reg <= ppc64.FREGEXT {
   890  				return 2
   891  			}
   892  		}
   893  
   894  		if p.From.Type == obj.TYPE_REG && v.Type == obj.TYPE_REG && p.From.Reg == v.Reg {
   895  			return 2
   896  		}
   897  
   898  		if s != nil {
   899  			if copysub(&p.To, v, s, true) {
   900  				return 1
   901  			}
   902  			return 0
   903  		}
   904  		if copyau(&p.To, v) {
   905  			return 4
   906  		}
   907  		return 3
   908  
   909  		// R0 is zero, used by DUFFZERO, cannot be substituted.
   910  	// R3 is ptr to memory, used and set, cannot be substituted.
   911  	case obj.ADUFFZERO:
   912  		if v.Type == obj.TYPE_REG {
   913  			if v.Reg == 0 {
   914  				return 1
   915  			}
   916  			if v.Reg == 3 {
   917  				return 2
   918  			}
   919  		}
   920  
   921  		return 0
   922  
   923  		// R3, R4 are ptr to src, dst, used and set, cannot be substituted.
   924  	// R5 is scratch, set by DUFFCOPY, cannot be substituted.
   925  	case obj.ADUFFCOPY:
   926  		if v.Type == obj.TYPE_REG {
   927  			if v.Reg == 3 || v.Reg == 4 {
   928  				return 2
   929  			}
   930  			if v.Reg == 5 {
   931  				return 3
   932  			}
   933  		}
   934  
   935  		return 0
   936  
   937  	case obj.ATEXT: /* funny */
   938  		if v.Type == obj.TYPE_REG {
   939  			if v.Reg == ppc64.REGARG {
   940  				return 3
   941  			}
   942  		}
   943  		return 0
   944  
   945  	case obj.APCDATA,
   946  		obj.AFUNCDATA,
   947  		obj.AVARDEF,
   948  		obj.AVARKILL,
   949  		obj.AVARLIVE,
   950  		obj.AUSEFIELD:
   951  		return 0
   952  	}
   953  }
   954  
   955  // copyas returns true if a and v address the same register.
   956  //
   957  // If a is the from operand, this means this operation reads the
   958  // register in v. If a is the to operand, this means this operation
   959  // writes the register in v.
   960  func copyas(a *obj.Addr, v *obj.Addr) bool {
   961  	return regtyp(v) && a.Type == v.Type && a.Reg == v.Reg
   962  }
   963  
   964  // copyau returns true if a either directly or indirectly addresses the
   965  // same register as v.
   966  //
   967  // If a is the from operand, this means this operation reads the
   968  // register in v. If a is the to operand, this means the operation
   969  // either reads or writes the register in v (if !copyas(a, v), then
   970  // the operation reads the register in v).
   971  func copyau(a *obj.Addr, v *obj.Addr) bool {
   972  	if copyas(a, v) {
   973  		return true
   974  	}
   975  	if v.Type == obj.TYPE_REG {
   976  		if a.Type == obj.TYPE_MEM || (a.Type == obj.TYPE_ADDR && a.Reg != 0) {
   977  			if v.Reg == a.Reg {
   978  				return true
   979  			}
   980  		}
   981  	}
   982  	return false
   983  }
   984  
   985  // copyau1 returns true if p->reg references the same register as v and v
   986  // is a direct reference.
   987  func copyau1(p *obj.Prog, v *obj.Addr) bool {
   988  	return regtyp(v) && v.Reg != 0 && p.Reg == v.Reg
   989  }
   990  
   991  // copysub replaces v with s in a if f==true or indicates it if could if f==false.
   992  // Returns true on failure to substitute (it always succeeds on ppc64).
   993  // TODO(dfc) remove unused return value and callers where f=false.
   994  func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
   995  	if f && copyau(a, v) {
   996  		a.Reg = s.Reg
   997  	}
   998  	return false
   999  }
  1000  
  1001  // copysub1 replaces v with s in p1->reg if f==true or indicates if it could if f==false.
  1002  // Returns true on failure to substitute (it always succeeds on ppc64).
  1003  // TODO(dfc) remove unused return value and callers where f=false.
  1004  func copysub1(p1 *obj.Prog, v *obj.Addr, s *obj.Addr, f bool) bool {
  1005  	if f && copyau1(p1, v) {
  1006  		p1.Reg = s.Reg
  1007  	}
  1008  	return false
  1009  }
  1010  
  1011  func sameaddr(a *obj.Addr, v *obj.Addr) bool {
  1012  	if a.Type != v.Type {
  1013  		return false
  1014  	}
  1015  	if regtyp(v) && a.Reg == v.Reg {
  1016  		return true
  1017  	}
  1018  	if v.Type == obj.NAME_AUTO || v.Type == obj.NAME_PARAM {
  1019  		if v.Offset == a.Offset {
  1020  			return true
  1021  		}
  1022  	}
  1023  	return false
  1024  }
  1025  
  1026  func smallindir(a *obj.Addr, reg *obj.Addr) bool {
  1027  	return reg.Type == obj.TYPE_REG && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && 0 <= a.Offset && a.Offset < 4096
  1028  }
  1029  
  1030  func stackaddr(a *obj.Addr) bool {
  1031  	return a.Type == obj.TYPE_REG && a.Reg == ppc64.REGSP
  1032  }