github.com/hikaru7719/go@v0.0.0-20181025140707-c8b2ac68906a/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. Additional levels (beyond -l) may be buggy and
    12  // are not supported.
    13  //      0: disabled
    14  //      1: 80-nodes leaf functions, oneliners, panic, lazy typechecking (default)
    15  //      2: (unassigned)
    16  //      3: (unassigned)
    17  //      4: allow non-leaf functions
    18  //
    19  // At some point this may get another default and become switch-offable with -N.
    20  //
    21  // The -d typcheckinl flag enables early typechecking of all imported bodies,
    22  // which is useful to flush out bugs.
    23  //
    24  // The debug['m'] flag enables diagnostic output.  a single -m is useful for verifying
    25  // which calls get inlined or not, more is for debugging, and may go away at any point.
    26  
    27  package gc
    28  
    29  import (
    30  	"cmd/compile/internal/types"
    31  	"cmd/internal/obj"
    32  	"cmd/internal/src"
    33  	"fmt"
    34  	"strings"
    35  )
    36  
    37  // Inlining budget parameters, gathered in one place
    38  const (
    39  	inlineMaxBudget       = 80
    40  	inlineExtraAppendCost = 0
    41  	inlineExtraCallCost   = inlineMaxBudget // default is do not inline, -l=4 enables by using 1 instead.
    42  	inlineExtraPanicCost  = 1               // do not penalize inlining panics.
    43  	inlineExtraThrowCost  = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
    44  
    45  	inlineBigFunctionNodes   = 5000 // Functions with this many nodes are considered "big".
    46  	inlineBigFunctionMaxCost = 20   // Max cost of inlinee when inlining into a "big" function.
    47  )
    48  
    49  // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods
    50  // the ->sym can be re-used in the local package, so peel it off the receiver's type.
    51  func fnpkg(fn *Node) *types.Pkg {
    52  	if fn.IsMethod() {
    53  		// method
    54  		rcvr := fn.Type.Recv().Type
    55  
    56  		if rcvr.IsPtr() {
    57  			rcvr = rcvr.Elem()
    58  		}
    59  		if rcvr.Sym == nil {
    60  			Fatalf("receiver with no sym: [%v] %L  (%v)", fn.Sym, fn, rcvr)
    61  		}
    62  		return rcvr.Sym.Pkg
    63  	}
    64  
    65  	// non-method
    66  	return fn.Sym.Pkg
    67  }
    68  
    69  // Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck
    70  // because they're a copy of an already checked body.
    71  func typecheckinl(fn *Node) {
    72  	lno := setlineno(fn)
    73  
    74  	expandInline(fn)
    75  
    76  	// typecheckinl is only for imported functions;
    77  	// their bodies may refer to unsafe as long as the package
    78  	// was marked safe during import (which was checked then).
    79  	// the ->inl of a local function has been typechecked before caninl copied it.
    80  	pkg := fnpkg(fn)
    81  
    82  	if pkg == localpkg || pkg == nil {
    83  		return // typecheckinl on local function
    84  	}
    85  
    86  	if Debug['m'] > 2 || Debug_export != 0 {
    87  		fmt.Printf("typecheck import [%v] %L { %#v }\n", fn.Sym, fn, asNodes(fn.Func.Inl.Body))
    88  	}
    89  
    90  	savefn := Curfn
    91  	Curfn = fn
    92  	typecheckslice(fn.Func.Inl.Body, Etop)
    93  	Curfn = savefn
    94  
    95  	// During typechecking, declarations are added to
    96  	// Curfn.Func.Dcl. Move them to Inl.Dcl for consistency with
    97  	// how local functions behave. (Append because typecheckinl
    98  	// may be called multiple times.)
    99  	fn.Func.Inl.Dcl = append(fn.Func.Inl.Dcl, fn.Func.Dcl...)
   100  	fn.Func.Dcl = nil
   101  
   102  	lineno = lno
   103  }
   104  
   105  // Caninl determines whether fn is inlineable.
   106  // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy.
   107  // fn and ->nbody will already have been typechecked.
   108  func caninl(fn *Node) {
   109  	if fn.Op != ODCLFUNC {
   110  		Fatalf("caninl %v", fn)
   111  	}
   112  	if fn.Func.Nname == nil {
   113  		Fatalf("caninl no nname %+v", fn)
   114  	}
   115  
   116  	var reason string // reason, if any, that the function was not inlined
   117  	if Debug['m'] > 1 {
   118  		defer func() {
   119  			if reason != "" {
   120  				fmt.Printf("%v: cannot inline %v: %s\n", fn.Line(), fn.Func.Nname, reason)
   121  			}
   122  		}()
   123  	}
   124  
   125  	// If marked "go:noinline", don't inline
   126  	if fn.Func.Pragma&Noinline != 0 {
   127  		reason = "marked go:noinline"
   128  		return
   129  	}
   130  
   131  	// If marked "go:norace" and -race compilation, don't inline.
   132  	if flag_race && fn.Func.Pragma&Norace != 0 {
   133  		reason = "marked go:norace with -race compilation"
   134  		return
   135  	}
   136  
   137  	// If marked "go:cgo_unsafe_args", don't inline, since the
   138  	// function makes assumptions about its argument frame layout.
   139  	if fn.Func.Pragma&CgoUnsafeArgs != 0 {
   140  		reason = "marked go:cgo_unsafe_args"
   141  		return
   142  	}
   143  
   144  	// The nowritebarrierrec checker currently works at function
   145  	// granularity, so inlining yeswritebarrierrec functions can
   146  	// confuse it (#22342). As a workaround, disallow inlining
   147  	// them for now.
   148  	if fn.Func.Pragma&Yeswritebarrierrec != 0 {
   149  		reason = "marked go:yeswritebarrierrec"
   150  		return
   151  	}
   152  
   153  	// If fn has no body (is defined outside of Go), cannot inline it.
   154  	if fn.Nbody.Len() == 0 {
   155  		reason = "no function body"
   156  		return
   157  	}
   158  
   159  	if fn.Typecheck() == 0 {
   160  		Fatalf("caninl on non-typechecked function %v", fn)
   161  	}
   162  
   163  	n := fn.Func.Nname
   164  	if n.Func.InlinabilityChecked() {
   165  		return
   166  	}
   167  	defer n.Func.SetInlinabilityChecked(true)
   168  
   169  	cc := int32(inlineExtraCallCost)
   170  	if Debug['l'] == 4 {
   171  		cc = 1 // this appears to yield better performance than 0.
   172  	}
   173  
   174  	// At this point in the game the function we're looking at may
   175  	// have "stale" autos, vars that still appear in the Dcl list, but
   176  	// which no longer have any uses in the function body (due to
   177  	// elimination by deadcode). We'd like to exclude these dead vars
   178  	// when creating the "Inline.Dcl" field below; to accomplish this,
   179  	// the hairyVisitor below builds up a map of used/referenced
   180  	// locals, and we use this map to produce a pruned Inline.Dcl
   181  	// list. See issue 25249 for more context.
   182  
   183  	visitor := hairyVisitor{
   184  		budget:        inlineMaxBudget,
   185  		extraCallCost: cc,
   186  		usedLocals:    make(map[*Node]bool),
   187  	}
   188  	if visitor.visitList(fn.Nbody) {
   189  		reason = visitor.reason
   190  		return
   191  	}
   192  	if visitor.budget < 0 {
   193  		reason = fmt.Sprintf("function too complex: cost %d exceeds budget %d", inlineMaxBudget-visitor.budget, inlineMaxBudget)
   194  		return
   195  	}
   196  
   197  	n.Func.Inl = &Inline{
   198  		Cost: inlineMaxBudget - visitor.budget,
   199  		Dcl:  inlcopylist(pruneUnusedAutos(n.Name.Defn.Func.Dcl, &visitor)),
   200  		Body: inlcopylist(fn.Nbody.Slice()),
   201  	}
   202  
   203  	// hack, TODO, check for better way to link method nodes back to the thing with the ->inl
   204  	// this is so export can find the body of a method
   205  	fn.Type.FuncType().Nname = asTypesNode(n)
   206  
   207  	if Debug['m'] > 1 {
   208  		fmt.Printf("%v: can inline %#v as: %#v { %#v }\n", fn.Line(), n, fn.Type, asNodes(n.Func.Inl.Body))
   209  	} else if Debug['m'] != 0 {
   210  		fmt.Printf("%v: can inline %v\n", fn.Line(), n)
   211  	}
   212  }
   213  
   214  // inlFlood marks n's inline body for export and recursively ensures
   215  // all called functions are marked too.
   216  func inlFlood(n *Node) {
   217  	if n == nil {
   218  		return
   219  	}
   220  	if n.Op != ONAME || n.Class() != PFUNC {
   221  		Fatalf("inlFlood: unexpected %v, %v, %v", n, n.Op, n.Class())
   222  	}
   223  	if n.Func == nil {
   224  		Fatalf("inlFlood: missing Func on %v", n)
   225  	}
   226  	if n.Func.Inl == nil {
   227  		return
   228  	}
   229  
   230  	if n.Func.ExportInline() {
   231  		return
   232  	}
   233  	n.Func.SetExportInline(true)
   234  
   235  	typecheckinl(n)
   236  
   237  	inspectList(asNodes(n.Func.Inl.Body), func(n *Node) bool {
   238  		switch n.Op {
   239  		case ONAME:
   240  			// Mark any referenced global variables or
   241  			// functions for reexport. Skip methods,
   242  			// because they're reexported alongside their
   243  			// receiver type.
   244  			if n.Class() == PEXTERN || n.Class() == PFUNC && !n.isMethodExpression() {
   245  				exportsym(n)
   246  			}
   247  
   248  		case OCALLFUNC, OCALLMETH:
   249  			// Recursively flood any functions called by
   250  			// this one.
   251  			inlFlood(asNode(n.Left.Type.Nname()))
   252  		}
   253  		return true
   254  	})
   255  }
   256  
   257  // hairyVisitor visits a function body to determine its inlining
   258  // hairiness and whether or not it can be inlined.
   259  type hairyVisitor struct {
   260  	budget        int32
   261  	reason        string
   262  	extraCallCost int32
   263  	usedLocals    map[*Node]bool
   264  }
   265  
   266  // Look for anything we want to punt on.
   267  func (v *hairyVisitor) visitList(ll Nodes) bool {
   268  	for _, n := range ll.Slice() {
   269  		if v.visit(n) {
   270  			return true
   271  		}
   272  	}
   273  	return false
   274  }
   275  
   276  func (v *hairyVisitor) visit(n *Node) bool {
   277  	if n == nil {
   278  		return false
   279  	}
   280  
   281  	switch n.Op {
   282  	// Call is okay if inlinable and we have the budget for the body.
   283  	case OCALLFUNC:
   284  		if isIntrinsicCall(n) {
   285  			v.budget--
   286  			break
   287  		}
   288  		// Functions that call runtime.getcaller{pc,sp} can not be inlined
   289  		// because getcaller{pc,sp} expect a pointer to the caller's first argument.
   290  		//
   291  		// runtime.throw is a "cheap call" like panic in normal code.
   292  		if n.Left.Op == ONAME && n.Left.Class() == PFUNC && isRuntimePkg(n.Left.Sym.Pkg) {
   293  			fn := n.Left.Sym.Name
   294  			if fn == "getcallerpc" || fn == "getcallersp" {
   295  				v.reason = "call to " + fn
   296  				return true
   297  			}
   298  			if fn == "throw" {
   299  				v.budget -= inlineExtraThrowCost
   300  				break
   301  			}
   302  		}
   303  
   304  		if fn := n.Left.Func; fn != nil && fn.Inl != nil {
   305  			v.budget -= fn.Inl.Cost
   306  			break
   307  		}
   308  		if n.Left.isMethodExpression() {
   309  			if d := asNode(n.Left.Sym.Def); d != nil && d.Func.Inl != nil {
   310  				v.budget -= d.Func.Inl.Cost
   311  				break
   312  			}
   313  		}
   314  		// TODO(mdempsky): Budget for OCLOSURE calls if we
   315  		// ever allow that. See #15561 and #23093.
   316  
   317  		// Call cost for non-leaf inlining.
   318  		v.budget -= v.extraCallCost
   319  
   320  	// Call is okay if inlinable and we have the budget for the body.
   321  	case OCALLMETH:
   322  		t := n.Left.Type
   323  		if t == nil {
   324  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   325  		}
   326  		if t.Nname() == nil {
   327  			Fatalf("no function definition for [%p] %+v\n", t, t)
   328  		}
   329  		if isRuntimePkg(n.Left.Sym.Pkg) {
   330  			fn := n.Left.Sym.Name
   331  			if fn == "heapBits.nextArena" {
   332  				// Special case: explicitly allow
   333  				// mid-stack inlining of
   334  				// runtime.heapBits.next even though
   335  				// it calls slow-path
   336  				// runtime.heapBits.nextArena.
   337  				//
   338  				// TODO(austin): Once mid-stack
   339  				// inlining is the default, remove
   340  				// this special case.
   341  				break
   342  			}
   343  		}
   344  		if inlfn := asNode(t.FuncType().Nname).Func; inlfn.Inl != nil {
   345  			v.budget -= inlfn.Inl.Cost
   346  			break
   347  		}
   348  		// Call cost for non-leaf inlining.
   349  		v.budget -= v.extraCallCost
   350  
   351  	// Things that are too hairy, irrespective of the budget
   352  	case OCALL, OCALLINTER:
   353  		// Call cost for non-leaf inlining.
   354  		v.budget -= v.extraCallCost
   355  
   356  	case OPANIC:
   357  		v.budget -= inlineExtraPanicCost
   358  
   359  	case ORECOVER:
   360  		// recover matches the argument frame pointer to find
   361  		// the right panic value, so it needs an argument frame.
   362  		v.reason = "call to recover"
   363  		return true
   364  
   365  	case OCLOSURE,
   366  		OCALLPART,
   367  		ORANGE,
   368  		OFOR,
   369  		OFORUNTIL,
   370  		OSELECT,
   371  		OTYPESW,
   372  		OPROC,
   373  		ODEFER,
   374  		ODCLTYPE, // can't print yet
   375  		OBREAK,
   376  		ORETJMP:
   377  		v.reason = "unhandled op " + n.Op.String()
   378  		return true
   379  
   380  	case OAPPEND:
   381  		v.budget -= inlineExtraAppendCost
   382  
   383  	case ODCLCONST, OEMPTY, OFALL, OLABEL:
   384  		// These nodes don't produce code; omit from inlining budget.
   385  		return false
   386  
   387  	case OIF:
   388  		if Isconst(n.Left, CTBOOL) {
   389  			// This if and the condition cost nothing.
   390  			return v.visitList(n.Ninit) || v.visitList(n.Nbody) ||
   391  				v.visitList(n.Rlist)
   392  		}
   393  
   394  	case ONAME:
   395  		if n.Class() == PAUTO {
   396  			v.usedLocals[n] = true
   397  		}
   398  
   399  	}
   400  
   401  	v.budget--
   402  
   403  	// When debugging, don't stop early, to get full cost of inlining this function
   404  	if v.budget < 0 && Debug['m'] < 2 {
   405  		return true
   406  	}
   407  
   408  	return v.visit(n.Left) || v.visit(n.Right) ||
   409  		v.visitList(n.List) || v.visitList(n.Rlist) ||
   410  		v.visitList(n.Ninit) || v.visitList(n.Nbody)
   411  }
   412  
   413  // Inlcopy and inlcopylist recursively copy the body of a function.
   414  // Any name-like node of non-local class is marked for re-export by adding it to
   415  // the exportlist.
   416  func inlcopylist(ll []*Node) []*Node {
   417  	s := make([]*Node, 0, len(ll))
   418  	for _, n := range ll {
   419  		s = append(s, inlcopy(n))
   420  	}
   421  	return s
   422  }
   423  
   424  func inlcopy(n *Node) *Node {
   425  	if n == nil {
   426  		return nil
   427  	}
   428  
   429  	switch n.Op {
   430  	case ONAME, OTYPE, OLITERAL:
   431  		return n
   432  	}
   433  
   434  	m := n.copy()
   435  	if m.Func != nil {
   436  		Fatalf("unexpected Func: %v", m)
   437  	}
   438  	m.Left = inlcopy(n.Left)
   439  	m.Right = inlcopy(n.Right)
   440  	m.List.Set(inlcopylist(n.List.Slice()))
   441  	m.Rlist.Set(inlcopylist(n.Rlist.Slice()))
   442  	m.Ninit.Set(inlcopylist(n.Ninit.Slice()))
   443  	m.Nbody.Set(inlcopylist(n.Nbody.Slice()))
   444  
   445  	return m
   446  }
   447  
   448  func countNodes(n *Node) int {
   449  	if n == nil {
   450  		return 0
   451  	}
   452  	cnt := 1
   453  	cnt += countNodes(n.Left)
   454  	cnt += countNodes(n.Right)
   455  	for _, n1 := range n.Ninit.Slice() {
   456  		cnt += countNodes(n1)
   457  	}
   458  	for _, n1 := range n.Nbody.Slice() {
   459  		cnt += countNodes(n1)
   460  	}
   461  	for _, n1 := range n.List.Slice() {
   462  		cnt += countNodes(n1)
   463  	}
   464  	for _, n1 := range n.Rlist.Slice() {
   465  		cnt += countNodes(n1)
   466  	}
   467  	return cnt
   468  }
   469  
   470  // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
   471  // calls made to inlineable functions. This is the external entry point.
   472  func inlcalls(fn *Node) {
   473  	savefn := Curfn
   474  	Curfn = fn
   475  	maxCost := int32(inlineMaxBudget)
   476  	if countNodes(fn) >= inlineBigFunctionNodes {
   477  		maxCost = inlineBigFunctionMaxCost
   478  	}
   479  	fn = inlnode(fn, maxCost)
   480  	if fn != Curfn {
   481  		Fatalf("inlnode replaced curfn")
   482  	}
   483  	Curfn = savefn
   484  }
   485  
   486  // Turn an OINLCALL into a statement.
   487  func inlconv2stmt(n *Node) {
   488  	n.Op = OBLOCK
   489  
   490  	// n->ninit stays
   491  	n.List.Set(n.Nbody.Slice())
   492  
   493  	n.Nbody.Set(nil)
   494  	n.Rlist.Set(nil)
   495  }
   496  
   497  // Turn an OINLCALL into a single valued expression.
   498  // The result of inlconv2expr MUST be assigned back to n, e.g.
   499  // 	n.Left = inlconv2expr(n.Left)
   500  func inlconv2expr(n *Node) *Node {
   501  	r := n.Rlist.First()
   502  	return addinit(r, append(n.Ninit.Slice(), n.Nbody.Slice()...))
   503  }
   504  
   505  // Turn the rlist (with the return values) of the OINLCALL in
   506  // n into an expression list lumping the ninit and body
   507  // containing the inlined statements on the first list element so
   508  // order will be preserved Used in return, oas2func and call
   509  // statements.
   510  func inlconv2list(n *Node) []*Node {
   511  	if n.Op != OINLCALL || n.Rlist.Len() == 0 {
   512  		Fatalf("inlconv2list %+v\n", n)
   513  	}
   514  
   515  	s := n.Rlist.Slice()
   516  	s[0] = addinit(s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...))
   517  	return s
   518  }
   519  
   520  func inlnodelist(l Nodes, maxCost int32) {
   521  	s := l.Slice()
   522  	for i := range s {
   523  		s[i] = inlnode(s[i], maxCost)
   524  	}
   525  }
   526  
   527  // inlnode recurses over the tree to find inlineable calls, which will
   528  // be turned into OINLCALLs by mkinlcall. When the recursion comes
   529  // back up will examine left, right, list, rlist, ninit, ntest, nincr,
   530  // nbody and nelse and use one of the 4 inlconv/glue functions above
   531  // to turn the OINLCALL into an expression, a statement, or patch it
   532  // in to this nodes list or rlist as appropriate.
   533  // NOTE it makes no sense to pass the glue functions down the
   534  // recursion to the level where the OINLCALL gets created because they
   535  // have to edit /this/ n, so you'd have to push that one down as well,
   536  // but then you may as well do it here.  so this is cleaner and
   537  // shorter and less complicated.
   538  // The result of inlnode MUST be assigned back to n, e.g.
   539  // 	n.Left = inlnode(n.Left)
   540  func inlnode(n *Node, maxCost int32) *Node {
   541  	if n == nil {
   542  		return n
   543  	}
   544  
   545  	switch n.Op {
   546  	// inhibit inlining of their argument
   547  	case ODEFER, OPROC:
   548  		switch n.Left.Op {
   549  		case OCALLFUNC, OCALLMETH:
   550  			n.Left.SetNoInline(true)
   551  		}
   552  		return n
   553  
   554  	// TODO do them here (or earlier),
   555  	// so escape analysis can avoid more heapmoves.
   556  	case OCLOSURE:
   557  		return n
   558  	}
   559  
   560  	lno := setlineno(n)
   561  
   562  	inlnodelist(n.Ninit, maxCost)
   563  	for _, n1 := range n.Ninit.Slice() {
   564  		if n1.Op == OINLCALL {
   565  			inlconv2stmt(n1)
   566  		}
   567  	}
   568  
   569  	n.Left = inlnode(n.Left, maxCost)
   570  	if n.Left != nil && n.Left.Op == OINLCALL {
   571  		n.Left = inlconv2expr(n.Left)
   572  	}
   573  
   574  	n.Right = inlnode(n.Right, maxCost)
   575  	if n.Right != nil && n.Right.Op == OINLCALL {
   576  		if n.Op == OFOR || n.Op == OFORUNTIL {
   577  			inlconv2stmt(n.Right)
   578  		} else {
   579  			n.Right = inlconv2expr(n.Right)
   580  		}
   581  	}
   582  
   583  	inlnodelist(n.List, maxCost)
   584  	switch n.Op {
   585  	case OBLOCK:
   586  		for _, n2 := range n.List.Slice() {
   587  			if n2.Op == OINLCALL {
   588  				inlconv2stmt(n2)
   589  			}
   590  		}
   591  
   592  	case ORETURN, OCALLFUNC, OCALLMETH, OCALLINTER, OAPPEND, OCOMPLEX:
   593  		// if we just replaced arg in f(arg()) or return arg with an inlined call
   594  		// and arg returns multiple values, glue as list
   595  		if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 {
   596  			n.List.Set(inlconv2list(n.List.First()))
   597  			break
   598  		}
   599  		fallthrough
   600  
   601  	default:
   602  		s := n.List.Slice()
   603  		for i1, n1 := range s {
   604  			if n1 != nil && n1.Op == OINLCALL {
   605  				s[i1] = inlconv2expr(s[i1])
   606  			}
   607  		}
   608  	}
   609  
   610  	inlnodelist(n.Rlist, maxCost)
   611  	if n.Op == OAS2FUNC && n.Rlist.First().Op == OINLCALL {
   612  		n.Rlist.Set(inlconv2list(n.Rlist.First()))
   613  		n.Op = OAS2
   614  		n.SetTypecheck(0)
   615  		n = typecheck(n, Etop)
   616  	} else {
   617  		s := n.Rlist.Slice()
   618  		for i1, n1 := range s {
   619  			if n1.Op == OINLCALL {
   620  				if n.Op == OIF {
   621  					inlconv2stmt(n1)
   622  				} else {
   623  					s[i1] = inlconv2expr(s[i1])
   624  				}
   625  			}
   626  		}
   627  	}
   628  
   629  	inlnodelist(n.Nbody, maxCost)
   630  	for _, n := range n.Nbody.Slice() {
   631  		if n.Op == OINLCALL {
   632  			inlconv2stmt(n)
   633  		}
   634  	}
   635  
   636  	// with all the branches out of the way, it is now time to
   637  	// transmogrify this node itself unless inhibited by the
   638  	// switch at the top of this function.
   639  	switch n.Op {
   640  	case OCALLFUNC, OCALLMETH:
   641  		if n.NoInline() {
   642  			return n
   643  		}
   644  	}
   645  
   646  	switch n.Op {
   647  	case OCALLFUNC:
   648  		if Debug['m'] > 3 {
   649  			fmt.Printf("%v:call to func %+v\n", n.Line(), n.Left)
   650  		}
   651  		if n.Left.Func != nil && n.Left.Func.Inl != nil && !isIntrinsicCall(n) { // normal case
   652  			n = mkinlcall(n, n.Left, maxCost)
   653  		} else if n.Left.isMethodExpression() && asNode(n.Left.Sym.Def) != nil {
   654  			n = mkinlcall(n, asNode(n.Left.Sym.Def), maxCost)
   655  		} else if n.Left.Op == OCLOSURE {
   656  			if f := inlinableClosure(n.Left); f != nil {
   657  				n = mkinlcall(n, f, maxCost)
   658  			}
   659  		} else if n.Left.Op == ONAME && n.Left.Name != nil && n.Left.Name.Defn != nil {
   660  			if d := n.Left.Name.Defn; d.Op == OAS && d.Right.Op == OCLOSURE {
   661  				if f := inlinableClosure(d.Right); f != nil {
   662  					// NB: this check is necessary to prevent indirect re-assignment of the variable
   663  					// having the address taken after the invocation or only used for reads is actually fine
   664  					// but we have no easy way to distinguish the safe cases
   665  					if d.Left.Addrtaken() {
   666  						if Debug['m'] > 1 {
   667  							fmt.Printf("%v: cannot inline escaping closure variable %v\n", n.Line(), n.Left)
   668  						}
   669  						break
   670  					}
   671  
   672  					// ensure the variable is never re-assigned
   673  					if unsafe, a := reassigned(n.Left); unsafe {
   674  						if Debug['m'] > 1 {
   675  							if a != nil {
   676  								fmt.Printf("%v: cannot inline re-assigned closure variable at %v: %v\n", n.Line(), a.Line(), a)
   677  							} else {
   678  								fmt.Printf("%v: cannot inline global closure variable %v\n", n.Line(), n.Left)
   679  							}
   680  						}
   681  						break
   682  					}
   683  					n = mkinlcall(n, f, maxCost)
   684  				}
   685  			}
   686  		}
   687  
   688  	case OCALLMETH:
   689  		if Debug['m'] > 3 {
   690  			fmt.Printf("%v:call to meth %L\n", n.Line(), n.Left.Right)
   691  		}
   692  
   693  		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
   694  		if n.Left.Type == nil {
   695  			Fatalf("no function type for [%p] %+v\n", n.Left, n.Left)
   696  		}
   697  
   698  		if n.Left.Type.Nname() == nil {
   699  			Fatalf("no function definition for [%p] %+v\n", n.Left.Type, n.Left.Type)
   700  		}
   701  
   702  		n = mkinlcall(n, asNode(n.Left.Type.FuncType().Nname), maxCost)
   703  	}
   704  
   705  	lineno = lno
   706  	return n
   707  }
   708  
   709  // inlinableClosure takes an OCLOSURE node and follows linkage to the matching ONAME with
   710  // the inlinable body. Returns nil if the function is not inlinable.
   711  func inlinableClosure(n *Node) *Node {
   712  	c := n.Func.Closure
   713  	caninl(c)
   714  	f := c.Func.Nname
   715  	if f == nil || f.Func.Inl == nil {
   716  		return nil
   717  	}
   718  	return f
   719  }
   720  
   721  // reassigned takes an ONAME node, walks the function in which it is defined, and returns a boolean
   722  // indicating whether the name has any assignments other than its declaration.
   723  // The second return value is the first such assignment encountered in the walk, if any. It is mostly
   724  // useful for -m output documenting the reason for inhibited optimizations.
   725  // NB: global variables are always considered to be re-assigned.
   726  // TODO: handle initial declaration not including an assignment and followed by a single assignment?
   727  func reassigned(n *Node) (bool, *Node) {
   728  	if n.Op != ONAME {
   729  		Fatalf("reassigned %v", n)
   730  	}
   731  	// no way to reliably check for no-reassignment of globals, assume it can be
   732  	if n.Name.Curfn == nil {
   733  		return true, nil
   734  	}
   735  	f := n.Name.Curfn
   736  	// There just might be a good reason for this although this can be pretty surprising:
   737  	// local variables inside a closure have Curfn pointing to the OCLOSURE node instead
   738  	// of the corresponding ODCLFUNC.
   739  	// We need to walk the function body to check for reassignments so we follow the
   740  	// linkage to the ODCLFUNC node as that is where body is held.
   741  	if f.Op == OCLOSURE {
   742  		f = f.Func.Closure
   743  	}
   744  	v := reassignVisitor{name: n}
   745  	a := v.visitList(f.Nbody)
   746  	return a != nil, a
   747  }
   748  
   749  type reassignVisitor struct {
   750  	name *Node
   751  }
   752  
   753  func (v *reassignVisitor) visit(n *Node) *Node {
   754  	if n == nil {
   755  		return nil
   756  	}
   757  	switch n.Op {
   758  	case OAS:
   759  		if n.Left == v.name && n != v.name.Name.Defn {
   760  			return n
   761  		}
   762  		return nil
   763  	case OAS2, OAS2FUNC, OAS2MAPR, OAS2DOTTYPE:
   764  		for _, p := range n.List.Slice() {
   765  			if p == v.name && n != v.name.Name.Defn {
   766  				return n
   767  			}
   768  		}
   769  		return nil
   770  	}
   771  	if a := v.visit(n.Left); a != nil {
   772  		return a
   773  	}
   774  	if a := v.visit(n.Right); a != nil {
   775  		return a
   776  	}
   777  	if a := v.visitList(n.List); a != nil {
   778  		return a
   779  	}
   780  	if a := v.visitList(n.Rlist); a != nil {
   781  		return a
   782  	}
   783  	if a := v.visitList(n.Ninit); a != nil {
   784  		return a
   785  	}
   786  	if a := v.visitList(n.Nbody); a != nil {
   787  		return a
   788  	}
   789  	return nil
   790  }
   791  
   792  func (v *reassignVisitor) visitList(l Nodes) *Node {
   793  	for _, n := range l.Slice() {
   794  		if a := v.visit(n); a != nil {
   795  			return a
   796  		}
   797  	}
   798  	return nil
   799  }
   800  
   801  func tinlvar(t *types.Field, inlvars map[*Node]*Node) *Node {
   802  	if n := asNode(t.Nname); n != nil && !n.isBlank() {
   803  		inlvar := inlvars[n]
   804  		if inlvar == nil {
   805  			Fatalf("missing inlvar for %v\n", n)
   806  		}
   807  		return inlvar
   808  	}
   809  
   810  	return typecheck(nblank, Erv|Easgn)
   811  }
   812  
   813  var inlgen int
   814  
   815  // If n is a call, and fn is a function with an inlinable body,
   816  // return an OINLCALL.
   817  // On return ninit has the parameter assignments, the nbody is the
   818  // inlined function body and list, rlist contain the input, output
   819  // parameters.
   820  // The result of mkinlcall MUST be assigned back to n, e.g.
   821  // 	n.Left = mkinlcall(n.Left, fn, isddd)
   822  func mkinlcall(n, fn *Node, maxCost int32) *Node {
   823  	if fn.Func.Inl == nil {
   824  		// No inlinable body.
   825  		return n
   826  	}
   827  	if fn.Func.Inl.Cost > maxCost {
   828  		// The inlined function body is too big. Typically we use this check to restrict
   829  		// inlining into very big functions.  See issue 26546 and 17566.
   830  		return n
   831  	}
   832  
   833  	if fn == Curfn || fn.Name.Defn == Curfn {
   834  		// Can't recursively inline a function into itself.
   835  		return n
   836  	}
   837  
   838  	if instrumenting && isRuntimePkg(fn.Sym.Pkg) {
   839  		// Runtime package must not be instrumented.
   840  		// Instrument skips runtime package. However, some runtime code can be
   841  		// inlined into other packages and instrumented there. To avoid this,
   842  		// we disable inlining of runtime functions when instrumenting.
   843  		// The example that we observed is inlining of LockOSThread,
   844  		// which lead to false race reports on m contents.
   845  		return n
   846  	}
   847  
   848  	if Debug_typecheckinl == 0 {
   849  		typecheckinl(fn)
   850  	}
   851  
   852  	// We have a function node, and it has an inlineable body.
   853  	if Debug['m'] > 1 {
   854  		fmt.Printf("%v: inlining call to %v %#v { %#v }\n", n.Line(), fn.Sym, fn.Type, asNodes(fn.Func.Inl.Body))
   855  	} else if Debug['m'] != 0 {
   856  		fmt.Printf("%v: inlining call to %v\n", n.Line(), fn)
   857  	}
   858  	if Debug['m'] > 2 {
   859  		fmt.Printf("%v: Before inlining: %+v\n", n.Line(), n)
   860  	}
   861  
   862  	if ssaDump != "" && ssaDump == Curfn.funcname() {
   863  		ssaDumpInlined = append(ssaDumpInlined, fn)
   864  	}
   865  
   866  	ninit := n.Ninit
   867  
   868  	// Make temp names to use instead of the originals.
   869  	inlvars := make(map[*Node]*Node)
   870  
   871  	// record formals/locals for later post-processing
   872  	var inlfvars []*Node
   873  
   874  	// Handle captured variables when inlining closures.
   875  	if fn.Name.Defn != nil {
   876  		if c := fn.Name.Defn.Func.Closure; c != nil {
   877  			for _, v := range c.Func.Closure.Func.Cvars.Slice() {
   878  				if v.Op == OXXX {
   879  					continue
   880  				}
   881  
   882  				o := v.Name.Param.Outer
   883  				// make sure the outer param matches the inlining location
   884  				// NB: if we enabled inlining of functions containing OCLOSURE or refined
   885  				// the reassigned check via some sort of copy propagation this would most
   886  				// likely need to be changed to a loop to walk up to the correct Param
   887  				if o == nil || (o.Name.Curfn != Curfn && o.Name.Curfn.Func.Closure != Curfn) {
   888  					Fatalf("%v: unresolvable capture %v %v\n", n.Line(), fn, v)
   889  				}
   890  
   891  				if v.Name.Byval() {
   892  					iv := typecheck(inlvar(v), Erv)
   893  					ninit.Append(nod(ODCL, iv, nil))
   894  					ninit.Append(typecheck(nod(OAS, iv, o), Etop))
   895  					inlvars[v] = iv
   896  				} else {
   897  					addr := newname(lookup("&" + v.Sym.Name))
   898  					addr.Type = types.NewPtr(v.Type)
   899  					ia := typecheck(inlvar(addr), Erv)
   900  					ninit.Append(nod(ODCL, ia, nil))
   901  					ninit.Append(typecheck(nod(OAS, ia, nod(OADDR, o, nil)), Etop))
   902  					inlvars[addr] = ia
   903  
   904  					// When capturing by reference, all occurrence of the captured var
   905  					// must be substituted with dereference of the temporary address
   906  					inlvars[v] = typecheck(nod(OIND, ia, nil), Erv)
   907  				}
   908  			}
   909  		}
   910  	}
   911  
   912  	for _, ln := range fn.Func.Inl.Dcl {
   913  		if ln.Op != ONAME {
   914  			continue
   915  		}
   916  		if ln.Class() == PPARAMOUT { // return values handled below.
   917  			continue
   918  		}
   919  		if ln.isParamStackCopy() { // ignore the on-stack copy of a parameter that moved to the heap
   920  			continue
   921  		}
   922  		inlvars[ln] = typecheck(inlvar(ln), Erv)
   923  		if ln.Class() == PPARAM || ln.Name.Param.Stackcopy != nil && ln.Name.Param.Stackcopy.Class() == PPARAM {
   924  			ninit.Append(nod(ODCL, inlvars[ln], nil))
   925  		}
   926  		if genDwarfInline > 0 {
   927  			inlf := inlvars[ln]
   928  			if ln.Class() == PPARAM {
   929  				inlf.SetInlFormal(true)
   930  			} else {
   931  				inlf.SetInlLocal(true)
   932  			}
   933  			inlf.Pos = ln.Pos
   934  			inlfvars = append(inlfvars, inlf)
   935  		}
   936  	}
   937  
   938  	// temporaries for return values.
   939  	var retvars []*Node
   940  	for i, t := range fn.Type.Results().Fields().Slice() {
   941  		var m *Node
   942  		mpos := t.Pos
   943  		if n := asNode(t.Nname); n != nil && !n.isBlank() {
   944  			m = inlvar(n)
   945  			m = typecheck(m, Erv)
   946  			inlvars[n] = m
   947  		} else {
   948  			// anonymous return values, synthesize names for use in assignment that replaces return
   949  			m = retvar(t, i)
   950  		}
   951  
   952  		if genDwarfInline > 0 {
   953  			// Don't update the src.Pos on a return variable if it
   954  			// was manufactured by the inliner (e.g. "~R2"); such vars
   955  			// were not part of the original callee.
   956  			if !strings.HasPrefix(m.Sym.Name, "~R") {
   957  				m.SetInlFormal(true)
   958  				m.Pos = mpos
   959  				inlfvars = append(inlfvars, m)
   960  			}
   961  		}
   962  
   963  		ninit.Append(nod(ODCL, m, nil))
   964  		retvars = append(retvars, m)
   965  	}
   966  
   967  	// Assign arguments to the parameters' temp names.
   968  	as := nod(OAS2, nil, nil)
   969  	as.Rlist.Set(n.List.Slice())
   970  
   971  	// For non-dotted calls to variadic functions, we assign the
   972  	// variadic parameter's temp name separately.
   973  	var vas *Node
   974  
   975  	if fn.IsMethod() {
   976  		rcv := fn.Type.Recv()
   977  
   978  		if n.Left.Op == ODOTMETH {
   979  			// For x.M(...), assign x directly to the
   980  			// receiver parameter.
   981  			if n.Left.Left == nil {
   982  				Fatalf("method call without receiver: %+v", n)
   983  			}
   984  			ras := nod(OAS, tinlvar(rcv, inlvars), n.Left.Left)
   985  			ras = typecheck(ras, Etop)
   986  			ninit.Append(ras)
   987  		} else {
   988  			// For T.M(...), add the receiver parameter to
   989  			// as.List, so it's assigned by the normal
   990  			// arguments.
   991  			if as.Rlist.Len() == 0 {
   992  				Fatalf("non-method call to method without first arg: %+v", n)
   993  			}
   994  			as.List.Append(tinlvar(rcv, inlvars))
   995  		}
   996  	}
   997  
   998  	for _, param := range fn.Type.Params().Fields().Slice() {
   999  		// For ordinary parameters or variadic parameters in
  1000  		// dotted calls, just add the variable to the
  1001  		// assignment list, and we're done.
  1002  		if !param.Isddd() || n.Isddd() {
  1003  			as.List.Append(tinlvar(param, inlvars))
  1004  			continue
  1005  		}
  1006  
  1007  		// Otherwise, we need to collect the remaining values
  1008  		// to pass as a slice.
  1009  
  1010  		numvals := n.List.Len()
  1011  		if numvals == 1 && n.List.First().Type.IsFuncArgStruct() {
  1012  			numvals = n.List.First().Type.NumFields()
  1013  		}
  1014  
  1015  		x := as.List.Len()
  1016  		for as.List.Len() < numvals {
  1017  			as.List.Append(argvar(param.Type, as.List.Len()))
  1018  		}
  1019  		varargs := as.List.Slice()[x:]
  1020  
  1021  		vas = nod(OAS, tinlvar(param, inlvars), nil)
  1022  		if len(varargs) == 0 {
  1023  			vas.Right = nodnil()
  1024  			vas.Right.Type = param.Type
  1025  		} else {
  1026  			vas.Right = nod(OCOMPLIT, nil, typenod(param.Type))
  1027  			vas.Right.List.Set(varargs)
  1028  		}
  1029  	}
  1030  
  1031  	if as.Rlist.Len() != 0 {
  1032  		as = typecheck(as, Etop)
  1033  		ninit.Append(as)
  1034  	}
  1035  
  1036  	if vas != nil {
  1037  		vas = typecheck(vas, Etop)
  1038  		ninit.Append(vas)
  1039  	}
  1040  
  1041  	// Zero the return parameters.
  1042  	for _, n := range retvars {
  1043  		ras := nod(OAS, n, nil)
  1044  		ras = typecheck(ras, Etop)
  1045  		ninit.Append(ras)
  1046  	}
  1047  
  1048  	retlabel := autolabel(".i")
  1049  
  1050  	inlgen++
  1051  
  1052  	parent := -1
  1053  	if b := Ctxt.PosTable.Pos(n.Pos).Base(); b != nil {
  1054  		parent = b.InliningIndex()
  1055  	}
  1056  	newIndex := Ctxt.InlTree.Add(parent, n.Pos, fn.Sym.Linksym())
  1057  
  1058  	if genDwarfInline > 0 {
  1059  		if !fn.Sym.Linksym().WasInlined() {
  1060  			Ctxt.DwFixups.SetPrecursorFunc(fn.Sym.Linksym(), fn)
  1061  			fn.Sym.Linksym().Set(obj.AttrWasInlined, true)
  1062  		}
  1063  	}
  1064  
  1065  	subst := inlsubst{
  1066  		retlabel:    retlabel,
  1067  		retvars:     retvars,
  1068  		inlvars:     inlvars,
  1069  		bases:       make(map[*src.PosBase]*src.PosBase),
  1070  		newInlIndex: newIndex,
  1071  	}
  1072  
  1073  	body := subst.list(asNodes(fn.Func.Inl.Body))
  1074  
  1075  	lab := nod(OLABEL, retlabel, nil)
  1076  	body = append(body, lab)
  1077  
  1078  	typecheckslice(body, Etop)
  1079  
  1080  	if genDwarfInline > 0 {
  1081  		for _, v := range inlfvars {
  1082  			v.Pos = subst.updatedPos(v.Pos)
  1083  		}
  1084  	}
  1085  
  1086  	//dumplist("ninit post", ninit);
  1087  
  1088  	call := nod(OINLCALL, nil, nil)
  1089  	call.Ninit.Set(ninit.Slice())
  1090  	call.Nbody.Set(body)
  1091  	call.Rlist.Set(retvars)
  1092  	call.Type = n.Type
  1093  	call.SetTypecheck(1)
  1094  
  1095  	// transitive inlining
  1096  	// might be nice to do this before exporting the body,
  1097  	// but can't emit the body with inlining expanded.
  1098  	// instead we emit the things that the body needs
  1099  	// and each use must redo the inlining.
  1100  	// luckily these are small.
  1101  	inlnodelist(call.Nbody, maxCost)
  1102  	for _, n := range call.Nbody.Slice() {
  1103  		if n.Op == OINLCALL {
  1104  			inlconv2stmt(n)
  1105  		}
  1106  	}
  1107  
  1108  	if Debug['m'] > 2 {
  1109  		fmt.Printf("%v: After inlining %+v\n\n", call.Line(), call)
  1110  	}
  1111  
  1112  	return call
  1113  }
  1114  
  1115  // Every time we expand a function we generate a new set of tmpnames,
  1116  // PAUTO's in the calling functions, and link them off of the
  1117  // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
  1118  func inlvar(var_ *Node) *Node {
  1119  	if Debug['m'] > 3 {
  1120  		fmt.Printf("inlvar %+v\n", var_)
  1121  	}
  1122  
  1123  	n := newname(var_.Sym)
  1124  	n.Type = var_.Type
  1125  	n.SetClass(PAUTO)
  1126  	n.Name.SetUsed(true)
  1127  	n.Name.Curfn = Curfn // the calling function, not the called one
  1128  	n.SetAddrtaken(var_.Addrtaken())
  1129  
  1130  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
  1131  	return n
  1132  }
  1133  
  1134  // Synthesize a variable to store the inlined function's results in.
  1135  func retvar(t *types.Field, i int) *Node {
  1136  	n := newname(lookupN("~R", i))
  1137  	n.Type = t.Type
  1138  	n.SetClass(PAUTO)
  1139  	n.Name.SetUsed(true)
  1140  	n.Name.Curfn = Curfn // the calling function, not the called one
  1141  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
  1142  	return n
  1143  }
  1144  
  1145  // Synthesize a variable to store the inlined function's arguments
  1146  // when they come from a multiple return call.
  1147  func argvar(t *types.Type, i int) *Node {
  1148  	n := newname(lookupN("~arg", i))
  1149  	n.Type = t.Elem()
  1150  	n.SetClass(PAUTO)
  1151  	n.Name.SetUsed(true)
  1152  	n.Name.Curfn = Curfn // the calling function, not the called one
  1153  	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n)
  1154  	return n
  1155  }
  1156  
  1157  // The inlsubst type implements the actual inlining of a single
  1158  // function call.
  1159  type inlsubst struct {
  1160  	// Target of the goto substituted in place of a return.
  1161  	retlabel *Node
  1162  
  1163  	// Temporary result variables.
  1164  	retvars []*Node
  1165  
  1166  	inlvars map[*Node]*Node
  1167  
  1168  	// bases maps from original PosBase to PosBase with an extra
  1169  	// inlined call frame.
  1170  	bases map[*src.PosBase]*src.PosBase
  1171  
  1172  	// newInlIndex is the index of the inlined call frame to
  1173  	// insert for inlined nodes.
  1174  	newInlIndex int
  1175  }
  1176  
  1177  // list inlines a list of nodes.
  1178  func (subst *inlsubst) list(ll Nodes) []*Node {
  1179  	s := make([]*Node, 0, ll.Len())
  1180  	for _, n := range ll.Slice() {
  1181  		s = append(s, subst.node(n))
  1182  	}
  1183  	return s
  1184  }
  1185  
  1186  // node recursively copies a node from the saved pristine body of the
  1187  // inlined function, substituting references to input/output
  1188  // parameters with ones to the tmpnames, and substituting returns with
  1189  // assignments to the output.
  1190  func (subst *inlsubst) node(n *Node) *Node {
  1191  	if n == nil {
  1192  		return nil
  1193  	}
  1194  
  1195  	switch n.Op {
  1196  	case ONAME:
  1197  		if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
  1198  			if Debug['m'] > 2 {
  1199  				fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
  1200  			}
  1201  			return inlvar
  1202  		}
  1203  
  1204  		if Debug['m'] > 2 {
  1205  			fmt.Printf("not substituting name %+v\n", n)
  1206  		}
  1207  		return n
  1208  
  1209  	case OLITERAL, OTYPE:
  1210  		// If n is a named constant or type, we can continue
  1211  		// using it in the inline copy. Otherwise, make a copy
  1212  		// so we can update the line number.
  1213  		if n.Sym != nil {
  1214  			return n
  1215  		}
  1216  
  1217  		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function.
  1218  
  1219  	//		dump("Return before substitution", n);
  1220  	case ORETURN:
  1221  		m := nod(OGOTO, subst.retlabel, nil)
  1222  		m.Ninit.Set(subst.list(n.Ninit))
  1223  
  1224  		if len(subst.retvars) != 0 && n.List.Len() != 0 {
  1225  			as := nod(OAS2, nil, nil)
  1226  
  1227  			// Make a shallow copy of retvars.
  1228  			// Otherwise OINLCALL.Rlist will be the same list,
  1229  			// and later walk and typecheck may clobber it.
  1230  			for _, n := range subst.retvars {
  1231  				as.List.Append(n)
  1232  			}
  1233  			as.Rlist.Set(subst.list(n.List))
  1234  			as = typecheck(as, Etop)
  1235  			m.Ninit.Append(as)
  1236  		}
  1237  
  1238  		typecheckslice(m.Ninit.Slice(), Etop)
  1239  		m = typecheck(m, Etop)
  1240  
  1241  		//		dump("Return after substitution", m);
  1242  		return m
  1243  
  1244  	case OGOTO, OLABEL:
  1245  		m := n.copy()
  1246  		m.Pos = subst.updatedPos(m.Pos)
  1247  		m.Ninit.Set(nil)
  1248  		p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen)
  1249  		m.Left = newname(lookup(p))
  1250  
  1251  		return m
  1252  	}
  1253  
  1254  	m := n.copy()
  1255  	m.Pos = subst.updatedPos(m.Pos)
  1256  	m.Ninit.Set(nil)
  1257  
  1258  	if n.Op == OCLOSURE {
  1259  		Fatalf("cannot inline function containing closure: %+v", n)
  1260  	}
  1261  
  1262  	m.Left = subst.node(n.Left)
  1263  	m.Right = subst.node(n.Right)
  1264  	m.List.Set(subst.list(n.List))
  1265  	m.Rlist.Set(subst.list(n.Rlist))
  1266  	m.Ninit.Set(append(m.Ninit.Slice(), subst.list(n.Ninit)...))
  1267  	m.Nbody.Set(subst.list(n.Nbody))
  1268  
  1269  	return m
  1270  }
  1271  
  1272  func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
  1273  	pos := Ctxt.PosTable.Pos(xpos)
  1274  	oldbase := pos.Base() // can be nil
  1275  	newbase := subst.bases[oldbase]
  1276  	if newbase == nil {
  1277  		newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
  1278  		subst.bases[oldbase] = newbase
  1279  	}
  1280  	pos.SetBase(newbase)
  1281  	return Ctxt.PosTable.XPos(pos)
  1282  }
  1283  
  1284  func pruneUnusedAutos(ll []*Node, vis *hairyVisitor) []*Node {
  1285  	s := make([]*Node, 0, len(ll))
  1286  	for _, n := range ll {
  1287  		if n.Class() == PAUTO {
  1288  			if _, found := vis.usedLocals[n]; !found {
  1289  				continue
  1290  			}
  1291  		}
  1292  		s = append(s, n)
  1293  	}
  1294  	return s
  1295  }