github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/bootstrap6g/peep.go (about)

     1  // Do not edit. Bootstrap copy of /Users/rsc/g/go/src/cmd/6g/peep.go
     2  
     3  // Derived from Inferno utils/6c/peep.c
     4  // http://code.google.com/p/inferno-os/source/browse/utils/6c/peep.c
     5  //
     6  //	Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
     7  //	Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
     8  //	Portions Copyright © 1997-1999 Vita Nuova Limited
     9  //	Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
    10  //	Portions Copyright © 2004,2006 Bruce Ellis
    11  //	Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
    12  //	Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
    13  //	Portions Copyright © 2009 The Go Authors.  All rights reserved.
    14  //
    15  // Permission is hereby granted, free of charge, to any person obtaining a copy
    16  // of this software and associated documentation files (the "Software"), to deal
    17  // in the Software without restriction, including without limitation the rights
    18  // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
    19  // copies of the Software, and to permit persons to whom the Software is
    20  // furnished to do so, subject to the following conditions:
    21  //
    22  // The above copyright notice and this permission notice shall be included in
    23  // all copies or substantial portions of the Software.
    24  //
    25  // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
    26  // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
    27  // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
    28  // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
    29  // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
    30  // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
    31  // THE SOFTWARE.
    32  
    33  package main
    34  
    35  import (
    36  	"rsc.io/tmp/bootstrap/internal/gc"
    37  	"rsc.io/tmp/bootstrap/internal/obj"
    38  	"rsc.io/tmp/bootstrap/internal/obj/x86"
    39  	"fmt"
    40  )
    41  
    42  var gactive uint32
    43  
    44  const (
    45  	exregoffset = x86.REG_R15
    46  )
    47  
    48  // do we need the carry bit
    49  func needc(p *obj.Prog) bool {
    50  	for p != nil {
    51  		flags := progcarryflags(p)
    52  		if flags&gc.UseCarry != 0 {
    53  			return true
    54  		}
    55  		if flags&(gc.SetCarry|gc.KillCarry) != 0 {
    56  			return false
    57  		}
    58  		p = p.Link
    59  	}
    60  
    61  	return false
    62  }
    63  
    64  func rnops(r *gc.Flow) *gc.Flow {
    65  	if r != nil {
    66  		var p *obj.Prog
    67  		var r1 *gc.Flow
    68  		for {
    69  			p = r.Prog
    70  			if p.As != obj.ANOP || p.From.Type != obj.TYPE_NONE || p.To.Type != obj.TYPE_NONE {
    71  				break
    72  			}
    73  			r1 = gc.Uniqs(r)
    74  			if r1 == nil {
    75  				break
    76  			}
    77  			r = r1
    78  		}
    79  	}
    80  
    81  	return r
    82  }
    83  
    84  func peep(firstp *obj.Prog) {
    85  	g := (*gc.Graph)(gc.Flowstart(firstp, nil))
    86  	if g == nil {
    87  		return
    88  	}
    89  	gactive = 0
    90  
    91  	// byte, word arithmetic elimination.
    92  	elimshortmov(g)
    93  
    94  	// constant propagation
    95  	// find MOV $con,R followed by
    96  	// another MOV $con,R without
    97  	// setting R in the interim
    98  	var p *obj.Prog
    99  	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
   100  		p = r.Prog
   101  		switch p.As {
   102  		case x86.ALEAL,
   103  			x86.ALEAQ:
   104  			if regtyp(&p.To) {
   105  				if p.From.Sym != nil {
   106  					if p.From.Index == x86.REG_NONE {
   107  						conprop(r)
   108  					}
   109  				}
   110  			}
   111  
   112  		case x86.AMOVB,
   113  			x86.AMOVW,
   114  			x86.AMOVL,
   115  			x86.AMOVQ,
   116  			x86.AMOVSS,
   117  			x86.AMOVSD:
   118  			if regtyp(&p.To) {
   119  				if p.From.Type == obj.TYPE_CONST || p.From.Type == obj.TYPE_FCONST {
   120  					conprop(r)
   121  				}
   122  			}
   123  		}
   124  	}
   125  
   126  	var r *gc.Flow
   127  	var r1 *gc.Flow
   128  	var p1 *obj.Prog
   129  	var t int
   130  loop1:
   131  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   132  		gc.Dumpit("loop1", g.Start, 0)
   133  	}
   134  
   135  	t = 0
   136  	for r = g.Start; r != nil; r = r.Link {
   137  		p = r.Prog
   138  		switch p.As {
   139  		case x86.AMOVL,
   140  			x86.AMOVQ,
   141  			x86.AMOVSS,
   142  			x86.AMOVSD:
   143  			if regtyp(&p.To) {
   144  				if regtyp(&p.From) {
   145  					if copyprop(g, r) {
   146  						excise(r)
   147  						t++
   148  					} else if subprop(r) && copyprop(g, r) {
   149  						excise(r)
   150  						t++
   151  					}
   152  				}
   153  			}
   154  
   155  		case x86.AMOVBLZX,
   156  			x86.AMOVWLZX,
   157  			x86.AMOVBLSX,
   158  			x86.AMOVWLSX:
   159  			if regtyp(&p.To) {
   160  				r1 = rnops(gc.Uniqs(r))
   161  				if r1 != nil {
   162  					p1 = r1.Prog
   163  					if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
   164  						p1.As = x86.AMOVL
   165  						t++
   166  					}
   167  				}
   168  			}
   169  
   170  		case x86.AMOVBQSX,
   171  			x86.AMOVBQZX,
   172  			x86.AMOVWQSX,
   173  			x86.AMOVWQZX,
   174  			x86.AMOVLQSX,
   175  			x86.AMOVLQZX,
   176  			x86.AMOVQL:
   177  			if regtyp(&p.To) {
   178  				r1 = rnops(gc.Uniqs(r))
   179  				if r1 != nil {
   180  					p1 = r1.Prog
   181  					if p.As == p1.As && p.To.Type == p1.From.Type && p.To.Reg == p1.From.Reg {
   182  						p1.As = x86.AMOVQ
   183  						t++
   184  					}
   185  				}
   186  			}
   187  
   188  		case x86.AADDL,
   189  			x86.AADDQ,
   190  			x86.AADDW:
   191  			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
   192  				break
   193  			}
   194  			if p.From.Offset == -1 {
   195  				if p.As == x86.AADDQ {
   196  					p.As = x86.ADECQ
   197  				} else if p.As == x86.AADDL {
   198  					p.As = x86.ADECL
   199  				} else {
   200  					p.As = x86.ADECW
   201  				}
   202  				p.From = obj.Addr{}
   203  				break
   204  			}
   205  
   206  			if p.From.Offset == 1 {
   207  				if p.As == x86.AADDQ {
   208  					p.As = x86.AINCQ
   209  				} else if p.As == x86.AADDL {
   210  					p.As = x86.AINCL
   211  				} else {
   212  					p.As = x86.AINCW
   213  				}
   214  				p.From = obj.Addr{}
   215  				break
   216  			}
   217  
   218  		case x86.ASUBL,
   219  			x86.ASUBQ,
   220  			x86.ASUBW:
   221  			if p.From.Type != obj.TYPE_CONST || needc(p.Link) {
   222  				break
   223  			}
   224  			if p.From.Offset == -1 {
   225  				if p.As == x86.ASUBQ {
   226  					p.As = x86.AINCQ
   227  				} else if p.As == x86.ASUBL {
   228  					p.As = x86.AINCL
   229  				} else {
   230  					p.As = x86.AINCW
   231  				}
   232  				p.From = obj.Addr{}
   233  				break
   234  			}
   235  
   236  			if p.From.Offset == 1 {
   237  				if p.As == x86.ASUBQ {
   238  					p.As = x86.ADECQ
   239  				} else if p.As == x86.ASUBL {
   240  					p.As = x86.ADECL
   241  				} else {
   242  					p.As = x86.ADECW
   243  				}
   244  				p.From = obj.Addr{}
   245  				break
   246  			}
   247  		}
   248  	}
   249  
   250  	if t != 0 {
   251  		goto loop1
   252  	}
   253  
   254  	// MOVLQZX removal.
   255  	// The MOVLQZX exists to avoid being confused for a
   256  	// MOVL that is just copying 32-bit data around during
   257  	// copyprop.  Now that copyprop is done, remov MOVLQZX R1, R2
   258  	// if it is dominated by an earlier ADDL/MOVL/etc into R1 that
   259  	// will have already cleared the high bits.
   260  	//
   261  	// MOVSD removal.
   262  	// We never use packed registers, so a MOVSD between registers
   263  	// can be replaced by MOVAPD, which moves the pair of float64s
   264  	// instead of just the lower one.  We only use the lower one, but
   265  	// the processor can do better if we do moves using both.
   266  	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
   267  		p = r.Prog
   268  		if p.As == x86.AMOVLQZX {
   269  			if regtyp(&p.From) {
   270  				if p.From.Type == p.To.Type && p.From.Reg == p.To.Reg {
   271  					if prevl(r, int(p.From.Reg)) {
   272  						excise(r)
   273  					}
   274  				}
   275  			}
   276  		}
   277  
   278  		if p.As == x86.AMOVSD {
   279  			if regtyp(&p.From) {
   280  				if regtyp(&p.To) {
   281  					p.As = x86.AMOVAPD
   282  				}
   283  			}
   284  		}
   285  	}
   286  
   287  	// load pipelining
   288  	// push any load from memory as early as possible
   289  	// to give it time to complete before use.
   290  	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
   291  		p = r.Prog
   292  		switch p.As {
   293  		case x86.AMOVB,
   294  			x86.AMOVW,
   295  			x86.AMOVL,
   296  			x86.AMOVQ,
   297  			x86.AMOVLQZX:
   298  			if regtyp(&p.To) && !regconsttyp(&p.From) {
   299  				pushback(r)
   300  			}
   301  		}
   302  	}
   303  
   304  	gc.Flowend(g)
   305  }
   306  
   307  func pushback(r0 *gc.Flow) {
   308  	var r *gc.Flow
   309  	var p *obj.Prog
   310  
   311  	var b *gc.Flow
   312  	p0 := (*obj.Prog)(r0.Prog)
   313  	for r = gc.Uniqp(r0); r != nil && gc.Uniqs(r) != nil; r = gc.Uniqp(r) {
   314  		p = r.Prog
   315  		if p.As != obj.ANOP {
   316  			if !regconsttyp(&p.From) || !regtyp(&p.To) {
   317  				break
   318  			}
   319  			if copyu(p, &p0.To, nil) != 0 || copyu(p0, &p.To, nil) != 0 {
   320  				break
   321  			}
   322  		}
   323  
   324  		if p.As == obj.ACALL {
   325  			break
   326  		}
   327  		b = r
   328  	}
   329  
   330  	if b == nil {
   331  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   332  			fmt.Printf("no pushback: %v\n", r0.Prog)
   333  			if r != nil {
   334  				fmt.Printf("\t%v [%v]\n", r.Prog, gc.Uniqs(r) != nil)
   335  			}
   336  		}
   337  
   338  		return
   339  	}
   340  
   341  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   342  		fmt.Printf("pushback\n")
   343  		for r := (*gc.Flow)(b); ; r = r.Link {
   344  			fmt.Printf("\t%v\n", r.Prog)
   345  			if r == r0 {
   346  				break
   347  			}
   348  		}
   349  	}
   350  
   351  	t := obj.Prog(*r0.Prog)
   352  	for r = gc.Uniqp(r0); ; r = gc.Uniqp(r) {
   353  		p0 = r.Link.Prog
   354  		p = r.Prog
   355  		p0.As = p.As
   356  		p0.Lineno = p.Lineno
   357  		p0.From = p.From
   358  		p0.To = p.To
   359  
   360  		if r == b {
   361  			break
   362  		}
   363  	}
   364  
   365  	p0 = r.Prog
   366  	p0.As = t.As
   367  	p0.Lineno = t.Lineno
   368  	p0.From = t.From
   369  	p0.To = t.To
   370  
   371  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   372  		fmt.Printf("\tafter\n")
   373  		for r := (*gc.Flow)(b); ; r = r.Link {
   374  			fmt.Printf("\t%v\n", r.Prog)
   375  			if r == r0 {
   376  				break
   377  			}
   378  		}
   379  	}
   380  }
   381  
   382  func excise(r *gc.Flow) {
   383  	p := (*obj.Prog)(r.Prog)
   384  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   385  		fmt.Printf("%v ===delete===\n", p)
   386  	}
   387  
   388  	obj.Nopout(p)
   389  
   390  	gc.Ostats.Ndelmov++
   391  }
   392  
   393  func regtyp(a *obj.Addr) bool {
   394  	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)
   395  }
   396  
   397  // movb elimination.
   398  // movb is simulated by the linker
   399  // when a register other than ax, bx, cx, dx
   400  // is used, so rewrite to other instructions
   401  // when possible.  a movb into a register
   402  // can smash the entire 32-bit register without
   403  // causing any trouble.
   404  //
   405  // TODO: Using the Q forms here instead of the L forms
   406  // seems unnecessary, and it makes the instructions longer.
   407  func elimshortmov(g *gc.Graph) {
   408  	var p *obj.Prog
   409  
   410  	for r := (*gc.Flow)(g.Start); r != nil; r = r.Link {
   411  		p = r.Prog
   412  		if regtyp(&p.To) {
   413  			switch p.As {
   414  			case x86.AINCB,
   415  				x86.AINCW:
   416  				p.As = x86.AINCQ
   417  
   418  			case x86.ADECB,
   419  				x86.ADECW:
   420  				p.As = x86.ADECQ
   421  
   422  			case x86.ANEGB,
   423  				x86.ANEGW:
   424  				p.As = x86.ANEGQ
   425  
   426  			case x86.ANOTB,
   427  				x86.ANOTW:
   428  				p.As = x86.ANOTQ
   429  			}
   430  
   431  			if regtyp(&p.From) || p.From.Type == obj.TYPE_CONST {
   432  				// move or artihmetic into partial register.
   433  				// from another register or constant can be movl.
   434  				// we don't switch to 64-bit arithmetic if it can
   435  				// change how the carry bit is set (and the carry bit is needed).
   436  				switch p.As {
   437  				case x86.AMOVB,
   438  					x86.AMOVW:
   439  					p.As = x86.AMOVQ
   440  
   441  				case x86.AADDB,
   442  					x86.AADDW:
   443  					if !needc(p.Link) {
   444  						p.As = x86.AADDQ
   445  					}
   446  
   447  				case x86.ASUBB,
   448  					x86.ASUBW:
   449  					if !needc(p.Link) {
   450  						p.As = x86.ASUBQ
   451  					}
   452  
   453  				case x86.AMULB,
   454  					x86.AMULW:
   455  					p.As = x86.AMULQ
   456  
   457  				case x86.AIMULB,
   458  					x86.AIMULW:
   459  					p.As = x86.AIMULQ
   460  
   461  				case x86.AANDB,
   462  					x86.AANDW:
   463  					p.As = x86.AANDQ
   464  
   465  				case x86.AORB,
   466  					x86.AORW:
   467  					p.As = x86.AORQ
   468  
   469  				case x86.AXORB,
   470  					x86.AXORW:
   471  					p.As = x86.AXORQ
   472  
   473  				case x86.ASHLB,
   474  					x86.ASHLW:
   475  					p.As = x86.ASHLQ
   476  				}
   477  			} else if p.From.Type != obj.TYPE_REG {
   478  				// explicit zero extension, but don't
   479  				// do that if source is a byte register
   480  				// (only AH can occur and it's forbidden).
   481  				switch p.As {
   482  				case x86.AMOVB:
   483  					p.As = x86.AMOVBQZX
   484  
   485  				case x86.AMOVW:
   486  					p.As = x86.AMOVWQZX
   487  				}
   488  			}
   489  		}
   490  	}
   491  }
   492  
   493  // is 'a' a register or constant?
   494  func regconsttyp(a *obj.Addr) bool {
   495  	if regtyp(a) {
   496  		return true
   497  	}
   498  	switch a.Type {
   499  	case obj.TYPE_CONST,
   500  		obj.TYPE_FCONST,
   501  		obj.TYPE_SCONST,
   502  		obj.TYPE_ADDR: // TODO(rsc): Not all TYPE_ADDRs are constants.
   503  		return true
   504  	}
   505  
   506  	return false
   507  }
   508  
   509  // is reg guaranteed to be truncated by a previous L instruction?
   510  func prevl(r0 *gc.Flow, reg int) bool {
   511  	for r := (*gc.Flow)(gc.Uniqp(r0)); r != nil; r = gc.Uniqp(r) {
   512  		p := r.Prog
   513  		if p.To.Type == obj.TYPE_REG && int(p.To.Reg) == reg {
   514  			flags := progflags(p)
   515  			if flags&gc.RightWrite != 0 {
   516  				if flags&gc.SizeL != 0 {
   517  					return true
   518  				}
   519  				return false
   520  			}
   521  		}
   522  	}
   523  
   524  	return false
   525  }
   526  
   527  /*
   528   * the idea is to substitute
   529   * one register for another
   530   * from one MOV to another
   531   *	MOV	a, R0
   532   *	ADD	b, R0	/ no use of R1
   533   *	MOV	R0, R1
   534   * would be converted to
   535   *	MOV	a, R1
   536   *	ADD	b, R1
   537   *	MOV	R1, R0
   538   * hopefully, then the former or latter MOV
   539   * will be eliminated by copy propagation.
   540   */
   541  func subprop(r0 *gc.Flow) bool {
   542  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   543  		fmt.Printf("subprop %v\n", r0.Prog)
   544  	}
   545  	p := (*obj.Prog)(r0.Prog)
   546  	v1 := (*obj.Addr)(&p.From)
   547  	if !regtyp(v1) {
   548  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   549  			fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v1))
   550  		}
   551  		return false
   552  	}
   553  
   554  	v2 := (*obj.Addr)(&p.To)
   555  	if !regtyp(v2) {
   556  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   557  			fmt.Printf("\tnot regtype %v; return 0\n", gc.Ctxt.Dconv(v2))
   558  		}
   559  		return false
   560  	}
   561  
   562  	for r := gc.Uniqp(r0); r != nil; r = gc.Uniqp(r) {
   563  		if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   564  			fmt.Printf("\t? %v\n", r.Prog)
   565  		}
   566  		if gc.Uniqs(r) == nil {
   567  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   568  				fmt.Printf("\tno unique successor\n")
   569  			}
   570  			break
   571  		}
   572  
   573  		p = r.Prog
   574  		if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
   575  			continue
   576  		}
   577  		if p.Info.Flags&gc.Call != 0 {
   578  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   579  				fmt.Printf("\tfound %v; return 0\n", p)
   580  			}
   581  			return false
   582  		}
   583  
   584  		if p.Info.Reguse|p.Info.Regset != 0 {
   585  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   586  				fmt.Printf("\tfound %v; return 0\n", p)
   587  			}
   588  			return false
   589  		}
   590  
   591  		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 {
   592  			copysub(&p.To, v1, v2, 1)
   593  			if gc.Debug['P'] != 0 {
   594  				fmt.Printf("gotit: %v->%v\n%v", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), r.Prog)
   595  				if p.From.Type == v2.Type && p.From.Reg == v2.Reg {
   596  					fmt.Printf(" excise")
   597  				}
   598  				fmt.Printf("\n")
   599  			}
   600  
   601  			for r = gc.Uniqs(r); r != r0; r = gc.Uniqs(r) {
   602  				p = r.Prog
   603  				copysub(&p.From, v1, v2, 1)
   604  				copysub(&p.To, v1, v2, 1)
   605  				if gc.Debug['P'] != 0 {
   606  					fmt.Printf("%v\n", r.Prog)
   607  				}
   608  			}
   609  
   610  			t := int(int(v1.Reg))
   611  			v1.Reg = v2.Reg
   612  			v2.Reg = int16(t)
   613  			if gc.Debug['P'] != 0 {
   614  				fmt.Printf("%v last\n", r.Prog)
   615  			}
   616  			return true
   617  		}
   618  
   619  		if copyau(&p.From, v2) || copyau(&p.To, v2) {
   620  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   621  				fmt.Printf("\tcopyau %v failed\n", gc.Ctxt.Dconv(v2))
   622  			}
   623  			break
   624  		}
   625  
   626  		if copysub(&p.From, v1, v2, 0) != 0 || copysub(&p.To, v1, v2, 0) != 0 {
   627  			if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   628  				fmt.Printf("\tcopysub failed\n")
   629  			}
   630  			break
   631  		}
   632  	}
   633  
   634  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   635  		fmt.Printf("\tran off end; return 0\n")
   636  	}
   637  	return false
   638  }
   639  
   640  /*
   641   * The idea is to remove redundant copies.
   642   *	v1->v2	F=0
   643   *	(use v2	s/v2/v1/)*
   644   *	set v1	F=1
   645   *	use v2	return fail
   646   *	-----------------
   647   *	v1->v2	F=0
   648   *	(use v2	s/v2/v1/)*
   649   *	set v1	F=1
   650   *	set v2	return success
   651   */
   652  func copyprop(g *gc.Graph, r0 *gc.Flow) bool {
   653  	if gc.Debug['P'] != 0 && gc.Debug['v'] != 0 {
   654  		fmt.Printf("copyprop %v\n", r0.Prog)
   655  	}
   656  	p := (*obj.Prog)(r0.Prog)
   657  	v1 := (*obj.Addr)(&p.From)
   658  	v2 := (*obj.Addr)(&p.To)
   659  	if copyas(v1, v2) {
   660  		return true
   661  	}
   662  	gactive++
   663  	return copy1(v1, v2, r0.S1, 0)
   664  }
   665  
   666  func copy1(v1 *obj.Addr, v2 *obj.Addr, r *gc.Flow, f int) bool {
   667  	if uint32(r.Active) == gactive {
   668  		if gc.Debug['P'] != 0 {
   669  			fmt.Printf("act set; return 1\n")
   670  		}
   671  		return true
   672  	}
   673  
   674  	r.Active = int32(gactive)
   675  	if gc.Debug['P'] != 0 {
   676  		fmt.Printf("copy %v->%v f=%d\n", gc.Ctxt.Dconv(v1), gc.Ctxt.Dconv(v2), f)
   677  	}
   678  	var t int
   679  	var p *obj.Prog
   680  	for ; r != nil; r = r.S1 {
   681  		p = r.Prog
   682  		if gc.Debug['P'] != 0 {
   683  			fmt.Printf("%v", p)
   684  		}
   685  		if f == 0 && gc.Uniqp(r) == nil {
   686  			f = 1
   687  			if gc.Debug['P'] != 0 {
   688  				fmt.Printf("; merge; f=%d", f)
   689  			}
   690  		}
   691  
   692  		t = copyu(p, v2, nil)
   693  		switch t {
   694  		case 2: /* rar, can't split */
   695  			if gc.Debug['P'] != 0 {
   696  				fmt.Printf("; %v rar; return 0\n", gc.Ctxt.Dconv(v2))
   697  			}
   698  			return false
   699  
   700  		case 3: /* set */
   701  			if gc.Debug['P'] != 0 {
   702  				fmt.Printf("; %v set; return 1\n", gc.Ctxt.Dconv(v2))
   703  			}
   704  			return true
   705  
   706  		case 1, /* used, substitute */
   707  			4: /* use and set */
   708  			if f != 0 {
   709  				if gc.Debug['P'] == 0 {
   710  					return false
   711  				}
   712  				if t == 4 {
   713  					fmt.Printf("; %v used+set and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
   714  				} else {
   715  					fmt.Printf("; %v used and f=%d; return 0\n", gc.Ctxt.Dconv(v2), f)
   716  				}
   717  				return false
   718  			}
   719  
   720  			if copyu(p, v2, v1) != 0 {
   721  				if gc.Debug['P'] != 0 {
   722  					fmt.Printf("; sub fail; return 0\n")
   723  				}
   724  				return false
   725  			}
   726  
   727  			if gc.Debug['P'] != 0 {
   728  				fmt.Printf("; sub %v/%v", gc.Ctxt.Dconv(v2), gc.Ctxt.Dconv(v1))
   729  			}
   730  			if t == 4 {
   731  				if gc.Debug['P'] != 0 {
   732  					fmt.Printf("; %v used+set; return 1\n", gc.Ctxt.Dconv(v2))
   733  				}
   734  				return true
   735  			}
   736  		}
   737  
   738  		if f == 0 {
   739  			t = copyu(p, v1, nil)
   740  			if f == 0 && (t == 2 || t == 3 || t == 4) {
   741  				f = 1
   742  				if gc.Debug['P'] != 0 {
   743  					fmt.Printf("; %v set and !f; f=%d", gc.Ctxt.Dconv(v1), f)
   744  				}
   745  			}
   746  		}
   747  
   748  		if gc.Debug['P'] != 0 {
   749  			fmt.Printf("\n")
   750  		}
   751  		if r.S2 != nil {
   752  			if !copy1(v1, v2, r.S2, f) {
   753  				return false
   754  			}
   755  		}
   756  	}
   757  
   758  	return true
   759  }
   760  
   761  /*
   762   * return
   763   * 1 if v only used (and substitute),
   764   * 2 if read-alter-rewrite
   765   * 3 if set
   766   * 4 if set and used
   767   * 0 otherwise (not touched)
   768   */
   769  func copyu(p *obj.Prog, v *obj.Addr, s *obj.Addr) int {
   770  	switch p.As {
   771  	case obj.AJMP:
   772  		if s != nil {
   773  			if copysub(&p.To, v, s, 1) != 0 {
   774  				return 1
   775  			}
   776  			return 0
   777  		}
   778  
   779  		if copyau(&p.To, v) {
   780  			return 1
   781  		}
   782  		return 0
   783  
   784  	case obj.ARET:
   785  		if s != nil {
   786  			return 1
   787  		}
   788  		return 3
   789  
   790  	case obj.ACALL:
   791  		if x86.REGEXT != 0 /*TypeKind(100016)*/ && v.Type == obj.TYPE_REG && v.Reg <= x86.REGEXT && v.Reg > exregoffset {
   792  			return 2
   793  		}
   794  		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
   795  			return 2
   796  		}
   797  		if v.Type == p.From.Type && v.Reg == p.From.Reg {
   798  			return 2
   799  		}
   800  
   801  		if s != nil {
   802  			if copysub(&p.To, v, s, 1) != 0 {
   803  				return 1
   804  			}
   805  			return 0
   806  		}
   807  
   808  		if copyau(&p.To, v) {
   809  			return 4
   810  		}
   811  		return 3
   812  
   813  	case obj.ATEXT:
   814  		if x86.REGARG >= 0 && v.Type == obj.TYPE_REG && v.Reg == x86.REGARG {
   815  			return 3
   816  		}
   817  		return 0
   818  	}
   819  
   820  	if p.As == obj.AVARDEF || p.As == obj.AVARKILL {
   821  		return 0
   822  	}
   823  
   824  	if (p.Info.Reguse|p.Info.Regset)&RtoB(int(v.Reg)) != 0 {
   825  		return 2
   826  	}
   827  
   828  	if p.Info.Flags&gc.LeftAddr != 0 {
   829  		if copyas(&p.From, v) {
   830  			return 2
   831  		}
   832  	}
   833  
   834  	if p.Info.Flags&(gc.RightRead|gc.RightWrite) == gc.RightRead|gc.RightWrite {
   835  		if copyas(&p.To, v) {
   836  			return 2
   837  		}
   838  	}
   839  
   840  	if p.Info.Flags&gc.RightWrite != 0 {
   841  		if copyas(&p.To, v) {
   842  			if s != nil {
   843  				return copysub(&p.From, v, s, 1)
   844  			}
   845  			if copyau(&p.From, v) {
   846  				return 4
   847  			}
   848  			return 3
   849  		}
   850  	}
   851  
   852  	if p.Info.Flags&(gc.LeftAddr|gc.LeftRead|gc.LeftWrite|gc.RightAddr|gc.RightRead|gc.RightWrite) != 0 {
   853  		if s != nil {
   854  			if copysub(&p.From, v, s, 1) != 0 {
   855  				return 1
   856  			}
   857  			return copysub(&p.To, v, s, 1)
   858  		}
   859  
   860  		if copyau(&p.From, v) {
   861  			return 1
   862  		}
   863  		if copyau(&p.To, v) {
   864  			return 1
   865  		}
   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.Fatal("use of byte register")
   879  	}
   880  	if x86.REG_AL <= v.Reg && v.Reg <= x86.REG_R15B {
   881  		gc.Fatal("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  
   940  	return false
   941  }
   942  
   943  /*
   944   * substitute s for v in a
   945   * return failure to substitute
   946   */
   947  func copysub(a *obj.Addr, v *obj.Addr, s *obj.Addr, f int) int {
   948  	if copyas(a, v) {
   949  		reg := int(int(s.Reg))
   950  		if reg >= x86.REG_AX && reg <= x86.REG_R15 || reg >= x86.REG_X0 && reg <= x86.REG_X0+15 {
   951  			if f != 0 {
   952  				a.Reg = int16(reg)
   953  			}
   954  		}
   955  
   956  		return 0
   957  	}
   958  
   959  	if regtyp(v) {
   960  		reg := int(int(v.Reg))
   961  		if a.Type == obj.TYPE_MEM && int(a.Reg) == reg {
   962  			if (s.Reg == x86.REG_BP || s.Reg == x86.REG_R13) && a.Index != x86.REG_NONE {
   963  				return 1 /* can't use BP-base with index */
   964  			}
   965  			if f != 0 {
   966  				a.Reg = s.Reg
   967  			}
   968  		}
   969  
   970  		//			return 0;
   971  		if int(a.Index) == reg {
   972  			if f != 0 {
   973  				a.Index = s.Reg
   974  			}
   975  			return 0
   976  		}
   977  
   978  		return 0
   979  	}
   980  
   981  	return 0
   982  }
   983  
   984  func conprop(r0 *gc.Flow) {
   985  	var p *obj.Prog
   986  	var t int
   987  
   988  	p0 := (*obj.Prog)(r0.Prog)
   989  	v0 := (*obj.Addr)(&p0.To)
   990  	r := (*gc.Flow)(r0)
   991  
   992  loop:
   993  	r = gc.Uniqs(r)
   994  	if r == nil || r == r0 {
   995  		return
   996  	}
   997  	if gc.Uniqp(r) == nil {
   998  		return
   999  	}
  1000  
  1001  	p = r.Prog
  1002  	t = copyu(p, v0, nil)
  1003  	switch t {
  1004  	case 0, // miss
  1005  		1: // use
  1006  		goto loop
  1007  
  1008  	case 2, // rar
  1009  		4: // use and set
  1010  		break
  1011  
  1012  	case 3: // set
  1013  		if p.As == p0.As {
  1014  			if p.From.Type == p0.From.Type {
  1015  				if p.From.Reg == p0.From.Reg {
  1016  					if p.From.Node == p0.From.Node {
  1017  						if p.From.Offset == p0.From.Offset {
  1018  							if p.From.Scale == p0.From.Scale {
  1019  								if p.From.Type == obj.TYPE_FCONST && p.From.Val.(float64) == p0.From.Val.(float64) {
  1020  									if p.From.Index == p0.From.Index {
  1021  										excise(r)
  1022  										goto loop
  1023  									}
  1024  								}
  1025  							}
  1026  						}
  1027  					}
  1028  				}
  1029  			}
  1030  		}
  1031  	}
  1032  }
  1033  
  1034  func smallindir(a *obj.Addr, reg *obj.Addr) bool {
  1035  	return regtyp(reg) && a.Type == obj.TYPE_MEM && a.Reg == reg.Reg && a.Index == x86.REG_NONE && 0 <= a.Offset && a.Offset < 4096
  1036  }
  1037  
  1038  func stackaddr(a *obj.Addr) bool {
  1039  	return a.Type == obj.TYPE_REG && a.Reg == x86.REG_SP
  1040  }