github.com/huandu/go@v0.0.0-20151114150818-04e615e41150/src/cmd/compile/internal/gc/popt.go (about)

     1  // Derived from Inferno utils/6c/gc.h
     2  // http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
     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  // "Portable" optimizations.
    32  
    33  package gc
    34  
    35  import (
    36  	"cmd/internal/obj"
    37  	"fmt"
    38  	"sort"
    39  	"strings"
    40  )
    41  
    42  type OptStats struct {
    43  	Ncvtreg int32
    44  	Nspill  int32
    45  	Nreload int32
    46  	Ndelmov int32
    47  	Nvar    int32
    48  	Naddr   int32
    49  }
    50  
    51  var Ostats OptStats
    52  
    53  var noreturn_symlist [10]*Sym
    54  
    55  // p is a call instruction. Does the call fail to return?
    56  func Noreturn(p *obj.Prog) bool {
    57  	if noreturn_symlist[0] == nil {
    58  		noreturn_symlist[0] = Pkglookup("panicindex", Runtimepkg)
    59  		noreturn_symlist[1] = Pkglookup("panicslice", Runtimepkg)
    60  		noreturn_symlist[2] = Pkglookup("throwinit", Runtimepkg)
    61  		noreturn_symlist[3] = Pkglookup("gopanic", Runtimepkg)
    62  		noreturn_symlist[4] = Pkglookup("panicwrap", Runtimepkg)
    63  		noreturn_symlist[5] = Pkglookup("throwreturn", Runtimepkg)
    64  		noreturn_symlist[6] = Pkglookup("selectgo", Runtimepkg)
    65  		noreturn_symlist[7] = Pkglookup("block", Runtimepkg)
    66  	}
    67  
    68  	if p.To.Node == nil {
    69  		return false
    70  	}
    71  	s := ((p.To.Node).(*Node)).Sym
    72  	if s == nil {
    73  		return false
    74  	}
    75  	for i := 0; noreturn_symlist[i] != nil; i++ {
    76  		if s == noreturn_symlist[i] {
    77  			return true
    78  		}
    79  	}
    80  	return false
    81  }
    82  
    83  // JMP chasing and removal.
    84  //
    85  // The code generator depends on being able to write out jump
    86  // instructions that it can jump to now but fill in later.
    87  // the linker will resolve them nicely, but they make the code
    88  // longer and more difficult to follow during debugging.
    89  // Remove them.
    90  
    91  /* what instruction does a JMP to p eventually land on? */
    92  func chasejmp(p *obj.Prog, jmploop *int) *obj.Prog {
    93  	n := 0
    94  	for p != nil && p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH {
    95  		n++
    96  		if n > 10 {
    97  			*jmploop = 1
    98  			break
    99  		}
   100  
   101  		p = p.To.Val.(*obj.Prog)
   102  	}
   103  
   104  	return p
   105  }
   106  
   107  /*
   108   * reuse reg pointer for mark/sweep state.
   109   * leave reg==nil at end because alive==nil.
   110   */
   111  var alive interface{} = nil
   112  var dead interface{} = 1
   113  
   114  /* mark all code reachable from firstp as alive */
   115  func mark(firstp *obj.Prog) {
   116  	for p := firstp; p != nil; p = p.Link {
   117  		if p.Opt != dead {
   118  			break
   119  		}
   120  		p.Opt = alive
   121  		if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil {
   122  			mark(p.To.Val.(*obj.Prog))
   123  		}
   124  		if p.As == obj.AJMP || p.As == obj.ARET || p.As == obj.AUNDEF {
   125  			break
   126  		}
   127  	}
   128  }
   129  
   130  func fixjmp(firstp *obj.Prog) {
   131  	if Debug['R'] != 0 && Debug['v'] != 0 {
   132  		fmt.Printf("\nfixjmp\n")
   133  	}
   134  
   135  	// pass 1: resolve jump to jump, mark all code as dead.
   136  	jmploop := 0
   137  
   138  	for p := firstp; p != nil; p = p.Link {
   139  		if Debug['R'] != 0 && Debug['v'] != 0 {
   140  			fmt.Printf("%v\n", p)
   141  		}
   142  		if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.AJMP {
   143  			p.To.Val = chasejmp(p.To.Val.(*obj.Prog), &jmploop)
   144  			if Debug['R'] != 0 && Debug['v'] != 0 {
   145  				fmt.Printf("->%v\n", p)
   146  			}
   147  		}
   148  
   149  		p.Opt = dead
   150  	}
   151  
   152  	if Debug['R'] != 0 && Debug['v'] != 0 {
   153  		fmt.Printf("\n")
   154  	}
   155  
   156  	// pass 2: mark all reachable code alive
   157  	mark(firstp)
   158  
   159  	// pass 3: delete dead code (mostly JMPs).
   160  	var last *obj.Prog
   161  
   162  	for p := firstp; p != nil; p = p.Link {
   163  		if p.Opt == dead {
   164  			if p.Link == nil && p.As == obj.ARET && last != nil && last.As != obj.ARET {
   165  				// This is the final ARET, and the code so far doesn't have one.
   166  				// Let it stay. The register allocator assumes that all live code in
   167  				// the function can be traversed by starting at all the RET instructions
   168  				// and following predecessor links. If we remove the final RET,
   169  				// this assumption will not hold in the case of an infinite loop
   170  				// at the end of a function.
   171  				// Keep the RET but mark it dead for the liveness analysis.
   172  				p.Mode = 1
   173  			} else {
   174  				if Debug['R'] != 0 && Debug['v'] != 0 {
   175  					fmt.Printf("del %v\n", p)
   176  				}
   177  				continue
   178  			}
   179  		}
   180  
   181  		if last != nil {
   182  			last.Link = p
   183  		}
   184  		last = p
   185  	}
   186  
   187  	last.Link = nil
   188  
   189  	// pass 4: elide JMP to next instruction.
   190  	// only safe if there are no jumps to JMPs anymore.
   191  	if jmploop == 0 {
   192  		var last *obj.Prog
   193  		for p := firstp; p != nil; p = p.Link {
   194  			if p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH && p.To.Val == p.Link {
   195  				if Debug['R'] != 0 && Debug['v'] != 0 {
   196  					fmt.Printf("del %v\n", p)
   197  				}
   198  				continue
   199  			}
   200  
   201  			if last != nil {
   202  				last.Link = p
   203  			}
   204  			last = p
   205  		}
   206  
   207  		last.Link = nil
   208  	}
   209  
   210  	if Debug['R'] != 0 && Debug['v'] != 0 {
   211  		fmt.Printf("\n")
   212  		for p := firstp; p != nil; p = p.Link {
   213  			fmt.Printf("%v\n", p)
   214  		}
   215  		fmt.Printf("\n")
   216  	}
   217  }
   218  
   219  // Control flow analysis. The Flow structures hold predecessor and successor
   220  // information as well as basic loop analysis.
   221  //
   222  //	graph = flowstart(firstp, 0);
   223  //	... use flow graph ...
   224  //	flowend(graph); // free graph
   225  //
   226  // Typical uses of the flow graph are to iterate over all the flow-relevant instructions:
   227  //
   228  //	for(f = graph->start; f != nil; f = f->link)
   229  //
   230  // or, given an instruction f, to iterate over all the predecessors, which is
   231  // f->p1 and this list:
   232  //
   233  //	for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
   234  //
   235  // The size argument to flowstart specifies an amount of zeroed memory
   236  // to allocate in every f->data field, for use by the client.
   237  // If size == 0, f->data will be nil.
   238  
   239  var flowmark int
   240  
   241  // MaxFlowProg is the maximum size program (counted in instructions)
   242  // for which the flow code will build a graph. Functions larger than this limit
   243  // will not have flow graphs and consequently will not be optimized.
   244  const MaxFlowProg = 50000
   245  
   246  func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
   247  	// Count and mark instructions to annotate.
   248  	nf := 0
   249  
   250  	for p := firstp; p != nil; p = p.Link {
   251  		p.Opt = nil // should be already, but just in case
   252  		Thearch.Proginfo(p)
   253  		if p.Info.Flags&Skip != 0 {
   254  			continue
   255  		}
   256  		p.Opt = &flowmark
   257  		nf++
   258  	}
   259  
   260  	if nf == 0 {
   261  		return nil
   262  	}
   263  
   264  	if nf >= MaxFlowProg {
   265  		if Debug['v'] != 0 {
   266  			Warn("%v is too big (%d instructions)", Curfn.Func.Nname.Sym, nf)
   267  		}
   268  		return nil
   269  	}
   270  
   271  	// Allocate annotations and assign to instructions.
   272  	graph := new(Graph)
   273  	ff := make([]Flow, nf)
   274  	start := &ff[0]
   275  	id := 0
   276  	var last *Flow
   277  	for p := firstp; p != nil; p = p.Link {
   278  		if p.Opt == nil {
   279  			continue
   280  		}
   281  		f := &ff[0]
   282  		ff = ff[1:]
   283  		p.Opt = f
   284  		f.Prog = p
   285  		if last != nil {
   286  			last.Link = f
   287  		}
   288  		last = f
   289  		if newData != nil {
   290  			f.Data = newData()
   291  		}
   292  		f.Id = int32(id)
   293  		id++
   294  	}
   295  
   296  	// Fill in pred/succ information.
   297  	var f1 *Flow
   298  	var p *obj.Prog
   299  	for f := start; f != nil; f = f.Link {
   300  		p = f.Prog
   301  		if p.Info.Flags&Break == 0 {
   302  			f1 = f.Link
   303  			f.S1 = f1
   304  			f1.P1 = f
   305  		}
   306  
   307  		if p.To.Type == obj.TYPE_BRANCH {
   308  			if p.To.Val == nil {
   309  				Fatal("pnil %v", p)
   310  			}
   311  			f1 = p.To.Val.(*obj.Prog).Opt.(*Flow)
   312  			if f1 == nil {
   313  				Fatal("fnil %v / %v", p, p.To.Val.(*obj.Prog))
   314  			}
   315  			if f1 == f {
   316  				//fatal("self loop %v", p);
   317  				continue
   318  			}
   319  
   320  			f.S2 = f1
   321  			f.P2link = f1.P2
   322  			f1.P2 = f
   323  		}
   324  	}
   325  
   326  	graph.Start = start
   327  	graph.Num = nf
   328  	return graph
   329  }
   330  
   331  func Flowend(graph *Graph) {
   332  	for f := graph.Start; f != nil; f = f.Link {
   333  		f.Prog.Info.Flags = 0 // drop cached proginfo
   334  		f.Prog.Opt = nil
   335  	}
   336  }
   337  
   338  /*
   339   * find looping structure
   340   *
   341   * 1) find reverse postordering
   342   * 2) find approximate dominators,
   343   *	the actual dominators if the flow graph is reducible
   344   *	otherwise, dominators plus some other non-dominators.
   345   *	See Matthew S. Hecht and Jeffrey D. Ullman,
   346   *	"Analysis of a Simple Algorithm for Global Data Flow Problems",
   347   *	Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
   348   *	Oct. 1-3, 1973, pp.  207-217.
   349   * 3) find all nodes with a predecessor dominated by the current node.
   350   *	such a node is a loop head.
   351   *	recursively, all preds with a greater rpo number are in the loop
   352   */
   353  func postorder(r *Flow, rpo2r []*Flow, n int32) int32 {
   354  	r.Rpo = 1
   355  	r1 := r.S1
   356  	if r1 != nil && r1.Rpo == 0 {
   357  		n = postorder(r1, rpo2r, n)
   358  	}
   359  	r1 = r.S2
   360  	if r1 != nil && r1.Rpo == 0 {
   361  		n = postorder(r1, rpo2r, n)
   362  	}
   363  	rpo2r[n] = r
   364  	n++
   365  	return n
   366  }
   367  
   368  func rpolca(idom []int32, rpo1 int32, rpo2 int32) int32 {
   369  	if rpo1 == -1 {
   370  		return rpo2
   371  	}
   372  	var t int32
   373  	for rpo1 != rpo2 {
   374  		if rpo1 > rpo2 {
   375  			t = rpo2
   376  			rpo2 = rpo1
   377  			rpo1 = t
   378  		}
   379  
   380  		for rpo1 < rpo2 {
   381  			t = idom[rpo2]
   382  			if t >= rpo2 {
   383  				Fatal("bad idom")
   384  			}
   385  			rpo2 = t
   386  		}
   387  	}
   388  
   389  	return rpo1
   390  }
   391  
   392  func doms(idom []int32, r int32, s int32) bool {
   393  	for s > r {
   394  		s = idom[s]
   395  	}
   396  	return s == r
   397  }
   398  
   399  func loophead(idom []int32, r *Flow) bool {
   400  	src := r.Rpo
   401  	if r.P1 != nil && doms(idom, src, r.P1.Rpo) {
   402  		return true
   403  	}
   404  	for r = r.P2; r != nil; r = r.P2link {
   405  		if doms(idom, src, r.Rpo) {
   406  			return true
   407  		}
   408  	}
   409  	return false
   410  }
   411  
   412  func loopmark(rpo2r **Flow, head int32, r *Flow) {
   413  	if r.Rpo < head || r.Active == head {
   414  		return
   415  	}
   416  	r.Active = head
   417  	r.Loop += LOOP
   418  	if r.P1 != nil {
   419  		loopmark(rpo2r, head, r.P1)
   420  	}
   421  	for r = r.P2; r != nil; r = r.P2link {
   422  		loopmark(rpo2r, head, r)
   423  	}
   424  }
   425  
   426  func flowrpo(g *Graph) {
   427  	g.Rpo = make([]*Flow, g.Num)
   428  	idom := make([]int32, g.Num)
   429  
   430  	for r1 := g.Start; r1 != nil; r1 = r1.Link {
   431  		r1.Active = 0
   432  	}
   433  
   434  	rpo2r := g.Rpo
   435  	d := postorder(g.Start, rpo2r, 0)
   436  	nr := int32(g.Num)
   437  	if d > nr {
   438  		Fatal("too many reg nodes %d %d", d, nr)
   439  	}
   440  	nr = d
   441  	var r1 *Flow
   442  	for i := int32(0); i < nr/2; i++ {
   443  		r1 = rpo2r[i]
   444  		rpo2r[i] = rpo2r[nr-1-i]
   445  		rpo2r[nr-1-i] = r1
   446  	}
   447  
   448  	for i := int32(0); i < nr; i++ {
   449  		rpo2r[i].Rpo = i
   450  	}
   451  
   452  	idom[0] = 0
   453  	var me int32
   454  	for i := int32(0); i < nr; i++ {
   455  		r1 = rpo2r[i]
   456  		me = r1.Rpo
   457  		d = -1
   458  
   459  		// rpo2r[r->rpo] == r protects against considering dead code,
   460  		// which has r->rpo == 0.
   461  		if r1.P1 != nil && rpo2r[r1.P1.Rpo] == r1.P1 && r1.P1.Rpo < me {
   462  			d = r1.P1.Rpo
   463  		}
   464  		for r1 = r1.P2; r1 != nil; r1 = r1.P2link {
   465  			if rpo2r[r1.Rpo] == r1 && r1.Rpo < me {
   466  				d = rpolca(idom, d, r1.Rpo)
   467  			}
   468  		}
   469  		idom[i] = d
   470  	}
   471  
   472  	for i := int32(0); i < nr; i++ {
   473  		r1 = rpo2r[i]
   474  		r1.Loop++
   475  		if r1.P2 != nil && loophead(idom, r1) {
   476  			loopmark(&rpo2r[0], i, r1)
   477  		}
   478  	}
   479  
   480  	for r1 := g.Start; r1 != nil; r1 = r1.Link {
   481  		r1.Active = 0
   482  	}
   483  }
   484  
   485  func Uniqp(r *Flow) *Flow {
   486  	r1 := r.P1
   487  	if r1 == nil {
   488  		r1 = r.P2
   489  		if r1 == nil || r1.P2link != nil {
   490  			return nil
   491  		}
   492  	} else if r.P2 != nil {
   493  		return nil
   494  	}
   495  	return r1
   496  }
   497  
   498  func Uniqs(r *Flow) *Flow {
   499  	r1 := r.S1
   500  	if r1 == nil {
   501  		r1 = r.S2
   502  		if r1 == nil {
   503  			return nil
   504  		}
   505  	} else if r.S2 != nil {
   506  		return nil
   507  	}
   508  	return r1
   509  }
   510  
   511  // The compilers assume they can generate temporary variables
   512  // as needed to preserve the right semantics or simplify code
   513  // generation and the back end will still generate good code.
   514  // This results in a large number of ephemeral temporary variables.
   515  // Merge temps with non-overlapping lifetimes and equal types using the
   516  // greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation",
   517  // ACM TOPLAS 1999.
   518  
   519  type TempVar struct {
   520  	node    *Node
   521  	def     *Flow    // definition of temp var
   522  	use     *Flow    // use list, chained through Flow.data
   523  	merge   *TempVar // merge var with this one
   524  	start   int64    // smallest Prog.pc in live range
   525  	end     int64    // largest Prog.pc in live range
   526  	addr    uint8    // address taken - no accurate end
   527  	removed uint8    // removed from program
   528  }
   529  
   530  type startcmp []*TempVar
   531  
   532  func (x startcmp) Len() int {
   533  	return len(x)
   534  }
   535  
   536  func (x startcmp) Swap(i, j int) {
   537  	x[i], x[j] = x[j], x[i]
   538  }
   539  
   540  func (x startcmp) Less(i, j int) bool {
   541  	a := x[i]
   542  	b := x[j]
   543  
   544  	if a.start < b.start {
   545  		return true
   546  	}
   547  	if a.start > b.start {
   548  		return false
   549  	}
   550  
   551  	// Order what's left by id or symbol name,
   552  	// just so that sort is forced into a specific ordering,
   553  	// so that the result of the sort does not depend on
   554  	// the sort implementation.
   555  	if a.def != b.def {
   556  		return int(a.def.Id-b.def.Id) < 0
   557  	}
   558  	if a.node != b.node {
   559  		return stringsCompare(a.node.Sym.Name, b.node.Sym.Name) < 0
   560  	}
   561  	return false
   562  }
   563  
   564  // Is n available for merging?
   565  func canmerge(n *Node) bool {
   566  	return n.Class == PAUTO && strings.HasPrefix(n.Sym.Name, "autotmp")
   567  }
   568  
   569  func mergetemp(firstp *obj.Prog) {
   570  	const (
   571  		debugmerge = 0
   572  	)
   573  
   574  	g := Flowstart(firstp, nil)
   575  	if g == nil {
   576  		return
   577  	}
   578  
   579  	// Build list of all mergeable variables.
   580  	nvar := 0
   581  	for l := Curfn.Func.Dcl; l != nil; l = l.Next {
   582  		if canmerge(l.N) {
   583  			nvar++
   584  		}
   585  	}
   586  
   587  	var_ := make([]TempVar, nvar)
   588  	nvar = 0
   589  	var n *Node
   590  	var v *TempVar
   591  	for l := Curfn.Func.Dcl; l != nil; l = l.Next {
   592  		n = l.N
   593  		if canmerge(n) {
   594  			v = &var_[nvar]
   595  			nvar++
   596  			n.SetOpt(v)
   597  			v.node = n
   598  		}
   599  	}
   600  
   601  	// Build list of uses.
   602  	// We assume that the earliest reference to a temporary is its definition.
   603  	// This is not true of variables in general but our temporaries are all
   604  	// single-use (that's why we have so many!).
   605  	for f := g.Start; f != nil; f = f.Link {
   606  		p := f.Prog
   607  		if p.From.Node != nil && ((p.From.Node).(*Node)).Opt() != nil && p.To.Node != nil && ((p.To.Node).(*Node)).Opt() != nil {
   608  			Fatal("double node %v", p)
   609  		}
   610  		v = nil
   611  		n, _ = p.From.Node.(*Node)
   612  		if n != nil {
   613  			v, _ = n.Opt().(*TempVar)
   614  		}
   615  		if v == nil {
   616  			n, _ = p.To.Node.(*Node)
   617  			if n != nil {
   618  				v, _ = n.Opt().(*TempVar)
   619  			}
   620  		}
   621  		if v != nil {
   622  			if v.def == nil {
   623  				v.def = f
   624  			}
   625  			f.Data = v.use
   626  			v.use = f
   627  			if n == p.From.Node && (p.Info.Flags&LeftAddr != 0) {
   628  				v.addr = 1
   629  			}
   630  		}
   631  	}
   632  
   633  	if debugmerge > 1 && Debug['v'] != 0 {
   634  		Dumpit("before", g.Start, 0)
   635  	}
   636  
   637  	nkill := 0
   638  
   639  	// Special case.
   640  	for i := 0; i < len(var_); i++ {
   641  		v = &var_[i]
   642  		if v.addr != 0 {
   643  			continue
   644  		}
   645  
   646  		// Used in only one instruction, which had better be a write.
   647  		f := v.use
   648  		if f != nil && f.Data.(*Flow) == nil {
   649  			p := f.Prog
   650  			if p.To.Node == v.node && (p.Info.Flags&RightWrite != 0) && p.Info.Flags&RightRead == 0 {
   651  				p.As = obj.ANOP
   652  				p.To = obj.Addr{}
   653  				v.removed = 1
   654  				if debugmerge > 0 && Debug['v'] != 0 {
   655  					fmt.Printf("drop write-only %v\n", v.node.Sym)
   656  				}
   657  			} else {
   658  				Fatal("temp used and not set: %v", p)
   659  			}
   660  			nkill++
   661  			continue
   662  		}
   663  
   664  		// Written in one instruction, read in the next, otherwise unused,
   665  		// no jumps to the next instruction. Happens mainly in 386 compiler.
   666  		f = v.use
   667  		if f != nil && f.Link == f.Data.(*Flow) && (f.Data.(*Flow)).Data.(*Flow) == nil && Uniqp(f.Link) == f {
   668  			p := f.Prog
   669  			p1 := f.Link.Prog
   670  			const (
   671  				SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD
   672  			)
   673  			if p.From.Node == v.node && p1.To.Node == v.node && (p.Info.Flags&Move != 0) && (p.Info.Flags|p1.Info.Flags)&(LeftAddr|RightAddr) == 0 && p.Info.Flags&SizeAny == p1.Info.Flags&SizeAny {
   674  				p1.From = p.From
   675  				Thearch.Excise(f)
   676  				v.removed = 1
   677  				if debugmerge > 0 && Debug['v'] != 0 {
   678  					fmt.Printf("drop immediate-use %v\n", v.node.Sym)
   679  				}
   680  			}
   681  
   682  			nkill++
   683  			continue
   684  		}
   685  	}
   686  
   687  	// Traverse live range of each variable to set start, end.
   688  	// Each flood uses a new value of gen so that we don't have
   689  	// to clear all the r->active words after each variable.
   690  	gen := int32(0)
   691  
   692  	for i := 0; i < len(var_); i++ {
   693  		v = &var_[i]
   694  		gen++
   695  		for f := v.use; f != nil; f = f.Data.(*Flow) {
   696  			mergewalk(v, f, uint32(gen))
   697  		}
   698  		if v.addr != 0 {
   699  			gen++
   700  			for f := v.use; f != nil; f = f.Data.(*Flow) {
   701  				varkillwalk(v, f, uint32(gen))
   702  			}
   703  		}
   704  	}
   705  
   706  	// Sort variables by start.
   707  	bystart := make([]*TempVar, len(var_))
   708  
   709  	for i := 0; i < len(var_); i++ {
   710  		bystart[i] = &var_[i]
   711  	}
   712  	sort.Sort(startcmp(bystart[:len(var_)]))
   713  
   714  	// List of in-use variables, sorted by end, so that the ones that
   715  	// will last the longest are the earliest ones in the array.
   716  	// The tail inuse[nfree:] holds no-longer-used variables.
   717  	// In theory we should use a sorted tree so that insertions are
   718  	// guaranteed O(log n) and then the loop is guaranteed O(n log n).
   719  	// In practice, it doesn't really matter.
   720  	inuse := make([]*TempVar, len(var_))
   721  
   722  	ninuse := 0
   723  	nfree := len(var_)
   724  	var t *Type
   725  	var v1 *TempVar
   726  	var j int
   727  	for i := 0; i < len(var_); i++ {
   728  		v = bystart[i]
   729  		if debugmerge > 0 && Debug['v'] != 0 {
   730  			fmt.Printf("consider %v: removed=%d\n", Nconv(v.node, obj.FmtSharp), v.removed)
   731  		}
   732  
   733  		if v.removed != 0 {
   734  			continue
   735  		}
   736  
   737  		// Expire no longer in use.
   738  		for ninuse > 0 && inuse[ninuse-1].end < v.start {
   739  			ninuse--
   740  			v1 = inuse[ninuse]
   741  			nfree--
   742  			inuse[nfree] = v1
   743  		}
   744  
   745  		if debugmerge > 0 && Debug['v'] != 0 {
   746  			fmt.Printf("consider %v: removed=%d nfree=%d nvar=%d\n", Nconv(v.node, obj.FmtSharp), v.removed, nfree, len(var_))
   747  		}
   748  
   749  		// Find old temp to reuse if possible.
   750  		t = v.node.Type
   751  
   752  		for j = nfree; j < len(var_); j++ {
   753  			v1 = inuse[j]
   754  			if debugmerge > 0 && Debug['v'] != 0 {
   755  				fmt.Printf("consider %v: maybe %v: type=%v,%v addrtaken=%v,%v\n", Nconv(v.node, obj.FmtSharp), Nconv(v1.node, obj.FmtSharp), t, v1.node.Type, v.node.Addrtaken, v1.node.Addrtaken)
   756  			}
   757  
   758  			// Require the types to match but also require the addrtaken bits to match.
   759  			// If a variable's address is taken, that disables registerization for the individual
   760  			// words of the variable (for example, the base,len,cap of a slice).
   761  			// We don't want to merge a non-addressed var with an addressed one and
   762  			// inhibit registerization of the former.
   763  			if Eqtype(t, v1.node.Type) && v.node.Addrtaken == v1.node.Addrtaken {
   764  				inuse[j] = inuse[nfree]
   765  				nfree++
   766  				if v1.merge != nil {
   767  					v.merge = v1.merge
   768  				} else {
   769  					v.merge = v1
   770  				}
   771  				nkill++
   772  				break
   773  			}
   774  		}
   775  
   776  		// Sort v into inuse.
   777  		j = ninuse
   778  		ninuse++
   779  
   780  		for j > 0 && inuse[j-1].end < v.end {
   781  			inuse[j] = inuse[j-1]
   782  			j--
   783  		}
   784  
   785  		inuse[j] = v
   786  	}
   787  
   788  	if debugmerge > 0 && Debug['v'] != 0 {
   789  		fmt.Printf("%v [%d - %d]\n", Curfn.Func.Nname.Sym, len(var_), nkill)
   790  		var v *TempVar
   791  		for i := 0; i < len(var_); i++ {
   792  			v = &var_[i]
   793  			fmt.Printf("var %v %v %d-%d", Nconv(v.node, obj.FmtSharp), v.node.Type, v.start, v.end)
   794  			if v.addr != 0 {
   795  				fmt.Printf(" addr=1")
   796  			}
   797  			if v.removed != 0 {
   798  				fmt.Printf(" dead=1")
   799  			}
   800  			if v.merge != nil {
   801  				fmt.Printf(" merge %v", Nconv(v.merge.node, obj.FmtSharp))
   802  			}
   803  			if v.start == v.end && v.def != nil {
   804  				fmt.Printf(" %v", v.def.Prog)
   805  			}
   806  			fmt.Printf("\n")
   807  		}
   808  
   809  		if debugmerge > 1 && Debug['v'] != 0 {
   810  			Dumpit("after", g.Start, 0)
   811  		}
   812  	}
   813  
   814  	// Update node references to use merged temporaries.
   815  	for f := g.Start; f != nil; f = f.Link {
   816  		p := f.Prog
   817  		n, _ = p.From.Node.(*Node)
   818  		if n != nil {
   819  			v, _ = n.Opt().(*TempVar)
   820  			if v != nil && v.merge != nil {
   821  				p.From.Node = v.merge.node
   822  			}
   823  		}
   824  		n, _ = p.To.Node.(*Node)
   825  		if n != nil {
   826  			v, _ = n.Opt().(*TempVar)
   827  			if v != nil && v.merge != nil {
   828  				p.To.Node = v.merge.node
   829  			}
   830  		}
   831  	}
   832  
   833  	// Delete merged nodes from declaration list.
   834  	var l *NodeList
   835  	for lp := &Curfn.Func.Dcl; ; {
   836  		l = *lp
   837  		if l == nil {
   838  			break
   839  		}
   840  
   841  		Curfn.Func.Dcl.End = l
   842  		n = l.N
   843  		v, _ = n.Opt().(*TempVar)
   844  		if v != nil && (v.merge != nil || v.removed != 0) {
   845  			*lp = l.Next
   846  			continue
   847  		}
   848  
   849  		lp = &l.Next
   850  	}
   851  
   852  	// Clear aux structures.
   853  	for i := 0; i < len(var_); i++ {
   854  		var_[i].node.SetOpt(nil)
   855  	}
   856  
   857  	Flowend(g)
   858  }
   859  
   860  func mergewalk(v *TempVar, f0 *Flow, gen uint32) {
   861  	var p *obj.Prog
   862  	var f1 *Flow
   863  
   864  	for f1 = f0; f1 != nil; f1 = f1.P1 {
   865  		if uint32(f1.Active) == gen {
   866  			break
   867  		}
   868  		f1.Active = int32(gen)
   869  		p = f1.Prog
   870  		if v.end < p.Pc {
   871  			v.end = p.Pc
   872  		}
   873  		if f1 == v.def {
   874  			v.start = p.Pc
   875  			break
   876  		}
   877  	}
   878  
   879  	var f2 *Flow
   880  	for f := f0; f != f1; f = f.P1 {
   881  		for f2 = f.P2; f2 != nil; f2 = f2.P2link {
   882  			mergewalk(v, f2, gen)
   883  		}
   884  	}
   885  }
   886  
   887  func varkillwalk(v *TempVar, f0 *Flow, gen uint32) {
   888  	var p *obj.Prog
   889  	var f1 *Flow
   890  
   891  	for f1 = f0; f1 != nil; f1 = f1.S1 {
   892  		if uint32(f1.Active) == gen {
   893  			break
   894  		}
   895  		f1.Active = int32(gen)
   896  		p = f1.Prog
   897  		if v.end < p.Pc {
   898  			v.end = p.Pc
   899  		}
   900  		if v.start > p.Pc {
   901  			v.start = p.Pc
   902  		}
   903  		if p.As == obj.ARET || (p.As == obj.AVARKILL && p.To.Node == v.node) {
   904  			break
   905  		}
   906  	}
   907  
   908  	for f := f0; f != f1; f = f.S1 {
   909  		varkillwalk(v, f.S2, gen)
   910  	}
   911  }
   912  
   913  // Eliminate redundant nil pointer checks.
   914  //
   915  // The code generation pass emits a CHECKNIL for every possibly nil pointer.
   916  // This pass removes a CHECKNIL if every predecessor path has already
   917  // checked this value for nil.
   918  //
   919  // Simple backwards flood from check to definition.
   920  // Run prog loop backward from end of program to beginning to avoid quadratic
   921  // behavior removing a run of checks.
   922  //
   923  // Assume that stack variables with address not taken can be loaded multiple times
   924  // from memory without being rechecked. Other variables need to be checked on
   925  // each load.
   926  
   927  var killed int // f->data is either nil or &killed
   928  
   929  func nilopt(firstp *obj.Prog) {
   930  	g := Flowstart(firstp, nil)
   931  	if g == nil {
   932  		return
   933  	}
   934  
   935  	if Debug_checknil > 1 { /* || strcmp(curfn->nname->sym->name, "f1") == 0 */
   936  		Dumpit("nilopt", g.Start, 0)
   937  	}
   938  
   939  	ncheck := 0
   940  	nkill := 0
   941  	var p *obj.Prog
   942  	for f := g.Start; f != nil; f = f.Link {
   943  		p = f.Prog
   944  		if p.As != obj.ACHECKNIL || !Thearch.Regtyp(&p.From) {
   945  			continue
   946  		}
   947  		ncheck++
   948  		if Thearch.Stackaddr(&p.From) {
   949  			if Debug_checknil != 0 && p.Lineno > 1 {
   950  				Warnl(int(p.Lineno), "removed nil check of SP address")
   951  			}
   952  			f.Data = &killed
   953  			continue
   954  		}
   955  
   956  		nilwalkfwd(f)
   957  		if f.Data != nil {
   958  			if Debug_checknil != 0 && p.Lineno > 1 {
   959  				Warnl(int(p.Lineno), "removed nil check before indirect")
   960  			}
   961  			continue
   962  		}
   963  
   964  		nilwalkback(f)
   965  		if f.Data != nil {
   966  			if Debug_checknil != 0 && p.Lineno > 1 {
   967  				Warnl(int(p.Lineno), "removed repeated nil check")
   968  			}
   969  			continue
   970  		}
   971  	}
   972  
   973  	for f := g.Start; f != nil; f = f.Link {
   974  		if f.Data != nil {
   975  			nkill++
   976  			Thearch.Excise(f)
   977  		}
   978  	}
   979  
   980  	Flowend(g)
   981  
   982  	if Debug_checknil > 1 {
   983  		fmt.Printf("%v: removed %d of %d nil checks\n", Curfn.Func.Nname.Sym, nkill, ncheck)
   984  	}
   985  }
   986  
   987  func nilwalkback(fcheck *Flow) {
   988  	for f := fcheck; f != nil; f = Uniqp(f) {
   989  		p := f.Prog
   990  		if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
   991  			// Found initialization of value we're checking for nil.
   992  			// without first finding the check, so this one is unchecked.
   993  			return
   994  		}
   995  
   996  		if f != fcheck && p.As == obj.ACHECKNIL && Thearch.Sameaddr(&p.From, &fcheck.Prog.From) {
   997  			fcheck.Data = &killed
   998  			return
   999  		}
  1000  	}
  1001  }
  1002  
  1003  // Here is a more complex version that scans backward across branches.
  1004  // It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason
  1005  // to keep the check (setting fcheck->kill = 0).
  1006  // It doesn't handle copying of aggregates as well as I would like,
  1007  // nor variables with their address taken,
  1008  // and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
  1009  /*
  1010  for(f1 = f0; f1 != nil; f1 = f1->p1) {
  1011  	if(f1->active == gen)
  1012  		break;
  1013  	f1->active = gen;
  1014  	p = f1->prog;
  1015  
  1016  	// If same check, stop this loop but still check
  1017  	// alternate predecessors up to this point.
  1018  	if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from))
  1019  		break;
  1020  
  1021  	if((p.Info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
  1022  		// Found initialization of value we're checking for nil.
  1023  		// without first finding the check, so this one is unchecked.
  1024  		fcheck->kill = 0;
  1025  		return;
  1026  	}
  1027  
  1028  	if(f1->p1 == nil && f1->p2 == nil) {
  1029  		print("lost pred for %v\n", fcheck->prog);
  1030  		for(f1=f0; f1!=nil; f1=f1->p1) {
  1031  			thearch.proginfo(&info, f1->prog);
  1032  			print("\t%v %d %d %D %D\n", r1->prog, info.flags&RightWrite, thearch.sameaddr(&f1->prog->to, &fcheck->prog->from), &f1->prog->to, &fcheck->prog->from);
  1033  		}
  1034  		fatal("lost pred trail");
  1035  	}
  1036  }
  1037  
  1038  for(f = f0; f != f1; f = f->p1)
  1039  	for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
  1040  		nilwalkback(fcheck, f2, gen);
  1041  */
  1042  
  1043  func nilwalkfwd(fcheck *Flow) {
  1044  	// If the path down from rcheck dereferences the address
  1045  	// (possibly with a small offset) before writing to memory
  1046  	// and before any subsequent checks, it's okay to wait for
  1047  	// that implicit check. Only consider this basic block to
  1048  	// avoid problems like:
  1049  	//	_ = *x // should panic
  1050  	//	for {} // no writes but infinite loop may be considered visible
  1051  
  1052  	var last *Flow
  1053  	for f := Uniqs(fcheck); f != nil; f = Uniqs(f) {
  1054  		p := f.Prog
  1055  		if (p.Info.Flags&LeftRead != 0) && Thearch.Smallindir(&p.From, &fcheck.Prog.From) {
  1056  			fcheck.Data = &killed
  1057  			return
  1058  		}
  1059  
  1060  		if (p.Info.Flags&(RightRead|RightWrite) != 0) && Thearch.Smallindir(&p.To, &fcheck.Prog.From) {
  1061  			fcheck.Data = &killed
  1062  			return
  1063  		}
  1064  
  1065  		// Stop if another nil check happens.
  1066  		if p.As == obj.ACHECKNIL {
  1067  			return
  1068  		}
  1069  
  1070  		// Stop if value is lost.
  1071  		if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
  1072  			return
  1073  		}
  1074  
  1075  		// Stop if memory write.
  1076  		if (p.Info.Flags&RightWrite != 0) && !Thearch.Regtyp(&p.To) {
  1077  			return
  1078  		}
  1079  
  1080  		// Stop if we jump backward.
  1081  		if last != nil && f.Id <= last.Id {
  1082  			return
  1083  		}
  1084  		last = f
  1085  	}
  1086  }