github.com/mh-cbon/go@v0.0.0-20160603070303-9e112a3fe4c0/src/cmd/compile/internal/amd64/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 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.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 := 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 := 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, 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 := 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 := 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 := b; ; r = r.Link {
   342  			fmt.Printf("\t%v\n", r.Prog)
   343  			if r == r0 {
   344  				break
   345  			}
   346  		}
   347  	}
   348  
   349  	t := *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 := 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 := 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 := 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 arithmetic 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 int16) bool {
   509  	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
   510  		p := r.Prog
   511  		if p.To.Type == obj.TYPE_REG && 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  	return false
   522  }
   523  
   524  /*
   525   * the idea is to substitute
   526   * one register for another
   527   * from one MOV to another
   528   *	MOV	a, R0
   529   *	ADD	b, R0	/ no use of R1
   530   *	MOV	R0, R1
   531   * would be converted to
   532   *	MOV	a, R1
   533   *	ADD	b, R1
   534   *	MOV	R1, R0
   535   * hopefully, then the former or latter MOV
   536   * will be eliminated by copy propagation.
   537   */
   538  func subprop(r0 *gc.Flow) bool {
   539  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   540  		fmt.Printf("subprop %v\n", r0.Prog)
   541  	}
   542  	p := r0.Prog
   543  	v1 := &p.From
   544  	if !regtyp(v1) {
   545  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   546  			fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v1))
   547  		}
   548  		return false
   549  	}
   550  
   551  	v2 := &p.To
   552  	if !regtyp(v2) {
   553  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   554  			fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v2))
   555  		}
   556  		return false
   557  	}
   558  
   559  	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
   560  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   561  			fmt.Printf("\t? %v\n", r.Prog)
   562  		}
   563  		if gc.Uniqs(r) == nil {
   564  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   565  				fmt.Printf("\tno unique successor\n")
   566  			}
   567  			break
   568  		}
   569  
   570  		p = r.Prog
   571  		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
   572  			continue
   573  		}
   574  		if p.Info.Flags&gc.Call != 0 {
   575  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   576  				fmt.Printf("\tfound %v; return 0\n", p)
   577  			}
   578  			return false
   579  		}
   580  
   581  		if p.Info.Reguse|p.Info.Regset != 0 {
   582  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   583  				fmt.Printf("\tfound %v; return 0\n", p)
   584  			}
   585  			return false
   586  		}
   587  
   588  		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 {
   589  			copysub(&p.To, v1, v2, true)
   590  			if gc.Debug['P'] != 0 {
   591  				fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
   592  				if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
   593  					fmt.Printf(" excise")
   594  				}
   595  				fmt.Printf("\n")
   596  			}
   597  
   598  			for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
   599  				p = r.Prog
   600  				copysub(&p.From, v1, v2, true)
   601  				copysub(&p.To, v1, v2, true)
   602  				if gc.Debug['P'] != 0 {
   603  					fmt.Printf("%v\n", r.Prog)
   604  				}
   605  			}
   606  
   607  			v1.Reg, v2.Reg = v2.Reg, v1.Reg
   608  			if gc.Debug['P'] != 0 {
   609  				fmt.Printf("%v last\n", r.Prog)
   610  			}
   611  			return true
   612  		}
   613  
   614  		if copyau(&p.From, v2) || copyau(&p.To, v2) {
   615  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   616  				fmt.Printf("\tcopyau %v failed\n", gc.Ctxt.Dconv(v2))
   617  			}
   618  			break
   619  		}
   620  
   621  		if copysub(&p.From, v1, v2, false) || copysub(&p.To, v1, v2, false) {
   622  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   623  				fmt.Printf("\tcopysub failed\n")
   624  			}
   625  			break
   626  		}
   627  	}
   628  
   629  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   630  		fmt.Printf("\tran off end; return 0\n")
   631  	}
   632  	return false
   633  }
   634  
   635  /*
   636   * The idea is to remove redundant copies.
   637   *	v1->v2	F=0
   638   *	(use v2	s/v2/v1/)*
   639   *	set v1	F=1
   640   *	use v2	return fail
   641   *	-----------------
   642   *	v1->v2	F=0
   643   *	(use v2	s/v2/v1/)*
   644   *	set v1	F=1
   645   *	set v2	return success
   646   */
   647  func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
   648  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   649  		fmt.Printf("copyprop %v\n", r0.Prog)
   650  	}
   651  	p := r0.Prog
   652  	v1 := &p.From
   653  	v2 := &p.To
   654  	if copyas(v1, v2) {
   655  		return true
   656  	}
   657  	gactive++
   658  	return copy1(v1, v2, r0.S1, false)
   659  }
   660  
   661  func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f bool) bool {
   662  	if uint32(r.Active) == gactive {
   663  		if gc.Debug['P'] != 0 {
   664  			fmt.Printf("act set; return 1\n")
   665  		}
   666  		return true
   667  	}
   668  
   669  	r.Active = int32(gactive)
   670  	if gc.Debug['P'] != 0 {
   671  		fmt.Printf("copy %v->%v f=%v\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
   672  	}
   673  	for ; r != nil; r = r.S1 {
   674  		p := r.Prog
   675  		if gc.Debug['P'] != 0 {
   676  			fmt.Printf("%v", p)
   677  		}
   678  		if !f && gc.Uniqp(r) == nil {
   679  			f = true
   680  			if gc.Debug['P'] != 0 {
   681  				fmt.Printf("; merge; f=%v", f)
   682  			}
   683  		}
   684  
   685  		switch t := copyu(p, v2, nil); t {
   686  		case 2: /* rar, can't split */
   687  			if gc.Debug['P'] != 0 {
   688  				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
   689  			}
   690  			return false
   691  
   692  		case 3: /* set */
   693  			if gc.Debug['P'] != 0 {
   694  				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
   695  			}
   696  			return true
   697  
   698  		case 1, /* used, substitute */
   699  			4: /* use and set */
   700  			if f {
   701  				if gc.Debug['P'] == 0 {
   702  					return false
   703  				}
   704  				if t == 4 {
   705  					fmt.Printf("; %v used+set and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
   706  				} else {
   707  					fmt.Printf("; %v used and f=%v; return 0\n", gc.Ctxt.Dconv(v2), f)
   708  				}
   709  				return false
   710  			}
   711  
   712  			if copyu(p, v2, v1) != 0 {
   713  				if gc.Debug['P'] != 0 {
   714  					fmt.Printf("; sub fail; return 0\n")
   715  				}
   716  				return false
   717  			}
   718  
   719  			if gc.Debug['P'] != 0 {
   720  				fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
   721  			}
   722  			if t == 4 {
   723  				if gc.Debug['P'] != 0 {
   724  					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
   725  				}
   726  				return true
   727  			}
   728  		}
   729  
   730  		if !f {
   731  			t := copyu(p, v1, nil)
   732  			if t == 2 || t == 3 || t == 4 {
   733  				f = true
   734  				if gc.Debug['P'] != 0 {
   735  					fmt.Printf("; %v set and !f; f=%v", gc.Ctxt.Dconv(v1), f)
   736  				}
   737  			}
   738  		}
   739  
   740  		if gc.Debug['P'] != 0 {
   741  			fmt.Printf("\n")
   742  		}
   743  		if r.S2 != nil {
   744  			if !copy1(v1, v2, r.S2, f) {
   745  				return false
   746  			}
   747  		}
   748  	}
   749  	return true
   750  }
   751  
   752  /*
   753   * return
   754   * 1 if v only used (and substitute),
   755   * 2 if read-alter-rewrite
   756   * 3 if set
   757   * 4 if set and used
   758   * 0 otherwise (not touched)
   759   */
   760  func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
   761  	switch p.As {
   762  	case obj.AJMP:
   763  		if s != nil {
   764  			if copysub(&p.To, v, s, true) {
   765  				return 1
   766  			}
   767  			return 0
   768  		}
   769  
   770  		if copyau(&p.To, v) {
   771  			return 1
   772  		}
   773  		return 0
   774  
   775  	case obj.ARET:
   776  		if s != nil {
   777  			return 1
   778  		}
   779  		return 3
   780  
   781  	case obj.ACALL:
   782  		if x86.REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= x86.REGEXT && v.Reg > exregoffset {
   783  			return 2
   784  		}
   785  		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
   786  			return 2
   787  		}
   788  		if v.Type == p.From.Type && v.Reg == p.From.Reg {
   789  			return 2
   790  		}
   791  
   792  		if s != nil {
   793  			if copysub(&p.To, v, s, true) {
   794  				return 1
   795  			}
   796  			return 0
   797  		}
   798  
   799  		if copyau(&p.To, v) {
   800  			return 4
   801  		}
   802  		return 3
   803  
   804  	case obj.ATEXT:
   805  		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
   806  			return 3
   807  		}
   808  		return 0
   809  	}
   810  
   811  	if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
   812  		return 0
   813  	}
   814  
   815  	if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
   816  		return 2
   817  	}
   818  
   819  	if (p.Info.Reguse|p.Info.Regset)&FtoB(int(v.Reg)) != 0 {
   820  		return 2
   821  	}
   822  
   823  	if p.Info.Flags&gc.LeftAddr != 0 {
   824  		if copyas(&p.From, v) {
   825  			return 2
   826  		}
   827  	}
   828  
   829  	if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
   830  		if copyas(&p.To, v) {
   831  			return 2
   832  		}
   833  	}
   834  
   835  	if p.Info.Flags&gc.RightWrite != 0 {
   836  		if copyas(&p.To, v) {
   837  			if s != nil {
   838  				if copysub(&p.From, v, s, true) {
   839  					return 1
   840  				}
   841  				return 0
   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, true) {
   853  				return 1
   854  			}
   855  			if copysub(&p.To, v, s, true) {
   856  				return 1
   857  			}
   858  			return 0
   859  		}
   860  
   861  		if copyau(&p.From, v) {
   862  			return 1
   863  		}
   864  		if copyau(&p.To, v) {
   865  			return 1
   866  		}
   867  	}
   868  	return 0
   869  }
   870  
   871  /*
   872   * direct reference,
   873   * could be set/use depending on
   874   * semantics
   875   */
   876  func copyas(a *obj.Addr, v *obj.Addr) bool {
   877  	if x86.REG_AL <= a.Reg && a.Reg <= x86.REG_R15B {
   878  		gc.Fatalf("use of byte register")
   879  	}
   880  	if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_R15B {
   881  		gc.Fatalf("use of byte register")
   882  	}
   883  
   884  	if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
   885  		return false
   886  	}
   887  	if regtyp(v) {
   888  		return true
   889  	}
   890  	if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
   891  		if v.Offset == a.Offset {
   892  			return true
   893  		}
   894  	}
   895  	return false
   896  }
   897  
   898  func sameaddr(a *obj.Addr, v *obj.Addr) bool {
   899  	if a.Type != v.Type || a.Name != v.Name || a.Reg != v.Reg {
   900  		return false
   901  	}
   902  	if regtyp(v) {
   903  		return true
   904  	}
   905  	if v.Type == obj.TYPE_MEM && (v.Name == obj.NAME_AUTO || v.Name == obj.NAME_PARAM) {
   906  		if v.Offset == a.Offset {
   907  			return true
   908  		}
   909  	}
   910  	return false
   911  }
   912  
   913  /*
   914   * either direct or indirect
   915   */
   916  func copyau(a *obj.Addr, v *obj.Addr) bool {
   917  	if copyas(a, v) {
   918  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   919  			fmt.Printf("\tcopyau: copyas returned 1\n")
   920  		}
   921  		return true
   922  	}
   923  
   924  	if regtyp(v) {
   925  		if a.Type == obj.TYPE_MEM && a.Reg == v.Reg {
   926  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   927  				fmt.Printf("\tcopyau: found indir use - return 1\n")
   928  			}
   929  			return true
   930  		}
   931  
   932  		if a.Index == v.Reg {
   933  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   934  				fmt.Printf("\tcopyau: found index use - return 1\n")
   935  			}
   936  			return true
   937  		}
   938  	}
   939  	return false
   940  }
   941  
   942  // copysub substitute s for v in a.
   943  // copysub returns true on failure to substitute. TODO(dfc) reverse this logic, copysub should return false on failure
   944  func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f bool) bool {
   945  	if copyas(a, v) {
   946  		if s.Reg >= x86.REG_AX && s.Reg <= x86.REG_R15 || s.Reg >= x86.REG_X0 && s.Reg <= x86.REG_X0+15 {
   947  			if f {
   948  				a.Reg = s.Reg
   949  			}
   950  		}
   951  		return false
   952  	}
   953  
   954  	if regtyp(v) {
   955  		if a.Type == obj.TYPE_MEM && a.Reg == v.Reg {
   956  			if (s.Reg == x86.REG_BP || s.Reg == x86.REG_R13) && a.Index != x86.REG_NONE {
   957  				return true /* can't use BP-base with index */
   958  			}
   959  			if f {
   960  				a.Reg = s.Reg
   961  			}
   962  		}
   963  		if a.Index == v.Reg {
   964  			if f {
   965  				a.Index = s.Reg
   966  			}
   967  		}
   968  	}
   969  	return false
   970  }
   971  
   972  func conprop(r0 *gc.Flow) {
   973  	p0 := r0.Prog
   974  	v0 := &p0.To
   975  	r := r0
   976  
   977  loop:
   978  	r = gc.Uniqs(r)
   979  	if r == nil || r == r0 {
   980  		return
   981  	}
   982  	if gc.Uniqp(r) == nil {
   983  		return
   984  	}
   985  
   986  	p := r.Prog
   987  	t := copyu(p, v0, nil)
   988  	switch t {
   989  	case 0, // miss
   990  		1: // use
   991  		goto loop
   992  
   993  	case 2, // rar
   994  		4: // use and set
   995  		break
   996  
   997  	case 3: // set
   998  		if p.As == p0.As {
   999  			if p.From.Type == p0.From.Type {
  1000  				if p.From.Reg == p0.From.Reg {
  1001  					if p.From.Node == p0.From.Node {
  1002  						if p.From.Offset == p0.From.Offset {
  1003  							if p.From.Scale == p0.From.Scale {
  1004  								if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) {
  1005  									if p.From.Index == p0.From.Index {
  1006  										excise(r)
  1007  										goto loop
  1008  									}
  1009  								}
  1010  							}
  1011  						}
  1012  					}
  1013  				}
  1014  			}
  1015  		}
  1016  	}
  1017  }
  1018  
  1019  func smallindir(a *obj.Addr, reg *obj.Addr) bool {
  1020  	return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096
  1021  }
  1022  
  1023  func stackaddr(a *obj.Addr) bool {
  1024  	return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP
  1025  }