github.com/q45/go@v0.0.0-20151101211701-a4fb8c13db3f/src/cmd/compile/internal/gc/inl.go (about)

     1  // Copyright 2011 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  //
     5  // The inlining facility makes 2 passes: first caninl determines which
     6  // functions are suitable for inlining, and for those that are it
     7  // saves a copy of the body. Then inlcalls walks each function body to
     8  // expand calls to inlinable functions.
     9  //
    10  // The debug['l'] flag controls the agressiveness. Note that main() swaps level 0 and 1,
    11  // making 1 the default and -l disable.  -ll and more is useful to flush out bugs.
    12  // These additional levels (beyond -l) may be buggy and are not supported.
    13  //      0: disabled
    14  //      1: 40-nodes leaf functions, oneliners, lazy typechecking (default)
    15  //      2: early typechecking of all imported bodies
    16  //      3: allow variadic functions
    17  //      4: allow non-leaf functions , (breaks runtime.Caller)
    18  //
    19  //  At some point this may get another default and become switch-offable with -N.
    20  //
    21  //  The debug['m'] flag enables diagnostic output.  a single -m is useful for verifying
    22  //  which calls get inlined or not, more is for debugging, and may go away at any point.
    23  //
    24  // TODO:
    25  //   - inline functions with ... args
    26  //   - handle T.meth(f()) with func f() (t T, arg, arg, )
    27  
    28  package gc
    29  
    30  import (
    31  	"cmd/internal/obj"
    32  	"fmt"
    33  )
    34  
    35  // Used by caninl.
    36  
    37  // Used by inlcalls
    38  
    39  // Used during inlsubst[list]
    40  var inlfn *Node // function currently being inlined
    41  
    42  var inlretlabel *Node // target of the goto substituted in place of a return
    43  
    44  var inlretvars *NodeList // temp out variables
    45  
    46  // Get the function's package.  For ordinary functions it's on the ->sym, but for imported methods
    47  // the ->sym can be re-used in the local package, so peel it off the receiver's type.
    48  func fnpkg(fn *Node) *Pkg {
    49  	if fn.Type.Thistuple != 0 {
    50  		// method
    51  		rcvr := getthisx(fn.Type).Type.Type
    52  
    53  		if Isptr[rcvr.Etype] {
    54  			rcvr = rcvr.Type
    55  		}
    56  		if rcvr.Sym == nil {
    57  			Fatalf("receiver with no sym: [%v] %v  (%v)", fn.Sym, Nconv(fn, obj.FmtLong), rcvr)
    58  		}
    59  		return rcvr.Sym.Pkg
    60  	}
    61  
    62  	// non-method
    63  	return fn.Sym.Pkg
    64  }
    65  
    66  // Lazy typechecking of imported bodies.  For local functions, caninl will set ->typecheck
    67  // because they're a copy of an already checked body.
    68  func typecheckinl(fn *Node) {
    69  	lno := int(setlineno(fn))
    70  
    71  	// typecheckinl is only for imported functions;
    72  	// their bodies may refer to unsafe as long as the package
    73  	// was marked safe during import (which was checked then).
    74  	// the ->inl of a local function has been typechecked before caninl copied it.
    75  	pkg := fnpkg(fn)
    76  
    77  	if pkg == localpkg || pkg == nil {
    78  		return // typecheckinl on local function
    79  	}
    80  
    81  	if Debug['m'] > 2 {
    82  		fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, obj.FmtLong), Hconv(fn.Func.Inl, obj.FmtSharp))
    83  	}
    84  
    85  	save_safemode := safemode
    86  	safemode = 0
    87  
    88  	savefn := Curfn
    89  	Curfn = fn
    90  	typechecklist(fn.Func.Inl, Etop)
    91  	Curfn = savefn
    92  
    93  	safemode = save_safemode
    94  
    95  	lineno = int32(lno)
    96  }
    97  
    98  // Caninl determines whether fn is inlineable.
    99  // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
   100  // fn and ->nbody will already have been typechecked.
   101  func caninl(fn *Node) {
   102  	if fn.Op != ODCLFUNC {
   103  		Fatalf("caninl %v", fn)
   104  	}
   105  	if fn.Func.Nname == nil {
   106  		Fatalf("caninl no nname %v", Nconv(fn, obj.FmtSign))
   107  	}
   108  
   109  	// If marked "go:noinline", don't inline
   110  	if fn.Func.Noinline {
   111  		return
   112  	}
   113  
   114  	// If fn has no body (is defined outside of Go), cannot inline it.
   115  	if fn.Nbody == nil {
   116  		return
   117  	}
   118  
   119  	if fn.Typecheck == 0 {
   120  		Fatalf("caninl on non-typechecked function %v", fn)
   121  	}
   122  
   123  	// can't handle ... args yet
   124  	if Debug['l'] < 3 {
   125  		for t := fn.Type.Type.Down.Down.Type; t != nil; t = t.Down {
   126  			if t.Isddd {
   127  				return
   128  			}
   129  		}
   130  	}
   131  
   132  	// Runtime package must not be instrumented.
   133  	// Instrument skips runtime package. However, some runtime code can be
   134  	// inlined into other packages and instrumented there. To avoid this,
   135  	// we disable inlining of runtime functions when instrumenting.
   136  	// The example that we observed is inlining of LockOSThread,
   137  	// which lead to false race reports on m contents.
   138  	if instrumenting && myimportpath == "runtime" {
   139  		return
   140  	}
   141  
   142  	const maxBudget = 80
   143  	budget := maxBudget // allowed hairyness
   144  	if ishairylist(fn.Nbody, &budget) || budget < 0 {
   145  		return
   146  	}
   147  
   148  	savefn := Curfn
   149  	Curfn = fn
   150  
   151  	fn.Func.Nname.Func.Inl = fn.Nbody
   152  	fn.Nbody = inlcopylist(fn.Func.Nname.Func.Inl)
   153  	fn.Func.Nname.Func.Inldcl = inlcopylist(fn.Func.Nname.Name.Defn.Func.Dcl)
   154  	fn.Func.Nname.Func.InlCost = int32(maxBudget - budget)
   155  
   156  	// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
   157  	// this is so export can find the body of a method
   158  	fn.Type.Nname = fn.Func.Nname
   159  
   160  	if Debug['m'] > 1 {
   161  		fmt.Printf("%v: can inline %v as: %v { %v }\n", fn.Line(), Nconv(fn.Func.Nname, obj.FmtSharp), Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Nname.Func.Inl, obj.FmtSharp))
   162  	} else if Debug['m'] != 0 {
   163  		fmt.Printf("%v: can inline %v\n", fn.Line(), fn.Func.Nname)
   164  	}
   165  
   166  	Curfn = savefn
   167  }
   168  
   169  // Look for anything we want to punt on.
   170  func ishairylist(ll *NodeList, budget *int) bool {
   171  	for ; ll != nil; ll = ll.Next {
   172  		if ishairy(ll.N, budget) {
   173  			return true
   174  		}
   175  	}
   176  	return false
   177  }
   178  
   179  func ishairy(n *Node, budget *int) bool {
   180  	if n == nil {
   181  		return false
   182  	}
   183  
   184  	switch n.Op {
   185  	// Call is okay if inlinable and we have the budget for the body.
   186  	case OCALLFUNC:
   187  		if n.Left.Func != nil && n.Left.Func.Inl != nil {
   188  			*budget -= int(n.Left.Func.InlCost)
   189  			break
   190  		}
   191  		if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
   192  			if n.Left.Sym.Def != nil && n.Left.Sym.Def.Func.Inl != nil {
   193  				*budget -= int(n.Left.Sym.Def.Func.InlCost)
   194  				break
   195  			}
   196  		}
   197  		if Debug['l'] < 4 {
   198  			return true
   199  		}
   200  
   201  	// Call is okay if inlinable and we have the budget for the body.
   202  	case OCALLMETH:
   203  		if n.Left.Type == nil {
   204  			Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, obj.FmtSign))
   205  		}
   206  		if n.Left.Type.Nname == nil {
   207  			Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
   208  		}
   209  		if n.Left.Type.Nname.Func.Inl != nil {
   210  			*budget -= int(n.Left.Type.Nname.Func.InlCost)
   211  			break
   212  		}
   213  		if Debug['l'] < 4 {
   214  			return true
   215  		}
   216  
   217  	// Things that are too hairy, irrespective of the budget
   218  	case OCALL, OCALLINTER, OPANIC, ORECOVER:
   219  		if Debug['l'] < 4 {
   220  			return true
   221  		}
   222  
   223  	case OCLOSURE,
   224  		OCALLPART,
   225  		ORANGE,
   226  		OFOR,
   227  		OSELECT,
   228  		OSWITCH,
   229  		OPROC,
   230  		ODEFER,
   231  		ODCLTYPE,  // can't print yet
   232  		ODCLCONST, // can't print yet
   233  		ORETJMP:
   234  		return true
   235  	}
   236  
   237  	(*budget)--
   238  
   239  	return *budget < 0 || ishairy(n.Left, budget) || ishairy(n.Right, budget) || ishairylist(n.List, budget) || ishairylist(n.Rlist, budget) || ishairylist(n.Ninit, budget) || ishairylist(n.Nbody, budget)
   240  }
   241  
   242  // Inlcopy and inlcopylist recursively copy the body of a function.
   243  // Any name-like node of non-local class is marked for re-export by adding it to
   244  // the exportlist.
   245  func inlcopylist(ll *NodeList) *NodeList {
   246  	var l *NodeList
   247  	for ; ll != nil; ll = ll.Next {
   248  		l = list(l, inlcopy(ll.N))
   249  	}
   250  	return l
   251  }
   252  
   253  func inlcopy(n *Node) *Node {
   254  	if n == nil {
   255  		return nil
   256  	}
   257  
   258  	switch n.Op {
   259  	case ONAME, OTYPE, OLITERAL:
   260  		return n
   261  	}
   262  
   263  	m := Nod(OXXX, nil, nil)
   264  	*m = *n
   265  	if m.Func != nil {
   266  		m.Func.Inl = nil
   267  	}
   268  	m.Left = inlcopy(n.Left)
   269  	m.Right = inlcopy(n.Right)
   270  	m.List = inlcopylist(n.List)
   271  	m.Rlist = inlcopylist(n.Rlist)
   272  	m.Ninit = inlcopylist(n.Ninit)
   273  	m.Nbody = inlcopylist(n.Nbody)
   274  
   275  	return m
   276  }
   277  
   278  // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
   279  // calls made to inlineable functions.  This is the external entry point.
   280  func inlcalls(fn *Node) {
   281  	savefn := Curfn
   282  	Curfn = fn
   283  	inlnode(&fn)
   284  	if fn != Curfn {
   285  		Fatalf("inlnode replaced curfn")
   286  	}
   287  	Curfn = savefn
   288  }
   289  
   290  // Turn an OINLCALL into a statement.
   291  func inlconv2stmt(n *Node) {
   292  	n.Op = OBLOCK
   293  
   294  	// n->ninit stays
   295  	n.List = n.Nbody
   296  
   297  	n.Nbody = nil
   298  	n.Rlist = nil
   299  }
   300  
   301  // Turn an OINLCALL into a single valued expression.
   302  func inlconv2expr(np **Node) {
   303  	n := *np
   304  	r := n.Rlist.N
   305  	addinit(&r, concat(n.Ninit, n.Nbody))
   306  	*np = r
   307  }
   308  
   309  // Turn the rlist (with the return values) of the OINLCALL in
   310  // n into an expression list lumping the ninit and body
   311  // containing the inlined statements on the first list element so
   312  // order will be preserved Used in return, oas2func and call
   313  // statements.
   314  func inlconv2list(n *Node) *NodeList {
   315  	if n.Op != OINLCALL || n.Rlist == nil {
   316  		Fatalf("inlconv2list %v\n", Nconv(n, obj.FmtSign))
   317  	}
   318  
   319  	l := n.Rlist
   320  	addinit(&l.N, concat(n.Ninit, n.Nbody))
   321  	return l
   322  }
   323  
   324  func inlnodelist(l *NodeList) {
   325  	for ; l != nil; l = l.Next {
   326  		inlnode(&l.N)
   327  	}
   328  }
   329  
   330  // inlnode recurses over the tree to find inlineable calls, which will
   331  // be turned into OINLCALLs by mkinlcall.  When the recursion comes
   332  // back up will examine left, right, list, rlist, ninit, ntest, nincr,
   333  // nbody and nelse and use one of the 4 inlconv/glue functions above
   334  // to turn the OINLCALL into an expression, a statement, or patch it
   335  // in to this nodes list or rlist as appropriate.
   336  // NOTE it makes no sense to pass the glue functions down the
   337  // recursion to the level where the OINLCALL gets created because they
   338  // have to edit /this/ n, so you'd have to push that one down as well,
   339  // but then you may as well do it here.  so this is cleaner and
   340  // shorter and less complicated.
   341  func inlnode(np **Node) {
   342  	if *np == nil {
   343  		return
   344  	}
   345  
   346  	n := *np
   347  
   348  	switch n.Op {
   349  	// inhibit inlining of their argument
   350  	case ODEFER, OPROC:
   351  		switch n.Left.Op {
   352  		case OCALLFUNC, OCALLMETH:
   353  			// TODO(marvin): Fix Node.EType type union.
   354  			n.Left.Etype = EType(n.Op)
   355  		}
   356  		fallthrough
   357  
   358  		// TODO do them here (or earlier),
   359  	// so escape analysis can avoid more heapmoves.
   360  	case OCLOSURE:
   361  		return
   362  	}
   363  
   364  	lno := int(setlineno(n))
   365  
   366  	inlnodelist(n.Ninit)
   367  	for l := n.Ninit; l != nil; l = l.Next {
   368  		if l.N.Op == OINLCALL {
   369  			inlconv2stmt(l.N)
   370  		}
   371  	}
   372  
   373  	inlnode(&n.Left)
   374  	if n.Left != nil && n.Left.Op == OINLCALL {
   375  		inlconv2expr(&n.Left)
   376  	}
   377  
   378  	inlnode(&n.Right)
   379  	if n.Right != nil && n.Right.Op == OINLCALL {
   380  		if n.Op == OFOR {
   381  			inlconv2stmt(n.Right)
   382  		} else {
   383  			inlconv2expr(&n.Right)
   384  		}
   385  	}
   386  
   387  	inlnodelist(n.List)
   388  	switch n.Op {
   389  	case OBLOCK:
   390  		for l := n.List; l != nil; l = l.Next {
   391  			if l.N.Op == OINLCALL {
   392  				inlconv2stmt(l.N)
   393  			}
   394  		}
   395  
   396  		// if we just replaced arg in f(arg()) or return arg with an inlined call
   397  	// and arg returns multiple values, glue as list
   398  	case ORETURN,
   399  		OCALLFUNC,
   400  		OCALLMETH,
   401  		OCALLINTER,
   402  		OAPPEND,
   403  		OCOMPLEX:
   404  		if count(n.List) == 1 && n.List.N.Op == OINLCALL && count(n.List.N.Rlist) > 1 {
   405  			n.List = inlconv2list(n.List.N)
   406  			break
   407  		}
   408  		fallthrough
   409  
   410  	default:
   411  		for l := n.List; l != nil; l = l.Next {
   412  			if l.N.Op == OINLCALL {
   413  				inlconv2expr(&l.N)
   414  			}
   415  		}
   416  	}
   417  
   418  	inlnodelist(n.Rlist)
   419  	switch n.Op {
   420  	case OAS2FUNC:
   421  		if n.Rlist.N.Op == OINLCALL {
   422  			n.Rlist = inlconv2list(n.Rlist.N)
   423  			n.Op = OAS2
   424  			n.Typecheck = 0
   425  			typecheck(np, Etop)
   426  			break
   427  		}
   428  		fallthrough
   429  
   430  	default:
   431  		for l := n.Rlist; l != nil; l = l.Next {
   432  			if l.N.Op == OINLCALL {
   433  				if n.Op == OIF {
   434  					inlconv2stmt(l.N)
   435  				} else {
   436  					inlconv2expr(&l.N)
   437  				}
   438  			}
   439  		}
   440  	}
   441  
   442  	inlnodelist(n.Nbody)
   443  	for l := n.Nbody; l != nil; l = l.Next {
   444  		if l.N.Op == OINLCALL {
   445  			inlconv2stmt(l.N)
   446  		}
   447  	}
   448  
   449  	// with all the branches out of the way, it is now time to
   450  	// transmogrify this node itself unless inhibited by the
   451  	// switch at the top of this function.
   452  	switch n.Op {
   453  	case OCALLFUNC, OCALLMETH:
   454  		// TODO(marvin): Fix Node.EType type union.
   455  		if n.Etype == EType(OPROC) || n.Etype == EType(ODEFER) {
   456  			return
   457  		}
   458  	}
   459  
   460  	switch n.Op {
   461  	case OCALLFUNC:
   462  		if Debug['m'] > 3 {
   463  			fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign))
   464  		}
   465  		if n.Left.Func != nil && n.Left.Func.Inl != nil { // normal case
   466  			mkinlcall(np, n.Left, n.Isddd)
   467  		} else if n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME { // methods called as functions
   468  			if n.Left.Sym.Def != nil {
   469  				mkinlcall(np, n.Left.Sym.Def, n.Isddd)
   470  			}
   471  		}
   472  
   473  	case OCALLMETH:
   474  		if Debug['m'] > 3 {
   475  			fmt.Printf("%v:call to meth %v\n", n.Line(), Nconv(n.Left.Right, obj.FmtLong))
   476  		}
   477  
   478  		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
   479  		if n.Left.Type == nil {
   480  			Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, obj.FmtSign))
   481  		}
   482  
   483  		if n.Left.Type.Nname == nil {
   484  			Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign))
   485  		}
   486  
   487  		mkinlcall(np, n.Left.Type.Nname, n.Isddd)
   488  	}
   489  
   490  	lineno = int32(lno)
   491  }
   492  
   493  func mkinlcall(np **Node, fn *Node, isddd bool) {
   494  	save_safemode := safemode
   495  
   496  	// imported functions may refer to unsafe as long as the
   497  	// package was marked safe during import (already checked).
   498  	pkg := fnpkg(fn)
   499  
   500  	if pkg != localpkg && pkg != nil {
   501  		safemode = 0
   502  	}
   503  	mkinlcall1(np, fn, isddd)
   504  	safemode = save_safemode
   505  }
   506  
   507  func tinlvar(t *Type) *Node {
   508  	if t.Nname != nil && !isblank(t.Nname) {
   509  		if t.Nname.Name.Inlvar == nil {
   510  			Fatalf("missing inlvar for %v\n", t.Nname)
   511  		}
   512  		return t.Nname.Name.Inlvar
   513  	}
   514  
   515  	typecheck(&nblank, Erv|Easgn)
   516  	return nblank
   517  }
   518  
   519  var inlgen int
   520  
   521  // if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL.
   522  // On return ninit has the parameter assignments, the nbody is the
   523  // inlined function body and list, rlist contain the input, output
   524  // parameters.
   525  func mkinlcall1(np **Node, fn *Node, isddd bool) {
   526  	// For variadic fn.
   527  	if fn.Func.Inl == nil {
   528  		return
   529  	}
   530  
   531  	if fn == Curfn || fn.Name.Defn == Curfn {
   532  		return
   533  	}
   534  
   535  	if Debug['l'] < 2 {
   536  		typecheckinl(fn)
   537  	}
   538  
   539  	n := *np
   540  
   541  	// Bingo, we have a function node, and it has an inlineable body
   542  	if Debug['m'] > 1 {
   543  		fmt.Printf("%v: inlining call to %v %v { %v }\n", n.Line(), fn.Sym, Tconv(fn.Type, obj.FmtSharp), Hconv(fn.Func.Inl, obj.FmtSharp))
   544  	} else if Debug['m'] != 0 {
   545  		fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
   546  	}
   547  
   548  	if Debug['m'] > 2 {
   549  		fmt.Printf("%v: Before inlining: %v\n", n.Line(), Nconv(n, obj.FmtSign))
   550  	}
   551  
   552  	saveinlfn := inlfn
   553  	inlfn = fn
   554  
   555  	ninit := n.Ninit
   556  
   557  	//dumplist("ninit pre", ninit);
   558  
   559  	var dcl *NodeList
   560  	if fn.Name.Defn != nil { // local function
   561  		dcl = fn.Func.Inldcl // imported function
   562  	} else {
   563  		dcl = fn.Func.Dcl
   564  	}
   565  
   566  	inlretvars = nil
   567  	i := 0
   568  
   569  	// Make temp names to use instead of the originals
   570  	for ll := dcl; ll != nil; ll = ll.Next {
   571  		if ll.N.Class == PPARAMOUT { // return values handled below.
   572  			continue
   573  		}
   574  		if ll.N.Op == ONAME {
   575  			ll.N.Name.Inlvar = inlvar(ll.N)
   576  
   577  			// Typecheck because inlvar is not necessarily a function parameter.
   578  			typecheck(&ll.N.Name.Inlvar, Erv)
   579  
   580  			if ll.N.Class&^PHEAP != PAUTO {
   581  				ninit = list(ninit, Nod(ODCL, ll.N.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs
   582  			}
   583  		}
   584  	}
   585  
   586  	// temporaries for return values.
   587  	var m *Node
   588  	for t := getoutargx(fn.Type).Type; t != nil; t = t.Down {
   589  		if t != nil && t.Nname != nil && !isblank(t.Nname) {
   590  			m = inlvar(t.Nname)
   591  			typecheck(&m, Erv)
   592  			t.Nname.Name.Inlvar = m
   593  		} else {
   594  			// anonymous return values, synthesize names for use in assignment that replaces return
   595  			m = retvar(t, i)
   596  			i++
   597  		}
   598  
   599  		ninit = list(ninit, Nod(ODCL, m, nil))
   600  		inlretvars = list(inlretvars, m)
   601  	}
   602  
   603  	// assign receiver.
   604  	var as *Node
   605  	if fn.Type.Thistuple != 0 && n.Left.Op == ODOTMETH {
   606  		// method call with a receiver.
   607  		t := getthisx(fn.Type).Type
   608  
   609  		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
   610  			Fatalf("missing inlvar for %v\n", t.Nname)
   611  		}
   612  		if n.Left.Left == nil {
   613  			Fatalf("method call without receiver: %v", Nconv(n, obj.FmtSign))
   614  		}
   615  		if t == nil {
   616  			Fatalf("method call unknown receiver type: %v", Nconv(n, obj.FmtSign))
   617  		}
   618  		as = Nod(OAS, tinlvar(t), n.Left.Left)
   619  		if as != nil {
   620  			typecheck(&as, Etop)
   621  			ninit = list(ninit, as)
   622  		}
   623  	}
   624  
   625  	// check if inlined function is variadic.
   626  	variadic := false
   627  
   628  	var varargtype *Type
   629  	varargcount := 0
   630  	for t := fn.Type.Type.Down.Down.Type; t != nil; t = t.Down {
   631  		if t.Isddd {
   632  			variadic = true
   633  			varargtype = t.Type
   634  		}
   635  	}
   636  
   637  	// but if argument is dotted too forget about variadicity.
   638  	if variadic && isddd {
   639  		variadic = false
   640  	}
   641  
   642  	// check if argument is actually a returned tuple from call.
   643  	multiret := 0
   644  
   645  	if n.List != nil && n.List.Next == nil {
   646  		switch n.List.N.Op {
   647  		case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH:
   648  			if n.List.N.Left.Type.Outtuple > 1 {
   649  				multiret = n.List.N.Left.Type.Outtuple - 1
   650  			}
   651  		}
   652  	}
   653  
   654  	if variadic {
   655  		varargcount = count(n.List) + multiret
   656  		if n.Left.Op != ODOTMETH {
   657  			varargcount -= fn.Type.Thistuple
   658  		}
   659  		varargcount -= fn.Type.Intuple - 1
   660  	}
   661  
   662  	// assign arguments to the parameters' temp names
   663  	as = Nod(OAS2, nil, nil)
   664  
   665  	as.Rlist = n.List
   666  	ll := n.List
   667  
   668  	// TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call?
   669  	if fn.Type.Thistuple != 0 && n.Left.Op != ODOTMETH {
   670  		// non-method call to method
   671  		if n.List == nil {
   672  			Fatalf("non-method call to method without first arg: %v", Nconv(n, obj.FmtSign))
   673  		}
   674  
   675  		// append receiver inlvar to LHS.
   676  		t := getthisx(fn.Type).Type
   677  
   678  		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil {
   679  			Fatalf("missing inlvar for %v\n", t.Nname)
   680  		}
   681  		if t == nil {
   682  			Fatalf("method call unknown receiver type: %v", Nconv(n, obj.FmtSign))
   683  		}
   684  		as.List = list(as.List, tinlvar(t))
   685  		ll = ll.Next // track argument count.
   686  	}
   687  
   688  	// append ordinary arguments to LHS.
   689  	chkargcount := n.List != nil && n.List.Next != nil
   690  
   691  	var vararg *Node      // the slice argument to a variadic call
   692  	var varargs *NodeList // the list of LHS names to put in vararg.
   693  	if !chkargcount {
   694  		// 0 or 1 expression on RHS.
   695  		var i int
   696  		for t := getinargx(fn.Type).Type; t != nil; t = t.Down {
   697  			if variadic && t.Isddd {
   698  				vararg = tinlvar(t)
   699  				for i = 0; i < varargcount && ll != nil; i++ {
   700  					m = argvar(varargtype, i)
   701  					varargs = list(varargs, m)
   702  					as.List = list(as.List, m)
   703  				}
   704  
   705  				break
   706  			}
   707  
   708  			as.List = list(as.List, tinlvar(t))
   709  		}
   710  	} else {
   711  		// match arguments except final variadic (unless the call is dotted itself)
   712  		var t *Type
   713  		for t = getinargx(fn.Type).Type; t != nil; {
   714  			if ll == nil {
   715  				break
   716  			}
   717  			if variadic && t.Isddd {
   718  				break
   719  			}
   720  			as.List = list(as.List, tinlvar(t))
   721  			t = t.Down
   722  			ll = ll.Next
   723  		}
   724  
   725  		// match varargcount arguments with variadic parameters.
   726  		if variadic && t != nil && t.Isddd {
   727  			vararg = tinlvar(t)
   728  			var i int
   729  			for i = 0; i < varargcount && ll != nil; i++ {
   730  				m = argvar(varargtype, i)
   731  				varargs = list(varargs, m)
   732  				as.List = list(as.List, m)
   733  				ll = ll.Next
   734  			}
   735  
   736  			if i == varargcount {
   737  				t = t.Down
   738  			}
   739  		}
   740  
   741  		if ll != nil || t != nil {
   742  			Fatalf("arg count mismatch: %v  vs %v\n", Tconv(getinargx(fn.Type), obj.FmtSharp), Hconv(n.List, obj.FmtComma))
   743  		}
   744  	}
   745  
   746  	if as.Rlist != nil {
   747  		typecheck(&as, Etop)
   748  		ninit = list(ninit, as)
   749  	}
   750  
   751  	// turn the variadic args into a slice.
   752  	if variadic {
   753  		as = Nod(OAS, vararg, nil)
   754  		if varargcount == 0 {
   755  			as.Right = nodnil()
   756  			as.Right.Type = varargtype
   757  		} else {
   758  			vararrtype := typ(TARRAY)
   759  			vararrtype.Type = varargtype.Type
   760  			vararrtype.Bound = int64(varargcount)
   761  
   762  			as.Right = Nod(OCOMPLIT, nil, typenod(varargtype))
   763  			as.Right.List = varargs
   764  			as.Right = Nod(OSLICE, as.Right, Nod(OKEY, nil, nil))
   765  		}
   766  
   767  		typecheck(&as, Etop)
   768  		ninit = list(ninit, as)
   769  	}
   770  
   771  	// zero the outparams
   772  	for ll := inlretvars; ll != nil; ll = ll.Next {
   773  		as = Nod(OAS, ll.N, nil)
   774  		typecheck(&as, Etop)
   775  		ninit = list(ninit, as)
   776  	}
   777  
   778  	inlretlabel = newlabel_inl()
   779  	inlgen++
   780  	body := inlsubstlist(fn.Func.Inl)
   781  
   782  	body = list(body, Nod(OGOTO, inlretlabel, nil)) // avoid 'not used' when function doesn't have return
   783  	body = list(body, Nod(OLABEL, inlretlabel, nil))
   784  
   785  	typechecklist(body, Etop)
   786  
   787  	//dumplist("ninit post", ninit);
   788  
   789  	call := Nod(OINLCALL, nil, nil)
   790  
   791  	call.Ninit = ninit
   792  	call.Nbody = body
   793  	call.Rlist = inlretvars
   794  	call.Type = n.Type
   795  	call.Typecheck = 1
   796  
   797  	// Hide the args from setlno -- the parameters to the inlined
   798  	// call already have good line numbers that should be preserved.
   799  	args := as.Rlist
   800  	as.Rlist = nil
   801  
   802  	setlno(call, int(n.Lineno))
   803  
   804  	as.Rlist = args
   805  
   806  	//dumplist("call body", body);
   807  
   808  	*np = call
   809  
   810  	inlfn = saveinlfn
   811  
   812  	// transitive inlining
   813  	// might be nice to do this before exporting the body,
   814  	// but can't emit the body with inlining expanded.
   815  	// instead we emit the things that the body needs
   816  	// and each use must redo the inlining.
   817  	// luckily these are small.
   818  	body = fn.Func.Inl
   819  	fn.Func.Inl = nil // prevent infinite recursion (shouldn't happen anyway)
   820  	inlnodelist(call.Nbody)
   821  	for ll := call.Nbody; ll != nil; ll = ll.Next {
   822  		if ll.N.Op == OINLCALL {
   823  			inlconv2stmt(ll.N)
   824  		}
   825  	}
   826  	fn.Func.Inl = body
   827  
   828  	if Debug['m'] > 2 {
   829  		fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(*np, obj.FmtSign))
   830  	}
   831  }
   832  
   833  // Every time we expand a function we generate a new set of tmpnames,
   834  // PAUTO's in the calling functions, and link them off of the
   835  // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
   836  func inlvar(var_ *Node) *Node {
   837  	if Debug['m'] > 3 {
   838  		fmt.Printf("inlvar %v\n", Nconv(var_, obj.FmtSign))
   839  	}
   840  
   841  	n := newname(var_.Sym)
   842  	n.Type = var_.Type
   843  	n.Class = PAUTO
   844  	n.Used = true
   845  	n.Name.Curfn = Curfn // the calling function, not the called one
   846  	n.Addrtaken = var_.Addrtaken
   847  
   848  	// This may no longer be necessary now that we run escape analysis
   849  	// after wrapper generation, but for 1.5 this is conservatively left
   850  	// unchanged.  See bugs 11053 and 9537.
   851  	if var_.Esc == EscHeap {
   852  		addrescapes(n)
   853  	}
   854  
   855  	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
   856  	return n
   857  }
   858  
   859  // Synthesize a variable to store the inlined function's results in.
   860  func retvar(t *Type, i int) *Node {
   861  	n := newname(Lookupf("~r%d", i))
   862  	n.Type = t.Type
   863  	n.Class = PAUTO
   864  	n.Used = true
   865  	n.Name.Curfn = Curfn // the calling function, not the called one
   866  	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
   867  	return n
   868  }
   869  
   870  // Synthesize a variable to store the inlined function's arguments
   871  // when they come from a multiple return call.
   872  func argvar(t *Type, i int) *Node {
   873  	n := newname(Lookupf("~arg%d", i))
   874  	n.Type = t.Type
   875  	n.Class = PAUTO
   876  	n.Used = true
   877  	n.Name.Curfn = Curfn // the calling function, not the called one
   878  	Curfn.Func.Dcl = list(Curfn.Func.Dcl, n)
   879  	return n
   880  }
   881  
   882  var newlabel_inl_label int
   883  
   884  func newlabel_inl() *Node {
   885  	newlabel_inl_label++
   886  	n := newname(Lookupf(".inlret%.6d", newlabel_inl_label))
   887  	n.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
   888  	return n
   889  }
   890  
   891  // inlsubst and inlsubstlist recursively copy the body of the saved
   892  // pristine ->inl body of the function while substituting references
   893  // to input/output parameters with ones to the tmpnames, and
   894  // substituting returns with assignments to the output.
   895  func inlsubstlist(ll *NodeList) *NodeList {
   896  	var l *NodeList
   897  	for ; ll != nil; ll = ll.Next {
   898  		l = list(l, inlsubst(ll.N))
   899  	}
   900  	return l
   901  }
   902  
   903  func inlsubst(n *Node) *Node {
   904  	if n == nil {
   905  		return nil
   906  	}
   907  
   908  	switch n.Op {
   909  	case ONAME:
   910  		if n.Name.Inlvar != nil { // These will be set during inlnode
   911  			if Debug['m'] > 2 {
   912  				fmt.Printf("substituting name %v  ->  %v\n", Nconv(n, obj.FmtSign), Nconv(n.Name.Inlvar, obj.FmtSign))
   913  			}
   914  			return n.Name.Inlvar
   915  		}
   916  
   917  		if Debug['m'] > 2 {
   918  			fmt.Printf("not substituting name %v\n", Nconv(n, obj.FmtSign))
   919  		}
   920  		return n
   921  
   922  	case OLITERAL, OTYPE:
   923  		return n
   924  
   925  		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
   926  
   927  	//		dump("Return before substitution", n);
   928  	case ORETURN:
   929  		m := Nod(OGOTO, inlretlabel, nil)
   930  
   931  		m.Ninit = inlsubstlist(n.Ninit)
   932  
   933  		if inlretvars != nil && n.List != nil {
   934  			as := Nod(OAS2, nil, nil)
   935  
   936  			// shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that.
   937  			for ll := inlretvars; ll != nil; ll = ll.Next {
   938  				as.List = list(as.List, ll.N)
   939  			}
   940  			as.Rlist = inlsubstlist(n.List)
   941  			typecheck(&as, Etop)
   942  			m.Ninit = list(m.Ninit, as)
   943  		}
   944  
   945  		typechecklist(m.Ninit, Etop)
   946  		typecheck(&m, Etop)
   947  
   948  		//		dump("Return after substitution", m);
   949  		return m
   950  
   951  	case OGOTO, OLABEL:
   952  		m := Nod(OXXX, nil, nil)
   953  		*m = *n
   954  		m.Ninit = nil
   955  		p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
   956  		m.Left = newname(Lookup(p))
   957  
   958  		return m
   959  	}
   960  
   961  	m := Nod(OXXX, nil, nil)
   962  	*m = *n
   963  	m.Ninit = nil
   964  
   965  	if n.Op == OCLOSURE {
   966  		Fatalf("cannot inline function containing closure: %v", Nconv(n, obj.FmtSign))
   967  	}
   968  
   969  	m.Left = inlsubst(n.Left)
   970  	m.Right = inlsubst(n.Right)
   971  	m.List = inlsubstlist(n.List)
   972  	m.Rlist = inlsubstlist(n.Rlist)
   973  	m.Ninit = concat(m.Ninit, inlsubstlist(n.Ninit))
   974  	m.Nbody = inlsubstlist(n.Nbody)
   975  
   976  	return m
   977  }
   978  
   979  // Plaster over linenumbers
   980  func setlnolist(ll *NodeList, lno int) {
   981  	for ; ll != nil; ll = ll.Next {
   982  		setlno(ll.N, lno)
   983  	}
   984  }
   985  
   986  func setlno(n *Node, lno int) {
   987  	if n == nil {
   988  		return
   989  	}
   990  
   991  	// don't clobber names, unless they're freshly synthesized
   992  	if n.Op != ONAME || n.Lineno == 0 {
   993  		n.Lineno = int32(lno)
   994  	}
   995  
   996  	setlno(n.Left, lno)
   997  	setlno(n.Right, lno)
   998  	setlnolist(n.List, lno)
   999  	setlnolist(n.Rlist, lno)
  1000  	setlnolist(n.Ninit, lno)
  1001  	setlnolist(n.Nbody, lno)
  1002  }