| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | // Copyright 2011 The Go Authors. All rights reserved. | 
					
						
							|  |  |  | // Use of this source code is governed by a BSD-style | 
					
						
							|  |  |  | // license that can be found in the LICENSE file. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The inlining facility makes 2 passes: first caninl determines which | 
					
						
							|  |  |  | // functions are suitable for inlining, and for those that are it | 
					
						
							|  |  |  | // saves a copy of the body. Then inlcalls walks each function body to | 
					
						
							|  |  |  | // expand calls to inlinable functions. | 
					
						
							|  |  |  | // | 
					
						
							| 
									
										
										
										
											2016-02-06 20:35:29 +09:00
										 |  |  | // The debug['l'] flag controls the aggressiveness. Note that main() swaps level 0 and 1, | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | // making 1 the default and -l disable.  -ll and more is useful to flush out bugs. | 
					
						
							|  |  |  | // These additional levels (beyond -l) may be buggy and are not supported. | 
					
						
							|  |  |  | //      0: disabled | 
					
						
							|  |  |  | //      1: 40-nodes leaf functions, oneliners, lazy typechecking (default) | 
					
						
							|  |  |  | //      2: early typechecking of all imported bodies | 
					
						
							|  |  |  | //      3: allow variadic functions | 
					
						
							|  |  |  | //      4: allow non-leaf functions , (breaks runtime.Caller) | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //  At some point this may get another default and become switch-offable with -N. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | //  The debug['m'] flag enables diagnostic output.  a single -m is useful for verifying | 
					
						
							|  |  |  | //  which calls get inlined or not, more is for debugging, and may go away at any point. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // TODO: | 
					
						
							|  |  |  | //   - inline functions with ... args | 
					
						
							|  |  |  | //   - handle T.meth(f()) with func f() (t T, arg, arg, ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | package gc | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"cmd/internal/obj" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Used by caninl. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Used by inlcalls | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Used during inlsubst[list] | 
					
						
							|  |  |  | var inlfn *Node // function currently being inlined | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var inlretlabel *Node // target of the goto substituted in place of a return | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var inlretvars *NodeList // temp out variables | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-01 23:21:55 +00:00
										 |  |  | // Get the function's package. For ordinary functions it's on the ->sym, but for imported methods | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | // the ->sym can be re-used in the local package, so peel it off the receiver's type. | 
					
						
							|  |  |  | func fnpkg(fn *Node) *Pkg { | 
					
						
							|  |  |  | 	if fn.Type.Thistuple != 0 { | 
					
						
							|  |  |  | 		// method | 
					
						
							| 
									
										
										
										
											2016-03-09 20:54:59 -08:00
										 |  |  | 		rcvr := fn.Type.Recv().Type | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-01 07:54:01 +00:00
										 |  |  | 		if Isptr[rcvr.Etype] { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			rcvr = rcvr.Type | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 		if rcvr.Sym == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("receiver with no sym: [%v] %v  (%v)", fn.Sym, Nconv(fn, obj.FmtLong), rcvr) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return rcvr.Sym.Pkg | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// non-method | 
					
						
							|  |  |  | 	return fn.Sym.Pkg | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-01 23:21:55 +00:00
										 |  |  | // Lazy typechecking of imported bodies. For local functions, caninl will set ->typecheck | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | // because they're a copy of an already checked body. | 
					
						
							|  |  |  | func typecheckinl(fn *Node) { | 
					
						
							| 
									
										
										
										
											2016-03-02 12:49:37 -08:00
										 |  |  | 	lno := setlineno(fn) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// typecheckinl is only for imported functions; | 
					
						
							|  |  |  | 	// their bodies may refer to unsafe as long as the package | 
					
						
							|  |  |  | 	// was marked safe during import (which was checked then). | 
					
						
							|  |  |  | 	// the ->inl of a local function has been typechecked before caninl copied it. | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	pkg := fnpkg(fn) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if pkg == localpkg || pkg == nil { | 
					
						
							|  |  |  | 		return // typecheckinl on local function | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if Debug['m'] > 2 { | 
					
						
							| 
									
										
										
										
											2016-03-04 13:16:48 -08:00
										 |  |  | 		fmt.Printf("typecheck import [%v] %v { %v }\n", fn.Sym, Nconv(fn, obj.FmtLong), Hconv(fn.Func.Inl, obj.FmtSharp)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	save_safemode := safemode | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	safemode = 0 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	savefn := Curfn | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	Curfn = fn | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | 	typechecklist(fn.Func.Inl.Slice(), Etop) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	Curfn = savefn | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	safemode = save_safemode | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 12:49:37 -08:00
										 |  |  | 	lineno = lno | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Caninl determines whether fn is inlineable. | 
					
						
							|  |  |  | // If so, caninl saves fn->nbody in fn->inl and substitutes it with a copy. | 
					
						
							|  |  |  | // fn and ->nbody will already have been typechecked. | 
					
						
							|  |  |  | func caninl(fn *Node) { | 
					
						
							|  |  |  | 	if fn.Op != ODCLFUNC { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 		Fatalf("caninl %v", fn) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-27 10:42:55 -04:00
										 |  |  | 	if fn.Func.Nname == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 		Fatalf("caninl no nname %v", Nconv(fn, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-08-24 19:45:59 -05:00
										 |  |  | 	// If marked "go:noinline", don't inline | 
					
						
							| 
									
										
										
										
											2016-02-26 13:32:28 -08:00
										 |  |  | 	if fn.Func.Pragma&Noinline != 0 { | 
					
						
							| 
									
										
										
										
											2015-08-24 19:45:59 -05:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	// If fn has no body (is defined outside of Go), cannot inline it. | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	if len(fn.Nbody.Slice()) == 0 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if fn.Typecheck == 0 { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 		Fatalf("caninl on non-typechecked function %v", fn) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// can't handle ... args yet | 
					
						
							|  |  |  | 	if Debug['l'] < 3 { | 
					
						
							| 
									
										
										
										
											2016-03-08 16:31:28 -08:00
										 |  |  | 		for t, it := IterFields(fn.Type.Params()); t != nil; t = it.Next() { | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 			if t.Isddd { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				return | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-10-20 10:00:07 -07:00
										 |  |  | 	// Runtime package must not be instrumented. | 
					
						
							|  |  |  | 	// Instrument skips runtime package. However, some runtime code can be | 
					
						
							| 
									
										
										
										
											2015-04-09 10:08:29 +03:00
										 |  |  | 	// inlined into other packages and instrumented there. To avoid this, | 
					
						
							| 
									
										
										
										
											2015-10-20 10:00:07 -07:00
										 |  |  | 	// we disable inlining of runtime functions when instrumenting. | 
					
						
							| 
									
										
										
										
											2015-04-09 10:08:29 +03:00
										 |  |  | 	// The example that we observed is inlining of LockOSThread, | 
					
						
							|  |  |  | 	// which lead to false race reports on m contents. | 
					
						
							| 
									
										
										
										
											2015-10-20 10:00:07 -07:00
										 |  |  | 	if instrumenting && myimportpath == "runtime" { | 
					
						
							| 
									
										
										
										
											2015-04-09 10:08:29 +03:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 	const maxBudget = 80 | 
					
						
							|  |  |  | 	budget := maxBudget // allowed hairyness | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	if ishairylist(fn.Nbody, &budget) || budget < 0 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	savefn := Curfn | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	Curfn = fn | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	fn.Func.Nname.Func.Inl.Set(fn.Nbody.Slice()) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	fn.Nbody.Set(inlcopylist(fn.Func.Nname.Func.Inl.Slice())) | 
					
						
							|  |  |  | 	inldcl := inlcopylist(fn.Func.Nname.Name.Defn.Func.Dcl) | 
					
						
							| 
									
										
										
										
											2016-02-26 13:48:24 -08:00
										 |  |  | 	if len(inldcl) > 0 { | 
					
						
							|  |  |  | 		fn.Func.Nname.Func.Inldcl = &inldcl | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-05-27 10:42:55 -04:00
										 |  |  | 	fn.Func.Nname.Func.InlCost = int32(maxBudget - budget) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// hack, TODO, check for better way to link method nodes back to the thing with the ->inl | 
					
						
							|  |  |  | 	// this is so export can find the body of a method | 
					
						
							| 
									
										
										
										
											2015-05-27 10:42:55 -04:00
										 |  |  | 	fn.Type.Nname = fn.Func.Nname | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if Debug['m'] > 1 { | 
					
						
							| 
									
										
										
										
											2016-03-04 13:16:48 -08:00
										 |  |  | 		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)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} else if Debug['m'] != 0 { | 
					
						
							| 
									
										
										
										
											2015-05-27 10:42:55 -04:00
										 |  |  | 		fmt.Printf("%v: can inline %v\n", fn.Line(), fn.Func.Nname) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	Curfn = savefn | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Look for anything we want to punt on. | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | func ishairylist(ll Nodes, budget *int) bool { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	for _, n := range ll.Slice() { | 
					
						
							|  |  |  | 		if ishairy(n, budget) { | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return false | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | func ishairy(n *Node, budget *int) bool { | 
					
						
							|  |  |  | 	if n == nil { | 
					
						
							|  |  |  | 		return false | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 	// Call is okay if inlinable and we have the budget for the body. | 
					
						
							|  |  |  | 	case OCALLFUNC: | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 		if n.Left.Func != nil && len(n.Left.Func.Inl.Slice()) != 0 { | 
					
						
							| 
									
										
										
										
											2015-03-25 19:33:01 -07:00
										 |  |  | 			*budget -= int(n.Left.Func.InlCost) | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		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 | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 			if n.Left.Sym.Def != nil && len(n.Left.Sym.Def.Func.Inl.Slice()) != 0 { | 
					
						
							| 
									
										
										
										
											2015-03-25 19:33:01 -07:00
										 |  |  | 				*budget -= int(n.Left.Sym.Def.Func.InlCost) | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if Debug['l'] < 4 { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Call is okay if inlinable and we have the budget for the body. | 
					
						
							|  |  |  | 	case OCALLMETH: | 
					
						
							|  |  |  | 		if n.Left.Type == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if n.Left.Type.Nname == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 		if len(n.Left.Type.Nname.Func.Inl.Slice()) != 0 { | 
					
						
							| 
									
										
										
										
											2015-03-25 19:33:01 -07:00
										 |  |  | 			*budget -= int(n.Left.Type.Nname.Func.InlCost) | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if Debug['l'] < 4 { | 
					
						
							|  |  |  | 			return true | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// Things that are too hairy, irrespective of the budget | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 	case OCALL, OCALLINTER, OPANIC, ORECOVER: | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		if Debug['l'] < 4 { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 			return true | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case OCLOSURE, | 
					
						
							|  |  |  | 		OCALLPART, | 
					
						
							|  |  |  | 		ORANGE, | 
					
						
							|  |  |  | 		OFOR, | 
					
						
							|  |  |  | 		OSELECT, | 
					
						
							|  |  |  | 		OSWITCH, | 
					
						
							|  |  |  | 		OPROC, | 
					
						
							|  |  |  | 		ODEFER, | 
					
						
							|  |  |  | 		ODCLTYPE,  // can't print yet | 
					
						
							|  |  |  | 		ODCLCONST, // can't print yet | 
					
						
							|  |  |  | 		ORETJMP: | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 		return true | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	(*budget)-- | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	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) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Inlcopy and inlcopylist recursively copy the body of a function. | 
					
						
							|  |  |  | // Any name-like node of non-local class is marked for re-export by adding it to | 
					
						
							|  |  |  | // the exportlist. | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | func inlcopylist(ll []*Node) []*Node { | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	s := make([]*Node, 0, nodeSeqLen(ll)) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	for _, n := range ll { | 
					
						
							|  |  |  | 		s = append(s, inlcopy(n)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	return s | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func inlcopy(n *Node) *Node { | 
					
						
							|  |  |  | 	if n == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 	case ONAME, OTYPE, OLITERAL: | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		return n | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	m := Nod(OXXX, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	*m = *n | 
					
						
							| 
									
										
										
										
											2015-03-10 21:37:13 -07:00
										 |  |  | 	if m.Func != nil { | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 		m.Func.Inl.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-03-10 21:37:13 -07:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	m.Left = inlcopy(n.Left) | 
					
						
							|  |  |  | 	m.Right = inlcopy(n.Right) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	m.List.Set(inlcopylist(n.List.Slice())) | 
					
						
							|  |  |  | 	m.Rlist.Set(inlcopylist(n.Rlist.Slice())) | 
					
						
							|  |  |  | 	m.Ninit.Set(inlcopylist(n.Ninit.Slice())) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	m.Nbody.Set(inlcopylist(n.Nbody.Slice())) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return m | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any | 
					
						
							| 
									
										
										
										
											2016-03-01 23:21:55 +00:00
										 |  |  | // calls made to inlineable functions. This is the external entry point. | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | func inlcalls(fn *Node) { | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	savefn := Curfn | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	Curfn = fn | 
					
						
							|  |  |  | 	inlnode(&fn) | 
					
						
							|  |  |  | 	if fn != Curfn { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 		Fatalf("inlnode replaced curfn") | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	Curfn = savefn | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Turn an OINLCALL into a statement. | 
					
						
							|  |  |  | func inlconv2stmt(n *Node) { | 
					
						
							|  |  |  | 	n.Op = OBLOCK | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// n->ninit stays | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	n.List.Set(n.Nbody.Slice()) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	n.Nbody.Set(nil) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	n.Rlist.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Turn an OINLCALL into a single valued expression. | 
					
						
							|  |  |  | func inlconv2expr(np **Node) { | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	n := *np | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	r := n.Rlist.First() | 
					
						
							|  |  |  | 	addinit(&r, append(n.Ninit.Slice(), n.Nbody.Slice()...)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	*np = r | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Turn the rlist (with the return values) of the OINLCALL in | 
					
						
							|  |  |  | // n into an expression list lumping the ninit and body | 
					
						
							|  |  |  | // containing the inlined statements on the first list element so | 
					
						
							|  |  |  | // order will be preserved Used in return, oas2func and call | 
					
						
							|  |  |  | // statements. | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | func inlconv2list(n *Node) []*Node { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	if n.Op != OINLCALL || n.Rlist.Len() == 0 { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 		Fatalf("inlconv2list %v\n", Nconv(n, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	s := n.Rlist.Slice() | 
					
						
							|  |  |  | 	addinit(&s[0], append(n.Ninit.Slice(), n.Nbody.Slice()...)) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	return s | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | func inlnodelist(l Nodes) { | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 	s := l.Slice() | 
					
						
							|  |  |  | 	for i := range s { | 
					
						
							|  |  |  | 		inlnode(&s[i]) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | // inlnode recurses over the tree to find inlineable calls, which will | 
					
						
							| 
									
										
										
										
											2016-03-01 23:21:55 +00:00
										 |  |  | // be turned into OINLCALLs by mkinlcall. When the recursion comes | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | // back up will examine left, right, list, rlist, ninit, ntest, nincr, | 
					
						
							|  |  |  | // nbody and nelse and use one of the 4 inlconv/glue functions above | 
					
						
							|  |  |  | // to turn the OINLCALL into an expression, a statement, or patch it | 
					
						
							|  |  |  | // in to this nodes list or rlist as appropriate. | 
					
						
							|  |  |  | // NOTE it makes no sense to pass the glue functions down the | 
					
						
							|  |  |  | // recursion to the level where the OINLCALL gets created because they | 
					
						
							|  |  |  | // have to edit /this/ n, so you'd have to push that one down as well, | 
					
						
							|  |  |  | // but then you may as well do it here.  so this is cleaner and | 
					
						
							|  |  |  | // shorter and less complicated. | 
					
						
							|  |  |  | func inlnode(np **Node) { | 
					
						
							|  |  |  | 	if *np == nil { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	n := *np | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							|  |  |  | 	// inhibit inlining of their argument | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 	case ODEFER, OPROC: | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		switch n.Left.Op { | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 		case OCALLFUNC, OCALLMETH: | 
					
						
							| 
									
										
										
										
											2015-09-24 23:21:18 +02:00
										 |  |  | 			// TODO(marvin): Fix Node.EType type union. | 
					
						
							|  |  |  | 			n.Left.Etype = EType(n.Op) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		fallthrough | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// TODO do them here (or earlier), | 
					
						
							|  |  |  | 	// so escape analysis can avoid more heapmoves. | 
					
						
							|  |  |  | 	case OCLOSURE: | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 12:49:37 -08:00
										 |  |  | 	lno := setlineno(n) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	inlnodelist(n.Ninit) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	for _, n1 := range n.Ninit.Slice() { | 
					
						
							|  |  |  | 		if n1.Op == OINLCALL { | 
					
						
							|  |  |  | 			inlconv2stmt(n1) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inlnode(&n.Left) | 
					
						
							|  |  |  | 	if n.Left != nil && n.Left.Op == OINLCALL { | 
					
						
							|  |  |  | 		inlconv2expr(&n.Left) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inlnode(&n.Right) | 
					
						
							|  |  |  | 	if n.Right != nil && n.Right.Op == OINLCALL { | 
					
						
							| 
									
										
										
										
											2015-05-22 01:16:52 -04:00
										 |  |  | 		if n.Op == OFOR { | 
					
						
							|  |  |  | 			inlconv2stmt(n.Right) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			inlconv2expr(&n.Right) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inlnodelist(n.List) | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							|  |  |  | 	case OBLOCK: | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		for _, n2 := range n.List.Slice() { | 
					
						
							|  |  |  | 			if n2.Op == OINLCALL { | 
					
						
							|  |  |  | 				inlconv2stmt(n2) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// if we just replaced arg in f(arg()) or return arg with an inlined call | 
					
						
							|  |  |  | 	// and arg returns multiple values, glue as list | 
					
						
							|  |  |  | 	case ORETURN, | 
					
						
							|  |  |  | 		OCALLFUNC, | 
					
						
							|  |  |  | 		OCALLMETH, | 
					
						
							|  |  |  | 		OCALLINTER, | 
					
						
							|  |  |  | 		OAPPEND, | 
					
						
							|  |  |  | 		OCOMPLEX: | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		if n.List.Len() == 1 && n.List.First().Op == OINLCALL && n.List.First().Rlist.Len() > 1 { | 
					
						
							|  |  |  | 			n.List.Set(inlconv2list(n.List.First())) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fallthrough | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 		s := n.List.Slice() | 
					
						
							|  |  |  | 		for i1, n1 := range s { | 
					
						
							|  |  |  | 			if n1.Op == OINLCALL { | 
					
						
							|  |  |  | 				inlconv2expr(&s[i1]) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inlnodelist(n.Rlist) | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							|  |  |  | 	case OAS2FUNC: | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		if n.Rlist.First().Op == OINLCALL { | 
					
						
							|  |  |  | 			n.Rlist.Set(inlconv2list(n.Rlist.First())) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			n.Op = OAS2 | 
					
						
							|  |  |  | 			n.Typecheck = 0 | 
					
						
							|  |  |  | 			typecheck(np, Etop) | 
					
						
							|  |  |  | 			break | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		fallthrough | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 		s := n.Rlist.Slice() | 
					
						
							|  |  |  | 		for i1, n1 := range s { | 
					
						
							|  |  |  | 			if n1.Op == OINLCALL { | 
					
						
							| 
									
										
										
										
											2015-05-22 01:16:52 -04:00
										 |  |  | 				if n.Op == OIF { | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 					inlconv2stmt(n1) | 
					
						
							| 
									
										
										
										
											2015-05-22 01:16:52 -04:00
										 |  |  | 				} else { | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 					inlconv2expr(&s[i1]) | 
					
						
							| 
									
										
										
										
											2015-05-22 01:16:52 -04:00
										 |  |  | 				} | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	inlnodelist(n.Nbody) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	for _, n := range n.Nbody.Slice() { | 
					
						
							|  |  |  | 		if n.Op == OINLCALL { | 
					
						
							|  |  |  | 			inlconv2stmt(n) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// with all the branches out of the way, it is now time to | 
					
						
							|  |  |  | 	// transmogrify this node itself unless inhibited by the | 
					
						
							|  |  |  | 	// switch at the top of this function. | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 	case OCALLFUNC, OCALLMETH: | 
					
						
							| 
									
										
										
										
											2015-09-24 23:21:18 +02:00
										 |  |  | 		// TODO(marvin): Fix Node.EType type union. | 
					
						
							|  |  |  | 		if n.Etype == EType(OPROC) || n.Etype == EType(ODEFER) { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			return | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							|  |  |  | 	case OCALLFUNC: | 
					
						
							|  |  |  | 		if Debug['m'] > 3 { | 
					
						
							|  |  |  | 			fmt.Printf("%v:call to func %v\n", n.Line(), Nconv(n.Left, obj.FmtSign)) | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 		if n.Left.Func != nil && len(n.Left.Func.Inl.Slice()) != 0 { // normal case | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 			mkinlcall(np, n.Left, n.Isddd) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} 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 | 
					
						
							|  |  |  | 			if n.Left.Sym.Def != nil { | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 				mkinlcall(np, n.Left.Sym.Def, n.Isddd) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	case OCALLMETH: | 
					
						
							|  |  |  | 		if Debug['m'] > 3 { | 
					
						
							|  |  |  | 			fmt.Printf("%v:call to meth %v\n", n.Line(), Nconv(n.Left.Right, obj.FmtLong)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// typecheck should have resolved ODOTMETH->type, whose nname points to the actual function. | 
					
						
							|  |  |  | 		if n.Left.Type == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("no function type for [%p] %v\n", n.Left, Nconv(n.Left, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if n.Left.Type.Nname == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("no function definition for [%p] %v\n", n.Left.Type, Tconv(n.Left.Type, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 		mkinlcall(np, n.Left.Type.Nname, n.Isddd) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 12:49:37 -08:00
										 |  |  | 	lineno = lno | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | func mkinlcall(np **Node, fn *Node, isddd bool) { | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	save_safemode := safemode | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// imported functions may refer to unsafe as long as the | 
					
						
							|  |  |  | 	// package was marked safe during import (already checked). | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	pkg := fnpkg(fn) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if pkg != localpkg && pkg != nil { | 
					
						
							|  |  |  | 		safemode = 0 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	mkinlcall1(np, fn, isddd) | 
					
						
							|  |  |  | 	safemode = save_safemode | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func tinlvar(t *Type) *Node { | 
					
						
							|  |  |  | 	if t.Nname != nil && !isblank(t.Nname) { | 
					
						
							| 
									
										
										
										
											2015-05-15 10:02:19 -07:00
										 |  |  | 		if t.Nname.Name.Inlvar == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("missing inlvar for %v\n", t.Nname) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-05-15 10:02:19 -07:00
										 |  |  | 		return t.Nname.Name.Inlvar | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	typecheck(&nblank, Erv|Easgn) | 
					
						
							|  |  |  | 	return nblank | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var inlgen int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // if *np is a call, and fn is a function with an inlinable body, substitute *np with an OINLCALL. | 
					
						
							|  |  |  | // On return ninit has the parameter assignments, the nbody is the | 
					
						
							|  |  |  | // inlined function body and list, rlist contain the input, output | 
					
						
							|  |  |  | // parameters. | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | func mkinlcall1(np **Node, fn *Node, isddd bool) { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	// For variadic fn. | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	if len(fn.Func.Inl.Slice()) == 0 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-26 22:19:27 -04:00
										 |  |  | 	if fn == Curfn || fn.Name.Defn == Curfn { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if Debug['l'] < 2 { | 
					
						
							|  |  |  | 		typecheckinl(fn) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	n := *np | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Bingo, we have a function node, and it has an inlineable body | 
					
						
							|  |  |  | 	if Debug['m'] > 1 { | 
					
						
							| 
									
										
										
										
											2016-03-04 13:16:48 -08:00
										 |  |  | 		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)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} else if Debug['m'] != 0 { | 
					
						
							| 
									
										
										
										
											2015-04-17 12:03:22 -04:00
										 |  |  | 		fmt.Printf("%v: inlining call to %v\n", n.Line(), fn) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if Debug['m'] > 2 { | 
					
						
							|  |  |  | 		fmt.Printf("%v: Before inlining: %v\n", n.Line(), Nconv(n, obj.FmtSign)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	saveinlfn := inlfn | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	inlfn = fn | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	ninit := n.Ninit | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	//dumplist("ninit pre", ninit); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-25 10:35:19 -08:00
										 |  |  | 	var dcl []*Node | 
					
						
							| 
									
										
										
										
											2016-02-26 13:48:24 -08:00
										 |  |  | 	if fn.Name.Defn != nil { | 
					
						
							|  |  |  | 		// local function | 
					
						
							|  |  |  | 		if fn.Func.Inldcl != nil { | 
					
						
							|  |  |  | 			dcl = *fn.Func.Inldcl | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} else { | 
					
						
							| 
									
										
										
										
											2016-02-26 13:48:24 -08:00
										 |  |  | 		// imported function | 
					
						
							| 
									
										
										
										
											2015-03-25 19:33:01 -07:00
										 |  |  | 		dcl = fn.Func.Dcl | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inlretvars = nil | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	i := 0 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// Make temp names to use instead of the originals | 
					
						
							| 
									
										
										
										
											2016-02-25 10:35:19 -08:00
										 |  |  | 	for _, ln := range dcl { | 
					
						
							|  |  |  | 		if ln.Class == PPARAMOUT { // return values handled below. | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			continue | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-02-25 10:35:19 -08:00
										 |  |  | 		if ln.Op == ONAME { | 
					
						
							|  |  |  | 			ln.Name.Inlvar = inlvar(ln) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// Typecheck because inlvar is not necessarily a function parameter. | 
					
						
							| 
									
										
										
										
											2016-02-25 10:35:19 -08:00
										 |  |  | 			typecheck(&ln.Name.Inlvar, Erv) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-25 10:35:19 -08:00
										 |  |  | 			if ln.Class&^PHEAP != PAUTO { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				ninit.Append(Nod(ODCL, ln.Name.Inlvar, nil)) // otherwise gen won't emit the allocations for heapallocs | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// temporaries for return values. | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	var m *Node | 
					
						
							| 
									
										
										
										
											2016-03-08 16:31:28 -08:00
										 |  |  | 	for t, it := IterFields(fn.Type.Results()); t != nil; t = it.Next() { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		if t != nil && t.Nname != nil && !isblank(t.Nname) { | 
					
						
							|  |  |  | 			m = inlvar(t.Nname) | 
					
						
							|  |  |  | 			typecheck(&m, Erv) | 
					
						
							| 
									
										
										
										
											2015-05-15 10:02:19 -07:00
										 |  |  | 			t.Nname.Name.Inlvar = m | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			// anonymous return values, synthesize names for use in assignment that replaces return | 
					
						
							|  |  |  | 			m = retvar(t, i) | 
					
						
							|  |  |  | 			i++ | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		ninit.Append(Nod(ODCL, m, nil)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		inlretvars = list(inlretvars, m) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// assign receiver. | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	var as *Node | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	if fn.Type.Thistuple != 0 && n.Left.Op == ODOTMETH { | 
					
						
							|  |  |  | 		// method call with a receiver. | 
					
						
							| 
									
										
										
										
											2016-03-09 20:54:59 -08:00
										 |  |  | 		t := fn.Type.Recv() | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-15 10:02:19 -07:00
										 |  |  | 		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("missing inlvar for %v\n", t.Nname) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 		if n.Left.Left == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("method call without receiver: %v", Nconv(n, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if t == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("method call unknown receiver type: %v", Nconv(n, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		as = Nod(OAS, tinlvar(t), n.Left.Left) | 
					
						
							|  |  |  | 		if as != nil { | 
					
						
							|  |  |  | 			typecheck(&as, Etop) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			ninit.Append(as) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// check if inlined function is variadic. | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	variadic := false | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-03-02 14:22:05 -05:00
										 |  |  | 	var varargtype *Type | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	varargcount := 0 | 
					
						
							| 
									
										
										
										
											2016-03-08 16:31:28 -08:00
										 |  |  | 	for t, it := IterFields(fn.Type.Params()); t != nil; t = it.Next() { | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 		if t.Isddd { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 			variadic = true | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			varargtype = t.Type | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// but if argument is dotted too forget about variadicity. | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 	if variadic && isddd { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 		variadic = false | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// check if argument is actually a returned tuple from call. | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	multiret := 0 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	if n.List.Len() == 1 { | 
					
						
							|  |  |  | 		switch n.List.First().Op { | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 		case OCALL, OCALLFUNC, OCALLINTER, OCALLMETH: | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			if n.List.First().Left.Type.Outtuple > 1 { | 
					
						
							|  |  |  | 				multiret = n.List.First().Left.Type.Outtuple - 1 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 	if variadic { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		varargcount = n.List.Len() + multiret | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		if n.Left.Op != ODOTMETH { | 
					
						
							|  |  |  | 			varargcount -= fn.Type.Thistuple | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		varargcount -= fn.Type.Intuple - 1 | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// assign arguments to the parameters' temp names | 
					
						
							|  |  |  | 	as = Nod(OAS2, nil, nil) | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	as.Rlist.Set(n.List.Slice()) | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 	li := 0 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	// TODO: if len(nlist) == 1 but multiple args, check that n->list->n is a call? | 
					
						
							|  |  |  | 	if fn.Type.Thistuple != 0 && n.Left.Op != ODOTMETH { | 
					
						
							|  |  |  | 		// non-method call to method | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		if n.List.Len() == 0 { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("non-method call to method without first arg: %v", Nconv(n, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// append receiver inlvar to LHS. | 
					
						
							| 
									
										
										
										
											2016-03-09 20:54:59 -08:00
										 |  |  | 		t := fn.Type.Recv() | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-05-15 10:02:19 -07:00
										 |  |  | 		if t != nil && t.Nname != nil && !isblank(t.Nname) && t.Nname.Name.Inlvar == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("missing inlvar for %v\n", t.Nname) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		if t == nil { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 			Fatalf("method call unknown receiver type: %v", Nconv(n, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		as.List.Append(tinlvar(t)) | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 		li++ | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// append ordinary arguments to LHS. | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	chkargcount := n.List.Len() > 1 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	var vararg *Node    // the slice argument to a variadic call | 
					
						
							|  |  |  | 	var varargs []*Node // the list of LHS names to put in vararg. | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 	if !chkargcount { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		// 0 or 1 expression on RHS. | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 		var i int | 
					
						
							| 
									
										
										
										
											2016-03-08 16:31:28 -08:00
										 |  |  | 		for t, it2 := IterFields(fn.Type.Params()); t != nil; t = it2.Next() { | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 			if variadic && t.Isddd { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				vararg = tinlvar(t) | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 				for i = 0; i < varargcount && li < n.List.Len(); i++ { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 					m = argvar(varargtype, i) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 					varargs = append(varargs, m) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 					as.List.Append(m) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			as.List.Append(tinlvar(t)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		// match arguments except final variadic (unless the call is dotted itself) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 		var t *Type | 
					
						
							| 
									
										
										
										
											2016-03-08 16:31:28 -08:00
										 |  |  | 		for t = fn.Type.Params().Type; t != nil; { | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 			if li >= n.List.Len() { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 			if variadic && t.Isddd { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				break | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			as.List.Append(tinlvar(t)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			t = t.Down | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 			li++ | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// match varargcount arguments with variadic parameters. | 
					
						
							| 
									
										
										
										
											2015-03-09 16:24:07 +11:00
										 |  |  | 		if variadic && t != nil && t.Isddd { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			vararg = tinlvar(t) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			var i int | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 			for i = 0; i < varargcount && li < n.List.Len(); i++ { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 				m = argvar(varargtype, i) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 				varargs = append(varargs, m) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				as.List.Append(m) | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 				li++ | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			if i == varargcount { | 
					
						
							|  |  |  | 				t = t.Down | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-09 12:39:36 -08:00
										 |  |  | 		if li < n.List.Len() || t != nil { | 
					
						
							| 
									
										
										
										
											2016-03-08 16:31:28 -08:00
										 |  |  | 			Fatalf("arg count mismatch: %v  vs %v\n", Tconv(fn.Type.Params(), obj.FmtSharp), Hconv(n.List, obj.FmtComma)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	if as.Rlist.Len() != 0 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		typecheck(&as, Etop) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		ninit.Append(as) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// turn the variadic args into a slice. | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 	if variadic { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		as = Nod(OAS, vararg, nil) | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 		if varargcount == 0 { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			as.Right = nodnil() | 
					
						
							|  |  |  | 			as.Right.Type = varargtype | 
					
						
							|  |  |  | 		} else { | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			vararrtype := typ(TARRAY) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			vararrtype.Type = varargtype.Type | 
					
						
							|  |  |  | 			vararrtype.Bound = int64(varargcount) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			as.Right = Nod(OCOMPLIT, nil, typenod(varargtype)) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			as.Right.List.Set(varargs) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			as.Right = Nod(OSLICE, as.Right, Nod(OKEY, nil, nil)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		typecheck(&as, Etop) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		ninit.Append(as) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// zero the outparams | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	for ll := inlretvars; ll != nil; ll = ll.Next { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		as = Nod(OAS, ll.N, nil) | 
					
						
							|  |  |  | 		typecheck(&as, Etop) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		ninit.Append(as) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inlretlabel = newlabel_inl() | 
					
						
							|  |  |  | 	inlgen++ | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	body := inlsubstlist(fn.Func.Inl) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	body = append(body, Nod(OGOTO, inlretlabel, nil)) // avoid 'not used' when function doesn't have return | 
					
						
							|  |  |  | 	body = append(body, Nod(OLABEL, inlretlabel, nil)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	typecheckslice(body, Etop) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	//dumplist("ninit post", ninit); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	call := Nod(OINLCALL, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	call.Ninit.Set(ninit.Slice()) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	call.Nbody.Set(body) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	setNodeSeq(&call.Rlist, inlretvars) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	call.Type = n.Type | 
					
						
							|  |  |  | 	call.Typecheck = 1 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-29 16:30:19 -04:00
										 |  |  | 	// Hide the args from setlno -- the parameters to the inlined | 
					
						
							|  |  |  | 	// call already have good line numbers that should be preserved. | 
					
						
							|  |  |  | 	args := as.Rlist | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	as.Rlist.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-06-29 16:30:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 12:49:37 -08:00
										 |  |  | 	setlno(call, n.Lineno) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	as.Rlist.Set(args.Slice()) | 
					
						
							| 
									
										
										
										
											2015-06-29 16:30:19 -04:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	//dumplist("call body", body); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*np = call | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	inlfn = saveinlfn | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// transitive inlining | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 	// might be nice to do this before exporting the body, | 
					
						
							|  |  |  | 	// but can't emit the body with inlining expanded. | 
					
						
							|  |  |  | 	// instead we emit the things that the body needs | 
					
						
							|  |  |  | 	// and each use must redo the inlining. | 
					
						
							|  |  |  | 	// luckily these are small. | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	body = fn.Func.Inl.Slice() | 
					
						
							|  |  |  | 	fn.Func.Inl.Set(nil) // prevent infinite recursion (shouldn't happen anyway) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	inlnodelist(call.Nbody) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	for _, n := range call.Nbody.Slice() { | 
					
						
							|  |  |  | 		if n.Op == OINLCALL { | 
					
						
							|  |  |  | 			inlconv2stmt(n) | 
					
						
							| 
									
										
										
										
											2015-02-24 12:19:01 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	fn.Func.Inl.Set(body) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if Debug['m'] > 2 { | 
					
						
							|  |  |  | 		fmt.Printf("%v: After inlining %v\n\n", n.Line(), Nconv(*np, obj.FmtSign)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Every time we expand a function we generate a new set of tmpnames, | 
					
						
							|  |  |  | // PAUTO's in the calling functions, and link them off of the | 
					
						
							|  |  |  | // PPARAM's, PAUTOS and PPARAMOUTs of the called function. | 
					
						
							|  |  |  | func inlvar(var_ *Node) *Node { | 
					
						
							|  |  |  | 	if Debug['m'] > 3 { | 
					
						
							|  |  |  | 		fmt.Printf("inlvar %v\n", Nconv(var_, obj.FmtSign)) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	n := newname(var_.Sym) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	n.Type = var_.Type | 
					
						
							|  |  |  | 	n.Class = PAUTO | 
					
						
							| 
									
										
										
										
											2015-03-06 21:18:41 +11:00
										 |  |  | 	n.Used = true | 
					
						
							| 
									
										
										
										
											2015-05-27 07:31:56 -04:00
										 |  |  | 	n.Name.Curfn = Curfn // the calling function, not the called one | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	n.Addrtaken = var_.Addrtaken | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-06-16 18:28:01 -04:00
										 |  |  | 	// This may no longer be necessary now that we run escape analysis | 
					
						
							|  |  |  | 	// after wrapper generation, but for 1.5 this is conservatively left | 
					
						
							| 
									
										
										
										
											2016-03-01 23:21:55 +00:00
										 |  |  | 	// unchanged. See bugs 11053 and 9537. | 
					
						
							| 
									
										
										
										
											2015-06-16 18:28:01 -04:00
										 |  |  | 	if var_.Esc == EscHeap { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		addrescapes(n) | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-02-25 10:35:19 -08:00
										 |  |  | 	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	return n | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Synthesize a variable to store the inlined function's results in. | 
					
						
							|  |  |  | func retvar(t *Type, i int) *Node { | 
					
						
							| 
									
										
										
										
											2015-03-06 12:02:24 -08:00
										 |  |  | 	n := newname(Lookupf("~r%d", i)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	n.Type = t.Type | 
					
						
							|  |  |  | 	n.Class = PAUTO | 
					
						
							| 
									
										
										
										
											2015-03-06 21:18:41 +11:00
										 |  |  | 	n.Used = true | 
					
						
							| 
									
										
										
										
											2015-05-27 07:31:56 -04:00
										 |  |  | 	n.Name.Curfn = Curfn // the calling function, not the called one | 
					
						
							| 
									
										
										
										
											2016-02-25 10:35:19 -08:00
										 |  |  | 	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	return n | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Synthesize a variable to store the inlined function's arguments | 
					
						
							|  |  |  | // when they come from a multiple return call. | 
					
						
							|  |  |  | func argvar(t *Type, i int) *Node { | 
					
						
							| 
									
										
										
										
											2015-03-06 12:02:24 -08:00
										 |  |  | 	n := newname(Lookupf("~arg%d", i)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	n.Type = t.Type | 
					
						
							|  |  |  | 	n.Class = PAUTO | 
					
						
							| 
									
										
										
										
											2015-03-06 21:18:41 +11:00
										 |  |  | 	n.Used = true | 
					
						
							| 
									
										
										
										
											2015-05-27 07:31:56 -04:00
										 |  |  | 	n.Name.Curfn = Curfn // the calling function, not the called one | 
					
						
							| 
									
										
										
										
											2016-02-25 10:35:19 -08:00
										 |  |  | 	Curfn.Func.Dcl = append(Curfn.Func.Dcl, n) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	return n | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | var newlabel_inl_label int | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func newlabel_inl() *Node { | 
					
						
							|  |  |  | 	newlabel_inl_label++ | 
					
						
							| 
									
										
										
										
											2015-03-06 12:02:24 -08:00
										 |  |  | 	n := newname(Lookupf(".inlret%.6d", newlabel_inl_label)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	n.Etype = 1 // flag 'safe' for escape analysis (no backjumps) | 
					
						
							|  |  |  | 	return n | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | // inlsubst and inlsubstlist recursively copy the body of the saved | 
					
						
							|  |  |  | // pristine ->inl body of the function while substituting references | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | // to input/output parameters with ones to the tmpnames, and | 
					
						
							|  |  |  | // substituting returns with assignments to the output. | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | func inlsubstlist(ll Nodes) []*Node { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	s := make([]*Node, 0, ll.Len()) | 
					
						
							|  |  |  | 	for _, n := range ll.Slice() { | 
					
						
							|  |  |  | 		s = append(s, inlsubst(n)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	return s | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | func inlsubst(n *Node) *Node { | 
					
						
							|  |  |  | 	if n == nil { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	switch n.Op { | 
					
						
							|  |  |  | 	case ONAME: | 
					
						
							| 
									
										
										
										
											2015-05-15 10:02:19 -07:00
										 |  |  | 		if n.Name.Inlvar != nil { // These will be set during inlnode | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			if Debug['m'] > 2 { | 
					
						
							| 
									
										
										
										
											2015-05-15 10:02:19 -07:00
										 |  |  | 				fmt.Printf("substituting name %v  ->  %v\n", Nconv(n, obj.FmtSign), Nconv(n.Name.Inlvar, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2015-05-15 10:02:19 -07:00
										 |  |  | 			return n.Name.Inlvar | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		if Debug['m'] > 2 { | 
					
						
							|  |  |  | 			fmt.Printf("not substituting name %v\n", Nconv(n, obj.FmtSign)) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return n | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 	case OLITERAL, OTYPE: | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		return n | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// Since we don't handle bodies with closures, this return is guaranteed to belong to the current inlined function. | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	//		dump("Return before substitution", n); | 
					
						
							|  |  |  | 	case ORETURN: | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 		m := Nod(OGOTO, inlretlabel, nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		m.Ninit.Set(inlsubstlist(n.Ninit)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		if inlretvars != nil && n.List.Len() != 0 { | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			as := Nod(OAS2, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 			// shallow copy or OINLCALL->rlist will be the same list, and later walk and typecheck may clobber that. | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 			for ll := inlretvars; ll != nil; ll = ll.Next { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 				as.List.Append(ll.N) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			as.Rlist.Set(inlsubstlist(n.List)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 			typecheck(&as, Etop) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 			m.Ninit.Append(as) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | 		typechecklist(m.Ninit.Slice(), Etop) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		typecheck(&m, Etop) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		//		dump("Return after substitution", m); | 
					
						
							|  |  |  | 		return m | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-04-01 09:38:44 -07:00
										 |  |  | 	case OGOTO, OLABEL: | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 		m := Nod(OXXX, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		*m = *n | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 		m.Ninit.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 		p := fmt.Sprintf("%s·%d", n.Left.Sym.Name, inlgen) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		m.Left = newname(Lookup(p)) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		return m | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2015-02-23 16:07:24 -05:00
										 |  |  | 	m := Nod(OXXX, nil, nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	*m = *n | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	m.Ninit.Set(nil) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if n.Op == OCLOSURE { | 
					
						
							| 
									
										
										
										
											2015-08-30 23:10:03 +02:00
										 |  |  | 		Fatalf("cannot inline function containing closure: %v", Nconv(n, obj.FmtSign)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	m.Left = inlsubst(n.Left) | 
					
						
							|  |  |  | 	m.Right = inlsubst(n.Right) | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	m.List.Set(inlsubstlist(n.List)) | 
					
						
							|  |  |  | 	m.Rlist.Set(inlsubstlist(n.Rlist)) | 
					
						
							|  |  |  | 	m.Ninit.Set(append(m.Ninit.Slice(), inlsubstlist(n.Ninit)...)) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	m.Nbody.Set(inlsubstlist(n.Nbody)) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return m | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Plaster over linenumbers | 
					
						
							| 
									
										
										
										
											2016-03-08 10:26:20 -08:00
										 |  |  | func setlnolist(ll Nodes, lno int32) { | 
					
						
							| 
									
										
										
										
											2016-03-08 15:10:26 -08:00
										 |  |  | 	for _, n := range ll.Slice() { | 
					
						
							|  |  |  | 		setlno(n, lno) | 
					
						
							| 
									
										
										
										
											2016-02-27 14:31:33 -08:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-02 12:49:37 -08:00
										 |  |  | func setlno(n *Node, lno int32) { | 
					
						
							| 
									
										
										
										
											2015-02-17 22:13:49 -05:00
										 |  |  | 	if n == nil { | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	// don't clobber names, unless they're freshly synthesized | 
					
						
							|  |  |  | 	if n.Op != ONAME || n.Lineno == 0 { | 
					
						
							| 
									
										
										
										
											2016-03-02 12:49:37 -08:00
										 |  |  | 		n.Lineno = lno | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	setlno(n.Left, lno) | 
					
						
							|  |  |  | 	setlno(n.Right, lno) | 
					
						
							|  |  |  | 	setlnolist(n.List, lno) | 
					
						
							|  |  |  | 	setlnolist(n.Rlist, lno) | 
					
						
							|  |  |  | 	setlnolist(n.Ninit, lno) | 
					
						
							| 
									
										
										
										
											2016-03-04 09:37:58 -08:00
										 |  |  | 	setlnolist(n.Nbody, lno) | 
					
						
							| 
									
										
										
										
											2015-02-13 14:40:36 -05:00
										 |  |  | } |