github.com/rsc/tmp@v0.0.0-20240517235954-6deaab19748b/bootstrap/internal/gc/popt.go (about)

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