]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/inline/inl.go
[dev.typeparams] all: merge dev.regabi (063c72f) into dev.typeparams
[gostls13.git] / src / cmd / compile / internal / inline / inl.go
1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4 //
5 // The inlining facility makes 2 passes: first caninl determines which
6 // functions are suitable for inlining, and for those that are it
7 // saves a copy of the body. Then InlineCalls walks each function body to
8 // expand calls to inlinable functions.
9 //
10 // The Debug.l flag controls the aggressiveness. Note that main() swaps level 0 and 1,
11 // making 1 the default and -l disable. Additional levels (beyond -l) may be buggy and
12 // are not supported.
13 //      0: disabled
14 //      1: 80-nodes leaf functions, oneliners, panic, lazy typechecking (default)
15 //      2: (unassigned)
16 //      3: (unassigned)
17 //      4: allow non-leaf functions
18 //
19 // At some point this may get another default and become switch-offable with -N.
20 //
21 // The -d typcheckinl flag enables early typechecking of all imported bodies,
22 // which is useful to flush out bugs.
23 //
24 // The Debug.m flag enables diagnostic output.  a single -m is useful for verifying
25 // which calls get inlined or not, more is for debugging, and may go away at any point.
26
27 package inline
28
29 import (
30         "fmt"
31         "go/constant"
32         "strings"
33
34         "cmd/compile/internal/base"
35         "cmd/compile/internal/ir"
36         "cmd/compile/internal/logopt"
37         "cmd/compile/internal/typecheck"
38         "cmd/compile/internal/types"
39         "cmd/internal/obj"
40         "cmd/internal/src"
41 )
42
43 // Inlining budget parameters, gathered in one place
44 const (
45         inlineMaxBudget       = 80
46         inlineExtraAppendCost = 0
47         // default is to inline if there's at most one call. -l=4 overrides this by using 1 instead.
48         inlineExtraCallCost  = 57              // 57 was benchmarked to provided most benefit with no bad surprises; see https://github.com/golang/go/issues/19348#issuecomment-439370742
49         inlineExtraPanicCost = 1               // do not penalize inlining panics.
50         inlineExtraThrowCost = inlineMaxBudget // with current (2018-05/1.11) code, inlining runtime.throw does not help.
51
52         inlineBigFunctionNodes   = 5000 // Functions with this many nodes are considered "big".
53         inlineBigFunctionMaxCost = 20   // Max cost of inlinee when inlining into a "big" function.
54 )
55
56 func InlinePackage() {
57         // Find functions that can be inlined and clone them before walk expands them.
58         ir.VisitFuncsBottomUp(typecheck.Target.Decls, func(list []*ir.Func, recursive bool) {
59                 numfns := numNonClosures(list)
60                 for _, n := range list {
61                         if !recursive || numfns > 1 {
62                                 // We allow inlining if there is no
63                                 // recursion, or the recursion cycle is
64                                 // across more than one function.
65                                 CanInline(n)
66                         } else {
67                                 if base.Flag.LowerM > 1 {
68                                         fmt.Printf("%v: cannot inline %v: recursive\n", ir.Line(n), n.Nname)
69                                 }
70                         }
71                         InlineCalls(n)
72                 }
73         })
74 }
75
76 // CanInline determines whether fn is inlineable.
77 // If so, CanInline saves fn->nbody in fn->inl and substitutes it with a copy.
78 // fn and ->nbody will already have been typechecked.
79 func CanInline(fn *ir.Func) {
80         if fn.Nname == nil {
81                 base.Fatalf("CanInline no nname %+v", fn)
82         }
83
84         var reason string // reason, if any, that the function was not inlined
85         if base.Flag.LowerM > 1 || logopt.Enabled() {
86                 defer func() {
87                         if reason != "" {
88                                 if base.Flag.LowerM > 1 {
89                                         fmt.Printf("%v: cannot inline %v: %s\n", ir.Line(fn), fn.Nname, reason)
90                                 }
91                                 if logopt.Enabled() {
92                                         logopt.LogOpt(fn.Pos(), "cannotInlineFunction", "inline", ir.FuncName(fn), reason)
93                                 }
94                         }
95                 }()
96         }
97
98         // If marked "go:noinline", don't inline
99         if fn.Pragma&ir.Noinline != 0 {
100                 reason = "marked go:noinline"
101                 return
102         }
103
104         // If marked "go:norace" and -race compilation, don't inline.
105         if base.Flag.Race && fn.Pragma&ir.Norace != 0 {
106                 reason = "marked go:norace with -race compilation"
107                 return
108         }
109
110         // If marked "go:nocheckptr" and -d checkptr compilation, don't inline.
111         if base.Debug.Checkptr != 0 && fn.Pragma&ir.NoCheckPtr != 0 {
112                 reason = "marked go:nocheckptr"
113                 return
114         }
115
116         // If marked "go:cgo_unsafe_args", don't inline, since the
117         // function makes assumptions about its argument frame layout.
118         if fn.Pragma&ir.CgoUnsafeArgs != 0 {
119                 reason = "marked go:cgo_unsafe_args"
120                 return
121         }
122
123         // If marked as "go:uintptrescapes", don't inline, since the
124         // escape information is lost during inlining.
125         if fn.Pragma&ir.UintptrEscapes != 0 {
126                 reason = "marked as having an escaping uintptr argument"
127                 return
128         }
129
130         // The nowritebarrierrec checker currently works at function
131         // granularity, so inlining yeswritebarrierrec functions can
132         // confuse it (#22342). As a workaround, disallow inlining
133         // them for now.
134         if fn.Pragma&ir.Yeswritebarrierrec != 0 {
135                 reason = "marked go:yeswritebarrierrec"
136                 return
137         }
138
139         // If fn has no body (is defined outside of Go), cannot inline it.
140         if len(fn.Body) == 0 {
141                 reason = "no function body"
142                 return
143         }
144
145         if fn.Typecheck() == 0 {
146                 base.Fatalf("CanInline on non-typechecked function %v", fn)
147         }
148
149         n := fn.Nname
150         if n.Func.InlinabilityChecked() {
151                 return
152         }
153         defer n.Func.SetInlinabilityChecked(true)
154
155         cc := int32(inlineExtraCallCost)
156         if base.Flag.LowerL == 4 {
157                 cc = 1 // this appears to yield better performance than 0.
158         }
159
160         // At this point in the game the function we're looking at may
161         // have "stale" autos, vars that still appear in the Dcl list, but
162         // which no longer have any uses in the function body (due to
163         // elimination by deadcode). We'd like to exclude these dead vars
164         // when creating the "Inline.Dcl" field below; to accomplish this,
165         // the hairyVisitor below builds up a map of used/referenced
166         // locals, and we use this map to produce a pruned Inline.Dcl
167         // list. See issue 25249 for more context.
168
169         visitor := hairyVisitor{
170                 budget:        inlineMaxBudget,
171                 extraCallCost: cc,
172         }
173         if visitor.tooHairy(fn) {
174                 reason = visitor.reason
175                 return
176         }
177
178         n.Func.Inl = &ir.Inline{
179                 Cost: inlineMaxBudget - visitor.budget,
180                 Dcl:  pruneUnusedAutos(n.Defn.(*ir.Func).Dcl, &visitor),
181                 Body: inlcopylist(fn.Body),
182         }
183
184         if base.Flag.LowerM > 1 {
185                 fmt.Printf("%v: can inline %v with cost %d as: %v { %v }\n", ir.Line(fn), n, inlineMaxBudget-visitor.budget, fn.Type(), ir.Nodes(n.Func.Inl.Body))
186         } else if base.Flag.LowerM != 0 {
187                 fmt.Printf("%v: can inline %v\n", ir.Line(fn), n)
188         }
189         if logopt.Enabled() {
190                 logopt.LogOpt(fn.Pos(), "canInlineFunction", "inline", ir.FuncName(fn), fmt.Sprintf("cost: %d", inlineMaxBudget-visitor.budget))
191         }
192 }
193
194 // Inline_Flood marks n's inline body for export and recursively ensures
195 // all called functions are marked too.
196 func Inline_Flood(n *ir.Name, exportsym func(*ir.Name)) {
197         if n == nil {
198                 return
199         }
200         if n.Op() != ir.ONAME || n.Class != ir.PFUNC {
201                 base.Fatalf("Inline_Flood: unexpected %v, %v, %v", n, n.Op(), n.Class)
202         }
203         fn := n.Func
204         if fn == nil {
205                 base.Fatalf("Inline_Flood: missing Func on %v", n)
206         }
207         if fn.Inl == nil {
208                 return
209         }
210
211         if fn.ExportInline() {
212                 return
213         }
214         fn.SetExportInline(true)
215
216         typecheck.ImportedBody(fn)
217
218         var doFlood func(n ir.Node)
219         doFlood = func(n ir.Node) {
220                 switch n.Op() {
221                 case ir.OMETHEXPR, ir.ODOTMETH:
222                         Inline_Flood(ir.MethodExprName(n), exportsym)
223
224                 case ir.ONAME:
225                         n := n.(*ir.Name)
226                         switch n.Class {
227                         case ir.PFUNC:
228                                 Inline_Flood(n, exportsym)
229                                 exportsym(n)
230                         case ir.PEXTERN:
231                                 exportsym(n)
232                         }
233
234                 case ir.OCALLPART:
235                         // Okay, because we don't yet inline indirect
236                         // calls to method values.
237                 case ir.OCLOSURE:
238                         // VisitList doesn't visit closure bodies, so force a
239                         // recursive call to VisitList on the body of the closure.
240                         ir.VisitList(n.(*ir.ClosureExpr).Func.Body, doFlood)
241                 }
242         }
243
244         // Recursively identify all referenced functions for
245         // reexport. We want to include even non-called functions,
246         // because after inlining they might be callable.
247         ir.VisitList(ir.Nodes(fn.Inl.Body), doFlood)
248 }
249
250 // hairyVisitor visits a function body to determine its inlining
251 // hairiness and whether or not it can be inlined.
252 type hairyVisitor struct {
253         budget        int32
254         reason        string
255         extraCallCost int32
256         usedLocals    ir.NameSet
257         do            func(ir.Node) bool
258 }
259
260 func (v *hairyVisitor) tooHairy(fn *ir.Func) bool {
261         v.do = v.doNode // cache closure
262         if ir.DoChildren(fn, v.do) {
263                 return true
264         }
265         if v.budget < 0 {
266                 v.reason = fmt.Sprintf("function too complex: cost %d exceeds budget %d", inlineMaxBudget-v.budget, inlineMaxBudget)
267                 return true
268         }
269         return false
270 }
271
272 func (v *hairyVisitor) doNode(n ir.Node) bool {
273         if n == nil {
274                 return false
275         }
276         switch n.Op() {
277         // Call is okay if inlinable and we have the budget for the body.
278         case ir.OCALLFUNC:
279                 n := n.(*ir.CallExpr)
280                 // Functions that call runtime.getcaller{pc,sp} can not be inlined
281                 // because getcaller{pc,sp} expect a pointer to the caller's first argument.
282                 //
283                 // runtime.throw is a "cheap call" like panic in normal code.
284                 if n.X.Op() == ir.ONAME {
285                         name := n.X.(*ir.Name)
286                         if name.Class == ir.PFUNC && types.IsRuntimePkg(name.Sym().Pkg) {
287                                 fn := name.Sym().Name
288                                 if fn == "getcallerpc" || fn == "getcallersp" {
289                                         v.reason = "call to " + fn
290                                         return true
291                                 }
292                                 if fn == "throw" {
293                                         v.budget -= inlineExtraThrowCost
294                                         break
295                                 }
296                         }
297                 }
298
299                 if ir.IsIntrinsicCall(n) {
300                         // Treat like any other node.
301                         break
302                 }
303
304                 if fn := inlCallee(n.X); fn != nil && fn.Inl != nil {
305                         v.budget -= fn.Inl.Cost
306                         break
307                 }
308
309                 // Call cost for non-leaf inlining.
310                 v.budget -= v.extraCallCost
311
312         // Call is okay if inlinable and we have the budget for the body.
313         case ir.OCALLMETH:
314                 n := n.(*ir.CallExpr)
315                 t := n.X.Type()
316                 if t == nil {
317                         base.Fatalf("no function type for [%p] %+v\n", n.X, n.X)
318                 }
319                 fn := ir.MethodExprName(n.X).Func
320                 if types.IsRuntimePkg(fn.Sym().Pkg) && fn.Sym().Name == "heapBits.nextArena" {
321                         // Special case: explicitly allow
322                         // mid-stack inlining of
323                         // runtime.heapBits.next even though
324                         // it calls slow-path
325                         // runtime.heapBits.nextArena.
326                         break
327                 }
328                 if fn.Inl != nil {
329                         v.budget -= fn.Inl.Cost
330                         break
331                 }
332                 // Call cost for non-leaf inlining.
333                 v.budget -= v.extraCallCost
334
335         // Things that are too hairy, irrespective of the budget
336         case ir.OCALL, ir.OCALLINTER:
337                 // Call cost for non-leaf inlining.
338                 v.budget -= v.extraCallCost
339
340         case ir.OPANIC:
341                 n := n.(*ir.UnaryExpr)
342                 if n.X.Op() == ir.OCONVIFACE && n.X.(*ir.ConvExpr).Implicit() {
343                         // Hack to keep reflect.flag.mustBe inlinable for TestIntendedInlining.
344                         // Before CL 284412, these conversions were introduced later in the
345                         // compiler, so they didn't count against inlining budget.
346                         v.budget++
347                 }
348                 v.budget -= inlineExtraPanicCost
349
350         case ir.ORECOVER:
351                 // recover matches the argument frame pointer to find
352                 // the right panic value, so it needs an argument frame.
353                 v.reason = "call to recover"
354                 return true
355
356         case ir.OCLOSURE:
357                 // TODO(danscales,mdempsky): Get working with -G.
358                 // Probably after #43818 is fixed.
359                 if base.Flag.G > 0 {
360                         v.reason = "inlining closures not yet working with -G"
361                         return true
362                 }
363
364                 // TODO(danscales) - fix some bugs when budget is lowered below 15
365                 // Maybe make budget proportional to number of closure variables, e.g.:
366                 //v.budget -= int32(len(n.(*ir.ClosureExpr).Func.ClosureVars) * 3)
367                 v.budget -= 15
368                 // Scan body of closure (which DoChildren doesn't automatically
369                 // do) to check for disallowed ops in the body and include the
370                 // body in the budget.
371                 if doList(n.(*ir.ClosureExpr).Func.Body, v.do) {
372                         return true
373                 }
374
375         case ir.ORANGE,
376                 ir.OSELECT,
377                 ir.OGO,
378                 ir.ODEFER,
379                 ir.ODCLTYPE, // can't print yet
380                 ir.OTAILCALL:
381                 v.reason = "unhandled op " + n.Op().String()
382                 return true
383
384         case ir.OAPPEND:
385                 v.budget -= inlineExtraAppendCost
386
387         case ir.ODCLCONST, ir.OFALL:
388                 // These nodes don't produce code; omit from inlining budget.
389                 return false
390
391         case ir.OFOR, ir.OFORUNTIL:
392                 n := n.(*ir.ForStmt)
393                 if n.Label != nil {
394                         v.reason = "labeled control"
395                         return true
396                 }
397         case ir.OSWITCH:
398                 n := n.(*ir.SwitchStmt)
399                 if n.Label != nil {
400                         v.reason = "labeled control"
401                         return true
402                 }
403         // case ir.ORANGE, ir.OSELECT in "unhandled" above
404
405         case ir.OBREAK, ir.OCONTINUE:
406                 n := n.(*ir.BranchStmt)
407                 if n.Label != nil {
408                         // Should have short-circuited due to labeled control error above.
409                         base.Fatalf("unexpected labeled break/continue: %v", n)
410                 }
411
412         case ir.OIF:
413                 n := n.(*ir.IfStmt)
414                 if ir.IsConst(n.Cond, constant.Bool) {
415                         // This if and the condition cost nothing.
416                         // TODO(rsc): It seems strange that we visit the dead branch.
417                         return doList(n.Init(), v.do) ||
418                                 doList(n.Body, v.do) ||
419                                 doList(n.Else, v.do)
420                 }
421
422         case ir.ONAME:
423                 n := n.(*ir.Name)
424                 if n.Class == ir.PAUTO {
425                         v.usedLocals.Add(n)
426                 }
427
428         case ir.OBLOCK:
429                 // The only OBLOCK we should see at this point is an empty one.
430                 // In any event, let the visitList(n.List()) below take care of the statements,
431                 // and don't charge for the OBLOCK itself. The ++ undoes the -- below.
432                 v.budget++
433
434         case ir.OCALLPART, ir.OSLICELIT:
435                 v.budget-- // Hack for toolstash -cmp.
436
437         case ir.OMETHEXPR:
438                 v.budget++ // Hack for toolstash -cmp.
439         }
440
441         v.budget--
442
443         // When debugging, don't stop early, to get full cost of inlining this function
444         if v.budget < 0 && base.Flag.LowerM < 2 && !logopt.Enabled() {
445                 v.reason = "too expensive"
446                 return true
447         }
448
449         return ir.DoChildren(n, v.do)
450 }
451
452 func isBigFunc(fn *ir.Func) bool {
453         budget := inlineBigFunctionNodes
454         return ir.Any(fn, func(n ir.Node) bool {
455                 budget--
456                 return budget <= 0
457         })
458 }
459
460 // inlcopylist (together with inlcopy) recursively copies a list of nodes, except
461 // that it keeps the same ONAME, OTYPE, and OLITERAL nodes. It is used for copying
462 // the body and dcls of an inlineable function.
463 func inlcopylist(ll []ir.Node) []ir.Node {
464         s := make([]ir.Node, len(ll))
465         for i, n := range ll {
466                 s[i] = inlcopy(n)
467         }
468         return s
469 }
470
471 // inlcopy is like DeepCopy(), but does extra work to copy closures.
472 func inlcopy(n ir.Node) ir.Node {
473         var edit func(ir.Node) ir.Node
474         edit = func(x ir.Node) ir.Node {
475                 switch x.Op() {
476                 case ir.ONAME, ir.OTYPE, ir.OLITERAL, ir.ONIL:
477                         return x
478                 }
479                 m := ir.Copy(x)
480                 ir.EditChildren(m, edit)
481                 if x.Op() == ir.OCLOSURE {
482                         x := x.(*ir.ClosureExpr)
483                         // Need to save/duplicate x.Func.Nname,
484                         // x.Func.Nname.Ntype, x.Func.Dcl, x.Func.ClosureVars, and
485                         // x.Func.Body for iexport and local inlining.
486                         oldfn := x.Func
487                         newfn := ir.NewFunc(oldfn.Pos())
488                         if oldfn.ClosureCalled() {
489                                 newfn.SetClosureCalled(true)
490                         }
491                         m.(*ir.ClosureExpr).Func = newfn
492                         newfn.Nname = ir.NewNameAt(oldfn.Nname.Pos(), oldfn.Nname.Sym())
493                         // XXX OK to share fn.Type() ??
494                         newfn.Nname.SetType(oldfn.Nname.Type())
495                         newfn.Nname.Ntype = inlcopy(oldfn.Nname.Ntype).(ir.Ntype)
496                         newfn.Body = inlcopylist(oldfn.Body)
497                         // Make shallow copy of the Dcl and ClosureVar slices
498                         newfn.Dcl = append([]*ir.Name(nil), oldfn.Dcl...)
499                         newfn.ClosureVars = append([]*ir.Name(nil), oldfn.ClosureVars...)
500                 }
501                 return m
502         }
503         return edit(n)
504 }
505
506 // Inlcalls/nodelist/node walks fn's statements and expressions and substitutes any
507 // calls made to inlineable functions. This is the external entry point.
508 func InlineCalls(fn *ir.Func) {
509         savefn := ir.CurFunc
510         ir.CurFunc = fn
511         maxCost := int32(inlineMaxBudget)
512         if isBigFunc(fn) {
513                 maxCost = inlineBigFunctionMaxCost
514         }
515         // Map to keep track of functions that have been inlined at a particular
516         // call site, in order to stop inlining when we reach the beginning of a
517         // recursion cycle again. We don't inline immediately recursive functions,
518         // but allow inlining if there is a recursion cycle of many functions.
519         // Most likely, the inlining will stop before we even hit the beginning of
520         // the cycle again, but the map catches the unusual case.
521         inlMap := make(map[*ir.Func]bool)
522         var edit func(ir.Node) ir.Node
523         edit = func(n ir.Node) ir.Node {
524                 return inlnode(n, maxCost, inlMap, edit)
525         }
526         ir.EditChildren(fn, edit)
527         ir.CurFunc = savefn
528 }
529
530 // Turn an OINLCALL into a statement.
531 func inlconv2stmt(inlcall *ir.InlinedCallExpr) ir.Node {
532         n := ir.NewBlockStmt(inlcall.Pos(), nil)
533         n.List = inlcall.Init()
534         n.List.Append(inlcall.Body.Take()...)
535         return n
536 }
537
538 // Turn an OINLCALL into a single valued expression.
539 // The result of inlconv2expr MUST be assigned back to n, e.g.
540 //      n.Left = inlconv2expr(n.Left)
541 func inlconv2expr(n *ir.InlinedCallExpr) ir.Node {
542         r := n.ReturnVars[0]
543         return ir.InitExpr(append(n.Init(), n.Body...), r)
544 }
545
546 // Turn the rlist (with the return values) of the OINLCALL in
547 // n into an expression list lumping the ninit and body
548 // containing the inlined statements on the first list element so
549 // order will be preserved. Used in return, oas2func and call
550 // statements.
551 func inlconv2list(n *ir.InlinedCallExpr) []ir.Node {
552         if n.Op() != ir.OINLCALL || len(n.ReturnVars) == 0 {
553                 base.Fatalf("inlconv2list %+v\n", n)
554         }
555
556         s := n.ReturnVars
557         s[0] = ir.InitExpr(append(n.Init(), n.Body...), s[0])
558         return s
559 }
560
561 // inlnode recurses over the tree to find inlineable calls, which will
562 // be turned into OINLCALLs by mkinlcall. When the recursion comes
563 // back up will examine left, right, list, rlist, ninit, ntest, nincr,
564 // nbody and nelse and use one of the 4 inlconv/glue functions above
565 // to turn the OINLCALL into an expression, a statement, or patch it
566 // in to this nodes list or rlist as appropriate.
567 // NOTE it makes no sense to pass the glue functions down the
568 // recursion to the level where the OINLCALL gets created because they
569 // have to edit /this/ n, so you'd have to push that one down as well,
570 // but then you may as well do it here.  so this is cleaner and
571 // shorter and less complicated.
572 // The result of inlnode MUST be assigned back to n, e.g.
573 //      n.Left = inlnode(n.Left)
574 func inlnode(n ir.Node, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.Node) ir.Node) ir.Node {
575         if n == nil {
576                 return n
577         }
578
579         switch n.Op() {
580         case ir.ODEFER, ir.OGO:
581                 n := n.(*ir.GoDeferStmt)
582                 switch call := n.Call; call.Op() {
583                 case ir.OCALLFUNC, ir.OCALLMETH:
584                         call := call.(*ir.CallExpr)
585                         call.NoInline = true
586                 }
587
588         // TODO do them here (or earlier),
589         // so escape analysis can avoid more heapmoves.
590         case ir.OCLOSURE:
591                 return n
592         case ir.OCALLMETH:
593                 // Prevent inlining some reflect.Value methods when using checkptr,
594                 // even when package reflect was compiled without it (#35073).
595                 n := n.(*ir.CallExpr)
596                 if s := ir.MethodExprName(n.X).Sym(); base.Debug.Checkptr != 0 && types.IsReflectPkg(s.Pkg) && (s.Name == "Value.UnsafeAddr" || s.Name == "Value.Pointer") {
597                         return n
598                 }
599         }
600
601         lno := ir.SetPos(n)
602
603         ir.EditChildren(n, edit)
604
605         if as := n; as.Op() == ir.OAS2FUNC {
606                 as := as.(*ir.AssignListStmt)
607                 if as.Rhs[0].Op() == ir.OINLCALL {
608                         as.Rhs = inlconv2list(as.Rhs[0].(*ir.InlinedCallExpr))
609                         as.SetOp(ir.OAS2)
610                         as.SetTypecheck(0)
611                         n = typecheck.Stmt(as)
612                 }
613         }
614
615         // with all the branches out of the way, it is now time to
616         // transmogrify this node itself unless inhibited by the
617         // switch at the top of this function.
618         switch n.Op() {
619         case ir.OCALLFUNC, ir.OCALLMETH:
620                 n := n.(*ir.CallExpr)
621                 if n.NoInline {
622                         return n
623                 }
624         }
625
626         var call *ir.CallExpr
627         switch n.Op() {
628         case ir.OCALLFUNC:
629                 call = n.(*ir.CallExpr)
630                 if base.Flag.LowerM > 3 {
631                         fmt.Printf("%v:call to func %+v\n", ir.Line(n), call.X)
632                 }
633                 if ir.IsIntrinsicCall(call) {
634                         break
635                 }
636                 if fn := inlCallee(call.X); fn != nil && fn.Inl != nil {
637                         n = mkinlcall(call, fn, maxCost, inlMap, edit)
638                 }
639
640         case ir.OCALLMETH:
641                 call = n.(*ir.CallExpr)
642                 if base.Flag.LowerM > 3 {
643                         fmt.Printf("%v:call to meth %v\n", ir.Line(n), call.X.(*ir.SelectorExpr).Sel)
644                 }
645
646                 // typecheck should have resolved ODOTMETH->type, whose nname points to the actual function.
647                 if call.X.Type() == nil {
648                         base.Fatalf("no function type for [%p] %+v\n", call.X, call.X)
649                 }
650
651                 n = mkinlcall(call, ir.MethodExprName(call.X).Func, maxCost, inlMap, edit)
652         }
653
654         base.Pos = lno
655
656         if n.Op() == ir.OINLCALL {
657                 ic := n.(*ir.InlinedCallExpr)
658                 switch call.Use {
659                 default:
660                         ir.Dump("call", call)
661                         base.Fatalf("call missing use")
662                 case ir.CallUseExpr:
663                         n = inlconv2expr(ic)
664                 case ir.CallUseStmt:
665                         n = inlconv2stmt(ic)
666                 case ir.CallUseList:
667                         // leave for caller to convert
668                 }
669         }
670
671         return n
672 }
673
674 // inlCallee takes a function-typed expression and returns the underlying function ONAME
675 // that it refers to if statically known. Otherwise, it returns nil.
676 func inlCallee(fn ir.Node) *ir.Func {
677         fn = ir.StaticValue(fn)
678         switch fn.Op() {
679         case ir.OMETHEXPR:
680                 fn := fn.(*ir.SelectorExpr)
681                 n := ir.MethodExprName(fn)
682                 // Check that receiver type matches fn.X.
683                 // TODO(mdempsky): Handle implicit dereference
684                 // of pointer receiver argument?
685                 if n == nil || !types.Identical(n.Type().Recv().Type, fn.X.Type()) {
686                         return nil
687                 }
688                 return n.Func
689         case ir.ONAME:
690                 fn := fn.(*ir.Name)
691                 if fn.Class == ir.PFUNC {
692                         return fn.Func
693                 }
694         case ir.OCLOSURE:
695                 fn := fn.(*ir.ClosureExpr)
696                 c := fn.Func
697                 CanInline(c)
698                 return c
699         }
700         return nil
701 }
702
703 func inlParam(t *types.Field, as ir.InitNode, inlvars map[*ir.Name]*ir.Name) ir.Node {
704         if t.Nname == nil {
705                 return ir.BlankNode
706         }
707         n := t.Nname.(*ir.Name)
708         if ir.IsBlank(n) {
709                 return ir.BlankNode
710         }
711         inlvar := inlvars[n]
712         if inlvar == nil {
713                 base.Fatalf("missing inlvar for %v", n)
714         }
715         as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, inlvar))
716         inlvar.Name().Defn = as
717         return inlvar
718 }
719
720 var inlgen int
721
722 // SSADumpInline gives the SSA back end a chance to dump the function
723 // when producing output for debugging the compiler itself.
724 var SSADumpInline = func(*ir.Func) {}
725
726 // If n is a call node (OCALLFUNC or OCALLMETH), and fn is an ONAME node for a
727 // function with an inlinable body, return an OINLCALL node that can replace n.
728 // The returned node's Ninit has the parameter assignments, the Nbody is the
729 // inlined function body, and (List, Rlist) contain the (input, output)
730 // parameters.
731 // The result of mkinlcall MUST be assigned back to n, e.g.
732 //      n.Left = mkinlcall(n.Left, fn, isddd)
733 func mkinlcall(n *ir.CallExpr, fn *ir.Func, maxCost int32, inlMap map[*ir.Func]bool, edit func(ir.Node) ir.Node) ir.Node {
734         if fn.Inl == nil {
735                 if logopt.Enabled() {
736                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
737                                 fmt.Sprintf("%s cannot be inlined", ir.PkgFuncName(fn)))
738                 }
739                 return n
740         }
741         if fn.Inl.Cost > maxCost {
742                 // The inlined function body is too big. Typically we use this check to restrict
743                 // inlining into very big functions.  See issue 26546 and 17566.
744                 if logopt.Enabled() {
745                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", ir.FuncName(ir.CurFunc),
746                                 fmt.Sprintf("cost %d of %s exceeds max large caller cost %d", fn.Inl.Cost, ir.PkgFuncName(fn), maxCost))
747                 }
748                 return n
749         }
750
751         if fn == ir.CurFunc {
752                 // Can't recursively inline a function into itself.
753                 if logopt.Enabled() {
754                         logopt.LogOpt(n.Pos(), "cannotInlineCall", "inline", fmt.Sprintf("recursive call to %s", ir.FuncName(ir.CurFunc)))
755                 }
756                 return n
757         }
758
759         if base.Flag.Cfg.Instrumenting && types.IsRuntimePkg(fn.Sym().Pkg) {
760                 // Runtime package must not be instrumented.
761                 // Instrument skips runtime package. However, some runtime code can be
762                 // inlined into other packages and instrumented there. To avoid this,
763                 // we disable inlining of runtime functions when instrumenting.
764                 // The example that we observed is inlining of LockOSThread,
765                 // which lead to false race reports on m contents.
766                 return n
767         }
768
769         if inlMap[fn] {
770                 if base.Flag.LowerM > 1 {
771                         fmt.Printf("%v: cannot inline %v into %v: repeated recursive cycle\n", ir.Line(n), fn, ir.FuncName(ir.CurFunc))
772                 }
773                 return n
774         }
775         inlMap[fn] = true
776         defer func() {
777                 inlMap[fn] = false
778         }()
779         if base.Debug.TypecheckInl == 0 {
780                 typecheck.ImportedBody(fn)
781         }
782
783         // We have a function node, and it has an inlineable body.
784         if base.Flag.LowerM > 1 {
785                 fmt.Printf("%v: inlining call to %v %v { %v }\n", ir.Line(n), fn.Sym(), fn.Type(), ir.Nodes(fn.Inl.Body))
786         } else if base.Flag.LowerM != 0 {
787                 fmt.Printf("%v: inlining call to %v\n", ir.Line(n), fn)
788         }
789         if base.Flag.LowerM > 2 {
790                 fmt.Printf("%v: Before inlining: %+v\n", ir.Line(n), n)
791         }
792
793         SSADumpInline(fn)
794
795         ninit := n.Init()
796
797         // For normal function calls, the function callee expression
798         // may contain side effects (e.g., added by addinit during
799         // inlconv2expr or inlconv2list). Make sure to preserve these,
800         // if necessary (#42703).
801         if n.Op() == ir.OCALLFUNC {
802                 callee := n.X
803                 for callee.Op() == ir.OCONVNOP {
804                         conv := callee.(*ir.ConvExpr)
805                         ninit.Append(ir.TakeInit(conv)...)
806                         callee = conv.X
807                 }
808                 if callee.Op() != ir.ONAME && callee.Op() != ir.OCLOSURE && callee.Op() != ir.OMETHEXPR {
809                         base.Fatalf("unexpected callee expression: %v", callee)
810                 }
811         }
812
813         // Make temp names to use instead of the originals.
814         inlvars := make(map[*ir.Name]*ir.Name)
815
816         // record formals/locals for later post-processing
817         var inlfvars []*ir.Name
818
819         for _, ln := range fn.Inl.Dcl {
820                 if ln.Op() != ir.ONAME {
821                         continue
822                 }
823                 if ln.Class == ir.PPARAMOUT { // return values handled below.
824                         continue
825                 }
826                 inlf := typecheck.Expr(inlvar(ln)).(*ir.Name)
827                 inlvars[ln] = inlf
828                 if base.Flag.GenDwarfInl > 0 {
829                         if ln.Class == ir.PPARAM {
830                                 inlf.Name().SetInlFormal(true)
831                         } else {
832                                 inlf.Name().SetInlLocal(true)
833                         }
834                         inlf.SetPos(ln.Pos())
835                         inlfvars = append(inlfvars, inlf)
836                 }
837         }
838
839         nreturns := 0
840         ir.VisitList(ir.Nodes(fn.Inl.Body), func(n ir.Node) {
841                 if n != nil && n.Op() == ir.ORETURN {
842                         nreturns++
843                 }
844         })
845
846         // We can delay declaring+initializing result parameters if:
847         // (1) there's only one "return" statement in the inlined
848         // function, and (2) the result parameters aren't named.
849         delayretvars := nreturns == 1
850
851         // temporaries for return values.
852         var retvars []ir.Node
853         for i, t := range fn.Type().Results().Fields().Slice() {
854                 var m *ir.Name
855                 if nn := t.Nname; nn != nil && !ir.IsBlank(nn.(*ir.Name)) && !strings.HasPrefix(nn.Sym().Name, "~r") {
856                         n := nn.(*ir.Name)
857                         m = inlvar(n)
858                         m = typecheck.Expr(m).(*ir.Name)
859                         inlvars[n] = m
860                         delayretvars = false // found a named result parameter
861                 } else {
862                         // anonymous return values, synthesize names for use in assignment that replaces return
863                         m = retvar(t, i)
864                 }
865
866                 if base.Flag.GenDwarfInl > 0 {
867                         // Don't update the src.Pos on a return variable if it
868                         // was manufactured by the inliner (e.g. "~R2"); such vars
869                         // were not part of the original callee.
870                         if !strings.HasPrefix(m.Sym().Name, "~R") {
871                                 m.Name().SetInlFormal(true)
872                                 m.SetPos(t.Pos)
873                                 inlfvars = append(inlfvars, m)
874                         }
875                 }
876
877                 retvars = append(retvars, m)
878         }
879
880         // Assign arguments to the parameters' temp names.
881         as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
882         as.Def = true
883         if n.Op() == ir.OCALLMETH {
884                 sel := n.X.(*ir.SelectorExpr)
885                 if sel.X == nil {
886                         base.Fatalf("method call without receiver: %+v", n)
887                 }
888                 as.Rhs.Append(sel.X)
889         }
890         as.Rhs.Append(n.Args...)
891
892         // For non-dotted calls to variadic functions, we assign the
893         // variadic parameter's temp name separately.
894         var vas *ir.AssignStmt
895
896         if recv := fn.Type().Recv(); recv != nil {
897                 as.Lhs.Append(inlParam(recv, as, inlvars))
898         }
899         for _, param := range fn.Type().Params().Fields().Slice() {
900                 // For ordinary parameters or variadic parameters in
901                 // dotted calls, just add the variable to the
902                 // assignment list, and we're done.
903                 if !param.IsDDD() || n.IsDDD {
904                         as.Lhs.Append(inlParam(param, as, inlvars))
905                         continue
906                 }
907
908                 // Otherwise, we need to collect the remaining values
909                 // to pass as a slice.
910
911                 x := len(as.Lhs)
912                 for len(as.Lhs) < len(as.Rhs) {
913                         as.Lhs.Append(argvar(param.Type, len(as.Lhs)))
914                 }
915                 varargs := as.Lhs[x:]
916
917                 vas = ir.NewAssignStmt(base.Pos, nil, nil)
918                 vas.X = inlParam(param, vas, inlvars)
919                 if len(varargs) == 0 {
920                         vas.Y = typecheck.NodNil()
921                         vas.Y.SetType(param.Type)
922                 } else {
923                         lit := ir.NewCompLitExpr(base.Pos, ir.OCOMPLIT, ir.TypeNode(param.Type), nil)
924                         lit.List = varargs
925                         vas.Y = lit
926                 }
927         }
928
929         if len(as.Rhs) != 0 {
930                 ninit.Append(typecheck.Stmt(as))
931         }
932
933         if vas != nil {
934                 ninit.Append(typecheck.Stmt(vas))
935         }
936
937         if !delayretvars {
938                 // Zero the return parameters.
939                 for _, n := range retvars {
940                         ninit.Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
941                         ras := ir.NewAssignStmt(base.Pos, n, nil)
942                         ninit.Append(typecheck.Stmt(ras))
943                 }
944         }
945
946         retlabel := typecheck.AutoLabel(".i")
947
948         inlgen++
949
950         parent := -1
951         if b := base.Ctxt.PosTable.Pos(n.Pos()).Base(); b != nil {
952                 parent = b.InliningIndex()
953         }
954
955         sym := fn.Linksym()
956         newIndex := base.Ctxt.InlTree.Add(parent, n.Pos(), sym)
957
958         // Add an inline mark just before the inlined body.
959         // This mark is inline in the code so that it's a reasonable spot
960         // to put a breakpoint. Not sure if that's really necessary or not
961         // (in which case it could go at the end of the function instead).
962         // Note issue 28603.
963         inlMark := ir.NewInlineMarkStmt(base.Pos, types.BADWIDTH)
964         inlMark.SetPos(n.Pos().WithIsStmt())
965         inlMark.Index = int64(newIndex)
966         ninit.Append(inlMark)
967
968         if base.Flag.GenDwarfInl > 0 {
969                 if !sym.WasInlined() {
970                         base.Ctxt.DwFixups.SetPrecursorFunc(sym, fn)
971                         sym.Set(obj.AttrWasInlined, true)
972                 }
973         }
974
975         subst := inlsubst{
976                 retlabel:     retlabel,
977                 retvars:      retvars,
978                 delayretvars: delayretvars,
979                 inlvars:      inlvars,
980                 bases:        make(map[*src.PosBase]*src.PosBase),
981                 newInlIndex:  newIndex,
982                 fn:           fn,
983         }
984         subst.edit = subst.node
985
986         body := subst.list(ir.Nodes(fn.Inl.Body))
987
988         lab := ir.NewLabelStmt(base.Pos, retlabel)
989         body = append(body, lab)
990
991         typecheck.Stmts(body)
992
993         if base.Flag.GenDwarfInl > 0 {
994                 for _, v := range inlfvars {
995                         v.SetPos(subst.updatedPos(v.Pos()))
996                 }
997         }
998
999         //dumplist("ninit post", ninit);
1000
1001         call := ir.NewInlinedCallExpr(base.Pos, nil, nil)
1002         *call.PtrInit() = ninit
1003         call.Body = body
1004         call.ReturnVars = retvars
1005         call.SetType(n.Type())
1006         call.SetTypecheck(1)
1007
1008         // transitive inlining
1009         // might be nice to do this before exporting the body,
1010         // but can't emit the body with inlining expanded.
1011         // instead we emit the things that the body needs
1012         // and each use must redo the inlining.
1013         // luckily these are small.
1014         ir.EditChildren(call, edit)
1015
1016         if base.Flag.LowerM > 2 {
1017                 fmt.Printf("%v: After inlining %+v\n\n", ir.Line(call), call)
1018         }
1019
1020         return call
1021 }
1022
1023 // Every time we expand a function we generate a new set of tmpnames,
1024 // PAUTO's in the calling functions, and link them off of the
1025 // PPARAM's, PAUTOS and PPARAMOUTs of the called function.
1026 func inlvar(var_ *ir.Name) *ir.Name {
1027         if base.Flag.LowerM > 3 {
1028                 fmt.Printf("inlvar %+v\n", var_)
1029         }
1030
1031         n := typecheck.NewName(var_.Sym())
1032         n.SetType(var_.Type())
1033         n.Class = ir.PAUTO
1034         n.SetUsed(true)
1035         n.Curfn = ir.CurFunc // the calling function, not the called one
1036         n.SetAddrtaken(var_.Addrtaken())
1037
1038         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
1039         return n
1040 }
1041
1042 // Synthesize a variable to store the inlined function's results in.
1043 func retvar(t *types.Field, i int) *ir.Name {
1044         n := typecheck.NewName(typecheck.LookupNum("~R", i))
1045         n.SetType(t.Type)
1046         n.Class = ir.PAUTO
1047         n.SetUsed(true)
1048         n.Curfn = ir.CurFunc // the calling function, not the called one
1049         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
1050         return n
1051 }
1052
1053 // Synthesize a variable to store the inlined function's arguments
1054 // when they come from a multiple return call.
1055 func argvar(t *types.Type, i int) ir.Node {
1056         n := typecheck.NewName(typecheck.LookupNum("~arg", i))
1057         n.SetType(t.Elem())
1058         n.Class = ir.PAUTO
1059         n.SetUsed(true)
1060         n.Curfn = ir.CurFunc // the calling function, not the called one
1061         ir.CurFunc.Dcl = append(ir.CurFunc.Dcl, n)
1062         return n
1063 }
1064
1065 // The inlsubst type implements the actual inlining of a single
1066 // function call.
1067 type inlsubst struct {
1068         // Target of the goto substituted in place of a return.
1069         retlabel *types.Sym
1070
1071         // Temporary result variables.
1072         retvars []ir.Node
1073
1074         // Whether result variables should be initialized at the
1075         // "return" statement.
1076         delayretvars bool
1077
1078         inlvars map[*ir.Name]*ir.Name
1079
1080         // bases maps from original PosBase to PosBase with an extra
1081         // inlined call frame.
1082         bases map[*src.PosBase]*src.PosBase
1083
1084         // newInlIndex is the index of the inlined call frame to
1085         // insert for inlined nodes.
1086         newInlIndex int
1087
1088         edit func(ir.Node) ir.Node // cached copy of subst.node method value closure
1089
1090         // If non-nil, we are inside a closure inside the inlined function, and
1091         // newclofn is the Func of the new inlined closure.
1092         newclofn *ir.Func
1093
1094         fn *ir.Func // For debug -- the func that is being inlined
1095 }
1096
1097 // list inlines a list of nodes.
1098 func (subst *inlsubst) list(ll ir.Nodes) []ir.Node {
1099         s := make([]ir.Node, 0, len(ll))
1100         for _, n := range ll {
1101                 s = append(s, subst.node(n))
1102         }
1103         return s
1104 }
1105
1106 // fields returns a list of the fields of a struct type representing receiver,
1107 // params, or results, after duplicating the field nodes and substituting the
1108 // Nname nodes inside the field nodes.
1109 func (subst *inlsubst) fields(oldt *types.Type) []*types.Field {
1110         oldfields := oldt.FieldSlice()
1111         newfields := make([]*types.Field, len(oldfields))
1112         for i := range oldfields {
1113                 newfields[i] = oldfields[i].Copy()
1114                 if oldfields[i].Nname != nil {
1115                         newfields[i].Nname = subst.node(oldfields[i].Nname.(*ir.Name))
1116                 }
1117         }
1118         return newfields
1119 }
1120
1121 // clovar creates a new ONAME node for a local variable or param of a closure
1122 // inside a function being inlined.
1123 func (subst *inlsubst) clovar(n *ir.Name) *ir.Name {
1124         // TODO(danscales): want to get rid of this shallow copy, with code like the
1125         // following, but it is hard to copy all the necessary flags in a maintainable way.
1126         // m := ir.NewNameAt(n.Pos(), n.Sym())
1127         // m.Class = n.Class
1128         // m.SetType(n.Type())
1129         // m.SetTypecheck(1)
1130         //if n.IsClosureVar() {
1131         //      m.SetIsClosureVar(true)
1132         //}
1133         m := &ir.Name{}
1134         *m = *n
1135         m.Curfn = subst.newclofn
1136         if n.Defn != nil && n.Defn.Op() == ir.ONAME {
1137                 if !n.IsClosureVar() {
1138                         base.FatalfAt(n.Pos(), "want closure variable, got: %+v", n)
1139                 }
1140                 if n.Sym().Pkg != types.LocalPkg {
1141                         // If the closure came from inlining a function from
1142                         // another package, must change package of captured
1143                         // variable to localpkg, so that the fields of the closure
1144                         // struct are local package and can be accessed even if
1145                         // name is not exported. If you disable this code, you can
1146                         // reproduce the problem by running 'go test
1147                         // go/internal/srcimporter'. TODO(mdempsky) - maybe change
1148                         // how we create closure structs?
1149                         m.SetSym(types.LocalPkg.Lookup(n.Sym().Name))
1150                 }
1151                 // Make sure any inlvar which is the Defn
1152                 // of an ONAME closure var is rewritten
1153                 // during inlining. Don't substitute
1154                 // if Defn node is outside inlined function.
1155                 if subst.inlvars[n.Defn.(*ir.Name)] != nil {
1156                         m.Defn = subst.node(n.Defn)
1157                 }
1158         }
1159         if n.Outer != nil {
1160                 // Either the outer variable is defined in function being inlined,
1161                 // and we will replace it with the substituted variable, or it is
1162                 // defined outside the function being inlined, and we should just
1163                 // skip the outer variable (the closure variable of the function
1164                 // being inlined).
1165                 s := subst.node(n.Outer).(*ir.Name)
1166                 if s == n.Outer {
1167                         s = n.Outer.Outer
1168                 }
1169                 m.Outer = s
1170         }
1171         return m
1172 }
1173
1174 // closure does the necessary substitions for a ClosureExpr n and returns the new
1175 // closure node.
1176 func (subst *inlsubst) closure(n *ir.ClosureExpr) ir.Node {
1177         m := ir.Copy(n)
1178         m.SetPos(subst.updatedPos(m.Pos()))
1179         ir.EditChildren(m, subst.edit)
1180
1181         //fmt.Printf("Inlining func %v with closure into %v\n", subst.fn, ir.FuncName(ir.CurFunc))
1182
1183         // The following is similar to funcLit
1184         oldfn := n.Func
1185         newfn := ir.NewFunc(oldfn.Pos())
1186         // These three lines are not strictly necessary, but just to be clear
1187         // that new function needs to redo typechecking and inlinability.
1188         newfn.SetTypecheck(0)
1189         newfn.SetInlinabilityChecked(false)
1190         newfn.Inl = nil
1191         newfn.SetIsHiddenClosure(true)
1192         newfn.Nname = ir.NewNameAt(n.Pos(), ir.BlankNode.Sym())
1193         newfn.Nname.Func = newfn
1194         newfn.Nname.Ntype = subst.node(oldfn.Nname.Ntype).(ir.Ntype)
1195         newfn.Nname.Defn = newfn
1196
1197         m.(*ir.ClosureExpr).Func = newfn
1198         newfn.OClosure = m.(*ir.ClosureExpr)
1199
1200         if subst.newclofn != nil {
1201                 //fmt.Printf("Inlining a closure with a nested closure\n")
1202         }
1203         prevxfunc := subst.newclofn
1204
1205         // Mark that we are now substituting within a closure (within the
1206         // inlined function), and create new nodes for all the local
1207         // vars/params inside this closure.
1208         subst.newclofn = newfn
1209         newfn.Dcl = nil
1210         newfn.ClosureVars = nil
1211         for _, oldv := range oldfn.Dcl {
1212                 newv := subst.clovar(oldv)
1213                 subst.inlvars[oldv] = newv
1214                 newfn.Dcl = append(newfn.Dcl, newv)
1215         }
1216         for _, oldv := range oldfn.ClosureVars {
1217                 newv := subst.clovar(oldv)
1218                 subst.inlvars[oldv] = newv
1219                 newfn.ClosureVars = append(newfn.ClosureVars, newv)
1220         }
1221
1222         // Need to replace ONAME nodes in
1223         // newfn.Type().FuncType().Receiver/Params/Results.FieldSlice().Nname
1224         oldt := oldfn.Type()
1225         newrecvs := subst.fields(oldt.Recvs())
1226         var newrecv *types.Field
1227         if len(newrecvs) > 0 {
1228                 newrecv = newrecvs[0]
1229         }
1230         newt := types.NewSignature(oldt.Pkg(), newrecv,
1231                 subst.fields(oldt.Params()), subst.fields(oldt.Results()))
1232
1233         newfn.Nname.SetType(newt)
1234         newfn.Body = subst.list(oldfn.Body)
1235
1236         // Remove the nodes for the current closure from subst.inlvars
1237         for _, oldv := range oldfn.Dcl {
1238                 delete(subst.inlvars, oldv)
1239         }
1240         for _, oldv := range oldfn.ClosureVars {
1241                 delete(subst.inlvars, oldv)
1242         }
1243         // Go back to previous closure func
1244         subst.newclofn = prevxfunc
1245
1246         // Actually create the named function for the closure, now that
1247         // the closure is inlined in a specific function.
1248         m.SetTypecheck(0)
1249         if oldfn.ClosureCalled() {
1250                 typecheck.Callee(m)
1251         } else {
1252                 typecheck.Expr(m)
1253         }
1254         return m
1255 }
1256
1257 // node recursively copies a node from the saved pristine body of the
1258 // inlined function, substituting references to input/output
1259 // parameters with ones to the tmpnames, and substituting returns with
1260 // assignments to the output.
1261 func (subst *inlsubst) node(n ir.Node) ir.Node {
1262         if n == nil {
1263                 return nil
1264         }
1265
1266         switch n.Op() {
1267         case ir.ONAME:
1268                 n := n.(*ir.Name)
1269
1270                 // Handle captured variables when inlining closures.
1271                 if n.IsClosureVar() && subst.newclofn == nil {
1272                         o := n.Outer
1273
1274                         // Deal with case where sequence of closures are inlined.
1275                         // TODO(danscales) - write test case to see if we need to
1276                         // go up multiple levels.
1277                         if o.Curfn != ir.CurFunc {
1278                                 o = o.Outer
1279                         }
1280
1281                         // make sure the outer param matches the inlining location
1282                         if o == nil || o.Curfn != ir.CurFunc {
1283                                 base.Fatalf("%v: unresolvable capture %v\n", ir.Line(n), n)
1284                         }
1285
1286                         if base.Flag.LowerM > 2 {
1287                                 fmt.Printf("substituting captured name %+v  ->  %+v\n", n, o)
1288                         }
1289                         return o
1290                 }
1291
1292                 if inlvar := subst.inlvars[n]; inlvar != nil { // These will be set during inlnode
1293                         if base.Flag.LowerM > 2 {
1294                                 fmt.Printf("substituting name %+v  ->  %+v\n", n, inlvar)
1295                         }
1296                         return inlvar
1297                 }
1298
1299                 if base.Flag.LowerM > 2 {
1300                         fmt.Printf("not substituting name %+v\n", n)
1301                 }
1302                 return n
1303
1304         case ir.OMETHEXPR:
1305                 n := n.(*ir.SelectorExpr)
1306                 return n
1307
1308         case ir.OLITERAL, ir.ONIL, ir.OTYPE:
1309                 // If n is a named constant or type, we can continue
1310                 // using it in the inline copy. Otherwise, make a copy
1311                 // so we can update the line number.
1312                 if n.Sym() != nil {
1313                         return n
1314                 }
1315
1316         case ir.ORETURN:
1317                 if subst.newclofn != nil {
1318                         // Don't do special substitutions if inside a closure
1319                         break
1320                 }
1321                 // Since we don't handle bodies with closures,
1322                 // this return is guaranteed to belong to the current inlined function.
1323                 n := n.(*ir.ReturnStmt)
1324                 init := subst.list(n.Init())
1325                 if len(subst.retvars) != 0 && len(n.Results) != 0 {
1326                         as := ir.NewAssignListStmt(base.Pos, ir.OAS2, nil, nil)
1327
1328                         // Make a shallow copy of retvars.
1329                         // Otherwise OINLCALL.Rlist will be the same list,
1330                         // and later walk and typecheck may clobber it.
1331                         for _, n := range subst.retvars {
1332                                 as.Lhs.Append(n)
1333                         }
1334                         as.Rhs = subst.list(n.Results)
1335
1336                         if subst.delayretvars {
1337                                 for _, n := range as.Lhs {
1338                                         as.PtrInit().Append(ir.NewDecl(base.Pos, ir.ODCL, n.(*ir.Name)))
1339                                         n.Name().Defn = as
1340                                 }
1341                         }
1342
1343                         init = append(init, typecheck.Stmt(as))
1344                 }
1345                 init = append(init, ir.NewBranchStmt(base.Pos, ir.OGOTO, subst.retlabel))
1346                 typecheck.Stmts(init)
1347                 return ir.NewBlockStmt(base.Pos, init)
1348
1349         case ir.OGOTO:
1350                 n := n.(*ir.BranchStmt)
1351                 m := ir.Copy(n).(*ir.BranchStmt)
1352                 m.SetPos(subst.updatedPos(m.Pos()))
1353                 *m.PtrInit() = nil
1354                 p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
1355                 m.Label = typecheck.Lookup(p)
1356                 return m
1357
1358         case ir.OLABEL:
1359                 if subst.newclofn != nil {
1360                         // Don't do special substitutions if inside a closure
1361                         break
1362                 }
1363                 n := n.(*ir.LabelStmt)
1364                 m := ir.Copy(n).(*ir.LabelStmt)
1365                 m.SetPos(subst.updatedPos(m.Pos()))
1366                 *m.PtrInit() = nil
1367                 p := fmt.Sprintf("%s·%d", n.Label.Name, inlgen)
1368                 m.Label = typecheck.Lookup(p)
1369                 return m
1370
1371         case ir.OCLOSURE:
1372                 return subst.closure(n.(*ir.ClosureExpr))
1373
1374         }
1375
1376         m := ir.Copy(n)
1377         m.SetPos(subst.updatedPos(m.Pos()))
1378         ir.EditChildren(m, subst.edit)
1379         return m
1380 }
1381
1382 func (subst *inlsubst) updatedPos(xpos src.XPos) src.XPos {
1383         pos := base.Ctxt.PosTable.Pos(xpos)
1384         oldbase := pos.Base() // can be nil
1385         newbase := subst.bases[oldbase]
1386         if newbase == nil {
1387                 newbase = src.NewInliningBase(oldbase, subst.newInlIndex)
1388                 subst.bases[oldbase] = newbase
1389         }
1390         pos.SetBase(newbase)
1391         return base.Ctxt.PosTable.XPos(pos)
1392 }
1393
1394 func pruneUnusedAutos(ll []*ir.Name, vis *hairyVisitor) []*ir.Name {
1395         s := make([]*ir.Name, 0, len(ll))
1396         for _, n := range ll {
1397                 if n.Class == ir.PAUTO {
1398                         if !vis.usedLocals.Has(n) {
1399                                 continue
1400                         }
1401                 }
1402                 s = append(s, n)
1403         }
1404         return s
1405 }
1406
1407 // numNonClosures returns the number of functions in list which are not closures.
1408 func numNonClosures(list []*ir.Func) int {
1409         count := 0
1410         for _, fn := range list {
1411                 if fn.OClosure == nil {
1412                         count++
1413                 }
1414         }
1415         return count
1416 }
1417
1418 func doList(list []ir.Node, do func(ir.Node) bool) bool {
1419         for _, x := range list {
1420                 if x != nil {
1421                         if do(x) {
1422                                 return true
1423                         }
1424                 }
1425         }
1426         return false
1427 }