github.com/mattn/go@v0.0.0-20171011075504-07f7db3ea99f/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 aggressiveness. 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: 80-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  
    27  package gc
    28  
    29  import (
    30  	"cmd/compile/internal/types"
    31  	"cmd/internal/src"
    32  	"fmt"
    33  )
    34  
    35  // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
    36  // the ->sym can be re-used in the local package, so peel it off the receiver's type.
    37  func fnpkg(fn *Node) *types.Pkg {
    38  	if fn.IsMethod() {
    39  		// method
    40  		rcvr := fn.Type.Recv().Type
    41  
    42  		if rcvr.IsPtr() {
    43  			rcvr = rcvr.Elem()
    44  		}
    45  		if rcvr.Sym == nil {
    46  			Fatalf("receiver with no sym: [%v] %L  (%v)", fn.Sym, fn, rcvr)
    47  		}
    48  		return rcvr.Sym.Pkg
    49  	}
    50  
    51  	// non-method
    52  	return fn.Sym.Pkg
    53  }
    54  
    55  // Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
    56  // because they're a copy of an already checked body.
    57  func typecheckinl(fn *Node) {
    58  	lno := setlineno(fn)
    59  
    60  	// typecheckinl is only for imported functions;
    61  	// their bodies may refer to unsafe as long as the package
    62  	// was marked safe during import (which was checked then).
    63  	// the ->inl of a local function has been typechecked before caninl copied it.
    64  	pkg := fnpkg(fn)
    65  
    66  	if pkg == localpkg || pkg == nil {
    67  		return // typecheckinl on local function
    68  	}
    69  
    70  	if Debug['m'] > 2 || Debug_export != 0 {
    71  		fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, fn.Func.Inl)
    72  	}
    73  
    74  	save_safemode := safemode
    75  	safemode = false
    76  
    77  	savefn := Curfn
    78  	Curfn = fn
    79  	typecheckslice(fn.Func.Inl.Slice(), Etop)
    80  	Curfn = savefn
    81  
    82  	safemode = save_safemode
    83  
    84  	lineno = lno
    85  }
    86  
    87  // Caninl determines whether fn is inlineable.
    88  // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
    89  // fn and ->nbody will already have been typechecked.
    90  func caninl(fn *Node) {
    91  	if fn.Op != ODCLFUNC {
    92  		Fatalf("caninl %v", fn)
    93  	}
    94  	if fn.Func.Nname == nil {
    95  		Fatalf("caninl no nname %+v", fn)
    96  	}
    97  
    98  	var reason string // reason, if any, that the function was not inlined
    99  	if Debug['m'] > 1 {
   100  		defer func() {
   101  			if reason != "" {
   102  				fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
   103  			}
   104  		}()
   105  	}
   106  
   107  	// If marked "go:noinline", don't inline
   108  	if fn.Func.Pragma&Noinline != 0 {
   109  		reason = "marked go:noinline"
   110  		return
   111  	}
   112  
   113  	// If marked "go:cgo_unsafe_args", don't inline, since the
   114  	// function makes assumptions about its argument frame layout.
   115  	if fn.Func.Pragma&CgoUnsafeArgs != 0 {
   116  		reason = "marked go:cgo_unsafe_args"
   117  		return
   118  	}
   119  
   120  	// If fn has no body (is defined outside of Go), cannot inline it.
   121  	if fn.Nbody.Len() == 0 {
   122  		reason = "no function body"
   123  		return
   124  	}
   125  
   126  	if fn.Typecheck() == 0 {
   127  		Fatalf("caninl on non-typechecked function %v", fn)
   128  	}
   129  
   130  	// can't handle ... args yet
   131  	if Debug['l'] < 3 {
   132  		f := fn.Type.Params().Fields()
   133  		if len := f.Len(); len > 0 {
   134  			if t := f.Index(len - 1); t.Isddd() {
   135  				reason = "has ... args"
   136  				return
   137  			}
   138  		}
   139  	}
   140  
   141  	// Runtime package must not be instrumented.
   142  	// Instrument skips runtime package. However, some runtime code can be
   143  	// inlined into other packages and instrumented there. To avoid this,
   144  	// we disable inlining of runtime functions when instrumenting.
   145  	// The example that we observed is inlining of LockOSThread,
   146  	// which lead to false race reports on m contents.
   147  	if instrumenting && myimportpath == "runtime" {
   148  		reason = "instrumenting and is runtime function"
   149  		return
   150  	}
   151  
   152  	const maxBudget = 80
   153  	visitor := hairyVisitor{budget: maxBudget}
   154  	if visitor.visitList(fn.Nbody) {
   155  		reason = visitor.reason
   156  		return
   157  	}
   158  	if visitor.budget < 0 {
   159  		reason = fmt.Sprintf("function too complex: cost %d exceeds budget %d", maxBudget-visitor.budget, maxBudget)
   160  		return
   161  	}
   162  
   163  	savefn := Curfn
   164  	Curfn = fn
   165  
   166  	n := fn.Func.Nname
   167  
   168  	n.Func.Inl.Set(fn.Nbody.Slice())
   169  	fn.Nbody.Set(inlcopylist(n.Func.Inl.Slice()))
   170  	inldcl := inlcopylist(n.Name.Defn.Func.Dcl)
   171  	n.Func.Inldcl.Set(inldcl)
   172  	n.Func.InlCost = maxBudget - visitor.budget
   173  
   174  	// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
   175  	// this is so export can find the body of a method
   176  	fn.Type.FuncType().Nname = asTypesNode(n)
   177  
   178  	if Debug['m'] > 1 {
   179  		fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, n.Func.Inl)
   180  	} else if Debug['m'] != 0 {
   181  		fmt.Printf("%v: can inline %v\n", fn.Line(), n)
   182  	}
   183  
   184  	Curfn = savefn
   185  }
   186  
   187  // hairyVisitor visits a function body to determine its inlining
   188  // hairiness and whether or not it can be inlined.
   189  type hairyVisitor struct {
   190  	budget int32
   191  	reason string
   192  }
   193  
   194  // Look for anything we want to punt on.
   195  func (v *hairyVisitor) visitList(ll Nodes) bool {
   196  	for _, n := range ll.Slice() {
   197  		if v.visit(n) {
   198  			return true
   199  		}
   200  	}
   201  	return false
   202  }
   203  
   204  func (v *hairyVisitor) visit(n *Node) bool {
   205  	if n == nil {
   206  		return false
   207  	}
   208  
   209  	switch n.Op {
   210  	// Call is okay if inlinable and we have the budget for the body.
   211  	case OCALLFUNC:
   212  		if isIntrinsicCall(n) {
   213  			v.budget--
   214  			break
   215  		}
   216  		// Functions that call runtime.getcaller{pc,sp} can not be inlined
   217  		// because getcaller{pc,sp} expect a pointer to the caller's first argument.
   218  		if n.Left.Op == ONAME && n.Left.Class() == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
   219  			fn := n.Left.Sym.Name
   220  			if fn == "getcallerpc" || fn == "getcallersp" {
   221  				v.reason = "call to " + fn
   222  				return true
   223  			}
   224  		}
   225  
   226  		if fn := n.Left.Func; fn != nil && fn.Inl.Len() != 0 {
   227  			v.budget -= fn.InlCost
   228  			break
   229  		}
   230  
   231  		if n.isMethodCalledAsFunction() {
   232  			if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl.Len() != 0 {
   233  				v.budget -= d.Func.InlCost
   234  				break
   235  			}
   236  		}
   237  		if Debug['l'] < 4 {
   238  			v.reason = "non-leaf function"
   239  			return true
   240  		}
   241  
   242  	// Call is okay if inlinable and we have the budget for the body.
   243  	case OCALLMETH:
   244  		t := n.Left.Type
   245  		if t == nil {
   246  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   247  		}
   248  		if t.Nname() == nil {
   249  			Fatalf("no function definition for [%p] %+v\n", t, t)
   250  		}
   251  		if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl.Len() != 0 {
   252  			v.budget -= inlfn.InlCost
   253  			break
   254  		}
   255  		if Debug['l'] < 4 {
   256  			v.reason = "non-leaf method"
   257  			return true
   258  		}
   259  
   260  	// Things that are too hairy, irrespective of the budget
   261  	case OCALL, OCALLINTER, OPANIC, ORECOVER:
   262  		if Debug['l'] < 4 {
   263  			v.reason = "non-leaf op " + n.Op.String()
   264  			return true
   265  		}
   266  
   267  	case OCLOSURE,
   268  		OCALLPART,
   269  		ORANGE,
   270  		OFOR,
   271  		OFORUNTIL,
   272  		OSELECT,
   273  		OTYPESW,
   274  		OPROC,
   275  		ODEFER,
   276  		ODCLTYPE, // can't print yet
   277  		OBREAK,
   278  		ORETJMP:
   279  		v.reason = "unhandled op " + n.Op.String()
   280  		return true
   281  
   282  	case ODCLCONST, OEMPTY, OFALL, OLABEL:
   283  		// These nodes don't produce code; omit from inlining budget.
   284  		return false
   285  	}
   286  
   287  	v.budget--
   288  	// TODO(mdempsky/josharian): Hacks to appease toolstash; remove.
   289  	// See issue 17566 and CL 31674 for discussion.
   290  	switch n.Op {
   291  	case OSTRUCTKEY:
   292  		v.budget--
   293  	case OSLICE, OSLICEARR, OSLICESTR:
   294  		v.budget--
   295  	case OSLICE3, OSLICE3ARR:
   296  		v.budget -= 2
   297  	}
   298  
   299  	// When debugging, don't stop early, to get full cost of inlining this function
   300  	if v.budget < 0 && Debug['m'] < 2 {
   301  		return true
   302  	}
   303  
   304  	return v.visit(n.Left) || v.visit(n.Right) ||
   305  		v.visitList(n.List) || v.visitList(n.Rlist) ||
   306  		v.visitList(n.Ninit) || v.visitList(n.Nbody)
   307  }
   308  
   309  // Inlcopy and inlcopylist recursively copy the body of a function.
   310  // Any name-like node of non-local class is marked for re-export by adding it to
   311  // the exportlist.
   312  func inlcopylist(ll []*Node) []*Node {
   313  	s := make([]*Node, 0, len(ll))
   314  	for _, n := range ll {
   315  		s = append(s, inlcopy(n))
   316  	}
   317  	return s
   318  }
   319  
   320  func inlcopy(n *Node) *Node {
   321  	if n == nil {
   322  		return nil
   323  	}
   324  
   325  	switch n.Op {
   326  	case ONAME, OTYPE, OLITERAL:
   327  		return n
   328  	}
   329  
   330  	m := *n
   331  	if m.Func != nil {
   332  		m.Func.Inl.Set(nil)
   333  	}
   334  	m.Left = inlcopy(n.Left)
   335  	m.Right = inlcopy(n.Right)
   336  	m.List.Set(inlcopylist(n.List.Slice()))
   337  	m.Rlist.Set(inlcopylist(n.Rlist.Slice()))
   338  	m.Ninit.Set(inlcopylist(n.Ninit.Slice()))
   339  	m.Nbody.Set(inlcopylist(n.Nbody.Slice()))
   340  
   341  	return &m
   342  }
   343  
   344  // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
   345  // calls made to inlineable functions. This is the external entry point.
   346  func inlcalls(fn *Node) {
   347  	savefn := Curfn
   348  	Curfn = fn
   349  	fn = inlnode(fn)
   350  	if fn != Curfn {
   351  		Fatalf("inlnode replaced curfn")
   352  	}
   353  	Curfn = savefn
   354  }
   355  
   356  // Turn an OINLCALL into a statement.
   357  func inlconv2stmt(n *Node) {
   358  	n.Op = OBLOCK
   359  
   360  	// n->ninit stays
   361  	n.List.Set(n.Nbody.Slice())
   362  
   363  	n.Nbody.Set(nil)
   364  	n.Rlist.Set(nil)
   365  }
   366  
   367  // Turn an OINLCALL into a single valued expression.
   368  // The result of inlconv2expr MUST be assigned back to n, e.g.
   369  // 	n.Left = inlconv2expr(n.Left)
   370  func inlconv2expr(n *Node) *Node {
   371  	r := n.Rlist.First()
   372  	return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
   373  }
   374  
   375  // Turn the rlist (with the return values) of the OINLCALL in
   376  // n into an expression list lumping the ninit and body
   377  // containing the inlined statements on the first list element so
   378  // order will be preserved Used in return, oas2func and call
   379  // statements.
   380  func inlconv2list(n *Node) []*Node {
   381  	if n.Op != OINLCALL || n.Rlist.Len() == 0 {
   382  		Fatalf("inlconv2list %+v\n", n)
   383  	}
   384  
   385  	s := n.Rlist.Slice()
   386  	s[0] = addinit(s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...))
   387  	return s
   388  }
   389  
   390  func inlnodelist(l Nodes) {
   391  	s := l.Slice()
   392  	for i := range s {
   393  		s[i] = inlnode(s[i])
   394  	}
   395  }
   396  
   397  // inlnode recurses over the tree to find inlineable calls, which will
   398  // be turned into OINLCALLs by mkinlcall. When the recursion comes
   399  // back up will examine left, right, list, rlist, ninit, ntest, nincr,
   400  // nbody and nelse and use one of the 4 inlconv/glue functions above
   401  // to turn the OINLCALL into an expression, a statement, or patch it
   402  // in to this nodes list or rlist as appropriate.
   403  // NOTE it makes no sense to pass the glue functions down the
   404  // recursion to the level where the OINLCALL gets created because they
   405  // have to edit /this/ n, so you'd have to push that one down as well,
   406  // but then you may as well do it here.  so this is cleaner and
   407  // shorter and less complicated.
   408  // The result of inlnode MUST be assigned back to n, e.g.
   409  // 	n.Left = inlnode(n.Left)
   410  func inlnode(n *Node) *Node {
   411  	if n == nil {
   412  		return n
   413  	}
   414  
   415  	switch n.Op {
   416  	// inhibit inlining of their argument
   417  	case ODEFER, OPROC:
   418  		switch n.Left.Op {
   419  		case OCALLFUNC, OCALLMETH:
   420  			n.Left.SetNoInline(true)
   421  		}
   422  		return n
   423  
   424  	// TODO do them here (or earlier),
   425  	// so escape analysis can avoid more heapmoves.
   426  	case OCLOSURE:
   427  		return n
   428  	}
   429  
   430  	lno := setlineno(n)
   431  
   432  	inlnodelist(n.Ninit)
   433  	for _, n1 := range n.Ninit.Slice() {
   434  		if n1.Op == OINLCALL {
   435  			inlconv2stmt(n1)
   436  		}
   437  	}
   438  
   439  	n.Left = inlnode(n.Left)
   440  	if n.Left != nil && n.Left.Op == OINLCALL {
   441  		n.Left = inlconv2expr(n.Left)
   442  	}
   443  
   444  	n.Right = inlnode(n.Right)
   445  	if n.Right != nil && n.Right.Op == OINLCALL {
   446  		if n.Op == OFOR || n.Op == OFORUNTIL {
   447  			inlconv2stmt(n.Right)
   448  		} else {
   449  			n.Right = inlconv2expr(n.Right)
   450  		}
   451  	}
   452  
   453  	inlnodelist(n.List)
   454  	switch n.Op {
   455  	case OBLOCK:
   456  		for _, n2 := range n.List.Slice() {
   457  			if n2.Op == OINLCALL {
   458  				inlconv2stmt(n2)
   459  			}
   460  		}
   461  
   462  	case ORETURN, OCALLFUNC, OCALLMETH, OCALLINTER, OAPPEND, OCOMPLEX:
   463  		// if we just replaced arg in f(arg()) or return arg with an inlined call
   464  		// and arg returns multiple values, glue as list
   465  		if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 {
   466  			n.List.Set(inlconv2list(n.List.First()))
   467  			break
   468  		}
   469  		fallthrough
   470  
   471  	default:
   472  		s := n.List.Slice()
   473  		for i1, n1 := range s {
   474  			if n1 != nil && n1.Op == OINLCALL {
   475  				s[i1] = inlconv2expr(s[i1])
   476  			}
   477  		}
   478  	}
   479  
   480  	inlnodelist(n.Rlist)
   481  	if n.Op == OAS2FUNC && n.Rlist.First().Op == OINLCALL {
   482  		n.Rlist.Set(inlconv2list(n.Rlist.First()))
   483  		n.Op = OAS2
   484  		n.SetTypecheck(0)
   485  		n = typecheck(n, Etop)
   486  	} else {
   487  		s := n.Rlist.Slice()
   488  		for i1, n1 := range s {
   489  			if n1.Op == OINLCALL {
   490  				if n.Op == OIF {
   491  					inlconv2stmt(n1)
   492  				} else {
   493  					s[i1] = inlconv2expr(s[i1])
   494  				}
   495  			}
   496  		}
   497  	}
   498  
   499  	inlnodelist(n.Nbody)
   500  	for _, n := range n.Nbody.Slice() {
   501  		if n.Op == OINLCALL {
   502  			inlconv2stmt(n)
   503  		}
   504  	}
   505  
   506  	// with all the branches out of the way, it is now time to
   507  	// transmogrify this node itself unless inhibited by the
   508  	// switch at the top of this function.
   509  	switch n.Op {
   510  	case OCALLFUNC, OCALLMETH:
   511  		if n.NoInline() {
   512  			return n
   513  		}
   514  	}
   515  
   516  	switch n.Op {
   517  	case OCALLFUNC:
   518  		if Debug['m'] > 3 {
   519  			fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
   520  		}
   521  		if n.Left.Func != nil && n.Left.Func.Inl.Len() != 0 && !isIntrinsicCall(n) { // normal case
   522  			n = mkinlcall(n, n.Left, n.Isddd())
   523  		} else if n.isMethodCalledAsFunction() && asNode(n.Left.Sym.Def) != nil {
   524  			n = mkinlcall(n, asNode(n.Left.Sym.Def), n.Isddd())
   525  		}
   526  
   527  	case OCALLMETH:
   528  		if Debug['m'] > 3 {
   529  			fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
   530  		}
   531  
   532  		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
   533  		if n.Left.Type == nil {
   534  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   535  		}
   536  
   537  		if n.Left.Type.Nname() == nil {
   538  			Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
   539  		}
   540  
   541  		n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), n.Isddd())
   542  	}
   543  
   544  	lineno = lno
   545  	return n
   546  }
   547  
   548  // The result of mkinlcall MUST be assigned back to n, e.g.
   549  // 	n.Left = mkinlcall(n.Left, fn, isddd)
   550  func mkinlcall(n *Node, fn *Node, isddd bool) *Node {
   551  	save_safemode := safemode
   552  
   553  	// imported functions may refer to unsafe as long as the
   554  	// package was marked safe during import (already checked).
   555  	pkg := fnpkg(fn)
   556  
   557  	if pkg != localpkg && pkg != nil {
   558  		safemode = false
   559  	}
   560  	n = mkinlcall1(n, fn, isddd)
   561  	safemode = save_safemode
   562  	return n
   563  }
   564  
   565  func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
   566  	if asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
   567  		inlvar := inlvars[asNode(t.Nname)]
   568  		if inlvar == nil {
   569  			Fatalf("missing inlvar for %v\n", asNode(t.Nname))
   570  		}
   571  		return inlvar
   572  	}
   573  
   574  	return typecheck(nblank, Erv|Easgn)
   575  }
   576  
   577  var inlgen int
   578  
   579  // If n is a call, and fn is a function with an inlinable body,
   580  // return an OINLCALL.
   581  // On return ninit has the parameter assignments, the nbody is the
   582  // inlined function body and list, rlist contain the input, output
   583  // parameters.
   584  // The result of mkinlcall1 MUST be assigned back to n, e.g.
   585  // 	n.Left = mkinlcall1(n.Left, fn, isddd)
   586  func mkinlcall1(n, fn *Node, isddd bool) *Node {
   587  	if fn.Func.Inl.Len() == 0 {
   588  		// No inlinable body.
   589  		return n
   590  	}
   591  
   592  	if fn == Curfn || fn.Name.Defn == Curfn {
   593  		// Can't recursively inline a function into itself.
   594  		return n
   595  	}
   596  
   597  	if Debug['l'] < 2 {
   598  		typecheckinl(fn)
   599  	}
   600  
   601  	// We have a function node, and it has an inlineable body.
   602  	if Debug['m'] > 1 {
   603  		fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, fn.Func.Inl)
   604  	} else if Debug['m'] != 0 {
   605  		fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
   606  	}
   607  	if Debug['m'] > 2 {
   608  		fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
   609  	}
   610  
   611  	ninit := n.Ninit
   612  
   613  	// Find declarations corresponding to inlineable body.
   614  	var dcl []*Node
   615  	if fn.Name.Defn != nil {
   616  		dcl = fn.Func.Inldcl.Slice() // local function
   617  	} else {
   618  		dcl = fn.Func.Dcl // imported function
   619  	}
   620  
   621  	// Make temp names to use instead of the originals.
   622  	inlvars := make(map[*Node]*Node)
   623  	for _, ln := range dcl {
   624  		if ln.Op != ONAME {
   625  			continue
   626  		}
   627  		if ln.Class() == PPARAMOUT { // return values handled below.
   628  			continue
   629  		}
   630  		if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
   631  			continue
   632  		}
   633  		inlvars[ln] = typecheck(inlvar(ln), Erv)
   634  		if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
   635  			ninit.Append(nod(ODCL, inlvars[ln], nil))
   636  		}
   637  	}
   638  
   639  	// temporaries for return values.
   640  	var retvars []*Node
   641  	for i, t := range fn.Type.Results().Fields().Slice() {
   642  		var m *Node
   643  		if t != nil && asNode(t.Nname) != nil && !isblank(asNode(t.Nname)) {
   644  			m = inlvar(asNode(t.Nname))
   645  			m = typecheck(m, Erv)
   646  			inlvars[asNode(t.Nname)] = m
   647  		} else {
   648  			// anonymous return values, synthesize names for use in assignment that replaces return
   649  			m = retvar(t, i)
   650  		}
   651  
   652  		ninit.Append(nod(ODCL, m, nil))
   653  		retvars = append(retvars, m)
   654  	}
   655  
   656  	// Assign arguments to the parameters' temp names.
   657  	as := nod(OAS2, nil, nil)
   658  	as.Rlist.Set(n.List.Slice())
   659  
   660  	// For non-dotted calls to variadic functions, we assign the
   661  	// variadic parameter's temp name separately.
   662  	var vas *Node
   663  
   664  	if fn.IsMethod() {
   665  		rcv := fn.Type.Recv()
   666  
   667  		if n.Left.Op == ODOTMETH {
   668  			// For x.M(...), assign x directly to the
   669  			// receiver parameter.
   670  			if n.Left.Left == nil {
   671  				Fatalf("method call without receiver: %+v", n)
   672  			}
   673  			ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
   674  			ras = typecheck(ras, Etop)
   675  			ninit.Append(ras)
   676  		} else {
   677  			// For T.M(...), add the receiver parameter to
   678  			// as.List, so it's assigned by the normal
   679  			// arguments.
   680  			if as.Rlist.Len() == 0 {
   681  				Fatalf("non-method call to method without first arg: %+v", n)
   682  			}
   683  			as.List.Append(tinlvar(rcv, inlvars))
   684  		}
   685  	}
   686  
   687  	for _, param := range fn.Type.Params().Fields().Slice() {
   688  		// For ordinary parameters or variadic parameters in
   689  		// dotted calls, just add the variable to the
   690  		// assignment list, and we're done.
   691  		if !param.Isddd() || isddd {
   692  			as.List.Append(tinlvar(param, inlvars))
   693  			continue
   694  		}
   695  
   696  		// Otherwise, we need to collect the remaining values
   697  		// to pass as a slice.
   698  
   699  		numvals := n.List.Len()
   700  		if numvals == 1 && n.List.First().Type.IsFuncArgStruct() {
   701  			numvals = n.List.First().Type.NumFields()
   702  		}
   703  
   704  		x := as.List.Len()
   705  		for as.List.Len() < numvals {
   706  			as.List.Append(argvar(param.Type, as.List.Len()))
   707  		}
   708  		varargs := as.List.Slice()[x:]
   709  
   710  		vas = nod(OAS, tinlvar(param, inlvars), nil)
   711  		if len(varargs) == 0 {
   712  			vas.Right = nodnil()
   713  			vas.Right.Type = param.Type
   714  		} else {
   715  			vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
   716  			vas.Right.List.Set(varargs)
   717  		}
   718  	}
   719  
   720  	if as.Rlist.Len() != 0 {
   721  		as = typecheck(as, Etop)
   722  		ninit.Append(as)
   723  	}
   724  
   725  	if vas != nil {
   726  		vas = typecheck(vas, Etop)
   727  		ninit.Append(vas)
   728  	}
   729  
   730  	// Zero the return parameters.
   731  	for _, n := range retvars {
   732  		ras := nod(OAS, n, nil)
   733  		ras = typecheck(ras, Etop)
   734  		ninit.Append(ras)
   735  	}
   736  
   737  	retlabel := autolabel(".i")
   738  	retlabel.Etype = 1 // flag 'safe' for escape analysis (no backjumps)
   739  
   740  	inlgen++
   741  
   742  	parent := -1
   743  	if b := Ctxt.PosTable.Pos(n.Pos).Base(); b != nil {
   744  		parent = b.InliningIndex()
   745  	}
   746  	newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
   747  
   748  	subst := inlsubst{
   749  		retlabel:    retlabel,
   750  		retvars:     retvars,
   751  		inlvars:     inlvars,
   752  		bases:       make(map[*src.PosBase]*src.PosBase),
   753  		newInlIndex: newIndex,
   754  	}
   755  
   756  	body := subst.list(fn.Func.Inl)
   757  
   758  	lab := nod(OLABEL, retlabel, nil)
   759  	body = append(body, lab)
   760  
   761  	typecheckslice(body, Etop)
   762  
   763  	//dumplist("ninit post", ninit);
   764  
   765  	call := nod(OINLCALL, nil, nil)
   766  	call.Ninit.Set(ninit.Slice())
   767  	call.Nbody.Set(body)
   768  	call.Rlist.Set(retvars)
   769  	call.Type = n.Type
   770  	call.SetTypecheck(1)
   771  
   772  	// transitive inlining
   773  	// might be nice to do this before exporting the body,
   774  	// but can't emit the body with inlining expanded.
   775  	// instead we emit the things that the body needs
   776  	// and each use must redo the inlining.
   777  	// luckily these are small.
   778  	inlnodelist(call.Nbody)
   779  	for _, n := range call.Nbody.Slice() {
   780  		if n.Op == OINLCALL {
   781  			inlconv2stmt(n)
   782  		}
   783  	}
   784  
   785  	if Debug['m'] > 2 {
   786  		fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
   787  	}
   788  
   789  	return call
   790  }
   791  
   792  // Every time we expand a function we generate a new set of tmpnames,
   793  // PAUTO's in the calling functions, and link them off of the
   794  // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
   795  func inlvar(var_ *Node) *Node {
   796  	if Debug['m'] > 3 {
   797  		fmt.Printf("inlvar %+v\n", var_)
   798  	}
   799  
   800  	n := newname(var_.Sym)
   801  	n.Type = var_.Type
   802  	n.SetClass(PAUTO)
   803  	n.Name.SetUsed(true)
   804  	n.Name.Curfn = Curfn // the calling function, not the called one
   805  	n.SetAddrtaken(var_.Addrtaken())
   806  
   807  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   808  	return n
   809  }
   810  
   811  // Synthesize a variable to store the inlined function's results in.
   812  func retvar(t *types.Field, i int) *Node {
   813  	n := newname(lookupN("~r", i))
   814  	n.Type = t.Type
   815  	n.SetClass(PAUTO)
   816  	n.Name.SetUsed(true)
   817  	n.Name.Curfn = Curfn // the calling function, not the called one
   818  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   819  	return n
   820  }
   821  
   822  // Synthesize a variable to store the inlined function's arguments
   823  // when they come from a multiple return call.
   824  func argvar(t *types.Type, i int) *Node {
   825  	n := newname(lookupN("~arg", i))
   826  	n.Type = t.Elem()
   827  	n.SetClass(PAUTO)
   828  	n.Name.SetUsed(true)
   829  	n.Name.Curfn = Curfn // the calling function, not the called one
   830  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
   831  	return n
   832  }
   833  
   834  // The inlsubst type implements the actual inlining of a single
   835  // function call.
   836  type inlsubst struct {
   837  	// Target of the goto substituted in place of a return.
   838  	retlabel *Node
   839  
   840  	// Temporary result variables.
   841  	retvars []*Node
   842  
   843  	inlvars map[*Node]*Node
   844  
   845  	// bases maps from original PosBase to PosBase with an extra
   846  	// inlined call frame.
   847  	bases map[*src.PosBase]*src.PosBase
   848  
   849  	// newInlIndex is the index of the inlined call frame to
   850  	// insert for inlined nodes.
   851  	newInlIndex int
   852  }
   853  
   854  // list inlines a list of nodes.
   855  func (subst *inlsubst) list(ll Nodes) []*Node {
   856  	s := make([]*Node, 0, ll.Len())
   857  	for _, n := range ll.Slice() {
   858  		s = append(s, subst.node(n))
   859  	}
   860  	return s
   861  }
   862  
   863  // node recursively copies a node from the saved pristine body of the
   864  // inlined function, substituting references to input/output
   865  // parameters with ones to the tmpnames, and substituting returns with
   866  // assignments to the output.
   867  func (subst *inlsubst) node(n *Node) *Node {
   868  	if n == nil {
   869  		return nil
   870  	}
   871  
   872  	switch n.Op {
   873  	case ONAME:
   874  		if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
   875  			if Debug['m'] > 2 {
   876  				fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
   877  			}
   878  			return inlvar
   879  		}
   880  
   881  		if Debug['m'] > 2 {
   882  			fmt.Printf("not substituting name %+v\n", n)
   883  		}
   884  		return n
   885  
   886  	case OLITERAL, OTYPE:
   887  		// If n is a named constant or type, we can continue
   888  		// using it in the inline copy. Otherwise, make a copy
   889  		// so we can update the line number.
   890  		if n.Sym != nil {
   891  			return n
   892  		}
   893  
   894  		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
   895  
   896  	//		dump("Return before substitution", n);
   897  	case ORETURN:
   898  		m := nod(OGOTO, subst.retlabel, nil)
   899  		m.Ninit.Set(subst.list(n.Ninit))
   900  
   901  		if len(subst.retvars) != 0 && n.List.Len() != 0 {
   902  			as := nod(OAS2, nil, nil)
   903  
   904  			// Make a shallow copy of retvars.
   905  			// Otherwise OINLCALL.Rlist will be the same list,
   906  			// and later walk and typecheck may clobber it.
   907  			for _, n := range subst.retvars {
   908  				as.List.Append(n)
   909  			}
   910  			as.Rlist.Set(subst.list(n.List))
   911  			as = typecheck(as, Etop)
   912  			m.Ninit.Append(as)
   913  		}
   914  
   915  		typecheckslice(m.Ninit.Slice(), Etop)
   916  		m = typecheck(m, Etop)
   917  
   918  		//		dump("Return after substitution", m);
   919  		return m
   920  
   921  	case OGOTO, OLABEL:
   922  		m := nod(OXXX, nil, nil)
   923  		*m = *n
   924  		m.Pos = subst.updatedPos(m.Pos)
   925  		m.Ninit.Set(nil)
   926  		p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
   927  		m.Left = newname(lookup(p))
   928  
   929  		return m
   930  	}
   931  
   932  	m := nod(OXXX, nil, nil)
   933  	*m = *n
   934  	m.Pos = subst.updatedPos(m.Pos)
   935  	m.Ninit.Set(nil)
   936  
   937  	if n.Op == OCLOSURE {
   938  		Fatalf("cannot inline function containing closure: %+v", n)
   939  	}
   940  
   941  	m.Left = subst.node(n.Left)
   942  	m.Right = subst.node(n.Right)
   943  	m.List.Set(subst.list(n.List))
   944  	m.Rlist.Set(subst.list(n.Rlist))
   945  	m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
   946  	m.Nbody.Set(subst.list(n.Nbody))
   947  
   948  	return m
   949  }
   950  
   951  func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
   952  	pos := Ctxt.PosTable.Pos(xpos)
   953  	oldbase := pos.Base() // can be nil
   954  	newbase := subst.bases[oldbase]
   955  	if newbase == nil {
   956  		newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
   957  		subst.bases[oldbase] = newbase
   958  	}
   959  	pos.SetBase(newbase)
   960  	return Ctxt.PosTable.XPos(pos)
   961  }
   962  
   963  func (n *Node) isMethodCalledAsFunction() bool {
   964  	return n.Left.Op == ONAME && n.Left.Left != nil && n.Left.Left.Op == OTYPE && n.Left.Right != nil && n.Left.Right.Op == ONAME
   965  }