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