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